programiranje u assembleru

Upload: eldin-marizela-mujagic

Post on 18-Jul-2015

927 views

Category:

Documents


6 download

TRANSCRIPT

Programiranje u AssembleruUvod: Pokuati u ispriati priu o tom zanimljivom nainu programiranja iz kuta kako sam ga ja doivio i kako ja gledam na njega. Ovo nee biti prepisivanje iz neke knjige ili sa raznih stranica na internetu. Tko eli moe uvjek proitati veoma zanimljivu knjigu "Art of programming". Sve one koji poznaju taj jezik, moda i nije pravi izraz, neka se ukljue svojim komentarima i primjedbama te pomognu da se dobije to kvalitetniji uvod u taj nain programiranja. Obino, kad se pogleda ak i najjednostavniji niz naredbi koji ine neku smislenu cjelinu u assembleru, veina tad pomisli kako je to strano kompicirano i potpuno nerazumljivo u usporedbi sa naredbama u viim programskim jezicima. Tu obino i prestaje bilo kakvo zanimanje za taj,raunalu najblii, nain programiranja. Code: Select allavr0014: ldi rcall lsr dec brne ret r17, 0xCB avr002A r18 r16 avr000F

Code: Select allint uart_getc(void) { if (bit_is_set(UCSRA, RXC) == 0) return -1; return UDR; }

Gornji primjeri moda nisu najbolji no pozluit e da se vidi ta razlika. Vjerujem da je i laiku jasno koja je rutina pisana u asembleru. Krenimo na upoznavanje s assemblerom, zapravo onim to bi bilo dobro da razumijemo prije nego se upustimo u izradu programa tim jezikom (kako nevolim taj izraz). To je najjednostavniji jezik. Zapravo i nije jezik, vie je jednostavna matrica koja text prevodi u narebe razumljive raunalu, objektni kod. Njegova sintaksa je jednostavna i moe se pisati u bilo kojem programu za obradu teksta. Assembler (sastavlja) je u principu jednostavno i napisat, pod uvjetom da imamo naredbe objektnog koda za dati stroj. Moderni asembleri su kompleksniji i omoguuju upotrebu makro naredbi kao i ukljuivanje koda drugih programa pisanih u asembleru, objektnom kodu, itd... Najee ih nazivju Macroassemblerima. Za rad u assembleru potrebno je poznavati raunalo, procesor... ,njegovu internu arhitekturu, za kojeg piemo program. To je kljuno za ak i za jednostavne programe.

Malo o raunalu: Vjerujem da mnogi od vas poznaju osnove raunala. Postoji i vrlo kvalitetna literatura. Raunalo je u svojoj osnovi prost stroj. Iako mnogi nemisle tako, no to je zbog nepoznavanja naina njegova rada. Za programera u asembleru je vano da zna broj radnih registara, veliinu, dubinu i tip stoga, adresni prostor prg. mem., naine adresiranja, veliinu rama, strukturu naredbi,broj ciklusa izvrenja naredbe, trajanje uzmi/izvri ciklusa, broj prekida, prekidni vektor, internu sabirnicu, vanjsku sabirnicu... Ima toga puno. Mikroraunalo: Poto emo obradit programiranje u assembleru za 8 bitno mikroraunalo Harvardskog tipa i to MCU (mikrokontroler) serije AVR/Mega moramo znati da je dubina programske memorije, memorije podataka i rama zadana samim HW-om. Kod rama postoji mogunost ogranienog proirenja na utrb nekih drugih funkcija, no otom -potom. Veliina polja registara najee je proirena na ram. No skup radnih regstara koji neposredno sudjeluju u operaciji a ALU-om (arihmetio-logika jedinica) je fiksan i on ovisi o tipu jezgre (processoru). Npr PIC 16xxx serija ima klasinu akumulatorski orijentiranu jezgru. Sve operacije s ALU, ali ne s samo s njom, se odvijaju preko jednog registra (akumulatora - W). AVR/Mega jezgre imaju moderniju arhitekturu i rade s 32 registra no 16 rade sve operacije s tim da tri para registara mogu radit u 16 bitnom modu. Tu je i polje tkzv. registara specijane namjene koje je dio RAM-a. O detaljima kasnije. Obje serije imaju tkzv. RISC klasu procesora, reducirani skup naredbi. Bez brige, ak i tako moete odratit sve to poelite. Dali RISC ili CISC - kompleksni skup naredbi,nije na kraju toliko bitno. Poto je to MCU on u svojoj arhitekturi ima na internu sabirnicu spojene i HW sklopove: ADC, komunikacione sklopove (hardverski implemet njihovih protokola i registre za njihovu kontrolu i razmjenu podataka) itd... irok je spektar onoga to je postavljeno u ta mala raunala. Tu su jo i nezaobilazni konfiguracijski registri koji predefiniraju modalitete rada i ponaanja MCU-a. Mislim da je to dovoljno za uvod. Poetak upoznavanja sa programiranjem u asembleru. P.S. Bude li zainteresiranih za tu temu nastavit u zapoetu priu. Molim vas da za komentare i kritike piete u nekom drugom topic-u. Prije nego odemo pojanjavat vezu arhitekture mikroraunala i asemblera nebi bilo loe da raistimo jednu veoma vanu stvar a to je pojam vremena. ovijek, kao ivo bie a ne kronometar, vrijeme doivljava i proivljava pa mu je ono, koliko god satovi bili toni, promjenjivo. Ne traje nam sekunda, minuta, sat... uvijek isto. Vjerujem da se veina zapitala koliko zaista traje milisekunda. Dok nisam poeo pisat programe u assembleru osjeaj vremena je stalno "klizio iz ruku". to hou rei, uei assembler osjeaj vremena postaje stvarniji. Ne samo da razumijete

"uasno spore" mili sekunde ve i prilino duge delaye od 100 microS. Sekunde da ni ne spominjem. A sa mikrosekunadama i nano sekundama ste na ti i sve bolje razumijete vrijeme. Bez toga bi rad u assembleru bio gotovo nemogu. Imali bi velikih problema. Kompjuteru je vremenska baza jako vana stvar. Vidjeli ste esto, u raznim alatima za pisanje programa u viim programskim jezicima, kako vas uredno pitaju da im navedete frekvenciju oscilatora. Bez toga bi izraunati delayi bili potpuno krivi i va program bi u najbolju ruku "tekao". U assembleru nema tko raunati delaye za vas (ima nekih programa kao AVR kalkulator no bilo bi dobro da ga ne koristite jer on ionako rauna samo vrijednosti za timere, dali obini dali PWM mod). Znai najprije treba vidjeti koja je vremenska baza takt oscilatora processora. Oscilatoru od 1 MHz takt je 1 microS (to znamo). No to je tek poetak. Da bi nam taj podatak iemu sluio moramo znati koliko takt impulsa koristi bazina operacija jezgre raunala a to je uzmi/izvri, koja se jo naziva i ciklus. Jezgre AVR/Mega imaju jednotaktni uzmi/izvri ili ti ciklus. Jezgre PIC16xxx serije) imaju 4 taktni ciklus. Znai da e AVR/Mega jezgra 4 x bre odraditi ciklus od PIC-a za istu brzinu takt oscilatora. Nije to naravno kraj prie o vremenu. Sa gore navedenim podacima ete se susretati kod izrauna vrijednosti za HW-ski implementirane timere (bilo koji mod), no za emulirane delaye, kad nemate dovoljno timera ili nesmijete iz nekog razloga postavljati prekid u aktivni mod, ili vam, kad zbrojite kanjenje rutine, ispadne da je bre emulirati nego setirati timere, itd... tada ete kao podlogu za izraun vrijednosti delaya morati koristiti neto drugo. To neto je vrijeme izvrenja instrukcije. Zvui komplicirano? Videjti ete da nije ako se samo malo potrudite razumjeti. U svim dokumentima o processorima, mikroraunalima itd... jedna od vanih stvari jest i tablica naredbi. Uredno poredane po funkciji ili abecednom redu ekaju da ih koristite. Jedna stvar vam nikako nebi smjela promaknuti, vrijeme izvrenja naredbe. Uz svaku naredbu, osim njenog opisa, stoji i koliki broj ciklusa traje. Sad vam je, nadam se, jasno emu je gornji dio teksta sluio. Veina naredbi AVR/Mega jezgre traje izmeu 1 najvie 2 ciklusa. Opracije dugog granjana, indirektnog skoka u rutinu ili poziva na istu 3-4 ciklusa, rijetko koja due. Najvei broj naredbi traje jedan ciklus kao i kod PIC16xxx serije. E sad smo napokon doli do korisnog podatka za izraun utroenog vremena mikroraunala za odreenu rutinu. Jel vas to podsjea na delay? Nije tu u pitanju samo kanjenje ve puno vanije stvari, a to su vremenski kritine operacije. Programi, ee rutine, koji se moraju izvriti u tono odreeneom vremenu. Mikroraunalo je ogranieno, arhitekturom, maximalnom freq -> taktom, vremenom trajanja ciklusa... da bi te ogranienosti izbjegli, ako je ikako mogue, poznavanje vremena izvreenja naredbe pomoi e vam da vidite to e proi a to nee i da koristite one naredbe koje e maksimalno utedjeti na vremenu, ili to je puno bolje razmislite o nainu postavljanja problema na drugi nain. Primjer naredbi i ciklusa: AVR/Mega jezgre: ldi r17, 1 (neposredno punjenje registra) --> ldi = 1 ciklus ==> 1 x

(uzmi/izvri x 1 takt). PIC 16Fxx jezgra: movlw 8 (neposredno punjenje acc) --> movlw = 1 ciklus ==> 1 x (uzmi/izvri x 4 takta). AVR/Mega je 4x bra za isti generator takta. Vrijeme trajanja ciklusa je na 1MHz = 1 microS kod PIC16xxx je 4 mikroS. Eto, na kraju se vraamo na poetak, frekvenciju, no, nadam se, s jasnijom predodbom kako funkcionira vrijeme u naem raunalu. Ve kad smo kod vremena da spomenemo taj pojam: MIPS s kojim ete se susretati u dokumentacijama raunala (nemislim na poznatog proizvoaa prosessora). Nastao je puno ranije i oznaava broj miliona instrukcija u sekundi. AVR/Mega na freq 1 MHz moe maksimalno da "vozi" 1 MIPS, PIC16xxx seiji za istu brzinu izvoenja operacija treba 4MHz. To su idealne veliine i u praksi su neto manje. Nebih elio da me ljubitelji PIC16xxx serije krivo razumiju, jer nemislim da je zbog gore navedenih podataka ta serija MCU-a manje vrijedna. Svako mikroraunalo, ako je pravilno koriteno za ono to realno moe njegov HW, je dobro. Najee problem predstavljaju programeri. Moda ova pria o assembleru pomogne da se pojasni vanost poznavanja detalja rada mikroraunala i okoline za koju program piemo. Arhitektura mikroracunala. Ni u ovom dijelu price necemo obradivati detalje kompletne arhitekture pojedinih serija mikroracunala. Nije cilj ovog dijela da C/P-a bilo ciju tehnicku dokumentaciju vec da pokua proniknuti u tajnu veze izmedu svijeta hardwera i softwera, a jedna od najneposrednijih veza jest asembler. Taj nacin programiranja je zaista specifican a to se ogleda i na vezi imedu naredbi i strukture samog mikroracunala za kojeg piemo program. Poto obradujemo mikroracunalo a ne procesor kao poseban sklop tako je i assembler za mikroracunalo kompleksniji i osebujniji proporcionalno kompleksnosti samog hardwera mirkoracunala od onoga to je sama jezgra. Naredbe asemblera prilagodene su samoj arhitekturi tog malog "cuda". Primjer: Primjetili ste kako ja odvajam seriju AVR od ATMega serije iako u tehnickoj dokumentaciji i deklaraciji proizvodaca jasno trpaju ATmega mikroracunalo kao AVR strukturu. U cemu je problem? Razlika. Naizgled je nema, vodi se Mega jezgra kao AVR, jasno i nedvosmisleno. No... Ima jedna naredba koja je dodana AVR jezgri kakvu imaju AT90Sxxxx... ta serija. Ta naredba se zove SPM. Netko ce reci pa to je tu toliko strano. Jedna naredba pa to? U raznih proizvodjatja u istoj seriji znaju varirati pokoje naredbe. Za programera u asembleru, ali i drugim jezicima SPM naredba nije samo promjena u mikrpoprogramskom slijedniku, memoriji, a djelomicno i u samoj arhitekturi jezgre, vec i u nacinu na koji moete postavti va program globalno. Ta je naredba donijela potpuno nove momente u tu seriju. Pitate se zato? Ne samo da ona omogucava samoprogramiranje (SPM --> Self Programming Mode) vec je, zbog promjene na arhitektuiri jezgre mirkroracunala omoguceno da napiete bootloader, premjestite prekidne vektore u njega,

a tu su promjene i na konfiguracijskim registrima,itd... PIC16Fxxx seija zanimljive je arhitekture i zanimljivih rijeenja. Ona nema naredbu slicnu SPM no omogucava primjenom odredenog algoritma, prisanjem posebne rutine, samoprogramiranje. No za razliku od ATMega serije ne prati je sva ona podrka u HW-skoj strukturi koja omogucuje kreiranje bootloader sektora, promjenu pozicije (pocetnu adresu) prekidnog vektora, nacin pristupa zaticenoj zoni bootloadea, itd... Naravno, moemo se posluiti "virtualnom" kreiranju zone bootloadera u PIC16Fxxx seriji. Nadam se da vam je ovaj primjer pomogao da vidite kako naizgled "nevana" promjena, jedna dodana naredba, zapravo znaci i promjenu u strukturi jezgre, vecu ili manju, a to omogucava vanu promjenu u samom programiranju mikroracunala tj. strukture i rijeenja samog programa. Da se vratimo arhitekturi. Na internu sabirnicu mikroracunala vezana je sama jezgra: akumulator( kod PIC16xxx), zona radnih registara (AVR/Mega), SRAM (Staticki RAM; koji je, najcece, i polje radnih registara, stog i polje registara spec. namijene), PC (programski brojac), adresni brojac (srama, stoga..) Mikroprogramska memorija. Programska memorija kao i memorija podataka naizgled pripadaju samoj jezgri no nisu ba dio nje. Znam, neki ce prigovoriti da se slicno moe reci i za SRAM no poto je dio SRAM-a predefiniran kao zona radnih registara(AVR/Mega serija) postavio sam ga kao dio jezgre. Opet da kaem o tome se uvijek moe popriati. PIC16xxxx serija ima akumulator kao radni registar i poseban stog (dubina je 8 x 12-14bita). Ovo nam govori kako je osnova njegove arhitekture neto starija, tipski. U SRAMU je smjetena zona registara speijalne namijene. Serije se razlikuju, zbog specificnosti arhitekture, i u nacinu sada s adresni brojacem (kako programskim tako i rama). AVR/Mega serija, njen adresni brojac rama, kao i indeksni brojaci, imaju neposredan pristup cijeloj velicini SRAM-a. Kod PIC16xxxx serije brojac srama je 7 bitni + bitovi RP0 i RP1 koji su dio SFR-a (specijalnog registra funkcija) i cine tkzv. adresu bloka. Ima tu jo detalja za izracum pozicija srama po blokovima. No to su zaista detalji. U indeksno adresiranje neemo ulaziti. Bar ne za sad. Primjer citanja podatka s adrese 0x0110: Code: Select all- u PIC16F877: BCF STATUS,RP0 BSF STATUS,RP1 MOVF 0x10, W akumulatoru ; definiramo blok RP0=0 RP1=2 ==> blok 2 ; procitani podatak s adrese rama 0x0110 je u

- u ATm8: lds r17, 0x0110 ; proitani podatak s adrese 0x0110 je u radnom registru (jednom od 16)

Ta razlicitost u arhitekturi jezgri ima svoju neposredu refleksiju na naredbe u asembleru i nacin upravljanja adresnim brojaem rama. Kod AVR/Mega on je "lineran" dok je kod PIC16xxx serije, kao to vidite, predodreden adresom bloka (ne ulazeci u detalje). Slino je i kod programske memorije. AVR/Mega imaju za veinu ipova neblokovsko

adresiranje (linearno) do 64KB (tj. 32KW) dok PIC16xxx serija ima podijeljenu programsku memoriju u manje blokove (stranice od 2KB, npr. 16F877). U Mega seriji na MCU-u ATMega128 (ili ATmega104) gornjih 64kB se definira statusom RAMPZ bita. Primjer za PIC16F877 iitavanje podatka iz programske memorije u zoni --> org 018fc: -- rutina za itanje ID-a memorije (podatka) iz baze podataka u programskoj memoriji Code: Select all

RDID MOVF 0x38,W ; u registru 0x38 nalazi se vrijednost adrese za PCL ( nii byte adrese). BSF PCLATH,3h ; postavljamo adresu zadnjeg bloka (page-a) programske memorije BSF PCLATH,4h CALL IDVAL ; pozivamo rutinu koja isitava podatak iz baza ID-a memorija programatora BCF PCLATH,4h ; vraamo se nazad u prvi blok programske memorije BCF PCLATH,3h . . ORG 018FC ; IDVAL BCF PCLATH,2h ; postavljamo poetne parametre 11 bitnog adresnog brojaa --> 2K blok BCF PCLATH,1h BSF PCLATH,0h ; nia 3 od 5 PCLATH bita MOVWF PCL ; adresa u bloku je ==> 3 nia PCLATH bita + 8 bita PCL-a. RETLW 0xC2 ; podatak, jedan od, iz tabele. RETLW 0x00 RETLW 0x00 RETLW 0x00 .

Primjer za ATMega8: Code: Select all

ldi ZH, 0x08 ; itamo podatak iz zone programske memorije na adresi 0x0800 ldi ZL, 0x00 ; postavljamo u indeksne brojae ZH, ZL adresu lpm ; itamo podatak iz programske memorije sa eljene adrese / rezultat je u r0

I na ovom primjeru vidite koliko arhitekura mikroraunala utjee na strukturu i tip naredbi asemblera. A to znai i samo dizaniranje programskih rutina. Ostaje nam jo ono zbog cega je mikrokontroler (MCU), to malo mikroracunalo, specificno. HW-ski I/O (Ulazno/izlani) sklopovi dodani na samu sabirnicu cine ga posebnim. Taj dio cine I/O portovi (vrata) a poto je to MCU-a tu su i I/O spec namjene. Razni komunikacioni inteface-i(sucelja), ADC-i, Timeri, PWM, Analogni komparatori, itd... Zbog tih sklopova asembler je zaista specifican svakoj seriji. Svakako da nije to jedini razlog posebnosti asemblera od serije do serije, vec je to i zbog same arhitekture jezgre, a koji put i zbog samog naziva naredbe/i.

Primjer razlike u nazivima istih naredbi (gledano u grubo): Code: Select allldi sts

r16, 5 ; neposredno punjenje radnog registra AVR/Mega 0x61, r16 ; upii registar u SRAM, lokacija 61h ; neposredno punjenje akumulatora PIC16xxx serije ; upii sadraj registra u sram lokacija 61h

movlw 5 movwf 0x61

U oba slucaja se radi o funkcionalno istoj rutini. Istina je da te dvije naredbe (sts i movwf) nisu ba iste u potpunosti. Vano je podsjetiti da se osim HW-skih implemenata za pojedine operacije emulacijom odreenih protokola, pisanjem drivera i sl. mogu dodavati nove mogunosti mikroraunalu. Jedan od primjera za to moe biti i emulacija USART protokola a ne koritenje njegovog HWskog implementa koji esto zna biti ograniavajui faktor u upotrebi oscilatora takta kojeg elite ili s istim nemoete ostvariti sve brzine prijenosa standardne, i nestandardne, za taj komunikacioni protokol. U nastavku emo se okrenuti i tom dijelu prie. Vjerojatno ste se pitali drei u rukama mikroraunalo kako napisati program za njega, koji nain programiranja je najbolji i slina pitanja. Ljudi mnoge stvari pokuavaju napraviti tako da one budu njima to razumljivije, jednostavnije za koritenje pa tako i pisanje programa za raunalo. Od samih poetaka smiljao se nain kako premostiti jaz izmeu onoga to raunalo zaista "razumije" i eljom za stvaranjem jezika koji e biti blizak ljudima. Vrlo brzo je stvoren simboliki jezik, najjednostavniji nain programiranja koji nije objektni kod (pisanje naredbi u hexadecimalnom sustavu) a opet je razumljiv ovijeku, assembler. Nije se tu stalo pa su "izmiljeni" (mislim da je to jedini pravi izraz) brojni vii programski jezici (HPL). Jezici koji su daleko blii ovijeku no imaju jednu manu, programer dri kontrolu nad programom dok radi sa samim alatom a im stisne "tipku" : compile, make... kontrolu preuzima program prevodilac. Assembler nema taj problem zbog same prirode tog naina programiranja. Mnogi programeri u HPL-u e rei kako je njihov kod prenosiv. Istina, no najvei broj njih ili nezna ili, najee, ne eli znati koja je cijena "prenosivosti". Ako se tome pridoda da se veina programa prenosi unutar porodice mikroraunala za koju je kod pisan tad stvar postaje jo ozbiljnija. esta pria, koju sam sluao, kako je program pisan u assembleru teko prenosiv je samo polovino tona a u praksi veoma rijetka. Mislim da netreba previe pojanjavati. No, za one koji misle da treba, esto se programi za mikroraunala ne prenose s jedne potpuno razliite porodice na drugu; PIC16xxx na ATmegu, ST710 ili obrnuto. Pogotovo je to jasno kod mikroraunala specijalne namjene. Poto je ova pria o assembleru vezana na mala osam bitna mikroraunala, MCU-e to je razlog da popriamo o programiranju u asembleru vei. Neemo se bavit paljenjem "lampica", to programeru u assembleru nebi trebao predstavljat problem ve iz same filozofije tog naina programiranja. Prvi zadatak je upoznati se sa tehnikom dokumentacijom mikroraunala s kojim elimo raditi (i njegovom porodicom).

Znam i vidim da su mnogi nestrpljivi kad kupe ili dobiju mikrokontroler i prvo to naprave nije itanje tehnike dokumentacije ve etanje po razno-raznim boardima i pokuaj da neto naprave a da pritom uope neznaju to je to raunalo, kako to radi itd... No to je njihov problem. Poto smo odluili da emo se upoznati s assemblerom za porodicu AVR/Mega drati emo se njenog hardwera. Znai prvi korak je upoznavanje s arhitekturom mikroraunala iz te porodice. U ranijim tekstovima upoznali smo se djelomino s temeljem te arhitekture no kroz kasniji tekst i primjere upoznati emo se sa realnim strojem. Iz dokumentacije je jasno da je jezgra raunalo Harwardskog tipa, to je reeno jo na poetku, a to znai da imamo jasno odvojenu programsku memoriju od memorije podataka. Dodaci u macroassembleru kao .db (niz jednobaytnih podataka) .dw (niz 16bitnih podataka u intel hex formatu --> reversni) koji oznaavaju podatke kao i naredba lpm (Load Program Memeory --> isitavanje iz programske memorije ) samo potvruju strogu odijeljenost podataka od naredbi. Takav tip raunala nam dosta olakava posao oko programiranja. Primjeri: Code: Select all

.dw 0x773F, 0x2518, 0x8000, 0x0014, 0x6854 .db 0x84,"SLOT ",0x85,"FREQ ",0x86,"U MODE "

Polje rama kao i EEPROM-a, su iskljuivo vezani na uvanje podataka. Pisanjem algoritama za samoprogramiranje i te se memorije mogu pretvoriti u neku vrst memorije za trajno ili privremeno uvanje programa. Moda se pitate moe li assembler da bude modularni kao i vii programski jezici. Odgovor je moe! To potvruje najee prva nareba, ne samo macroassemblera,: .include "Xxxxdef.inc". U module mogu biti ukljuene i definicije kao i asm. programi,itd... No poanta pisanja programa u assembleru nije modularnost kao prioritet ve efikasnost. Na kraju krajeva sve te definicije ili module moete ukljuiti u svoj program obinim kopiranjem, C/P. Najvea vrijednost assemblera je u tome (po meni) to moete veoma precizno i jednostavno upravljati strukturom programa, rutinama, registrima, poljem rama, kompletnim HW-rom mikroraunala kao i njegovim okruenjem. Svim onim to e omoguiti da va program bude jednostavniji, bri, efikacniji... U svakom trenutku tono znate kako bi trebao sustav reagirati na naredbu, u kom pravcu e se odvijati va program u svakoj toki. U HPL-ima to je apsolutno nemogue bez disasembliranja i analize programa (reininjeringa). Nikakvi simulatori nee dati tonu sliku stanja onoga to se zaista odvija u kompiliranom objektnom kodu. Da ne spominjemo prekomjernu upotrebu stoga i ve znanu priu oko koritenja radnih registara (push / pop naredbe). Tu su i tkzv. duh rutine koja jedna drugu pozivaju potpuno nepotrebno itd.. Taj problem programer u assembleru nema, nepostoji. Primjetiti ete vrlo brzo kako je rukovanje i upotreba skupom radnih registara u assembleru daleko kvalitetni a time odvijanje programa. Da ne ulazimo u strukturu programa i programskih rutina. Jasno je da programer u viem programskom jeziku, ni uz najbolju volju, nemoe znati to e compiler uraditi od njegova koda. Nadam se da vam je jasno kako se ni jedan jedini znani vii proramski jezik nemoe mjeriti s assemblerom. U daljnjim tekstu pokuati emo pojasniti zato je to tako.

Krenimo na posao. Spomenuti emo, iako mislim da je to jasno od ranije, kako je vano da odaberemo MCU koji e zadovoljavati kriterije potrebne da bi na sustav radio kako treba i da bi nali najbolji balans izmeu HW i SW. Nije to ba tako jednostavno, bar ne uvijek. Pretpostavljam to e neki rei; mi smo programeri. Mnogi moji znanci ponosno su isticali kako oni nemaju veze s HW, sve to drugi rijee a oni rade iskljuivo SW. Pogotovo kod nas je to poprimilo maha poodavno, valjda zato to nemamo vlastitu elektroniku industriju. Zapadnije od nas je malo drugaija precepcija odnosa HW/SW. Poto smatram programiranje u assembleru najboljim to se moe nai u svijetu programiranja za odreenu mainu a ono pretpostavlja poznavanje HW kompletnog ureaja, ne samo mikroraunala, za kojeg se program pie. esto takvi ljudi odreuju balans izmeu HW-skih i SW-skih rijeenja samog ureaja. to e biti emulirano, to nee i na koji nain. Znam, rei ete da smo otili u dizajn samog sustava. Tono! Iz mnogih upita po ovom boardu, i ne samo ovom, vidi se da neki ljudi i pored znanja iz programiranja ne poznaju HW, tehnologiju u kojoj je MCU raen pa to zna dovest do problema ak i kad je rutina dobro dizajnirana. Vratimo se naem mikroraunalu. Recimo da naem ureaju odgovara ATmega8, ili nemamo nita bolje pri ruci. Naravno, nemamo uvijek sve MCU-e na raspolaganu ili nam je koji put mikroraunalo kojeg imamo, uz manje preinake u dizajnu HW ureaja, sasvim zadovoljavajue. Odabrali smo MCU, dizajnirali HW, odredili to e biti ime rijeeno i sad treba zapoeti pisati program da odradi treni posao. Vjerojatno ste se prvi put pitali kako poeti. Iako mnogi alati (macroassembleri) omoguuju kod otvaranja projekta da za vas kreiraju mali uvod na poetku. Poimo nekim redom. Mali primjer kako poeti s dokumentiranjem. Code: Select all;//////////////////////////////////// KOMANDER /////////////////////////////////////// ;/// THIS SOURCE CODE IS PRIVATE PROPERTY OF ime prezime AND CAN'T BE USED BY ENYONE WHITHOUT SPETIAL ;/// PREMISSION / CODE IS MADED 12.09.2005 ;/// ; OVAJ IZVORNI KOD NIJE DOZVOLJENO KORISTITI BEZ AUTOROVOG PRISTANKA ! ; SAMO ZA PRIVATNU UPOTREBU !!! ;//////////////////////////////////////////////////////////////////// ///////////////// ;/// IZVRSNI PROGRAM KORISTI LCD IZ NOKIJE 3410 KAO PRIKAZNU JEDINICU , KORISTI 4 TASTERA ZA UPRAVLJANJE ;/// KORISTI TIMER ZA MINUTE I TIMER ZA LCD PAUZE , BUZZER ZA GENERIRANJE ZVUKA , U EPROMU POHRANJUJE PODATKE O ;/// JEDINICAMA KOJIMA UPRAVLJA / ADR=00 TRENUTNI MAX BROJ ADR01=JED1 ADR02=ACTIVE/TIME [BIT7 0=NEAKTIVAN] 5 BITOVA TIME ;/// FuseL==E4 intosc / DE Q FuseH==CC-512W..CC-256W sa bootl /CF bez bootl

ili ovaj: Code: Select all

; un-assembled & TPScrypt code by Threat ; private source code for authorised peoples only !!!

Dokumentacija? Ako su mi ita prigovarali moji prijatelji to je jako loa dokumentiranost programa. Mislim na one beskonano duge opise to koja rutina radi (ak i one s tri-etiri linije) kojih se grozim. Za mene je to gubljenje vremena. Iz jednostane logike, programeru u assembleru netrebaju opisi svake, i najmanje rutine, da bi razumio emu ona slui. Ali, vi ipak dokumentirajte rutine da nebi ispalo da vas loe savijetujem. Dijagrami toka? Sad, ako vam je on zaista potreban da bi lake odradili posao piite ga. Da nebi stvari preskakali, ve sagledali kompletan kontekst opcija naeg malog raunala prije poetka pisanja prvih redova naredbi imamo za obaviti jako vaan zadatak. Izvriti definiranje poetnih parametara rada naeg MCU-a. Vjerujem da znate na to mislim? Koji tip oscilatora, wdt ili ne, pullup ili ne, bootloader da/ne i koje veliine, zakljuavanje ili ne i koji mod, itd... Nadam se da vam je jasno da je na MCU ( u ovom sluaju ATmega8) ne fiksne strukture. Njegov se HW moe podesiti vaim potrebama (naravno ogranieno). Spoj glavnih konfiguracionih bytova, koji se eto upisuju programatarom, iako mogu i iz bootloadera (za Mega seriju, o tome kasnije), i registara specialne namjene konfiguriraju va mali stroj po eljenim parametrima (ogranieni onim to je proizvoat ponudio). Upisom konfiguracionih bytova Hifuse, Lowfuse ili kao to zna biti prezentirano u programatorima kao odabir bitova preko maske odreujemo poetno ponaanje MCU-a. Recimo da ne elimo troiti novac na externi oscilator (kristal ili neto drugo) i elimo da MCU sadi to bre moe. Primjer: Code: Select allFuseLow ==> E4 odabiremo, izmeu ostalog, interniosc (RC) Postavljanjem vrijednosti OSCALL registra na 0xFF, ako je MCU na radnom naponu od 5V, va interni oscilator e raditi na 16MHz. Ako je radni napon izmeu 3,1-->3,3V tad e frekvencija biti 14MHz.

Pravilnim odabiramom vrijednosti OSCALL registra moete sasim dobro podesiti takt frekvenciju. Da, jedna napomena za one koji to moda nisu znali ili misle da nemoe, MCU-i u Cmos tehnologijama koji su deklarirani na 5V bez problema e raditi i na 3V3 i na 2V7 a mikrochipovi MCU-i (testirano na seriji 16F) rade dobro na naponu od 2V2 pa ak i na 1V8 i to sputajui napon napajanja u samom radu MCU-a. Vano je jedno da znate i toga se drite ako sami dizajnirate HW, to je prag logike "0". Na to je cmos osjetljiv. Ima jako malu toleranciju prema "0". Malo mu treba da prebaci s "0" na "1". To je i razlog one "nevolje" oko reseta za onu Megu168. Eto jo jedan od razloga zato je potrebno ne samo poznavati mirkoraunalo (strukturu) ve i tehnologiju u kojoj je raen, naravno za one koji planiraju, jednom, dizajnirati svoj vlastiti ureaj. to dalje? AVR- macroassembler (AVR Studio) poinje kopijom tkzv. startne definicije prije poetka oznake za poetak programa .cseg a to je u naem sluaju ova naredba assembleru .include "m8def.inc" Ta naredba nije ni nita drugo ve skup definicija imena registara kao i imenovanje MCU-a: Code: Select all.device ATmega128. (Bila mi je pri ruci) ; ; ;********************************************************************

********* ; CPU Register Declarations ;******************************************************************** ********* .def XL = r26 ; X pointer low .def XH = r27 ; X pointer high .def YL = r28 ; Y pointer low .def YH = r29 ; Y pointer high .def ZL = r30 ; Z pointer low .def ZH = r31 ; Z pointer high ; ; ;**** Interrupt Vectors **** .equ INT0addr = $002 ; External Interrupt0 Vector Address .equ INT1addr = $004 ; External Interrupt1 Vector Address .equ INT2addr = $006 ; External Interrupt2 Vector Address .equ INT3addr = $008 ; External Interrupt3 Vector Address .equ INT4addr = $00a ; External Interrupt4 Vector Address .equ INT5addr = $00c ; External Interrupt5 Vector Address .equ INT6addr = $00e ; External Interrupt6 Vector Address .equ INT7addr = $010 ; External Interrupt7 Vector Address .equ OC2addr = $012 ; Output Compare2 Interrupt Vector Address .equ OVF2addr = $014 ; Overflow2 Interrupt Vector Address .equ ICP1addr = $016 ; Input Capture1 Interrupt Vector Address .equ OC1Aaddr = $018 ; Output Compare1A Interrupt Vector Address .equ OC1Baddr = $01a ; Output Compare1B Interrupt Vector Address .equ OVF1addr = $01c ; Overflow1 Interrupt Vector Address .equ OC0addr = $01e ; Output Compare0 Interrupt Vector Address .equ OVF0addr = $020 ; Overflow0 Interrupt Vector Address ; itd...

Jasno je da taj dodatak uope nije potreban osim deklaracije MCU-a (.device ATmega8). Nemojte se isuavat jer na MCU ionako nerazumije imena, no radi nas samih ipak je korisno. Da nebude nikakve zabune vi sami u svom assembleru moete te registre preminovati ili koristiti neki svoj vlastiti "m8def.inc" file ili kako god ga elite nazvati. To je obian text! Iz ovoga je jasno da imate mogunost da sami definirate nazive registara, zone rama, zone programske memorije itd,itd... Prije nego prijeemo na definiranje naziva radnih registara (ako to elimo) moramo uiniti jednu vanu stvar, ono to je esto bolna toka viih programskih jezika, dodjeljivanje funkcija tj. imenovanje varijabli i pridruivanje skupu ili pojedinom registru iz skupa radnih registra ili polja rama. Poto u rutinama stalno trebaju neki od radnih registara (imamo ih 16 potpuno operativnih) za neposredni upis ili prijenos s jednog mjesta na drugo u ramu, eepromu, prg memoriji ( to oko prg memorije kad doemo na bootloader i samoprogramiranje). Korisno je i definirati kojima od registara neemo dodijeliti nikakvu funkciju tj. koji e biti tkzv (tmp) slobodni registri (iako mnogi programeri u asembleru imaju svoje "favorite" pa ih znaju napamet i koriste u gotovo svim programima). Mega jezgre, kao i AVR imaju skup od 32 registara od toga 16 ope namjene no u tih 16 tri su indeksna para registara a od njih je jedan par ZH:ZL, par kojemu je dodijeljena specijala

funkcija. Samo oni gu biti pokazivai adrese u naredbi indirektnog poziva i indirektnog skoka (icall i ijmp) kao i adresni brojai naredbi lpm, spm... Primjer jedne jednostavne definicije registara na samaom poetku programa: Code: Select all.cseg .def LINEX=r24 .def LINEY=r23 TMARK=r21 ; inL=r4 inH=r5 tmL=r6 tmH=r7 Maxlen=r8 COUNT=r2 PNS=r10 TIMER=r22 Slika1=0x0081 OldKurs=0x0080 PosBlink=0x0082 Anim1pos=0x0085 Anim1old=0x0086 ; pozicije u ramu ; trenutna pos blinka

.def .def .def .def .def .def .def .def .def .equ .equ .equ .equ .equ

Svakako pokazati emo i primjer sloenije predefinicije: Code: Select all.equ FRACT=0x0156 ; trenutna freq .equ SLF0=0x0157 ; .equ SLF5=0x0158 ; .equ YDAT=0x0159 ; podatak za PLL registar // SwB .equ STRLEN=0x015A ; broj znakova u stringu [hexstr pretvorbom] .equ SLC4=0x015B ; komplement slota SLF4 .equ SLOTA=0x015C ; slot za identifikaciju / samo ako ima novi .equ SLOTX=0x015D ; upravo pobrisani slot .equ SPLOW=0x015E ; TMP SPI LOW adr .equ SPHIG=0x015F ; TMP SPI HI adr .equ SPSHA=0x0160 ; TMP SPI SHI adr .equ ROSWN=0x0161 ; nova pozicija rotary switch .equ ROSWO=0x0162 ; stara pozicija rotary switcha .equ MENOD=0x0163 ; odgovori poz hi byte SPI // start 00 eng cita iz SPI .equ MENPO=0x0164 ; postavke menija hi byte SPI .equ ROVAL=0x0165 ; vrijednost dobivena rotary SW algoritmom .equ MEOLD=0x0166 ; stara zadnja pozicija menija u SPI //ZH val .equ MENLO=0x0167 ; postavke menija lo byte SPI .equ METMP=0x0168 ; privremena pos ZLa za sub menije .equ MELNG=0x0169 ; aktivni jezik u meniju .equ RDMST=0x016A ; readme i o uredjaju pocetna najvisa adresa .equ TIMERX=0xFC17 ; inv timera za 64 miliS prescaler 1024 //03E8 .equ SPIODE=0x0000 ; ADRESA BAZA ODGOVORA ENG shi i

hi low =00 // SPI .equ SPIRDM=0x0100 ==00 // SPI .equ SETBYT=0x07F0 jezik // max 30 jezika ; itd....

; ADRESA README DOC

shi i hi low

; adresa set byte u INTEEP za

Kad smo definirali varijable i dodjelili im registre ili polja rama itd... definirali sve funkcije koje mislimo da trebamo postavljmo assembleru poetak naredbom .org Iza te naredbe slijedi polje prekidnog vektora tj. adresa prekida (prekidnih rutina). Njegova dubina ovisi o MCU-u kojeg koristimo. Prva adresa nije i je prekid (zaprvo je reset), naravno, i ako nita nije upisano u to polje program e ii dalje do svog "prirodnog" starta tj. kraja polja prekidnog vektora. Ako su koritene naredbe reti ili kombinacija reti i nop to god da se dogodilo u programu, a uzrok je greka, i dovede do skoka u zonu prekidnog vektora (a nisu reset) vratiti e se nazad bez veih posljedica po odvijanje programa osim gubljenja koje mikrosekunde. Poto mikroraunala nisu savrena takve se stvari dogaaju. Evo kako to izgleda: Code: Select all.org 0 rjmp INIT ; odmah skaemo na inicijalizacijsku rutinu // Naziv te rutine nije vaan reti reti reti reti reti reti reti ; reti nop reti nop ; ; reti .org 0x0016 ; povratna adresa iz bootloadera i prva adresa programa poslije polja prekidnog vektora. Ako ne koristimo bootloader ova .org definicija nam ne treba INIT: ldi r17, 4 ; poetak programa

Kao to smo vidjeli u ranijem tekstu s reset adrese skacemo u rutinu kojoj smo dali ime INIT. To je prva rutina koju cemo napisati, bar bi bilo dobro. U njoj cemo konfigurirati registre specialne namijene, definirati velicinu stoga u ramu, postaviti pocetne parametre portova, preskalera itd... Obicno se ta rutina jo naziva i inicijalizacijska rutina. Odmah da neke stvari rasistimo, ovdije neemo pojanjavati imena i funkcije pojedinih registara specijalne namijene ili naredbi ako one nisu u slubi pojanjenja problema ili lakeg raumijevanja toka programa i same upotrebe assemblera. Na poetku je reeno da se prije bilo kakvog uputanja u pisanje programa u asembleru mora prouiti tehnika dokumentacije MCU-

a kojeg koristimo kao i okruenja u kojem on djeluje, HW-a ureaja. Pisanje programa u asembleru nije isto to i pisanje programa u C-u, VB-u s koritenjem pojedinih programskih odsjeaka pisanih u asembleru. Radi se o potpuno drugaijem pristupu postavljanju i voenju programa. To su dva razliita svijeta. Moda ovaj dio, uvod u program, i ne izgleda neto zanimljiv i naizgled je idetian onome to rade alati u C-u ali to je sve. Pogotovo kod jednostavnijih programa i definicija. Nebi bilo loe da proitate komentare sa strane u primjerima jer oni opisuju ono to se dogaa, to pojedina veliina unosi u registar, ram, eeprom... Komentari sa strane su veoma esti kod assemblerskih programa. Netko ih koristi u veoj netko u manjoj mjeri. Oni vam ga vie izau kao prilino dobra dokumentacija i uputa za neka budua rijeenja. Polje registara specijalne namijene smjeteno je u ramu na relativnoj adresi 0x00 pa navie, ovisi o MCU-u. U naem sluaju ono ide do relativne adrese 0x3F. Zato smo spominjali relativnu adresu rama? Ipak je MCU realan stroj s realnim tj. apsolutnim veliinama i jedino njih on razumije, pa tako i na ATm8. 32 registra ope namjene (16/16) relano nisu nikakvo zasebno polje skupa registara, oni su samo prikazani programeru kao takvi a dio su realnog HW-a polja rama i to od apsolutne adrese 0x00 do 0x1F, to znai da je stvarno polje naih registara specijalne namijene od vrijednosti 0x20 pa do 0x5F. To je navedeno i u tehnikoj dokumentaciji (dodue sitnijim slovima) pa rekoh da vam bar malo olakam snalaenje. Zato je to bitno? Programer u assembleru mora poznavati te detalje (kako je esto naglaavano) jer za njega nema tko o tome voditi rauna kao to to rade compileri u alatima HPL-a; C, VB... Znai da na realni sektor, tj. stvarno polje rama poinje od adrese 0x60 pa do kraja rama. Pravilnom upotrebom indeksnih registara moete, to veina compilera nemoe jer im brani upravo ta zatita od sluajnog ulaska u polje registara specijalne namijene, direkto unositi podatke u radne registre predstavljajui ih maini kao ram. To se npr. pokazalo kao vrlo korisno u pisanju sloenih algoritama enkripcije i dekripcije. No najvanije je da znamo pravo stanje stvari u naem stroju. Koliko ega imamo na raspolaganju kao programeri. Primjer inicijalizacijske rutine: IME RUTINE NAREDBE KOMENTARI INIT: ldi r17, 4 ; 4 ATm8 INIT STACK out SPH, r17 ; moe se koristiti i predefinicija iz m8def zvana RAMEND clr r17 ; out SPL, r17 ; lds r17, SFIOR ori r17, 8 sts SFIOR, r17 ; onemogucen ADC i ADC mux sbi ACSR, 7 cbi ADCSR, ADEN ; onemoguci ADC konvertor ;sts ADCSR, r17 ;in r17, MCUCSR ; konfigutacija sleep moda opcija power-down int0 aktive low ;andi r17, 0xDF ; brise bit 5 ;out MCUCSR, r17 ;in r17, EMCUCR

;andi r17, 0x7F ; brise bit 7 ;out EMCUCR, r17 out TIFR, r17 ldi r17, 0xA8 ; ivsel=0 // omogucen SLEEP mode s Power down i padajucim sign out MCUCR, r17 ; 38 ==8515 // m8==A8 ldi r17, 0x40 ; omoguci prekid preko INT0 tu ce bit OK taster kasnije onemoguciti out GICR, r17 nop clr r17 ; setiranje timera out TCCR1A, r17 ; normal port operation / bez PWMa i OCNa out TIMSK, r17 ; timer stopiran ldi r17, 5 out TCCR1B, r17 ; preskaler postavljen na 1024 ldi r17, 0x5F ; EE // B7 -ldi r16, 0xC8 ; D1 //18 A037 presk 1024 14MHz== 3S compl==5FC8 out TCNT1H, r17 out TCNT1L, r16 ; TIMSK ce kasnije bit setiran na OVFL mode ldi r17, 4 out TCCR0, r17 ; postavi timer 0 u normal mod s preskalerom 256 ;clr r17 ; out GIFR, r17 ; prekidni flagovi u 00 ldi r17, 0xFF ; bio F8 za 5V out OSCCAL, r17 ; 14MHz nop clr r17 out DDRC, r17 out PORTC, r17 ldi r17, 0xC0 ; svi ulazni osim PD6 i PD7 out DDRD, r17 nop ldi r17, 0xFF out DDRB, r17 ; izlazni portovi out PORTD, r17 nop cbi PORTD, 6 ; iskljuci TX / primjer nemaskiranog, direktnog, postavljanja pina u "0" ldi r17, 0x3E ; bit 6==0 iskljuci TX i 7==0 iskljuci sound out PORTB, r17 nop ldi r17, 0x80 sts Anim1pos, r17 ; upisuje vrijednost iz r17 u ram odreen pozicijom Anim1pos sts Anim1old, r17 sei ; omoguci opci prekid generalno rjmp START ; Primjetiti cete da za definicije velicine stoga (SPH: SPL) nisu koritene predefinicije iz m8def.inc. U asembleru to nije vano, vano je da znate to cinite. Dali cete za to koristiti predefiniciju, decimalni, oktalni, hexadecimalni ili binarni broj nije bitno. Neke od naredbi imaju pocetak sa ; Taj znak, tocka-zarez, kazuje asembleru da tu naredbu ne uzima u obzir. Nakon definicije smijera podataka porta primjetiti cete da obicno koristim naredbu NOP (no

operation) . Ta naredba slui da bi se dalo vremena racunalu da se port sinkronizira i postavi kako treba prije slijedece operativne naredbe. NOP naredba uglavnom slui za "kupovanje" vremena tj. za kratka kanjenja potrebna stroju da postavi vrijednost u realnom vremenu. O realnom vremenu smo neto ve i govorili. Ako programer ne razumije vrijeme i nain realnog ponaanja stroja i misli kako se njegove naredbe izvravaju u nekom "warp" polju imati 'e ne malih proglema u stvarnosti i interakciji s HW-om ureaja. Svaka tehnologija ima svoje probleme, svaki stroj svoje realno kanjenje. Ti se problemi najvie ogledaju kad se piu rutine za rad s vanjskim sklopovima. Znate, itanje i iitavanje podataka iz rama u flash, iz flasha u ram, iz jednog u drugi registar se odvije unutar sustava ije kanjenje je dio njega samog no to nije sluaj sa radom s vanjskim sklopovima. Moete uzeti primjer I2C eeproma koji su uasno spori. Ili pisanje inicijalizaciske rutine za driver MMC/SD kartice ija brzina u inicijalizaciji komunikacije nesmije prijei 400kHz, emuliranje USART protokola (HW-ski i SW-ski layer) itd... Upravo radi tih stvari slobodno mogu rei da je NOP bogom dana naredba. Koliko god se to nekome inilo neobino. No kad razmislite o tome vidjeti ete da sam u pravu. U registre iz skupa registara specijalne namijene koje vidite u gornjoj rutini nemoe se direktno upisivati vrijednost vec samo preko radnih registara naredbama in, out, lds, sts. Ovo je primjer gdje to nije slucaj: cbi PORTD, 6 vec se direktno postavlja (setira) ili brie (resetira) bit. Ovako, jedno je bitno, nemorate vi definirati vrijednosti svih registara iz tog skupa vec samo onih koji ce neposredno utjecati na odvijanje vaeg programa i postavku HW-ra uredaja vama bitnu. Npr kao definicija SFIOR registra. Ako ne elite promijeniti ostale bitove tj, opcije registra specijalne namijene, u ovom slucaju nek to bude SFIOR, tada se posluimo tkzv. maskiranjem bita. Primjer: lds r17, SFIOR ; iscitavamo trenutno stanje registra SFIOR ori r17, 8 ; vrimo maskiranje bita postavljanjem logicke jedinice i u bit 3 sts SFIOR, r17 ; spremamo novo stanje u SFIOR Ili ovaj primjer in r17, SFIOR ori r17, 4 ; onemoguci PULLUP otpornike u MCU-u. out SFIOR, r17 ; Moe i ovaj primjer in r17, SFIOR andi r17, 0xFB ; omoguci PUD (pullup) bit 2 / 1=disable 0=eneable out SFIOR, r17 ; Kao to vidite u sva tri primjera radi se o maskiranju bita operacijama koje za to i slue u racunalu, kojem god; OR i AND. Naredba andi se koristi kad se odabrani bit u maski eli pobrisati, tj. postaviti u logicku nulu a ori kad se odredeni bit eli postaviti u logicku jedinicu. Da nebude krivo shvaceno, bilo kad i bilo gdje u programu moete podeavati registre specijalne namjene a ova rutina se postavlja kao inicijalna, u njoj su pocetni uvjeti starta naeg MCU-a. Sad kad smo naem MCU-u zadali pocetne parametre, kreirali tip i velicinu oscilatora takta, boot zonu (o njoj kasnije), definirali portove (smijer i startnu vrijednost), odabrali jo neke od

specijalnih funkcija kao sleep s aktivacijom na prekidnom vektoru int0 u padajucoj ivici signala (postaje aktivan na logickoj nuli), definirali timere, ako nam trebaju, moemo krenuti dalje. rjmp START voditi ce nas prema glavnom programu. To su naredbe i pozivi na rutine koje postavljaju pocetne parametre okolnog HW-ra uredaja, testiraju ga, testiraju komunikacije, provjeravaju ID-e pojedinih chipova ili modula u sustavu i ako je sve uredu idu pravo u glavni program ako nije obavjetavaju nas o greci, pod uvjetom da je taj dio obraden. Kod jednostavnih programa, kao oni za paljenje lampica, raznih releja i slino netreba vam takva rutina. Netreba vam ni inicijalizacija... Poto su oni prejednostavni, bez uvrede, nemogu biti uzeti kao primjer u prii o asembleru jer im ne treba dobar dio strukture programa. Uglavnom se svode na postavljanje ili brisanje bita odabranog porta i kanjenja (dali timerom ili emuliranih). Nebi ih ak ni preporuio za uenje rada u assembleru. Jer se nema to nauit. No idemo dalje! Primjer rutine koja vri inicijalizaciju HW-a ureaja, test pojedinih rutina ili baza podataka itd: START: sleep ; MCU ceka budjenje s tasterom OK !!!! nop in r17, GICR andi r17, 0xBF ; brise bit 6 onemoguci prekid s I/O porta PD2 ==INT0 out GICR, r17 ; to je samo jedna od multipleksiranih funkcija porta MCU-a nop Kao to vidite ovdje smo redefinirali status specijalnog registra jer nam vie nece trebati sleep mod pa da nam nebi MCU sluajno "zaspao". rcall ZVUK ; SUSTAV JE UKLJUCEN - poziv na rutinu koja generira zvuk na buzzeru. rcall TESTCOM ;-----testiranje comunikacije sa USB /rs232 VCPa Ove dvije gornje naredbe rcall su poziv na rutinu koja je smjetena unutar bloka. Dubina je najcece oko 2KB. Zbog krivog izrauna stvarne razlike od naredbe do stvarne rutine moe vam MCU upast u reset vektor ili negdje drugdje zaglibit. Ako niste sigurni uvijek se moete posluiti naredbana za apsolutni poziv call ili skok jmp. str0: clr ZH clr ZL ; clr PNS ; postavi normal mode za znakove rcall IEPRD ; cita interni eeprom str1: mov Maxlen, byte , podatak iz eeproma sprema u registar Maxlen rcall LCDini ; vri inicijalizaciju LCD-a pozivom na rutinu/e u driveru rcall SKCOPY ldi YH, 1 ; pos srama sa podacima za svaki skuter / time i status clr YL sts Slika1, YL clr inL clr tmH inc tmH strX: rcall M1SLIKA ; postavljamo pocetnu sliku na LCD mov tmL, Maxlen ldi LINEX, 0x40

strs: inc LINEX cpi LINEX, 0x46 ; po 5 skutera breq MAIN Naredba uvjetnog grananja breq njen doseg, dubina, je 256. Macroasembler e vas upozorit ako preete maximalnu vrijednost. rcall LINxy rcall SKUNM ; prikaz reda // S01 00 ISKLJ dec tmL ; maxlen brne strs ; jo jedna naredba uvjetnog grananja Tu bi mogli reci da nedostaje uvjet kojeg testira naredba uvjetnog grananja kao u gornjem primjeru naredba cpi , no u vecini maina status "0" se ne postavalja u uvjet direktno, iako moe. Ionako se nalazi u status registru (jednom od registara u polju registara specijalne namjene) u formi zastavice (flag). Tako da cim registar tmL dostigne nulu biti ce zadovoljen uvjet za preskok grananja i program ce nastaviti u slijedecoj naredbi. U ovom slucaju u glavnom programu. Tu smo utedjeli jednu nadbu, najmanje jedan ciklus. MAIN: rcall TASTS ; //// POINJE GLAVNI PROGRAM //// Vidjeli smo kako su u dijelu programa nazvanog START postavljeni pocetni parametri funkcija u registre ili stog, neki su iscitani iz interne memorije podataka. S ovim dijelom programa zavreno je konfiguriranje sustava kao i postavljanje svih pocetnih vrijednosti u registre, ram, portove... Da nebi bilo zabune, mnoge od tih rutina koje su pozvane, kao i driveri koji se pozivanju u toj fazi izrade programa, vjerojatno nisu napisani (ili kopirani) no to nije bitno. Vano je da smo postavili sve kako bi trebalo biti ili mislimo da treba. Svakako i ovo, fiziki ta rutina (START) nemora biti na poetku, to je jasno ja se nadam, moe biti bilo gdje vano je da se poziva prije poetka izvrenja glavnog programa. Netko e moda rei kako je nepotrebna. Moda, kod programa koji su neprofesionalno raeni, ili postoji, iskreno neznam kakav, razlog za ne testiranje sustava prije poetka odvijanja glavnog programa. ak i za relativno jednostavne ureaje ona je korisna. Moe se dodat glavnom programu ako doe do neke od greaka da ponovo krene od takve rutine. O upravljanju error kodom (grekom) emo se pozabaviti kasnije. Naalost neki programeni to smatraju gubljenjem vremena, a neki kao da ni neznaju to je to obrada greke i koliko je ona bitna programu. I tako, malo po malo mi doosmo do glavnog programa. U asembleru je on principielno postavljen gotovo na isti nain kao i kod viih programskih jezika. Uglavnom se pozivaju funkcionalne cjeline (potprogrami) jedan za drugim do kraja glavnog programa. Veina glavnih programa kao i potprograma i rutina nema kraj u klasinom smislu te rijei. Glavni program se uvijek vraa na svoj poetak zatvoren u bezuvjetnu petlju ili uvjetnu s grananjem na njegov poetak kao jednom od opcija. Ja se ne sjeam ni jednog programa koji je imao klasian kraj, osim nekih koji su sluili testiranju. To nam govori jednu veoma vanu stvar, da se glavna bitka kod izrade programa pa tako i srukturiranje vri u potprogramima, rutinama, driverima itd... No ipak, on nam govori, struktura glavnog programa, koliko smo dobro segmentirali program i jesmo li dobro odvagali funkcionalne cjeline. Kao to nevalja previe rascjepkat glavni program tako nevalja ni nagurat hrpu stvari u dva-tri funkcionalana bloka.

Glavni program je na prvi korak, ulaz, u strukturiranje programa bez obzira to e najvei teret podnijeti potprogrami a poesto male rutine. Najvanije je da se ne upustimo u beskrajno cjepaknje potprograma kao ni pretjerano sabijanje u jednu nefunkcionalnu, bolje re teko funkcionalnu, cjelinu. Na primjerima koje slijede pokuati u vam pokazati kako gore reeno i nemora uvijek biti ispravno. Naravno nemora uvijek glavni program biti samo niz poziva na vee potprograme. Dobar primjer za to jesu emulatori pay-tv kartica. Njihovi glavni programi su prilino dugaki i nerjetko kompleksni. Ali to je samo radi specifinosti problema koji se njima rjeavaju a ne nepoznavanja programiranja u asembleru. Primjer jednog glavnog programa takvog emulatora: Code: Select all; main: avr00BF:

clr r17 clr XH sts 0x0062, r17 sts 0x0063, r17 clr r8 clr r7 clr r21 rcall avr0046 bbg: ldi ZH, 0x02 0x02FE (0xFF80) clr r17 ldi XL, 0x61 ld r17, X cpi r17, 0x05 brne avr00D3 rjmp avr01C1 interesting part!!!! avr00D3: 0062 sig avr00D7: cpi r17, 0x01 brne avr00EE rjmp EMM wrong! ld r17, X+ cpi r17, 0x0A brne avr00E6 ld r17, X+ cpi r17, 0x05 brne avr00E6 ld r17, X+ subi r17, 0x02 ld ZH, X+ ld ZL, X+ clt ld r18, X+ rcall avr02FD dec r17 brne avr00E1 set rjmp avr018C ldi r17, 0x69

; 00BF 2711 ; 00C0 9310 0062 upisi 00 ; 00C2 9310 0063 ; 00C4 2488 ; 00C5 DF80 ; 00C6 E0F2 ; ; ; ; ; 00CE 00CF 00D0 00D1 00D2 E6A1 911C 3015 F409 C0EE 01

Load a config in @

Handle ECM, EMM rutina EMM bio 0096

; 00D4 3011 ; 00D6 CFBF ; ; ; ; ; ; ; ; ; ; ; ; ; ; 00D7 00D8 00D9 00DA 00DB 00DC 00DD 00DE 00DF 00E0 00E1 00E2 00E3 00E4

911D 301A F461 911D 3015 F449 911D 5012 12-2=10h 91FD 91ED 912D D21A 951A F7E1

avr00E1:

avr00E6:

; 00E5 C0A6 ; 00E6 E619

ldi XL, 0x02 ; 00E7 E6A2 st X+, r17 ; 00E8 931D ldi r17, 0x00 ; 00E9 E010 st X+, r17 ; 00EA 931D ldi XL, 0x67 ; 00EB E6A7 st X+, r17 ; 00EC 931D rjmp avr018C ; 00ED C09E avr00EE: ldi XL, 0x64 ; 00F2 E6A4 --------- pocinje klasa 02 prijavna rutina -----------------------ld r17, X+ ; 00F3 911D ext eeprom write cpi r17, 0xFF ; 00F4 3F1F breq avr00D7 ; 00F5 F309 set ; 00F6 9468 cpi r17, 0x00 ; 00F7 3010 brne avr00FE ; 00F8 F429 ldi ZL, 0x15 ; 00F9 E1E5 serial num ldi r17, 0x14 ; 00FA E114 sts 0x0067, r17 ; 00FB 9310 0067 rjmp avr018B ; 00FD C08D avr00FE: cpi r17, 0x01 ; 00FE 3011 P1 01 (card serial num HEX) brne avr0107 ; 00FF F439 ldi r17, 0x10 ; 0101 E110 sts 0x0067, r17 ; 0102 9310 0067 ldi ZL, 0xF0 rcall avr02F2 mov r18, r0 cpi r18, 0x01 brne vlki ldi ZL,0x8A rjmp avr018B ; -- bio wfc hex ser iz flasa vlki: ldi ZL, 0x2A ; 0100 E2EA trebalo biti od providera tekuceg !:)bio A2 rjmp avr010A ; 0106 C085 salje u cam avr0107: cpi r17, 0x02 ; 0107 3012 P1 02 (country code + COCO string) brne avr0110 ; 0108 F439 ldi ZL, 0x3B ; 0109 E3EB treba bit od tekuceg providera (a moze i ALL) avr010A: ldi r17, 0x10 ; 010A E110 avr010D: sts 0x0067, r17 ; 010B 9310 0067 len rjmp avr018B ; 010F C07C avr0110: cpi r17, 0x0B ; 0110 301B P1 0B (country code other way) brne avr0114 ; 0111 F411 ldi ZL, 0x3B ; 0112 E4E8 coco rjmp avr010A ; 0113 CFF6 avr0114: cpi r17, 0x03 ; 0114 3013 P1 03 (get PID ) brne avr0125 ; 0115 F479 ldi r17, 0x18 ; 0116 E118 14 + 4 =18 ldi ZL, 0x4C ; 0119 E4EC PW 0315 za P00 lds r25, 0x0066 ; 011B 919D uzima provider num iz srama ! cpi r25, 0x00 ; 011C 3090 P2 00 (provider 00) ako ne 10 !! :) breq avr010D ; 011D F021 ldi ZL, 0x65 ; 011E E6E5 za P 10 0318 (PW) rjmp avr010D ; 0121 C06A uzima config u obzir i trazi u eepromu avr0125: cpi r17, 0x0E ; 0125 301E P1 0E (read card file) brne avr013D ; 0126 F429 staviti CF umjesto

kljuceva za secu u eeprom 00 ldi XL, 0x65 ; ldi ZH, 0x00 ; ld r22, X+ ; cpi r22, 0x02 ; breq avr0126 ; cpi r22, 0x03 ; breq avr0127 ; avr0126: ldi ZL, 0x00 ; CF 1 begin rjmp avr0128 ; avr0127: ldi ZL, 0x40 ; CF 2 begin avr0128: ldi r17, 0x40 ; 0128 E410 sts 0x0067, r17 ; 0129 9310 0067 sve sto izbacuje prema camu pocinje od 60 rjmp avr018B ; 012B C05F sa rutinom avr018B :) avr013D: cpi r17, 0xEF ; 013D 3E1F brne avr012C ; 013E F441 ldi XL, 0x68 ; 013F E6A8 ld ZH, X+ ; 0140 91FD ld ZL, X+ ; 0141 91ED ldi r17, 0x12 ; 0142 E112 sts 0x0067, r17 ; 0143 9310 0067 rcall avr02E1 ; 0145 D19B rjmp avr018C ; 0146 C045 bio 018C avr012C: cpi r17, 0x08 ; 012C 3018 P1 08 (20h baytes from buffer ??) brne avr0133 ; 012D F429 ldi ZL, 0xA0 ; 012E E8E0 bio 80 ldi r17, 0x20 ; 012F E210 FF00000000000000000000000000000000000000 32 bayt sts 0x0067, r17 ; 0130 9310 0067 rjmp avr018B ; 0132 C058 avr0133: cpi r17, 0x11 ; 0133 3111 P1 11 (????) nije mi trebao brne ldi ldi ldi sts ldi sts rjmp cpi brne ld cpi brne ldi ldi st ldi st sts lds lsl lsl lsl ldi add mov ldi avr0147 ; 0134 F441 ZL, 0x00 ; 0135 EAE0 never use it ZH, 0x00 r17, 0x58 ; 0136 E518 0x0062, r17 ; 0137 9310 0062 r17, 0x40 ; 0139 E410 0x0067, r17 ; 013A 9310 0067 avr018B ; 013C C04E r17, 0x09 ; 0147 3019 P1 09 (cam key) avr0166 ; 0148 F4E9 r17, X+ ; 0149 911D r17, 0x03 ; 014A 3013 avr0165 ; 014B F4C9 r17, 0x55 ; 014C E515 XL, 0x62 ; 014D E6A2 X+, r17 ; 014E 931D r17, 0x00 ; 014F E010 X+, r17 ; 0150 931D 0x0067, r17 ; 0151 E6A7 r17, 0x0066 ; 0153 E6A6 r17 ; 0155 0F11 r17 ; 0156 0F11 r17 ; 0157 0F11 r25, 0x68 ; 0158 E698 08 r17, r25 ; 0159 0F19 XL, r17 ; 015A 2FA1 pozicija cam keya r17, 0x08 ; 015B E017 bio 07

avr0147:

ldi YH, 0x01 key c6----last byt c5 ldi YL, 0xCD avr015E: ld r18, X+ st -Y, r18 dec r17 brne avr015E rcall CKP avr0165: rjmp avr018C avr0166: cpi r17, 0x0A breq avr0169 rjmp avr00E6 avr0169: ld r17, X+ cpi r17, 0x01 brne avr0180 ld r17, X+ cpi r17, 0x02 brne avr0180 ld r17, X+ cpi r17, 0x04 brne avr0180 ld r17, X+ cpi r17, 0x47 brne avr0180 ld r17, X+ cpi r17, 0x11 brne avr0180 ldi ZH, 0x02 ldi ZL, 0x40 ld r18, X+ clt rcall avr02FD ld r18, X+ rcall avr02FD set avr0180: ldi r17, 0x00 sts 0x0067, r17 lds r17, 0x0065 ldi r25, 0x5E sbrs r17, 1 ldi r25, 0x50 sts 0x0062, r25 rjmp avr018C

; 015C E0F1 stog 01c5--- 8 bayta za cam ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; 015E 015F 0160 0161 0166 0167 0168 0169 016A 016B 016C 016D 016E 016F 0170 0171 0172 0173 0174 0175 0176 0177 0178 0179 017A 017B 017C 017D 017E 017F 0180 0181 0183 0185 0186 0187 0188 018A 912D 9321 reversno spremanje 951A F7E1 301A F009 CF7D 911D 3011 F4A1 911D 3012 F489 911D 3014 F471 911D 3417 F459 911D 3111 F441 E0F2 E4E0 912D 94E8 D180 912D D17E 9468 E010 9310 0067 9110 0065 E59E FF11 E590 9390 0062 C001

pin answer

avr018B: rcall avr002D ; 018B cam odgovora avr018C: ldi r21, 0x00 ; 018C avr018D: rcall avr007B ; 018D rjmp avr00BF ; 018E bezuvjetnu petlju na svoj poetak

DEA1 citanje eeproma i slanje u E050 DEED CF30 upis u cam Kao to vidite ide u

Primjer jednog kasinog glavnog programa: Code: Select allMAIN: skutera rcall TASTS clr TMARK ; bivsi TASTE ; marker za operaciju umanji TIMER ; brojac prolaska 6S [timer mode] * 10

clr COUNT == 60S // 1min

TAS1:

ldi r17, 4 out TIMSK, r17 clr YL sbrc TMARK, 0 rcall TMDOW sbrc TMARK, 7 rcall BLINK

; bio 80 ; ukljuci timer1 16bitni na OVFL mode ; umanji vrijeme skuterima za jedan ; rutina za upozorenje da je vrijeme

isteklo

rcall ANIM1 ; poziva potprogram za animaciju, generira pokretnu sliku na LCD rcall DEL87mS ; ovi dely-i od 87mS su dodani radi usporavanja zbog animacije. Gore ; UP taster rcall UPMD Dolje ; Ova naredba je jedan od primjera macro naredbe // DOWN taster rcall DOWMD rcall DEL87mS OK ; OK taster rjmp TAS2 Stop ; STOP taster rjmp TAS4 rjmp TAS1 ; kao to vidimo ovaj glavni program vrti od starta TAS1 to je stvarni glavni program

Donji glavni program je veoma jednostavan. Poziva direktno tri vea potprograma i uvjetno, ovisi o stisnutom tasteru, etiri jednostavnija potprograma. I ovdje je kao i u gornjem primjeru izveno, na neki nain, uvjetno grananje na poetak iako je naredba za direktno grananje rjmp koritena no njoj prethodi macro naredba Stop u kojoj se testira bit i odreuje gdje e program ii. To je jedan od najeih naina vraanja na poetak. U primjerima, pogotovo donjem, vidjeli smo da moemo definirati i svoje vlastite naredbe, macro naredbe. Naravno assembler e ih uredno prevesi u jedini skup naredbi kojeg mikroraunalo razumije, objektni kod. Za razliku od C-a, VB-a... mi emo tono znati strukturu te virtualne naredbe jer emo je morati napisati s naredbama iz skupa naredbi s liste MCU-a. Primjer one nae macro naredbe: .macro Gore sbis PIND, 1 .endm Iz ovog primjera je jasno da ona ne skrauje postupak niti ita pojednostavljuje ve nam samo omoguava da preimenujemo naredbu sbis PIND, 1 u nama razumljiviji oblik. Takve se vrste macro definicija koriste kad imate puno toga za definirati pa da vam bude lake pamtiti. Pogotovo na primjerima kompleksnijih upotreba pinova MCU-a. Kad radite s hrpom pinova kojima su dodjeljene odreene funkcije na HW-skom layeru. HW-ski layer je maska (neto sloenije) koja se koristi kod spajanja nekog sklopa, IC-a, komunikacije, itd... na MCU. Npr. CS, WE, RD, Vpp... signali koji se koriste kod programiranja recimo UV-eeproma a realno su pinovi naeg MCU-a. Njih je tad dobro nazvati funkcionalnim imenima. Na raunalu, u stvarnosti, nema varanja. Kako god dubili na glavi neete utedit vrijeme nikakvim macro, i slinim virtualnim, naredbama. To je jedino mogue paljivim postavljanjem

strukture programa i samih naina rijeavanja problema. Pisanjem to jednostavnijeg algoritma. Ja u poetku gotovo da uope nisam koristio macro naredbe upravo zbog navedenih razloga. Kasnije sam ipak, kako su dolazili sloeniji programi, poeo i njih koristiti. Zato one i postoje. Primjer macro naredbe, malo sloeniji: .macro set_Vpp1 ; PG 4 // 12V6 pin 13 TSOP48 pin Vpp lds r17, PORTG ori r17, 0x10 sts PORTG, r17 nop .endm Ovaj primjer nam tedi "papir" tj. pisanje programa ini neto jednostavnijim i lake razumljivim. U primjeru vidite da je PORTG pozvan naredbom lds. U ATm128, ATm104 i slinim taj port je dio polja skupa registara specijalne namijene i to iji bitovi nemogu biti direktno proitani ni upisani. Pa je koritenje macro naredbe tu zaista dobro dolo. Kao to vidimo definiranje macro naredbe uvijek poine s .macro IME NAREDBE po naoj elji, slijedi neka naredba ili skup naredbi i obezno zavrava s .endm Primjer jednostavnog no nestandardnog glavnog programa: Code: Select allMAIN: call KRENI cp r19, r17 breq maia sts SLOTO, r17 rcall AUTOMD sbis PIND, 5 jmp SBMENU ;--- cita status slota ----; ; ide na auto detekciju stanja slota ; --- citamo taster rotary SW ;tu je info menu , settingsi i manual ;--!! TESTP za standardni multicam

mair: maia:

mode mali: jmp DBXCOM DBXCOM ---- s impulsom rjmp MAIN

Ovaj primjer govori da su dva potprograma funkcionalno i stukturno prilino sloena (jmp SBMENU i jmp DBXCOM) pa se i vraanje iz njih obavlja naredbom direktnog skoka ( jmp MAIN). Takvi potprogrami se obino ne pozivaju naredbama call, icall, rcall ve jmp ili ijmp. Iako je i potprogram rcall AUTOMD dosta kompleksan ipak njegova struktura dozvoljava standardni poziv i vraanje. Iz same strukture glavnog programa se vidi da se na neki nanim modus glavnog programa preselio u potprogram DBXCOM. Ovo je primjer kad potprogram preuzima funkciju glavnog programa (u veini), a za koje naravno postoje realni razlozi. Mislim da su ova tri primjera glavnih programa pokazala kako situacija, bolje rei problem, ponekad od nas trae drugaije pristupe postavljanju strukture programa. Sva tri primjera su drastino razliita. Najtipini i najei je onaj srednji primjer postavljanja glavnog programa. Uskoro ulazimo u "zonu sumraka", potprograme i rutine, drivere itd.... Tamo gdje se zaista odvija pravi posao.

Kanjenje? Moda ce nekome izgledati vec videna tema no iz kuta programera u asembleru ta tema je gotovo vjecna. Moc asemblerskog programiranja, izmedu ostalog, ogleda se i u opcijama koje nam se pruaju kod kreiranja moda kanjenja (famoznog delay-a). U HPL-ima kanjenje moete obaviti na dva nacina, uglavnom, klasicnom delay(xxxx) naredbom ili postavljanjem HW-skog timera sa ili bez prescalera, 8 ili 16 bitnog. No ovo oko postavljanja timera u prekidnom vektoru sa internim HW-om se ionako u HPL-ima mora uraditi kreiranjem assemblerske rutine. Dok naredbom delay(100) u HPL-u najcece postavljamo kanjenje od npr. 100 miliS a compiler to "lijepo" prevede u rutinu koja davi mikroracunalo kako je to lijepo pojasnio na kolega u "Tartufima" u assembleru uopce ne postoji tako to. Jednostavno toga nema! Naredbe delay u asembleru nema iz prostog razloga jer nije na listi naredbi MCU-a. Znaci moramo sami izracunati kanjenje i napraviti petlju. Naizgled bi nas to moglo navesti na krivi zakljucak kako je bolje imati HPL pa ti napie delay a compiler nek se muci. No ima jedna sitna razlika, u assembleru vi tocno znate to, kako i na koji nacin cete izvesti kanjenje. To najcece ovisi o vaoj kreativnosti. Najjednostavniji oblici kanjena jesu oni koji su i najnematovitiji. Primjer: ldi r17, 0x25 ; 14MHz==> 25h za 115kbit // kanjenje za USART emulirani 8n1. rcall DEL14 ; poziv na kanjenje ; ; DEL14: dec r17 ; rutina za kanjenje brne DEL14 ret ; Iz ovoga se vidi kako nam dobro dode poznavanje vremena izvrenja naredbe. Tj. ona vremenska baza, temelj bilo kakvog ozbiljnijeg rada oko mikroracunala, racunala uopce. Osnova izracuna je ===> ukupan broj ciklusa u petlji * vrijeme izvrenja ciklusa. U gornjem primjeru su dvije naredbe jedna ima 1 ciklus a druga 2, treca ( ret) je vracanje i uzima se u izracun kod jako kratkih vremena kanjenja ( ispod 2 microS) na trajanju cyklusa od 50-->80nS kao i naredba za poziv rutine za kanjenje rcall DEL14. U stvarnosti one se unose kao korektivni faktor u samu vrijednost varijable. Poto smo objasnili sve oko izracuna ciklusa u ranijem tekstu necemo ga ponavljati. Primjer 2: ldi r17, 0xF2 ; rcall DELAY ; 14MHz==> 0xF2 4800 bita // kanjenje za emulirani USART 8in1 ; ; ; DELAY: dec r17 ; nop nop nop nop nop nop

nop nop nop brne DELAY ret ; Poto je kanjenje daleko vece nego je moguce to dobiti sa rutinom DEL14 i maximalnom vrijednosti r17 registra napisana je ova. Iz nje se vidi kako se naredbama nop "kupuje" vrijeme mjesto da se koristi vie registara. Ovo je vie prilika da se vidi za to se sve ta naredba moe koristiti. Nebi to bio asembler kad nam nebi pruio mogucnost da smislimo jo koju opciju. Npr. kao delayi mogu se koristiti neke druge rutine ili dijelovi potprograma. Npr. rutine za animaciju slike, sortiranje podataka i sl. Svakako tu su i klasicni timeri. Definicijom u Inicijalizacijskoj rutini, ili bilo gdje u programu, te postavljanjem adrese prekidnog vektora za odabrani mod timera kojeg elimo moemo aktivirati HW-ski brojac. I on je kao i sve u racunalu vezan na takt oscilatora. Od preskalera pa na dalje. Funkcionalno gledano to je dobri stari brojac (T -FlipFlop) impulsa. Moe da radi kao brojac nagore ili nadolje, s prescalerom ili bez njega... Pridodane su im, najcece, opcije za komparaciju. Bojac TCNT1x (x= H,L) broji do vrijednosti postavljene u komparacionom registru OCR1BHx (x=H,L) i postavlja zastavicu prekida kad je ispunjen uvjet. Primjer brojaca s komparacijom: ldi r16, 0x02 out OCR1BH, r16 ; komparaciona vrijednost u H i L regostrima / 16 bitni ldi r16, 0xE8 ; out OCR1BL, r16 ldi r16, 0x01 out TCNT1H, r16 ; pocetna vrijednost brojaca u H i L registrima / 16 bitni ldi r16, 0x00 out TCNT1L, r16 ldi r16, 0x20 ; postavljanjem bita 5 u registru i njegovim kopiranjem u TIMSK postavili smo out TIMSK, r16 ; gornje timere u aktivni mod / ovo moe biti uradeno bilo gdje u programu. out TIFR, r16 Postavljanjem prekidne maske u TIMSK registar i zastavice u TIFR pod uvjetom da je postavljen opci uvjet prekida sei pocinje odbrojavanje. Ako u bilo kom dijelu programa poelite zaustavtit brojanje to moete uciniti najednostavnije na dva nacina; resetiranjem bita TIMSK registra za odabrani timer i mod koritenjem opcije maskiranja (zapamtite to je registar specijalne namjene) ili brisanjem registra za omogucavanje opceg prekida naredbom cli. Ako nemate ni jednu drugu prekidnu opciju aktivnu cli je najjednostavnija opcija. Poto smo koristili samo taj timer nije bilo potrebno izvriti operaciju maskiranja vec je to ucinjeno naredbom ldi r16, 0x20. Kao to se da vidjeti najcece su bit u TIMSK registru i njegova zasatavica u TIFR registru na istoj poziciji u registru, u naem primjeru bitu 5 (0x20 = bit 5).

Da malo pojasnimo to sa HEX kodom. Osam (8) bitni registar je podjeljen funkcionalno u nibble-e, gornji i donji. Bitovi od 0-->3 ine donji nibble a 4-->7 gornji nibble. Tu osnovu HEX coda bi svaki programer trebao poznavati bez obzira jeli koristi HPL ili asembler. Prvi bit donjeg nibble-a (0) je 1, drugi (1)je 2, trei (2)je 4 etvrti(3) je 8 kad to zbrojimo dobijemo 0xF kao maximalnu vrijednost. Prvi bit gornjeg nibblea bit(4) je 0x10, drugi(5) je 0x20, trei(6) je 0x40, etvrti(7) je 0x80. Kad ih zbrojimo dobijemo 0xF0. Zbrajanjem oba nibble-a u 8 bitni broj dobijemo 0xFF kao maximalnu vrijednost. U naem skupu naredbi (ATMega ali i AVR, PIC...) postoji naredba swap (zamijeni) kojom mijenjamo mjesta nibleu, gornji --> donji i obratno. Raunanje u HEX kodu nije toliko strano koliko se to na prvi pogled ini. Pravilnim odabiraom vrijednosti za registar koji vri kotrolu nad odabranim timerom moemo odabrati izmedu osatalog i preskaler opciju. U donjem primjeru je odabran preskaler koji broji 32 takta (u naem slucaju cyklusa) za 8 bitni brojac. Primjer: ldi r17, 3 out TCCR0, r17 ; normal mode prescaler 32 cykl ==> 2 microS za freq. takta od 16 Mhz. ldi r17, 0x5F ; "obicno" postavljanje 16 bitnog brojaca ldi r16, 0xC8 ; out TCNT1H, r17 out TCNT1L, r16 ; U svakom slucaju odabiraom bilo koje od opcija s brojacima moete imati irok spektar kanjenja po osnovi prekidnog vektora i HW-ra specijalne namjene. Koristite li taj mod kanjenja vae racunalo ce normalno raditi svoj posao dok HW ne dode na zadane parametre. Tada ce sustav postaviti prekidnu zastavicu i skociti na adresu prekidnog vektora za taj brojac i mod u kojem je koriten. Kad dode na tu adresu uciniti ce ono to ste mu vi rekli, reti --> vratiti se nazad u program na prvu slijedecu naredbu od one gdje je prekid izvren, ili rjmp, jmp --> skociti u prekidnu rutinu. Emulacijom USART-a vrijeme kanjenjenja na cekanje izmedu dva bita moe se koristiti na razne nacine, jedan od njih je i pokretanje potprograma koji nisu vremenski kriticni ili pak jesu dio vremenski kriticne operacije, kao dekripcija DW-a koje znaju biti due od 60 - 80 000 cyklusa pa i mnogo vie. Kako god, asembler vam prua iroke mogucnosti manipulacijom kanjenja, tj koritenja tog vremena u korisne svrhe. Kao to rekoh na uvodu ogranicenje smo mi sami i naa mata. Sposobnost da nadmudrimo sustav. Experimentirajte malo s raznim opcijama pa vidite kako sve to izgleda u stvarnosti. Najgore je kad se zatvorimo u neke obrasce i iz njih se ne micemo tjeeci se kako smo zadovoljani onim to znamo. Zapamtite, racunalo je uasno prost stroj, gotovo za smijat se jednostavan a jedino to vrijedi ste vi, njegov programer. Sva njegova pamet i glupost je iskljucivo u vaim rukama. Isto tako ne postoji toliko lo kompjuter koliko moe bit lo programer i zato nikad opravdanje za pogreke ne traite u tom malom jednostavnom stroju, mikroracunalu. One se tamo sigurno ne nalaze. Asembler vam prua mogucnost da se direktno suocite sa samim sobom, najprije, jer vam daje kompletnu mainu na raspolagnje, sve njene registre, memorije, mogucnosti... a sve ostalo je na vaoj kreativnosti, sposobnosti kao i poznavanju samog HW-ra ureaja i tehnologije kojom je raen.

Prije odlaska u "zonu sumraka" mogli bi vidjeti to je to zapravo bootloader. Cemu on slui i to moe. Bootloader? Hm. Malo sam razmiljao o nainu na koji bih pokuao pojasniti to bi to bilo. Strukturno gledano i HW-ski a i SW-ski u ATmega MCU-u je to ne samo, manje ili vie kompleksan, program ve i posebna zona u programskoj memoriji. Ne samo to, ima posebne registre u skupu konfiguracionih registara kojima se predefinira njegovo ponaanje i odnos prema dijelu programske memorije gdje je smjetena aplikacija, radni dio vaeg programa. On nemora biti vezan za aplikaciju koja se pie a smjetena je u dijelu programske memorije koja nije boot zona. Postavlja se pravilnim konfiguriranjem u fuseH registru gdje mu se odmah odreuje i veliina, tj. dubina. Konfiguracioni bitovi koji to definiraju jesu u donjem nibbleu tog registra. To su bitovi BOTSZ0 i BOTSZ1. Postavljanjem bita BOOTRST u "0" rekli smo HW-ru MCU-a da da starta od adrese definirane bootsz bitovima. Uvijek je postavljen tako da su mu zadnje adrese dubine ujedno i najvie apsolutne adrese programske memorije. Iz toga je jasno da dubinu rauna od kraja prema najnioj adresi koju odreuje veliina bloka tj njegova fizika veliina u bytovima. Jesam zakomplicirao? Detalje konfiguracionih bitova kao i maski bootlock bitova ( BLBx )imate odlino definirane u tehnikoj dokumentaciji tog processora i to u tabelama u zoni koja opisuje programiranje chipa. Pa da ne kopiram tabele. Za funkcionalni opis bootloadera nije toliko bitno. to bi to zapravo uope bio bootloader i emu uope na njega "gubit vrijeme". Tehnoloki ureaji dananjice gotovo da su preplavljeni razno-raznim raunalima, uglavnom specijalne namjene. Tako da su mnogi ljudi, ak i oni koji nemaju ama ba nikakve veze s raunalima, uli za neto to se zove bootanje (dizanje sustava). Ono "boot" na displayu u raznoraznim ureajima. Usporedit u ga, jer on to naelno a i funkcionalno je, s BIOS-om na matinim ploama vaih kunih ljubimaca IBM standarda, oli ti PC-a. No bit u toliko zloest pa u ga usporediti s MBR sektorom ( Master Boot Record ) vaih "tvrdih" diskova. Jel vam sad bar malo jasnije koliko ste dobili ako mjesto primjera radi 0xCF stavite recimo 0xCC u fuseH registar ATm8? ... Nije! Uh. Proizvoa vam je omoguio da kreirate pravi pravcati bootloader sa svim onim opcijama podranim u konfiguraciji a koje moete po uzoru na, npr. BIOS, pretvoriti u veoma kvalitetan alat. Ne samo za samoprogramiranje ili itanje podataka ili dijelova podataka iz bilo koje od memorija ve moete, unoenjem algoritama za komunikacije, ili koritenjem HW-skih implemenata, stvoriti program kojim ete moi testirati i kontrolirati vae raunalo, mijenjati temeljne konfiguracione postavke sustava, sve konfiguracione bitove kao i lock bitove. Nemate straha da ete sluajno zakljuati MCU jer izradom rutina dodanih na komunikacije, tkzv. SW leyerom, ili ti specifinim protokolom moete napraviti da va bootlodar za vas radi sve ono, samo puno bre i kvalitetnije, to radi bilo koji programator. ak i paralelni.

Primjer: Code: Select all

MAINB: rcall iboot bootloaderom s usb ili rs232 rcall AECCPY rutinu i kljuc u sram rcall Testaek glx: clr ZH clr ZL clr r5 gl0: rcall inst lds r24, CMD cpi r24, 0xA0 brne gl3 rjmp wspmr gl1: cpi r24, 0xA2 brne gl3 rjmp akeyn ;gl2: cpi r24, 0xA4 ;brne gl3 ;jmp IEPRD gl3: cpi r24, 0xA6 brne gl6 rjmp IEWR gl6: cpi r24, 0xA8 ostaviti automatski **** brne glA rjmp LOCKB glA: cpi r24, 0x9F brne glB rjmp pts3 glB: rjmp gl0 ;

;-- testira dal ima zahtijev za ; kopira tabele AES 128b decrypto ; izracun AES prosirenog kljuca

; CITA NAREDBU ; ; self prg routine ; promijena kljuca dekrypcije!! ; upisi poz novog kljuca ; int eprom read ; int eeprom write ; ---****** Kasnije izbrisati tj ; upis blb i lock bitova ! ; izadji ; izai iz bootloadera

Na gornjem primjeru se vidi jedan obian protokol kojim upravljamo bootloaderm. Slanjem jedne od naredbi u SRAM iz PC-a moemo odabrati ponuenu operaciju ili izai iz bootloadera. U donjoj rutini vidite tipian izlazak iz bootloadera. Primjer moete nai i u dkumentaviji proizvoaa. Code: Select allpts3: ldi r22, 0x11 ; povratak u aplikaciju !! r22==spmval rcall spmr ; u kontrolni registar postavlja vrijednost za izlazak iz bootloadera. rjmp 0x0014 ; prva adresa programa aplikacije a u ovom sluaju i prva adresa nakon kraja prekidnog vektora.

Dodavanjem grafike i LCD-a dobijate veoma moan alat i to popuno neovisam. Protokole upravljakih naredbi emulirate u bilo koji od script jezika (java, php, VB, pyton... ili, jednostavnije, koristite hyperterminal ili telnet) i sa bilo kojeg PC-a moete kontrolirati rad vaeg mikroraunala. Dodavanjem algoritama enkripcije moete va kod aplikacije za upload dodatno zatiti.

Mogunosti su velike i ovise iskljuivo o vaoj matovitosti i potrebama. Od prve ATmege na dalje nikad nisam nijednu koristio bez bootloadera. Jednostavnijeg ili sloenijeg, ovisilo je o potrebama. To nesmijemo nikako zaboraviti, SPM naredba ( Self Programming Mode) radi iskljuivo u bootloader zoni i mora biti aktivirana na konfiguracionoj maski. Ona je, ako se sjeam zadnja adresa prekidnog vektora. Kontrolom registara specijalne namjene vezne na tu naredbu koristite razne modalitete njene primjene. Tu je i prekidni vektor. Postavljanjem bita IVSEL premjetamo prekidni vektor sa poetka programske memorije na poetak bootzone ako to elimo. Ovako izgleda poetak bootloaer zone u programskoj memoriji kad prvi put piemo program a elimo odmah ubaciti bootloader. .org 0x0C00 ; 1B00 2KB byte dubina / 1KW /// Primjer samo... Da bude jasno, bootloader moemo napisati kao zaseban program i uprogramirati ga u prg. memoriju. Nemora biti pisan kao dio aplikacije. Vano!! Ako ste jednom upisali bootloader u va MCU netreba vam nikakva pomo programatora. Jedino ako elite mijenjati sam bootloader (iako to moe uiniti sam bootloader primjenom odreenog algoritma) ili ste zaboravili postaviti algoritam za promjenu konfiguracionih bytova a iz nekog razloga to morate redefinirati. Nadam se da vam je jasmo da ste s bootloaderaom dobili mainu koju moete pragramirati, emulirate li protokol, koju moete veoma efikasno kotrolirati na daljinu i uploadati va program veoma jednostavno na veoma udaljenim tokama. Definiranjem konfiguracije BootLockBitova bootloader se moe koristi da dozvoljava koritenje svojih rutina iz aplikacije u potpunosti, djelomino ili je potpuno zatvoren. Ovako, o bootlodaru bi mogli danima priat i teko da bi sve rekli. No nadam se da je neto jasnije emu on slui i koje vam mogunosti prua. Eto, ako se sjetitite onog s poetaka, tako neto, kad sam vam priao o onoj neobinoj naredbi (SPM) koja je izmjenila strukturu i ponaanje HW ali i mogunosti postavljanja programa, same aplikacije. Bez nje bi sam bootloader bio prilino osakaen. to ako ne elite u bootloader, netreba vam trenutno a postavljen je BOOTRST bit u "0" i imate upisam bootloader? Evo jedna jednostavna rutina: Code: Select alliboot: clr XH ft232r --clr XL ldi r25, 20 iboo0: sbis PINB, 1 rjmp iboo1 clc adiw XH:XL, 1 ;-------- scan ulaza u bootloader sa max211 i

;

maximalno ceka oko 32 mS x 20 ==640mS

brcc iboo0 ; ovdje je delay rijeen emulacijom jer ionako mora ekati. dec r25 ; ovako duga kanjenja se mogu koristit za autotest ili neto slino. brne iboo0 rjmp pts3 ; izadji iz bootloader nema zahtijeva za ulaz iboo1: ldi byte, 0x46 ; FBQ == 46h 42h 51h alje potvrdu PC-u ili nekom drugom raunalu da je uao u boot rcall sendbyte ; na njegov zahtjev // to je neka vrsta identifikacije ili ti ID-a ureaja ldi byte, 0x42 ; rcall sendbyte ldi byte, 0x51 rcall sendbyte ret ;

Da ne zaboravimo spomenuti i ovo, ako koristite SPM naredbu i elite njome programirati vau prg. memoriju ne zaboravite da sve ATmege korite pageing, oli ti u sram upie stranicu (page) odreene duine , ovisi o MCU-u koji imate, i tad kad ste upisali sve baytove po zadanoj veliini stranice (len) pozivate rutinu za samoprogramiranje. U dokumentaciji je to dobro objanjeno i primjerima u C-u i asembleru. EEprom podataka se ne upisuje u page modu ve byte na byte. elite li promijeniti samo jedan byte u programskoj memoriji iitate itavu stranicu gdje se taj byte nalazi u sram po page obraascu, postavljanjem poetne adrese u indeksne registare, npr. XH:XL, i promijenite ga u sramu. Postavite poetne adrese stranice prg. memorije,gdje je bio onaj bzte, u registre ZH:ZL i adrese srama u indeksne registre XH:XL i tad pozovete rutinu za samoprogramiranje. Na taj nain moete mijenjati jedan byte ili vie u prg. mem. Prije nego to nastavimo dalje nebi bilo loe da se malo zadrimo oko Samoprogramiranja. Nije to samo pitanje rutine u bootloader zoni vezane na naredbu SPM ve i mogonosti da utjeemo na program. Na njegovu strukturu, mjenjamo pojedine rutine ili kreiramo potpuno nove. Na taj nain raunalu moemo omoguiti samounje, izradu jednostavnih compilera koji su dio bootloadera ili aplikacije. Moemo kreirati svoj vlastiti operativni sustav podeen naim potrebama itd. Poimo najprije od te famozne SPM naredbe. Uz tu naredbu vezan je registar u polju registara specijalne namjene SPMCR (SPM Control Register) oli ti kontrolni registar SPM naredbe. To je vie funkcija nego klasina naredba. Pravilnim postavljanjem bitova u SPMCR odreujemo to e SPM naredba uraditi. Kao adresni brojai koriste se registri r31 i r30 znani kao ZH i ZL a kao registri za prijenos podataka u privremeni buffer (veliine stranice) koriste se registri r1 i r0 poto su naredbe AVR-ATmega 16bitne. Primjer jezgre rutine za samoprogramiranje: Samo da dodam, prije SPM naredbe onemoguite sve prekide naredbom cli !! Moe i postavljanjem vektor u zonu bootloadera ali ovo je sigurnije. Code: Select allspmr: sbic rjmp out spm EECR, EEWE spmr SPMCR, r22

sp1:

.dw $FFFF nop in r19, SPMCR sbrc r19, SPMEN rjmp sp1 ret

Prva naredba sbic provjerava status EECR bita u EEWE registru i ako je zadovoljen uvjet grananja program preskae prvu bezuvjetnu petlju rjmp i ide na slijedeu naredbu. Tom naredbom upisujemo eljenu vrijednost u SPM kontrolni registar i njome odreujemo njeno ponaanje, tj. koju e opraciju napraviti. Sad slijedi sama SPM naredba. Nakon te naredbe se nalazi neto to bi molo neke i zauditi .dw 0xFFFF ( $ => jo jedan od markera hex broja). Nalog raunalu da odmah po SPM naredbi postavi dvobaytno "prazno polje". Neobino, jeli tako. No poto je nae raunalo malo "bedast stroj" ono e uredno pokuat izvrit naredbu. Naravno poto ta naredba ne postoji u skupu naredbi samo e gubit vrijeme na putu da doe do prve naredbe iz skupa. Da ponovimo, raunalo ne razumije simbolike naredbe assemblera ve samo binarne, u naem sluaju 16bitne. Dobili smo ono to smo trebali, gubljenje vremena. Pretpostavljam da se pitate zato moramo gubiti vrijeme. Ako vaem raunalu postavite frekvencije iznad 12MHz treba mu malo vremena da pravilno izvri SPM naredbu tj. dovri proces upisa stranice u programsku memoriju. Mislim da se pitate zato to nije moglo s NOP naredbom. Moglo je, no ovo je jo jedan od primjera kojim sam elio pokazati kako je raunalu relativan pojam ak i upotreba same naredbe. Pokazao sam vam jo jedan od naina kako se moe ostvariti malo kanjenje. U pravilu to se radi NOP opracijama. Ova NOP naredba ispod .dw je dodana jer raunalo radi na 16MHz. Ako bi koristili oscilator na 20MHz tada ubacite jo jednu liniju .dw 0xFFFF. Mislim da vam je razlog jasan. Poto maina bre radi a vrijeme programiranja stranice je konstanta treba mu i vee kanjenje. Na feq. od 28MHz stavite najmanje tri .dw 0xFFFF linije ili adekvatan broj NOP naredbi. U slijedeoj naredbi in r19, SPMCR ita kontrolni registar i sprema njegov radraj u jedan od registara ope namjene (r19) jer se na registrima i skupa registara specijalne namjene nemogu izvriti operacije testiranja bita kao to je slijedea naredba. Naredba sbrc tesira bit SPMEN u registru r19 i ako je uvjet grananja zadovoljen ("0") odlazi na naredbu ret tj. vraa se u potprogram iz kojeg je pozvan. Znam to se pitate, kako se SPMEN (SPM eneable = omogui) naao u r19 kad je on bit registra specijalne namijene SPMCR. Jednostavno. Sjeate se naeg uvoda u pisanje programa i onog poetka pozivom na m8def.inc? Tad sam rekao da su svi ti SPMCR, TIME0, PORTB itd.. samo obian tekst koji zamjenjuje broj ili adresu registra, ili bit u registru... Upravo to, SPMEN je obian broj a u naem sluaju to je bit 0. Znai da smo istu stvar mogli dobit da smo napisali naredbu na slijedei nain sbrc r19, 0. Vjerojatno ste primjetili kako se registri ZH:ZL koriste i kod naredbe LPM kao adresni brojai no oni se koriste i kod veoma zanimljivih no rijetko koritenih naredbi indirektnog skoka ijmp i indirektnog poziva icall.

Od svih registarskih parova samo se ZH:ZL koristi u naredbama koje zahtjevaju privremenu predefiniciju adresnog brojaa, njegove vrijednosti: SPM, LPM ili trajnu: icall i ijmp. Kao to se ta dva indeksna registra korite za posebne operacije, tj operacije s adresnim brojaem tako se i dva registra iz skupa registara opee namjene takoer koriste za unos ili prihvat podataka iz naredbi koje rade s itanje ili upisom u programsku memoriju ili naredbama mnoenja a to su registri r0 i r1. Iskljuivo preko njih moemo upisivati podatke u privremenu zomu rama prije upisa u programsku memoriju. Primjer: ldi r22, 3 ; pobrii stranicu rcall spmr wsp1: ld r0, Y+ ; upii u stranicu ld r1, Y+ ldi r22, 1 ; puni temp registar 32Word (16bit) rcall spmr adiw ZH:ZL, 2 ; uvecaj adresu cpi YL, 0x80 brne wsp1 ldi r22, 5 ; upii stranicu u programsku memoriju rcall spmr U gornjem primjeru vidimo kako izgleda postupak programiranja jedne stranice (page) u programsku memoriju. Kao i kod programatora moramo najprije pobrisati stranicu koju u mislimo upisati nove podatke. Brisanje znai postavljanje svih bitova u stanje logike "1" ( 0xff). Kao i svi EEPROM-i (elektrikki izbrisive programibilne memorije) tako i naa u ATm8 moe programirati samo logike "0" i zato mora biti posemnim postupkom koji je dio HW-a dovedena u gore opisano stanje. Slijedi upis u privremenu zonu srama (page) i to iskljuivo preko registara r1:r0. Iz primjera se vidi kako se pomou indeksnih brojaa ( registraskog para XH:XL) iz srama naredbom ld (load) uzimaju podaci i upisuju u navedene registre r1:r0 ( r1 dri vii byte 16 bitnog broja a r0 nii). Nakon svakog postavljanja podataka moramo postaviti SPMCR registar u opciju "puni temp. registar" i pozvati rutinu izvrenja SPM naredbe. Kontrolom vrijednosti indeksnog brojaa pratimo jesmo li upisali cijelu stranicu u privremeni dio rama. Ako jesno postavljanjem opcije za upis u programsku memoriju pozivamo rutinu za izvrenje naredbe SPM (rutina u prolom lanku). To je dio potprograma, zapravo samo rutina, koji slui za programiranje nae ATm8. Naredba LMP iskljuivo u r0 upisuje proitani podatak iz programske memorije. Primjer: lds ZH, MENPO lds ZL, MENLO lpm mov r18, r0 itamo podatak iz programske memorije na adresi koja je definirama na poetku programa,

moe i bio gdje drugdje u programu, definicijom .equ MENLO=0x0200 i .equ MENPO=0x0201. Naredba lds ita podatak iz srama i stavlja ga u indeksni registar (ZH ili ZL). Slijedi itanje naredbom LPM (Load Program Memory) a zadnjom naredbom rezultat koji se nalazi (iskljuivo) u r0 premjetamo u r18. To je opciono, nemoramo rezultat premjetati nigdje ako na to nije potrebno. Funkcionalno naredba mov kopira sadraj jednog registra u drugi. Naredba mul (mnoenje 8 bitnog broja) pohranjuje 16 bitni rezultat u registre r1:r0. Primjer: ldi r16, 5 ; upisujemo mnoitelj u registar r16 ld r18, X+ ; mnoenik uzimamo iz srama mul r18, r16 ; mnoimo ta dva registra movw ZH:ZL, r1:r0 ; rezultat mnoenja iz para r1:r0 premjetamo u reg. par ZH:ZL U ovom primjeru mnoitelj je fiksan broj (5) u registru r16 dok smo moenik uzeli iz srama ije je ukaziva adrese indeksni registarski par XH:XL i smjestili ga u registar r18. X+ znai da e se nakon itanja podatka iz srama indeksni registarski par uveati za 1. Slijedi sama naredba mnoenja mul dva registra a rezultat iz r1:r0 je u ovom sluaju pohranjen u indeksne registre ZH:ZL. Naredbe icall i ijmp omuguavaju ne samo direktan skok bilo gdje u program ijmp ili poziv potprograma/rutine icall ve nam ostavljaju prostor redefiniranju programa, izradu operativnog sustava, jednostavnog compilera itd. Omoguuju modularnost sustavu, jednostavnu nadogradnju i sl. Kod upotrebi tih naredbi morate znati tono to radite jer one pozivaju icall tj. skau ijmp na apsolutnu adresu programske memorije navedenu u registrima ZH:ZL (a ako imate prg. mem. veu od 64k i vrijednoi bita rampz). Njih je dobro koristiti sa nekim jednostavnim file sustavom, virtualnim, ili markerima apsolutnih adresa svih potprograma i rutina u programskoj memoriji spremljenih u samu prg memoriju ili memoriju podataka. U kombinaciji s njima i bootloader zonom te SPM naredbom moete dobiti veoma dinamine strukture programa gdje se rutine i potpogrami mogu uvati bilo gdje, npr. u vanjskoj serijskoj memoriji, MMC/SD kartici i sl. te pozivati po potrebi i upisivati u programsku memoriju i na taj nain davati neke nove sadraje vaoj aplikaciji. Uiniti je modularnom bez potrebe da se nanovo reprogramira ijela prog memorija. Primjer postavljanaj tih naredbi: ldi ZH, high(SETBYT) ldi ZL, low(SETBYT) ; ijmp Bezuvjetni skok na zadanu adresu u programskoj memoriji postavljene u ZH:ZL. ldi ZH, high(SETBYT) ldi ZL, low(SETBYT) ; icall Poziv potprograma ili rutine po osnovi apsolutne adrese programske memorije postavljene u

ZH:ZL. Vjerujem da vam je jasno koliko i najmanja greka moe zeznuti stvar. No uz malo panje nebi trebalo imati straha. Bude li vremena moda se vie pozabavimo tim opcijama. Dolo je vrijeme da se okrenemo samoj izradi programa tamo gdje se on zaista i odvija u potprogramima i malim programskim odsjecima; rutinama, koje esto obavljaju jednostavne zadae. No prije svega toga moramo znati da za nas nitko nee voditi brigu o niemu, jer asembler je obian sastavlja s minimumom uplitanja njegova autora u kod koji ste napisali. Zapravo uplitanja kao kod HPL-a nema. Uglavnom se radi o prostim predefinicaja opisanima u ranijem tekstu. I to sad? Nebi bilo loe da se pozabavimo samim naredbama asemblera, odnosno skupon naredbi koje razumije na ATm8 mCU. Naznakovitije naredbe bilo kojeg programskog jezika jesu naredbe uvjetnih grananja. One stvaraju u nama osjeaj kako je raunalo neki zaista pametan stroj. Kod viih programskih jezika obino se nazivaju petlje kao: for-next, do-loop, while-do... itd. Bez naredbi uvjetnih grananja (i bezuvjetnih) praktiki nebi bilo mogue napisati ni jedan iole smisleniji program. Pitate se kako neke od gore navedenih naredbi HPL-a izgledaju u asembleru? Asembler ne poznaje tako to i u njemu to ne postoji, bar ne na taj nain no postoji veoma moan podskup naredbi za uvjetna i bezuvjetna grananja. Sve naredbe uvjetnih grananja su u principu, a i funkcionalno, povezne za jedan registar, poesto izgubljen u masi drugih "vanijih" registara i problema, a to je STATUS-ni registar. Bitovi tog registara, ne svi (npr. bit opeg prekida ne), oznaavaju staus opracije nad podacima, oli ti rezultata, u samoj ALU (arihmetiko-logikoj jedinici). Zato je taj registar direktno vezan na nju. To su gotovo u pravilu, stanje nule (svi bitovi rezultata = 0x00), Negativnog rezultata, preljeva, prijenosa, poluprijenosa itd... Bitovi tog registra se mogu testirati svaki posebno, moe se cijeli isitati a mogu se i upisivati. Primjer za prekid bit7 I: sei Koritenjem gore navedene naredbe sei (set interrupt = omogui opi prekid) u bit7 I STATUS registra upisuje se logika jedinica i na taj nain omoguava opi prekid bez kojed bi nam koritenje ISR-a, prekidnog vektora, bilo besmisleno, kao i sve nae definicije HW-skih timera, brojaa, USARTA, I2C komunikacija, SPM-a itd...bez obizira na nae postavljanje bitova za omoguavnje prekida u registar nie razine xxxxCR. O tome je ve pisano kod konfiguracije timera. cli Tom naredbom (clear interrupt = onemogui opi prekid) u bit7 (I) STATUS registra postavljamo logiku nulu i, kao to sam naziv kae, onemoguavamo sve prekide na svim razinama. Prekidni vekor je tad neupotrebljiv. Petlje. Programska grananja se u asembleru rade na najednostavniji nain, tesiranjem bita STATUS registra ili upotrebom naredbi za testiranje statusa bita I/O porta (npr. sbic ili

sbis). Primjeri grananja, tj. petlji, testiranjem bita Z ( rezultat =="0") STATUS registra: ldi r25, 8 ; test1: dec r25 ; umanji za 1 brne test1 ; Naredba brne (granaj ako nije jednak na test1) se najee koristi nakon naredbe usporedbe dva registra no poto je to raunalo, a ne ljudski mozak, rekli smo da nakon svake opracije ALU u status registar upisuje trenutno stanje. Kad r25 doe do nule u tom registru e zatavica Z biti postavljena i testiranjem bita Z naredbom brne, koja naizgled nema nikakve veze s tim, program e izii iz petlje. Stvar moda zvui udno jer nismo rekli s im na r25 mora biti jednak. U asembleru, bar svima u kojima sam radio, nedefinirani uvijet kompracije ALU uzima kao nulu i to je sva tajna. Tako da na brne u ovom sluaju znai ako je r25 =0x00 izai iz petlje. Ona, ta naredba, stvarno znai suprotno, kao to je i napisano na poetku, no poto to raunalo ne razumije, ono jednostavno tako ne radi, u stvarnosti testira bit Z i ako nije ili je postavljen odrauje operaciju (naredbu) grananja. Slino vam rade i uvjetna grananja na vei ili manji operand. Mislim da slutitite i kako. Veina toga se vrti oko bita Z, N i C. Z je apsolutni favorit. test2: rcall readbyte st X+, byte ; pocinju naredbe cpi XL, 0x66 brne test2 Ovo je primjer najeeg oblika koritenja uvjetnog grananja naredbom brne iako se funkcionalno opet svodi na testiranje bita Z STATUS registra jer ALU tj programski slijednik daje nalog ALU-u da oduzme vrijednost u registru XL i, u naem sluaju, vrijednosti 0x66 s tim da se vrijednost u registru ne mijenja. Ako je rezultat razliit od nule nee biti zadovoljen uvjet izlaska i na e programa biti u petlji (ide na grananje test2) dok se on ne zadovolji. mov r1, round test3: tst r1 breq test3a add r0, r3 dec r1 rjmp test3 test3a: ret Nareba tst testira jeli vrijednost u naem registru r1, mora biti jedan od registra iz skupa registra ope namijene, jednaka nuli i, ovisno o rezultatu, mijenja status Z bita koji kasnije moete testirati nekom od naredbi uvjernog grananja. U naem sluaju breq (granaj ako je jednak). Poto testiramo nulu nije potrebno navoditi kome je jednak iz ranije opisanog razloga. No kako rekoh u najveem broju sluajeva sve se svodi na testiranje bita Z. Mogli bi redati gomile primjera razliitih testiranja na nulu. Mnoge naredbe uvjetnog grananja jesu logike operacije, najee u formi ekskluzivno OR (eor,xor...) i testiraju najee bit Z. Primjer za grananje na bit C STATUS registra (zastavica preljeva):

test4: lsl r14 brcc test4 eor r14, r19 Naredba brcc (Granaj ako je zastavica grananja, bit C, jednaka nuli). Obino se prije upotrebe ove naredbe bit C brie naredbom clc (brii zastavicu prijenosa). Naravno, nemora uvijek biti tako. Vano je zapamtiti da se nakon najveeg broja naredbi mijenja i stanje zastavica STATUS registra shodno rezultatu u ALU-u. Asembler vam d