Forum: Mikrocontroller und Digitale Elektronik Fehler in der Timerinitialisierung


von µC-noob (Gast)


Lesenswert?

Wo liegt mein Fehler:

Gerät:
Atmega 128
fcpu = 16MHz
Timerinterrupt soll alle 10ms aufgerufen werden

Laut datenblatt:

fOC = (fcpu) / ( 2 * N *( OC - 1) )

=>
OC =  [(fcpu) / ( 2  N  f0C )] - 1

Also für ca. 10ms

OC = 16MHz / (2* 1024 * 1 / 10ms) - 1
OC = 77

=> 255 - 77 = 178
1
void timer0_init(void)
2
{
3
  // 
4
  //  TCCR0 [FOC0  WGM00  COM01  COM00  WGM01  CS02  CS01  CS00]
5
  //        [ 0      0     0       0      1     1     1      1 ]
6
  //
7
  TCCR0      =   (1<<CS00)  | (CS01) | (1<<CS02) | (1<<WGM01);  //prescaler 1024, CTC-mode
8
9
  //
10
  // OCIE2 [TOIE2 TICIE1 OCIE1A OCIE1B TOIE1 OCIE0 TOIE0 TIMSK]
11
  //       [ 0      0     0       0      1     1     1      1 ]
12
  //
13
  TIMSK      |=   (1<<OCIE0);                //Enable Timer/iCounter0 Compare Match interrupt.
14
       
15
  ASSR     =   0x00;                   //intern clock (!= from TOSC), synchronous clock
16
  OCR0    =   178;                     //timetick = 10ms: (1/(F_CPU/1024) x 156 = 10ms)
17
}
1
ISR(TIMER0_COMP_vect)     
2
{
3
  globalTime_10ms++;
4
}

Wenn ich nun die Zeit hochlaufen lass, läuft die Weitaus schneller als 
10ms.

Was ist falsch??

Gruß
Jo

von Johannes M. (johnny-m)


Lesenswert?

Schau Dir die Zeile mit TCCR0 mal genau an...

...v.a. die Stelle mit CS01...

Na, siehste das auch? Dein Timer läuft genau 8 mal so schnell, wie er 
sollte.

von Paul Baumann (Gast)


Lesenswert?

Ich verstehe nichts von C, denke aber, daß Du so knapp 5ms erzeugst.

16Mhz/1024=15625Hz
und dann: 15625Hz / 77 = ca. 203Hz

das wären 4,9ms

Meines Achtens müßte statt 77 99 da stehen.

MfG Paul

von Johannes M. (johnny-m)


Lesenswert?

Paul Baumann wrote:
> Ich verstehe nichts von C, denke aber, daß Du so knapp 5ms erzeugst.
>
> 16Mhz/1024=15625Hz
> und dann: 15625Hz / 77 = ca. 203Hz
Richtig, er hat noch nen Faktor 2 drin. Wenn er einen Pin toggeln will 
mit einer Periodendauer von 10 ms (also 100 Hz), dann wären die 
Einstellungen richtig...

> Meines Achtens müßte statt 77 99 da stehen.
Wieso 99? Wohl eher 155...
15625 Hz / 156 = ca. 100 Hz
bzw.
64 µs * 156 = 9,98 ms

EDIT:
Sorry, hatte nicht gesehen, worauf Du genau mit der 77 hinauswolltest... 
Aber ich denke, wenn man es so rechnet wie oben, dann leuchtet es ein.

von Paul Baumann (Gast)


Lesenswert?

Ja, so habe ich das gemeint: Er lädt oben in seinem Programm den Timer 
mit
178. Dann läuft der Timer von da ab bis 255. Wenn man ihn mit 99 lädt, 
dann macht er noch 156 Schritte bis "oben hin".

MfG Paul

von Johannes M. (johnny-m)


Lesenswert?

Paul Baumann wrote:
> Ja, so habe ich das gemeint: Er lädt oben in seinem Programm den Timer
> mit
> 178. Dann läuft der Timer von da ab bis 255. Wenn man ihn mit 99 lädt,
> dann macht er noch 156 Schritte bis "oben hin".
Das stimmt ja nicht. Er benutzt ja die Compare-Einheit (CTC-Betrieb), 
und da läuft der Timer von 0 bis 178+1. Er hat nur die Werte irgendwie 
durcheinandergebracht (und eben auch noch den Faktor 2 drin, den man nur 
braucht, wenn man einen Pin toggeln will, weil man dann pro Periode 
zweimal toggeln muss).

Er hat ja schon den Compare-Wert richtig ausgerechnet, dann aber:
=> 255 - 77 = 178
...und schreibt den Wert ins OCR, was natürlich falsch ist. Die 77 hätte 
in dem Fall ins OCR gehört und nicht die Differenz. Bis auf die Zeile 
und die 2 stimmt es aber...

von Paul Baumann (Gast)


Lesenswert?

Ach so, CTC-Betrieb hatte ich übersehen. (Schäm)

MfG Paul

von µC-noob (Gast)


Lesenswert?

Danke erstmal,
aber irgendwie tuts noch nicht wies soll.

Hier mal des Timercode:
1
void timer0_init(void)
2
{
3
  // 
4
  //  TCCR0 [FOC0  WGM00  COM01  COM00  WGM01  CS02  CS01  CS00]
5
  //        [ 0      0     0       0      1     1     1      1 ]
6
  //
7
  TCCR0      =   (1<<CS00)  | (CS01) | (1<<CS02) | (1<<WGM01);  //prescaler 1024, CTC-mode
8
9
  //
10
  // OCIE0 [TOIE2 TICIE1 OCIE1A OCIE1B TOIE1 OCIE0 TOIE0 TIMSK]
11
  //       [ 0      0     0       0      0     0     0      1 ]
12
  //
13
  TIMSK      |=   (1<<OCIE0);                //Enable Timer/iCounter0 Compare Match interrupt.
14
       
15
  OCR0    =   155;                     //timetick = 10ms: (1/(F_CPU/1024) x 155 = 10ms)
16
} 
17
18
19
ISR(TIMER0_COMP_vect)     
20
{
21
  globalTime_10ms++;
22
}

Ok nun habe ich vorerst zu testzwecken eine Zeit hochlaufen Lassen:
1
void task_systemTime(void)
2
{ 
3
4
  if (globalTime_10ms >= 100 ) // 10ms * 100 = 1000ms = 1s
5
  {   
6
    globalTime_10ms = globalTime_10ms - 100;                   
7
      STO_Time.Second++;                    
8
  } 
9
10
  if (STO_Time.Second >= 60)
11
  {      
12
    STO_Time.Second = STO_Time.Second - 60;                 
13
      STO_Time.Minute++;                    
14
  } 
15
16
  if (STO_Time.Minute >= 60)
17
  {                      
18
      STO_Time.Minute = STO_Time.Minute - 60;
19
      STO_Time.Hour++;                    
20
  }
21
22
  if (STO_Time.Hour >= 24)
23
  {
24
      STO_Time.Hour = STO_Time.Hour - 24;
25
      STO_Time.Day++;
26
    }
27
28
  if (STO_Time.Day >=31)
29
  {
30
    STO_Time.Second = 0;
31
    STO_Time.Minute = 0;
32
    STO_Time.Hour = 0;
33
    STO_Time.Day = 0;
34
  }
35
}

Aber das ist alles nur keine richtige Zeit.

Was ist noch falsch, wo liegt mein denkfehler.

von Falk B. (falk)


Lesenswert?

@ µC-noob (Gast)

>Aber das ist alles nur keine richtige Zeit.
>Was ist noch falsch, wo liegt mein denkfehler.

Ein VOLLSTÄNDIGER  Quelltext wäre hilfreich. Bitte als Anhang.

MFG
Falk

von Michael Wilhelm (Gast)


Lesenswert?

>TCCR0      =   (1<<CS00)  | (CS01) | (1<<CS02) | (1<<WGM01);
                             ^^^^^^

//prescaler 1024, CTC-mode

MW

von Karl H. (kbuchegg)


Lesenswert?

µC-noob wrote:
> Danke erstmal,
> aber irgendwie tuts noch nicht wies soll.
>
> Hier mal des Timercode:
>
>
1
> void timer0_init(void)
2
> {
3
>   //
4
>   //  TCCR0 [FOC0  WGM00  COM01  COM00  WGM01  CS02  CS01  CS00]
5
>   //        [ 0      0     0       0      1     1     1      1 ]
6
>   //
7
>   TCCR0      =   (1<<CS00)  | (CS01) | (1<<CS02) | (1<<WGM01);
8
> //prescaler 1024, CTC-mode
9
>

> Was ist noch falsch, wo liegt mein denkfehler.

Und nochmal der Hinweis:

Schau Dir die Zeile mit TCCR0 mal genau an...

...v.a. die Stelle mit CS01...

von MD-Gast (Gast)


Lesenswert?

Hallo,
ich denke Karl hat Recht ;-). Also, da ist der Faktor falsch: da fehlt 
das (1<<CS01).
Schreib doch einfach:
1
 TCCR0 = 0x0F; //1024er-Scaler, CTC-Mode
Das mit dem OCRA ist 'ne gute Sache. Jedoch meine ich, dass Du den OCRA 
auf 77 setzen mußt, nicht auf 178, da in diesem Modus der TCNT bei 
CompareMatch mit OCRA auf Null gesetzt wird und den Interrupt auslöst 
(kein Overflow mehr, sondern ein CompareMatch).

Grüße

Kai

von Falk B. (falk)


Lesenswert?

@ Michael Wilhelm (Gast)
1
// komische Schreibweise und kann ins Auge gehen!
2
// hier klappt es zufällig!
3
4
// da kommt raus
5
                  1       |    1   |    4      | 8           = 0b1101
6
TCCR0      =   (1<<CS00)  | (CS01) | (1<<CS02) | (1<<WGM01);
7
8
// wenn, dann besser so
9
//                1       |    0      |   4       |    8
10
TCCR0      =   (1<<CS00)  | (0<<CS01) | (1<<CS02) | (1<<WGM01);
11
12
// besser so
13
14
TCCR0      =   (1<<WGM01) | 5;

MFG
Falk

von MD-Gast (Gast)


Lesenswert?

Nochmal,
upps...Fehler <schäm>
Prescaler: 5 = 1024 ... nich nörgeln. ;-)
TCCR0 = 0x05+0x08; //1024er-Scaler, CTC-Mode
...so wie Falk sacht.

Kai

von MD-Gast (Gast)


Lesenswert?

Nochmals ...dat mit 77 war auch Müll von mir,

zur Richtigstellung für AT90CAN128 an 16MHz:

Timer0 mit timeOver-Methode:
1
u32 CPUCLK=8000000;       //std. 8MHz
2
u08 SCLOCK=8;      //std. 8MHz
3
4
//count up in Timer with 100Hz
5
volatile u16 Delay_SystemTicks=0;
6
//change OCR0A if Frequency!~=100Hz is needed
7
8
//---------------------------------------------------------
9
//---------------------------------------------------------
10
//Timer
11
static void (*T0_Intfunction)(void);
12
13
//---------------------------------------------------------
14
//---------------------------------------------------------
15
// initialize timer 0
16
// Param: Freq, external function
17
// Timer is used for Ramps, Controls, Can-Output, Keys etc.
18
//---------------------------------------------------------
19
void CPUSYS_init(u08 Freq,void (*insertTimer0Int) (void))
20
{
21
  //JTAG disable  ... muss ja nich
22
  MCUCR=0x80;
23
  MCUCR=0x80;  
24
  //
25
  TIMSK0=(1<<OCIE0A);  //OC-Interrupt enab
26
  //
27
  TCCR0A=(0x08)|(0x05);   //CTC|5 = CLOCK/1024
28
  if (Freq==16) {
29
    SCLOCK=16;   //set Systemclock to 16 MHz
30
    CLKPR=0x80;  //for AT90CAN128
31
    CLKPR=0x00;  //16 MHz
32
  }
33
  else {
34
    SCLOCK=  8;
35
    //set Systemclock to 8 MHz
36
    CLKPR=0x80;  //for AT90CAN128
37
    CLKPR=0x01;  //8 MHz
38
  }
39
  //
40
  CPUCLK  =1000000*SCLOCK;
41
  //100Hz-Init
42
  OCR0A   =(u08)(CPUCLK/(u32)102400); //+/-1 for nuts
43
  TCNT0   =0;            //set Counter
44
  //
45
  T0_Intfunction=insertTimer0Int;
46
}
47
48
//---------------------------------------------------------
49
//IRQ handler
50
SIGNAL(SIG_OUTPUT_COMPARE0)
51
{
52
  //
53
  Delay_SystemTicks++;
54
  //
55
  T0_Intfunction();
56
}
57
58
//---------------------------------------------------------
59
//Delay_SystemTicks counted up in Timer0
60
//return 1 if Timeout
61
u08 timeOver(u16 oldtime,u16 MaxDiff) {
62
  u16 Difference=Delay_SystemTicks-oldtime;
63
  if (Difference>MaxDiff)
64
    return 1;
65
  else
66
    return 0;
67
}

von Johannes M. (johnny-m)


Lesenswert?

@MD-Gast:
Bitte nicht SIGNAL! Das ist veraltet und µC-noob hat das in seinem 
ersten Versuch schon ganz richtig mit ISR gemacht!

von µC-noob (Gast)


Lesenswert?

Danke euch allen für eure Hilfe, es läuft jetzt....

Nur hab ich noch nicht exakt 10ms, da muss ich noch hirnen,...

Grund:

Über Timer0 läuft ein Tasksystem und eine zentrale Uhr die in 10ms 
schritten läuft.

Von dieser Zentralen Uhr leite ich dann alles andere ab (sec, min std, 
tag....
Ich weiß, besser wär ss::mm:hh, aber die Vorgabe ist eine Zentrale Zeit 
in ms.

Hab folgendes gefunden:
Beitrag "Die genaue Sekunde / RTC"

Mal schauen ob ichs versteh....

chiao
Jo

von Johannes M. (johnny-m)


Lesenswert?

Das Hauptproblem, warum es nicht genau 10 ms sind, liegt in der Wahl des 
Vorteilers. Wenn Du mit 16 MHz taktest und diesen Takt durch 1024 
teilst, dann kommt eben was raus, was nicht mehr ganzzahlig in 10 ms 
reingeht. Wenn es auch 1 oder 2 ms sein können: die lassen sich bei der 
Taktfrequenz problemlos präzise erzeugen. Bei einem Prescaler von 128 
und einem Compare-Wert von 249 gibts z.B. 1 ms, bei einem Prescaler von 
256 und ebenfalls einem Compare-Wert von 249 dann 2 ms. Mehr ist mit dem 
8-Bit-Timer bei 16 MHz nicht drin.

von µC-noob (Gast)


Lesenswert?

Danke!

Werds auf 1ms initialisieren


Gruß

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.