1.3 Zustandsdiagramm
Benötigte Hilfsmittel: TGI-Formelsammlung, Software Umlet, Anleitung zu Umlet:
Zustandsdiagramm für Lüftersteuerung
PA1 | PA6 | PA10 |
---|---|---|
An <-> Aus | langsamer | schneller |
Ein Lüfter soll mit den Tasten PA1 (An/Aus) PA6 (Lüfter langsamer) und PA10 (Lüfter schneller) gesteuert werden. Es gibt 4 Lüfterstufen 0..3. Bei Stufe 0 leuchtet nur LC0 an PC0 als Betriebsanzeige.
Die letzte Lüfterstufe soll beim Ausschalten gemerkt werden und beim Anschalten wieder eingestellt sein. Bei ausgeschaltetem Lüfter leuchtet keine LED und die Taster PA6 und PA10 sind ohne Funktion.
Bei der Verwendung von digitalRead(..) müsste Prellen berücksichtigt und auf das Loslassen der Tasten gewartet werden. Deshalb steht die Funktion buttonCheck() zur prellfreien Erkennung von Tastenbetätigungen zur Verfügung.
Stufe | PC3 | PC2 | PC1 | PC0 |
---|---|---|---|---|
Aus | 0 | 0 | 0 | 0 |
Stufe 0 | 0 | 0 | 0 | 1 |
Stufe 1 | 0 | 0 | 1 | 1 |
Stufe 2 | 0 | 1 | 1 | 1 |
Stufe 3 | 1 | 1 | 1 | 1 |
Aufzählungsdatentyp enum
Die Zustände müssen codiert werden. Der Quellcode ist besser lesbar wenn statt Zahlen 0,1… für zustand aussagekräftige Namen vergeben werden. Mit dem Aufzählungsdatentyp enum ist dies möglich. Es kann sogar ein eigener wiederverwendbarer Datentyp mittels typedef definiert werden. Die Symbole {AN,AUS} sollten aber Groß geschrieben werden.
enum {AUS,AN} zustand=AUS; // Aufzaehlungstyp
//typedef enum {AUS,AN} ZustandTyp; // Aufzaehlungstyp
//ZustandTyp zustand;
Möglicher Code für Zustandsdiagramm der Lüftersteuerung
void setup() {
pinMode(PC0,OUTPUT);
pinMode(PC1,OUTPUT);
pinMode(PC2,OUTPUT);
pinMode(PC3,OUTPUT);
pinMode(PA1,INPUT_PULLDOWN);
pinMode(PA6,INPUT_PULLDOWN);
pinMode(PA10,INPUT_PULLDOWN);
}
#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;
}
}
}
enum {AUS,AN} zustand=AUS; // Aufzaehlung der Zustände
int stufe = 0;
void ausgebenStufe(){ // Luefterstufen als Leuchtband ausgeben
int ausgabe=1;
for(int i=0; i<stufe; i++){
ausgabe = (ausgabe<<1)+1;
}
GPIOC->ODR = ausgabe;
}
void ausschaltenLED(){
GPIOC->ODR = 0;
}
void minusLuefter(){
if(stufe>0) stufe--;
}
void plusLuefter(){
if(stufe<3) stufe++;
}
void loop() {
buttonCheck();
switch (zustand){. // je nach Zustand
case AUS: // Zustand Aus
if(buttonEnter&(1<<1)){ // PA1 gedrueckt?
ausgebenStufe();
zustand = AN;
}
break;
case AN: // Zustand An
if(buttonEnter&(1<<1)){ // PA1 gedrueckt?
ausschaltenLED();
zustand = AUS;
}
if(buttonEnter&(1<<6)){ // PA6 gedrueckt?
minusLuefter();
ausgebenStufe();
}
if(buttonEnter&(1<<10)){ // PA10 gedrueckt?
plusLuefter();
ausgebenStufe();
}
break;
}
}
Lösung verschönern mit #define
Es gibt noch “hässliche” Ausdrücke wie buttonEnter&(1<<1) im Projekt. Vor dem Kompilieren kann der C-Prä-Prozessor Texte ersetzen. Z.B T_ANAUS durch buttonEnter&(1<<1). D.h. wir könnten das Zustandsdiagramm und das Programm damit lesbarer machen! Hier mein Vorschlag: Das T_ steht für Taste. Die Ersetzungen sollten Groß geschrieben werden.
#define T_ANAUS buttonEnter&(1<<1)
#define T_LANGSAMER buttonEnter&(1<<6)
#define T_SCHNELLER buttonEnter&(1<<10)
Verschönern Sie das Zustandsdiagramm und den Quellcode damit!
Lösung Zustandsdiagramm
Lösung Programmcode
void setup() {
pinMode(PC0,OUTPUT);
pinMode(PC1,OUTPUT);
pinMode(PC2,OUTPUT);
pinMode(PC3,OUTPUT);
pinMode(PA1,INPUT_PULLDOWN);
pinMode(PA6,INPUT_PULLDOWN);
pinMode(PA10,INPUT_PULLDOWN);
}
#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;
}
}
}
#define T_ANAUS buttonEnter&(1<<1)
#define T_LANGSAMER buttonEnter&(1<<6)
#define T_SCHNELLER buttonEnter&(1<<10)
enum {AUS,AN} zustand=AUS; // Aufzaehlungstyp
int stufe = 0;
void ausgebenStufe(){ // Luefterstufen ausgeben
int ausgabe=1;
for(int i=0; i<stufe; i++){
ausgabe = (ausgabe<<1)+1;
}
GPIOC->ODR = ausgabe;
}
void ausschaltenLED(){
GPIOC->ODR = 0;
}
void minusLuefter(){
if(stufe>0) stufe--;
}
void plusLuefter(){
if(stufe<3) stufe++;
}
void loop() {
buttonCheck();
switch (zustand){
case AUS: // Zustand Aus
if(T_ANAUS){ // AnAus gedruekt?
ausgebenStufe();
zustand = AN;
}
break;
case AN: // Zustand An
if(T_ANAUS){ // Taste AnAus gedruekt?
ausschaltenLED();
zustand = AUS;
}
if(T_LANGSAMER){ // Taste langsamer gedrueckt?
minusLuefter();
ausgebenStufe();
}
if(T_SCHNELLER){ // Taste schneller gedrueckt?
plusLuefter();
ausgebenStufe();
}
break;
}
}
Lösung verschönern mit isEnter()
Wem die #define -Lösung nicht gefällt könnte sich ja eine Hilfsfunktion isEnter(n:int):boolean wobei n die Pin-Nummer des Tasters ist ausdenken:
boolean isEnter(int n){
return buttonEnter&(1<<n);
}
Einschalten auch mit Tasten PA6 und PA10
Der Lüfter soll nun auch mit den Tasten PA6 und PA10 eingeschaltet werden können. Modifizieren Sie das Zustandsdiagramm und das Programm entsprechend, verwenden Sie diesmal isEnter() zur Tastenabfrage.
Lösung Zustandsdiagramm
Autoblinker
PA1 | PA6 | PA10 |
---|---|---|
Nach links | Nach rechts | Warnblinker |
Wenn PA1 gedrückt wird soll sich ein Leuchtband von LC0 bis LC7 aufbauen mit Zeitabstand LEUCHTDAUER. Bei Betätigen von PA6 wird das Leuchtband von LC7 bis LC0 aufgebaut. Solange PA10 gedrückt ist sollen alle LED blinken mit Zeitabstand BLINKDAUER.
Diesmal wird die Arduino-Funktion digitalRead(..) verwendet. Hier Code und Zustandsdiagramm zum Start:
void setup() {
pinMode(PC0, OUTPUT); // ohne diese Zeile klappts nicht
GPIOC->MODER = 0x5555; // PC0..PC7 als Ausgang
pinMode(PA1,INPUT_PULLDOWN);
pinMode(PA6,INPUT_PULLDOWN);
pinMode(PA10,INPUT_PULLDOWN);
}
enum {AUS,LINKS,RECHTS,WARNBLINKEN} zustand=AUS; // Aufzaehlungstyp
#define LEUCHTDAUER 70
#define BLINKDAUER 400
Wenn alle Tasten gedrückt werden sollte der Warnblinker Vorrang haben.
Entwickeln Sie aus dem Zustandsdiagramm den restlichen Code. Bin gespannt ob das Experiment klappt 🤠.
Lösung Programmcode
void setup() {
pinMode(PC0, OUTPUT); // ohne diese Zeile klappts nicht
GPIOC->MODER = 0x5555; // PC0..PC7 als Ausgang
pinMode(PA1,INPUT_PULLDOWN);
pinMode(PA6,INPUT_PULLDOWN);
pinMode(PA10,INPUT_PULLDOWN);
}
enum {AUS,LINKS,RECHTS,WARNBLINKEN} zustand=AUS; // Aufzaehlungstyp
#define LEUCHTDAUER 70
#define BLINKDAUER 400
void loop() {
switch (zustand){
case AUS: // Zustand Aus
delay(BLINKDAUER);
if(digitalRead(PA1)){ // Links blinken?
zustand = LINKS;
}
if(digitalRead(PA6)){ // Rechts blinken?
zustand = RECHTS;
}
if(digitalRead(PA10)){ // Warnblinken?
zustand = WARNBLINKEN;
}
break;
case LINKS: // Zustand Links
if(GPIOC->ODR>=0xff){ // Alle leuchten?
zustand = AUS;
GPIOC->ODR = 0;
}
else{
GPIOC->ODR = (GPIOC->ODR<<1)+1;
delay(LEUCHTDAUER);
}
break;
case RECHTS: // Zustand rechts
if(GPIOC->ODR>=0xff){ // Alle leuchten?
zustand = AUS;
GPIOC->ODR = 0;
}
else{
GPIOC->ODR = (GPIOC->ODR>>1)+0x80;
delay(LEUCHTDAUER);
}
break;
case WARNBLINKEN: // Zustand Warnblinken
GPIOC->ODR = 0xff;
delay(BLINKDAUER);
GPIOC->ODR = 0;
zustand = AUS;
break;
}
}
Warum ist ein Entprellen diesmal nicht notwendig?
UpDown-Zähler mit 7Segmentanzeige
Mit den Tasten PA6 (Up) und PA1 (Down) soll eine Zahl auf der 7-Segmentanzeige ausgegeben werden.
Beim Eintritt in den Chillen-Zustand muss wegen enter/ausgeben() ausgeben() aus den Transitionen setup(), von StufeUp und StufeDown aufgerufen werden. Kriegt man das eleganter hin, ohne ausgebenEiner() drei mal aufrufen zu müssen? Wie wäre es mit einem Zustand CHILLEN_ENTER, der dann in den Zustand CHILLEN wechselt?
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
pinMode(PA1,INPUT_PULLDOWN);
pinMode(PA6,INPUT_PULLDOWN);
}
int bcd_7seg[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f}; // Umrechnung
int stufe=0;
void ausgebenEiner(){
GPIOC->ODR = bcd_7seg[stufe] | (1<<11); // Einer einschalten
}
enum {CHILLEN_ENTER,CHILLEN,STUFEUP,STUFEDOWN} zustand=CHILLEN_ENTER;
void loop(){
switch(zustand){
case CHILLEN_ENTER:
ausgebenEiner();
zustand = CHILLEN;
break;
case CHILLEN:
if(digitalRead(PA6) && stufe<9){
stufe++;
zustand = STUFEUP;
delay(5); // Entprellen
}
if(digitalRead(PA1) && stufe>0){
stufe--;
zustand = STUFEDOWN;
delay(5); // Entprellen
}
break;
case STUFEUP:
if(!digitalRead(PA6)){
zustand = CHILLEN_ENTER;
delay(5);
}
break;
case STUFEDOWN:
if(!digitalRead(PA1)){
zustand = CHILLEN_ENTER;
delay(5);
}
break;
}
}
Zweistellige Ausgabe
Die Segmentanzeigen werden im Zeitmultiplex betrieben. Einerstelle ausgeben, warten, Zehnerstelle ausgeben, warten und wieder von vorne und das die ganze Zeit. Ersetze enter/ausgebenEiner() durch do/ausgeben().
#define AZEIT 20 // 20ms Stelle anzeigen, Flackern ist sichtbar
void ausgeben(){
GPIOC->ODR = bcd_7seg[stufe%10] | (1<<11); // Einer einschalten
delay(AZEIT);
GPIOC->ODR = bcd_7seg[stufe/10] | (1<<12); // Zehner einschalten
delay(AZEIT);
}
Beim Drücken einer Taste bleibt die Ausgabe allerdings stehen. Auch bei StufeUp und StufeDown sollte ausgegeben werden.
Da es eh für alle Zustände gilt, kann ausgeben() auch vor der Switch-Anweisung aufgerufen werden.
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
pinMode(PA1,INPUT_PULLDOWN);
pinMode(PA6,INPUT_PULLDOWN);
}
int bcd_7seg[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f}; // Umrechnung
int stufe=0;
#define AZEIT 10
void ausgeben(){
GPIOC->ODR = bcd_7seg[stufe%10] | (1<<11); // Einer einschalten
delay(AZEIT);
GPIOC->ODR = bcd_7seg[stufe/10] | (1<<12); // Zehner einschalten
delay(AZEIT);
}
enum {CHILLEN,STUFEUP,STUFEDOWN} zustand=CHILLEN;
void loop(){
ausgeben();
switch(zustand){
case CHILLEN:
if(digitalRead(PA6) && stufe<99){
stufe++;
zustand = STUFEUP;
delay(5); // Entprellen
}
if(digitalRead(PA1) && stufe>0){
stufe--;
zustand = STUFEDOWN;
delay(5); // Entprellen
}
break;
case STUFEUP:
if(!digitalRead(PA6)){
zustand = CHILLEN;
delay(5);
}
break;
case STUFEDOWN:
if(!digitalRead(PA1)){
zustand = CHILLEN;
delay(5);
}
break;
}
}
Garagentorsteuerungssimulation
Die Simulation einer Garagentorsteuerung sollen Sie entwickeln. Der Zustand des Tors wird durch Leuchtband L0..L6 angezeigt. Wenn das Tor auf ist, leuchtet nur L0, ist es zu ist leuchten L0..L6. L7 soll später blinken, wenn sich das Tor bewegt. Zunächst wird nur der Schlüsselschalter mit PA1 (zu) und PA6 (auf) und L0..L6 berücksichtigt.


PA1 | PA6 | PA10 |
---|---|---|
Zu | Auf | Handsender |
Teil 1: Schlüsselschalter steuert Tor, noch kein Blinken und kein Handsender
Die Taster sind nicht entprellt! Durch Betätigen von PA1 fährt das Tor zu, ein kurzes Betätigen reicht, um die Fahrt in Gang zu setzen. Dabei wird in der Simulation nach der Zeit LEUCHTDAUER jeweils eine weitere LED eingeschaltet, bis L0..L6 leuchten, dann stoppt das Tor. Entsprechend der Ablauf zum Öffnen des Tors mit PA6. Wird während des Laufs der Schalter in die Gegenrichtung bewegt, stoppt das Tor auch. Hier ein wenig Quelltext-Vorgabe:
int tor = 1;
enum {STOPP,ZU,AUF} zustand=STOPP; // Aufzaehlungstyp
#define LEUCHTDAUER 300
void setup() {
pinMode(PC0, OUTPUT); // ohne diese Zeile klappts nicht
GPIOC->MODER = 0x5555; // PC0..PC7 als Ausgang
pinMode(PA1,INPUT_PULLDOWN); // Zu
pinMode(PA6,INPUT_PULLDOWN); // Auf
pinMode(PA10,INPUT_PULLDOWN);// Handsender
GPIOC->ODR = tor;
}
void loop() {
}
Erstellen Sie ein Zustandsdiagramm und entwickeln Sie daraus das Programm. Verwenden Sie zunächst digitalRead(). Ich bin auf Ihre Lösungen gespannt!
Naives Zustandsdiagramm
Naiver Code dazu
int tor = 1;
enum {STOPP,ZU,AUF} zustand=STOPP; // Aufzaehlungstyp
#define LEUCHTDAUER 300
void setup() {
pinMode(PC0, OUTPUT); // ohne diese Zeile klappts nicht
GPIOC->MODER = 0x5555; // PC0..PC7 als Ausgang
pinMode(PA1,INPUT_PULLDOWN); // Zu
pinMode(PA6,INPUT_PULLDOWN); // Auf
pinMode(PA10,INPUT_PULLDOWN);// Handsender
GPIOC->ODR = tor;
}
void loop() {
switch (zustand){ // in Abhaengigkeit des Zustands
case STOPP:
if(digitalRead(PA1)){ // Zu?
zustand=ZU;
}
if(digitalRead(PA6)){ // Auf?
zustand=AUF;
}
break;
case ZU:
if(digitalRead(PA6) || tor>=0b1000000){ // Auf oder Tor zu
zustand=STOPP;
}
else{ // do Aktionen
tor = (tor<<1) + 1;
GPIOC->ODR = tor;
delay(LEUCHTDAUER);
}
break;
case AUF:
if(digitalRead(PA1) || tor<=0b1){ // Zu oder Tor offen
zustand=STOPP;
}
else{ // do Aktionen
tor = tor>>1;
GPIOC->ODR = tor;
delay(LEUCHTDAUER);
}
break;
}
}
Bei meinen naiven Lösungsvorschlägen wurde das Prellen der Tasten nicht beachtet, sehen Sie eine Auswirkung?
Teil 2: Handsender verwenden können
Durch Betätigen von PA10 (Handsender) soll das Tor in den jeweils nächsten Zustand schalten:
ZU->STOPP->AUF->STOPP->ZU->STOPP usw.
Um das Prellen in den Griff zu kriegen und eine “schönere” Lösung zu erhalten ist dieser Code-Schnipsel vorgegeben. Erweitern Sie Ihr Zustandsdiagramm entsprechend und testen Sie ihre Lösung.
#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(7); // 7ms 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;
}
}
}
#define T_ZU (buttonEnter&1<<1) // PA1
#define T_AUF (buttonEnter&1<<6) // PA6
#define T_HAND (buttonEnter&1<<10) // PA10
typedef enum {STOPP,ZU,AUF} ZustandTyp; // Aufzaehlungstyp
ZustandTyp zustand = STOPP;
ZustandTyp letzteRichtung = ZU;
Mögliches Zustandsdiagramm
Teil 3: Besser reagieren und mit Blinken
Zwei Dinge sollen besser werden, durch das Delay für die Leuchtdauer werden manche Tastendrücke nicht wahr genommen. Beim Lauf des Tors soll L7 blinken. Ein Unterprogramm fahren() soll L7 mit 100ms Delay umschalten und nach 4 Zyklen jeweils eine LED des Leuchtbandes ein- bzw. ausschalten. Modifizieren Sie das Zustandsdiagramm und entwickeln Sie die Lösung.
Mögliches Zustandsdiagramm
Möglicher Quellcode
int tor = 1;
#define LEUCHTDAUER 100
void setup() {
pinMode(PC0, OUTPUT); // ohne diese Zeile klappts nicht
GPIOC->MODER = 0x5555; // PC0..PC7 als Ausgang
pinMode(PA1,INPUT_PULLDOWN); // Zu
pinMode(PA6,INPUT_PULLDOWN); // Auf
pinMode(PA10,INPUT_PULLDOWN);// Handsender
GPIOC->ODR = tor;
}
#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(7); // 7ms 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;
}
}
}
#define T_ZU (buttonEnter&1<<1) // PA1
#define T_AUF (buttonEnter&1<<6) // PA6
#define T_HAND (buttonEnter&1<<10) // PA10
typedef enum {STOPP,ZU,AUF} ZustandTyp; // Aufzaehlungstyp
ZustandTyp zustand = STOPP;
ZustandTyp letzteRichtung = ZU;
void fahren(){
static int blinken =0;
blinken++;
if(blinken%4==0){
if(zustand == ZU){
tor = (tor<<1) + 1;
}
else{
tor = tor>>1;
}
GPIOC->ODR = tor;
}
if(blinken%2) GPIOC->BSRR = 1<<7;
else GPIOC->BSRR = 1<<7+16;
delay(LEUCHTDAUER);
}
void loop() {
buttonCheck();
switch (zustand){ // in Abhaengigkeit des Zustands
case STOPP:
if(T_ZU){ // Zu?
zustand=ZU;
}
if(T_AUF){ // Auf?
zustand=AUF;
}
if(T_HAND){
if(letzteRichtung==ZU){
zustand=AUF;
letzteRichtung=AUF;
}
else{
zustand=ZU;
letzteRichtung=ZU;
}
}
break;
case ZU:
if(T_HAND || T_AUF || tor>=0b1000000){ // Auf oder Tor zu
zustand=STOPP;
GPIOC->BSRR = 1<<7+16; // L7 aus
}
else{ // do Aktionen
fahren();
}
break;
case AUF:
if(T_HAND || T_ZU || tor<=0b1){ // Zu oder Tor offen
zustand=STOPP;
GPIOC->BSRR = 1<<7+16; // L7 aus
}
else{ // do Aktionen
fahren();
}
break;
}
}