Die Softwarestruktur eines uC-Programms sollte so aussehen, dass alle "üblichen" Arbeiten in einer Hauptschleife ausgeführt werden. Interrupt-Rotuinen setzen "nur" Flags oder verwalten FIFOs.
Zeiten können elegant über eine Struktur (ti) verwaltet werden, die eine Systemzeit (ti.Akt) und andere Aktionszeiten bzw. Triggerzeiten enthält.
#include <avr/io.h>
#include <avr/interrupt.h>
#include <stdint.h>
//...
volatile uint32_t gtiAkt;
typedef {
uint32_t Akt; // Systemzeit in ms
uint32_t Start;
uint32_t Stop;
uint32_t Event;
// usw...
} tiStruct;
tiStruct ti;
// Timer-Compare Interrupt ISR, wird z.B. alle 10ms ausgefuehrt
ISR(TIMER1_COMPA_vect)
{
//...
gtiAkt+=10;
//...
}
int main(void)
{
//...
uint_32t *tiptr;
//...
cli(); // Interupts deaktivieren
ti.Akt = gtiAkt; // Zeit atomar abholen
sei(); // Ints wieder aktivieren
if(ti.Akt&0xC0000000) { // Zeitstempel laufen an die Obergrenze
tiptr = (uint_32t*)(ti); // von jedem Zeitstempel Offset abziehen
for(char i=0; i<sizeof(ti)/sizeof(uint32_t); tiptr++)
*tiptr-=0x80000000;
}
// Start-Zeitpunkt erreicht
if(ti.Akt>ti.Start) {
run = 1;
ti.Start = ti.Akt + 100000;
ti.Stop = ti.Akt + 1000;
}
// Stop-Zeitpunkt erreicht
if(ti.Akt>ti.Stop) {
run = 0;
ti.Start = ti.Akt + 2000;
ti.Stop = ti.Akt + 100000;
}
// Zeit für Port-Pin low
if (PortPin) ti.Event = ti.Akt;
lowtime = ti.Akt-ti.Event; // zählt hoch, solange Portpin low
//...
}
Hier wird in einer Interruptroutine ein Millisekunden-Zähler hochgezählt und als Zeitbasis auf eine globale Struktur abgebildet. Auf diese systemweit einmalige Zeit werden dann alle lokalen Zeiten bezogen. Bei einem drohenden Überlauf wird von allen Zeiten in der ti-Struktur ein Offset abgezogen.