mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik Fehler in der Timerinitialisierung


Autor: µC-noob (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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
void timer0_init(void)
{
  // 
  //  TCCR0 [FOC0  WGM00  COM01  COM00  WGM01  CS02  CS01  CS00]
  //        [ 0      0     0       0      1     1     1      1 ]
  //
  TCCR0      =   (1<<CS00)  | (CS01) | (1<<CS02) | (1<<WGM01);  //prescaler 1024, CTC-mode

  //
  // OCIE2 [TOIE2 TICIE1 OCIE1A OCIE1B TOIE1 OCIE0 TOIE0 TIMSK]
  //       [ 0      0     0       0      1     1     1      1 ]
  //
  TIMSK      |=   (1<<OCIE0);                //Enable Timer/iCounter0 Compare Match interrupt.
       
  ASSR     =   0x00;                   //intern clock (!= from TOSC), synchronous clock
  OCR0    =   178;                     //timetick = 10ms: (1/(F_CPU/1024) x 156 = 10ms)
} 
ISR(TIMER0_COMP_vect)     
{
  globalTime_10ms++;
}


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

Was ist falsch??

Gruß
Jo

Autor: Johannes M. (johnny-m)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Paul Baumann (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Johannes M. (johnny-m)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Paul Baumann (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Johannes M. (johnny-m)
Datum:

Bewertung
0 lesenswert
nicht 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...

Autor: Paul Baumann (Gast)
Datum:

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

MfG Paul

Autor: µC-noob (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Danke erstmal,
aber irgendwie tuts noch nicht wies soll.

Hier mal des Timercode:
void timer0_init(void)
{
  // 
  //  TCCR0 [FOC0  WGM00  COM01  COM00  WGM01  CS02  CS01  CS00]
  //        [ 0      0     0       0      1     1     1      1 ]
  //
  TCCR0      =   (1<<CS00)  | (CS01) | (1<<CS02) | (1<<WGM01);  //prescaler 1024, CTC-mode

  //
  // OCIE0 [TOIE2 TICIE1 OCIE1A OCIE1B TOIE1 OCIE0 TOIE0 TIMSK]
  //       [ 0      0     0       0      0     0     0      1 ]
  //
  TIMSK      |=   (1<<OCIE0);                //Enable Timer/iCounter0 Compare Match interrupt.
       
  OCR0    =   155;                     //timetick = 10ms: (1/(F_CPU/1024) x 155 = 10ms)
} 


ISR(TIMER0_COMP_vect)     
{
  globalTime_10ms++;
}

Ok nun habe ich vorerst zu testzwecken eine Zeit hochlaufen Lassen:
void task_systemTime(void)
{ 

  if (globalTime_10ms >= 100 ) // 10ms * 100 = 1000ms = 1s
  {   
    globalTime_10ms = globalTime_10ms - 100;                   
      STO_Time.Second++;                    
  } 

  if (STO_Time.Second >= 60)
  {      
    STO_Time.Second = STO_Time.Second - 60;                 
      STO_Time.Minute++;                    
  } 

  if (STO_Time.Minute >= 60)
  {                      
      STO_Time.Minute = STO_Time.Minute - 60;
      STO_Time.Hour++;                    
  }

  if (STO_Time.Hour >= 24)
  {
      STO_Time.Hour = STO_Time.Hour - 24;
      STO_Time.Day++;
    }

  if (STO_Time.Day >=31)
  {
    STO_Time.Second = 0;
    STO_Time.Minute = 0;
    STO_Time.Hour = 0;
    STO_Time.Day = 0;
  }
}

Aber das ist alles nur keine richtige Zeit.

Was ist noch falsch, wo liegt mein denkfehler.

Autor: Falk Brunner (falk)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Michael Wilhelm (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>TCCR0      =   (1<<CS00)  | (CS01) | (1<<CS02) | (1<<WGM01);
                             ^^^^^^

//prescaler 1024, CTC-mode

MW

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

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

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

Autor: MD-Gast (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,
ich denke Karl hat Recht ;-). Also, da ist der Faktor falsch: da fehlt 
das (1<<CS01).
Schreib doch einfach:
 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

Autor: Falk Brunner (falk)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@ Michael Wilhelm (Gast)

// komische Schreibweise und kann ins Auge gehen!
// hier klappt es zufällig!

// da kommt raus
                  1       |    1   |    4      | 8           = 0b1101
TCCR0      =   (1<<CS00)  | (CS01) | (1<<CS02) | (1<<WGM01);

// wenn, dann besser so
//                1       |    0      |   4       |    8
TCCR0      =   (1<<CS00)  | (0<<CS01) | (1<<CS02) | (1<<WGM01);

// besser so

TCCR0      =   (1<<WGM01) | 5;

MFG
Falk

Autor: MD-Gast (Gast)
Datum:

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

Kai

Autor: MD-Gast (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Nochmals ...dat mit 77 war auch Müll von mir,

zur Richtigstellung für AT90CAN128 an 16MHz:

Timer0 mit timeOver-Methode:

u32 CPUCLK=8000000;       //std. 8MHz
u08 SCLOCK=8;      //std. 8MHz

//count up in Timer with 100Hz
volatile u16 Delay_SystemTicks=0;
//change OCR0A if Frequency!~=100Hz is needed

//---------------------------------------------------------
//---------------------------------------------------------
//Timer
static void (*T0_Intfunction)(void);

//---------------------------------------------------------
//---------------------------------------------------------
// initialize timer 0
// Param: Freq, external function
// Timer is used for Ramps, Controls, Can-Output, Keys etc.
//---------------------------------------------------------
void CPUSYS_init(u08 Freq,void (*insertTimer0Int) (void))
{
  //JTAG disable  ... muss ja nich
  MCUCR=0x80;
  MCUCR=0x80;  
  //
  TIMSK0=(1<<OCIE0A);  //OC-Interrupt enab
  //
  TCCR0A=(0x08)|(0x05);   //CTC|5 = CLOCK/1024
  if (Freq==16) {
    SCLOCK=16;   //set Systemclock to 16 MHz
    CLKPR=0x80;  //for AT90CAN128
    CLKPR=0x00;  //16 MHz
  }
  else {
    SCLOCK=  8;
    //set Systemclock to 8 MHz
    CLKPR=0x80;  //for AT90CAN128
    CLKPR=0x01;  //8 MHz
  }
  //
  CPUCLK  =1000000*SCLOCK;
  //100Hz-Init
  OCR0A   =(u08)(CPUCLK/(u32)102400); //+/-1 for nuts
  TCNT0   =0;            //set Counter
  //
  T0_Intfunction=insertTimer0Int;
}

//---------------------------------------------------------
//IRQ handler
SIGNAL(SIG_OUTPUT_COMPARE0)
{
  //
  Delay_SystemTicks++;
  //
  T0_Intfunction();
}

//---------------------------------------------------------
//Delay_SystemTicks counted up in Timer0
//return 1 if Timeout
u08 timeOver(u16 oldtime,u16 MaxDiff) {
  u16 Difference=Delay_SystemTicks-oldtime;
  if (Difference>MaxDiff)
    return 1;
  else
    return 0;
}


Autor: Johannes M. (johnny-m)
Datum:

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

Autor: µC-noob (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Johannes M. (johnny-m)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: µC-noob (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Danke!

Werds auf 1ms initialisieren


Gruß

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.