1.2 Aufgaben zum Einstieg
SOS ausgeben mit BoardLED D13. … – – – …
Auf der BoardLED 13 soll ein SOS-Blinken ausgegeben werden.
Hier das Zeitschema zur Ausgabe. Mit einer Variable int dit soll die Dauer des kurzen Signals einstellbar sein.
Zum Testen usw. https://morsedecoder.com
Erstellen Sie ein Programm, ein dit soll die Länge 200ms haben. Hier ein paar Anregungen:
- Lineares Programm (Ausgaben einfach runter programmieren)?
- Mit Unterprogrammen dit(), dah()
- Zählschleifen verwenden
Lösungsvorschlag (klick mich wenn du nicht weiter kommst)
// https://de.wikipedia.org/wiki/Morsecode#Zeitschema_und_Veranschaulichung
#define BOARD_LED D13
char empfangByte = 0; // für empfangenes Byte
int dit = 200; // Basislänge in ms
void setup(){ // Einmalige Ausführung => Initialisierungen...
pinMode(BOARD_LED, OUTPUT); // Pin als Ausgang
Serial.begin(115200); // Serielle Schnittstelle starten und Baudrate festlegen
}
void led_dit(){ // Dit ausgeben
digitalWrite(BOARD_LED,HIGH);
delay(dit);
digitalWrite(BOARD_LED,LOW);
delay(dit); // ein dit Symbolabstand
Serial.print(".");
}
void led_dah(){ // Dah ausgeben
digitalWrite(BOARD_LED,HIGH);
delay(3*dit);
digitalWrite(BOARD_LED,LOW);
delay(dit); // ein dit Symbolabstand
Serial.print("-");
}
void buchstabenAbstand(){ // Buchstabenstand ausgeben
delay(2*dit); // 3-1
Serial.print(" ");
}
void wortAbstand(){ // Wortabstand ausgeben
delay(6*dit); // 7-1
Serial.print(" ");
}
void morseSOS(){
int i;
for(i=0;i<3;i++){ // S
led_dit();
}
buchstabenAbstand();
for(i=0;i<3;i++){ // O
led_dah();
}
buchstabenAbstand();
for(i=0;i<3;i++){ // S
led_dit();
}
}
void loop(){;
morseSOS();
delay(1000);
}
// Vorgabe
#define BOARD_LED D13
int dit = 200; // Basislänge in ms
void setup(){ // Einmalige Ausführung => Initialisierungen...
pinMode(BOARD_LED, OUTPUT); // Pin als Ausgang
Serial.begin(115200); // Serielle Schnittstelle starten und Baudrate festlegen
}
void morseSOS(){
}
void loop(){
morseSOS();
delay(1000);
}
String ausgeben … — …
- Die SOS-Ausgabe soll nun mit Taste an PA1 starten und dabei ein Unterprogramm ausgebenString(s);
- Der Morsecode soll in einem String s =“… — …“; gespeichert sein.
Lösungsvorschlag
#define BOARD_LED D13
char empfangByte = 0; // für empfangenes Byte
int dit = 200; // Basislänge in ms
String s="... --- ..."; // auszugebender Code
void setup(){ // Einmalige Ausführung => Initialisierungen...
pinMode(BOARD_LED, OUTPUT); // Pin als Ausgang
pinMode(PA1,INPUT_PULLDOWN); // PA1 als Eingang
Serial.begin(115200); // Serielle Schnittstelle starten und Baudrate festlegen
}
void led_dit(){ // Dit ausgeben
digitalWrite(BOARD_LED,HIGH);
delay(dit);
digitalWrite(BOARD_LED,LOW);
delay(dit); // ein dit Symbolabstand
Serial.print(".");
}
void led_dah(){ // Dah ausgeben
digitalWrite(BOARD_LED,HIGH);
delay(3*dit);
digitalWrite(BOARD_LED,LOW);
delay(dit); // ein dit Symbolabstand
Serial.print("-");
}
void buchstabenAbstand(){ // Buchstabenstand ausgeben
delay(2*dit); // 3-1
Serial.print(" ");
}
void wortAbstand(){ // Wortabstand ausgeben
delay(6*dit); // 7-1
Serial.print(" ");
}
void morseSOS(){
int i;
for(i=0;i<3;i++){ // S
led_dit();
}
buchstabenAbstand();
for(i=0;i<3;i++){ // O
led_dah();
}
buchstabenAbstand();
for(i=0;i<3;i++){ // S
led_dit();
}
}
void ausgebenString(String s){
int i;
for (i=0;i<s.length();i++){
switch(s[i]){
case '.':
led_dit();
break;
case '-':
led_dah();
break;
case ' ':
buchstabenAbstand();
}
}
}
void loop(){;
//morseSOS();
if(digitalRead(PA1)){ // wenn Taste A1 dedrückt
ausgebenString(s);
wortAbstand();
ausgebenString("-- --- .-. ... .");
Serial.println();
delay(1000);
}
}
Bonus: String ausgeben „SOS“
- Das Unterprogramm ausgebenString(String s) soll nun ganze Sätze verarbeiten können.
- Die Eingabe kann über den Seriellen Monitor erfolgen.
Noch keine Lösung…
Ampelsteuerung (mit Sturm-Board, Multifunction-Shield)
Für die Ampeln werden auf dem Multifunction-Shield die LEDs LC0..LC7 an den Portpins PC0..PC7 verwendet.
Zuerst soll eine Straßenampel für Autos mit LC0,LC2 und LC4 implementiert werden. Später werden zusätzlich LC6 und LC7 für die Fußgänger verwendet. Tipp: Einschalten Rot mit digitalWrite(PC0,HIGH);
❗️Quellcode muss anständig formatiert und mit sinnvollen Kommentaren versehen sein!
Es gibt 4 Auto-Ampelphasen: Grün, Gelb, Rot, Rot-Gelb. Nach Rot-Gelb wird wieder auf Grün gesprungen.
Erstellen Sie den Code für setup(), um die verwendeten Port-Pins als Ausgänge zu definieren.
Erstellen Sie den Code für loop(), um mit digitalWrite(..), delay(1000) die Ampelphasen im Sekundentakt zu wechseln.
Lösungsvorschlag
void setup() {
pinMode(PC0,OUTPUT); // Rot
pinMode(PC2,OUTPUT); // Gelb
pinMode(PC4,OUTPUT); // Grün
}
void loop() {
digitalWrite(PC4,HIGH); // Grün an
delay(1000);
digitalWrite(PC4,LOW); // Grün aus
digitalWrite(PC2,HIGH); // Gelb an
delay(1000);
digitalWrite(PC2,LOW); // Gelb aus
digitalWrite(PC0,HIGH); // Rot an
delay(1000);
digitalWrite(PC2,HIGH); // Gelb an
delay(1000);
digitalWrite(PC0,LOW); // Rot aus
digitalWrite(PC2,LOW); // Gelb aus
}
Fußgängerampel
Nun bauen wir eine Fußgängerampel, die Pins PC6 und PC7 sind dafür vorgesehen. Die Fußgänger bekommen nur während der Auto-Rot-Phase Grün, sonst sehen sie Rot. Mit digitalWrite(..) würde der Code lang und unübersichtlich werden, daher setzen wir die Ausgänge mit GPIOC->ODR = Bitmuster in einem Rutsch. Für das Bitmuster ergänzen Sie diese Tabelle:
Ampel-Phase | PC7 Fuß-GN | PC6 Fuß-RT | PC5 | PC4 Auto-GN | PC3 | PC2 Auto-GE | PC1 | PC0 Auto-RT | GPIOC->ODR= |
---|---|---|---|---|---|---|---|---|---|
0 Grün | 0 | 1 | 0 | 1 | 0 | 0 | 0 | 0 | 0b0101 0000 |
1 Gelb | 1 | 0 | 0 | 0 | |||||
2 Rot | 1 | 0 | 0 | 0 | |||||
3 Rot-Gelb | 0 | 0 | 0 |
Lösung
Ampel-Phase | PC7 Fuß-GN | PC6 Fuß-RT | PC5 | PC4 Auto-GN | PC3 | PC2 Auto-GE | PC1 | PC0 Auto-RT | GPIOC->ODR= |
---|---|---|---|---|---|---|---|---|---|
0 Grün | 0 | 1 | 0 | 1 | 0 | 0 | 0 | 0 | 0b0101 0000 |
1 Gelb | 0 | 1 | 0 | 0 | 0 | 1 | 0 | 0 | 0b0100 0100 |
2 Rot | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0b1000 0001 |
3 Rot-Gelb | 0 | 1 | 0 | 0 | 0 | 1 | 0 | 1 | 0b0100 0101 |
Die 4 Ampelphasen werden in einem Feld unsigned char ampelphase[4]= {0b0101 000,…}; gespeichert, vervollständigen Sie die Initialisierung. Für die grüne Ampelphase kann nun schlicht geschrieben werden: GPIOC->ODR= ampelphase[0];
Steuerung mit Taster an PA1
Ein Taster an PA1 ist für die Fußgänger. Er ist mit 3,3V verbunden, der PullDown-Widerstand an PA1 soll eingeschaltet werden.
Die Ampel zeigt normalerweise für die Autofahrer Grün (Phase 0). PA1 startet folgenden Ablauf:
- 6 Sec warten (sinnlos weiter rumstehen)
- Phase 1 ausgeben
- 2 Sec warten
- Phase 2 ausgeben
- 6 Sec warten
- Phase 3 ausgeben
- 3 Sec warten
- zurück zu Phase 0
Der Taster PA1 wird so initialisiert und verwendet:
// setup
pinMode(PA1,INPUT_PULLDOWN); // Taster schaltet VCC
// abfragen
wert = digitalRead(PA1); // 1 wenn gedrückt
🖥 Ergänzen Sie den Code für setup(), das Feld und erstellen Sie den neuen Code für loop().
Lösungsvorschlag
void setup() {
pinMode(PC0,OUTPUT); // Rot
pinMode(PC2,OUTPUT); // Gelb
pinMode(PC4,OUTPUT); // Grün
pinMode(PC6,OUTPUT); // FRot
pinMode(PC7,OUTPUT); // FGrün
pinMode(PA1,INPUT_PULLDOWN);
}
const unsigned char ampelphase[4]={0b01010000,0b01000100,0b10000001,0b01000101};
void loop() {
GPIOC->ODR = ampelphase[0]; // Grün
while(!digitalRead(PA1));
delay(6000);
GPIOC->ODR = ampelphase[1]; // Gelb
delay(2000);
GPIOC->ODR = ampelphase[2]; // Rot
delay(6000);
GPIOC->ODR = ampelphase[3]; // RotGelb
delay(3000);
}
Abstimmanzeige (mit Sturm-Board, Multifunction-Shield)

Die Anzahl der gedrückten Tasten PA1, PA6 und PA10 soll auf den LED LC0 (PC0), LC1 (PC1 und LC2 (PC2) als Leuchtband ausgegeben werden. Siehe Funktionstabelle.
Code-Vorgabe
void setup() {
pinMode(PA1,INPUT_PULLDOWN); // PA1 als Eingang mit PullDown Widerstand
pinMode(PA6,INPUT_PULLDOWN);
pinMode(PA10,INPUT_PULLDOWN);
pinMode(PC0,OUTPUT);
pinMode(PC1,OUTPUT);
pinMode(PC2,OUTPUT);
}
void loop() {
int anzahl =0;
if(digitalRead(PA1)) anzahl++;
digitalWrite(PC0,HIGH); // LED LC0 einschalten
}
PA10 | PA6 | PA1 | LC2 (PC2) | LC1 (PC1) | LC0 (PC0) |
---|---|---|---|---|---|
0 | 0 | 0 | 0 | 0 | 0 |
0 | 0 | 1 | 0 | 0 | 1 |
0 | 1 | 0 | 0 | 0 | 1 |
0 | 1 | 1 | 0 | 1 | 1 |
1 | 0 | 0 | 0 | 0 | 1 |
1 | 0 | 1 | 0 | 1 | 1 |
1 | 1 | 0 | 0 | 1 | 1 |
1 | 1 | 1 | 1 | 1 | 1 |
Lösungsvorschlag mit switch und digitalWrite()
void setup() {
pinMode(PA1,INPUT_PULLDOWN); // PA1 als Eingang mit PullDown Widerstand
pinMode(PA6,INPUT_PULLDOWN);
pinMode(PA10,INPUT_PULLDOWN);
pinMode(PC0,OUTPUT);
pinMode(PC1,OUTPUT);
pinMode(PC2,OUTPUT);
}
void loop() {
int anzahl =0;
if(digitalRead(PA1)) anzahl++;
if(digitalRead(PA6)) anzahl++;
if(digitalRead(PA10)) anzahl++;
switch (anzahl){
case 0:
digitalWrite(PC0,LOW);
digitalWrite(PC1,LOW);
digitalWrite(PC2,LOW);
break;
case 1:
digitalWrite(PC0,HIGH);
digitalWrite(PC1,LOW);
digitalWrite(PC2,LOW);
break;
case 2:
digitalWrite(PC0,HIGH);
digitalWrite(PC1,HIGH);
digitalWrite(PC2,LOW);
break;
case 3:
digitalWrite(PC0,HIGH);
digitalWrite(PC1,HIGH);
digitalWrite(PC2,HIGH);
break;
}
}
Eleganter mit GPIOC->ODR
Statt die Ausgabe-Pins einzeln mit digitalWrite(..) zu schalten, könnten doch alle gleich mit GPIOC->ODR= auf einmal eingestellt werden.
🖥 Erstellen Sie eine Lösung.
Lösungsvorschlag mit switch und GPIOC->ODR=
void setup() {
pinMode(PA1,INPUT_PULLDOWN);
pinMode(PA6,INPUT_PULLDOWN);
pinMode(PA10,INPUT_PULLDOWN);
pinMode(PC0,OUTPUT);
pinMode(PC1,OUTPUT);
pinMode(PC2,OUTPUT);
}
void loop() {
int anzahl =0;
if(digitalRead(PA1)) anzahl++;
if(digitalRead(PA6)) anzahl++;
if(digitalRead(PA10)) anzahl++;
switch (anzahl){
case 0: GPIOC->ODR =0; break;
case 1: GPIOC->ODR =1; break;
case 2: GPIOC->ODR =3; break;
case 3: GPIOC->ODR =7; break;
}
}
Mit Array led[]={..}
Die Ausgaben können auch mit einem Array umgerechnet werden und ausgegeben werden Codeschnipsel:
const unsigned char led[]={0b000,...}; // konstantes Array mit Ausgaben
GPIOC->ODR=led[anzahl]; // ausgeben Muster aus Array
🖥 Erstellen Sie eine Lösung.
Lösungsvorschlag mit Array
void setup() {
pinMode(PA1,INPUT_PULLDOWN); // PA1 als Eingang mit PullDown Widerstand
pinMode(PA6,INPUT_PULLDOWN);
pinMode(PA10,INPUT_PULLDOWN);
pinMode(PC0,OUTPUT);
pinMode(PC1,OUTPUT);
pinMode(PC2,OUTPUT);
}
const unsigned char led[]={0b000,0b001,0b011,0b111}; // konstantes Array mit Ausgaben
void loop() {
int anzahl =0;
if(digitalRead(PA1)) anzahl++;
if(digitalRead(PA6)) anzahl++;
if(digitalRead(PA10)) anzahl++;
GPIOC->ODR=led[anzahl]; // ausgeben Muster aus Array
}
Bonus: Mit Bitschubserei zur Lösung
Zunächst: 1.1b 🚧🏋️ Bitschubserei lesen
Raffinierter Lösungsvorschlag mit Bitschubserei: Wie funktioniert das?
void setup() {
pinMode(PA1,INPUT_PULLDOWN);
pinMode(PA6,INPUT_PULLDOWN);
pinMode(PA10,INPUT_PULLDOWN);
pinMode(PC0,OUTPUT);
pinMode(PC1,OUTPUT);
pinMode(PC2,OUTPUT);
}
void loop() {
int aus =0;
int ein = GPIOA->IDR & 0b10001000010; // die Eingabe maskieren
while(ein >0){ // solange Einsen da sind
if(ein&1) aus=(aus<<1)+1; // zähle die 1 und baue Leuchtband auf
ein >>= 1; // schiebe 1 nach rechts
}
GPIOC->ODR = aus;
}
Lüftersteuerung mit LED-Leuchtbandanzeige

Ein Lüfter soll mit den Tasten PA1 (Ein/Aus) PA6 (Lüfter langsamer) und PA10 (Lüfter schneller) gesteuert werden. Es gibt 5 Lüfterstufen 0..4. Zunächst wird nur die LED-Anzeige (Leuchtband von LED LC0..LC3 an PC0..PC3) der Lüfterstufen entwickelt.
Die letzte Lüfterstufe soll beim Ausschalten gemerkt werden. Bei ausgeschaltetem Lüfter leuchtet keine LED und die Taster PA6 und PA10 sind ohne Funktion.
Stufe | LC3 (PC3) | LC2 (PC2) | LC1 (PC1) | LC0 (PC0) |
---|---|---|---|---|
0 | – | – | – | – |
1 | – | – | – | O |
2 | – | – | O | O |
3 | – | O | O | O |
4 | O | O | O | O |
Dieser Test-Quellcode ist schon gegeben:
void setup(){ // Einmalige Ausführung => Initialisierungen...
Serial.begin(9600); // Serielle Schnittstelle zum debuggen
pinMode(PC0, OUTPUT); // PC0 als Ausgang
pinMode(PC1, OUTPUT);
pinMode(PC2, OUTPUT);
pinMode(PC3, OUTPUT);
GPIOC->ODR = 0xf; // alle LED an zum Test
delay(500); // warte 0,5s
GPIOC->ODR = 0; // PC0..PC7 ausschalten
pinMode(PA1,INPUT_PULLDOWN); // Ein-Aus-Schalten
pinMode(PA6,INPUT_PULLDOWN); // minusLuefter
pinMode(PA10,INPUT_PULLDOWN); // plusLuefter
}
int stufe=0; // merken der Lüfterstufe
int an=0; // ist der Lüfter an
void ausgebenStufe(){
if(an){
GPIOC->ODR = stufe;
}
else GPIOC->ODR = 0;
}
void plusLuefter(){ // Lüfterstufe erhöhen und ausgeben
Serial.printf("plusLuefter: %d\n",stufe);
if(stufe<0b1000){ // wenn noch nicht Stufe 4
stufe = (stufe<<1)+1; // schiebe nach links und setze Bit 0
}
ausgebenStufe();
}
void loop(){
if(digitalRead(PA1)){ // wenn Taste PA1 gedrückt
stufe = 0; // Lüfterstufe = 0
ausgebenStufe();
Serial.println("zurückgesetzt");
while(digitalRead(PA1)); // warten bis Taste losgelassen
}
if(digitalRead(PA10)){ // wenn Taste PA10 gedrückt
an=1;
plusLuefter();
//delay(2); // Entprellen
while(digitalRead(PA10)); // warten bis Taste losgelassen
//delay(2); // Entprellen
}
}
🖥 Testen Sie das Programm, funktioniert die Erhöhung der Lüfterstufen richtig?
🖥 Entfernen Sie die Kommentierung der delay(2) Anweisungen und testen Sie erneut [->Brummen und Prellen].
🖥 Entwickeln Sie nun das vollständige Programm.
Bonus: Eine Status-LED ob der Lüfter an ist wäre wünschenswert. LED5 an PC5 soll dafür genutzt werden.
Lösungsvorschlag
void setup(){ // Einmalige Ausführung => Initialisierungen...
Serial.begin(9600); // Serielle Schnittstelle zum debuggen
pinMode(PC0, OUTPUT); // PC0 als Ausgang
pinMode(PC1, OUTPUT);
pinMode(PC2, OUTPUT);
pinMode(PC3, OUTPUT);
pinMode(PC5, OUTPUT);
GPIOC->ODR = 0xff; // alle LED an zum Test
delay(500); // warte 0,5s
GPIOC->ODR = 0; // PC0..PC7 ausschalten
pinMode(PA1,INPUT_PULLDOWN); // Ein-Aus-Schalten
pinMode(PA6,INPUT_PULLDOWN); // minusLuefter
pinMode(PA10,INPUT_PULLDOWN); // plusLuefter
}
int stufe=0; // merken der Lüfterstufe
bool an=0; // ist der Lüfter an
void ausgebenStufe(){
if(an){
GPIOC->ODR = stufe | 1<<5;
}
else GPIOC->ODR = 0;
}
void plusLuefter(){ // Lüfterstufe erhöhen und ausgeben
Serial.printf("plusLuefter: %d\n",stufe);
if(stufe<0b1000){ // wenn noch nicht Stufe 4
stufe = (stufe<<1)+1; // schiebe nach links und setze Bit 0
}
ausgebenStufe();
}
void minusLuefter(){
Serial.printf("minusLuefter: %d\n",stufe);
if(stufe>0){ // wenn noch nicht Stufe 0
stufe = stufe>>1;
}
ausgebenStufe();
}
void loop(){
if(digitalRead(PA1)){ // wenn Taste PA1 gedrückt
an = !an;
ausgebenStufe();
Serial.printf("Lüfteran: %d\n",an);
delay(2); // Entprellen
while(digitalRead(PA1)); // warten bis Taste losgelassen
delay(2); // Entprellen
}
if(an){
if(digitalRead(PA10)){ // wenn Taste PA10 gedrückt
plusLuefter();
delay(2); // Entprellen
while(digitalRead(PA10)); // warten bis Taste losgelassen
delay(2); // Entprellen
}
else if(digitalRead(PA6)){
minusLuefter();
delay(2); // Entprellen
while(digitalRead(PA6)); // warten bis Taste losgelassen
delay(2); // Entprellen
}
}
}
Entprellte Tastenabfrage mit buttonCheck()
Das Abfragen und Entprellen mehrerer Tasten müsste doch eleganter funktionieren. Durch das Warten bis eine Taste losgelassen wird ist das Hauptprogramm blockiert. Meine Lösung dafür ist ein Unterprogramm buttonCheck() das fragt die Tasten auf einmal ab und schreibt Änderungen (Flankendedektion) in zwei globale Variablen buttonEnter -bei Drücken von Tasten und buttonExit -bei Loslassen von Tasten. Das Unterprogramm benötigt dafür letztlich maximal die Zeit fürs Entprellen, das Hauptprogramm wird nicht lange blockiert. Im Hauptprogramm müssen nur noch die Bits der Tasten von buttonEnter bzw. buttonExit überprüft werden.
Zum Messen der Ausführungszeit von buttonCheck() wird PC8 als Ausgang verwendet.
Hier der Beispielcode:
void setup(){ // Einmalige Ausführung => Initialisierungen...
Serial.begin(115200); // Serielle Schnittstelle zum debuggen
pinMode(PC0, OUTPUT); // PC0 als Ausgang
pinMode(PC1, OUTPUT);
pinMode(PC2, OUTPUT);
pinMode(PC3, OUTPUT);
pinMode(PA1,INPUT_PULLDOWN); // Ein-Aus-Schalten
pinMode(PA6,INPUT_PULLDOWN); // minusLuefter
pinMode(PA10,INPUT_PULLDOWN); // plusLuefter
pinMode(PC8, OUTPUT); // Pin als Ausgang zum Messen der Ausführungszeit von buttonCheck()
}
#define BUTTONREADER GPIOA->IDR & 0b10001000010 // nur die relevanten Tastenbits
int buttonOld = 0; // alter Tasten-Zustand
int buttonEnter,buttonExit; // gedrueckte und losgelassene Tasten
void buttonCheck(){ // Tastaturabfrage mit Flankendedektion
int buttonTest,tmp;
buttonEnter = 0, buttonExit = 0;
buttonTest = BUTTONREADER; // Einlesen
if (buttonOld != buttonTest){ // hat sich was getan
delay(5); // 5ms Prellen abwarten
tmp = BUTTONREADER; // noch mal Einlesen
if (tmp == buttonTest){ // ist es stabil?
buttonEnter = (~buttonOld) & buttonTest; // steigende Flanke !alt und neu
buttonExit = buttonOld & (~buttonTest); // fallende Flanke alt und !neu
buttonOld = buttonTest;
}
}
}
int an=0; // Lüfter aus
void loop(){
GPIOC->BSRR = (1<<8); // PC8 <-1 zum Messen
buttonCheck(); // alle Tasten abfragen
GPIOC->BSRR = (1<<16+8); // PC8 <-0 zum Messen
if(buttonEnter&(1<<1)){ // wenn Taste PA1 gedrückt an/aus
if(an){ // wenn Lüfter an
an=0;
GPIOC->ODR=0;
Serial.println("Luefter aus");
}
else{
an=1;
GPIOC->ODR= 1<<5; // Betriebs-LED an
Serial.println("Luefter an");
}
}
}
Hier eine Messung der Ausführungsdauer von buttonCheck() an PC8 ohne Tastendruck. Die Zeit bei einem Tasten-Ereignis zu messen ist schwieriger, da im Single-Shot Modus des Oszis auf ein Tastenereignis getriggert werden muss.

Wieder so ein übles Nachprellen (Offnen der Taste) einer Taste (C1 gelb), buttonCheck() hält brav inne und wartet das Prellen ab (C2 blau). Scharfen Beobachtern fällt auf, dass die Wartezeit kleiner als das programmierte 5ms Delay ist. Wie funktioniert eigentlich das Arduino-Delay? Eine simple Warteschleife ist es jedenfalls nicht, sonst wäre die Zeit eher länger…
Hat was mit Timern zu tun und das lernen Sie bald kennen..
Bauen Sie buttonCheck() in ihre Lösung ein.
Lösungsvorschlag
void setup(){ // Einmalige Ausführung => Initialisierungen...
Serial.begin(115200); // Serielle Schnittstelle zum debuggen
pinMode(PC0, OUTPUT); // ohne diese Zeile klappts nicht
GPIOC->MODER = 0x5555; // PC0..PC7 als Ausgang
pinMode(PA1,INPUT_PULLDOWN); // Ein-Aus-Schalten
pinMode(PA6,INPUT_PULLDOWN); // minusLuefter
pinMode(PA10,INPUT_PULLDOWN); // plusLuefter
}
#define BUTTONREADER GPIOA->IDR & 0b10001000010 // nur die relevanten Tastenbits
int buttonOld = 0; // alter Tasten-Zustand
int buttonEnter,buttonExit; // gedrueckte und losgelassene Tasten
void buttonCheck(){ // Tastaturabfrage mit Flankendedektion
int buttonTest,tmp;
buttonEnter = 0, buttonExit = 0;
buttonTest = BUTTONREADER; // Einlesen
if (buttonOld != buttonTest){ // hat sich was getan
delay(5); // Prellen abwarten
tmp = BUTTONREADER; // noch mal Einlesen
if (tmp == buttonTest){ // ist es stabil?
buttonEnter = (~buttonOld) & buttonTest; // steigende Flanke !alt und neu
buttonExit = buttonOld & (~buttonTest); // fallende Flanke alt und !neu
buttonOld = buttonTest;
}
}
}
int stufe=0; // merken der Lüfterstufe
int an=0; // ist der Lüfter an
void plusLuefter(){
Serial.println("plusLuefter");
if(stufe<0b1000){ // wenn noch nicht Stufe 4
stufe = (stufe<<1)+1;
}
GPIOC->ODR = stufe | an<<5;
}
void minusLuefter(){
Serial.println("minusLuefter");
if(stufe>0){ // wenn noch nicht Stufe 0
stufe = stufe>>1;
}
GPIOC->ODR = stufe | an<<5;
}
void loop(){
buttonCheck(); // alle Tasten abfragen
if(buttonEnter&(1<<1)){ // wenn Taste PA1 gedrückt an/aus
if(an){ // wenn Lüfter an
an=0;
GPIOC->ODR=0;
Serial.println("Luefter aus");
}
else{
an=1;
GPIOC->ODR=stufe | an<<5;
Serial.println("Luefter an");
}
}
else if(an){
if(buttonEnter&(1<<10)){ // wenn Taste PA10 gedrückt
plusLuefter();
}
if(buttonEnter&(1<<6)){ // wenn Taste PA6 gedrückt
minusLuefter();
}
}
}
Leistungssteuerung mit PWM durch analogWrite()
Achtung! Erst ruhig alles durchlesen, Links verfolgen und verstehen, dann anfangen. 🤠
Die LED an PC7 soll jetzt entsprechend der Lüfterleistungsstufe verschieden hell leuchten.
Dazu wird PulsWeitenModulation (PWM) verwendet. Lesen: Einfach [arduino] Umfangreich [wikipedia]
Entsprechend der Lüfterstufe wird ein Helligkeitswert durch analogWrite(…) ausgegeben:
stufe->hell: 0->0; 1->10; 2->40; 3->100; 4->255.
Verwenden Sie analogWrite(PC7,hell), wobei int hell einen Wert von 0..255 annehmen kann.
Notwendige Umbauarbeiten: Die Variable stufe beinhaltet nun nicht mehr das Ausgabemuster sondern die Werte 0..4. Ein Unterprogramm ausgebenStufe() lässt die entsprechenden LED PC0..PC3 leuchten und setzt den Wert von stufe in den Helligkeitswert hell um und gibt ihn mit analogWrite(..) aus.
Messen Sie den Signalverlauf an PC7 bei verschiedenen Helligkeitsstufen, das Signal kann mit dem Tastkopf hier abgegriffen werden [Portpins]. Mit welcher Frequenz wird das Signal ausgegeben?
Bonus: Die Auflösung könnte gesteigert werden mit analogWriteResolution().
Lösungsvorschlag
void setup(){ // Einmalige Ausführung => Initialisierungen...
Serial.begin(115200); // Serielle Schnittstelle zum debuggen
pinMode(PC0, OUTPUT); // ohne diese Zeile klappts nicht
GPIOC->MODER = 0x5555; // PC0..PC7 als Ausgang
pinMode(PA1,INPUT_PULLDOWN); // Ein-Aus-Schalten
pinMode(PA6,INPUT_PULLDOWN); // minusLuefter
pinMode(PA10,INPUT_PULLDOWN); // plusLuefter
//analogWriteResolution (16); //0-65535 PWM duty cycle
//analogWriteFrequency(2000); // Set PMW period to 2000 Hz instead of 1000
pinMode(PA5,OUTPUT);
}
#define BUTTONREADER GPIOA->IDR & 0b10001000010 // nur die relevanten Tastenbits
int buttonOld = 0; // alter Tasten-Zustand
int buttonEnter,buttonExit; // gedrueckte und losgelassene Tasten
void buttonCheck(){ // Tastaturabfrage mit Flankendedektion
int buttonTest,tmp;
buttonEnter = 0, buttonExit = 0;
buttonTest = BUTTONREADER; // Einlesen
if (buttonOld != buttonTest){ // hat sich was getan
delay(5); // Prellen abwarten
tmp = BUTTONREADER; // noch mal Einlesen
if (tmp == buttonTest){ // ist es stabil?
buttonEnter = (~buttonOld) & buttonTest; // steigende Flanke !alt und neu
buttonExit = buttonOld & (~buttonTest); // fallende Flanke alt und !neu
buttonOld = buttonTest;
}
}
}
int stufe=0; // merken der Lüfterstufe
int an=0; // ist der Lüfter an
void plusLuefter(){
Serial.println("plusLuefter");
if(stufe<4){ // wenn noch nicht Stufe 4
stufe++;
}
ausgebenStufe();
}
void minusLuefter(){
Serial.println("minusLuefter");
if(stufe>0){ // wenn noch nicht Stufe 0
stufe--;
}
ausgebenStufe();
}
void ausgebenStufe(){
GPIOC->ODR =0;
for(int i=0;i<stufe;i++){
GPIOC->ODR = (GPIOC->ODR<<1)+1;
}
GPIOC->ODR |= an<<5; // PC5 als Status LED
int hell;
switch (stufe){
case 0: hell=0;break;
case 1: hell=10;break;
case 2: hell=40;break;
case 3: hell=100;break;
case 4: hell=255;break;
}
Serial.printf("Stufe: %d Helligkeit: %d\n",stufe,hell);
analogWrite(PC7,hell);
}
void loop(){
buttonCheck(); // alle Tasten abfragen
if(buttonEnter&(1<<1)){ // wenn Taste PA1 gedrückt an/aus
if(an){ // wenn Lüfter an
an=0;
GPIOC->ODR=0;
Serial.println("Luefter aus");
}
else{
an=1;
ausgebenStufe();
Serial.println("Luefter an");
}
}
else if(an){
if(buttonEnter&(1<<10)){ // wenn Taste PA10 gedrückt
plusLuefter();
}
if(buttonEnter&(1<<6)){ // wenn Taste PA6 gedrückt
minusLuefter();
}
}
}
ToDo: Motor mit Propeller über L293D anschließen.
Aufgaben: Analogwert von Poti an PA0 einlesen und ausgeben
Erstellen Sie ein Programm, dass den Wert von Poti mit analogRead(PA0) einliest und als Leuchtband auf LED0..6 ausgibt, LED7 soll entsprechend des Wertes mit analogWrite(..) verschieden hell leuchten. Die normale Auflösung von analogRead() ist 10 Bit, d.h. der Wertebereich ist 0..1023.
Bonus: Mit analogReadResolution(12) kann die Auflösung auf 12Bit hochgesetzt werden.
Lösungsvorschlag
void setup(){ // Einmalige Ausführung => Initialisierungen...
Serial.begin(115200); // Serielle Schnittstelle zum debuggen
pinMode(PC0, OUTPUT); // ohne diese Zeile klappts nicht
GPIOC->MODER = 0x5555; // PC0..PC7 als Ausgang
pinMode(PA1,INPUT_PULLDOWN); // Ein-Aus-Schalten
pinMode(PA6,INPUT_PULLDOWN); // minusLuefter
pinMode(PA10,INPUT_PULLDOWN); // plusLuefter
//analogWriteResolution (16); //0-65535 PWM duty cycle
//analogWriteFrequency(2000); // Set PMW period to 2000 Hz instead of 1000
//analogReadResolution(12);
pinMode(PA5,OUTPUT);
}
void ausgebenLeuchtband(int n){
GPIOC->ODR =0;
for(int i=0;i<n;i++){
GPIOC->ODR = (GPIOC->ODR<<1)+1;
}
}
void loop(){
int adWert = analogRead(PA0);
ausgebenLeuchtband(adWert/(1023/7));
int hellLED7 = adWert>>2;
analogWrite(PC7,hellLED7);
Serial.printf("AD-: %4d Helligkeit: %3d\n",adWert,hellLED7);
delay(300);
}
Erstellen Sie ein Programm, dass den Wert von Poti an PA0 einliest und zuerst einstellig und dann zweistellig auf der 7-Segmentanzeige ausgibt.
Tipp: Verwenden Sie ein Umwandungs-Array int bcd_7seg[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};
Lösungsvorschlag einstellig
void setup(){ // Einmalige Ausführung => Initialisierungen...
pinMode(PC0, OUTPUT); // ohne diese Zeile klappts nicht
GPIOC->MODER = 0x5555; // PC0..PC7 als Ausgang
pinMode(PC11,OUTPUT); // Einer
pinMode(PC12,OUTPUT); // Zehner
}
int bcd_7seg[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f}; // Umrechnung
void ausgebenSiebenSegment(int n){
GPIOC->ODR = bcd_7seg[n] | (1<<11); // Einer einschalten
}
void loop(){
int adWert = analogRead(PA0);
ausgebenSiebenSegment(adWert/(1023/9));
delay(100);
}
Lösungsvorschlag zweistellig
void setup(){ // Einmalige Ausführung => Initialisierungen...
pinMode(PC0, OUTPUT); // ohne diese Zeile klappts nicht
GPIOC->MODER = 0x5555; // PC0..PC7 als Ausgang
pinMode(PC11,OUTPUT); // Einer
pinMode(PC12,OUTPUT); // Zehner
}
int bcd_7seg[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f}; // Umrechnung
int adWert=0;
void loop(){
adWert = (analogRead(PA0)+adWert*9)/10; // Werte glätten
int aus=adWert/10;
//aus = aus>99?99:aus; // Wert begrenzen
if(aus>99) aus=99;
GPIOC->ODR = bcd_7seg[aus%10] | (1<<11); // Einer ausgeben
delay(10);
GPIOC->ODR = bcd_7seg[aus/10] | (1<<12); // Zehner ausgeben
delay(10);
}
Bonus: Temperaturwert von NTC-Widerstand an PA4 einlesen
In der Boardbeschreibung wird ein NTC-Temperaturabhängiger Widerstand [Pollin] auf Seite 5 erwähnt...
void setup(){ // Einmalige Ausführung => Initialisierungen...
pinMode(PC0, OUTPUT); // ohne diese Zeile klappts nicht
GPIOC->MODER = 0x5555; // PC0..PC7 als Ausgang
pinMode(PC11,OUTPUT); // Einer
pinMode(PC12,OUTPUT); // Zehner
analogReadResolution(12); // damit Temperatur genauer wird 12Bit
}
int bcd_7seg[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f}; // Umwandlung
float Wert = 0;
void loop(){
float R2_25 = 1500; // Widerstandswert NTC bei 25°C
float R2_theta;
float R1 = 1500; // Widerstandswert R1
float dt;
float t;
float alpha = -0.045;
Wert = (analogRead(PA4)+Wert*9)/10; // Messungen beruhigen, mitteln
R2_theta = R1*Wert/(4095-Wert);
dt = (R2_theta/R2_25-1)/alpha; // näherungsweise
t = 25+dt;
int aus = t; // in int umwandeln
GPIOC->ODR = bcd_7seg[aus%10] | (1<<11); // Einer ausgeben
delay(10);
GPIOC->ODR = bcd_7seg[aus/10] | (1<<12); // Zehner ausgeben
delay(10);
}