Hallo, ich versuche Servoimpulse aus dem Empfänger auzuwerten. Ich glaube aber das mein Ablauf zu ungenau ist. Ich verwende PIN1 INT0 interrupt und den Timer0 /64 clk. der Tiny13 läuft bei 4,8MHz. steigende Flanke löst interrupt aus ich warte mit delay 1000µs (weil es erst dann intressant wird) schalte den Timer ein warte bis PIN1 0 wird schate den Timer ab übergebe den Wert. Irgendwie ist das zu ungenau, kann das sein ? Sollte ich die Impulse generell anders auswerten ? viele Grüße Martin
hoschi schrieb: > steigende Flanke löst interrupt aus > ich warte mit delay 1000µs (weil es erst dann intressant wird) Vergiss diesen Schritt. Der delay ist ungefähr 1000µs, aber nicht exakt. Und wenn dir da dann auch noch ein Interrupt in der Delayzeit dazwischenfunkt, dann kannst du auch gleich eine Sanduhr nehmen um 1 Sekunde abzuwarten. > schalte den Timer ein > warte bis PIN1 0 wird > schate den Timer ab > übergebe den Wert. > > Irgendwie ist das zu ungenau, kann das sein ? > > Sollte ich die Impulse generell anders auswerten ? Starte den Timer, zähle die Overflows und rechne ein wenig.
aah, dann kann der delay auch wenn er in der interrupt Routine gerufen wird vom Interrupt unterbrochen werden weil es eine Funktion ist ?
hoschi schrieb: > aah, dann kann der delay auch wenn er in der interrupt Routine gerufen > wird vom Interrupt unterbrochen werden weil es eine Funktion ist ? Solage du nicht selbst mittels sei() die Interrupts freigibst, bist du in einer ISR vor weiteren Interrupt Aufrufen geschützt. Trotzdem macht man das nicht, dass man in einem Interrupt auf etwas längere Zeit wartet. Ansonsten: Code zeigen hilft. (Warum denkst du eigentlich, dass das zu ungenau ist)
Bei clk/64 und 4,8MHz wird die max. 1ms lange Servoposition in 75 Schritte aufgelöst. Die 1ms Verzögerung zu Anfang braucht es damit dann nicht, bei max 2.1ms Servopulslänge zählt der Timer höchstens bis 158. Das gibt niemals einen Overflow. Ob 75 Schritte ausreichend sind, musst du natürlich selber wissen. Oliver
ok, vielen Dank für die Tipps. Dann wäre der neue Programmablauf in etwa so: INT0 auf steigende Flanke Bei INT0 Timer0 = 0 Timer einschalten mit passendem Teiler (oder evtl. keinem) fallende/steigende INT0 Flanke umschalten bei fallender Flanke : Timer ausschalten Überläufe auswerten und endwert übergeben Überlaufzähler zurückstezen Bei INT Timer overflow Überläuf zählen
Hier mal mein Code versuch.
1 | #include "main.h" |
2 | |
3 | volatile int impuls; |
4 | volatile int tmr_ov; |
5 | |
6 | int main (void) { |
7 | |
8 | |
9 | GIMSK = (1<<INT0); // | (1<<PCIE); //INT0 enable PINchg enable |
10 | MCUCR = (1<<ISC00) | (1<<ISC01); //interrupt auf INT0 steigende Flanke |
11 | |
12 | |
13 | DDRB &= ~( 1 << DDB1 ); // Eingänge definieren |
14 | DDRB = (1 << DDB2) | (1 << DDB3 ) | (1 << DDB4 ); // Ausgang definieren |
15 | |
16 | sei(); |
17 | |
18 | while (1) { |
19 | |
20 | |
21 | if (impuls <= 130 && (impuls>=10) ) { // Werte müssen noch angepasst werden |
22 | PORTB |= (1<<PB2); |
23 | }
|
24 | else PORTB &= ~(1<<PB2); // Pin PB2 und Pin PB3 "low" |
25 | |
26 | |
27 | if (impuls >= 170) { // Werte müssen noch angepasst werden |
28 | PORTB |= (1<<PB3); |
29 | }
|
30 | else PORTB &= ~(1<<PB3); // Pin PB2 und Pin PB3 "low" |
31 | }
|
32 | }
|
33 | |
34 | |
35 | |
36 | ISR(INT0_vect) { |
37 | TCNT0=0; // Timer 0 auf 0 |
38 | |
39 | if (CS00 == 0) { |
40 | TCCR0B = (1<<CS00); // Timer 0 Prozessortakt (4,8Mhz) / 1 //timer 0 start |
41 | MCUCR = (1<<ISC01); // interrupt auf INT0 fallende Flanke |
42 | }
|
43 | |
44 | |
45 | if (CS00 == 1) { |
46 | TCCR0B &= ~(1<<CS00); // Timer 0 stop |
47 | MCUCR = (1<<ISC00) | (1<<ISC01); // interrupt auf INT0 steigende Flanke |
48 | |
49 | impuls=tmr_ov; // Wert an globale Variable evtl noch Berechnung |
50 | tmr_ov=0; // Overflow Zähler auf null |
51 | }
|
52 | |
53 | PORTB ^= ( 1 << PB4 ); // INT und Impulseingang Überwachung |
54 | }
|
55 | |
56 | |
57 | ISR(TIM0_OVF_vect) { // Timer overflow interrupt |
58 | tmr_ov++; |
59 | }
|
ich habe leider meine Testhardware nicht hier, kann das erst am Abend testen. Ich bin auch noch Anfänger bei dem Programmieren, ich bemühe mich aber kenne aber nicht viele Tricks. Jetzt müsste noch in etwa ausgerechnet werden wie hoch die gemessenen Werte sein können.
hoschi schrieb:
> if (CS00 == 0) {
CS00 ist immer 0.
CS00 ist nichts anderes als ein Makro, welches die Bitnummer für das
'CS00' Bit im Timerkonfiguratinsregister hinter einem Namen kaschiert
1 | #define CS00 0
|
so stehts irgendwo in den Header Files. Da dem aber so ist, wird dieser Vergleich immer TRUE ergeben. > if (CS00 == 1) { wohingegen, dieser niemals TRUE sein wird (OK. Ich verallgemeinere. Auf allen AVR Prozessoren die ich kenne, liegt CS00 an der Bitposition 0 und genau genommen muss das nicht unbedingt so sein)
1 | if (CS00 == 0) { |
2 | TCCR0B = (1<<CS00); // Timer 0 Prozessortakt (4,8Mhz) / 1 //timer 0 start |
3 | MCUCR = (1<<ISC01); // interrupt auf INT0 fallende Flanke |
Yep. Genau das ist einer der richtigen Wege.
1 | impuls=tmr_ov; // Wert an globale Variable evtl noch Berechnung |
2 | tmr_ov=0; // Overflow Zähler auf null |
Warum Overflow? Warum nicht erst mal den Timerstand selber?
ah, ok danke, du meinst dann warscheinlich eher so:
1 | #include "main.h" |
2 | |
3 | volatile int impuls; |
4 | volatile int tmr_ov; |
5 | volatile int flanke; |
6 | |
7 | int main (void) { |
8 | |
9 | |
10 | GIMSK = (1<<INT0); // | (1<<PCIE); //INT0 enable PINchg enable |
11 | MCUCR = (1<<ISC00) | (1<<ISC01); //interrupt auf INT0 steigende Flanke |
12 | |
13 | |
14 | DDRB &= ~( 1 << DDB1 ); // Eingänge definieren |
15 | DDRB = (1 << DDB2) | (1 << DDB3 ) | (1 << DDB4 ); // Ausgang definieren |
16 | |
17 | sei(); |
18 | |
19 | while (1) { |
20 | |
21 | |
22 | if (impuls <= 130 && (impuls>=10) ) { // Werte müssen noch angepasst werden |
23 | PORTB |= (1<<PB2); |
24 | }
|
25 | else PORTB &= ~(1<<PB2); // Pin PB2 und Pin PB3 "low" |
26 | |
27 | |
28 | if (impuls >= 170) { // Werte müssen noch angepasst werden |
29 | PORTB |= (1<<PB3); |
30 | }
|
31 | else PORTB &= ~(1<<PB3); // Pin PB2 und Pin PB3 "low" |
32 | }
|
33 | }
|
34 | |
35 | ISR(INT0_vect) { |
36 | TCNT0=0; // Timer 0 auf 0 |
37 | |
38 | if (flanke == 0) { |
39 | flanke = 1; |
40 | TCCR0B = (1<<CS00); // Timer 0 Prozessortakt (4,8Mhz) / 1 //timer 0 start |
41 | MCUCR = (1<<ISC01); // interrupt auf INT0 fallende Flanke |
42 | }
|
43 | else { |
44 | flanke = 0; |
45 | TCCR0B &= ~(1<<CS00); // Timer 0 stop |
46 | MCUCR = (1<<ISC00) | (1<<ISC01); // interrupt auf INT0 steigende Flanke |
47 | |
48 | impuls=(tmr_ov*256)+TCNT0; // Wert an globale Variable evtl noch Berechnung |
49 | tmr_ov=0; // Overflow Zähler auf null |
50 | }
|
51 | |
52 | PORTB ^= ( 1 << PB4 ); // INT und Impulseingang Überwachung |
53 | }
|
54 | |
55 | |
56 | ISR(TIM0_OVF_vect) { // Timer overflow interrupt |
57 | tmr_ov++; |
58 | }
|
hoschi schrieb: > ah, ok danke, du meinst dann warscheinlich eher so: Fast Welchen Wert wird wohl TCNT0 hier >
1 | > else { |
2 | > flanke = 0; |
3 | > TCCR0B &= ~(1<<CS00); // Timer 0 stop |
4 | > MCUCR = (1<<ISC00) | (1<<ISC01); // interrupt auf INT0 steigende Flanke |
5 | >
|
6 | > impuls=(tmr_ov*256)+TCNT0; // Wert an globale Variable evtl noch Berechnung |
7 | >
|
haben, nachdem du hier
>
1 | > ISR(INT0_vect) { |
2 | > TCNT0=0; // Timer 0 auf 0 |
3 | >
|
den TCNT0 immer auf 0 gesetzt hast :-) (OK, das ist jetzt ein trivialer Bug. Aber im Grunde: Ja, so sollte das fürs erste funktionieren)
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.