Operácie

Oneskorenia s AVR

Z SensorWiki

Poznámka k používaniu fukncie _delay_ms()

Funkcia _delay_ms() pozdrží dobu vykonávania programu na čas zadaný argumentom funkcie. Aby funkcia správne fungovala na rozličných procesoroch v rozličných konfiguráciach, potrebuje vedieť, akou frekvenciou procesor pracuje. Robí sa to tak, že zadefinujeme makro F_CPU ako frekvenciu v Hz. Pre Arduino kompatibilné dosky je to

#define F_CPU 16000000UL

Niekedy je však výhodné použiť ten istý zdrojový kód programu aj viackrát a preto nie je dobré priamo vkladať frekvenciu do kódu. Dá sa to urobiť aj dodatočne, definovaním hodnoty v príkazoch pre prekladač. V Atmel Studio je prístup cez Project > (ProjectName) Properties > Toolchain > AVR/GNU C Compiler > Symbols, treba tam potom pridať takýto výraz

F_CPU=16000000

pozrite aj obrázok.

MIPS AtmelStudioFCPU.png
Vkladanie informácie o frekvencii procesora pre kompilátor.

Funkcia je deklarovaná nasledovne

 void _delay_ms 	(  	double  	__ms 	 )  	
 // Perform a delay of __ms milliseconds, using _delay_loop_2()

Vyššie uvedená deklarácia funkcie, ktorá je predpripravená spolu s kompilátorom avr-gcc nám hovorí, že argumentom je počet milisekúnd oneskorenia, ktorým môže byť až 32-bitové celé čislo (double long int) alebo desatinné čislo s dvojitou presnosťou (double). Ktorá verzia je platná záleží na parametroch kompilátora (či zapneme aj používanie plávajúcej aritmetiky float, ktorá je default vypnutá, pretože zaberá veľa miesta). Zdalo by sa teda, že napríklad vytvoriť oneskorenie 1 sekunda je celkom jednoduché, stačí ako parameter vložiť číslo 1000.

Nie je to však také jednoduché. Dokumentácía k prekladaču[REF 1] sa píše doslova

The maximal possible delay is  (262.14 ms/F_CPU) where F_CPU is in MHz. 

Podobná poznámka je aj priamo v delay.h a pre frekvenciu 16 MHz to znamená, že maximálne oneskorenie, ktoré vieme touto funkciou vygenerovať je 16 milisekúnd! Preto si musíme napísať vlastnú funkciu, ktorá bude volať _delay_ms() s nejakým rozumným parametrom (1ms alebo 10ms) a tak dosiahneme potrebné dlhšie oneskorenia.

// this wrapper function calls _delay_ms with a known value of 1
// if you call _delay_ms(variable) then the floating point library
// is going to be included and your output file gets much larger

void delay_1ms(uint16_t ms) 
{
    uint16_t i;
    for(i=0;i<ms;i++) 
      _delay_ms(1);
}

A na záver ešte jedna poznámka, že hodnota oneskorenia by mala byť kompilátoru známa v čase prekladu, aby mohol daný výraz vyhodnotiť a nahradiť ho výsledkom. V opačnom prípade je na počet cyklov použitý výpočet, ktorý vyvolá potrebu použitie kniznice pre pracu s reálnymi číslami math.h čím veľkosť programu vzrastie o viac ako 2kB.


Celkom na záver pozorovanie, ktoré sme však zatiaľ neoverovali, že ak kompulátor optimalizuje preklad s prepínačom -O1, pribalí aj celú math knižnicu, ale už -O2 ju vynechá. Podobne je to pre -Os.