Forum: Mikrocontroller und Digitale Elektronik stateMachine


von Fragender (Gast)


Angehängte Dateien:

Lesenswert?

Hallo zusammen

Im Moment bin ich dabei eine stateMachine zu programmieren und hätte es 
wie im Bild oben dargestellt vor zu tun. Leider bin ich gerade dabei mir 
langsam die Zähne auszubeissen, weil ich nicht weiss, was mein Fehler 
ist.
Das Programm macht sich nämlich selbständig und schaltet zwischen den 
States ab und zu hin und her. (Debugger)

Es stehen mir 2 Touchkeys zur Verfügung, die mir dabei helben das 
Programm in die jeweiligen Zustände zu versetzen.
Touchkey 1 -> TK1
Touchkey 2 -> TK2

Ich habe nach der Initialisierung 3 Zustände, bei denen ich solange 
warten möchte, bis ein Touchkey betätigt wird.
Standby, SetTemp und Locked

Die Realisierung habe ich folgendermassen vollzogen, aber ich sehe 
leider nicht, wo sich mein Programmier- oder Denkfehler befindet. Ich 
hoffe sehr, dass mir hier jemand behilflich sein kann und hoffe, dass 
ich alles Notwendige hinzugefügt bzw. beschrieben habe.
Um nicht zu verwirren, habe ich nur das Notwendigste eingefügt
1
void acquireTouchkeys(void)
2
{
3
  // Touchkey 1
4
  if((TOUCHKEY1 <= SWITCHING_THRESHOLD_LOCK_UNPRESSED) & tscLockButtonPressed)
5
  {
6
    tscLockButtonPressed = false;
7
  }
8
  
9
  if((touchkey1>= SWITCHING_THRESHOLD_LOCK_PRESSED) & !tscLockButtonPressed)
10
  {
11
    tscLockButtonPressed = true;
12
    
13
    if((taskState == SET_TARGETTEMP) & tscLockButtonPressed)
14
    {
15
      taskState = BEEP;
16
      nextTaskState = SHOW_SIGN;
17
      lock = true;
18
      unlock = false;    
19
    }else if((taskState == LOCKED) & tscLockButtonPressed)
20
     {
21
       taskState = BEEP;
22
       nextTaskState = SHOW_SIGN;
23
       lock = false;
24
       unlock = true;
25
     }
26
  }
27
  
28
  // Touchkey2
29
  if((TOUCHKEY2 <= SWITCHING_THRESHOLD_PWR_UNPRESSED) & tscPowerButtonPressed)
30
  {
31
    tscPowerButtonPressed = false;
32
  }
33
  
34
  if((touchkey2>= SWITCHING_THRESHOLD_PWR_PRESSED) & !tscPowerButtonPressed)
35
  {
36
    tscPowerButtonPressed = true;
37
    
38
    // power on
39
    if((taskState == STANDBY) & tscPowerButtonPressed)
40
    {
41
      taskState = BEEP;  
42
      nextTaskState = SET_TARGETTEMP;                      
43
 
44
    }else if(((taskState == SET_TARGETTEMP) || (taskState == LOCKED)) & tscPowerButtonPressed)
45
      {
46
        taskState = BEEP;
47
        nextTaskState = SEND_TARGETTEMP; 
48
      }
49
  }
50
}

Innerhalb der while im Main
1
    switch(taskState)    
2
    {
3
      case SET_TARGETTEMP:
4
           
5
              handleTouchkeys();                              
6
  
7
      break; 
8
      case SEND_TARGETTEMP:
9
             if(oldTaskState == BEEP)
10
             {
11
               taskState = STANDBY;
12
             }else
13
              { 
14
                taskState = LOCKED;
15
              }
16
      break;
17
      case LOCKED: 
18
             handleTouchkeys();
19
20
      break;
21
      case STANDBY:
22
             handleTouchkeys();
23
       }
24
      break;
25
      case BEEP:
26
            BUZZER_beep(msgBeepTimes, msgBuzzerBeep_ms); 
27
            oldTaskState = taskState;                               
28
            taskState = nextTaskState;
29
      break;
30
      case SHOW_SIGN:
31
             oldTaskState = taskState;                              
32
             if(lock)
33
             {
34
                 taskState = SEND_TARGETTEMP;                         
35
                 nextTaskState = LOCKED;  
36
                 
37
               }     
38
             }
39
             
40
             if(unlock)
41
             {
42
                 taskState = SET_TARGETTEMP;                         
43
                 nextTaskState = 100;          
44
               }  
45
             }
46
      break;
47
  
48
      default:
49
              ;
50
      break;      
51
    }

von Falk B. (falk)


Lesenswert?

Fragender schrieb:

> Das Programm macht sich nämlich selbständig und schaltet zwischen den
> States ab und zu hin und her. (Debugger)

Vermutlich hat deine Tastenauswertung eine Macke.

> Es stehen mir 2 Touchkeys zur Verfügung, die mir dabei helben das
> Programm in die jeweiligen Zustände zu versetzen.
> Touchkey 1 -> TK1
> Touchkey 2 -> TK2

Schön. Du mußt die Dinger aber entsprechend auswerten und die Flanke 
(berührt/nicht berührt) dekodieren. Dieser Information geht dann an 
deine FSM, welche nach Auswertung der Flanke diese löscht. Damit 
verhindert man eine Mehrfachauswertung.

> Ich habe nach der Initialisierung 3 Zustände, bei denen ich solange
> warten möchte, bis ein Touchkey betätigt wird.
> Standby, SetTemp und Locked

Einfach.

Deine Tastenauswertung muss IMMER ausgeführt werden, nicht nur in 
bestimmten Zuständen. Diese liefert dann die entprellten und dekodierten 
Tastenereignisse. Siehe

https://www.mikrocontroller.net/articles/Entprellung#Komfortroutine_.28C_f.C3.BCr_AVR.29

In der FSM werden die Tastenergebnisse ausgewertet und danach GELÖSCHT! 
Das fehlt bei dir.

von Fragender (Gast)


Lesenswert?

Falk B. schrieb:
> Fragender schrieb:
>
>> Das Programm macht sich nämlich selbständig und schaltet zwischen den
>> States ab und zu hin und her. (Debugger)
>
> Vermutlich hat deine Tastenauswertung eine Macke.
>
>> Es stehen mir 2 Touchkeys zur Verfügung, die mir dabei helben das
>> Programm in die jeweiligen Zustände zu versetzen.
>> Touchkey 1 -> TK1
>> Touchkey 2 -> TK2
>
> Schön. Du mußt die Dinger aber entsprechend auswerten und die Flanke
> (berührt/nicht berührt) dekodieren. Dieser Information geht dann an
> deine FSM, welche nach Auswertung der Flanke diese löscht. Damit
> verhindert man eine Mehrfachauswertung.
>
>> Ich habe nach der Initialisierung 3 Zustände, bei denen ich solange
>> warten möchte, bis ein Touchkey betätigt wird.
>> Standby, SetTemp und Locked
>
> Einfach.
>
> Deine Tastenauswertung muss IMMER ausgeführt werden, nicht nur in
> bestimmten Zuständen. Diese liefert dann die entprellten und dekodierten
> Tastenereignisse. Siehe
>
> 
https://www.mikrocontroller.net/articles/Entprellung#Komfortroutine_.28C_f.C3.BCr_AVR.29
>
> In der FSM werden die Tastenergebnisse ausgewertet und danach GELÖSCHT!
> Das fehlt bei dir.

Guten Morgen Falk

Vielen Dank für deine Hinweise.
Noch bevor ich darauf eingehe, möchte ich vorerst noch eine Frage 
stellen, da ich die Vermutung habe, dass das Problem noch irgendwo 
anders liegt und zwar ist es so, dass ich beim Programmstart
taskState = STANDBY;
nextTaskState= DEFAULT
oldTaskState = DEFAULT setze.

Im Betrieb dann stelle ich die Temperatur ein und sehe zu wie das Gerät 
vor sich hin arbeitet. Die States sind dann:
taskState = LOCKED;
nextTaskState = LOCKED;
oldTaskState = SHOW_SIGN;

Das würde ja soweit passen.
Aber auf einmal stellt das Gerät ab und geht in den Standby Modus.
Die States sind dann wieder wie am Anfang,
taskState = STANDBY;
nextTaskState= DEFAULT
oldTaskState = DEFAULT
obwohl das nicht sein kann, weil ich ja die States vor allem 
oldTaskState und nextTaskState im Programm immer auf irgend einem Wert 
habe. Da ist doch noch irgend etwas anderes nicht richtig am Laufen.

von Stefan F. (Gast)


Lesenswert?

Ich würde mehrere BEEP Tasks verwenden, die jeweils den nextTaskState 
hard-codiert enthalten. Das wäre einfacher zu überblicken.

von C. U. (chriull)


Lesenswert?

Fragender schrieb:
> obwohl das nicht sein kann, weil ich ja die States vor allem
> oldTaskState und nextTaskState im Programm immer auf irgend einem Wert
> habe. Da ist doch noch irgend etwas anderes nicht richtig am Laufen.

Falls diese Werte nur bei nach der Initialisierung auftreten können, 
könnte es ja sein, das sie wieder Initialisiert wurden.

Hast du schon ausgeschlossen dass dein uC neu startet? (Problem in der 
Hardware, Watchdog, Brown Out, etc...)

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

Fragender schrieb:
> if((TOUCHKEY1 <= SWITCHING_THRESHOLD_LOCK_UNPRESSED) &
> tscLockButtonPressed)

Fragender schrieb:
> if((touchkey1>= SWITCHING_THRESHOLD_LOCK_PRESSED) &
> !tscLockButtonPressed)

Fragst du da wirklich zwei verschiedene 'TOUCHKEY1' bzw. 'touchkey1' ab? 
Gross- und Kleinschreibung spielt bei so gut wie allen Compilern eine 
Rolle.

von Falk B. (falk)


Lesenswert?

Fragender schrieb:

> anders liegt und zwar ist es so, dass ich beim Programmstart
> taskState = STANDBY;
> nextTaskState= DEFAULT
> oldTaskState = DEFAULT setze.

Wozu brauchst du nextTaskState und oldTaskState? Das braucht man im 
Normalfall nicht. Ich glaube du machst die Sache zu kompliziert.

> Aber auf einmal stellt das Gerät ab und geht in den Standby Modus.
> Die States sind dann wieder wie am Anfang,
> taskState = STANDBY;
> nextTaskState= DEFAULT
> oldTaskState = DEFAULT

Klingt nach einem Reset. Der kann durch die Hardware erzeugt werden 
(Brown Out, Störung) oder durch Software (Sprung in nichtvorhandene 
ISR), Stack Overflow etc.

von Fragender (Gast)


Lesenswert?

Christian U. schrieb:

> Hast du schon ausgeschlossen dass dein uC neu startet? (Problem in der
> Hardware, Watchdog, Brown Out, etc...)

Hallo Christian

Ja, das vermute ich auch leider irgendwie, dass er selbständig resettet.
Ich habe noch keinen Watchdog implementiert.

Matthias S. schrieb:
> Fragender schrieb:
>> if((TOUCHKEY1 <= SWITCHING_THRESHOLD_LOCK_UNPRESSED) &
>> tscLockButtonPressed)
>
> Fragender schrieb:
>> if((touchkey1>= SWITCHING_THRESHOLD_LOCK_PRESSED) &
>> !tscLockButtonPressed)
>
> Fragst du da wirklich zwei verschiedene 'TOUCHKEY1' bzw. 'touchkey1' ab?
> Gross- und Kleinschreibung spielt bei so gut wie allen Compilern eine
> Rolle.

Hallo Matthias
Nein, das kommt deshalb, weil mein Code hier so verschoben war und ich 
versehentlich Teile des ifs gelöscht habe.
Dann habe ich es von Hand offensichtlich "alles falsch klein" 
geschrieben.

Falk B. schrieb:
> Fragender schrieb:
>
>> anders liegt und zwar ist es so, dass ich beim Programmstart
>> taskState = STANDBY;
>> nextTaskState= DEFAULT
>> oldTaskState = DEFAULT setze.
>
> Wozu brauchst du nextTaskState und oldTaskState? Das braucht man im
> Normalfall nicht. Ich glaube du machst die Sache zu kompliziert.

Ich würde es mir auch gerne ersparen, wie wäre es einfacher?
Für jeden Ablauf vom Dauerzustand zB STANDBY oder LOCKED eigene States?

>> Aber auf einmal stellt das Gerät ab und geht in den Standby Modus.
>> Die States sind dann wieder wie am Anfang,
>> taskState = STANDBY;
>> nextTaskState= DEFAULT
>> oldTaskState = DEFAULT
>
> Klingt nach einem Reset. Der kann durch die Hardware erzeugt werden
> (Brown Out, Störung) oder durch Software (Sprung in nichtvorhandene
> ISR), Stack Overflow etc.

Wie prüfe ich einen Brown Out, oder Sprung in nichtvorhandene ISR?
Ich kann das ja nicht einfach debuggen?

Stefanus F. schrieb:
> Ich würde mehrere BEEP Tasks verwenden, die jeweils den
> nextTaskState
> hard-codiert enthalten. Das wäre einfacher zu überblicken.

Klingt gut, das versuche ich auch mal.

von Falk B. (falk)


Lesenswert?

Fragender schrieb:
> Christian U. schrieb:
>
>> Hast du schon ausgeschlossen dass dein uC neu startet? (Problem in der
>> Hardware, Watchdog, Brown Out, etc...)
>
> Hallo Christian
>
> Ja, das vermute ich auch leider irgendwie, dass er selbständig resettet.
> Ich habe noch keinen Watchdog implementiert.

Den braucht man meistens eher nicht!

> Nein, das kommt deshalb, weil mein Code hier so verschoben war und ich
> versehentlich Teile des ifs gelöscht habe.
> Dann habe ich es von Hand offensichtlich "alles falsch klein"
> geschrieben.

Eben sowas macht man NIEMALS! Code NIE abtippen sondern das unveränderte 
Original senden. Sei es als Ausschnitt oder meist besser als 
Dateianhang. Siehe Netiquette.

>> Wozu brauchst du nextTaskState und oldTaskState? Das braucht man im
>> Normalfall nicht. Ich glaube du machst die Sache zu kompliziert.
>
> Ich würde es mir auch gerne ersparen, wie wäre es einfacher?

Sicher.

> Für jeden Ablauf vom Dauerzustand zB STANDBY oder LOCKED eigene States?

Warum nicht? Die kosten kein Geld, bringen aber gute Struktur.

> Wie prüfe ich einen Brown Out,

Dafür gibt es ein Reset-Register, wo die Reset-Quellen drinstehen.

> oder Sprung in nichtvorhandene ISR?

Das ergibt je nach Compiler meist eine stillstehenden CPU oder Reset.

> Ich kann das ja nicht einfach debuggen?

Warum nicht?

von Fragender (Gast)


Lesenswert?

Falk B. schrieb:

>
>> Für jeden Ablauf vom Dauerzustand zB STANDBY oder LOCKED eigene States?
>
> Warum nicht? Die kosten kein Geld, bringen aber gute Struktur.

Na dann passe ich das an.


>
>> Wie prüfe ich einen Brown Out,
>
> Dafür gibt es ein Reset-Register, wo die Reset-Quellen drinstehen.

Ich hätte jetzt einfach einmal gemessen, ob der Controller die 3.3V 
durchgehend hat um so den Brown Out festzustellen.

Ich habe vorher nämlich im Datenblatt RM0091 schon nachgesehen, aber 
eine Brown Out detection hat dieser Controller offensichtlich nicht. 
Daher wüsste ich jetzt nicht in welchem Register ich nachsehen muss.
Ich habe den APB peripheral reset register 1 und 2.
>
>> oder Sprung in nichtvorhandene ISR?
>
> Das ergibt je nach Compiler meist eine stillstehenden CPU oder Reset.
>
>> Ich kann das ja nicht einfach debuggen?
>
> Warum nicht?

Debuggen schon, aber wie stelle ich fest wo er gerade ist, wenn es die 
ISR nicht gibt. Ich kann keinen STOP Punkt hinzufügen dort wo nichts 
ist.

von Falk B. (falk)


Lesenswert?

Fragender schrieb:

>> Dafür gibt es ein Reset-Register, wo die Reset-Quellen drinstehen.
>
> Ich hätte jetzt einfach einmal gemessen, ob der Controller die 3.3V
> durchgehend hat um so den Brown Out festzustellen.

Da muss man aber mit einem Oszi messen.

> Ich habe vorher nämlich im Datenblatt RM0091 schon nachgesehen, aber

Nun ja, bis jetzt kannten WIR deinen Controller nicht, ich hab 
instinktiv auf AVR getippt. Klappt halt nicht immer ;-)

> Debuggen schon, aber wie stelle ich fest wo er gerade ist,

Wenn man im Debugger Pause drückt, sieht man, wo die CPU gerade steht.

von Fragender (Gast)


Lesenswert?

Falk B. schrieb:
> Fragender schrieb:
>
>>> Dafür gibt es ein Reset-Register, wo die Reset-Quellen drinstehen.
>>
>> Ich hätte jetzt einfach einmal gemessen, ob der Controller die 3.3V
>> durchgehend hat um so den Brown Out festzustellen.
>
> Da muss man aber mit einem Oszi messen.

Das hätte ich vorgehabt ;)

>
>> Ich habe vorher nämlich im Datenblatt RM0091 schon nachgesehen, aber
>
> Nun ja, bis jetzt kannten WIR deinen Controller nicht, ich hab
> instinktiv auf AVR getippt. Klappt halt nicht immer ;-)
>
>> Debuggen schon, aber wie stelle ich fest wo er gerade ist,
>
> Wenn man im Debugger Pause drückt, sieht man, wo die CPU gerade steht.

Ich habe im Keil bisher keinen Pausebutton gefunden. :)

Ich danke dir und allen anderen vorerst einmal. Ich werde die paar 
Änderungen vornehmen und mich wieder rückmelden, wenn es mir gestattet 
ist.

Grüsse

von Jim M. (turboj)


Lesenswert?

Fragender schrieb:
> Ich habe im Keil bisher keinen Pausebutton gefunden. :)


Hast Du einen Debugger oder einen reinen Programmieradapter angesteckt? 
Die ARM µCs haben eigentlich hervorragende Debugging Möglichkeiten.

Übrigens ist die Groß- und Kleinschreibung in Deinen Touchkey Funktionen 
höchst verdächtig.

von Fragender (Gast)


Lesenswert?

Hallo zusammen

Ich habe inzwischen die states abgeändert und für jeden Ablauf eigene 
hart programmierte Zustände erstellt.
Auch wenn es so nun funktioniert und das andere wesentlich 
unübersichtlicher war, frage ich mich dennoch, warum die andere Version 
mit dem taskState = nextTaskState eigentlich nicht funktioniert hat. Die 
Zustände müssten demnach trotzdem definierte Zustände sein, ala wenn das 
und das der Fall ist nextTaskState = x, wenn das und das nextTaskState = 
y.
Warum das Programm dann hin und her springt ist mir noch nicht ganz so 
klar.

Wegen des Resets habe ich mal die steigende Flanke der 
uC-Versorgungsspannung gemessen und einen entsprechenden Kondensator 
gegen GND an den RESET pin angeschlossen.   (RC-Glied am NRST)
Mal sehen, ob so der Reset auch von selbst kommt. Das sollte das Problem 
eigentlich lösen.

von Fragender (Gast)


Lesenswert?

Jim M. schrieb:
> Fragender schrieb:
>> Ich habe im Keil bisher keinen Pausebutton gefunden. :)
>
> Hast Du einen Debugger oder einen reinen Programmieradapter angesteckt?
> Die ARM µCs haben eigentlich hervorragende Debugging Möglichkeiten.

Programmieradapter ST-Link, über diesen debugge ich das Ganze.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.