Hallo, bin zwar nicht ganz neu, aber ich hab meine Probleme mit den Timern. Ich verwende 3 Timer. Timer 0 wird fuer eine PWM benutzt. Timer 1 wird fuer Tastenabfrage und Uhrzeit benutzt. Und jetzt moechte ich gerne Timer 2 benutzen fuer eine Soft PWM. Hab mir hier auch einiges durchgelesen, auch die Tutorials, aber es entsteht immer das gleiche Problem. Und zwar blinkt die LED am Ausgang PB1 immer dann wenn mein Timer 1 eine Sekunde hochzaehlt. Ansonsten dimmt die LED so wie ich es will. Nur alle Sekunde geht sie aus und wieder an. Es kommt mir vor, als ob der Timeroverflow und der Timercompare sich ueberschneiden. Bitte helft mir, da ich echt nicht weiter weiss. Und bitte nicht nur auf die Tutorials verweisen, denn die hab ich schon durchgearbeitet;-). Ich hab sicherlich ein Verstaendnissproblem, dass ich leider nicht alleine loesen kann. Danke schon mal!!! Gruss Daniel ISR(TIMER1_COMPA_vect) { update_clock(); tick_display(); // tick every 0.5 sec exe_keypad(); } ISR(TIMER2_OVF_vect) { if (pwm_cnt < 20 ) PORTB &=~(1<<PB1); else PORTB |=(1<<PB1); if (pwm_cnt==127) pwm_cnt=0; else pwm_cnt++; } int main(void) { SPCR=(1<<MSTR); DDRB |= (1<<PB0)|(1<<PB1)|(1<<PB2)|(1<<PB3)|(1<<PB5)|(1<<PB6); wdt_enable(WDTO_2S); TCCR0= (1<<WGM00)|(1<<COM01)| (1<<COM00)|(1<<CS01);//|(1<<CS00); TCCR1B = (1<<WGM12)|(1<<CS10); TCCR2= (1<<CS20); OCR1A=37314; TCNT2=0; OCR0= 0; SREG = 0b10000000; TIFR= (1<<OCF1A); TIMSK = (1<<OCIE1A)|(1<<TOIE2); //Interrupt enablen while(1) { if( get_key_press( 1<<PC0 )){servicekey0();pp=0;PORTD |= (1<<PD6);} if( get_key_press( 1<<PC1 )){servicekey1();pp=0;PORTD |= (1<<PD6);} if( get_key_press( 1<<PC2 )){servicekey2();pp=0;PORTD |= (1<<PD6);} if( get_key_press( 1<<PC3 )){servicekey3();pp=0;PORTD |= (1<<PD6);} wdt_reset(); } return 0; }
Was versteckt sich hier dahinter
1 | ISR(TIMER1_COMPA_vect) |
2 | { update_clock(); |
3 | tick_display(); // tick every 0.5 sec |
4 | exe_keypad(); |
5 | }
|
Kann es sein, dass da längere Berechnungen laufen?
Ja, dass kann schon sein. obwohl dort nur die Uhr hochgezaehlt wird. D.h. eine Variable zaehlt bis 100 und dann ist eine Sekunde vorueber. Bei tick_display() blinkt der ":" des LCD Displays. Und exe_keypads wird die Tastenabfrage abgefragt. Es koennte schon sein, dass das mehr als 256 Taktzyklen brauch. Nur wie handhabe ich das dann. Da gibt es doch sicherlich eine einfache Loesung.....nur leider faellt die mir nicht ein :-)
Hallo, in der Interruptroutine nur ein Flag setzen (Hilfvariable, die auf 1 gesetzt wird). In main in der Hauptschleife dieses Flag abfragen, wenn es 1 ist, Deine Unterprogramme abarbeiten und die Variable wieder auf 0 setzen. Dann mag Deine Tastaturabfrage mal 1ms später kommen oder Deine Sekunde wird ms später hochgezählt, das stört aber nicht weiter. Gruß aus Berlin Michael
Daniel wrote: > die Tastenabfrage abgefragt. Es koennte schon sein, dass das mehr als > 256 Taktzyklen brauch. Wieviel mehr?
Hab leider erst heute die Gelegenheit gehabt, dass nachzuschauen. Es sind 273 Taktzyklen. @ michael Leider hab ich dein Prinzip nicht ganz verstanden, denn die Unterprogramme sind ja in den Interruptroutinen und nicht in der main Schleife. Vielleicht kannst du mir das anders beschreiben, was du meinst. Danke aber schonmal fuer die Antworten!!!!
Probier mal:
1 | ISR(TIMER1_COMPA_vect, ISR_NOBLOCK) |
2 | ...
|
Ist aber sehr mit Bedacht anzuwenden, also nie ohne Grund! Peter
Leider gibt der Compiler mir eine Fehlermeldung. Er sagt mir, dass ich nur ein Argument in die ISR eingeben darf. Ich bin ja wie gesagt erst neu in der Materie und frag mich wie ihr das denn immer macht um mehere Interrupts paralell laufen zu lassen. Ich koennte ja auch einen anderen Weg gehen. Ich moechte eben nur eine Softpwm machen, die eine hoehere Frequenz hat als die restlichen Aufrufe. Hab schon gedacht nur einen Interrupt zu nutzen aber wofuer hat man denn so viel;-)
Daniel wrote: > @ michael Leider hab ich dein Prinzip nicht ganz verstanden, denn die > Unterprogramme sind ja in den Interruptroutinen und nicht in der main > Schleife. Genau darauf will micheal ja hinaus, mache die Aufrufe nicht in der ISR, sondern in der main-Schleife > Vielleicht kannst du mir das anders beschreiben, was du > meinst. Simpel:
1 | volatile uint8_t IdleProcessing; |
2 | |
3 | ISR(TIMER1_COMPA_vect) |
4 | {
|
5 | IdleProcessing = 1; |
6 | }
|
7 | |
8 | ...
|
9 | |
10 | int main() |
11 | {
|
12 | ....
|
13 | |
14 | IdleProcessing = 0; |
15 | |
16 | ...
|
17 | |
18 | while( 1 ) |
19 | {
|
20 | |
21 | if( IdleProcessing ) |
22 | {
|
23 | IdleProcessing = 0; |
24 | |
25 | update_clock(); |
26 | tick_display(); // tick every 0.5 sec |
27 | exe_keypad(); |
28 | }
|
29 | |
30 | ....
|
31 | |
32 | }
|
33 | }
|
Der Hintergedanke ist der, dass die ISR nur das absolute Minimum machen muss, was möglich ist. Daher wird der Clock-Update und das Abfragen des Keypads in die main-Loop verfrachtet. Die ISR gibt nur noch Bescheid, wann es wieder mal soweit ist. Ob das Abfragen des Keypads ein paar Nanosekunden später erfolgt, weil dein Prozessor die Soft-PWM ISR ausführt oder nicht, spielt keine große Rolle. Es ist ebenfalls unkritisch, wenn das Programm beim Updaten das Tick-Displays unterbrochen wird. Wichtig ist nur, dass der Proz. so schnell wie möglich auf die ISR für die Software- PWM umschalten kann. Und das Einzige was das verhindern kann ist, wenn das Programm schon in einer anderen ISR steckt. Ergo: Sorge dafür, daß diese andere ISR so kurz wie nur irgend möglich und so schnell wie nur irgend möglich abgearbeitet werden kann.
Danke Karl Heinz. Jetzt klappt es wunderbar und ich hab das Problem erkannt!! Du bist echt ne riesen Hilfe in diesem Forum!!!
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.