U potrazi za tartufima AVR-a

Rasprava o AVR mikrokontrolerima, AVR projekti i drugo vezano za AVR...

Moderators: pedja089, stojke369, trax, InTheStillOfTheNight

User avatar
InTheStillOfTheNight
Odlično uznapredovao
Odlično uznapredovao
Posts: 938
Joined: 01-06-2006, 17:54
Location: Zagreb

U potrazi za tartufima AVR-a

Post by InTheStillOfTheNight »

"U potrazi za tartufima AVR-a" Uvod - 1. dio

Davno sam pročitao jedan članak iz svijeta elektronike "Regulacija temperature sa DS1820", no u tom delikventnom razdoblju dobro sam spajao otpornike, relaye i zaljevao cvijeće, no nažalost pojma nisam imao što je to DS1820, a još manje što je AT89C2051. Nakon godinu dana muke s tim pojmovima, nabavom programatora i ulaskom u to sve, vrlo brzo sam zaključio kako ništa ne znam, ni danas ništa ne znam, a vjerojatno nikad ništa neću niti znati...

To razdoblje zivota bavio sam se isključivo natjecanjima u robotici, elektronici, a opet pojma nisam imao, ili sam znao relativno malo više od drugih. Svi ti programi koje sam nekad pisao bili su metoda razmišljanja bez znanja, no to se kasnije pokazalo kao apsolutna ograničenost u programiranju.

No zašto ovo pišem?
Uvijek se sjetim mojih početaka kad smo internet vukli na slamku kroz 56k modem, i mislili da smo osvojili svijet ako znamo napraviti *.bat file... Tako nadobudni klinci kupovali smo Atmelove procesore, kao mi smo "programeri"... Sam pojam izazivao je strahopoštovanje... no ništa mi nismo znali, a informacije su bile nedostupne, a i ono što je dostupno bilo je, jel, na materinjem engleskom koji smo svi govorili tečno još u maternici...

I tako mi smo programirali... Upali, ugasi. Ako si upalio probaj ugasit, ako si ugasio, a "pero" stisnuo tipku, odmah upali, no ako je to bio "mato" čekaj malo, pa upali, pa ugasi, pa provjeri "peru", pa "matu" pa "juricu".
Dvije omiljene naredbe su WAIT i GOTO... Valjda svima početnicima srcu prirasle.
I naravno nekako smo mi sve programe navukli da rade, ali nismo naucili programirati!

Ovu temu otvorio sam jer ću pisati, kao što ste već skužili, samo o programiranju. Razlog tome je jer nitko nikad nije pisao o tome kada je to meni trebalo, ili nije postojao meni razumljiv tekst koji bih shvatio...
Davno sam postavljao početnička pitanja po forumu i često sam dobio profesionalne odgovore koje nisam shvaćao. On meni tamo piše o nekim "registrima" čudnih imena, boja i oblika, a ja ništa ne kužim, kao da mi na "Turskom" objašnjava "križni put 12 apostola", i onda tek izgubim volju za programiranjem. Dobar dio tih tekstova o programiranju često izaziva totalno kompleksan i neshvatljiv sadržaj za početnike, i često svi "normalni" jednostavno odustanu prije nego što uopće krenu.

Kod knjiga je opet problem jer su pisane dosta opširno, sa previše nevažnih pojmova, kao da se Einstein s nekim natječe "Tko će napisati opširniju znanstvenu knjigu!"... Naime, dobro je znati sve stvari iz knjiga, no teško ih je u potpunosti držati u glavi, pa stoga i najbolji programeri često imaju podeblju knjigu programskog jezika kraj svog stola... Čisto iz razloga jer se neki dijelovi programskog jezika koriste rijetko, pa se dobro podsjetiti iz knjige...

U ovom topicu pisati ću o programiranju, ipak o suštinskom, a ne znanstevnom. Svaki programerski pojam pokušat ću objasniti na što jednostavniji i razumljiviji način svojoj baki, a istovremeno gledano sa programerske strane nepobitno točno.

Najteži početnički problem je napraviti programator, odabrati procesor, programski jezik i compiler, jer na internetu ima toliko toga da me ponekad zaboli želudac i pomislim da bih se mogao pristojno ispovraćati od muke, kao i nauke...

Zato ću odabrati gotovo početničko rješenje na kojem će svi moji primjeri programa i opisi raditi dobro.
Sve što ću pisati biti će za istu platformu, isti procesor, isti editor i naravno isti compiler.
Razlog tome je jer ne želim paliti i gasiti ledice na svim procesorima ovog svijeta, dosta je monotno i naporno...
S druge strane, nemoguce je nauciti programirati na 100 procesora. Nauči samo jedan, znaš ih sve, no ako učiš sve, nikad nećeš naučiti niti jedan...

Postoji samo jedno parvilo:
Molim vas ne komentirajte temu, sve što vas zanima šaljite na PM, ili otvorite drugi TOPIC.
Razlog tome je jer ne želim zagušiti ideju da pišem postove o programiranju koji su zatrpani sa 1 000 000 pitanja i komentara...
Tema ce biti uvijek čista sa mojim postovima, a sva pitanja slobodno posaljite na PM i dobiti cete odgovore...
Sve ono što mi se učini nejasno potruditi ću napisati post koji objašnjava nedoumice AVR procesora i programskog jezika C.
I naravno postove neću pisati svaki dan jer sam previše zauzet, i nemam dovoljno slobodnog vremena da bih pisao toliko često...

Prvi post, prvi dio ne treba puno teksta:

MCU : ATMEGA88 - "Izgleda ko' čip, usudim se reći "JAK" čip AVR-a"

Editor : AVR Studio - "Izgleda ko' program za pisanje. Eh, u njemu mi tipkamo program..."

Compiler : WINAVR - "Ne izgleda. Samo ga koristimo kao prevodilac na strojni jezik i koristimo njegove biblioteke, tj gotove programe da ih ne pisemo ponovno jer je to vec netko drugi i iskusniji napisao..."

Programski jezit: C/assembler - "Jezik kojim govorimo procesoru što da radi! Tražio sam neki Turski ili Kineski jezik, ali ima samo "C".

To be continued...
InTheStillOfTheNight
User avatar
InTheStillOfTheNight
Odlično uznapredovao
Odlično uznapredovao
Posts: 938
Joined: 01-06-2006, 17:54
Location: Zagreb

Re: U potrazi za tartufima AVR-a

Post by InTheStillOfTheNight »

"U potrazi za tartufima AVR-a" Uvod - 2. dio

Što je mikroračunalo?
To je procesor. E baš nije, svi ga tako zovemo i dalje ćemo ga tako zvati no postoji bitna razlika.

Mikroračunalo i procesor su dva odvojena pojma. Svi mi to miješamo, pa ću pojasniti ono što čini te drastične razlike između "na oko" istog pojma.
Procesor ili CPU je "Centralna Procesorska Jedinica" što bi značilo da procesor samo izvršava programske
instrukcije. Procesor je onaj vrag u kompjuteru koji izvršava instrukcije sa vašeg Hard Diska, a rezultate
eventualno pohranjuje u RAM na vašem računalu. Ako dublje zabijete nos u matičnu ploču skužiti ćete da su sve te stvari odvojene i razbacane po matičnoj ploči. Procesor ne može biti samostalan jer nema nikakve memorije iz koje bi izvršavao instrukcije. Jer, recite vi meni u koji procesor je moguće strpati Windows XP? Takav ne postoji. Windows se na računalo učitava sa Hard disk-a, i odrađuje djelomično na Hard disk-u, a djelomično u RAM memoriji, a svim time upravlja procesor(CPU).

Mikroračunalo ili "Microcontroller"(MCU) je čitav mali kompjuter strpan u samo jedan čip (Naravno, bez monitora). Samom izjavom da je to čitavo računalo dolazimo i do tih osnovnih djelova mikro računala. Nemamo Hard Disk, no zato imamo FLASH memoriju kojoj je svrha da memorira program koji želimo izvršavati. Imamo vlastitu RAM memoriju, imamo vlastiti procesor ili jezgu (core), i imamo vlastitu periferiju mikroračunala. Najbolje od tog svega je činjanica da se sve nalazi u samo jednom malom čipu.

I dalje ćemo ga zvati procesor, no čisto da se zna, to nije procesor nego mikrokontroler...

Koja je onda uloga compilera, i programskog jezika?
Da bih mogao napisati ulogu moram napisati suštinsku povijest nastanka, pa ovaj daljni dio teksta pišem samo kao primjer razmišljanja prilikom nastanka mikroračunala:

Davno prije kada je nastao procesor kao izvršna jedinica ljudske kreativnosti nastale su i prve naredbe:

(HEX FILE)
AABF
DC52 110C
2135 12B6

Izmišljam naredbe, no odprilike tako se programiralo. Prvi parametar je bio što treba napraviti, a ostali parametri ako ih je naredba zahtjevala bili su "odakle i gdje"?
I sami ti kreativci nisu bili toliki konji da ne vide osnovni problem ovog pristupa programiranju -> Nečitljivo, teško, nerazumljivo!!! I osmislili su najniži programerski jezik "assembler". Zapravo su samo brojeve zamjenili sa slovima bližim ljudskom umu, pa onda ovaj isti tekst može izgledati ovako:

(ASM FILE)
SEI
MOV R21,R20
LDI R19,0xFF

Ovako je program izgledao dosta čitljivije. Assemblerska naredba SEI (Set Enable I) izvršava "Enable Global Interrupts", assemblerska naredba MOV registar R20 kopira u registar R21, a LDI (Load Immediate) konstantu 0xFF upisuje u registar r19.
Assembler kao programerski jezik ima puno većih ograničenja od tog teksta -> Sve moramo raditi na najnižoj razini samog računala. Možemo samo zbrajati, oduzimati uspoređivati te rezultate pohranjivati na željenu lokaciju u RAM memoriji ili ostavljati rezultate u radim registrima mikroračunala. To je bilo ograničeno ubijanje mozga sa glupostima, glupostima savršenstva.

Assembler je savršen programerski jezik, baziran na upravljanju svakog ciklusa i svakog događaja na računalu, no isto tako je besmisleno ubijanje mozga programera koji mora paziti na svaki korak mikrokontrolera. Drugi problem je što assemblerski napisan program može raditi isključivo na mikrokontroleru za koji je pisan, i jako teško ga je preseliti na drugi tip mikrokontrolera jer su drugačije i same naredbe, arhitektura, adrese registara...

Iz tog razloga nastali su viši programerski jezici koji glase ovako:

Broj1 = Broj2 + Broj3;

No nažalost ovaj tekst ništa ne znači za mikroračunalo, njemu jednostavno treba dati one "Guraj-Vuci" komande i za to postoji "Compiler".
Stoga "Compiler" je program koji će programerski jezik višeg i razumljivijeg nivoa prevesti na primitivni nivo jednog mikroračunala. (10100010110110111100101010001110000000110101)

Sve programe ću pisati u C-u (jednostavnijem i višem programskom jeziku), a WINAVR koristim da mi to prevede na strojni (HEX) file, tj da moj jednostavniji nivo razmišljanja prevede tom primitivnom mikroračunalu.

To be continued...
InTheStillOfTheNight
User avatar
InTheStillOfTheNight
Odlično uznapredovao
Odlično uznapredovao
Posts: 938
Joined: 01-06-2006, 17:54
Location: Zagreb

Re: U potrazi za tartufima AVR-a

Post by InTheStillOfTheNight »

"U potrazi za tartufima AVR-a" Uvod - 3. dio

Zbunjuje me totalno platforma. Rekoh moram odlučiti, i stalno važem , no nikako da više odlučim za koji AVR pisati. Napisao sam u prvom postu kako će to biti MEGA32, no to baš i ne spada u početnički AVR s obzirom da je dosta opširan. Isto pitanje vratio sam si 5 godina unazad i postavio ga ponovno. Dragi Josipe, s kojim bi ti mikrokontrolerom AVR-a volio početi? I gle odgovor je tu: Definitivno ATMEGA88. Možda mi je taj AVR malo prirastao srcu, no ta serija ATMEGA48, ATMEGA88 i ATMEGA168 ipak je najbolji početak. Zapravo radi se o procesoru koji je "skoro" identičan kao ATMEGA8(najpopularniji), no jači je u tome jer ima 1-wire Debug.

Što je 1 wire debug?
Većina programera najprije programiraju, onda to upucaju u MCU, i metodom palac-oko procjene jel radi, ili ne radi. Ako nešto ne radi onda bulje u program i po njemu traže grešku. Dakle, vide oni jako dobro da to ne radi kako treba, no ne znaju zašto? Što dakle da čine, osim da kopaju po svom programu i razmišljaju gdje su se zeznuli. Iz tog razloga je nastao pojam "On-Chip Debug".
Zamislimo da imamo 20 000 linija programa, i nešto nekad, iz čudnog razloga poludi. Prva metoda kopanja po programu odmah pada u vodu, jer nemoguće je toliko linija programa držati u glavi, a kamoli iz toga svega pronaći razlog zbog kojeg se program srušio.
On-Chip Debug nam dozvoljava da sa PC-a izvršavamo instrukciju po instrukciju programa, da analiziramo sve što se događa na mikrokontroleru, mijenjamo sve što želimo, zaustavljamo program kad želimo, kako želimo. Svaki puta kada program zaustavimo imamo detaljan uvid u stanje svih memorija, svih registara i svega što se nalazi u mikrokontroleru. Nemojte miješati ovaj DEBUG sa simulatorom. Simulator simulira ono što bi se trebalo dogoditi, a one wire debug govori ono što se točno događa. 1 Wire Debug se ne izvršava na PC-u, on se izvršava direktno na mikrokontroleru i prema PC-u šalje sve informacije iz svoje memorije, stoga je točan prikaz onoga što se događa na vašem hardware-u.

Ovaj dio i nije tako bitan za početnike, no upravo zbog toga "one wire debug-a" ću odabrati ATMEGA88 jer mogu izvršavati program direktno na njemu, te imati uvid u sve što se događa, a samim time mogu bolje i objasniti razloge nekih događaja koje u suštini često predvidimo, ili ih nemamo čime pogledati da bi ih shvatili... A opet na kraju svega odabrao sam AVR koji je kao naštiman za početnike. Nije toliko opširan, a ima gotovo sve što ima i svaki AVR mikrokontroler.

Platforma za koju ću pisati jer nju imam doma je ova: CPU 4U4I
http://www.inovatic.hr/default.aspx?id=69" onclick="window.open(this.href);return false;
Baš gledam, ima ih tu nekoliko, no ovu drugu odozgora imam doma tako da ću sve pisati za nju, a sad tko voli nek si prevodi :)

Registracija na http://www.atmel.com" onclick="window.open(this.href);return false; je obavezna... no AVR studio je besplatan i može se skinuti ovdje:
http://www.atmel.com/dyn/products/tools ... ily_id=760
AVR Studio 4.18 (build 684)
AVR Studio 4.18 SP3 (b716)

I još trebam prevodilac, opisan nedavno (WINAVR):
http://winavr.sourceforge.net/download.html" onclick="window.open(this.href);return false;
Skidajte uvijek zadnju verziju, trenutno vidim da je neka: 20100110

Znači ono što bi trebalo instalirati je ovim redom: AVR Studio 4, AVR Studio Service Pack 3, WINAVR.

To be continued...
InTheStillOfTheNight
User avatar
InTheStillOfTheNight
Odlično uznapredovao
Odlično uznapredovao
Posts: 938
Joined: 01-06-2006, 17:54
Location: Zagreb

Re: U potrazi za tartufima AVR-a

Post by InTheStillOfTheNight »

"U potrazi za tartufima AVR-a" Misija - 1. Upaliti LED

Ovo je valjda najjednostavnije što sam mogao smisliti. Nećemo za sada blinkati LED-icom, niti ćemo čitati tipke. Sve što treba napraviti je upaliti jednu LED diodu. Mislim da ovo svi početnici znaju, a isto tako mislim da niti jedan početnik ne razumije što je napravio.

On tamo u bascomu ili nekom drugom programu upiše 3 linije programa i LED svijetli, a samim time ograniči svoju kreativnost jer ne razumije što se u pozadini uopće događa.

Evo i naše omiljene knjige u kojoj ima sve što trebamo, te puno više od toga. Pročitao sam je nekoliko puta, ovisno što sam kada radio i koje poglavlje mi je kad trebalo. Ovo nije "Biblija" da je čitamo po redu. I često ćemo je pročitati, ali našim redosljedom onoga što nas u kojem trenutku zanima.
http://www.atmel.com/dyn/resources/prod ... oc2545.pdf


Ovako izgleda mikroračunalo ATMEGA88:
Image

Vidim ima tu nekih puno čudnih kvadratića, pa ću ja u svrhu ovog palenja LED-a obrisati one koji me ne interesiraju trenutno:
Image

Ovako je već bolje :) Napisati ću osnovne stvari o svakom kvadratiću, pa prije nego što možemo upaliti LED-icu ovo bi morali razumjeti.

To be continued...
InTheStillOfTheNight
User avatar
InTheStillOfTheNight
Odlično uznapredovao
Odlično uznapredovao
Posts: 938
Joined: 01-06-2006, 17:54
Location: Zagreb

Re: U potrazi za tartufima AVR-a

Post by InTheStillOfTheNight »

"U potrazi za tartufima AVR-a" Misija - 1. Upaliti LED

1. Power Supervision POR/BOD & RESET
Ovo služi da na neki način nadgleda MCU, osigurava dobar Start izvršavanja programa, te nekakve zaštite od kritičnih situacija sa naponom.

POR -> "Power On Reset" ima ulogu da svaki puta kada uključimo mikroračunalo on resetira program na početak, tj postavi to početno stanje iz kojeg uvijek kreće rad mikroračunala.

BOD -> "brown-out detection"
procesor ne smije izvršiti niti jednu krivu instrukciju, a može ih izvršavati 20 000 000 u sekundi, dakle jako brzo i puno instrukcija, a sve moraju biti bez greške. Jedini pravi problem je u naponu napajanja, te vanjskim smetnjama. Ako napon napajanja padne na kratko procesor može poluditi, a da se to ne dogodi služi ovaj BOD. Njega možemo uključiti ili isključiti. BOD monitorira napon na procesoru, te u slučaju da on padne ispod dozvoljene razine BOD će resetirati MCU kako bi program koji se izvršava krenuo od početka. Ovisno o onome što radimo, sami odlučujemo dali želimo da BOD štiti program restartom ili ne.

RESET -> Bio externi, interni POR, ili BOD ovo će resetirati procesor te program pokrenuti ispočetka.

2. FLASH
Tu ide onaj HEX file, program, instrukcije ili zovite to kako hoćete. To slikovito možemo zamisliti kao XXXX instrukcija od kojih se prva uvijek nalazi na adresi 0, a svaka sljedeća ima veću adresu. U MCU postoji nešto što se zove PC "Program counter", a to govori procesoru ili jezgri koju instrukciju treba izvršiti. Ovo govorim iz razloga jer je povezano sa resetom. Dakle kad resetiramo mikroračunalo onaj RESET će uvijek postaviti PC (program counter) na adresu 0. Dakle prva instrukcija koju će AVR jezgra izvršiti uvijek se nalazi na adresi 0 u FLASH-u. Postoji još nešto što se zove BOOTLOADER, pa se ta adresa može postaviti i na lokaciju BOOTLOADER-a, no za sada svi početnici uvijek trebaju znati da je prva instrukcija na adresi 0 u FLASH-u. ATMEGA88 ima 8k programske memorije(točnije 8192 bytea), seljački rečeno ima mjesta za 8192 broja od 0-255. Ti brojevi su instrukcije za AVR jezgru.


3.SRAM
Tamo se sprema ono što se zove varijabla u programiranju. AVR jezgra ima svoje radne registre gdje možemo držati nekakve brojeve, no njih je premalo i ne bi mogli u to strpati puno podataka. Zato postoji RAM memorija u koju procesor prema instrukcijama pohranjuje podatke, vuče ih nazad u registre te opet po programu nešto izvršava s tim podacima. Što je najgore da upalimo ledicu u ovoj našoj misiji, RAM nam nije potrebam, jer program je toliko jednostavan da ništa nećemo pohranjivati u RAM, samo trebamo napisati instrukcije za AVR jezgru koja će upaliti LED-icu. ATMEGA88 ima 1 kB RAM-a, ili seljački rečeno tamo može pohraniti 1024 broja od 0-255;

Najbitnija razlika između RAM-A i FLASHA je ta da FLASH programiramo i tamo instrukcije ostaju bez obzira jel procesor na napajanju ili nije. One su tamo trajno upisane kako bi mogli isključiti MCU, a da naredbe ostanu sigurne.

4.AVR CPU
E to je procesor, jezgra. Na svaki "clock" koji dođe sa oscilatora jezgra izvrši jednu assemblersku instrukciju iz FLASH-a. U sekundi može ih izvršiti po pravilima datasheeta maksimalno 20 000 000. Za one koji žele znati koliko je to brzo: 1/20 000 000 = 0,000 000 05 Sekundi ili 50 nS
Kao programeri prisiljeni smo razmišljati u takvom vremenu stoga stvarnosti "bye-bye".

5. Oscilator Circuits/Clock Generation
Dio procesora koji generira CLOCK za AVR jezgu te periferiju o kojoj ćemo kasnije govoriti puno više.
AVR možemo svakako konfigurirati. U sebi ima ugrađen interni oscilator koji možemo podesiti da radi na MAX 8 000 00 Mhz, a isto tako možemo podesiti da se clock uzima sa vanjskog kristala MAX 20 Mhz.
Isto tako možemo biti i dovoljno ludi da ga konfiguriramo na "Vanjski impuls" preko X2 pina, spojimo obični prekidač te mu mi govorimo u realnom vremenu da izvršava jednu po jednu assemblersku instrukciju.
Za sada o clocku treba znati da je to takt rada jezgre, te za palenje LED diode bilo kakav takt nam odgovara, stoga ovaj dio ću ostaviti kako je podešen na mojoj ploči. Svaki taj takt CPU jezgra izvrši jednu instrukciju iz FLASH-a.

6. PORT
E tamo su spojeni pinovi čipa. Nakon RESET-a mikroračunala svi PORTOVI (PORT B, PORT D PORT C) konfigigurirani su kao ULAZI. Postoje tu joše nekakva default pravila prilikom isporuke novog MCU-a iz atmela, pa recimo RESET linija nikad nije konfigurirana kao PORT, nego kao RESET pin... neću ih sad sve nabrajati jer još nisam pisao ništa o FUSE, stoga to ću ostaviti za neka druga vremena.

Program koji pali LED diodu trebao bi izgledati ovako:

1.Konfiguriraj PORT na kojemu je spojena LED-ica da bude IZLAZ.
2.Postavi Stanje PORT-a da bude na logičkom stanju koje pali LED.
3.Nemoj više ništa raditi. (ako je moguće).

To be continued...
InTheStillOfTheNight
User avatar
InTheStillOfTheNight
Odlično uznapredovao
Odlično uznapredovao
Posts: 938
Joined: 01-06-2006, 17:54
Location: Zagreb

Re: U potrazi za tartufima AVR-a

Post by InTheStillOfTheNight »

Ispravak i korekcija smislenih neistina...

Naravno, @Kizo me prvi isprvio jer decko zna previše :), no to je pozitivno, svi koji možete i znate puno obavezno me ispravljajte, jer nitko ne zna sve i dobro je da se tekst može korigirati za buduće čitatelje...

Kako već pišem za početnike ponekad da pojednostavim stvari ne pišem apsolutnu istinu, nego istinu koju bi početnik možda trebao znati prije nego se upusti u totalno nizak podhvat : "Razumjevanje mikroračunala". Postove pišem javno, pa stoga javno mogu pisati i neistine, no u svakom slučaju ako u teksovima napišem nešto što baš i ne bi trebalo biti tako napisano jer je pretjerano daleko od prave istine obavezno mi pošaljite poruku kako bi na kraju dobili što jednostavnije i smislenije upute za učenje programiranja AVR-a.

Sve tekstove koje pišem ću tjekom vremena iznova ažurirati i dorađivati, stoga je sasvim uredu da u tekstu može biti eventualnih propusta i grešaka. Oni koji su čitali postove ranije primjetili su možda da ATMEGA88 radi na 16 000 000. No to nije sasvim točno jer u datasheetu piše da radi na 20 Mhz. Stoga na takve propuste upozoravajte jer većinu teksta pišem iz glave, a ne iz datasheeta s obzirom da bi mi trebalo puno više vremena da sve što napišem provjerim u datasheetu.
Zapravo se trenutno borim sa nekim ARM procesorom koji je svoja vrsta kompleksne nauke, a njegov datasheet ima oko 900 stranica, stoga postoji mogućnost da pomješam sve te informacije u jednu trenutnu neistinu na forumu...

Hvala na uvaženim isprikama. :azdaja:
InTheStillOfTheNight
User avatar
InTheStillOfTheNight
Odlično uznapredovao
Odlično uznapredovao
Posts: 938
Joined: 01-06-2006, 17:54
Location: Zagreb

Re: U potrazi za tartufima AVR-a

Post by InTheStillOfTheNight »

"U potrazi za tartufima AVR-a" Misija - 1. Upaliti LED

Dakle malo sam se igrao instrumentom oko platforme UI 4x4 i skužio da postoji spojena LED dioda i RELAY koji se nalaze na PINU 23 mikroračunala ATMEGA88. Pogledam u datasheet, onu knjigicu sa 300 stranica i vidim da se radi o PC0 (PORT C 0). Također sam primjetio da se ta LED-ica i RELAY pale sa logičkom nulom. (0V). Stoga program mora postaviti PC0 kao izlaz, te na njega upisati logičku nulu, i po mogućnosti više ništa ne raditi.

No moram malo odlutati od teme:

Znate li da moj laptop ima 32 bitni procesor? Vaš je možda 64 bitni, pa vas pitam koliko je to bitno?
Bitno je, naravno da je bitno. Vaš je 64 bitan, a moj samo 32 bitan, stoga je vaš duplo bitniji nego moj?
Što znače ti bitni brojevi 32,8,64?

Evo jedan 8 bit-ni broj: (BIN)11111111
Evo jedan 32 bitni broj: (BIN)11111111 11111111 11111111 11111111
Po tome 64 bitni broj sastoji se od 64 znamenke ( 0 ili 1 ).

No zašto je to bitno?
Zaključili smo kako procesor samo izvršava instrukcije: zbroji, oduzmi, usporedi, poguraj, povuci, skoči tamo-vamo.
32 bitni, 64 bitni ili 8 bitni procesor znači broj bitova s koliko on računa "nešto" u jednoj assemblerskoj instrukciji.
ATMEGA88 je 8 bit-no računalo, pa mogu zaključiti kako je maksimalni broj s kojim on zna računati: BIN:11111111, HEX:FF ili DEC:255.
Za prebacivanje brojeva iz DEC, u HEX ili BIN najjednostavnije je koristiti Windows Calculator. Dobro je za početnike uhvatiti se malo http://www.google.com" onclick="window.open(this.href);return false; i proučiti kako se računa u HEX, DEC i BIN jer to su osnove koji bi ipak trebali znati.

Vraćam se temi LED-ice na portu PC0. Kako 8 bit-no računalo uvijek računa isključivo sa 8 bit-ova zato sve u tom računalu uvijek izgleda kao 8 nekakvih stanja (0 ili 1). Pa tako i portovi imaju imena od recimo PB0 do PB7.

Kako to u AVR studio izgledaju ti registi PORT-a C?
http://img857.imageshack.us/img857/7311/mega883.jpg" onclick="window.open(this.href);return false;

To be continued...
InTheStillOfTheNight
User avatar
InTheStillOfTheNight
Odlično uznapredovao
Odlično uznapredovao
Posts: 938
Joined: 01-06-2006, 17:54
Location: Zagreb

Re: U potrazi za tartufima AVR-a

Post by InTheStillOfTheNight »

"U potrazi za tartufima AVR-a" Misija - 1. Upaliti LED

Ako se malo bolje zagledate u zadnju objavljenu sliku, skužiti ćete kako svaki PORT AVR-a ima 3 registra:
DDRC
PINC
PORTC


Opisati ću važne stvari oko ova 3 registra (Barem važne kad želimo upaliti LED)...

DDRC -> Data Direction Register C
Ovaj registar sadrži informacije o onoj nožici mikrokontrolera (Ulaz ili izlaz). (Samo za PORT C, 8 Bitno računalo, 8 linija, 8 svega)
Procesor ili jezgra iz FLASH-a izvršava instukcije koje mogu upisati na ovaj registar 8 nula ili jedinica. A samim time naš program će sigurno tamo morati upisati "00000001" jer mi želimo izlaz na PC0, pošto želimo upaliti LED-icu koja se tamo nalazi. Ako bi imali spojenu LED-icu na PC7, onda bi u DDRC morali upisati ovo: 10000000 (BIN).

Prva nožica PORTA C, uvijek se zove PC0, a zadnja PC7.

Već sam naveo kako su svi PORT-ovi po default ULAZI, pa sada mogu napisati da logička "0" znači ulaz.

Kada se procesor uključi na napajanje te POR (Power on Reset) resetira CPU , te Program Counter bude postavljen na adresu 0 gdje se nalazi prva instrukcija FLASHA) svi registri PORT-ova biti će 0, tj ulaz. Lako je dakle zaključiti kako mi moramo na DDRC upisati "00000001" (BIN) kako bi postavili PCO kao izlaz.

Nemojte mješati PORT C sa PC0 -> Port C je čitav PORT (8 nožica mikroračunala), a PORTC0 je nulta nožica od tih 8... Dakle sve je 8 (PC0 - PC7).

PINC-> "Dvoličan registar" -> Može biti jedno, ali ako znaš malo više o njemu znaš, onda je sasvim drugo...
Ovaj registar ovisi o tome kako smo konfigurirali smijer podataka (DDRC) registar.
Za sada ćemo predpostaviti kako smo smijer (DDRC registar) odabrali kao izlaz zbog tog krajnjeg cilja palenja Led-a, onda PINC registar ima jednu ličnost...

Prva ličnost PINC registra....

Stavka 1: Ako ga čitamo, on će nam sigurno reći kakvo je stanje našeg izlaza -> Ovo može biti korisno ukoliko pri programiranju ne želimo pratiti kada smo izlaz postavili na LOG 1, te kada smo ga postavili na LOG 0. Jednostavno pročitamo PINC registar i tamo piše jeli izlazna linija na 0V ili na 5 V...

Stavka 2: Imena TOOGLE -> Također korisna stvar. Ako na ovaj registar upišemo logičku jedinicu, izlaz kakav god bio će promijeniti trenutno stanje. Dakle, ako je bio 0 postati će 1, a ako je bio 1 postati će 0. Korisno je ukoliko recimo želimo blinkati LED-icom, ali nas ne zanima jeli LED trenutno upaljen ili ugašen, stoga samo na PINC registar upišemo 1 (na poziciju PC0 -> 00000001), i sigurni smo da će taj PC0 promjeniti stanje izlaza...

O drugoj ličnosti ovog registra govoriti ćemo kada budemo nožicu mikroračunala koristili kao ULAZ.

PORTC -> Također "dvoličan" registar... Drugačije se ponaša kada je DDRC registar konfiguriran kao ulaz, a drugačije kad je izlaz. Trenutno ću opisati ličnost, samo kad je izlaz, jer to i je krajnji cilj ideje.
Ako na PORTC upišemo log "0", nožica mikrokontrolera će biti 0V povučena sa tranzistorom, stoga kroz ovu logičku "0" možemo vući struju za LED. Ako u PORTC registar upišemo LOG "1", tada će nožica mikrokontrolera biti 5V, no također 5V PNP zatvorenog tranzistora, stoga i iz ove situacije možemo također vuči struju...

Ovo je bitno ukoliko je netko radio sa 8051 arhitekturom, koja sve izlaze ima open-collector. Na 8051 postoji samo jedan tranzistor koji izlaz vuče na 0V te je 0V jedino iskoristivo za vući struju dovoljnu za palenje LED-a, dok AVR ima 2 PUSH-PULL tranzisotra koji mogu koristiti i 0V i 5V da bi povukli struju iz mikrokontrolera...

Kod 8051 bitno je kako okrenemo LED diodu, jer iskoristiva je jedino LOG 0 za dovoljnu struju koja može upaliti LED, dok kod AVR-a kako god je okrenemo, koristili LOG "0" ili LOG "1" mikrokontrolera, uvijek imamo osiguranu dovoljnu struju za LED.
Za početnike dobro bi bilo proučiti pojmove: "Open Collector", "Push-Pull"
Evo i neki link koji sam onako "odoka" metodom pronašao:
http://www.ecircuitcenter.com/circuits/ ... shpull.htm

Tranzistor kao sklopka ovisno o tipu PNP, ili NPN može liniju potrošača povlačiti na 0V (NPN), ili na 5V (PNP).
Kod 8051 postoji samo jedan NPN tranzistor, stoga izlaznu liniju moramo vući na 0V ako želimo iskoristiti struju tog tranzistora. Kod AVR-a imamo 2 tranzistora, jedan je zadužen da može povući struju prema 0V, dok je drugi zadužen da je može povući prema 5V.

Dosta zbunjeno ovo zvuči, no vjerujem da će biti jasnije kada budem programirao, te sve ove primjere prezentirao...

Mislio sam slikati fotićem konfiguraciju i programiranje, ali kasnije mi je došla ideja zašto to da ne snimim i dignem na youtube?? Onda sam pogledao u monitor preko fotića, i skužio da se ništa živo ne vidi. Pa sad sam u potrazi za nekim programom koji može snimati ono što se događa na monitoru...

Ne znam postoji li takvo nešto, no mislim da bi moralo postojati, jer ne vidim razlog da ne postoji, stoga ako netko zna takav program neka pošalje PM. Iskreno, još nisam ni kopao o tome po http://www.google.com" onclick="window.open(this.href);return false; jer sam danas planirao napisati barem jedan post o ovim registrima, pa sad bih ipak trebao nekakav takav program da sve ovo o čemu serem mogu snimiti, kako bi to zajedno dobilo nekakav smisao teksta...

Ovo o čemu sam danas pisao nalazi se na stranici 71 datasheeta one knjigice koju ne čitamo kao "Biblija":
13.2 Ports as General Digital I/O Page(71)

To be continued...
InTheStillOfTheNight
User avatar
InTheStillOfTheNight
Odlično uznapredovao
Odlično uznapredovao
Posts: 938
Joined: 01-06-2006, 17:54
Location: Zagreb

Re: U potrazi za tartufima AVR-a

Post by InTheStillOfTheNight »

"U potrazi za tartufima AVR-a" Misija - 1. Upaliti LED

Hvala, @feko, program je odličan... Budem dizao na youtube, jer mislim da je tako najbolje i sigurno najpreciznije kako napraviti palenje LED-a.

Jedina obavezna funkcija u programskom jeziku C je int main(void); i to po standardu C-a znači početak programa. Netko bi mogao pomisliti kako se to nalazi na adresi 0 u FLASH-u, no ti nije sasvim točno. Compiler će za nas odraditi nešto drugo na adresi 0 u FLASHU, a funkcija main biti će nešto malo dalje od adrese nula FLASH-a. Ovo ću kasnije objasniti detaljno, no za sada moramo znati da je svaki početak programa u programskom jeziku C uvijek funkcija "main", dok će se prevodilac pobrinuti da to dobro prevede na assemblerske naredbe.

Evo youtube link kako napisati program palenja LED-a.

http://www.youtube.com/watch?v=sbcrKH5aDco
"Prebaciti u HD"

Code:

Code: Select all

#include <avr\io.h>
int main(void){
    DDRC = 1;          
    while(1);       
}
Evo nedoumice koje bi mogle biti nejasne...

Nisam pisao po PORTC registru? Zašto?
Već sam do sad naveo kako su PORTC, PINC, te DDRC prilikom reseta mikrokontrolera uvijek logička nula, no naveo sam kako se LED na platformi UI4x4 pali sa logičkom nulom.
Dakle nisam morao ići upisati 0 na PORTC 0 jer je taj registar po defaultu 0 nakon reseta, stoga sve što sam morao napraviti je ulaz konfigurirati kao izlaz. DDRC = 1;
Nakon izvršavanja ove naredbe LED se pali.

#include <avr\io.h>
Da bih nešto upisao u registar moram znati na kojoj se on adresi nalazi. Naveo sam kako ćemo koristiti biblioteke compilera WINAVR, stoga sam u svoj program ubacio njihovu gotovu biblioteku u kojoj se nalaze sve adrese ovih registara. Kada god hoćete pisati po port registrima morate napraviti ovaj include.

"{" "}" - otvorena zagrada znači početak glavne funkcije programa int main(void);
int znači da funkcije može vratiti nekakav int parametar, no o tome ću pisati kada budem pisao o funkcijama. Void znači da funkcija nema atributa, što ću također pisati kada budem pisao o funkcijama.
Za sada treba znati kako je ovo osnovna funkcija svih programa, i što god da radili u AVR studio, ona mora postojati i uvijek označava početak programa.

while(1);
ili sve dok je jedan, no uvijek je 1 pa tako dobivam beskonačnu petlju. U jednom od postova napisao sam da procesor mora "ne raditi više ništa", no to se ne može baš tako jednostavno napraviti. Procesor je prisiljen na svaki clock izvršiti jednu instrukciju.

Stoga mu ja kažem da izvršava tu svoju jednu instrukciju, a ona glasi "sve dok je 1, izvršavaj isti sve dok je 1".

Dakle procesor će zaglaviti na toj naredbi, te je stalno izvršavati, a zapravo neće raditi ništa pametno. Time smo postigli da se program nikad ne završi ili izgubi, te da LED svijetli...
Postoje niz načina kako zaglaviti procesor.
while(1) je programska petlja koja se izvršava sve dok ovaj parametar 1 ne postane 0, a mi smo ga u samoj naredbi postavili na 1, te on nikad neće postati 0.

klik na build/rebuild all prevodimo C napisan program na strojni HEX jezik, te time kreiramo hex datoteku koju treba upisati u FLASH mikrokontrolera.

Fileove neću dizati na forum, jer mi nije cilj da početnik ima gotov program, jer poanta priče nije imati gomilu programa, nego pisati sve sam i učiti se kako ovo programirati.

To be continued...
InTheStillOfTheNight
User avatar
InTheStillOfTheNight
Odlično uznapredovao
Odlično uznapredovao
Posts: 938
Joined: 01-06-2006, 17:54
Location: Zagreb

Re: U potrazi za tartufima AVR-a

Post by InTheStillOfTheNight »

"U potrazi za tartufima AVR-a" - Juriš na assembler, bitka kod HEX-a

Ovaj naslov je i tako ispred svog vremena i davno sam odlučio da će takav biti. Prije ovoga mislio sam napisati post o "upucavanju" Hex file-a u ATMEGA88, no to ću napraviti kasnije.
Razlog tome je naravno bucin topic o assembleru i drago mi je da se odlučio pisati takvo nešto.
Cilj posta je svakako prezentacija odnosa snaga assemblera i C-a. Program palenja LED-a u C-u sam već napisao, no sa strane assemblera ovo izgleda potpuno drugačije. Bitka kod hex-a svodi se na najnižu razinu na koju se u programiranju možemo spustiti... "Dno-Dna" -> Sve ispod ovoga bi bilo dizajniranje vlastitiog računala...

Što je HEX file i kako izgleda?
Samo ime HEX govori da je datoteka zapisana u Hexadecimalnom brojevnom sustavu: (0,1,2,3,4,5,6,7,8,9,A,B,C,D,E,F)

Evo jedan red HEX file-a koji ću rastaviti i objasniti značenje HEX file-a:
(Ovo je prvi red iz HEX file-a za palenje LED-a i programa kojeg sam napisao u C-u)

:1000000019C020C01FC01EC01DC01CC01BC01AC00C

Ovako je to zapisano u HEX datoteci, no ubaciti ću nekoliko razmaka u taj red jer moram red drugačije formirati da bi razlikovali stvari koje se nalaze u jednom redu...

: 10 0000 00 19C0 20C0 1FC0 1EC0 1DC0 1CC0 1BC0 1AC0 0C

Hex rastavljen prema redosljedu logičkih cjelina:
: - označava početak reda u HEX datoteci. (Početak HEX zapisa)

10 - označava broj data byteova u tom redu. Ne radi se o 10 byteova nego o 16. Hex je pisan
u Hexadecimalnom sustavu, pa probajte kalkulatorom prebaciti HEX 10 u DEC sustav i to je 16
Tih 16 znači da u jednom redu postoji 16 "data" byteova.

0000 - Adresa na koju se upisuje data zapis HEX filea. Kao što vidite prvi red u HEX datoteci za
palenje LED-a ima adresu 0000 jer to je prva naredba koju će izvršiti AVR jezgra.

00 - ovo označava tip zapisa hex filea. 00 označava "DATA" zapis. U INTEL HEX fileu postoji 6
različitih tipova zapisa, no kad piše "00" sigurno se radi u DATA zapisu koji u sebi sadrži
16 bitnu adresu.

Nakon descriptora jednog reda idu instrukcije: 19C0 20C0 1FC0 1EC0 1DC0 1CC0 1BC0 1AC0.
Veličina svake instrukcije AVR jezgre je 2 byte-a. Postoje assemblerske instrukcije koje su 4 byte-a jer u 2 byte-a jednostavno je nemoguće napraviti sve instrukcije AVR-a. No to nam nije toliko bitno jer kada bi analizirali svaku naredbu skužili bi koja je 4 byte-a a koja 2 byte-a. Ovaj dio HEX filea sam izvukao iz palenja LED-a, pa također mogu zaključiti kako će AVR jezgra za prvu instrukciju sigurno izvršiti 19C0(HEX).
Bez obzira što ovo nitko nikad ne mora koristiti bitno je zapamtiti da svaka assemblerska instrukcija za AVR jezgru može biti 2 ili 4 byte-a.

Ako znamo koliko je velika jedna instrukcija, jednostavno je izračunati koliko instrukcija assemblera može stati u ATMEGA88.
Ako imao 8192 Bytea FLASH-a, onda sigurno u to može stati duplo manje assemblerskih instrukcija jer svaka instrukcija treba minimalno 2 byte-a.
8192/2 = 4096 -> ATMEGA88 može pohraniti u FLASH 4096 assemblerskih instrukcija

Ovo su instrukcije koje se nalaze u jednom redu HEX file-a.
Prvi byte u HEX fileu označava broj data byte-ova -> 10(HEX), 16(DEC).
Dakle idam zbrojiti koliko ima tih byteova assemblerskih instrukcija...

19C0 - 2 Bytea
20C0 - 2 Bytea
1FC0 - 2 Bytea
1EC0 - 2 Bytea
1DC0 - 2 Bytea
1CC0 - 2 Bytea
1BC0 - 2 Bytea
1AC0 - 2 Bytea

________________
Total = 16 bytes(DEC) (10HEX)

Moramo izvuči i zaključak ovoga -> U jednom redu HEX filea postoji max 8 assemblerskih naredbi, ili 16 data byteova za AVR jezgru.

Osatao je i famozni kraj HEX filea koji uvijek završava sa jednim byteom. U ovom slučaju piše -> "0C"
Kontrolni byte jednog reda reda HEX file-a zove se "checksum"
Dakle taj byte potvrđuje vjerodostojnost svih byteova u tom HEX redu i računa se na sljedeći način:

Ponovno mi treba čitav red HEX-a ->
:1000000019C020C01FC01EC01DC01CC01BC01AC00C

Zadnji byte ću obrisati kako bi ga mogao ponovno izračunati.

:1000000019C020C01FC01EC01DC01CC01BC01AC0

Prvo što radim je to da razdvojim to na byteove ->

10 00 00 00 19 C0 20 C0 1F C0 1E C0 1D C0 1C C0 1B C0 1A C0
Pokrenem windows calculator, prebacim ga u HEX i računam ovo:
10 + 00 + 00 + 00 + 19 + CO.... -> Zbrojim sve byteove u Hex redu. Osim zadnjeg kojeg smo obrisali jer njega računamo.
Rezultat koji dobivan je 06F4. Broj koji sam dobio veći je od jednog byte-a pa uvijek uzimam niži byte -> "F4". U calculatoru računam "F4 XOR FF" i za relultat dobivam "0B".
Dodam ovom "0B" rezultatu "01" i dobivam "OC". Dakle, OC mora biti na kraju ovog HEX reda. Evo univerzalna formula:
Checksum HEX reda računam tako da od zbroja svih byteova uzimam onaj niži (manje važeči), te računam XOR sa 0xFF i uvećavam rezultat za 1.
Bitno je primjetiti da sam izbrisao checksum prilikom njegovog računanja i taj zadnji byte ne ulazi u formulu za proračun checksuma.

Dakle ovaj zadnji byte je izračunat prema svim ostalim byteovima u istom redu HEX filea samo kako bi mogao dokazati vjerodostojnost podataka u istom redu. Ako promjenimo samo jedan BIT u čitavom HEX redu checksum neće odgovarati rezultatu checksuma i samim time naš HEX file nije dobro zapisan.

Koja je u tome najnižem nivou moć assemblera?
Ako možemo sami pisati HEX te izračunati sve što je potrebno za FLASH MCU-a što mi onda radimo? Programiramo ili pišemo brojeve?

Hex file je u principu strojni assembler, ovi brojevi su assemblerske naredbe koje su nazvane imenima čisto da bi komande imale smisla. U notepadu to izgleda kao broj, no radi se o čistoj, od majke rođenoj assemblerskoj instrukciji.

Tu nastaje ta prva rupa između C-a i assemblera. U c-u mi ne možemo utjecati na HEX file jer ga generira compiler, i on odlučuje kako će napraviti HEX file, dok u assembleru nas zapravo boli "k" za sve, jer mi smo ti koji odlučujemo o svakoj instrukciji. Mi smo oni koji slažu instukciju za instrukcijom i nitko drugi osim nas ne može utjecati na redosljed instrukcija AVR jezgre.

Žalosna istina na kraju ovog dijela napada na HEX je sljedeća:
Da bi mi upalili LED potebne su 3 assemblerske instrukcije (@buco vjerojatno zna i kraći način, no trenutno mi se ne kopa po assemblerskim instrukcijama da bih ovo napravio kraće)

Možda se pitate zašto HEX file koji je napravio compiler WINAVR iz C-a izgleda ovako:

Code: Select all

:1000000019C020C01FC01EC01DC01CC01BC01AC00C
:1000100019C018C017C016C015C014C013C012C034
:1000200011C010C00FC00EC00DC00CC00BC00AC064
:1000300009C008C011241FBECFEFD4E0DEBFCDBF82
:1000400002D004C0DDCF81E087B9FFCFF894FFCFA5
:00000001FF
dok Hex file koji sam kasnije napisao u assembleru izgleda ovako:

Code: Select all

:0600000081E087B9FFCF8B
:00000001FF
Vidite da je zadnji red HEX file-a identičan, i ako njega rastavimo po pravilima HEX file-a dobijemo ovo
00 0000 01 FF.
00 -> Broj byte-a je 0
0000 -> Adresa zapisa je 0
01 -> Tip zapisa više nije 00 nego je 01. Ovo u HEX-u znači kraj file-a.
FF -> Onaj dosadni checksum -> Zbroj byteova je 01 -> 01 XOR FF = FE, FE + 1 = FF -> Dakle checksum mora biti FF

U svakoj HEX datoteci može postojati samo jedan kraj file-a i uvijek se označava sa tipom zapisa "01". Orginalna ideja (iz 1970) tog kraja je da u njemu postoji i adresa prve instrukcije koju izvršava jezgra, pa je u ovom našem HEX fileu dobro upisana adresa na 0000. No ovo u stvarnosti baš ne drži vodu jer ne bira HEX file odakle će jezgra startati, nego to bira FUSE AVR MCU-a o kojemu ćemo naravno kasnije.

Ovaj tekst oko HEX file-a nije potrebno znati, ali onaj tko hoće može si bez problema otvoriti HEX file i analizirati sve instrukcije AVR jezgre.

Zašto ja pišem ove gluposti o HEX-u? Postoji samo jedna razlika između pravih programera, i dakako onih koji to nisu.
Što napraviti kad nastane problem???
Bascom, C i svi jezici koji nisu assembler u sebi imaju nešto što možemo nazvati RANDOM BUG, pa tu i tamo znaju popizditi i napraviti glupost. Te gluposti mogu biti ili neznanje programera da kaže compileru što želi, ili compiler jednostavno ni sam ne zna kako da napravi to što programer želi, pa napravi sranje od HEX file-a.

Snaga programera je samo u daljini koliko seže njegovo znanje te oružja s kojima raspolaže.
Ako ja napadam "problem", koji ne želi odustati, sigurno da ću otići u najgoru moguću krajnost assembera i HEX-a, dok programer C-a ili BASCOM-a mora ostati na razini višeg jezika i problem ne može riješiti narednih 200 godina.

Povući ću jednu zanimljivost o HEX file-u. Dok ne znate što je to svi mislite da se upisuje u FLASH MCU-a, no ti nije istina.
Kada pogledamo što sve postoji u HEX redu vidimo da postoje gluposti kao adresa, broj byte-ova u jednom redu, tip zapisa i checksum reda.
Koji bi to konj napravio MCU i upisao u FLASH čitav hex? Ono što se stvarno upisuje u FLASH MCU-a su samo instrukcije, a sve ostalo što se nalazi u samom HEX-u potrebno je da bi se znalo kamo što treba upisati.
Dakle u FLASH MCU-a ne ide HEX, nego samo instrukcije za jezgru. HEX je takav kakav je samo da bi protokol upisivanja FLASH-a znao kamo što upisati, pa mogu zaključiti kako za prvi red HEX-a u MCU FLASHA biti će upisane samo instrukcije: 19C0 20C0 1FC0 1EC0 1DC0 1CC0 1BC0 1AC0
Istinski FLASH u AVR-u nije HEX, nego samo instrukcije poslagane upravo onako kao HEX file opisuje.

To Be Continued...
InTheStillOfTheNight
User avatar
InTheStillOfTheNight
Odlično uznapredovao
Odlično uznapredovao
Posts: 938
Joined: 01-06-2006, 17:54
Location: Zagreb

Re: U potrazi za tartufima AVR-a

Post by InTheStillOfTheNight »

"U potrazi za tartufima AVR-a" Misija - 1. Upaliti LED (2. dio)

U C-u je nešto kompliciranije upravljati pojedinim izlazima na MCU. Jasno je kako se LED dioda nalazi na PC0, no postavlja se pitanje kako da upravljate sa PC0, a ne dirate ostale linije porta C?

Ako vi izjednačite registar smijera podataka sa nekim brojem "DDRC = 1;" upravo ste prepisali svih 8 bitova. DEC "1" je BIN "00000001" što bi značilo da je zadnji desni bit PC0.

Činjenica je da smo mi na točnu poziciju upisali "1", ali je isto tako činjenica da smo na sve ostale linije upisali ponovno "0", a to nismo željeli. Što ako je neki od njih bio "1" i morao ostati "1" ?

Možda se pitate zašto u C-u "AVR Studio, WINAVR" ne postoji ono PC1, PC2, PC3, pa da mi mozemo upisati samo jedan bit a ne svih 8?

Odgovor na to pitanje čisto je političke naravi: Programski jezik C je striktan sa puno pravila kojih se moramo držati u programiranju. Neki alati C-a tipa "codevision" imaju implementiranu mogućnost jednostavnog pristupa "bit-u", dok većina njih nema... No da se mi ne bavimo politikom, prava pravila C-a nemaju nikakve komande tipa PC0, PC1, PC2 ( na bazi jednog bita) i upravo zato AVR studio nije htio kršiti pravila C-a i napraviti nekakve svoje komande koje ne postoje u programskom jeziku C.
Apsolutno se slažem sa razmišljanjem ATMEL-a oko ovoga, jer zamislite da svaka firma u svakom compileru ubaci nekakve svoje komande, pa zaboga tko bi to sve pamtio. Programski jezik C mora biti jedan i jedinstven za sve compilere. Upravo ta činjenica nam dozvoljava da odaberemo bilo koji MCU, te poznavanjem C-a gotovo iste sekunde možemo početi programirati.

Jednom "bit-u" u AVR Studiu pristupamo operatorima "AND" i "OR"

1. Postavljanje prvog desnog bita (PC0) DDRC registra u logičku jedinicu radimo ovako:
DDRC |= (1<<0);

ovo je kraći zapis i ja ga uvijek koristim, a duži zapis je ovo:
DDRC = DDRC | (1<<0);

DDRC -> "Data direction register C" -> registar za smijer podataka porta C

| -> oznaka za "OR" operaciju u programskom jeziku C (ALT GR+W)

(1<<0) -> broj 1 pomičem u lijevo za 0 mjesta. :roll:

; -> kraj naredbe u C-u

Najveći prioritet u C-u su zagrade "()"- Program c-a uvijek računa sve s desne strane jednakosti i tada to upiše u ono što se nalazi na lijevoj strani. Ono što je u najvišem prioritetu je (1<<0), stoga se ovaj red izvršava sljedećim redosljedom:
"00000001" guram u lijevo za "0" mjesta i dobijem isto to: "0000 0001"; :ohno:

sada radim "ili" operaciju dobivenog broja sa DDRC registrom:
(DDRC) 00000000 ILI
(1<<0) 00000001
________________
(DDRC) 00000001


"ILI" operaciju sa 2 byte-a svi bi trebali znati. Ako je u bilo kojem byte-u na nekom mjestu logička jedinica rezultat će sigurno na istom mjestu imati logičku jedinicu. U našem slučaju radi se o PC0 koji je postao log "1", a samim time PC0 smo postavili kao izlaz.

Potrebno je i dokazati da smo promijenili stanje samo prvog bita, a to ćemo napraviti da zamislimo kako je DDRC registar trenutno "10101010" i mi na istom registu radimo istu stvar:
(DDRC) 10101010 ILI
(1<<0) 00000001
________________
(DDRC) 10101011


Jasno da smo radeći "ILI" operaciju promijenili samo prvi bit (krajnji desni) u logićku jedinicu. Svi ostali su identični.

Ali zašto sam ja šiftao broj "1" za "0" mjesta u lijevo? :?:
Lijen sam, neda mi se razmišljati... Slučajno se pogodilo da se radi o PC0 "bit-u" pa mi je to bilo jednostavnije napisati ovako: DDRC |= 1;

No što ako se radi o PC7 bitu??? Idemo probati PC7 bit podići u logicku jedinicu:
(DDRC) 00000000 ILI
(------) 10000000
________________
(DDRC) 10000000


Vidimo da moramo raditi "ILI" operaciju sa brojem BIN: 10000000, HEX: 0x80, DEC 128
Kao programerima neda nam se pisati u BIN jer ima puno nula i jedinica, ružno je i nečitljivo, HEX 0x80 i DEC 128 nekako je glupo pamtiti jer onda za 6-ti bit opet moramo pamtiti koji je to HEX, BIN ili DEC broj...

No ako smo već toliko ljeni pamtiti bin, hex i dex onda barem znamo izvesti trik:
Pa zasto ja ne bi onda uzeo obicni broj "1" i samo ga pogurao za broj porta?
Zadnji bit je sigurno PC7, pa ako njega dizem u log 1 najprije radim (1<<7), dakle gurnem broj "1" "7" puta u lijevo i znam da sam dobio ovo: 10000000. Ako želim bilo koji drugi PC0,1,2,3,4,5,6,7 samo poguram broj "1" toliko puta u lijevo. Ovo svi C compileri dobro razumiju i neće napraviti veći program zato jer mi imamo više teksta. Program je identičan u sva tri slučaja:
DDRC |=(1<<7); // DEC TRIK
DDRC |= 128; // Razmišljanje o DEC broju
DDRC |= 0x80; // Razmišljanje o HEX broju


Postoji još jedan dobar razlog zašto se radi (1<<XX). Ako sami računamo masku, tj taj broj s kojim radimo ili operaciju za jedan BIT onda imamo izbor ovo: HEX-> 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80
Onako "BUM" iz glave vas sad pitam sta je maska za PC4 i svi ćete morati razmišljati koji je sad to po redu... Ali ako znamo da se radi o PC4 uvijek mozemo napisati ovo (1<<4) i sigurno smo 100% tocni... Taj jedan razlog zbog kojeg se ovo radi je smanjivanje ljudske greske u racunanju... Nama je i cilj da sve sto napisemo bude 100% tocno... Pisanjem ovog guranja broja "1" u lijevo bili bi kreteni da se zajebemo, dok računanjem maske tipa 0x10 ipak je veća mogučnost pogreške.

Dosta sam pročitao programa što su pisali programeri ATMEL-a i ovaj način koriste i oni za pristup jednom bit-u te podizanje log 0 u log 1 stoga gledam si, ako su u stanju napraviti takvo računalo moram biti prisiljen vjerovati da je ovo najbolji način.

Evo konfiguracija izlaza za čitav port C:
DDRC |= (1<<0); //Config PC0 as output
DDRC |= (1<<1); //Config PC1 as output
DDRC |= (1<<2); //Config PC2 as output
DDRC |= (1<<3); //Config PC3 as output
DDRC |= (1<<4); //Config PC4 as output
DDRC |= (1<<5); //Config PC5 as output
DDRC |= (1<<6); //Config PC6 as output
DDRC |= (1<<7); //Config PC7 as output


Sve nakon "//" je komentar i tim načinom komentiramo ono što programiramo.

Ovaj način podizanja logičke nule nema veze sa DDRC registrom, to je standard C-a i dizanje bilo kakve nule u jedinicu u C-u na bazi jednog BIT-a uvijek se ovako radi. Ovo koristimo na varijablama i na svim registrima i općenito na svemu u C-u. Ako se radi o registru DR_MR_FR_GR koji ne postoji u AVR-u opet je ista stvar. Za prvi desni bit opet radimo:
DR_MR_FR_GR |= (1<<0);

ako se radi o varijabli C-a u ram-u imena "sabahudin" za prvi desni bit radimo ovo:
sabahudin |= (1<<0);

Dakle totalno univerzalna stvar za pristup jednom bit-u u C-u..

Čitav ovaj post govori o tome kako podići logičkI "0" u logičkI "1", no nisam spomenuo kako "1" vratiti nazad u "0".

Stvar je slične naravi, radi se sa "AND" operatorom i objasnim u sljedećem postu.

Za ovaj post dovoljno je zaključiti kako se izlaz za ledicu koja se nalazi na PC0 programira ovako:

DDRC |= (1<<0);

I kada to tako napišete to je jasno kao dan i meni, i svima koji programiraju u C-u. Pogotovo iz razloga jer programeri ATMEL-a rade identičnu stvar i svakako trebamo kopirati njihove trikove jer smo maleni za nešto pametnije.
Ovaj post se ne tiče samo AVR-a nego programskog jezika C, tako da se ista stvar može primjeniti na svim mikrokontrolerima koje programiramo u C-u.

To Be Continued...
InTheStillOfTheNight
User avatar
InTheStillOfTheNight
Odlično uznapredovao
Odlično uznapredovao
Posts: 938
Joined: 01-06-2006, 17:54
Location: Zagreb

Re: U potrazi za tartufima AVR-a

Post by InTheStillOfTheNight »

"U potrazi za tartufima AVR-a" Misija - 1. Upaliti LED (3. dio)

Spuštanje jednog BIT-a iz log "1" u log "0" nam ne treba da bi upalili LED na PC0, ali će nam sigurno trebati kasnije. Ove metode spuštanja i dizanja jednog BIT-a koristimo gotovo uvijek kada pristupamo registrima MCU-a pa tako da bi taj dio morao biti jasan.

Spuštanje PC0 BIT-a u logičku nulu:
__________________________________
kraći zapis:
DDRC &= ~(1<<0);

duži zapis:
DDRC = DDRC & ~(1<<0);
__________________________________

DDRC -> "Data direction register C" -> registar za smijer podataka porta C

& -> oznaka za "AND" operaciju u programskom jeziku C (SHIFT+6)

~ -> "Ones Complement" operator za okretanje stanja svih bitova (ALT GR+1)

(1<<0) -> broj 1 pomičem u lijevo za 0 mjesta. :roll:

; -> kraj naredbe u C-u
__________________________________

Opet krećemo od onog guranja broja "1" u lijevo (1<<0), dakle poguram broj 1 u lijevo za 0 mjesta i dobijem isto to BIN: 00000001

Sad ide ovaj čudni i nelogični znak "~", a on uvijek okreće stanje svih bitova. Uzmemo naš rezultat za (1<<0) i okrenemo mu sve bitove:

00000001 ~
________
11111110


i sada radimo "AND" operaciju sa DDRC registrom:
(DDRC) 00000001 AND
~(1<<0) 11111110
___________________
(DDRC) 00000000


AND operaciju bi svi trbali znati: Ako je bilo koji od BIT-ova logička "0", rezultat će za taj BIT uvijek biti logička "0".

Ovim načinom sigurno smo spustili jedan BIT (PC0 -> krajnji desni) u logički "0", no da bi dokazali da nismo promijenili ostale BIT-ove opet moramo uzeti slučaj kada oni nisu bili logička "0";

Dakle, zamislim da je DDRC registar trenutno BIN: 00110011, i samo želim spustiti PC0 u logičku nulu.

Prvo radim ovo: (1<<0) i rezultat je BIN: 00000001
Nakon toga izvršavam "~" i time okrenem stanje svih bitova te dobijem rezultat 11111110
Sada radim "AND" operaciju sa DDRC registrom:

(DDRC) 00110011 AND
~(1<<0) 11111110
___________________
(DDRC) 00110010


Kada radimo maskiranje sa AND operatorom vidimo da naša maska BIN 11111110 propušta sve logičke jedinice osim prve, i zato je DDRC registar zadržao sve logičke jedinice nepromjenjenima osim naravo one koju smo i htjeli spustiti u logičku nulu.

Evo konfiguracija ulaza za čitav port C:
DDRC &= ~(1<<0); //Config PC0 as input
DDRC &= ~(1<<1); //Config PC1 as input
DDRC &= ~(1<<2); //Config PC2 as input
DDRC &= ~(1<<3); //Config PC3 as input
DDRC &= ~(1<<4); //Config PC4 as input
DDRC &= ~(1<<5); //Config PC5 as input
DDRC &= ~(1<<6); //Config PC6 as input
DDRC &= ~(1<<7); //Config PC7 as input


U ovim postovima oko dizanja i spuštanja jednog BIT-a napisani su i objašnjeni primjeri za PC0, zbog ledice koju palimo, ali ovo su osnove koje moraju biti jasne da bi mogli bilo što raditi dalje. Bez ovoga ne možemo napisati niti jednu liniju programa i svakako bi svi oni koji ovo ne razumiju trebali uzeti olovku i papir i sami sebi dokazati zašto se to tako radi, i kako se računa. Programska osnova je jednostavna i imamo samo 2 kombinacije pisanja, pa evo na kraju u programu konfiguracija izlaza za čitav port C, te konfiguracija ulaza za isti PORTC, jer ako budete testirali moje linije vjerojatno ćete zaboraviti napraviti #include <avr\io.h>, a to je objašnjeno u prošlim postovima. Što se tiče razloga zašto opet guram broj "1" u lijevo identičan je kao i u prošlom postu.

Code: Select all

#include <avr\io.h>

int main(void){
    DDRC |= (1<<0); //Config PC0 as output
    DDRC |= (1<<1); //Config PC1 as output
    DDRC |= (1<<2); //Config PC2 as output
    DDRC |= (1<<3); //Config PC3 as output
    DDRC |= (1<<4); //Config PC4 as output
    DDRC |= (1<<5); //Config PC5 as output
    DDRC |= (1<<6); //Config PC6 as output
    DDRC |= (1<<7); //Config PC7 as output

    DDRC &= ~(1<<0); //Config PC0 as input
    DDRC &= ~(1<<1); //Config PC1 as input
    DDRC &= ~(1<<2); //Config PC2 as input
    DDRC &= ~(1<<3); //Config PC3 as input
    DDRC &= ~(1<<4); //Config PC4 as input 
    DDRC &= ~(1<<5); //Config PC5 as input
    DDRC &= ~(1<<6); //Config PC6 as input
    DDRC &= ~(1<<7); //Config PC7 as input    
    
    while(1);  //Do Nothing
}
To Be Continued...
InTheStillOfTheNight
User avatar
InTheStillOfTheNight
Odlično uznapredovao
Odlično uznapredovao
Posts: 938
Joined: 01-06-2006, 17:54
Location: Zagreb

Re: U potrazi za tartufima AVR-a

Post by InTheStillOfTheNight »

"U potrazi za tartufima AVR-a" Zavjera sa vremenom

Svaki novi projekt koji krećemo programirati jednostavno mora imati redosljed. Kao programeri ne možemo u glavi držati čitav program, nego ga moramo razbiti na 1000 jednostavnih stvari. Uvijek prvo konfiguriramo ulaze i izlaze (DDRB, DDRC, DDRD registri). Radimo identičnu stvar kao kad palimo LED na PC0. To je jednostavno napraviti jer imamo hardware i točno znamo na kojem PIN-u je što spojeno i samo prema tome radimo gore opisane konfiguracije smijera podataka.

Kad to napravimo dolazimo do najtežeg problema svih početnika, a to je "vrijeme". Bilo koji tečaj za početnike nije istina, lažu vam u osnovnoj školi pa onda u srednjoj. Kamo god se okretine lažu vam. Čitavo vrijeme nas uče krivo razmišljati da bi onda postavljali nemoguće misije programiranja...

Najbolji i najjednostavniji primjer je blinkanje LED-icom. Uče nas ovako:

Code: Select all

#include <avr\io.h>
#include <util\delay.h>

int main(void){

    DDRC |= (1<<0);    //Config PC0 as output

    while(1){ // do forever

        PORTC &= ~(1<<0); // Led_on

        _delay_ms(1000);  // wait 1S

        PORTC |= (1<<0);  // Led_off

        _delay_ms(1000);  // wait 1S
    }
}
Istina da se ovim načinom programiranja postiglo to da LED stvarno blinka, ali isto tako je istina da vi više ništa živo ne možete dopisati u ovakav program. Već sam naveo kako je snaga programiranja u našoj brzini izvršavanja instrukcija. (AVR može izvršiti jednu instrukciju za 0.000000050 S). Kada u programu napišete _delay_ms(1000); upravo ste uništili jedino ono što u programiranju imamo, a to je brzina. Upravo ste rekli mikrokontroleru da svoju dragocjenu brzinu potroši na čekanje jedne sekunde.

MCU ne radi ništa pametno čitavu sekundu, zbraja i oduzima jedan te isti broj, samo da bi prošlo vrijeme od jedne sekunde. Vi kao programeri u toj situaciji morate znati da nemate vremena bilo što raditi, jer ste upravo MCU natjerali da ne radi apsolutno ništa čitavu jednu sekundu.

Kako bi ja sad nekom drugom LED-icom blinkao svakih 0.010 sekundi? U ovom programu očito nikako jer nemam dovoljno vremena zbog velikog _delay_ms(1000);

Rekao sam i u prvom postu da ću pisati o suštinskom programiranju i ne želim vam govoriti kako se ovako programira. Od sada i na dalje zaboravite na _delay_ms naredbe i sve naredbe vezane za čekanje u programu. Programirali vi u bascomu, basicu, ili ne znam čemu naredba WAIT, DELAY, SLEEP za vas ne postoji u mikrokontrolerima... Da bi znali dobro primjeniti delay naredbu najprije moramo naučiti programirati bez nje...

Naš program nikada i nigdje ne smije stati, a opet moramo programirati u realnom vremenu. Moramo znati stvoriti 1 sekundu vremena, a da je ne čekamo. Mikrokontroler uvijek mora trčati po čitavom programu kao muha bez glave i nikada ne smije stati i čekati. (barem ne u realnom vremenu).

Naredba čekanja koristi se samo u malim dozama, pa često u pisanju komunikacijskih drivera sa vanjskim hardwareom moramo malo sačekati ako emuliramo protokol komunikacije. Taj delay uvijek je brz i radi se o svega nekoliko uS. Tu programsku žrtvu moramo raditi jer nemamo implementiran Hardware MCU-a za sve što spajamo na MCU, no dok god koristimo protokole komunikacije koji su hardwerski podržani na mikrokontroleru nećemo koristiti delay.
Ovo je svakako uvod u nešto težu temu, a to je blinkanje LED diodom na PC0.

To Be Continued...
InTheStillOfTheNight
User avatar
InTheStillOfTheNight
Odlično uznapredovao
Odlično uznapredovao
Posts: 938
Joined: 01-06-2006, 17:54
Location: Zagreb

Re: U potrazi za tartufima AVR-a

Post by InTheStillOfTheNight »

"U potrazi za tartufima AVR-a" Zavjera sa vremenom (2-dio)

Kao početnika uvijek me mučilo to kako netko može napisati 1000 linija programa. Koliko god se ja trudio uvijek sam se izgubio u 50 linija programa. U jednom segmntu čekam, a u drugom već kasnim jer odrađujem prvi segment... Muka po svim apostolima...

Vjerujem da većina onih koji čitaju moje postove misle da sam im odsjekao noge i ruke u programiranju ako sam rekao da se delay ne smije koristiti. Nije to samo pitanje ATMEL-a nego pitanje svih mikrokontrolera ovog svijeta.

Tu analizu programiranja vrlo je jednostavno testirati na svim do sad napisanim programima. Pokušajte uzeti bilo koji program sa delay naredbama i obrisati ih sve.... (bez obzira koji MCU programirali)
Jedino što možete zaključiti da mikrokontroler "leti" po čitavom programu, ljudskom umu teško shvatljivom brzinom. Upravo takav program trebamo pisati, jer dok god naš program leti maksimalnom brzinom imamo neograničene mogućnosti programiranja.

Postavlja se pitanje:
Kako možemo čekati 1 sekundu, ako naš program ne smije čekati?

Odgovor je u suštini jednostavan:
Program nigdje neće stati, ali zato će svaki krug koji napravi pogledati u sat.

Svi mikrokontroleri imaju TIMER, a sve što mi moramo napraviti je da nam TIMER bude naš sat koji za nas prati vrijeme.

Ovo možda zvuči trivijalno, ali nije. Da bi TIMER podesili kako treba morati ćemo naučiti puno pojmova vezanih za mikrokontrolere.

To Be Continued...
InTheStillOfTheNight
User avatar
InTheStillOfTheNight
Odlično uznapredovao
Odlično uznapredovao
Posts: 938
Joined: 01-06-2006, 17:54
Location: Zagreb

Re: U potrazi za tartufima AVR-a

Post by InTheStillOfTheNight »

"U potrazi za tartufima AVR-a" - TIMER

Razmišljao sam kako da napišem samo jedan post koji govori o tome kako se stvara vrijeme od 1 sekunde, ali mislim da tu ima previše nejasnih pojmova, pa ću o ovome pisati dio po dio. U prošlom postu sam rekao da za ovo trebamo TIMER, pa je on tema ovog posta.

Dakle opet datasheet (stranica 5):
http://www.atmel.com/dyn/resources/prod ... oc2545.pdf
Image

Nemojte zamjeriti, ali često čemo pogledati u datasheet. Ono što bi svi trebali znati da je dokumentacija najbitnija i moramo je naučiti čitati. Nemoguće je bilo što programirati, a ne pozivati se na orginalnu dokumentaciju mikroračunala. Ovo je i globalni problem svih početnika jer uporno odbijaju čitati dokumentaciju.

U block diagramu jasno se vidi da ATMEGA88 ima 3 TIMERA:
8bit T/C 0 - 8 Bitni TIMER 0
16bit T/C 1 -16 Bitni TIMER 1
8bit T/C 2 -8 Bitni TIMER 2

Neću ih sada sve opisivati nego ću metodom "palac-oko" odabrati samo jedan koji ćemo nešto detaljnije proučiti. U suštini svi su oni isti, svi broje "nešto". Programer uvijek sam odlučuje koji timer želi za nešto koristiti, i koje su prednosti jednog, drugog ili trećeg timera.

Mislim da je bilo koji TIMER najkompliciranija stvar u mikrokontroleru. Sigurno je naopširnije poglavlje sa najviše novih pojmova te različitih načina konfiguracije. Datasheet ATMEGA88 mikroračunala sastoji se od 277 stranica teksta, od kojih je 61 stranica posvećena samo TIMER-ima.

Valjda zbog toga se svima diže kosa na glavi kada netko spomene TIMER u programiranju, no nije sve tako crno. Od svih tih stranica nama je bitno samo 3 ili 4 naredbe koje moramo znati napisati... TIMER je često kompleksan samo zbog jako opširnih mogućnosti koje pruža programeru.

U tu zbrku sa pojmom TIMER, uz vraga, uvijek se tu trpa i neki ISR koji je opet novo poglavlje mikroračunala, pa je i to jedan od razloga zašto je za početnike "teško" shvatiti rad TIMER-a i sve njegove mogućnosti.

Čitav trik u ovoj priči je podešavanje TIMER-a da broji impulse oscilatora. Kada ga tako konfiguriramo naš program je slobodan, i nigdje ne moramo čekati, dok TIMER u pozadini kao neovisan dio MCU-a bez obzira na naš program ima samo jedan zadatak -> "Broji impulse sa oscilatora!!!"

Ovim načinom konfiguracije TIMER-a dobivamo upravo ono što želimo, a to je da "netko" za nas broji vrijeme. Naš program kad god želi može pogledati u registar TIMER-a i sa sigurnošću će zaključiti koliko je vremena prošlo. U ovoj priči neosporna je i činjenica da TIMER nikada ne laže. Ne može kasniti, ne može žuriti iz razloga jer njega ne zanima naš program, nego samo impulsi glavnog oscilatora. Dakle, neovisan je našem programu, niti ga zanima što mi radimo u programu... Izvršava samo svoju svetu zadaću brojanja impusla sa oscilatora.

Ipak, ono što naš program mora napraviti je pokrenuti TIMER da broji, a da bi to napravili morati ćemo uvesti još nekoliko važnih pojmova u ovu priču.

Ponovno ću filtrirati mikrokontroler i obrisati sve ono za nas nepotrebno. Nadam se da se ATMEL ne ljuti zbog toga jer im olako brišem mogućnosti AVR-a:
Image

To Be Continued...
InTheStillOfTheNight
User avatar
InTheStillOfTheNight
Odlično uznapredovao
Odlično uznapredovao
Posts: 938
Joined: 01-06-2006, 17:54
Location: Zagreb

Re: U potrazi za tartufima AVR-a

Post by InTheStillOfTheNight »

"U potrazi za tartufima AVR-a" - TIMER (2-dio)

Sve konfiguracije koje radim ponavljam svaki puta iznova. Datasheet Timera do sada sam pročitao barem 50 puta. I danas podešavam TIMER, a to radim zbog potrage tartufa opet iznova otvaram isti datasheet. Bitno je znati da ovo ne učimo napamet. Ono što bi trebali naučiti je čitanje tehničke dokumentacije. Bitno je poznavati logiku kojom radi TIMER, i nakon toga je nevažno koji MCU uzeli jer ako znamo čitati dokumentaciju, te ako razumijemo kako radi brojač tog trenutka svi mikrokontoleri postaju identični upravo zato jer znamo kako im pristupiti.

dakle opet link na datasheet:
http://www.atmel.com/dyn/resources/prod ... oc2545.pdf

Odabrati ću TIMER/COUNTER 0 koji za nas u narednim postovima mora postati SAT i osloboditi nas mučnih DELAY naredbi..

Timer 0 nalazi se na stranici 89 ovog datasheeta, no preskočiti ćemo uvod i otići na stranicu 90, te malo se zadržati na block diagramu TIMER-a 0:
Image

Evo nekoliko pitanja i odgovora koje možemo zaključiti samo gledajući u block diagram...
Prvo moramo razdvojiti pojmove TIMER i COUNTER. Ovo nije samo TIMER, a isto tako nije niti COUNTER. U navici nam je da ga zovemo TIMER, ali zapravo je TIMER/COUNTER. Stvar je samo u načinu konfiguracije. Ako pogledamo desni gornji kut digrama vidjeti ćemo jedan block koji se zove "Clock Select".
Upravo on čini razliku između TIMER-a i COUNTER-a.
U "Clock Select"-u postoje 2 ulaza. Jedan je "From prescaler" a drugi je "Tn"

Što je "From Prescaler"?
Hardrerski implementiran Prescaler ili djeljitelj frekvencije radi upravo ono što i samo ime govori. Može djeliti frekvenciju oscilatora sa nekim brojem. Na ovoj slici nije nacrtan prescaler, ali sve što za sada o njemu moramo znati je da nam on dovodi impulse sa oscilatora. Ti impulsi koji dolaze na prescaler su točni, te neovisni o programu MCU-a. Pošto oscilator MCU-a uvijek oscilira na točnoj frekvenciji, onda su i ovi impulsi točni kao i oscilator. Kada TIMER/COUNTER konfiguriramo da broji impulse sa prescaler-a tj svog oscilatora onda se radi o TIMERU, a ne COUNTERU.

Što je "Tn"
Tn je PIN MCU-a, a služi kako bi mogli koristiti TIMER/COUNTER da nam broji vanjske impulse. Ovo može biti korisno ako trebamo brojati nekakve impulse, a ne želimo to raditi analizom signala te programom. TIMER/COUNTER za nas može brojati vanjske impulse a mi u programu samo moramo pročitati koliko je on impulsa nabrojao u nekom vremenu. Ako brojimo impulse sa PIN-a Mikrokontrolera onda se definitivno radi o COUNTERU, a ne TIMERU.

COUNTER nas ne zanima trenutno, jer mi želimo brojati impulse našeg oscilatora kako bi mogli pratiti vrijeme.

Od ostalih registara za sada nam je bitan "TCNTn". Taj registar je brojač, i u njemu se povećava vrijenost na svaki clock koje uđe u TIMER.

Ako malo bolje pogledamo naziv timer-a vidjeti ćemo da piše 8 Bit TIMER/COUNTER 0, a ovaj "8-Bit" govori o tome koliko BIT-ova ima TIMER. Ako ih ima 8, kao i sve u tom MCU onda on može brojati do 255, a nakon toga dogodi se overflow ili preljev te TIMER počinje ponovno brojati od "0".
Ovaj dio odrađuje "Control Logic" koji je vidljiv u diagramu.
"Control Logic" upravlja radom TIMER-a te se brine oko Gornje i Donje vrijednosti TIMER-a. U diagramu je vidljivo da postoji TOP i BOTTOM koji ulaze u "Control Logic", a isto tako vidimo da može brojati napred, brojati nazad, te resetirati brojač. Kako će TIMER raditi na kraju krajeva ipak odlučujemo mi.

Trenutno ćemo predpostaviti da konfiguriramo TIMER samo da broji napred tj. da se na svakom impulsu koji dođe sa oscilatora (iz prescalera/1) poveća za "1".

Da bi koristili TIMER moramo znati izračunati koliko brzo on broji:
Zamislimo situaciju da naš MCU radi na 8 Mhz, i također zamislimo da smo TIMER konfigurirali da broji impulse oscilatora. Malo se moramo pozabaviti proračunom i izračunati koliko TIMER-u treba vremena da dođe do vrijednosti 255, tj koliko mu treba vremena da napravi čitav krug (od 0 do 0)?
Prvo nas zanima koliko traje jedan pulse sa oscilatora: To računamo tako da koristimo dobro znanu formulu koja povezuje period i frekvenciju T=1/f.
Dakle "1" djelim sa 8 000 000 i dobivam 0,000 000 125 Sekundi. (clock je 8 Mhz)

TIMER zapravo ima 256 stanja, brojevi od (0-255) pa će jedan krug TIMER-a biti 256 impulsa, a ne 255.
Ako brojimo impulse 8 Mhz oscilatora onda će se naš TIMER povećavati svakih 0, 000 000 125 Sekundi, a ako se mora povećati 256 puta da bi napravio čitav krug i ponovno završio na broju "0" onda će proći točno
0, 000 000 125 * 256 = 0, 000 032 Sekundi.

Dakle naš timer će na frekvenciji 8Mhz napraviti čitav krug za 32 uS...
Jasno je da 32 uS nema nikakve veze sa realnim vremenom, no morali smo ovo računati kako bi znali izračunati vrijeme koje mi želimo.

U programiranju već dugo koristim identičnu metodu konfiguracije TIMER-a, i to radim odmah nakon što konfiguriram ulaze i izlaze MCU-a. Opet ponavljam kako uvijek krećemo od DDRC, DDRD i DDRB registara, a kad to napravimo odmag idemo na računanje vrijednosti TIMERA.

U svim mikrokontrolerima koje programiram uvijek konfiguriram TIMER da mi stvori vrijeme od 1mS, dakle 0.001S

Ovo mi je najbolje zato jer ako vrijeme 1mS pomnožim sa 1000 dobivam ravno jednu sekundu. Kada konfiguriramo TIMER vidjeti ćemo načine kako se od 1mS jednostavno napravi sekunda vremena.

U ovom proračunu koji sam pisao vidljivo je da će TIMER napraviti krug svakih 32 uS, a nama treba 1 mS, tako da ćemo morati ubaciti još nekoliko pojmova kako da nam TIMER napravi krug svakih 1 mS, a ne 32 uS

Daleko smo još od pisanja programa, jer najprije moramo znati što želimo, a da bi to napisali u programu treba nam sigurno nekoliko programskih linija i svega 5 minuta vremena.

To Be Continued...
InTheStillOfTheNight
User avatar
InTheStillOfTheNight
Odlično uznapredovao
Odlično uznapredovao
Posts: 938
Joined: 01-06-2006, 17:54
Location: Zagreb

Re: U potrazi za tartufima AVR-a

Post by InTheStillOfTheNight »

"U potrazi za tartufima AVR-a" - TIMER (3-dio)

Analizirajući gornji proračun TIMER-a na frekvenciji 8 Mhz zaključili smo kako 8 Bit-ni TIMER 0 napravi čitav krug za 0.000032 S ili 32 uS. No to nama nikako ne odgovara. Najbolje bi bilo kada bi on napravio krug za točno 1mS, ali kako to već biva "Murphy" često gura nos u elektroniku i programiranje.

Ako je jedan krug 32 uS lako je zaključiti da TIMER broji previše brzo. Nekako ga moramo usporiti, a ne želimo mjenjati naš 8 Mhz kristal oscilator. Upravo zato i postoji prescaler u AVR-u. On nam omogućava da ulaznu frekvenciju oscilatora podijelimo s nekim brojem.

Dakle opet link na datasheet (Page 138)
http://www.atmel.com/dyn/resources/prod ... oc2545.pdf
Image

Opet promatramo samo sliku te idemo od početka, a to je "clk I/O" koji se nalazi gore lijevo na block diagramu. CLK I/O uvijek je frekvencija oscilatora, pa ako koristimo kristal 8 Mhz za pokretanje MCU-a onda je CLK I/O točno 8 Mhz. Ono što prvo moramo znati je tekst za koji piše CK/8 CK/64 CK/256 i CK/1024.

TIMER 0 i TIMER 1 koriste zajednički prescaler, no to nas trenutno ne treba zanimati, nego prvo idemo izračunati sve frekvencije koje možemo izvući sa prescalera te ih koristiti za TIMER.
CK/8 = 8 Mhz / 8 = 1 Mhz
CK/64 = 8 Mhz / 64 = 125 khz
CK/256 = 8 Mhz / 256 = 31,250 khz
CK/1024 = 8 Mhz / 1024 = 7812,5 Hz


U prošlom postu sam računao vrijeme za krug TIMER-a kao da djelim 8 Mhz sa prescalerom 1, pa možda vam je nejasno zašto njega nema? Ima ga, naravno da ima, samo ne ide preko prescalera, nego ide odmah prema CS odabiru prescalera što je također vidljivo iz block diagrama.

Što mislite postoji li signal ove frekvencije na svim linijama koje smo računali u trenutku kada upalimo MCU? Odgovor je DA!

Broje li TIMERI po defaultu nakon palenja MCU-a ? Odgovor je NE, svi su zaustavljeni.

Zaključimo dakle kako prescaler odmah nakon palenja MCU-a na napajanje počinje generirati impulse ovih izračunatih frekvencija, a naš timer ipak stoji čvrsto na nuli. Razlog tome nalazi se opet na slici iste stranice 138 datasheet-a.

U ovoj priči tek sada dolazimo do onoga s čime možemo upravljati iz programa. Svi TIMER-i bilo kojeg AVR-a imaju registar imena TCCRx, ili ponekad više njih u slučaju da konfiguracija timera ne stane u jedan registar. Puni naziv AVR registra ili više njih je "Timer Counter Control Registar -TCCR". U jednom ili drugom registru ovog naziva upravo se nalazi odgovor kako pokrenuti TIMER. TCCR registar sigurno ima 3 BIT-A koji se zovu CS00, CS01 i CS02.

Vratiti ćemo se ponovno na istu sliku i pronaći CS na slici.
CS ili puni naziv "Clock Select" na TIMER prespaja signale sa prescalera. Upravljanjem CS bitovima registra mi biramo što želimo spojiti na TIMER, pa ako se malo bolje zagledamo u sliku skužiti ćemo da za za TIMER0 možemo odabrati ovo:

Frekvencija 8Mhz koja ide direktno gore sa CLK IO
Frekvencija CK/8 = 1Mhz
Frekvencija CK/64 = 125 khz
Frekvencija CK/256 = 31,250 khz
Frekvencija CK/1024 = 7812,5 Hz
T0 - Frekvencija za vanjskog pina MCU-a

Za TIMER 1 možemo odabrati identičnu stvar, samo ako brojimo vanjske impulse onda se radi o drugom PINU koji se zove T1, a ne T0.

To be continued...
InTheStillOfTheNight
User avatar
InTheStillOfTheNight
Odlično uznapredovao
Odlično uznapredovao
Posts: 938
Joined: 01-06-2006, 17:54
Location: Zagreb

Re: U potrazi za tartufima AVR-a

Post by InTheStillOfTheNight »

"U potrazi za tartufima AVR-a" - Opet na mukama početnika

Mislite li da je ovo stvarno?
Što je tu opipljivo, a što samo imaginacija?
Govorim li ja o programskom jeziku C?

Programski jezik C zadnji puta sam spomenu kada sam govorio o laganju i DELAY naredbama, davno prije dosta postova. Kao sad ja govorim tu o nekom programiranju, a uopče ništa ne programiram? Pisanje programa uopće nema veze o ovome što govorim. Govorim li ja o imaginaciji? Imaginacija nema veze o ovome što govorim. Što dakle? Ovo je onda valjda ta zadnja gornja solucija nazvana "Stvarnost".

Neki to zovu Hardware pa ćemo i mi reći da je to hardware mikrokontrolera. Što mislite o čemu razmišljamo @buco - assembler, @noćni - C i @kizo - Bascom??? Razmišljamo li mi o linijama programa? Neee. Svi programeri bez obzira u kojem programskom jeziku pisali razmišljaju samo o jednoj te istoj stvari. HARDWARE MCU-a. Sve ovo o čemu pišem postoji u mikrokontoleru, doduše sitno, ali postoji.

Ponekad naletim na početnike koji mislie da je TIMER pojam kao recimo WINDOWS... TIMER nije pojam, on je stvaran kao i obični otpornik ili kondenzator. Moji zadnji postovi o TIMER-u nemaju nikakve veze sa programiranjem u C-u, programiranjem u BASCOM-u, Pascalu ili assembleru...

Kako onda kizo iz BASCOMA konfigurira TIMER??? Pa isto kao i ja jako dobro zna što je prescaler, što je CS, ali nekom BASCOM metodom napiše nešto tipa "CONFIG TIMER 0 As NEKI VRAG"

Kako buco konfigurira TIMER? Pa isto kao i ja, zna točno sve o čemu pišem i samo napiše assemblerske instrukcije koje podese registre TIMER-a

Kako ja konfiguriram TIMER? Pa isto kao i Buco i Kizo, samo iz C-a upišem u registre TIMER-a konfiguraciju kakvu želim.

Ono što želim reći je da svaki programer bez obzira u čemu programirao mora znati kako radi Hardware TIMER-a, a sada kako izgleda samo pisanje programa nas uopće ne interesira... Ne postoji niti jedan programski jezik u kojemu možemo programirati, a da ovo o čemu pišem ne znamo...

Svaki početnik trebao bi znati da ja ne govorim o C-u, Bascomu niti assembleru. Ja govorim trenutno o mikrokontroleru, o hardware-u a ne software-u, pa i ako mislite da ste dobri u recimo BASCOMU zapitajte se koliko znate o samom mikroračunalu kojeg programirate... Iz bascoma vrlo lako možemo programirati i nekoliko godina, a da uopće ne znamo s kakvim računalom radimo. Možemo živjeti u takvoj zabludi da mislimo kako postoji samo DELAY, FLASH i RAM, a sve ostalo što i je čudo tehnologije vrlo lako nam klizne pokraj očiju, i onda kao sljepac tapkamo u mraku misleći da smo programeri.

To be continued...
InTheStillOfTheNight
User avatar
InTheStillOfTheNight
Odlično uznapredovao
Odlično uznapredovao
Posts: 938
Joined: 01-06-2006, 17:54
Location: Zagreb

Re: U potrazi za tartufima AVR-a

Post by InTheStillOfTheNight »

"U potrazi za tartufima AVR-a" - TIMER (4-dio)

Do sada bi svakako trebali znati da TIMER broji isključivo impulse sa Prescalera ili vanjskog pina, isto tako moramo znati da prescaler uvijek i samo uvijek djeli frekvenciju sa "main" clocka.

Ovom pričom svakako zaobilazim jednu bitnu stvar AVR hardware-a imena FUSE. Uzeo sam zdravo za gotovo kako je AVR FUSE konfiguriran za "External Crystal Oscillator", te kako ga pogonim sa 8Mhz kristalom. AVR mikroračunala imaju implementiran i interni oscilator, pa ukoliko pogonimo MCU sa internog oscilatora moramo znati točnu frekvenciju rada kako bi mogli računati postavke TIMER-a. Princip računanja je identičan.
Evo primjer za 4 Mhz vanjski kristal osilator, te krug TIMER-a 0 na prescaleru / 1
Djelim frekvenciju sa prescalerom 1 i dobijem istu frekvenciju 4 Mhz.
Računam periodu te frekvencije po "t[s]=1/f[Hz]" formuli i dobijem 1/4000000 = 0,00000025 Sekundi
Množim vrijeme jednog impulsa sa 256 kako bi mi TIMER napravio puni krug:
0.00000025*256 = 0.000064S
Dakle na 4 Mhz kristal oscilatoru 8 Bitni TIMER će napraviti jedan krug za 64 uS.

Iz ovog proračuna lako je zaključiti da smo smanjivanjem frekvencije MCU-a sa 8 Mhz na 4 Mhz upravo povećali vrijeme jednog kruga TIMER-a sa 32uS na 64 uS. Zdravo seljački rečeno: duplo smanji brzinu mikroračunala i TIMERU treba duplo više vremena da nabroji čitav krug.

Ponovno se vraćam na cilj konfiguracije TIMER-a 0 te 8 Mhz oscilatoru i svakako cilju konfiguracije TIMER-a da napravi krug svake 1 mS.
Zaključili smo kako prescaler /1 (8 Mhz) pogoni TIMER prevelikom brzinom, pa ću ponovno napraviti PASTE frekvencija sa Prescalera, te pokušati pronaći neku frekvenciju koja mi najviše odgovara:

1. CK/1 = 8 Mhz / 1 = 8 Mhz -> Jedan krug 8 Bitnog TIMER-a: 32 uS
2. CK/8 = 8 Mhz / 8 = 1 Mhz
3. CK/64 = 8 Mhz / 64 = 125 khz
4. CK/256 = 8 Mhz / 256 = 31,250 khz
5. CK/1024 = 8 Mhz / 1024 = 7812,5 Hz

Računam za stavu "2" krug TIMER-a (1 Mhz):
Frekvenciju 8 Mhz dijelim sa prescalerom / 8 i dobivam frekvenciju 1 Mhz koju odabirem za pokretanje TIMER-a. Računam period 1 Mhz frekvencije formulom T=1/f i dobivam 1/1000000 = 0.000001 Sekundi
Množim vrijeme jednog impulsa sa 256 kako bi mi TIMER napravio puni krug:
0.000001 * 256 = 0.000256 S
Sad samo pogledam rezultat i vidim da je i ovo previše brzo. Timer će napraviti krug za 256 uS, a ja baš želim 1 mS. Svakako moram uzeti sljedeći prescaler i ponovno računati istu stvar za njega.

Računam za stavu "3" krug TIMER-a (125 khz):
Frekvenciju 8 Mhz dijelim sa prescalerom / 64 i dobivam frekvenciju 125 khz koju odabirem za pokretanje TIMER-a. Računam period 125 khz frekvencije formulom T=1/f i dobivam 1/125000 = 0.000008 Sekundi
Množim vrijeme jednog impulsa sa 256 kako bi mi TIMER napravio puni krug:
0.000008 * 256 = 0.002048 S

Upornog li TIMER-a, baš vraga ne možeš natjerati da napravi puni krug za 1 mS. :azdaja:
Čitavo vrijeme vam govorim kako podešavamo TIMER na 1mS puni krug, ali ipak znam da je to nemoguće bez mjenjanja kristal oscilatora.

Ružno je reći da sam lagao, prikladiji izraz je: Namjerno nisam rekao istinu:
Zapravo sam tražio samo vrijeme koje je veće od 1mS. Na frekvenciji 125 khz naš TIMER će napraviti krug svakih 2,048 mS i kada nađemo prvi prescaler koji je veći od 1 mS onda je to sigurno prescaler koji koristimo. Naš program morati će podesiti Hardware TIMER-a 0 na prescaler CK/64.
Naša konfiguracija slikovito se može prikazati ovako:
Image

Fora je u tome što TIMER-u možemo smanjiti krug, ali ga ne možemo povećati jer krov timera ili TOP vrijednost je MAX 255 (8 Bitni TIMER). Taj krov je hardwerski maksimalna vrijednost i nikako ne može biti veća. U daljnjoj konfiguraciji TIMER-a moramo znati da TIMER ne mora brojati do 255. Postoji mogućnost da mu mi kažemo točan broj do kojeg on broji, samo mora biti manji od 256. Ako možemo smanjivati gornju vrijednost TIMER-a jednostavno je zaključiti da smanjivanjem gornje vrijednosti TIMER-a mi smanjujemo i vrijeme jednog kruga. Ako TIMER 0 napravi krug na nešto više od 2 mS, sve što mi moramo napraviti je natjerati TIMER da ne pravi čitav krug nego recimo pola kruga.

To be continued...
InTheStillOfTheNight
User avatar
InTheStillOfTheNight
Odlično uznapredovao
Odlično uznapredovao
Posts: 938
Joined: 01-06-2006, 17:54
Location: Zagreb

Re: U potrazi za tartufima AVR-a

Post by InTheStillOfTheNight »

"U potrazi za tartufima AVR-a" - TIMER (5-dio)

Zamislimo da želimo napraviti SAT kojemu je Tick svakih 100mS a ne 1 ms??? Što onda radimo?
Identičnu stvar. Pogledamo kolika je frekvencija oscilatora, te krenemo računati prescalere. Kad najdemo prvi prescaler koji za krug timera ima vrijeme veće od 100 mS upravo smo izračunali prvi dio posla...

Opet se vraćam svojoj 1 mS, te onome što smo do sad mogli zaključiti. Računajući prescalere sa 8 Mhz kristala došli smo do onoga koji nama treba. Dakle CK/64 prescaler će sigurno napraviti krug Timera za 2.048 mS.

Kada sam opisivao prescaler spomenuo sam da on ima 3 bita imena CS0 CS1 CS2.
Ono što ja prvo tražim u datasheetu je tablica prescalera. Atmelov datasheet pisan mi je na jako razumljiv način. I kada pronađem tablicu prescalera, znam da mi odmah iznad te stranice mora biti REGISTER te lokacija vezanih Bitova.

Dakle opet link na datasheet (Page 105)
http://www.atmel.com/dyn/resources/prod ... oc2545.pdf
Image

U tablici je jasno vidljivo da ona povezuje stanje CS bitova i prescaler Timera 0, pa onda samo pronađemo onaj koji želimo koristiti: "clkI/O/64 (from prescaler)"
CS02 = 0
CS01 = 1
CS00 = 1


Ako ovako postavimo "CS" ili "Clock Select" bitove za Timer 0 onda moramo znati da će TIMER odmah početi brojati sa frekvencije 125 khz te će napraviti krug svakih 2.048mS

Odemo na stranicu 104 datasheta i evo naš registar koji sadrži bitove CS
Image

Bez obrira na programski jezik u kojemu programiramo mi na prvi i drugi desni BIT, dakle CS00 i CS01 moramo upisati logičku jedinicu kako bi pokrenuli TIMER sa željenog prescalera "/64"

Još jednu stvar moram napomenuti a to je razlika između CS00,CS01,CS02,CS10,CS11,CS12,CS20,CS21,CS22 ????
Odkud ih sad toliko???
Budete li kopali po datasheetu sigurno možete pronaći baš toliko CS bitova... Zašto toliko?
Zato jer imamo 3 TIMER-a,
Evo CS od TIMER-a 0: CS00, CS01, CS02 -> TCCR0B register
Evo CS od TIMER-a 1: CS10, CS11, CS12 -> TCCR1B register
Evo CS od TIMER-a 2: CS20, CS21, CS22 -> TCCR2B register

Dakle, samo ukazujem da ne smijemo mješati kruške i jabuke. Ako smo počeli podešavati TIMER 0, onda obavezno moramo pronaći sve točne tablice i diagrame za TIMER 0.

Sad se možda pitate kako to izgleda u programskom jeziku C?
Podizanjem CS00 i CS01 bitova samo pokrećemo TIMER i to je 30% onoga što moramo napraviti da bi stvorili taj sat koji broji vrijeme za nas umjesto DELAY naredbe...

Code: Select all

#include <avr\io.h>
																
int main(void){
												
	TCCR0B |= (1<<CS00) | (1<<CS01);	
	
	while(1);									
}
To be continued...
InTheStillOfTheNight
Post Reply