Folgendes Problemchen habe ich:
in tiner Interruptroutine wird ein Systemtimer im Millisekundentakt
erhöht:
1
uint32_tSystime=0;
2
3
SIGNAL(SIG_OUTPUT_COMPARE2)
4
{
5
Systime++;
6
}
wenn ich jetzt eine Wartefunktion ins Programm einbaue:
1
waitTime=Systime+500;// 500ms
2
3
while(Systime<waitTime);
kann es ja passieren, dass der Vergleich nicht funktioniert, wenn
Systime einmal übergelaufen ist, d.h. wieder von 0 angefangen hat zu
zählen.
Wie würdet ihr diese Problem lösen?
chris schrieb:
> kann es ja passieren, dass der Vergleich nicht funktioniert, wenn> Systime einmal übergelaufen ist, d.h. wieder von 0 angefangen hat zu> zählen.>> Wie würdet ihr diese Problem lösen?
Indem ich zuallererst ausrechne wie lange es dann eigentlich dauert, bis
ein 32-Bit Wert der jede Millisekunde erhöht wird überläuft :-)
chris schrieb:
> kann es ja passieren, dass der Vergleich nicht funktioniert, wenn> Systime einmal übergelaufen ist, d.h. wieder von 0 angefangen hat zu> zählen.
Ja, das ist die klassische Fallgrube, das hatten sogar mal
Windowsprogrammierer verpennt. Ein älteres Windows mußte nach xx Tagen
neu gestartet werden.
> Wie würdet ihr diese Problem lösen?
Mit der Differenzmethode. Differenzen stimmen immer, auch bei einem
Überlauf.
1
tmp_time=sys_time;
2
while((sys_time-tmp_time)<TIMEOUT);
Zusätzlich gibts aber noch das Atomicity-Problem, wenn die CPU < 32bit
ist.
Und das volatile Problem.
Peter
>Indem ich zuallererst ausrechne wie lange es dann eigentlich dauert, bis>ein 32-Bit Wert der jede Millisekunde erhöht wird überläuft :-)
Da passt die Antwort von Peter doch wunderbar:
>Ja, das ist die klassische Fallgrube, das hatten sogar mal>Windowsprogrammierer verpennt. Ein älteres Windows mußte nach xx Tagen>neu gestartet werden.
soviel zum ausrechnen.
>Atomicity-Problem
Ich nehme an, Du meinst den Interrupt, der möblicherweise beim Vergleich
dazwischenfunkt. D.h. sollte man vermutlich den Interrupt während des
Vergleiches sperren, also
Uhh ...
danke für Deine Hilfe ...
<util\atomic.h>
kannte ich ja noch gar nicht. Bringt es einen Vorteil gegenüber
1
cli();sei();
2
[/sei]
3
?
4
5
Beimcompilierenvon
6
7
[c]staticinlineuint32_tSystime(void)
ergibt sich bei mir
../time.c:14: error: static declaration of 'Systime' follows non-static
declaration
Warum sollte man die Funktion statisch deklarieren? Ich dachte, bei der
Verwendung von "inline" wird ohnehin der Funktionsinhalt an die
ensprechende Stelle des "calls" eingebaut.
>Es war nach 49,71026963 Tagen:>http://support.microsoft.com/kb/216641/EN-US/
Super, ich glaube das sind die Fehler, mit denen auch Raketen abstürzen
;-)
chris schrieb:
> ergibt sich bei mir>> ../time.c:14: error: static declaration of 'Systime' follows non-static> declaration
Wenn dein Programm noch irgendwelche Ähnlichkeiten mit dem
Ursprungsposting hat, dann hast du da auch noch eine Variable namens
Systime.
> Warum sollte man die Funktion statisch deklarieren? Ich dachte, bei der> Verwendung von "inline" wird ohnehin der Funktionsinhalt an die> ensprechende Stelle des "calls" eingebaut.
Schon.
Aber durch das static weiß der Compiler, dass diese Funktion aussrhalb
dieses *.c Files nirgends benutzt werden kann. Er muss daher auch keine
Funktion dafür erzeugen, selbst wenn der Funktionsinhalt innerhalb
dieses Files überall geinlined wird.
> Super, ich glaube das sind die Fehler, mit denen auch Raketen abstürzen> ;-)
Eine Rakte braucht selten 49 Tage, bis sie vom Boden aus ihre
Einsatzhöhe erreicht hat. Normalerweise ist das in ~15 Minuten
abgeschlossen, die Raktenstufe ist ausgebrannt und wird nicht mehr
benutzt. Und damit wäre ein derartiger Überlauf rein hypotetischer Natur
und man muss sich keine Sorgen machen. Wenn es allerdings eine einfache
Möglichkeit gibt, das Problem gar nicht erst entstehen zu lassen, wie
mit der Differenzmethode, gibt es auch keinen Grund die nicht zu
verwenden. Selbst wenn der Fall nie eintreten wird, weil das Gerät gar
nicht lang genug eingeschaltet ist.
Also für Wartefunktionen setze ich immer die Zeit als Wert ein und lass
den vom Interrupt runterzählen bis 0(aber nicht weiter). Damit gabs noch
nie Probleme.
Hier für 8(16) unabhängige Timer
typedef struct
{u16 en;
u32 c[8];
}sys_counters_t;
if (IRQSIG & RTOS_TIMER_BIT){// Timer 0 Interrupt jede ms
T0CLRI = 1; // ClearTimer0Interrupt
//SW-Timer decrementieren
for(tmp=0;tmp<8;tmp++){
if(sys_counters.en&(0x01<<tmp))if(sys_counters.c[tmp]!=0)
sys_counters.c[tmp]--;
}
//Funktionen zum Setzen/Lesen/Aktivieren
u32 tw_read(u8 cntr_nr)
{
return sys_counters.c[cntr_nr];
}
void tw_set(u8 cntr_nr,u32 value)
{
sys_counters.c[cntr_nr]=value;
}
void tf_set(u8 cntr_nr)
{
sys_counters.en |= (0x0001<<cntr_nr);
}
Wenn ich in eier State-Maschine eine Verzögerung brauche, oder ein
Timeout überwachen will dann
tw_set(2,100);//100ms
tf_set(2);//Zähler läuft
.
.
.
.
if((count=tw_read(2))!=0);//noch nicht abgelaufen
Grüße
chris schrieb:
> Hi geb,>> deine Lösung gefällt mir gut. Vielleicht sollte man daraus mal eine> eigene Libray machen.
Vorsicht.
Die Interruptlast ist natürlich höher, auch wenn kein Timer aktiv ist.
Bitzugriffe und besonders das variable Schieben sind beim AVR nämlich
aufwendig.
Und die Systemzeit hochzählen braucht man meistens trotzdem noch (z.B.
für Uhrzeit, Datum).
Beim "tw_read" fehlt wieder der atomare Zugriff.
Und eigentlich bei den Timern auch das volatile.
Aber es scheint, daß das ATOMIC_BLOCK-Macro implizit den Zugriff
volatile macht.
Im Unterschied zum cli/sei !
Peter