Hallo Zusammen, ich möchte über einen Timerinterrupt alle 100ms drei 74HC595 Schieberegister mit Daten befüllen. Wie könnte ich das mit einem der beiden 8 Bit Timer lösen? Alles was ich bisher dazu gefunden habe, benutzt dafür den 16 Bit Timer. Den kann ich aber nicht nutzen, weil ich per SoftwareSerial ein Modul steuern muss. Oder kann trotzdem der Timer 2 dafür verwendet werden? Der Arduino läuft mit 16Mhz. Das Problem ist also, einen Timerinterrupt zu erstellen der alle 100ms eine Aktion auslöst und nur einen 8 Bit Timer dafür zu verwenden. Liebe Grüße aus Hessen, Sebastian
Wenn der Timer mit größtmöglichem Vorteiler nicht auf 100ms kommt, wirst du halt in der ISR noch einen Softwarezähler einbauen müssen. Oliver
:
Bearbeitet durch User
Danke für die schnellen Antworten. :D @Oliver Das mit dem Softwarezähler hatte ich mir auch schon überlegt. Mir fehlt ein bisschen der Ansatz, wie ich den Timer passend initalisiere und dann nochmal einen Softwarezähler einbaue. Etwa so? (ist etwas zusammengeklaut...)
1 | void setup() { |
2 | cli(); //stop interrupts |
3 | //set timer0 interrupt at 1kHz
|
4 | TCCR0A = 0; // set entire TCCR0A register to 0 |
5 | TCCR0B = 0; // same for TCCR0B |
6 | TCNT0 = 0; //initialize counter value to 0 |
7 | // set compare match register for 1khz increments
|
8 | OCR0A = 249; // = (16*10^6) / (1000*64) - 1 (must be <256) |
9 | // turn on CTC mode
|
10 | TCCR0A |= (1 << WGM01); |
11 | // Set CS01 and CS00 bits for 64 prescaler
|
12 | TCCR0B |= (1 << CS01) | (1 << CS00); |
13 | // enable timer compare interrupt
|
14 | TIMSK0 |= (1 << OCIE0A); |
15 | sei(); //allow interrupts |
16 | int teiler = 0; |
17 | }
|
18 | |
19 | ISR(TIMER0_COMPA_vect) |
20 | {
|
21 | teiler++; // Teiler um 1 erhöhen |
22 | // Wenn Teiler 100 dann Code ausführen
|
23 | if (teiler == 100) { |
24 | //.. Code um das Schieberegister zu füllen ..
|
25 | teiler = 0; // Teiler zurück auf 0 setzen |
26 | }
|
27 | }
|
@Tommy An millis() hatte ich noch gar nicht gedacht. Das könnte auch eine Option sein. Da müsste man nur im loop() schauen, ob 100 oder mehr Ticks durch sind... Danke nochmals und schönen Abend noch. Sebastian
@Sebastian V. (n8falter74) >ich möchte über einen Timerinterrupt alle 100ms drei 74HC595 >Schieberegister mit Daten befüllen. Kann man machen. > Wie könnte ich das mit einem der >beiden 8 Bit Timer lösen? Kann man. >Das Problem ist also, einen Timerinterrupt zu erstellen der alle 100ms >eine Aktion auslöst und nur einen 8 Bit Timer dafür zu verwenden. Un das ist jetzt sooo schwer? Hast du dich schon mal ANSATZWEISE mit einem Timer beschäftigt? Wieviele CPU-Takte vergehen in 100ms bei 16 MHz? Wie oft läuft in der Zeit ein 8 Bit Zähler über? Welche Rolle spielt der Hardware-Vorteiler? Denk mal drüber nach . . .
Vorteiler: 256. F_CPU : 256 : 10 = Zählwert für deinen Timer, damit dieser alle 100ms Interrupt generiert. Bei 16MHz wäre das ein Wert von 6250.
> Un das ist jetzt sooo schwer? Hast du dich schon mal ANSATZWEISE mit > einem Timer beschäftigt? > > Wieviele CPU-Takte vergehen in 100ms bei 16 MHz? > > Wie oft läuft in der Zeit ein 8 Bit Zähler über? > > Welche Rolle spielt der Hardware-Vorteiler? > > Denk mal drüber nach . . . Hallo Falk, etwas habe ich mich schon mit Timern beschäftigt. Nachdem ich nicht weitergekommen bin, habe ich hier freundlich um Hilfe gebeten. Bei 16 Mhz würde ich von 1,6 Mio CPU Takten in 100ms ausgehen. Ein 8 Bit Zähler läuft dabei 6250 mal über. Mit den Prescalern 64 256 1024 komme ich nur auf krumme Werte. Wenn das Problem für Dich so einfach ist, kannst Du mir sicher auch mit einem vernünftigen Tipp helfen. :) Lieben Gruß aus Hessen Sebastian
Leg doch deine software uart auf nen 8bit timer. Soo niedrige baudraten das der dafür nicht reicht, wirst du wohl kaum haben. Alternativ, bau dir ne clock mit clockticks, und zähl die.
Moin, 16MHz sind 0,0625µs pro Takt. Vorteiler 1024 macht 64µs pro Überlauf bei 8 Bit. 64us_counter definiert als 16bit unsigned Timer0_isr: Inrc 64us_counter If 64us_counter = 1562 then ...mach alle 100ms was 64us_counter = 0 End if Return Fertig. Das geht 32µs falsch, was 0,032% entspricht. Da das genau einen halben Zähler falsch ist, könnte man das auf Null bekommen (mit dem Fehler als Jitter), wenn man bei jedem Treffer der If-Abfrage zwischen 1562 und 1563 wechselt. Gruß, Norbert
:
Bearbeitet durch User
@ Sebastian V. (n8falter74) >etwas habe ich mich schon mit Timern beschäftigt. Das hat man in deinem ersten Beitrag aber nicht gesehen. Da will der geneigte Leser/Helfende schon mal sehen, was der Fragende gedacht und ggf. gerechnet hat. >Bei 16 Mhz würde ich von 1,6 Mio CPU Takten in 100ms ausgehen. >Ein 8 Bit Zähler läuft dabei 6250 mal über. >Mit den Prescalern 64 256 1024 komme ich nur auf krumme Werte. Welche denn?? N = F_CPU Vorteiler ISR-Frequenz = 16 MHz 1024 10 Hz = 1562,5 Ein 8 Bit Zähler ist bei 10 Hz halt trotz Vorteiler zu klein. 10 Hz sind für einen uC auch eher langsam. 100-1000 Hz sind da eher üblich, kleinere Frequenzen macht man wie bereits gesagt über einen weiteren Softwareteiler. Bei 100 Hz wäre eine Zählerperiode von 156,25 korrekt. Das passt zwar in 8 Bit, aber nicht die Nachkommastellen. Also eher was pragmatisches. Nutzte den CTC Modus des Timer 2 mit 156 als Periode. Das ist nur einen Tick schneller als 100 Hz, hier ist das unkritisch, du baust ja keine Uhr. Wenn doch, dann so. AVR - Die genaue Sekunde / RTC
@falk @norberts Danke für Eure Antworten. Im Post Beitrag "Re: Arduino 8Bit Timer für 100ms Intervall verwenden" habe ich eine Timer0 Initalisierung, die ich im Internet gefunden habe, von 2 kHz auf 1 kHz abgeändert. In der ISR zähle ich dann eine Variable bis auf 100 hoch und führe dann jeweils den Code aus, der alle 100ms laufen soll. Ich habe das noch nicht testen können. Aber das entspricht ja eigentlich dem, was ihr beide mir vorgeschlagen habt. Allerdings habe ich irgendwo gelesen, dass das Verändern von globalen Variablen in einer ISR problematisch ist. Habt ihr das schon so in einem Projekt umgesetzt? Grüße aus Hessen Sebastian
@Sebastian V. (n8falter74) >eine Timer0 Initalisierung, die ich im Internet gefunden habe, von 2 kHz >auf 1 kHz abgeändert. In der ISR zähle ich dann eine Variable bis auf >100 hoch und führe dann jeweils den Code aus, der alle 100ms laufen >soll. Ist OK. >Allerdings habe ich irgendwo gelesen, dass das Verändern von globalen >Variablen in einer ISR problematisch ist. Nur wenn man es falsch macht. Außerdem muss die Variable teiler nicht global sein, sie kann auch statisch lokal sein. Dann gibt es erst recht keine komischen Nebeneffekte.
1 | ISR(TIMER0_COMPA_vect) |
2 | {
|
3 | static uint8_t teiler; |
4 | |
5 | teiler++; // Teiler um 1 erhöhen |
6 | // Wenn Teiler 100 dann Code ausführen
|
7 | if (teiler == 100) { |
8 | //.. Code um das Schieberegister zu füllen ..
|
9 | teiler = 0; // Teiler zurück auf 0 setzen |
10 | }
|
11 | }
|
https://www.mikrocontroller.net/articles/Interrupt#Interruptfeste_Programmierung > Habt ihr das schon so in einem Projekt umgesetzt? Unzählige Mal. ;-)
Sebastian V. schrieb: > Allerdings habe ich irgendwo gelesen, dass das Verändern von globalen > Variablen in einer ISR problematisch ist. Wieso? Jede Information zwischen ISR und anderen Programmteilen wird über globale Variablen ausgetauscht. Sie muss nur als 'volatile' gekennzeichnet werden und wenn sie länger ist als der Prozessor in einem Schritt verarbeiten kann, dann müssen für die Operationen außerhalb der ISR die Interrupts gesperrt werden (Stichwort atomic).
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.