Forum: Mikrocontroller und Digitale Elektronik hilfe für neueinsteiger - timerprogramierung


von swen (Gast)


Lesenswert?

Hallo liebe Gemeinde,

bin nun auch dem avr´s verfallen :) (..mache grad nen e-techniker), tue 
mich aber noch ein bissel schwer mit der programierung. c/c++ 
grundkennisse sind vorhanden.

ich versuch mich am stk500 mit nem atmega 8 (4mhz ext. quartz), atmega16 
&8815 wären auch vorhanden.

ich versuche mich gerade am timer. hab dazu ein testprogramm geschrieben 
(ja ich weis sollte besser über interupts geschehen, aber ich muss 
erstmal den timer verstehen bevor ich mit interrupts beschäftige, von 
daher verzeiht mir)

nun mein problem: der counter läuft nicht so wie ich gern möchte. er 
sollte im sekundentakt auf einem lcd hochzählen. läuft aber viel zu 
schnell (so mit gefühlen 1000hz - brauch also eine sekunde für nen 
durchlauf) am lcd.


hier mein prog:
1
#include <avr/io.h>
2
#include <stdlib.h>
3
#include "lcd-routines.h"
4
 
5
unsigned char  z;
6
int s = 0;
7
short a = 0;
8
9
10
int main()
11
{
12
13
lcd_init(); // LCD init
14
15
TCCR0 = (1<<CS01) | (1<<CS00);  // Prescaler Timer0 auf 1024 setzn
16
17
DDRB  = 0x00;  // Port B als Ausgang setzen
18
19
20
do{
21
  do{
22
    
23
    do{
24
    z = TIFR;  // Timer Counter Register auslesen
25
    z = z & 0x01; // Timer Interupt Flag (TOV0) mit Logisch 1 vergleichen 
26
    }
27
28
    while (z == 0); // Schleife solange wie TOV0 nicht gesetzt (Logisch 0)
29
30
  s=s+1; // "s" um 1 erhöhen 
31
  TIFR = (0<<TOV0); // Timer Interupt Flag (TOV0) zurücksetzen
32
  }
33
  while (s<15); // Schleife solange wie "s" < 15 (4Mhz/256/1024/15 sollte rund 1 Hz sein)
34
35
s=0;  // Schleifenzähler "s" zurücksetzen
36
a=a+1; // Zähler für LCD Ausgabe um 1 erhöhen
37
38
  {
39
  char b[5]; // b definieren
40
    itoa( a, b, 10 ); // übergabe int a >> char b
41
  set_cursor (0,1); // cursor pos setzen
42
  lcd_string( b ); // Anzeige b
43
   }
44
}   
45
while (a<1000); // bei LCD Anzeige 1000 beenden
46
47
return 0;
48
}


ich hab alles schön mit "remarks" meiner gedankengänge gefüllt. helft 
mir bitte meine "irrungen" zu finden.

grüsse swen

von spess53 (Gast)


Lesenswert?

Hi

> TIFR = (0<<TOV0); // Timer Interupt Flag (TOV0) zurücksetzen

...Alternatively,TOV0 is cleared by writing a logic one to the flag.

MfG Spess

von Karl H. (kbuchegg)


Lesenswert?

Diese Interrupt Flags werden anders zurückgesetzt

Nicht
  TIFR = (0<<TOV0); // Timer Interupt Flag (TOV0) zurücksetzen

sondern
  TIFR = (1<<TOV0); // Timer Interupt Flag (TOV0) zurücksetzen

(Ja das stimmt. Man schreibt eine 1 an die Position, an der man das Flag 
zurückgesetzt haben will)

von swen (Gast)


Lesenswert?

danke!,

das hätt ich wissen müssen, habs beim hier angebotenen tutorial 
gelesen..

-> achja wobei natürlich das "TOV0" nen overflow flag ist und kein 
interupt flag (tut aber programmtechnisch nix zu sache..) mein fehler :(

jetzt läuft wesentlich langsamer aber immer noch so mit 15hz zählrate.

hab ich da ne falsche vorstellung von der teilung des zählers?

von spess53 (Gast)


Lesenswert?

Hi

>jetzt läuft wesentlich langsamer aber immer noch so mit 15hz zählrate.


Ein 8-Bit-Timer hat bei 4MHz und Vorteiler 1024 eine Overflowtime von 
ca.65ms. Und 1/65ms macht ca. 15Hz.

von swen (Gast)


Lesenswert?

spess53 schrieb:
> Ein 8-Bit-Timer hat bei 4MHz und Vorteiler 1024 eine Overflowtime von
> ca.65ms. Und 1/65ms macht ca. 15Hz.


genau deswegen mache ich ja ne schleife mit 15 counts bevor am lcd 
höchgezählt wird.

[c]
while (s<15); // Schleife solange wie "s" < 15 (4Mhz/256/1024/15 sollte 
rund 1 Hz sein)
/[c]

hab trozdem keine 1Hz.

hab mal probehalber die schleife auf 250 gesetzt. ha sind ungefähr 1hz 
zählrate. mir ist das so wichtig weil ich einen frequenzzähler basteln 
möchte

von Karl H. (kbuchegg)


Lesenswert?

Nachmal ins Datenblatt:

Das hier
TCCR0 = (1<<CS01) | (1<<CS00);  // Prescaler Timer0 auf 1024 setzn

ist kein Vorteiler von 1024

(Und tu dir selbst einen Gefallen und sorg für ein sauberes 
Erscheinungsbild deines Codes. Du schiesst dich nur ins eigene Knie, 
wenn du es nicht tust. Einrückungen sollen konsistent sein. AUs 2 Meter 
Entfernnung soll erkennbar sein, welche Codeteile zusammen gehören und 
welche nicht. Viele Leerzeilen hintereinander ziehen den Code nur in die 
Länge, erhöhen aber nicht die Übersicht)

von swen (Gast)


Lesenswert?

danke Karl heinz,

ich hatte wirklich vorher ins datenblatt geschaut (seite 72). hab mich 
wohl in der zeile vertan, selbst beim kontrollieren. nun läufts prima!

mfg swen

von swen (Gast)


Lesenswert?

Karl heinz Buchegger schrieb:
> (Und tu dir selbst einen Gefallen und sorg für ein sauberes
> Erscheinungsbild deines Codes. Du schiesst dich nur ins eigene Knie,
> wenn du es nicht tust. Einrückungen sollen konsistent sein. AUs 2 Meter
> Entfernnung soll erkennbar sein, welche Codeteile zusammen gehören und
> welche nicht. Viele Leerzeilen hintereinander ziehen den Code nur in die
> Länge, erhöhen aber nicht die Übersicht)


jo werd ich ab jetzt machen. asche auf mein haupt

von Karl H. (kbuchegg)


Lesenswert?

Du sollst auch den 'natürlichen' Schleifentyp für eine Aufgabe benutzen. 
Wenn du Dinge abzählen willst, dann benutze eine for-Schleife. Dort hast 
du
  * Startwert
  * Endwert (und damit implizit die Anzahl der Wiederholungen)
  * den Wert um den erhöht wird
an einer Stelle beisammen und nicht quer über den ganzen Code verstreut

So könnte das zb aussehen
1
#include <avr/io.h>
2
#include <stdlib.h>
3
#include "lcd-routines.h"
4
 
5
uint8_t  NrTimerLoops;
6
uint16_t Counter = 0;
7
8
int main()
9
{
10
  DDRB  = 0x00;  // Port B als Ausgang setzen
11
  lcd_init();    // LCD init
12
13
  TCCR0 = (1<<CS01) | (1<<CS00);  // Prescaler Timer0 auf 64 setzn
14
15
  for( Counter = 0; Counter < 1000; Counter++ ) {
16
17
    // 15 Wiederholungen
18
    // 4Mhz/256/1024/15 -> 1Hz
19
    for( NrTimerLoops = 0; NrTimerLoops < 15; NrTimerLoops++ ) {
20
21
      while( TIFR & (1<<TOV0) )     // auf eine 1 im TOV0 Bit warten
22
        ;                           // -> der Timer ist übergelaufen
23
      TIFR = (1<<TOV0);             // Timer Interupt Flag (TOV0) zurücksetzen
24
    }
25
26
    {
27
      char b[5];                 // b definieren
28
      utoa( Counter, b, 10 );    // übergabe int a >> char b
29
      set_cursor (0,1);          // cursor pos setzen
30
      lcd_string( b );           // Anzeige b
31
    }
32
  }
33
34
  return 0;
35
}

von swen (Gast)


Lesenswert?

danke für die mühe karl heinz,

mit der for- schleife ist natürlich viel besser!

wobei wir natürlich

TCCR0 = (1<<CS02) | (1<<CS00);

setzen müssen sonst wird es nichts mit prescaler 1024 ;-).

ich habs gerade mal reingespielt. es hängt bei "178". werd mich dann mal 
dransetzen, muss wersmal ausser haus was erledigen gehen...

bis später

grüsse
swen

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.