Hallo Leute, ich bin relativ neu im Mikrokontroller Bereich und bräuchte euere Hilfe. Es geht darum eine Bitsequenz einzulesen. Dazu habe ich mir überlegt, dass ganze über einen externen Interrupt zu steuern. Sobald eine Flanke fällt, muss 250µs gewartet werden und dann das Bit ausgelesen werden. Fällt wieder eine Flanke, muss wiederum 250µs gewartet werden, und das Bit ausgelesen werden. Mein Problem ist bisher nur, dass mir das GCC Tutorial nicht "verraten" konnte, wie ich erst nach dem Interrupt einen Timer starte, und nach den 250µs wieder anhalte. Ich weiß bisher nur, wie ich einen Timer einfach konfigurieren kann und laufen lassen kann. Aber wie ich ihn erst bei einer fallenden Flanke starten kann, ist mir ein Rätzel. Ich hoffe jemand hat einen Tipp für mich. Danke, mfG David
Sehe ich das richtig im Datenblatt, dass das nicht möglich ist? ich hab mir gerade überlegt, dass ich ja den Timer auf 0 zurücksetzen kann, und dann abwarte bis etwas passiert. Aber Bits tatsächlich nur auslese wenn die flanke gefallen ist. Solange kann der Timer ja machen was er will, der beeinflusst ja eigentlich nichts. Sehe ich das richtig so?
David schrieb:
> Sehe ich das richtig im Datenblatt, dass das nicht möglich ist?
Das könnten wir beantworten wenn wir wüssten in welches Datenblatt Du
schaust.
im Flankeninterrupt Timer aktivieren, sprich den Prescaler der Clock in seinem TCCR ungleich 0 setzen, dann läuft der Timer. Z.B. über einen Compare Match Interrupt kannste dann nach 250 us nen weiteren Interrupt generieren lassen. In diesem setzt du den Clockprescaler wieder auf 0 (Timer stopped). Wert im TCNT nicht vergessen zurückzusetzen, da das nicht automatisch passiert, außer du stellst CTC ein (geht nicht bei allen Timern). So das war allgemein, für genauere Infos müssteste dann deine Schaltung/verwendeten Prozessor mitteilen ;-)
GENIAL! Auf die Idee bin ich nicht gekommen. Natürlich funktioniert das so. Dankeschön :) War übrigends ein Atmega 8535. Danke
Jetz wäre nur noch die Frage, wie ich genau 251,77µs bei 12Mhz hinbekomme. Aber dazu muss ich CTC verwenden. Mit Prescaler 64 und Vergleichswert 47 bekomme ich aber 250,666667µs hin, und das ist auserhalb von meinen 0,5% Toleranz die ich habe... :/ Zudem habe ich schon eine Lösung wie es auch ohne Starten und Stoppen des Timers geht. Ich lasse einfach einen Wert hochzählen (da ich auch ab und ein vielfaches von 251,77µs brauche) Danke
David schrieb:
> das ist auserhalb von meinen 0,5% Toleranz
Ich rechne bei 250,666667µs eine Abweichung von 0.44% aus.
Oh, du hast recht, ist schon spät... habs falsch gerechnet, aber danke :)
Nur aus Neugier. Was ist denn das für eine Anwendung, bei der man eine Leitung exakt 251,77 µs nach einer Flanke abfragen muss? 1µs davor bzw. 1µs danach liefert ein falsches Ergebnis. Das vom Auftreten der Flanke bis zum Abarbeiten der ISR bis dann in der ISR der Vorteiler für den Timer gesetzt wird auch Zeit vergeht hast du berücksichtigt? Dass von der Endemeldung des Timers bis zum tatsächlichen Auslesen des Pins ebenfalls Zeit vergeht, hast du ebenfalls berücksichtigt? Das sich dein ganzes Timing mit der nächsten Compilerversion (die ev. beim Eintritt in die ISR ein Register mehr/weniger pusht) minimal verschieben kann, hast du berücksichtigt?
Hallo, es geht darum, eine Datenleitung für ein Display auszulesen. Das Signal hat 32 Bit (also 32 verschiedene Leuchtelemente auf der Displaytafel) Das Signal baut sich so auf. Erst wird ca. 11ms eine Pause abgewartet (Signal High). Fällt die Flanke, kommt nach 241,77µs das erste bit. Dann muss man warten bis das Signal nach ein paar µs wieder auf High geht und erneut fällt. Dann wiederum muss 241,77µs auf das nächste Bit gewartet werden, etc. Hab den Code soweit fertig, nur was ich nicht verstehe ist: Wenn eine Fallende Flanke da ist, will ich den Timer zurücksetzen. Ich habe angenommen das ich einfach OCR2 = 1 sagen kann, und er dann egal bei welchem Wert er gerade ist, ein Interrupt macht und im Zähler selbst setze ich ihn wieder auf 61. Das hat sich aber als völliger Blödsinn rausgestellt. Ich möchte nur, das bei einer Flanke, der Timer wieder bei 0 zu zählen anfängt (also sich resettet). Hier habe ich mal den Code soweit:
1 | volatile uint8_t pause; |
2 | volatile uint8_t flanke; |
3 | volatile uint8_t read; |
4 | volatile uint8_t count; |
5 | |
6 | ///INT0 Interrupt
|
7 | ISR(INT0_vect) |
8 | {
|
9 | flanke = 1; |
10 | pause = 0; |
11 | count = 0; |
12 | ///Timer mit Flanke syncronisieren
|
13 | OCR2 = 1; |
14 | }
|
15 | |
16 | |
17 | ///252µs Timer
|
18 | ISR(TIMER2_COMP_vect) |
19 | {
|
20 | ///Timer ca 252µs laufen lassen +1 vom INT0 Interrupt
|
21 | OCR2 = 61; |
22 | count++; |
23 | if (count > 10) |
24 | {
|
25 | count = 9; |
26 | }
|
27 | |
28 | }
|
29 | |
30 | |
31 | ///Pause Timer
|
32 | ISR (TIMER1_COMPA_vect) |
33 | {
|
34 | pause++; |
35 | if (pause > 250){pause = 249;} |
36 | |
37 | }
|
38 | |
39 | uint32_t lesen(void){ |
40 | |
41 | uint8_t i; |
42 | uint32_t daten = 0x00; |
43 | |
44 | |
45 | for (i=1;i<33;i++) |
46 | {
|
47 | ///Solange keine Flanke, warten
|
48 | while (flanke != 1); |
49 | ///Wenn Flanke erkannt, auf 0 zurücksetzen
|
50 | if (flanke == 1) |
51 | {
|
52 | flanke = 0; |
53 | }
|
54 | ///Warten bis Timer 252µs gezählt hat
|
55 | while (count != 1); |
56 | ///wenn 252µs erreicht
|
57 | if (count == 1) |
58 | {
|
59 | ///Pin auf High, Bit setzen, sonst auf 0 lassen.
|
60 | if ( PIND & ( 1 << 1 ) ) |
61 | {
|
62 | daten |= (1<<i); |
63 | |
64 | }
|
65 | }
|
66 | |
67 | }
|
68 | ///Daten zurückgeben
|
69 | return daten; |
70 | |
71 | }
|
72 | |
73 | int main(void) |
74 | {
|
75 | uint32_t display; |
76 | char buffer[31]; |
77 | pause = 0; |
78 | flanke = 0; |
79 | read = 0; |
80 | |
81 | TCCR1B = (1<<CS11) | (1<<WGM12);///Prescaler auf 1024 und CTC |
82 | OCR1A = 124; ///Comparematch 86 -> 125 µs, also 88 mal für pause |
83 | |
84 | |
85 | TCCR2 = (1<<CS20) | (1<<CS21) | (1<<WGM21); ///Prescaler 32 Takt 8Mhz und CTC |
86 | OCR2 = 62; ///Comparematch 62 -> 252 µs |
87 | TIMSK |= (1<<OCIE2) | (1<<OCIE1A); /// Interrupts aktivieren, Timerstart |
88 | sei(); |
89 | |
90 | |
91 | ///Externer Interrupt aktivieren
|
92 | ///***
|
93 | GICR |= (1<<INT0);///INT0 eingang |
94 | MCUCR |= (1<<ISC11);///Fallende Flanke erzeugt den Interrupt |
95 | ///***
|
96 | |
97 | lcd_init(LCD_DISP_ON); |
98 | lcd_clrscr(); |
99 | lcd_command(_BV(LCD_CGRAM)); |
100 | |
101 | while(1){ |
102 | ///Wenn 11ms vorbei (88 x 125µs)
|
103 | if (pause > 87) |
104 | {
|
105 | ///Bereit zum lesen machen
|
106 | read = 1; |
107 | ///Pausendetektor auf 0 setzen
|
108 | pause = 0; |
109 | }
|
110 | ///Wenn Bereit zu lesen Read zurücksetzen und lesen() aufrufen
|
111 | if (read == 1) |
112 | {
|
113 | read = 0; |
114 | display = lesen(); |
115 | itoa (display, buffer, 10); |
116 | lcd_clrscr(); |
117 | lcd_puts(buffer); |
118 | }
|
119 | |
120 | |
121 | }///While |
122 | |
123 | }
|
1 | TCCR1B = (1<<CS11) | (1<<WGM12);///Prescaler auf 1024 und CTC |
das soll natürlich nicht 1024 sondern 8 sein, da hab ich vergessen die Kommentierung umzuschreiben
David schrieb: > Das Signal hat 32 Bit (also 32 verschiedene Leuchtelemente auf der > Displaytafel) > > Das Signal baut sich so auf. > > Erst wird ca. 11ms eine Pause abgewartet (Signal High). Fällt die > Flanke, kommt nach 241,77µs das erste bit. Dann muss man warten bis das > Signal nach ein paar µs wieder auf High geht und erneut fällt. Dann > wiederum muss 241,77µs auf das nächste Bit gewartet werden, etc. Sei mir nicht böse und wahrscheinlich kannst du nichts dafür. Aber wer denkt sich denn so einen Schwachsinn aus? In diesem Protokoll wird haufenwweise gewartet. Zuerst 11ms, dann 241µs. Nur in der 'heißen' Phase, wenn es darum geht den Zustand zu samplen, muss alles plötzlich auf 1µs genau sein? Demjenigen der sich das ausgedacht hat (wenn du die Protokollbeschreibung richtig hast), sollte man mit einem nassen Fetzen erschlagen. Der ist nicht zufällig BWL-er?
Was heißt den da haufenweiße warten???? Das ist ein ganz normales Protokoll??? Da is ne Pause, und danach kommen die Daten. Und damit man weiß welches Bit kommt, wartet man eine Flanke ab, und dann nach den paar µs kommt dann das Bit? Das is doch absolut simpel. und ob es auf eine 1µs wirklich ankommt weiß ich nicht. Da steht ne Tabelle, bei welcher Zeit welches Bit kommt, und obendrüber +- 0.5 % Und daran will ich mich nur halten. Gruß
Hat den keiner n kleinen Tipp wie ich den Timer auf 0 zurücksetze, damit er wieder neu zum zählen anfängt? Danke
TCNT2 = 0 sollte wohl gehen:P Man bin ich blind, das Stand sogar oben...
Zusätzlich habe ich nen Fehler gefunden, und zwar wird der Interrupthandeler vom INT0 solange aufgerufen, solang nach der gefallenen Flanke, das Signal auf low bleibt. Konnte ich aber auch nur mim Logicanalyzer feststellen...
>Zusätzlich habe ich nen Fehler gefunden, und zwar wird der >Interrupthandeler vom INT0 solange aufgerufen, solang nach der >gefallenen Flanke, das Signal auf low bleibt. Konnte ich aber auch nur >mim Logicanalyzer feststellen... Manche Interrupt-Flags muss man von Hand zurücksetzen...
Hey, Also es funktionier alles, ich hab einfach jedesmal die Timer usw. gestoppt, so dass sie sich nicht gegenseitig beeinflussen. Jetz läuft alles 1 a!
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.