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

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

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

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.

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



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);
}
}

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.


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
