Forum: Compiler & IDEs Timer auf Befehl starten


von David (Gast)


Lesenswert?

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

von David (Gast)


Lesenswert?

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?

von Grrrr (Gast)


Lesenswert?

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.

von Flo (Gast)


Lesenswert?

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 ;-)

von David (Gast)


Lesenswert?

GENIAL! Auf die Idee bin ich nicht gekommen. Natürlich funktioniert das 
so.

Dankeschön :)

War übrigends ein Atmega 8535.

Danke

von David (Gast)


Lesenswert?

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

von Grrrr (Gast)


Lesenswert?

David schrieb:
> das ist auserhalb von meinen 0,5% Toleranz

Ich rechne bei 250,666667µs eine Abweichung von 0.44% aus.

von David (Gast)


Lesenswert?

Oh, du hast recht, ist schon spät... habs falsch gerechnet, aber danke 
:)

von Karl H. (kbuchegg)


Lesenswert?

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?

von David (Gast)


Lesenswert?

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
}

von David (Gast)


Lesenswert?

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

von Karl H. (kbuchegg)


Lesenswert?

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?

von David (Gast)


Lesenswert?

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ß

von David (Gast)


Lesenswert?

Hat den keiner n kleinen Tipp wie ich den Timer auf 0 zurücksetze, damit 
er wieder neu zum zählen anfängt?

Danke

von David (Gast)


Lesenswert?

TCNT2 = 0 sollte wohl gehen:P Man bin ich blind, das Stand sogar oben...

von David (Gast)


Lesenswert?

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...

von STK500-Besitzer (Gast)


Lesenswert?

>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...

von David (Gast)


Lesenswert?

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
Noch kein Account? Hier anmelden.