Hallo Leute,
ich bräuchte mal Hilfe.
Ich verwende einen Attiny 13 um mittels internem Takt und 8Bit-Timer
grob eine Zeit zu messen.
Hier verwende ich den (modifizierten) Code aus dem Tutorial:
1
ISR(TIMER0_COMPA_vect)
2
{
3
millisekunden++;
4
5
if(millisekunden==1000)
6
{
7
sekunde++;
8
sekunden5++;
9
millisekunden=0;
10
11
if(sekunden5>=5)
12
{
13
sekundenflag=1;
14
}
15
16
if(sekunde==60)
17
{
18
minute++;
19
sekunde=0;
20
}
21
if(minute==60)
22
{
23
stunde++;
24
minute=0;
25
}
26
if(stunde==24)
27
{
28
stunde=0;
29
}
30
}
31
}
Soweit so gut. Aber, ich würde gerne den Timer nutzen um nach 5 Sekunden
eine Funktion aufzurufen. Also schaffe ich mir eine Flagvariable die ich
nach 5 Sekunden auf 1 setzte, in der while abfrage, von dort meine
Funktion aufrufe und danach die Flagvariable wieder auf 0 setze. Klappt
auch soweit.
Aber nun benötige ich noch eine blinkende LED innerhalb der Funktion,
Anzahl der Blinks abhängig einer Variablen mit Leuchtdauer500ms an,
500ms aus.
Wie stelle ich das an?
Die auszuführende Funktion sieht bisher mit delays so aus:
1
voidanzahlreset(void)
2
{
3
for(i=0;i<variable;i++)
4
{
5
PORTD|=(1<<LED_RT);
6
_delay_ms(500);
7
PORTD&=~(1<<LED_RT);
8
_delay_ms(500);
9
}
10
sekundenflag=0;
11
sekunden5=0;
12
}
Die delays müssen verschwinden und sattdessen dafür auch der Timer
verwendet werden. Jemand eine Idee? Oder sogar einen konkreten
Codevorschlag?
Bau dir über einen Timer eine interne Zeitbasis - zB 500ms.
Idealerweise lädst du den Timer auch schon vor bzw setzt das
entsprechende Register so, dass der Timer alle 500ms einen Overflow von
sich aus erzeugt (siehe Timer Tutorial - deine Lösung oben ist realtiv
schlecht..)
Im Timer Overflow der dann alle 500ms ausgelöst wird kannst du dann
mehrere Funktionen als "Event Handler" aufrufen - jede enthält eine
eigene State-Maschine für seine Aktion (LED blinken, 5s Zähler, usw)
Der Vorschlag von TestX ist gut.
Ich verwende auch immer ein Zeitscheiben Prinzip. Damit wird das System
übersichtlicher und deterministisch.
Kann man auch beliebig skalieren. Ich benütze z.B. 300ms für ein Display
update.
Timer_ISR(void)
{
Time_ms++;
if(Time_ms >= 10)
{
Time_ms = 0;
Flag_10ms = 1;
Time_10ms++;
if(Time_10ms >= 10)
{
Time_10ms = 0;
Flag_100ms = 1;
//Time_100ms++;
}
}
}
main:
// 10ms Tasks
if(Flag_10ms)
{
Tue_Irgendwas();
Flag_10ms = 0;
}
// 100ms Tasks
if(Flag_100ms)
{
Tue_Irgendwas_anderes();
Tue_Irgendwas_ganzanderes();
Flag_100ms = 0;
}
Sebastian R. schrieb:> while(millisekunden < (millisekundenalt + 500));
Ein schönes Delay, was du da gebastelt hast. Allerdings geht es darum,
das ohne Delay zu machen.
Oliver S. schrieb:> In der ISR die LED nach Ablauf der gewünschten Zeit ein- bzw> ausschalten.
Das ist eine Möglichkeit.
Eine andere Möglichkeit besteht darin, ein weiteres Flag in der ISR zu
setzen und damit eine getaktete Schleife in der main laufen zu lassen.
Das braucht man sowieso andauernd. Die Schleife wird je nach Anforderung
im Millisekunden- oder 10-Millisekundentakt aufgerufen. Mit
entsprechenden Zählvariablen können dann alle mögliche Timings
realisiert werden.
Thomas E. schrieb:> Ein schönes Delay, was du da gebastelt hast. Allerdings geht es darum,> das ohne Delay zu machen.
Ich wollte noch editieren und dazuschreiben, dass es genau so blockiert
wie delay, ging aber nicht mehr.
Sebastian R. schrieb:> Ich wollte noch editieren und dazuschreiben, dass es genau so blockiert> wie delay, ging aber nicht mehr.
Nicht nur das. Es funktioniert nicht wenn millisekunden >500 ist. Dann
ist millisekundenalt + 500 >1000 und millisekunden immer
<millisekundenalt, da es bei 1000 zurückgesetzt wird. Also der
Controller trampelt dann bis in alle Ewigkeit auf der Stelle. Das macht
das übliche Delay dann doch ein wenig besser.
Thomas E. schrieb:> Sebastian R. schrieb:>> while(millisekunden < (millisekundenalt + 500));>> Ein schönes Delay, was du da gebastelt hast.
Das ist ja auch richtig. Schließlich macht es das, was der TO in seiner
Überschrift verlangt hat:
>>Attiny13 - Timer im Timer verenden> Es funktioniert nicht wenn millisekunden >500 ist. Dann> ist millisekundenalt + 500 >1000 und millisekunden immer> <millisekundenalt, da es bei 1000 zurückgesetzt wird.
Dann verendet der Timer in der ISR.
Hey Jasper,
Multitasking wäre hier wirklich schöner, aber es geht auch so.
Hoffe ich habe dich da richtig verstanden:
Du hast doch schon deine millisekunden Variable, dann kannst einfach auf
die 500ms prüfen und die LED toggeln, deine Funktion musst du dann aus
der while() ständig aufrufen:
Jasper schrieb:> Versuche mich gerade an der Lösung von TestX un den Timerinteruppt> auf 500ms zu setzen.
Ich würde den Timer auf 1ms stellen und alles weitere machst du über
deine Zeit-Variablen.
Eine LED mithilfe eines Timer-Interrupts zu steuern, ist in meinen Augen
wie: "Mit Kanonen auf Spatzen schießen".
Kein Mensch sieht ob die LED nun 1 oder 2 oder sogar 10ms später oder
früher AN oder AUS geht.
Such hier mal nach Multitasking. Es gibt einige Beispiel von Falk. Es
gibt auch konkrete Umsetzung mit vielen Beispielen dazu. Wenn du als
Basis 1ms verwendest kannst du noch viel mehr machen. Der Ansatz ist
relativ einfach. Habe auch schon Tuts dazu gesehen
Jasper schrieb:> Soweit so gut. Aber, ich würde gerne den Timer nutzen um nach 5 Sekunden> eine Funktion aufzurufen. Also schaffe ich mir eine Flagvariable die ich> nach 5 Sekunden auf 1 setzte, in der while abfrage, von dort meine> Funktion aufrufe und danach die Flagvariable wieder auf 0 setze. Klappt> auch soweit.
Eine neue Variable als Flag deklarieren, die in main eingeschaltet und
in der Funktion (oder nach Rückkehr in main) ausgeschaltet wird:
Auf diese Weise funktioniert deine Timer ISR auch weiterhin als
normale Uhr und die LED kann auch von anderen Funktionen ein- oder
ausgeschaltet werden, mit verschiedenen Frequenzen.
P.S. Wenn du die sekunden5 dekrementierst, anstatt inkrementierst,
kannst du die Einschaltzeit variabel machen etwa so:
Ja, das ist alles über die Maßen kompliziert und geheimnisvoll mit dem
Multitasking.
Füge mal folgendes zu Deiner Eine-Millisekunden-Timer-ISR hinzu
(Variablendeklarationen für m und blinkcnt bitte selbst sinngemäß
ergänzen):
1
LEDState = LSB von blinkcnt; // LSB = 0[1] --> LED aus[an]
2
3
if (blinkcnt>0)
4
{
5
m++;
6
7
if(m==500)
8
{
9
m = 0;
10
blinkcnt++;
11
12
if (blinkcnt==2*variable)
13
{
14
blinkcnt = 0;
15
}
16
}
17
}
Dann kannst Du die Blinksequenz jederzeit im Programm starten mit
1
BlinkSequenceStart:
2
{
3
m = 0;
4
blinkcnt = 1;
5
}
und auch jederzeit wieder stoppen (falls es nötig sein sollte) mit:
LEUTZ.....ernsthaft?
Es scheint so, als würde Jasper noch nicht sehr lange programmieren,
ist ja kein Problem, jeder fängt mal ganz vorne an -
aber ihm dann solche Ratschläge geben?
Eine ISR sollte so kurz wie möglich sein und nicht 1000 Funktionalitäten
enthalten.
Lasst die ISR doch einfach den Tick behandeln und alles andere ist
extern viel einfacher und sauberer.
Vllt. kommt ja gleich noch der nächste der in der main() nur
1
voidmain(void)
2
{
3
while(1);
4
}
stehen hat und alles nur über Interrupts löst...
Die Regel heißt in etwa: "Teile und herrsche" - CleanCode lässt grüßen.
Wenn er das so weiter macht, dann hat er mal ein Counter da ein hier,
einer wird per ISR geregelt der andere nicht und irgendwann sieht man
den Wald vor lauter Bäume nicht :-/
Eine gut durchdachte Struktur lässt sich einfacher programmieren als
Spaghetticode.
Sorry, aber das musste mal gesagt werden.
Adam P. schrieb:> Lasst die ISR doch einfach den Tick behandeln und alles andere ist> extern viel einfacher und sauberer.
Und du meinst im Ernst, dass die ganze Sache ohne Flags funktioniert ?
> Eine gut durchdachte Struktur lässt sich einfacher programmieren als> Spaghetticode.>> Sorry, aber das musste mal gesagt werden.
Und was hast du jetzt so weltbewegendes, neues und kluges gesagt,
bzw. womit genau hast du dem TO geholfen ?
> Wenn er das so weiter macht, dann hat er mal ein Counter da ein hier,> einer wird per ISR geregelt der andere nicht und irgendwann sieht man> den Wald vor lauter Bäume nicht :-/
Wenn er was so weiter macht ?
Wo hat er einen Counter in der ISR und wo befinden sich die anderen
ausserhalb?
Selten einen Beitrag mit so vielen leeren Sprüchen, die zudem noch
nicht mal zutreffend sind, gesehen.
Jasper schrieb:> Nach dem Tutorial wäre dass dann in meinem Fall mit 8Mhz Takt:
Du solltest gelegentlich ins Datenblatt gucken. Dann wirst du
feststellen, daß der Attiny13 mit 9,6MHz bzw. 1,2MHz läuft.