Hmmm,
wenn ich Dir die Zustandcodierung für "Idle" gebe:
Code:
#include <avr/io.h>
#include "Statemanager.h"
#include "LED.h"
#include "Started.h"
uint16_t IdleCounter;
void Idle_KeyDown(uint8_t index)
{
// NOT USED
}
void Idle_KeyUp(uint8_t index)
{
if (index == 1)
Started_Init();
}
void Idle_TimerTick()
{
IdleCounter++;
if (IdleCounter > 2000)
{
IdleCounter = 0;
ToggleLED1();
}
}
void Idle_Init()
{
IdleCounter = 0;
ClearLED1();
ClearLED2();
AttachState(Idle_KeyDown, Idle_KeyUp, Idle_TimerTick);
}
...dazu noch die Beschreibung von "Started"...
Code:
#include <avr/io.h>
#include <stdlib.h> //required for rand()
#include "Statemanager.h"
#include "LED.h"
#include "Idle.h"
uint16_t StartedCounter;
uint8_t RandomDelay;
void Started_KeyDown(uint8_t index)
{
//Mogelvorbeugung: Abbruch, wenn in diesem Zustand die Reaktionstaste gedrückt wird
if (index == 2)
Idle_Init();
}
void Started_KeyUp(uint8_t index)
{
//Mogelvorbeugung: Abbruch, wenn in diesem Zustand die Reaktionstaste gedrückt wird
if (index == 2)
Idle_Init();
}
void Started_TimerTick()
{
//LED Startsequenz
switch(StartedCounter)
{
case 0:
case 1000:
case 2000:
SetLED2();
break;
case 300:
case 1300:
ClearLED2();
break;
}
if (StartedCounter >= (2000 + RandomDelay))
{
//MeasureInit();
}
StartedCounter++;
}
void Started_Init()
{
StartedCounter = 0;
ClearLED1();
ClearLED2();
RandomDelay = rand() % 500; //0..500 ticks delay
AttachState(Started_KeyDown, Started_KeyUp, Started_TimerTick);
}
...mit folgenden Infos...
- die Beiden ähneln sich doch sehr im Aufbau, wie man unschwer erkennt.
- Jeder Status captured für sich die Eingangsdaten KeyDown/KeyUp/TimerTick durch die Anmeldung über AttachState.
- Dieses "Capture" läuft über Funktionszeiger in einem Statemanager, den Du von weiter oben auch schon teilweise kennst
(.h)
Code:
#ifndef STATEMANAGER_H_
#define STATEMANAGER_H_
// function prototypes
typedef void ( *KeyDownCallback ) ( uint8_t );
typedef void ( *KeyUpCallback ) ( uint8_t );
typedef void ( *TimerTickCallback ) ( );
void AttachState(KeyDownCallback keyDown, KeyUpCallback keyUp, TimerTickCallback timerTick);
void Statemanager_Init();
#endif /* STATEMANAGER_H_ */
(.c)
Code:
#include <avr/io.h>
#include <avr/interrupt.h>
#include "Statemanager.h"
KeyDownCallback keyDownHandler;
KeyUpCallback keyUpHandler;
TimerTickCallback timerTickHandler;
uint8_t prevPINA;
void Statemanager_Init()
{
//TODO: Init Timer to 1ms tick
prevPINA = PINA;
}
ISR (TIM0_OVF_vect)
{
//Emit Tick
if (timerTickHandler != 0)
timerTickHandler();
uint8_t actPINA = PINA; //buffer actual state
uint8_t chPINA = prevPINA ^ actPINA; //get changes with XOR
uint8_t setPINA = chPINA & actPINA; // get new set pins
uint8_t clPINA = chPINA & ~actPINA; // get new cleared pins
prevPINA = actPINA; //save actual PINA in prevPINA for next ISR call
for (uint8_t i = 0; i<8; i++)
{
if ((setPINA >>i) & 0x01)
if (keyDownHandler != 0)
keyDownHandler(i); //Emit KeyDown
if ((clPINA >>i) & 0x01)
if (keyUpHandler != 0)
keyUpHandler(i); //Emit KeyUp
}
}
void AttachState(KeyDownCallback keyDown, KeyUpCallback keyUp, TimerTickCallback timerTick)
{
keyDownHandler = keyDown;
keyUpHandler = keyUp;
timerTickHandler = timerTick;
}
...erkennst Du vielleicht, worauf ich hinaus will:
Man braucht die main nur zur Initialisierung,...
Code:
#include <avr/io.h>
#include <avr/interrupt.h>
#include "Idle.h"
#include "StateManager.h"
int main(void)
{
//TODO: PORT INIT
Statemanager_Init();
Idle_Init();
sei(); //Enable interrupts
/* Replace with your application code */
while (1)
{
}
}
…, neue States lassen sich über eine Codevorlage als Modul per C&P und anschließendem Ersetzen von "State_" durch den Statusnamen sehr schnell hinzufügen,...
Code:
#include <avr/io.h>
#include "Statemanager.h"
#include "LED.h"
void State_KeyDown(uint8_t index)
{
}
void State_KeyUp(uint8_t index)
{
}
void State_TimerTick()
{
}
void State_Init()
{
AttachState(State_KeyDown, State_KeyUp, State_TimerTick);
}
…, danach kümmert man sich nur noch um das Wesentliche (das Verhalten des States in den vorgegebenen Funktionsrahmen zu codieren).
Damit man von einem State zum Nächsten springen kann, braucht man noch jeweils einen Minimalheader:
Beispiel Started.h
Code:
#ifndef STARTED_H_
#define STARTED_H_
void Started_Init();
#endif /* STARTED_H_ */
...mickrig!
Ob das der Königsweg ist, vermag ich nicht zu sagen (Gib 100 Programmierern ein Problem und Du bekommst 100 Lösungen). Aber selbst wenn Du den Timer im 1ms-Takt laufen lässt, sind das bei 8MHz 8000 Takte. Der gesamte oben geschriebene Code nimmt als Kompilat aber nur 1kB Flash in Anspruch. Da ist also bei den berühmten 1..4 cycles per instruction der AVRs noch eine ganze Menge Luft nach oben.
Bist Du immer noch der Meinung, Du brauchst eine Übergabe der Keys in die main()?
Lesezeichen