Hallo ich benutze zurzeit zwei Timer Interrupts (beim atmega8). leider verstehe ich nicht 100% die funktion von Interrupts. Wenn ich zum beispiel zwei timer laufen lasse und einer liest den adc wert aus und der andere führt einen bestimmte logik aus, wie sieht es mit dem timing aus? kann es sein, dass Werte verloren gehen? siehe erstmal programm (ohne jetzt auf die syntax zu achten): isr( timer0_Overflow) { // ADC Wert wird z.B. alle 10 ms eingelesen // } isr( timer1_Overflow) { // LED toggeln lassen // // ADC Werte auf 0 bis 255 begrenzen, wegen Timer // // TCNT1 = ADC_WERT // } Meine Frage ist nun, werden alle eingelesenen ADC Werte im Timer1 verwendet oder kann es sein, dass bei erhöhung der ADC Werte die zeit zu lange dauert (Toggeln) dass der timer1 noch rechtzeitig auf ein neues ereignis des timer0 reagiert? oder hab ich bzgl. Interrupt ein denkfehler? ich möchte gern impulse mit variabler frequenz aber gleichbleibendem duty cycle erzeugen, mein wunsch wäre bei einem wert von 0 = 10 ms und bei einem ADC wert von 255 = 500 us Impulse erzeugen. Ich benutze zurzeit einen internen RC mit 1 MHz. Muss cih vlt. einen höhren externen Oscillator nehmen, z.B. 4 MHz um diese Zeiten zu schaffen? Zurzeit schaffe ich es zwar diese impulse mit den interrupts zu erzeugen aber leider nicht mit diesen zeiten und zudem schwanken die impulse bei höheren werten wie z.B. 255. P.S. der prescaler sind bei beiden timern gleich --> auf 64 eingestellt
Das macht man anders. Man laesst einen Timer laufen und wenn der kommt setzt man einen Boolean. Im Main startet man den ADC wenn der Timer gekommen ist, indem dort der Timer boolean abgefragt wird. Das Lesen des ADC macht man im ADC interrupt.
Aus dem bisschen Pseudocode wird noch nicht viel klar. Häng doch mal den echten Code als Attachment an. Die restliche Fragestellung ist auch nicht sonderlich verständlich. Nur mal zur Klarstellung: Ein ADC Wert von 0 soll einer Impulslänge von 10ms (milli) entsprechen, und ein Wert von 255 soll 500us (mikro) entsprechen? Sind das die richtigen Größenordnungen? Timer1 ist ein 16bit Timer, kann also bis 65535 zählen, nutze das doch aus. Eventuell kannst du dadurch den Prescaler weglassen, oder auf 8 verringern, momentan ist deine Auflösung ja auf 64us begrenzt. ADC Messungen brauchen Zeit. Das Datenblatt empfiehlt eine ADC clock zwischen 50 und 200kHz, das heisst der ADC braucht einen Prescaler von 8 bei 1 MHz um 125kHz zu erreichen. Eine (Einzel-)Messung dauert dann 200us. Da bringt auch ein höherer Takt nichts. Im Regelfall lässt man die Interrupts aus, während einer Interrupt-routine, das hieße, während der ADC messung kann der Timer1 interrupt nicht aktiv werden. Wenn die Timer1 routine nichts anderes macht, als einen Pin zu toggeln, kannst du das ganz ohne Interrupt routine machen, und zwar an Pins OC1A, bzw. OC1B. Die Funktionalität kannst du in TCCR1A einstellen. Das funktioniert aber auch nur, während die Interrupts aktiv sind. Daher den Rat von oha befolgen. Wenn du sonst keine weiteren Interrupts verwendest, kannst du evtl. auch die die Interrupts in der Timer0 routine wieder aktivieren, aber damit kenne ich mich nicht aus.
Hallo danke für die hinweise, aber es geht nicht wirklich nur ums toggeln. dies diente nur zu testzwecken... es geht darum Hall Impulse NACHZUSIMULIEREN, indem abhängig vom ADC die Impulsbreite immer kürzer wird (Motorgeschwindigkeit steigt) oder immer breiter, wodurch simuliert wird, dass der Motor immer langsamer wird. Dabei möchte ich Impulse in der Grössenordnung zwischen 500 us und 10 ms erreichen. Geplant waren bisher dass alle 1 ms ein ADC Wert eingeselen wird. Können auch 2 ms oder etwas mehr sein...die auflösung ist nicht problematisch. im grunde ganz einfach, wenn man sich mit Timern und Interrupts speziell Timing auskennt. Leider hab ich noch nie damit gearbeitet und es trten halt die oben aufgelisteten Probleme auf: Schwanken im obenren Bereich, nicht erreichen von diesen gewünschten Zeiten (500 us und 10 ms)... Anbei der Code: Hoffe ihr habt eine idee warum das nicht so optimal klappt. Bislang schaffe ich es, dass die Impulse ihre Frequenz durch änderng der ADC Were ereichen, nur nicht wie gewünscht, aus welchen gründen auch immer? Würde es denn mit einem Timer1 besser klappen? Oder besser einen externen Quarz, der diese Zeiten problemlos schafft? Gruss und danke im voraus.
interrupt (englisch) = unterbrechen. Ein Interrupt unterbricht das laufende (Haupt-)Programm bei eintreffen einer bestimmten Bedingung. Nach der Abarbeitung des Interrupts fährt das (Haupt-)Programm genau an der Stelle fort, wo es zuvor unterbrochen worden ist.
Wäre super, wenn du auch für meine anderen Fragen eine Antwort hättest ;)
Sollte pulselength nicht volatile sein ?
1 | #include <util/delay.h> |
2 | #include <avr/interrupt.h> |
3 | #include <avr/io.h> |
4 | |
5 | volatile char pulselength; // somit wird die Variable vor jeder Benutztung neu geladen, sonnst könnte die Änderung durch die ISR "verloren" gehen. |
6 | char S1 = 0; |
7 | char S2 = 0; |
8 | char Direction = 1; |
9 | |
10 | volatile uint16_t AdcValue = 0; // hier auch ein Volatile ? |
Es gibt eine extra ISR um den ADC auszulesen... Vielleicht interessiert Dich auch der FreeRunningMode des AVR ?
Ganui Kliuz wrote: > ich benutze zurzeit zwei Timer Interrupts (beim atmega8). leider > verstehe ich nicht 100% die funktion von Interrupts. Wenn ich zum > beispiel zwei timer laufen lasse und einer liest den adc wert aus und > der andere führt einen bestimmte logik aus, wie sieht es mit dem timing > aus? kann es sein, dass Werte verloren gehen? Ja, kann sein. Es kommt auf die µC Architektur an und auf den konkreten Fall. Bei AVRs wird pro Interruptquelle ein weiterer Interrupt in der Warteschlange gehalten. Ist die ISR von Timer0 aktiv, müssen andere Irterrupts in der Warteschlange warten. Kommt zu einem wartenden Interrupt von Timer1 ein zweiter, geht einer verloren. Ob in deinem Fall mehrere Interrupts von Timer1 in der ISR von Timer0 kommen, bzw. auch umgekehrt, hängt von der Frequenz von Timer0 und Timer1 ab und wie lange die ISRs dauern. Daher das Ziel die ISRs zu kurz wie möglich zu halten. Eine ADC Messung ist da vergleichsweise eher "lang". > ich möchte gern impulse mit variabler frequenz aber gleichbleibendem > duty cycle erzeugen, mein wunsch wäre bei einem wert von 0 = 10 ms und > bei einem ADC wert von 255 = 500 us Impulse erzeugen. Ich benutze > zurzeit einen internen RC mit 1 MHz. Muss cih vlt. einen höhren externen > Oscillator nehmen, z.B. 4 MHz um diese Zeiten zu schaffen? Du kannst einen 10ms Timer laufen lassen und wie von oha vorgeschlagen ein volatile Flag in der ISR setzen, dass 10ms vergangen sind. In dem Hauptprogramm prüfst du dieses Flag, setzt das Flag zurück und machst eine ADC Messung. Den Messwert kannst du dann benutzen, um einen zweiten Timer zu steuern z.B. um dessen Startwert im CTC Modus zu verändern (hochsetzen => höhere Frequenz, runtersetzen => niedrigere Frequenz). 1 MHz sollte ausreichen, um einen 10ms Timer laufen zu lassen. Eine Möglichkeit bei AVRs wäre der 8-Bit Timer0 mit Prescaler von 8 und einen Startwert des Timerzählers von 131 (=256-125) und alle 10 Overflows das Flag setzen. Der Startwert wird in der ISR von Hand nachgeladen oder automatisch nachgeladen (CTC Modus). Bei dem 1 MHz internen RC-Oszillator bei den AVRs muss man beachten, dass der ggf. kalibriert werden muss, um genau zu laufen und dass eine rel. starke Abhängigkeit der Taktrate von der Umgebungstemperatur vorhanden ist. Wenn es genau sein soll, also eher auf externe Taktquelle wie Quarz oder Quarzoszillator gehen. 500µs Dauer für die Halbperiode... Bei einem 16-Bit Timer und Prescaler 1 sollten die Overflows alle 500 Takte kommen. Das ist wie oben machbar. Schön ist daran, dass die Dauer in µs direkt der Zahl der Takte zwischen den Overflows entspricht. Unschön ist die niedrige Zahl der Takte zwischen den Overflows. Das Hauptprogramm und die ISR Timer0 haben ja nicht viele Takte (500 - Zahl der Takte in der Timer1 ISR) zum arbeiten und das wird schlimmer, wenn die Dauer verkürzt werden soll. Da wären mehr MHz eindeutig geschickter.
Hallo ich hab es jetzt doch mit dem ADC Interrupt gemacht und es funktioniert soweit ganz gut. Ich kann die variablen Impulse erzeugen. Allerdings möchte ich gerne bei einem ADC Wert von 0, dass keine Impulse (also S1=S2=0..siehe anhang code)) erzeugt werden, wodurch der stillstand simuliert wird. zurzeit werden auch bei einem wert von 0 Impulse erzeugt und das soll ja nicht sein . Wie kann man die Logik erweitern, dass eben bei einem wert von NULL die Impulse ebenso NULL sind? Hab es mit der if (AdcValue <=1 && Direction) versucht, aber irgendwie kommen noch ganz kurze unregelmässige Impulse?... danke im vorraus und für die zahlreichen tipps
Ich würds so machen, dass bei einer pulslength von 0 der 2.te Timer ganz einfach über seinen Vorteiler abgeschaltet wird. Wird pulslength dann wieder ungleich 0, wird wieder ein Vorteiler gesetzt und der Timer tickt wieder. Edit: Ah, du erzeugst ja den Puls sowieso im Overflow Interrupt vom Timer 2. Also dort ganz einfach eine Abfrage rein, dass das Signal nur dann ausgegeben wird, wenn pulslength ungleich 0
Hallo das hab ich gerade versucht: if ( (Direction) && (pulselegth != 0) )... aber es tauchen immernoch irgendwelche kurzen impulse auf einem port pin.. liegt es am Timer2?
Google Master wrote: > Hallo > > das hab ich gerade versucht: > > if ( (Direction) && (pulselegth != 0) )... > dort wird aber der Puls am Pin nicht erzeugt :-) Aber warum so kompliziert? Warum nicht einfach
1 | ISR(TIMER2_OVF_vect ) |
2 | {
|
3 | if( pulslength != 0 ) |
4 | {
|
5 | //Vorwärtsbetrieb
|
6 | if (Direction) |
7 | {
|
8 | if ((S1==1) && (S2==1)) { S1 = 0; S2 = 1; } else |
9 | if ((S1==1) && (S2==0)) { S1 = 1; S2 = 1; } else |
10 | if ((S1==0) && (S2==0)) { S1 = 1; S2 = 0; } else |
11 | if ((S1==0) && (S2==1)) { S1 = 0; S2 = 0; } |
12 | }
|
13 | |
14 | // Rückwärtsbetrieb
|
15 | else if (!Direction) |
16 | {
|
17 | if ((S2==1) && (S1==1)) { S2 = 0; S1 = 1; } else |
18 | if ((S2==1) && (S1==0)) { S2 = 1; S1 = 1; } else |
19 | if ((S2==0) && (S1==0)) { S2 = 1; S1 = 0; } else |
20 | if ((S2==0) && (S1==1)) { S2 = 0; S1 = 0; } |
21 | }
|
22 | |
23 | if (S1) { PORTD |= (1<<PD1); } else { PORTD &= ~(1<<PD1); } |
24 | if (S2) { PORTD |= (1<<PD2); } else { PORTD &= ~(1<<PD2); } |
25 | |
26 | TCNT2 = pulselength; //Zählregister |
27 | }
|
28 | }
|
Wenn pulslength 0 erreicht hat, passiert einfach gar nichts mehr im Overflow Interrupt und damit herrscht dann Ruhe an den Pins. Wenn jetzt immer noch nicht Ruhe herrscht, dann liegt es daran, dass pulslength nie 0 wird.
1 | ISR(ADC_vect) |
2 | {
|
3 | AdcValue = ADCH; // Nur die MSB werden übernommen /// |
4 | |
5 | //Sicherheitsüberprüfung ADC
|
6 | if ( AdcValue < 1 ) AdcValue = 0; |
Das ist ja momentan ein wenig sinnfrei :-)
haha sinnfrei ist gut :P stimmt, blöde abfrage...hab es eliminiert. stimmt, bei 0 macht er immernoch nix...erst bei pulselegth > 2 herrscht ruhe. seltsam...
... nee doch nicht....war wohl nur zufall..ab und zu kommen dann doch welche impulse durch...hmmm
Nein, noch nicht. Würde es gerne machen, aber müsste mich erst in UART reinlesen wie man das am schnellsten hinkriegt. Gibt es da vlt. schon was fertiges? Ich benutze myAVR USB mit ISP und einen Atmega8L, falls das was ausmacht...
Achja ich arbeite bei der Firma Bosch und habe hier ein Problem mit Mikrokontrollern. Kann mir jemand das Programm schreiben ? Danke
>Achja ich arbeite bei der Firma Bosch und habe hier ein Problem mit >Mikrokontrollern. Kann mir jemand das Programm schreiben ? Laß das dann am Besten sein und versuche in die Personalabteilung zu wechseln. Dort kommt man auch ohne logisches Denken zum Erfolg. gez. Katapulski
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.