PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Timer0 stimmt nicht beim Atmega32



servusssss
29.04.2007, 14:29
hallo zusammen,
ich bin am verzweifeln ich schaffe es nicht das der timer0 richtig funktioniert.
](*,)

der atmega lauft mit 16Mhz auf der rn control 1.4

es ist das erste mal das ich diesen timer brauche und hab deshalb auch keine erfahrung und versuch mir mit einem reinen timer programm die sache zu erklären
ich hätte gerne das er alle 10 ms zur probe eine LED ein/ausschaltet.

mein code



#include <avr/io.h>
#include <stdlib.h>
#include <avr/interrupt.h>
#include <avr/pgmspace.h>
#include <avr/signal.h>

#include <string.h>

SIGNAL(SIG_OVERFLOW0){


static uint8_t count=0;

if (count == 156) {

count = 0; //zähler auf 0

if(bit_is_set(PORTC,7)) //PIN gesetzt ???
PORTC &= ~(1<<PC7);
else
PORTC |= (1<<PC7);
} else {
count++; // zahler erhöhen
}
TCNT0=0; //timer auf 0
}


int main (void){

TCCR0 |= (1 << CS00)|(1 << CS02); //prescaler 1024
TIMSK |= (1 << TOIE0); // Overflow Interrupt aktivieren
sei();
for(;;){


//mach was


}

}


bei 16 Mhz müsste der timer alle 64µs überlaufen?
wenn ja dann muss er 156 mal überlaufen um die led einmal ein und aus zu schalten? das wären dann alle 10 ms

ich weiß leider nicht ob das so stimmt?

besten dank!

servusssss

ps.: ich hab leider nicht im forum suchen könne falls es schon eine eintrag über dieses problem gibt.

linux_80
29.04.2007, 14:56
Hallo,

wenn Du den Teiler auf 1024 hast, wird der Timer alle 16MHz/1024 um eins hochgezählt. Er läuft dann über, wenn er bei 255 um eins hochzählen will, also noch mal durch 256 teilen, was dann mehr als 10ms ergibt.
Wenn du 10ms erreichen willst, muss Du den Timer mit 100 vorladen, nicht mit 0, denn das macht der selber wenn er übergelaufen ist.
Und bis 156 brauchst Du dann auch nicht zählen, einfach bei jedem IRQ die LED umschalten, und den Timer setzen.
Der Timer zählt dann von 100 bis 255 läuft danach über und ruft die ISR auf. Hier sind dann auch wieder deine 156 die Du errechnet hast.

servusssss
30.04.2007, 19:19
Hallo linux_80,

danke für deine antwort!
leider hab ich immer noch ein paar fragen

wenn ich das jetzt richtig verstanden habe dann setze ich den timer beim gleich auf "TCNT0=100;" beim Init steht das im Datenblatt?
wirkt sich das nicht auf die Zeit aus?
wenn nicht dann ist die zeit bis zum überlauf 16Mhz/1024 also 64µs?
wenn ich aber ein langsamers signal brauch (LED blinken) zähl ich in der SIGNAL(SIG_OVERFLOW0){ } einfach hoch?
zb 10 ms sind dann bis auf ca 156 zählen?

besten dank

servusssss

linux_80
30.04.2007, 20:21
huiui,

1. ja, gleich am Anfang setzen, aber auch in der ISR am Anfang

2. nein, steht nicht im DB, muss man selber ausrechnen, hast Du aber eigentlich schon gemacht (156 -> 256 - 156 = 100) !

3. ja, wirkt sich auf die Zeit aus, deshalb macht man es ja ^^

4. nein, überlauf ist erst nach max. 256 Takten, das was Du meinst ist für den Timer nur ein Takt. Hab ich oben schon geschrieben wie.

5. Du musst dann nicht selbst bis 156 zählen, sondern der Timer fängt bei 100 an, und zählt bis 256, dann ist die richtige Zeit um !
Dann kommt (wie schon oben erwähnt) der Overflow, und die ISR wird aufgerufen, und dort wird der Timer wieder mit 100 geladen, und die gewünschte Aktion ausgeführt.


Hint:
Dein Gedankenfehler bis jetzt, nach 16MHz/1024 läuft der Timer nicht über, sondern zählt nur um eins höher.
Der Zähler läuft erst über, wenn er bei 255 um eins weiterzählen würde, also bei 8Bit wieder bei 0 ankommt.
Hier wird dann die ISR aufgerufen.
Wenn der Timer nicht die ganzen 256 Takte durchzählen soll, weil die Zeit zu lange wäre, muss man den Zähler eben mit einem höheren Wert vorladen, hier mit 100, dann zählt er nur 156 Takte bis er überläuft.



Und dann noch ein paar Smilies, die nach belieben im Text oben verteilt werden sollten :mrgreen:
8-[ [-o< :-k :-b

servusssss
30.04.2007, 20:42
Hallo linux_80,

danke jetzt ist mir das klar! \:D/
man kann auch mit der kirche ums dorf und das auf dem holzweg [-o<

sg servusssss

Banzai
07.05.2007, 22:37
Hallo Leutz...

der Timer stimmt wirklich irgendwie nicht. Zumindest im µs Bereich.


//Für ATMega32 mit 16MHz
#include <avr/io.h>
#include <avr/interrupt.h>

volatile uint16_t ui16_msecs;
volatile uint16_t ms = 0;

void Clock();

ISR(TIMER0_OVF_vect)
{
TCNT0 = 240;
ui16_msecs++;
if( ui16_msecs >= 1000L ) // eine Millisekunde vergangen
{
ui16_msecs = 0;
ms++;
}
}

void initTimer()
{
TCCR0 = (1<<CS00); // Prescaler 1

TCNT0 = 240;

/* TOIE0 Overflow Interrupt */
TIMSK |= (1<<TOIE0);

sei(); /* Interrupt global einschalten */
}

void Clock()
{
static uint8_t s = 0;
static uint8_t m = 0;
static uint8_t h = 0;

if( ms > 999 )
{
ms -= 1000;
s++;
}
if( s > 59 )
{
s = 0;
m++;
}
if( m > 59 )
{
m = 0;
h++;
}
if( h > 23 )
h = 0;

// Ausgabe, wie auch immer von h,m,s und ms
}

int main(void)
{
initTimer();

while(1)
{
Clock();
}

return 0;
}


Laut dem Tool rnAVR sind die Werte für Prescaler und TCNT0 1 und 240.

Problem: Die Uhr läuft viel zu langsam! Geschätzt 3-4mal zu langsam.

Anders sieht es aus, wenn man keine µs will sondern eine ms!
rnAVR sagt Prescaler = 64, TCNT0 = 6


//Für ATMega32 mit 16MHz
#include <avr/io.h>
#include <avr/interrupt.h>

volatile uint16_t ms = 0;

void Clock();

ISR(TIMER0_OVF_vect)
{
TCNT0 = 6;
ms++;
}

void initTimer()
{
TCCR0 = (1<<CS01)|(1<<CS00); // Prescaler 64

TCNT0 = 6;

/* TOIE0 Overflow Interrupt */
TIMSK |= (1<<TOIE0);

sei(); /* Interrupt global einschalten */
}

void Clock()
{
static uint8_t s = 0;
static uint8_t m = 0;
static uint8_t h = 0;

if( ms > 999 )
{
ms -= 1000;
s++;
}
if( s > 59 )
{
s = 0;
m++;
}
if( m > 59 )
{
m = 0;
h++;
}
if( h > 23 )
h = 0;

// Ausgabe, wie auch immer von h,m,s und ms
}

int main(void)
{
initTimer();

while(1)
{
Clock();
}

return 0;
}

Da läuft die Uhr richtig.

Warum?
Wieso?
Weshalb?

Testet bitte die Codes, nicht damit ich wirklich einen fatalen Denkfehler habe (Ganz vollständig ist der Code u.U. nicht, da er hier editiert wurde, es geht hauptsächlich um die Presclaer/TCNT0-Werte).

thx4answer

Banzai