1.1 Einstieg in Arduino für STM32

Forum der STM32 Boardleute: https://www.stm32duino.com

Anleitung für MacOS

Arduino Software laden und installieren.
Unter Voreinstellungen zusätzliche Boardverwalter-URL eingeben damit die Erweiterung gefunden wird:
Das Kopieren und einfügen: https://github.com/stm32duino/BoardManagerFiles/raw/main/package_stmicroelectronics_index.json

Boardverwalter
Boardverwalter-URL hinzufügen

Arduino-IDE NEU Starten => Dann wird Eintrag unter Voreinstellungen erst aktiv!​
DANN In den Boardverwalter gehen und STM32 MCU based borads installieren
Werkzeuge => Board => Boardverwalter => STM32 => Installieren

Boardinstallation
Boardinstallation

Das richtige Board auswählen:
Werkzeuge =>​ Board =>​ STM32 boards =>​ Nucleo-64​

Nucleo-64 auswählen
Nucleo-64 auswählen

Den richtigen Chip auswählen
Werkzeuge =>​ Board part number =>​ Nucleo 152RE​

Einstecken des Nucleo​ zum Programmieren
Wie bei Arduino gewohnt:
Werkzeuge =>​ Port =>​ COM ???​ –Nein!
Unter MacOS wird das Board als Volume eingebunden.
Die Software wird auf das erscheinende externe Laufwerk NODE_L152RE kopiert.

Bord wird als Volume (ext. Datenspeicher) angezeigt
Bord wird als Volume (ext. Datenspeicher) angezeigt

Upload method: „Mass Storage“ auswählen.
Nicht 😭 wenn der Mac beim Upload über nicht richtig ausgeworfene Volumes 🤬.

Nicht korrekt ausgeworfen
Nicht korrekt ausgeworfen
Nucleo L152RE
Nucleo L152RE
Upload method: "Mass Storage"
Upload method: „Mass Storage“

Testprogramm

#define P_BOARD_LED 13 // grüne LED auf dem Board

void setup(){   // Einmalige Ausführung => Initialisierungen...
  pinMode(P_BOARD_LED, OUTPUT);  // Pin als Ausgang schalten
}

void loop(){ // wird immer wieder ausgeführt 
  digitalWrite(P_BOARD_LED, HIGH);// High ausgeben
  delay(200);                   // warte 200ms
  digitalWrite(P_BOARD_LED, LOW); // Low ausgeben
  delay(200);                   // warte 200ms
}

Erläuterungen
Die grüne LED auf dem Board ist an Arduino-Pin 13 angeschlossen, damit im Quelltext statt 13 das aussagekräftigere P_BOARD_LED verwendet werden kann lässt man mit #define P_BOARD_LED 13 den Präprozessor (Textverarbeitung vor dem Compiler) alle Vorkommen des Textes P_BOARD_LED durch den Text 13 ersetzen. Hinweise:

  • Das P_ vor dem Bezeichner bedeutet Pin.
  • Bei Arduino wird normalerweise 13 für Arduino-Pins geschrieben, durch die STM32-Lib kann auch D13 (besser lesbar) verwendet werden.

Im setup() werden alle Initialisierungen beim Programmstart oder nach einem Reset durchgeführt.
Bevor ein Pin als Ausgang verwendet werden kann muss er als Ausgang definiert werden: pinMode(P_BOARD_LED, OUTPUT) stellt die Hardware so ein, dass D13 als Ausgang funktioniert.
Die loop()-Funktion wird endlos ständig wiederholt.

Anleitung für Windows

Ausgeben und Empfangen über den Seriellen Monitor

Über den Seriellen Monitor können Texte vom µC zur Arduino Software übertragen und auch von dieser empfangen werden.
Arduino-Doku zur seriellen Schnittstelle Serial🔗. Zur besseren Lesbarkeit der Ausgaben wird printf📖 verwendet:

#define P_BOARD_LED 13 // grüne LED auf dem Board
char empfangByte = 0; // für empfangenes Byte

void setup(){   // Einmalige Ausführung => Initialisierungen...
  pinMode(P_BOARD_LED, OUTPUT);  // Pin als Ausgang
  Serial.begin(9600); // Serielle Schnittstelle starten und Baudrate festlegen
}

void loop(){ // wird immer wieder ausgeführt
  digitalWrite(P_BOARD_LED, HIGH); // LED einschalten
  Serial.println("an");          // Ausgabe auf Seriellen Monitor
  delay(1000);                   // 1s warten
  digitalWrite(P_BOARD_LED, LOW);  // LED ausschalten
  Serial.println("aus");         // Ausgabe auf Seriellen Monitor
  delay(1000);                   // 1s warten
  Serial.printf("Analogwert: %4d\n",analogRead(A0)); // AD-Wert ausgeben von A0
  if(Serial.available()>0){ // wurde was gesendet?
    empfangByte = Serial.read();  // lies ein Byte
    Serial.printf("Ich empfing: %3d 0x%2x %c\n",empfangByte,empfangByte,empfangByte);
  }
}
Port auswählen
Port auswählen

Die übliche, voreingestellte serielle Übertragungsgeschwindigkeit zwischen Board und Arduino ist 9600 Baud. Falls eine andere Geschwindigkeit gewünscht ist kann dies unten im Seriellen Monitor eingestellt werden.

Serieller Monitor
Serieller Monitor
Baudrate entsprechend einstellen
Baudrate entsprechend einstellen

Pin-Namen des Chips verwenden wenn es keine Arduino-Bezeichnungen dafür gibt

Die L152RE-Platine hat viel mehr Pins als nur die Arduino-Anschlüsse. Um z.B auf dem SturmBoard die LEDs an zu sprechen und die Taster ab zu fragen müssen dazu die Bezeichnungen des L152RE verwendet werden.

#define P_L0 PC0 // LED an PC0
#define P_L1 PC1
#define P_L2 PC2
#define P_S1 PA1 // Taster (Switch) an PA1
void setup(){   // Einmalige Ausführung => Initialisierungen...  
  pinMode(P_L0, OUTPUT);  // P_L0 (PC0) als Ausgang
  pinMode(P_L1, OUTPUT);  // P_L1 (PC1) als Ausgang
  pinMode(P_L2, OUTPUT);  // P_L2 (PC2) als Ausgang
  pinMode(P_S1, INPUT_PULLDOWN); // P_S1 (PA1) als Eingang mit Pulldown
}

void loop(){ // wird immer wieder ausgeführt
  digitalWrite(P_L2,digitalRead(P_S1)); // PA1 einlesen und auf PC2 ausgeben
  digitalWrite(P_L0, HIGH);  // PC0 <- 1
  delay(300);                // warte 300ms
  digitalWrite(P_L0, LOW);   // PC0 <- 0
  digitalWrite(P_L1, HIGH);  // PC1 <- 1
  delay(300);                // warte 300ms
  digitalWrite(P_L1, LOW);   // PC1 <- 0
}

Eine Pin-Bezeichnung im Kontext von pinMode(), digitalRead(), digitalWrite() wie 13, A0, D13, PA1, PC0 bestimmt welcher Pin des µC gemeint ist.
Letztlich wird die Pin-Bezeichnung auf eine Zahl abgebildet, die über die µC-Board-Library vom Compiler in für den µC passende Anweisungen übersetzt werden.
Sehr oft ist an einem Pin ein bestimmter Eingang (z.B. Taster S1 an Pin PA1) oder Ausgang (z.B. eine LED L0 an PC0) angeschlossen. Im Programm ist für die Programmiererin die Funktion wichtiger als der Pin auf dem die Funktion gelegt wurde. Daher wäre es praktisch die Funktion und nicht die Pin-Bezeichnung zu verwenden, also P_S1 (Pin für S1) statt PA1.
Für die Verständlichkeit des Programms ist das sehr sinnvoll.
Die Übersetzung soll der Compiler übernehmen! Lösungen:

Mit const int P_S1 = PA1 wird in P_S1 der ZahlenPinWert des Pins gespeichert.

Mit #define P_S1 PA1 werden durch den C-Präprozessor📖 vor der Compilierung alle Vorkommen von P_S1 durch PA1 im Quelltext ersetzt.


🍬 Ansprechen mehrerer nebeneinander liegender Pins?

void setup(){   // Einmalige Ausführung => Initialisierungen...
  Serial.begin(9600); // Serielle Schnittstelle initialisieren
  RCC->AHBENR |= (1<<2);  // Enable the GPIOC clock
  // pinMode(PC0, OUTPUT);  // hat die selbe Wirkung
  GPIOC->MODER = 0x5555; // PC0..PC7 als Ausgang
  GPIOC->ODR = 0xff;     // PC0..PC7 einschalten, alle LED leuchten
  Serial.printf("GPIOC->MODER: %#4x\n",GPIOC->MODER);
  pinMode(PA1, INPUT_PULLDOWN); // PA1 als Eingang mit Pulldown
  Serial.printf("GPIOA->MODER: %#4x\n",GPIOA->MODER); // PinMode
  Serial.printf("GPIOA->PUPDR: %#4x\n",GPIOA->PUPDR); // PullUpMode
}

void loop(){ // wird immer wieder ausgeführt
  digitalWrite(PC0, HIGH); // PC0 <-1
  digitalWrite(PC1, LOW);  // PC1 <-0
  delay(200);
  // ohne Arduino Watte, direkt über den Port zugreifen
  GPIOC->ODR &=~1;         // PC0 <-0
  GPIOC->ODR |=2;          // PC1 <-1
  delay(200);
  if(GPIOA->IDR & 0b10){   // wenn PA1
    GPIOC->ODR |= (1<<2);  // setzte PC2
  }
  else{                    // sonst
    GPIOC->ODR &= ~(1<<2); // lösche PC2
  }
  // mit Arduino Watte
  digitalWrite(PC3,digitalRead(PA1)); // PC3 <- PA1
}

Ausblick

Sobald auf einen Schlag mehrere Pins auf einmal geändert werden sollen, z.B. bei der Ansteuerung einer 7-Segment Anzeige wird es mit Arduino pinMode(), digitalWrite() usw. umständlich. Mit dem direkten Zugriff über die I/O-Register wird der Code dabei kompakter.

Allerdings wird der Code damit auch Hardware spezifischer und nicht mehr so leicht auf andere µC portierbar.

Info zu L152RE-Ports: 1.1x STM32 GPIO Ports