Forum: Mikrocontroller und Digitale Elektronik Fragen zum Timer (c-code)


von Jochen W. (-joh-)


Angehängte Dateien:

Lesenswert?

Moin zusammen,

ich hab' mir aus diversen Quellen (Tutorial, Doku etc.) mittlerweile so 
viele Infos zum Thema 7-Segment-Anzeigen und Timer reingepfiffen ... 
jetzt weiß ich nicht mehr, ob ich auf dem richtigen Schlauch stehe.

Der Code funktioniert.
Das Programm tut, was es soll.

Aber ich hätte doch gerne eine Bestätigung dafür, das ichs richtig mache 
und nicht nur Teufel Zufall das ganze funktionieren lässt^^

Also zum Ansatz:
- atmega8 als Prozessor, PORTD für die Ausgabe, PORTB für das 
Multiplexing via Transistor
- ich möchte ein Thermometer zum Auslesen der Werte aus dem 
Pufferspeicher mit Anzeige von 2 Temperaturen auf einer Anzeige 
realisieren
(Das Auslesen kommt später, erstmal muß ich 'ne stimmige Anzeige haben)
- Die Anzeige soll per Interrupt-Routine aus Variablen, die irgendwann 
die Temperaturroutine beschicken, angezeigt werden.
(Bei meinen ersten Tests (mit delay im Hauptprogramm) fiel mir auf, das 
die Anzeige bei längeren Berechnungen flackert)

Jetzt zu den Fragen:
- ich habe der Einfachkeit halber die beiden 8-bit-Timer benutzt, den 
einen davon einfach in ner Schleife im ISR nochmal um den Faktor 4 
verlängert. Ist das so krude, wie es mir vorkommt?
- Die Routine im Timer 1 ist mir für nen Anfangsversuch schon recht 
lang. Oder spielt das keine Rolle?
- Im Hauptprogramm hab' ich 'n zusätzliches Delay stehen. Bringt das 
was?
- wo gibt es sonstige Designfehler?

PS: Programmieren kann ich, hatte aber bisher weder was mit C noch mit 
µC zu tun. Daher wohl auch mein Versuch, am Anfang sauber zu 
programmieren.


Gruß
Joh

von Falk B. (falk)


Lesenswert?

@  Jochen W. (-joh-)

>Aber ich hätte doch gerne eine Bestätigung dafür, das ichs richtig mache
>und nicht nur Teufel Zufall das ganze funktionieren lässt^^

>- ich habe der Einfachkeit halber die beiden 8-bit-Timer benutzt, den
>einen davon einfach in ner Schleife im ISR nochmal um den Faktor 4
>verlängert. Ist das so krude, wie es mir vorkommt?

Ja ;-)

Du brauchst keine zwei Timer. Das kann man problemlos in einen 
Timer(interrupt) packen.

>- Die Routine im Timer 1 ist mir für nen Anfangsversuch schon recht
>lang.

Nein, das täuscht. Und lang ist relativ, siehe Interrupt. Die 
Routine muss nur weniger Zeit benötigen als das Timerintervall.

> Oder spielt das keine Rolle?

>- Im Hauptprogramm hab' ich 'n zusätzliches Delay stehen. Bringt das
>was?

Nö.

>- wo gibt es sonstige Designfehler?

Soweit keine.

MFG
Falk

von Karl H. (kbuchegg)


Lesenswert?

Die Reihenfolge der Aktionen in der ISR stimmt noch nicht ganz.
Du musst:

   Die vorhergehende Anzeige abschalten (PORTB)
   Das Bitmuster für die Segmente für die nächste
        Anzeige einschalten (PORTD)
   Die nächste Anzeige einschalten  (PORTB)

Ansonsten riskierst du 'Geisterbilder', weil du die nächste Anzeige 
schon einschaltest, während noch das Segmentmuster der vorhergehenden 
Anzeige an den LED anliegt.

>- Die Routine im Timer 1 ist mir für nen Anfangsversuch schon recht
>lang.

Um das noch einmal aufzugreifen, Falk hat sich ja dazu schon geäussert.
Du darfst nicht nach der Codemenge gehen. Die ist im Grunde egal, 
wichtig ist wieviel Zeit dieser Code verbraucht. Die ISR kann auch 2 
Bildschirmseiten lang sein. Wenn bei jedem ISR Aufruf immer nur 3 oder 4 
Zeilen davon zum Zug gekommen, dann ist sie (aus zeitlicher Sicht 
gesehen) immer noch kurz. Du hast zwar 'viel' Code in der ISR (in 
Wirklichkeit ist das auch noch nicht viel) aber von diesem Code wird bei 
jedem ISR Aufruf immer nur einer der case Zweige ausgeführt. Wenn du 
einen ISR AUfruf in Gedanken durchspielst, dann siehst du dass da nicht 
viel passiert und damit ist das dann ok.

von Jochen W. (-joh-)


Lesenswert?

Falk Brunner schrieb:

>>- ich habe der Einfachkeit halber die beiden 8-bit-Timer benutzt, den
>>einen davon einfach in ner Schleife im ISR nochmal um den Faktor 4
>>verlängert. Ist das so krude, wie es mir vorkommt?
>
> Ja ;-)

hmmm, und wie mach ichs besser?

> Du brauchst keine zwei Timer. Das kann man problemlos in einen
> Timer(interrupt) packen.

Ich hatte mir das so gedacht, das der eine Timer für die Anzeige ja mit 
60 Hz. getaktet wird, der andere (zum auslesen der Temperatur oder im 
Test als quasi-Sekundenanzeige) ja nur 1 x pro Sekunde.

Joh

von Jochen W. (-joh-)


Lesenswert?

Karl heinz Buchegger schrieb:

> Du musst:
>    Die vorhergehende Anzeige abschalten (PORTB)
>    Das Bitmuster für die Segmente für die nächste
>         Anzeige einschalten (PORTD)
>    Die nächste Anzeige einschalten  (PORTB)
>
> Ansonsten riskierst du 'Geisterbilder', weil du die nächste Anzeige
> schon einschaltest, während noch das Segmentmuster der vorhergehenden
> Anzeige an den LED anliegt.

klingt logisch. Hatte ich bisher noch nicht gelesen (oder wohl eher 
realisiert).

>>- Die Routine im Timer 1 ist mir für nen Anfangsversuch schon recht
>>lang.
>
> Um das noch einmal aufzugreifen, Falk hat sich ja dazu schon geäussert.
> Du darfst nicht nach der Codemenge gehen. Die ist im Grunde egal,
> wichtig ist wieviel Zeit dieser Code verbraucht. Die ISR kann auch 2
> Bildschirmseiten lang sein. Wenn bei jedem ISR Aufruf immer nur 3 oder 4
> Zeilen davon zum Zug gekommen, dann ist sie (aus zeitlicher Sicht
> gesehen) immer noch kurz. Du hast zwar 'viel' Code in der ISR (in
> Wirklichkeit ist das auch noch nicht viel) aber von diesem Code wird bei
> jedem ISR Aufruf immer nur einer der case Zweige ausgeführt. Wenn du
> einen ISR AUfruf in Gedanken durchspielst, dann siehst du dass da nicht
> viel passiert und damit ist das dann ok.

jepp, hast recht. Ich las nur immer: darf nicht lang sein; wenn sich das 
reinweg auf die Anzahl der verbratenen Takte bezieht habe ich zwischen 
60 Hz für die Anzeige und 1 MHz des Prozessors massig Befehle, die ich 
unterbringen kann.

Joh

von Falk B. (falk)


Lesenswert?

@  Jochen W. (-joh-)

>hmmm, und wie mach ichs besser?

Hab ich doch schon ansatzweise skizziert.

>> Du brauchst keine zwei Timer. Das kann man problemlos in einen
>> Timer(interrupt) packen.

>Ich hatte mir das so gedacht, das der eine Timer für die Anzeige ja mit
>60 Hz. getaktet wird, der andere (zum auslesen der Temperatur oder im
>Test als quasi-Sekundenanzeige) ja nur 1 x pro Sekunde.

Sicher, aber das ist massive Verschwendung. AUch wenn du in den meisten 
AVRs 3 Timer drin hast, aknn man sowas problemlos in einen Timer packen. 
In deinem 60 Hz Interrupt zählst du eine Variable hoch, wenn die 60 
erreicht hat, ist eine Sekunde um ;-)
Die paar Befehle sind keine Problem.

MFG
Falk

von Jochen W. (-joh-)


Lesenswert?

Falk Brunner schrieb:

>>hmmm, und wie mach ichs besser?
>
> Hab ich doch schon ansatzweise skizziert.

dann hatte ich dein ja auf meine Frage falsch interpretiert:

>>>> Ist das so krude, wie es mir vorkommt?
>>> Ja ;-)

für mich bezog sich das krude auf den zusätzlichen Zähler im Interrupt
für dich scheinbar auf den zusätzlichen ISR

>>> Du brauchst keine zwei Timer. Das kann man problemlos in einen
>>> Timer(interrupt) packen.
>
>>Ich hatte mir das so gedacht, das der eine Timer für die Anzeige ja mit
>>60 Hz. getaktet wird, der andere (zum auslesen der Temperatur oder im
>>Test als quasi-Sekundenanzeige) ja nur 1 x pro Sekunde.
>
> Sicher, aber das ist massive Verschwendung. AUch wenn du in den meisten
> AVRs 3 Timer drin hast, aknn man sowas problemlos in einen Timer packen.
> In deinem 60 Hz Interrupt zählst du eine Variable hoch, wenn die 60
> erreicht hat, ist eine Sekunde um ;-)
> Die paar Befehle sind keine Problem.

OK, also sollte man möglichst alle Zeitgetriggerten Ereignisse (Codes) 
in einen ISR packen, damit die anderen frei bleiben für andere Aufgaben.
Quasi ne Grundbedingung nach dem Motto:
- zaehler++
- Standardcode z.B. die Displayausgabe
- if (zaehler % x1 == 0)
  anderer code
- if (zaehler % x2 == 0)
  noch anderer code

Gruß
Joh

von Route_66 (Gast)


Lesenswert?

Hallo!
Etwa 60 Hz für eine Multiplexanzeige kömmen mir niedrig vor.
Flimmert es schon sichtbar?

von Falk B. (falk)


Lesenswert?

@Jochen W. (-joh-)

>OK, also sollte man möglichst alle Zeitgetriggerten Ereignisse (Codes)
>in einen ISR packen, damit die anderen frei bleiben für andere Aufgaben.

Nein, nur die Zähler. Dort werden dann Flags gesetzt und die Bearbeitung 
erfolgt meist in der Hauptschleife, siehe Interrupt.

>Quasi ne Grundbedingung nach dem Motto:
>- zaehler++

OK.

>- Standardcode z.B. die Displayausgabe

Hat in der ISR meist nix zu suchen. Ausnahmen sind natürlich gemuxte 
Anzeigen etc.

>- if (zaehler % x1 == 0)
>  anderer code
>- if (zaehler % x2 == 0)
>  noch anderer code

Naja, das % (Modulo) kostet ne Division, die relativ langsam ist. Besser 
einen einfachen Count Down Zähler mit Reload.

1
cnt--
2
if (!cnt) {
3
  CNT = RELOAD_CNT;
4
  flag=1;
5
}

MfG
Falk

von Jochen W. (-joh-)


Lesenswert?

Route_66 schrieb:
> Hallo!
> Etwa 60 Hz für eine Multiplexanzeige kömmen mir niedrig vor.
> Flimmert es schon sichtbar?

UUPS, stimmt...

aus dem Code:
> // Timer 0; 8bit, Prescaler 64 => 1.000.000  64  256 = ca. 61 Hertz
> TCCR0 = (1<< CS01);

hatte den Prescaler erst auf 64, dann aber auf 8 geändert und die 
drüberstehende Berechnung nicht angepaßt^^

ergo: Timer 0; 8bit, Prescaler 8 => 1.000.000  8  256 = ca. 488 Hertz

könnte eher n bischen viel sein...

Joh

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.