Epämääräisesti toimivat _delay_ funktiot

Elikkäs Atmega32:ssa on kiinni 16 mhz kide ja fuse biteistä otettu ulkoinen kide käyttöön. Ongelmana kuitenkin on, että _delay_ms ja _delay_us funktiot ovat varmaan noin 5 kertaa liian nopeita. Kokeilin laittaa kääntäjän optimoinnin (-Os) pois päältä, jolloin kyseiset funktiot toimivat suunnilleen oikealla nopeudella, mutta ovat silloin ehkä hieman liian hitaita. Mistä tälläinen epätarkkuus delay funktioissa voi johtua?

Ensinnäkään delay-funktioita ei kannata käyttää mihinkään aikakriittisiin juttuihin, timerit on niihin järkevämpi valinta. Juurikin epätarkkuuden ja kääntäjä(optimointi)riippuvuuden takia.

Oletko jossain määritellyt kontrollerin kellotaajuuden oikeaksi delay-funktioita varten? Noi delay-funktiot yleensä tarvii #define:lla määriteltynä F_CPU tai vastaavan määrittelyn. Saattaa olla myös Makefile:ssa jos käytät valmista sellaista. Ja olethan huomioinut kirjaston tarjoamien delay-funktioiden maksimipituuden? avr-libc:n tapauksessa kannattaa lukaista esim tämä: http://www.nongnu.org/avr-libc/user-manual/group__util__delay.html.

Joo no en siis sinänsä mihinkään niin hirveää tarkkuutta vaativaan ole sitä käyttänytkään (esim. lcd näytön ohjauksessa olen noita käyttänyt kun siinä tarvitsee viiveitä), ihmetyttää vain kun tuollakin sivulla kerrotaan huonoimmassakin tapauksessa delay funktion tarkkuudeksi 1/10 ms ja nyt tuo juoksee kyllä ihan eri aikaa. F_CPU:n olen definellä määritellyt tuohon 16mhz:iin. Tossa vielä yksinkertanen koodi millä tuota nyt testailin, juoksee aikamoista vauhtia sekunnit näytöllä, mikäli -Os on kääntäjän asetuksista päällä…

[code]#ifndef F_CPU
#define F_CPU 16E6UL // 16 MHz
#endif

#include <avr/io.h>
#include <inttypes.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#include <string.h>
#include <avr/pgmspace.h>
#include <stdio.h>
#include <stdlib.h>

#include “lcd.h”

int main(void)
{
lcd_init();
lcd_on(0,0); //lcd on, cursor off, cursor blink off
lcd_clr();
lcd_set_ddram(0x00);
lcd_print_char(‘0’);
lcd_print_char(‘0’);
lcd_print_char(’:’);
lcd_print_char(‘0’);
lcd_print_char(‘0’);

int sec, sec2;
sec = 0; //sekunnit
sec2 = 0;//sekunnin kymmenykset
char tmp[2] = {0};

while(1)
{
lcd_set_ddram(0x40);
_delay_ms(100);
sec2++;
if (sec2 >9)
{
	sec++;
	sec2 = 0;
}
itoa(sec, tmp, 10);
if (sec < 10)
{
	tmp[0] = '0';
	tmp[1] = sec + '0';
}

lcd_print_char(tmp[0]);
lcd_print_char(tmp[1]);
lcd_print_char(':');
lcd_print_char(sec2 + '0');
}
return 0;

}[/code]

Muistaakseni delay vaatii tosiaan optimoinnin. Lisäksi WinAVR:n mukana tulevat Makefilet olettavat, että F_CPU määritetään Makefilessä. Se annetaan sitten gcc-avr -DF_CPU 16000000
heittää jotain
#else
#error F_CPU ennen tuota #endiffiä.

Ja kirjoita se ihan numeroin. Tuota UL ei välttämättä tarvitse lisätä ja se joissain kolmansissa juhla kirjastoissa särkikin asioita.