Citac/casovac 0/1 - ukážka ovládania v C

Caute, by som potreboval poradit.
Potreboval by som ukazku ovladania casovaca0 a casovaca1 v C cku ide mi hlavne oto pri nastani prerusenia kde sa vykonava , alebo skor kde napisat program ktory sa ma vykonat pri preruseny, v asm je to lahsie tam nepusti adresa, ale ako to funguje v c ku, diki za radu

:arrow_right: administrator: přejmenováno z "Citac/casovac 0/1"

Tam je to tiez velmi jednoduche

napr. pre ATmega8, a casovac 2


int main(void)

{
   // nicializacna cast
   TCCR2 = ((1<<WGM21) + 3; // mod CTC a preddelic 32, CS22 = L, CS21 = H, CS20 = H
   OCR2 = 123; // predvolba do komparatora 
   TIMSK |= 1<<OCIE2; // povolenie prerusenia
   sei(); // povolenie globalneho prerusenia

   for(;;) 
  {
   // co len chces pri pravidelnom preruseni od casovaca pri dosiahnuti hodnoty ulozenej v OCR2
  }

}

ISR(SIG_OUTPUT_COMPARE2)
{

   // co len chces pri preruseni

}

vytrhal som to z nejakeho mojho kodu, tak som to dufam nevykorenil, ale v principe je to takto. Nazvy tych vektorov (co treba prasknut do tej zatvokry) najdes napriklad v iom32.h a im podobnym.
Inak v C-cku je praca velmi dobra a produktivna. Mozem iba doporucit.

Takze troska si to zhrnme :slight_smile:

TCCR2 = ((1<<WGM21) + 3; toto by som rad troska blizsie co znamena to WGM21, a ten zapis ((1<<WGM21) + 3, asi sa tam neda len priamo vlozit hodnota pre nastavenie ? co by som tam mal napisat napr pre mod normal a predelicka 64?

TIMSK |= 1<<OCIE2; // povolenie prerusenia
-takto sa zapisuje prerusenie pre zhodu? tam sa asi neda tiez priamo vlozit hodnota?

a este to prve prerusenie je pri pravidelno a to druhe sa vykona len raz?

a cisto teoretycky pre citac/casovac1 by vykonanie pre preruseny vyzeralo takto?
asi :slight_smile:
ISR(SIG_OUTPUT_COMPARE1)?
{
}
inak diki, moc si mi pomohol

Ale coze by sa nedala priamo vlozit hodota. Samozrejme sa da. Ale myslis, ze zapis

TCCR2 = 11;

je prehladnejsi ako

(omluvam sa, povodny zapis mal byt takyto a nie zapisany tak slendriansky ako som uviedol :slight_smile: )

TCCR2 = (1<<WGM21) + (1<<CS21) + (1<<CS20);

Aj po piatich rokoch a Xtych procesoroch vidim, co tym chcel autor povedat a cez PDF sa dopatram wo co gou. Ale TCCR2 = 11? To kto ma lustit ktory bit je nastaveny a co znamena?

Oba zapisy vygeneruju absolutne rovnaky kod, t.j. na adresu kde sa nachadza TCCR2 vlozia hodnotu 11. Ale druhy je jednoducho prehladnejsi a ak ti mozem poradit, tak sa toho drz. Uplna haluz je, ked niekto ziada o radu preco mu nejde ta ktora periferia a zavali kod typu:

NEJAKY_REGISTER = 0x45;
INI_REGISTER = 0b01101101;

no kto to ma lustit?!
A hlavne lahko takto sam spravi preklep a potom sa nestaci divit ako plytva svojim drahocennym casom pocas dlhych zimnych vecerov.

Co znamena nasledujuci zapis, predpokladam vies

cisloA<<cisloB

Definicia tohto zapisu patri medzi zaklady Ccka. CisloA sa posunie o cisloB krat do lava.
Takze

1<<WGM21 == 8
1<<CS21 == 2
1<<CS20 == 1

a spolu to bude 8+2+1 = 11

ale napriklad spravny je i zapis

3<<2 = 12

Tento zapis ma tu vyhodu, ze ak pouzijes iny procesor, ktory ma WGM21 na inom mieste ako ten predchadzajuci (TCCR2 = 11), nemusis menit zdrojak (a este predtym sa divit, preco to nefunguje podla ocakavania). Podla prislusnych hlavickovych suborov sa vsetko nastavi ako ma.

plati to, co v predchadzajucom texte.
Predpokladam ze vies, ze zapis

TIMSK |= 1<<OCIE2;

je totozny so zapisom

TIMSK = TIMSK | (1<<OCIE2);

a ze “|” je operator logicky OR.

Mohol by si zapisat i
TIMSK = 1<<OCIE2;

ale neviem, zi si nahodou uz predtym nieco v TIMSK nenastavoval, napriklad pre iny casovac v nejakej inej casti programu. Ak tam nedas ten OR, lahko si zmenis nejake predchadzajuce nastavenie a to je zas prilezitost na hladanie chyby. Ak tam ten OR das a je “zbytocny”, lebo nic ine nenastavujes, chybu urcite neurobis.

Ake druhe prerusenie? Kde vidis dve prerusenia?
Ved najprv si musis nastavit prerusenia ktore ta zaujimaju a potom musis povolit generalne prerusenie, ktore blokuje vsetky ostatne. Presne ako v ASM.

A to pre ktory procesor? Pre tu spomynanu ATmega8 urcite nie, lebo TIMER1
ma dva compare registre. Takze si spravne znenie vyhladaj v nasledujucom vypise (cast z hlavickoveho suboru iom8.h)

/* External Interrupt Request 0 */
#define INT0_vect			_VECTOR(1)
#define SIG_INTERRUPT0			_VECTOR(1)

/* External Interrupt Request 1 */
#define INT1_vect			_VECTOR(2)
#define SIG_INTERRUPT1			_VECTOR(2)

/* Timer/Counter2 Compare Match */
#define TIMER2_COMP_vect		_VECTOR(3)
#define SIG_OUTPUT_COMPARE2		_VECTOR(3)

/* Timer/Counter2 Overflow */
#define TIMER2_OVF_vect			_VECTOR(4)
#define SIG_OVERFLOW2			_VECTOR(4)

/* Timer/Counter1 Capture Event */
#define TIMER1_CAPT_vect		_VECTOR(5)
#define SIG_INPUT_CAPTURE1		_VECTOR(5)

/* Timer/Counter1 Compare Match A */
#define TIMER1_COMPA_vect		_VECTOR(6)
#define SIG_OUTPUT_COMPARE1A		_VECTOR(6)

/* Timer/Counter1 Compare Match B */
#define TIMER1_COMPB_vect		_VECTOR(7)
#define SIG_OUTPUT_COMPARE1B		_VECTOR(7)

/* Timer/Counter1 Overflow */
#define TIMER1_OVF_vect			_VECTOR(8)
#define SIG_OVERFLOW1			_VECTOR(8)

/* Timer/Counter0 Overflow */
#define TIMER0_OVF_vect			_VECTOR(9)
#define SIG_OVERFLOW0			_VECTOR(9)

/* Serial Transfer Complete */
#define SPI_STC_vect			_VECTOR(10)
#define SIG_SPI				_VECTOR(10)

/* USART, Rx Complete */
#define USART_RXC_vect			_VECTOR(11)
#define SIG_UART_RECV			_VECTOR(11)

/* USART Data Register Empty */
#define USART_UDRE_vect			_VECTOR(12)
#define SIG_UART_DATA			_VECTOR(12)

/* USART, Tx Complete */
#define USART_TXC_vect			_VECTOR(13)
#define SIG_UART_TRANS			_VECTOR(13)

/* ADC Conversion Complete */
#define ADC_vect			_VECTOR(14)
#define SIG_ADC				_VECTOR(14)

/* EEPROM Ready */
#define EE_RDY_vect			_VECTOR(15)
#define SIG_EEPROM_READY		_VECTOR(15)

/* Analog Comparator */
#define ANA_COMP_vect			_VECTOR(16)
#define SIG_COMPARATOR			_VECTOR(16)

/* 2-wire Serial Interface */
#define TWI_vect			_VECTOR(17)
#define SIG_2WIRE_SERIAL		_VECTOR(17)

/* Store Program Memory Ready */
#define SPM_RDY_vect			_VECTOR(18)
#define SIG_SPM_READY			_VECTOR(18)

Prerusenie nemusis vybrat od compare match, ale napriklad od pretecenia. To uz zavisi co potrebujes.

dakujem za podrobne vysvetlenie, v cecku robim zatial len par hod , trocha si treba zvyknut :slight_smile:

To je jen teorie, ale praxe je jiná. Pozice WGM21 je v registru asi všude stejná, ale u různých MCU je jiný způsob řízení periferie. Např. migrace mezi ATmega16 a ATmega164 není tak jednoduchá, aby se dala řešit výměnou hlavičkových souborů. Jako příklad uvedu řízení přerušení od timerů u ATmega16. Používá jediný registr TIMSK, takže povolení přerušení může vypadat takto:
TISMK |= 1<<TOIE0|1<<TOIE2; //současné povolení přerušení od T0 a T2
U ATmega164 by tento zápis nevyhověl, překladač by měl hlásit chybu.
Řádek se musí přepsat takto:
TIMSK0 |=1<<TOIE0;
TIMSK2 |=1<<TOIE2;
V tomto případě už nedochází k současnému povolení obou přerušení, takže tu máme další problém. V 99,5% to však není kritické.
Takovýchto nuancí je tam více.

skusam skusam ale som stale na mrtvom bode snazim sa to nejako modifikovat pre tiny2313, ten citac nespustim, nastavenia nastavim ale to miesto kde dat kod co sa vykona pri preruseni stale hlasi chybu

robim to cez interrupt a podla toho co ste mi poradili a s knihy pan Vaňa ale ten si tu knihu napisal asi sam pre seba

Ale to je uzasne :slight_smile:
Ako sa Ti podarilo, aby kod v procesore po vbehnuti do podprogramu prerusenia zahlasil nejaku chybu? Z toho logicky vyplyva, ze to prerusenie sa vykona. Akurat neviem, co ten kod sleduje a co a hlavne KDE to hlasi.

Ak Ti chybu zahlasi prekladac pri preklade, tak to prosim napis.
Alebo sa tam deje nieco uplne ineho? Ako to mame vediet?
Skus sem dat vypisy tych chyb. Ak to naozaj hlasi tvoj kod na nejakom tvojom display, alebo cez UART, (ved ako by to inak mohol hlasit )
daj sem tie jeho hlasky a uved, co ten tvoj kod skuma, ked sa mu to nepaci a ohlasuje to. :slight_smile:
Alebo nabuduce poriadne napis, co sa ti tam deje, aby ti bolo mozne poradit.

to Technik:

Samozrejme, ze pouzitie slovnych oznaceni jednotlivych bitov nie je samospasitelne a pri novom procesore si VZDY treba PORIADNE pozriet dokumentaciu. V kazdom pripade sa tym zvysuje citatelnost zdrojaku, hlavne ak ho treba predlozit na posudenie inym. To je ale myslim pravidlo, ktore by sa malo tykat nielen C-cka, ale aj ASM. Jednoducho, stabna kultura.

Problem so zdrojakmi a s roznymi procesormi riesim nasledovne(ale tiez treba vediet, ze to nemusi byt samospasitelne riesenie ako uz uviedol Technik):

inicializacny header. Tu je okrem procesora vybrany i hardver a premapovanie prislusnych pinov na nazvy jednotlivych svoriek (tato cast tu nie je uvedena)


#define XTAL 14745600
#define F_CPU XTAL

// Definice makier s parametrami
#define SET(BAJT,BIT) ((BAJT) |= (1<<(BIT)))
#define RES(BAJT,BIT) ((BAJT) &= ~(1<<(BIT)))
#define NEG(BAJT,BIT) ((BAJT) ^= (1<<(BIT)))
#define TST(BAJT,BIT) ((BAJT) & (1<<(BIT)))


#define ATmega8 0
#define ATmega644P 1

#define PROCESOR ATmega8

#if (PROCESOR == up_mega8)
	#ifndef __AVR_ATmega8__
	#define __AVR_ATmega8__
	#endif 
	#include <avr/iom8.h>

	#define ZAKAZ_GLOB_PRERUSENIE cli()
	#define POVOL_GLOB_PRERUSENIE sei()

	#define TB_DEFAULT_1 114 //115-1   pouzije sa POCET_PRVEJ_PREDVOLBY

	#if (XTAL == 7372800)
		#define TB_NASTAV_CASOVAC	(TCCR2 = ((1<<WGM21) + 3) // mod CTC a preddelic 32, CS22 = L, CS21 = H, CS20 = H
	#elif (XTAL == 14745600)
		#define TB_NASTAV_CASOVAC	(TCCR2 = (1<<WGM21) + 4) // mod CTC a preddelic 64, CS22 = H, CS21 = L, CS20 = L
	#endif

	#define TB_POVOLENIE_PRERUSENIA   (SET(TIMSK,OCIE2)) // povolenie interuptu pri compare match
	#define TB_ZAKAZ_PRERUSENIA   (RES(TIMSK,OCIE2)) // zakaz interuptu pri compare match
	#define TB_CNT TCNT2
	#define TB_PREDVOLBA OCR2
	#define TB_SIG_OUTPUT_COMPARE SIG_OUTPUT_COMPARE2 // nazov vektoru pre prerusenie od casovaca CZ - compare match

#elif PROCESOR ATmega644P

	#ifndef __AVR_ATmega644__
	#define __AVR_ATmega644__
	#endif 
	#include <avr/iom644.h>

	#define ZAKAZ_GLOB_PRERUSENIE cli()
	#define POVOL_GLOB_PRERUSENIE sei()

	#define TB_DEFAULT_1 114 //115-1   pouzije sa POCET_PRVEJ_PREDVOLBY

	#if (XTAL == 7372800) 
// mod CTC a preddelic 64, CS22 = H, CS21 = L, CS20 = L
		#define TB_NASTAV_CASOVAC	TCCR2A = (1<<WGM21);\
											TCCR2B = (1<<CS22)

	#elif ((XTAL == 14745600) || (XTAL == 18432000))				// mod CTC a preddelic 128, CS22 = H, CS21 = L, CS20 = H
		#define TB_NASTAV_CASOVAC	TCCR2A = (1<<WGM21);\
											TCCR2B = (1<<CS22) | (1<<CS20)

	#endif

	#define TB_POVOLENIE_PRERUSENIA   (SET(TIMSK2,OCIE2A)) // povolenie interuptu pri compare match
	#define TB_ZAKAZ_PRERUSENIA   (RES(TIMSK2,OCIE2A)) // zakaz interuptu pri compare match
	#define TB_CNT TCNT2
	#define TB_PREDVOLBA OCR2A
	#define TB_SIG_OUTPUT_COMPARE SIG_OUTPUT_COMPARE2A // nazov vektoru pre prerusenie od casovaca CZ - compare match

// definovanie COM0

	#define COM0_BAUD_RATE(komunikacna_rychlost) UBRR0H = 0xff & ((F_CPU / ((komunikacna_rychlost) * 16L) - 1)>>8);\
															    UBRR0L = 0xff & (F_CPU / ((komunikacna_rychlost) * 16L) - 1)

	#define COM0_REG_DATA_OUT UDR0
	#define COM0_REG_DATA_IN UDR0
	
	#define COM0_SETUP_ASYNCHRON_8N1	UCSR0C = ( (3<<UCSZ00));\
												RES(UCSR0A,U2X0);\
												RES(UCSR0A,MPCM0)

	#define COM0_SETUP_ASYNCHRON_8E1	UCSR0C = ( (3<<UCSZ00) | (1<<UPM01));\
												RES(UCSR0A,U2X0);\
												RES(UCSR0A,MPCM0)

	#define COM0_SETUP_ASYNCHRON_8O1	UCSR0C = ( (3<<UCSZ00) | (1<<UPM01) | (1<<UPM00));\
												RES(UCSR0A,U2X0);\
												RES(UCSR0A,MPCM0)

	#define COM0_SETUP_ASYNCHRON_8N2	UCSR0C = ( (1<<USBS0) | (3<<UCSZ00));\
												RES(UCSR0A,U2X0);\
												RES(UCSR0A,MPCM0)

	#define COM0_SETUP_ASYNCHRON_8E2	UCSR0C = ( (1<<USBS0) | (3<<UCSZ00) | (1<<UPM01));\
												RES(UCSR0A,U2X0);\
												RES(UCSR0A,MPCM0)

	#define COM0_SETUP_ASYNCHRON_8O2	UCSR0C = ( (1<<USBS0) | (3<<UCSZ00) | (1<<UPM01) | (1<<UPM00));\
												RES(UCSR0A,U2X0);\
												RES(UCSR0A,MPCM0)


	#define COM0_OTVOR_RX  SET(UCSR0B,RXEN0)
	#define COM0_ZATVOR_RX  RES(UCSR0B,RXEN0)
	#define COM0_OTVOR_TX  SET(UCSR0B,TXEN0)
	#define COM0_ZATVOR_TX  RES(UCSR0B,TXEN0)
	
	#define COM0_RX_INT_POVOL SET(UCSR0B,RXCIE0)
	#define COM0_RX_INT_ZAKAZ RES(UCSR0B,RXCIE0)
	#define COM0_TX_INT_POVOL SET(UCSR0B,TXCIE0)
	#define COM0_TX_INT_ZAKAZ RES(UCSR0B,TXCIE0)
	#define COM0_POVOL_INT_PRAZDNEHO_BUFERU SET(UCSR0B,UDRIE0)
	#define COM0_ZAKAZ_INT_PRAZDNEHO_BUFERU RES(UCSR0B,UDRIE0)
	#define COM0_ZRUS_PRIZNAK_PRAZDNEHO_BUFERU RES(UCSR0A,UDRE0)

	#define COM0_ZRUS_PRIZNAK_PRIJATIA_ZNAKU RES(UCSR0A,RXC0)
	#define COM0_ZRUS_PRIZNAK_ODVYSIELANIA_ZNAKU RES(UCSR0A,TXC0)


#endif

priklad samotneho programu, uryvok z rozsiahlejsieho cyklu


#include "tb_ini.h"

//.....

int main(void)

{
   TB_PREDVOLBA = TB_DEFAULT_1;
   TB_NASTAV_CASOVAC;
   TB_POVOLENIE_PRERUSENIA;
   POVOL_GLOB_PRERUSENIE;

   for(;;) {

   }
}


ISR(TB_SIG_OUTPUT_COMPARE)
{
   TB_PREDVOLBA = TB_DEFAULT_1;
   // co len chcem
}

Takto napisany program v C-cku je v znacnom rozsahu nezavisly od pouziteho procesora, pripadne od celej rodiny procesorov. Dolezite je si na zaciatku povedat, ake makra maju zmysel. Napriklad POVOL_PRERUSENIE, ZAKAZ_GLOB_PRERUSENIE.
S ATmega je velky problem v nastavovani komunikacnych parametrov po jednotlivych castiach. Napriklad tu si nastavim paritu a inde si nastavim pocet prenasanych bitov. Musel by som si obsah toho sibnuteho registra niekde odpamatat, lebo sa don neda robit OR. Preto tie makra vyzeraju ako vyzeraju, napriklad COM0_SETUP_ASYNCHRON_8N2. Ale v praxi to nevadi. Pre iny typ procesora s logickejsie vyriesenym nastavenim parametrov UARTU sa da makro tiez tak napisat, aby vyhovovalo tomuto principu.
Kto si vsak zavedie pri svojej praci ake pravidla, je v podstate na tom, co mu najviac vyhovuje. Mne ide hlavne o jednoduchu adaptaciu zdrojaku na rozny hardver a pre rozne procesory zvycajne dane tym hardverom. Projekt sa snazim skladat z co najvaciseho (rozumne) poctu logicky nezavislych celkov. Jeden subor je na komunikaciu a veci s nou spojene, iny na AD, dalsi na spristupneie ext. flash pamati cez SPI, LED display, LCD display. Vsetko tak, aby bolo samotne jadro riesiace ulohu co najviac odbremenene od takychto stereotypnych uloh. Pri rieseni novej ulohy si skopirujem tie *.c subory, ktore potrebujem do projektu (aj tieto *.c subory sa vyvijaju, tak aby som nejakou banalnou zmenou nemal problem pri preklade programu tri roky stareho projektu ukladam v projekte vsetko co k nemu patri), vytvorim samotne jadro novej aplikacie A JE TO…

No takze moj pokus :slight_smile: len sa nesmejte

PC Atiny2313, snazim sa o prerusenie Citaca0

#include <tiny2313.h>
#include <stdio.h>

void main(void)
{

TCCR0A=5;       // mod normal, delicka 1024 sry za zapis tie       programatorske finty este neovladam
TCCR0B=0x00;
TCNT0=0x00;
OCR0A=97;      //pre porovnanie malo by to vychadzat priblizne 200ms, pri 20Mhz kristaly
OCR0B=0x00;

TIMSK=2;       //povolenie prerusenia pri zhode

#asm("sei") ;

//no a teraz sa neviem pohnut dalej, kde napisa kod ktory vznikne pri preruseny

// vycital som daco taketo

interrupt [nieco-to nieco som este nezistil] void nieco_int(void){

      tu by asi mal ist ten kod :) 
}

}


no viac som s literatury cz-sk nenasiel.

si pripadam ako tlk :open_mouth:

Mozno by si mal zacat tym, ake C-cko pouzivas. Kazde C-cko (spravnejsie prekladac C-cka, samotne C-cko nema o vektoroch prerusenia ani sajn a ani ho nema preco mat) ma vektory prerusenia definovane inak. Potom Ti bude moc poradit priamo pouzivatel tvojho prekladaca. Ja som ti uvadzal priklady pre GCC, kolekcia programov WinAVR. Priamo sa zaintegruje do AVRstudia.

Najprv priznaj prekladac, potom sa da pohnut dalej. Stale si sem neuviedol chybove hlasenie, ktore si spomynal. Tak to uved tiez.

pred nekolika dny jsem psal pwm (3 fazovou) pro tiny2313, takze bych ti mohl neco poslat v celku, ale to bys prisel o tu radost ze zprovozneni svyho programu :slight_smile:
Kazdopadne pro povoleni preruseni neni treba asm, staci normalne “sei()”.
Dale obsluha preruseni (nebo alespon jeji inicializace) se nepise do main, ale mimo, je to samostatna funkce volana externi udalosti.
takze:

void main(void)
{
//nejaky kod

}

ISR(TIMER0_COMPA_vect)
{
//obsluha preruseni output compareA casovace 0

}

edit: zase pozde :smiley:
Jak pise martin, pouzitej prekladac by se hodilo vedet, tohle je pro gcc (winavr). Tvuj zpusob obsluhy jsem jeste nevidel (funkce definovana uvnitr jine mi prijde dost zvlastni), mozna ve tvy literature pouzivaj neco jinyho… Abych nezapomel - nevidim v mainu nekonecnou smycku :wink:

vidis Martin tu bude pes zakopany, pouzivam codevision, preto mi nesli do hlavi aky to subor mam editovat ked tam taky nemam. tym padom sa objasnuje aj chyba co mi pri compilacii hadze, inak je bezpredmetna pretoze tie bludi co tam pisem nebudu spravne

to piityy ta nekonecna smicka my tam chyba nasleduje po tom kode

Tak ti bude musiet poradit, ako sa to pise v CodeVision.
Ak by si sa rozhodol zmenit “dres”, GCC vo WinAVR tiez nie je na zahodenie, priamo sa automaticky integruje do AVRStudia a je uplne free bez akychkolvek obmedzeni v duchu GNU

Martine, je to hezký příklad ale nezapomeňme na to, kolik pojmů jsi nadefinoval a některé možná i zbytečně. Po přeložení se použije jen něco a výsledkem bude pár instrukcí. V ASM bych je napsal rovnou a bylo by hned zřejmé co nastavuji a jak. Velké množství pojmů má opačný účinek, člověk se v nich snadno ztratí nemluvě o tom, kolik pojmů je nutné vstřebat z datasheetu (jména registrů). Nemá smysl zdrojáky zbytečně komplikovat, když stejně nemohou být přenositelní na jiný hardware.
Přenosiltené mohou být jen ty části programu, které se neváží na HW, nebo jen na ten, který je shodný u všech MCU.
Hlavní smysl pojmenovávání konstant, registrů a bitů je ve snadném nalezení ve zdrojáku. Jestliže chci vědět, kde se povoluje přerušení T2, budu hledat ve zdrojáku TOIE2.

Já si to nemyslím a chtěl bych se Tě zeptat, zda si už dělal něco s ATxmega? Ten má neobyčejně rozsáhlou periferii a jiný způsob ovládání, takže bych se vsadit, že pro Xmega budeš mustet přepisovat prakticky vše co s HW jen trochu souvisí a to i přesto, že má stejné jádro. Takže POVOL_PRERUSENIE je k ničemu, protože xmega má 3 úrovně přerušení.
Asi každý programátor chce, aby odladěný program mohl bez úprav použít v jiné aplikaci. Dlouhá léta jsem o to usiloval, ale je to nemožné. Musel bych psát něco jako operační systém, a to MCU v jeho schopnostech degraduje. Nesnažme se o to u tak malých MCU jako je AVR8. Mnohem efektivnější je psát programy tak, aby části pracující s HW byly ve zdrojáku snado nalezitelné, přehledné a pohromadě. Je rychlejší upravit tyto části pro konkrétní HW (např. změna krystalu) než vymýšlet krkolomná makra a definice pro překladač, který možná i provede správně nastavení USART a Timerů.