Hallo zusammen, bin noch recht unerfahren in der C-Programmierung. Ich habe sowohl Peter Danneggers Tasten-Entprellcode als auch seinen Drehgeber-Code auf meinem STK200 ausprobiert. Beides funktioniert prächtig. Der Drehgeber und zwei Tasten sind dabei am selben Port angeschlossen. Ich möchte nun aber beide Codes gemeinsam nutzen. Beide nutzen den Timer0, jedoch einmal mit einem 10ms und einmal mit einem 1ms Takt. Kann ich nun einfach den 1ms Interrupt als Basis nehmen und bei jedem 10. Aufruf die Entprellcode-Teile ausführen? Oder ist das Quatsch?
Klaus schrieb: > Kann ich nun einfach den 1ms Interrupt als Basis nehmen und bei jedem > 10. Aufruf die Entprellcode-Teile ausführen? Oder ist das Quatsch? Klar geht das, solange deine ISR im worst case nicht länger als 1 ms läuft. Da passt sicher noch mehr rein. Ich erledige in einer Basis-Timerroutine auch Display-Ausgabe und Abfrage von seriellen Ports (bei 9600 Baud oder weniger) und Temperaturerfassung mit Glättung usw. Dazu fängt bei mir die ISR mit einem Dispatcher an, der Aufgaben gleichmässig verteilt, die alle 1,2,4 usw. ms erledigt werden sollen, dann kann man ausschliessen, dass dummerweise einmal alles auf einmal erledigt werden muss. D.h. 2 Aufgaben, die alle 2ms anstehen, werden im Wechsel ausgeführt. Gruss Reinhard
Klaus schrieb: > Tasten-Entprellcode als auch seinen Drehgeber-Code Bei richtiger Drehgeber-Dekodierung (siehe DSE-FAQ) braucht man keine Entprellung. Gruss Harald
Harald Wilhelms schrieb: > Bei richtiger Drehgeber-Dekodierung (siehe DSE-FAQ) braucht man > keine Entprellung. Lesen können hilft: er hat einen Encoder UND 2 Tasten. Gruss Reinhard
Danke! Funktioniert. Könnte man das Ganze eigentlich auch eleganter lösen als ich das getan habe indem ich die beiden Codes zusammengewürfelt habe? Peda verwendet in der Drehgeber-Routine den Timer0-Compare-Int und in der Entprellroutine den Timer0-Overflow-Int. Ist das Zufall, oder steckt da wieder so ein super-cleverer Gedankengang dahinter, den ich als Anfänger nicht sehe/verstehe? Bietet das eventuell die Möglichkeit beide Routinen in einem Progamm zu nutzen? Ich denke nicht, da ja beide Routinen unabhängig am TCNT0 manipulieren.
Klaus schrieb: > Bietet das eventuell die Möglichkeit beide Routinen in einem Progamm zu > nutzen? Ich denke nicht, da ja beide Routinen unabhängig am TCNT0 > manipulieren. Doch, das geht natürlich. Hier ist was für den Tiny26, wo beide Routinen in der gemeinsamen (CTC) ISR kombiniert sind:
1 | // Definitions
|
2 | // Rotary Encoder properties
|
3 | #define ROTARY_PORT PORTB
|
4 | #define ROTARY_DIR DDRB
|
5 | #define ROTARY_PIN PINB
|
6 | #define WHEEL1 6
|
7 | #define WHEEL2 5
|
8 | #define BUTTON 0
|
9 | |
10 | #define PHASE_A (ROTARY_PIN & 1<<WHEEL1)
|
11 | #define PHASE_B (ROTARY_PIN & 1<<WHEEL2)
|
12 | #define REPEAT_MASK (1 << BUTTON) // repeat: button
|
13 | #define KEY_MASK REPEAT_MASK
|
14 | #define REPEAT_START 150 // after 1500ms
|
15 | #define REPEAT_NEXT 100 // every 1000ms
|
16 | |
17 | // for 1 ms
|
18 | #define OCR_SET (uint8_t)(F_CPU/256*1e-3)
|
19 | |
20 | |
21 | // encoder routines a la PeDa
|
22 | void encoder_init( void ) |
23 | {
|
24 | int8_t enc_new; |
25 | |
26 | enc_new = 0; |
27 | if( PHASE_A ) |
28 | enc_new = 3; |
29 | if( PHASE_B ) |
30 | enc_new ^= 1; // convert gray to binary |
31 | enc_last = enc_new; // power on state |
32 | enc_delta = 0; |
33 | TCCR1A = 0; |
34 | OCR1C = OCR_SET; |
35 | TCCR1B = (1<<CTC1)|(1<<CS13)|(0<<CS12)|(0<<CS11)|(1<<CS10); // CTC, XTAL / 256 |
36 | TIMSK |= (1<<TOIE1); |
37 | }
|
38 | ISR(TIMER1_OVF1_vect) { |
39 | int8_t enc_new, diff; |
40 | static uint8_t ct0, ct1, rpt,btimer; |
41 | uint8_t i; |
42 | |
43 | // rotary handling
|
44 | enc_new = 0; |
45 | if( PHASE_A ) |
46 | enc_new = 3; |
47 | if( PHASE_B ) |
48 | enc_new ^= 1; // convert gray to binary |
49 | diff = enc_last - enc_new; // difference last - new |
50 | if( diff & 1 ){ // bit 0 = value (1) |
51 | enc_last = enc_new; // store new as next last |
52 | enc_delta += ((diff & 2) - 1); // bit 1 = direction (+/-) |
53 | }
|
54 | btimer++; |
55 | if (btimer > 9) { |
56 | // button handling
|
57 | i = key_state ^ ~ROTARY_PIN; |
58 | ct0 = ~(ct0 & i); |
59 | ct1 = ct0 ^ (ct1 & i); |
60 | i &= ct0 & ct1; |
61 | key_state ^= i; |
62 | key_press |= key_state & i; |
63 | if( (key_state & REPEAT_MASK) == 0 ) // check repeat function |
64 | rpt = REPEAT_START; // start delay |
65 | if( --rpt == 0 ){ |
66 | rpt = REPEAT_NEXT; // repeat delay |
67 | key_rpt |= key_state & REPEAT_MASK; |
68 | }
|
69 | btimer = 0; |
70 | }
|
71 | }
|
Wunder dich nicht, im Tiny26 bewirkt ein CTC Ereignis, das die Timer1 Overflow ISR angesprungen wird. Port Initialisierung ist hier weggelassen. Abfrage von Encoder und Knöpfen wie gehabt.
:
Bearbeitet durch User
Klaus schrieb: > Ist das Zufall, oder steckt > da wieder so ein super-cleverer Gedankengang dahinter, den ich als > Anfänger nicht sehe/verstehe? Als Peter die Entprellung schrieb, verwendete er wohl einen AVR, dessen für die Entprellung verwendete Timer noch keine Compare-Interrupts hatte. Der eigentlichen Entprellroutine ist es völlig egal, durch welchen Timer sie aufgerufen wird. Wichtig ist nur, dass es in (halbwegs) gleichmäßigen Zeitabständen passiert und zwischen den Aufrufen die restlichen Teile des Programms abgearbeitet werden können. Wenn mehrere Zeittakte benötigt werden, ist es sinnvoll, die langsameren Takte aus dem schnellsten abzuleiten. Das verhindert gegenseitige Beeinflussung mehrerer Timer-Interrupts und erlaubt durch eine Art Taskscheibe eine schnelle Abarbeitung der ISR. Aber das wurde ja hier bereits erwähnt: Beitrag "Re: Peter Danneggers Entprellung und Encoder-Code - wie kombinieren" ...
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.