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. Hier ein paar Anregungen:

  • Lineares Programm (Ausgaben einfach runter programmieren)
  • Mit Unterprogramm blink(int zeit)
  • Mit Unterprogrammen dit(), dah()
  • Zählschleife verwenden
  • Mit Unterprogramm blink(int zeit, int anzahl)
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);
}

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
// 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
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…

Zeiten mit Oszilloskop messen

Wie schnell kann ausgegeben werden? Die LED an D13 (PA5) so schnell wie möglich blinken lassen.
Das Signal mit einem Digital-Oszilloskop messen. (Bin hier im Paradies, hab ein Analog Discovery Studio)

Analog_Discovery_Studio
Analog_Discovery_Studio
Hameg_HM507
Hameg_HM507
Siglent_SDS1152CML
Siglent_SDS1152CML

In der Schule haben wir Hameg und Siglent Oszis.

Mit digitalWrite() Pin-Zustand ändern

#define Board_LED D13

void setup(){   // Einmalige Ausführung => Initialisierungen...
    pinMode(Board_LED, OUTPUT);  // Pin als Ausgang
}
void loop(){
    digitalWrite(Board_LED,HIGH);
    digitalWrite(Board_LED,LOW);
}
Messung mit einfachen Strippen
Messung mit einfachen Strippen
Messung mit Tastkopf
Messung mit Tastkopf

Ein richtiger Oszi-Tastkopf ergibt sauberere Signale als bei Verwendung einfacher Strippen, wenn die Frequenz höher wird.
Durch die digitale Messwerterfassung lassen sich Werte für die Dauer des positiven-, negativen Pegels und der Frequenz des Signals sofort anzeigen. Zwischen High und Low vergehen 1,4µs, zwischen Low und High 2,2µs warum?
Die loop() braucht für irgendwelche Arbeit etwas Zeit, neuer Versuch mit while(1):

#define Board_LED D13

void setup(){   // Einmalige Ausführung => Initialisierungen...
    pinMode(Board_LED, OUTPUT);  // Pin als Ausgang
}
void loop(){
  while(1){
    digitalWrite(Board_LED,HIGH);
    digitalWrite(Board_LED,LOW);
  }  
}
Messung mit While statt Loop
Messung mit While statt Loop

Yeah, wir werden schneller! Aber da geht noch was: Direkt auf das PortA zugreifen und das Bit 5 im ODR massieren:

Mit GPIOA->ODR die Hardware direkter ansprechen

Die Arduino-Funktion digitalWrite(..) ermöglicht einzelne Port-Pins einfach zu verändern. Das kostet allerdings Zeit durch interne Umrechnungen von Arduino-Bezeichnung des Pins zu passender Adresse und Bits des Ziel-Controllers. Wie Sie aus TG11 Assembler schon wissen wird im ODR (Output Data Register) des Ports die Ausgabe-Bitwerte für die Port-Pins gespeichert. Wenn PA5 als Ausgang 1 sein soll muss im ODR an Bit5 eine 1 stehen. Wenn ich nur PA5 auf 1 setzen will sollte ich die anderen Bits in Ruhe lassen. Mit GPIOA->ODR |= (1<<5) lade ich das ODR von PortA, mit |= (1<<5) setze ich an Bit5 eine 1 und schreibe den Wert ins ODR zurück. (1<<5) ist eine 1 5 mal nach links schieben also
(1<<5) ergibt 0b100000. Zum Rücksetzen von PA5 lade ich ODR und sorge mit einem bitweisen und mit einer 0 an Position 5 dafür dass PA0 wieder 0 wird.

void setup(){   // Einmalige Ausführung => Initialisierungen...
    pinMode(PA5, OUTPUT);  // Pin als Ausgang
}
void loop(){
  while(1){
    GPIOA->ODR |= (1<<5);  // PA5 <-1
    GPIOA->ODR &= ~(1<<5); // PA5 <-0
  }  
}
Direkter Port-Zugriff
Direkter Port-Zugriff

Menno, der Auto-Set des Oszis spinnt, zeigt nur Mist an, denke zuerst, ich habe Mist programmiert.
Dann aber manuell die Messzeit eingestellt und:
Wow, über sechs mal schneller, die Flanken werden flacher, das Messen kommt an Grenzen?
Geht da noch was? Noch schneller “Blinken”?
Statt den Port erst ein zu lesen und dann wieder neu zu setzen mit |= und &= gibt es noch ein BSRR-Register (Bit-Set-Reset-Register). Dabei werden die Bits im Ausgaberegister mit einem Maschinenbefehl direkt verändert:

Mit GPIOA->BSRR noch schneller werden

Statt ODR zu laden, zu verändern und wieder zu speichern gibt es ein Spezialregister BSRR (Bit Set Reset Register). Wenn dort in Position 0..15 eine 1 reingeschrieben wird ist im ODR an dieser Position eine 1 gesetzt, die Ausgabe an dem PortPin wird 1. Um ein Bit in der Position n zurück zu setzen, Reset, muss an Stelle 16+n eine 1 geschrieben werden. Unten das Beispiel für PA5 (D13):

void setup(){   // Einmalige Ausführung => Initialisierungen...
    pinMode(PA5, OUTPUT);  // Pin als Ausgang
}
void loop(){
  while(1){
    GPIOA->BSRR = (1<<5);    // PA5 <-1 mit BSRR können Bits gesetzt werden
    GPIOA->BSRR = (1<<16+5); // PA5 <-0 die oberen 16Bit sind fürs Rücksetzen
  }  
}
BSRR verwenden
BSRR verwenden

Irre, beinnahe drei mal schneller, das Oszi kommt noch gut hinterher bei 6,4 MHz!
Wir sind bei 30ns Befehlszeit zwischen an und aus, der Rück-Sprung in der While-Schleife braucht halt etwas…
Fazit: 6,4 MHz vs. 278 kHz: 23 mal schnellere Signale wenn hardwarenah programmiert wird.
Diskutieren Sie die Vor- und Nachteile bei der Programmentwicklung hardwarenah zu arbeiten versus die Arduino-Methoden zu verwenden.

Ausführungszeiten von Unterprogrammen und später Interrupt Service Routinen (ISR) mit Oszi messen können

Wie genau ist delay(500)?

#define zeit 500

void setup(){   // Einmalige Ausführung => Initialisierungen...
    pinMode(Board_LED, OUTPUT);  // Pin als Ausgang
}
void loop(){
  while(1){
    GPIOA->BSRR = (1<<5);    // PA5 <-1
    delay(zeit);
    GPIOA->BSRR = (1<<16+5); // PA5 <-0
    delay(zeit);
  }  
}
delay(500)
delay(500)
delay(1)
delay(1)

Okay, recht genau. Zum Spass wollen wir uns mal ein eigenes Delay basteln:

#define zeit 1000

void setup(){   // Einmalige Ausführung => Initialisierungen...
    pinMode(Board_LED, OUTPUT);  // Pin als Ausgang
}
//int a=0; // bei globaler Definition scheint kein volatile nötig
void myDelay(int n){ // mein Delay
  volatile int a=0;  // volatile bedeutet veränderlich
  for(int i=0;i<n;i++){
    a=!a; // in der Schleife muss es was zu tun geben
  }
}
void loop(){
  while(1){
    GPIOA->BSRR = (1<<5);    // PA5 <-1
    myDelay(zeit);
    GPIOA->BSRR = (1<<16+5); // PA5 <-0
    myDelay(zeit);
  }  
}
myDelay
myDelay

War das eine Geburt, der Compiler optimiert sinnlose Befehlssequenzen weg, z.B. einfach Hochzählen ohne dabei was zu verändern. Die Variable a zu invertieren sollte eine Aufgabe sein. Allerdings muss sie dazu entweder global definiert werden oder mit volatile als veränderlich gekennzeichnet sein. Probieren Sie es aus!
Bonus: Verbessern Sie myDelay() so, dass die Zeit stimmt.

Lösungsvorschlag
#define Board_LED D13
#define zeit 1000

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

void myDelay(int n){
  volatile int a=0;
  for(int i=0;i<n*2905;i++){
    a=!a;
  }
}
void loop(){
  while(1){
    GPIOA->BSRR = (1<<5);    // PA5 <-1
    myDelay(zeit);
    GPIOA->BSRR = (1<<16+5); // PA5 <-0
    myDelay(zeit);
  }  
}

Brummen und Prellen messen

Das Oszi ist noch warm, also noch ein paar Messungen damit machen. Den Tastkopf in A1 stecken, dort ist die Taste an PA1 angeschlossen. Dieses Programm ausführen und mit dem Finger die Leitung A1 berühren.

#define Board_LED D13 // PA5

void setup(){   // Einmalige Ausführung => Initialisierungen...
    pinMode(Board_LED, OUTPUT);  // Pin als Ausgang
    pinMode(PA1,INPUT);
}
void loop(){
  digitalWrite(Board_LED,digitalRead(PA1));
}
50 Hz Brummen macht der Finger
50 Hz Brummen macht der Finger

Wir wirken wie eine Antenne für die 50Hz Netzspannung, also mit dem “Finger-Test” lässt sich rausfinden ob ein Eingang “hochohmig” also kein Pullup- oder Pulldown-Widerstand eingeschaltet ist. Jetzt INPUT_PULLDOWN einstellen und mal schauen ob der Taster an PA1 prellt:

Tasterprellen entdeckt
Tasterprellen entdeckt

Musste das Oszi auf Single-Shot umstellen und ein wenig rumprobieren bis mir diese Aufnahme gelungen ist.
150µs prellt es hier.

Tastenprellen beim Loslassen
Tastenprellen beim Loslassen


Richtig übel kann das Prellen beim Loslassen der Taste werden, wie lange ist es im Bild oben?
Zum Abschluss noch den blauen User-Button an PC13 auf dem Nucleo-Board analysieren: Aha mit PullUp-Widerstand verbunden, ist High, Fingertest erzeugt kein Brummen. Scheint sogar elektrisch entprellt zu sein.
Idee für Hardcore-Bonusaufgabe: Software, die Prellen aufzeichnet, und auf dem seriellen Plotter ausgibt..

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 der Lüfterstufen entwickelt. Die Lüfterstufen 1..4 werden durch ein LED-Leuchtband PC0..PC3 angezeigt. 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.
Um sich den Code (8 Zeilen mit pinMode(..) ) zum Festlegen von PC0..PC7 als Ausgang für die LEDs zu sparen hat sich der faule IT-Lehrer sein Wissen über das Mode-Register zu nutze gemacht:
GPIOC->MODER = 0x5555; // PC0..PC7 als Ausgang
Ob und wie ein Port-Pin als Ausgang verwendet wird steht im MODER drin. Kann ja auch ohne Arduino-Zeug festgelegt werden.. Leider muss wenigstens ein pinMode(PC0, OUTPUT) im Quellcode rein sonst ging es nicht.. Wieso 0x5555 und nicht 0xFF könnte noch gefragt werden. Ja, so ein Pin kann Eingang oder Ausgang mit entweder OpenDrain oder PushPull sein. Also den Pin nach unten ziehen OpenDrain (OpenCollector) oder nix machen oder nach unten ziehen Pull -> 0 oder nach oben Push -> 1 liefern. Somit ergibt sich pro PortPin mehr als zwei Möglichkeiten Eingang, OpenDrain, PushPull. Folglich braucht es 2 Bit im ModeR pro Pin.
Dieser Test-Quellcode ist schon gegeben:

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
    GPIOC->ODR = 0xff;     // PC0..PC7 einschalten
    delay(500);
    GPIOC->ODR = 0;        // PC0..PC7 ausschalten
    pinMode(PA1,INPUT_PULLDOWN);  // Ein-Aus-Schalten
    pinMode(PA6,INPUT_PULLDOWN);  // minusLuefter
    pinMode(PA10,INPUT_PULLDOWN); // plusLuefter
}

void plusLuefter(){
  Serial.println("plusLuefter");
  if(GPIOC->ODR<0b1000){ // wenn noch nicht Stufe 4
    GPIOC->ODR = (GPIOC->ODR<<1)+1;
  }
}

void loop(){
  if(digitalRead(PA10)){ // wenn Taste PA10 gedrückt
    plusLuefter();
    delay(2); // Entprellen
    while(digitalRead(PA10)); // warten bis Taste losgelassen
    delay(2); // Entprellen
  }
}

Entwickeln Sie das vollständige Programm.
Bonus: Eine Status-LED ob der Lüfter an ist wäre wünschenswert. LED7 an PC7 soll dafür genutzt 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
    GPIOC->ODR = 0xff;   // PC0..PC7 einschalten
    delay(500);
    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 plusLuefter(){
  Serial.println("plusLuefter");
  if(stufe<0b1000){ // wenn noch nicht Stufe 4
    stufe = (stufe<<1)+1;
  }
  GPIOC->ODR = stufe | an<<7;
}
void minusLuefter(){
  Serial.println("minusLuefter");
  if(stufe>0){ // wenn noch nicht Stufe 0
    stufe = stufe>>1;
  }
  GPIOC->ODR = stufe | an<<7;
}
void loop(){
  if(digitalRead(PA1)){ // 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<<7;
      Serial.println("Luefter an");
    }
    delay(2); // Entprellen
    while(digitalRead(PA1)); // warten bis Taste losgelassen
    delay(2); // Entprellen
  }
  else if(an){
    if(digitalRead(PA10)){ // wenn Taste PA10 gedrückt
      plusLuefter();
      delay(2); // Entprellen
      while(digitalRead(PA10)); // warten bis Taste losgelassen
      delay(2); // Entprellen
    }
    if(digitalRead(PA6)){ // wenn Taste PA6 gedrückt
      minusLuefter();
      delay(2); // Entprellen
      while(digitalRead(PA6)); // warten bis Taste losgelassen
      delay(2); // Entprellen
    }
  }
}

Bessere Tastenabfrage mit buttonCheck()

Das Abfragen und Entprellen mehrerer Tasten müsste doch eleganter als oben 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.
Hier der Beispielcode:

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
    pinMode(PC8, OUTPUT);         // Pin als Ausgang
}

#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
  buttonCheck();  // alle Tasten abfragen
  GPIOC->BSRR = (1<<16+8); // PC8 <-0
  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<<7;  // Betriebs-LED an
      Serial.println("Luefter an");
    }
  }
}

Messen Sie die 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.

Entprellen mit buttonCheck
Entprellen mit buttonCheck

Wieder so ein übles Nachprellen 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<<7;
}
void minusLuefter(){
  Serial.println("minusLuefter");
  if(stufe>0){ // wenn noch nicht Stufe 0
    stufe = stufe>>1;
  }
  GPIOC->ODR = stufe | an<<7;
}
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<<7;
      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();
    }
  }
}

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht.