delay.h, závislost na F_CPU, principu přesnost a zpoždění

Dobrý den, prosím o vysvětlení principu spoždění v delay.h.
Mám nastaveno F_CPU 16000000UL (atmega644p)
a když dám v programu _delay_us(480)
vykoná mi to spoždění 480us? nezávisle na F_CPU.

Zde je kus kodu z knihovny delay.h a delay_basic.h, nějak se nemůžu dopočítat jak to opravdu vychází,v komentáři jsou uvedené moje vypočítané hodnoty, díky za pomoc.

[code]_delay_us(double __us)
{
uint8_t __ticks;
double __tmp = ((F_CPU) / 3e6) * __us; //16/3*480=2560
if (__tmp < 1.0)
__ticks = 1;
else if (__tmp > 255)
{
_delay_ms(__us / 1000.0); //_delay_ms(2,56)
return;
}
else
__ticks = (uint8_t)__tmp;
_delay_loop_1(__ticks);

void
_delay_ms(double __ms)
{
uint16_t __ticks;
double __tmp = ((F_CPU) / 4e3) * __ms; //=16000/4*2,56=10,24
if (__tmp < 1.0)
__ticks = 1;
else if (__tmp > 65535)
{
// __ticks = requested delay in 1/10 ms
__ticks = (uint16_t) (__ms * 10.0);
while(__ticks)
{
// wait 1/10 ms
_delay_loop_2(((F_CPU) / 4e3) / 10);
__ticks --;
}
return;
}
else
__ticks = (uint16_t)__tmp; //=10
_delay_loop_2(__ticks); //_delay_loop_2(10)
}

void
_delay_loop_1(uint8_t __count)
{
asm volatile (
“1: dec %0” “\n\t”
“brne 1b”
: “=r” (__count)
: “0” (__count)
);
}

void
_delay_loop_2(uint16_t __count)
{
asm volatile (
“1: sbiw %0,1” “\n\t”
“brne 1b”
: “=w” (__count)
: “0” (__count)
);
}
}[/code]

:arrow_right: administrator: přejmenováno z "delay.h AVR"

Tyto funkce nezaručují absolutně přesné zpoždění.
Přesnost závisí i na F_CPU.
Při 8 MHz bude zpoždění 480 us, při 1 MHz 479 us.

Přesnou hodnotu zjistíme pohodlně v simulátoru, když před funkcí _delay… vynulujeme Cycle counter .

Edit:
Předpokládá se samozřejmě, že hodnota F_CPU v kódu souhlasí s kmitočtem oscilátoru v mikroprocesoru.
delay.gif

Asi jsem to spatne pochopil

No ale ved ta rutina zavisla of F_CPU je. F_CPU sa nachadza vo vztahu hned prvom prikazovom riadku. inak plati to co tu uz bolo napisane

Jistěže rutina je závislá na F_CPU.
Vykoná pro určité zpoždění určitý počet cyklů.
A tento počet se liší podle kmitočtu oscilátoru.
Proto výsledné zpoždění na F_CPU nezávisí.

Kdyby to na F_CPU nezáviselo, tak by to počítalo správně bez ohledu na hodnotu F_CPU, což je samozřejmě nesmysl. Závislé na F_CPU to je a to tak, že zásadně. F_CPU musí být shodná s frekvencí mcu, jinak nebude zpoždění souhlasit. To AB samozřejmě ví, ale napsané je to… řekněme zvláštně.

Dobře, řeknu to jinak.

Jestliže F_CPU je 1MHz a kmitočet oscilátoru je 1 MHz, pak _delay_us(100) trvá 100 us.
Jestliže F_CPU je 8MHz a kmitočet oscilátoru je 8 MHz, pak _delay_us(100) trvá 100 us.
Jestliže F_CPU je 16MHz a kmitočet oscilátoru je 16 MHz, pak _delay_us(100) trvá 100 us.

Pokud F_CPU a kmitočet oscilátoru nesouhlasí, pak _delay_us(100) netrvá 100 us.

Správnost tohoto tvrzení AB jsem si nedobrovolně vyzkoušel při svém prvním pokusu, kdy celý cyklus trval místo 8 sekund 1 sekundu. Důvod byl právě v nesprávně určené frekvenci v programu. Mcu měl 8MHz a do programu jsem uvedl nesprávně, že má 1MHz. Proto celý cyklus trval 1/8.

Díky všem za rady,udělal jsem simulaci jak radil AB kde jsem vynululoval Cycle counter a spoždění jsem nastavil na 500us a při simulaci vychází cca 125us,Je to 4x méně než požadované spoždění.
Tak jsem zkontroloval frekvence F_CPU a frekvenci asi oscilátoru nebo co to je a F_CPU = 16MHz a frekcence osc = 4MHz to je asi ten rozdíl 4x.
Bohužel s programováním začínám takže mi toto není moc jasné, kdyby to někdo mohl vysvětlit,jestli mám v programu zadávat 4x vetší spoždění než požaduji, případně upravit soubor delay.h pro jednotlivé frekvence F_CPU.Díky
avr.JPG

frekvencia v simulatore sa dost “od veci” nastavuje v menu debug. Dlho mi trvalo, kym som to nasiel. Tam to niekde najdes. Je to v podmenu, kde sa da nastavit aj stimuly subor pre imitovanie vplyvyu okolia. Pre niektore typy mcu nepomoze ani toto nastavenie frekvencie. Ale tusim sa s tym stretol iba raz.

V Menu-Debug-Select Platform and Device nastav Avr simulator2 a Atmega644P.
Potom v Menu-Avr simulator 2 options nastav 16 MHz.

Ještě důležitá věc:
Máš ve fuse bitech správně nastavený krystalový oscilátor (nejlépe full swing)?

Mikroprocesor má uvnitř zabudovaný oscilátor (Internal RC oscillator). Ten je z továrny nastavený na 1 MHz.
Pokud ho takto použijeme, uvedeme v kódu:

#define F_CPU 1000000UL

Tím říkáme překladači:
"Oscilátor v našem mikroprocesoru kmitá na frekvenci 1 MHz. Nastav podle toho funkce delay() ".

Pokud chceme použít krystal, musíme pomocí programátoru ve fuse bitech změnit typ oscilátoru na krystalový (Ext. crystal nebo full swing) a připojit krystal.

Řekněme že nastavíme a připojíme krystal 16 MHz.
Oscilátor v mikroprocesoru teď bude kmitat na frekvenci krystalu.
A v kódu uvedeme #define F_CPU 16000000UL.
Tím opět informujeme překladač o skutečném kmitočtu oscilátoru v mikroprocesoru. Zpoždění budou fungovat jak mají.

Takže nic nenásobíme a žádné soubory neupravujeme.
Stačí když v definici F_CPU bude skutečný kmitočet oscilátoru v mikroprocesoru. Pak fungují zpoždění správně.

Ostatně, proč to nevyzkoušíš v reálu s blikající Ledkou?

Díky všem za objasnění,
tak v reálu mi spoždění funguje správně, zkoušel jsem to na vyčtení teploty z DS18B20 tam hodnoty spoždění fungují dle datasheetu. Jen jsem chtěl pochopit na jakém principu to spoždění funguje, když už to používám. Už jsem nastavil i frekvenci simulátoru a vše ok, díky všem za pomoc.