Sida 1 av 1
ATmega8:s interna oscillator
Postat: 21 april 2006, 14:55:49
av mrhedin
Jag har skrivit en delayfunktion i C som skall fördröja med det värde den blir anropad med. Testat att köra den för sig själv i AVRStudio med en sekund och AVRStudions stopwatch säger 1000.07ms.
Problemet är att om jag kör säg 10 min på labbplatta med tidtagarur så slår det med ca 5s. Jag använder den interna oscillatorn i atmegan på 8MHz och hörde att nån sa att den är inte noggrannare än så. Stämmer det eller är det jag som har programmerat fult så att det blir så i praktiken?
Kod: Markera allt
void delay_s(unsigned int x)
{
setbit(TCCR1B, CS10); // Starta Timer1, Prescaler 1024. TCLK=7812,5Hz @ Fosc 8MHz.
clearbit(TCCR1B, CS11); // Starta Timer1, Prescaler 1024. TCLK=7812,5Hz @ Fosc 8MHz.
setbit(TCCR1B, CS12); // Starta Timer1, Prescaler 1024. TCLK=7812,5Hz @ Fosc 8MHz.
while(x > 0)
{
setbit(TIFR, TOV1); // Cleara overflowflagga.
TCNT1=57723; // Laddar med värde för att få en sekund.
while(!checkbit(TIFR, TOV1)) {} // Vänta på overflowflagga.
x--;
}
clearbit(TCCR1B, CS10); // Timer1 avstängd.
clearbit(TCCR1B, CS11); // Timer1 avstängd.
clearbit(TCCR1B, CS12); // Timer1 avstängd.
}
Postat: 21 april 2006, 15:52:44
av Greensilver
Man kan kalibrera klockan mjukvarumässigt. Det finns info på
www.atmel.com om hur man gör. Har en kodsnutt någonstans dock ej för Mega8. Skall kika om jag hittar den. Enligt databladet till Mega32 går det att få den att gå med en noggrannhet på 2%.
Postat: 21 april 2006, 17:30:20
av sodjan
> Jag använder den interna oscillatorn i atmegan på 8MHz och hörde
> att nån sa att den är inte noggrannare än så.
Vadå "hörde" ??
Du läste väl i databladet ? Vad sa det ?
Postat: 21 april 2006, 20:42:06
av BEEP
Det här är det enda som jag hittade i databladet allt annat var bara om hur mycket frekvensen ändrades vid olika temperaturer och spänningar.
Oscillator
The calibrated internal RC Oscillator provides a fixed 1.0, 2.0, 4.0, or 8.0 MHz clock. All
frequencies are nominal values at 5V and 25°C. This clock may be selected as the system
clock by programming the CKSEL fuses as shown in Table 9. If selected, it will
operate with no external components. The CKOPT fuse should always be unprogrammed
when using this clock option. During reset, hardware loads the calibration byte
into the OSCCAL register and thereby automatically calibrates the RC Oscillator. At 5V,
25°C and 1.0 MHz Oscillator frequency selected, this calibration gives a frequency
within ± 1% of the nominal frequency.
Postat: 21 april 2006, 21:05:50
av Greensilver
Min kod hjälper dig nog inte heller är jag rädd, den använder en extern kristall för att kalibrera.
Kod: Markera allt
//Calibrate the internal OSCCAL byte, using the external
//32,768 kHz crystal as reference
void OSCCAL_calibration(void)
{
unsigned char calibrate = 0;//FALSE;
int temp;
unsigned char tempL;
CLKPR = (1<<CLKPCE); // set Clock Prescaler Change Enable
// set prescaler = 8, Inter RC 8Mhz / 8 = 1Mhz
CLKPR = (1<<CLKPS1) | (1<<CLKPS0);
TIMSK2 = 0; //disable OCIE2A and TOIE2
ASSR = (1<<AS2); //select asynchronous operation of timer2 (32,768kHz)
OCR2A = 200; // set timer2 compare value
TIMSK0 = 0; // delete any interrupt sources
TCCR1B = (1<<CS10); // start timer1 with no prescaling
TCCR2A = (1<<CS20); // start timer2 with no prescaling
while((ASSR & 0x01) | (ASSR & 0x04)); //wait for TCN2UB and TCR2UB to be cleared
// wait for external crystal to stabilise
for(int i = 0; i < 10; i++)
_delay_loop_2(30000);
while(!calibrate)
{
cli(); // mt __disable_interrupt(); // disable global interrupt
TIFR1 = 0xFF; // delete TIFR1 flags
TIFR2 = 0xFF; // delete TIFR2 flags
TCNT1H = 0; // clear timer1 counter
TCNT1L = 0;
TCNT2 = 0; // clear timer2 counter
while ( !(TIFR2 && (1<<OCF2A)) ); // wait for timer2 compareflag
TCCR1B = 0; // stop timer1
sei(); // __enable_interrupt(); // enable global interrupt
if ( (TIFR1 && (1<<TOV1)) )
{
temp = 0xFFFF; // if timer1 overflows, set the temp to 0xFFFF
}
else
{ // read out the timer1 counter value
tempL = TCNT1L;
temp = TCNT1H;
temp = (temp << 8);
temp += tempL;
}
if (temp > 6250)
{
OSCCAL--; // the internRC oscillator runs to fast, decrease the OSCCAL
}
else if (temp < 6120)
{
OSCCAL++; // the internRC oscillator runs to slow, increase the OSCCAL
}
else
calibrate = 1;//TRUE; // the interRC is correct
TCCR1B = (1<<CS10); // start timer1
}
}
Postat: 21 april 2006, 23:16:41
av Rohan
Din kod är det nog inget fel på men om du funderar lite så kanske det ger sig vad som är fel.
Du säger att det blir 5 sekunder fel på 10 minuter. 10 minuter är 600 sekunder. Vad säger databladet? Jo, att vid 5V och 25°C så ska det inte bli mer än 1% fel. Hur mycket är 1%? Precis, 6 sekunder. Det har alltså blivit lite bättre än databladet och du har säkert inte ens haft 25°C.
När de skriver nominellt och anger en spänning och temperatur så innebär det nästan ingenting, tyvärr.

Den interna oscillatorn är väldigt temperaturberoende och även beroende av spänningen.
Slutsats: För bättre precision behöver du en extern kristall.
Postat: 21 april 2006, 23:51:41
av mrhedin
Ja så verkar det faktiskt vara. Tack för hjälpen...