PIC'utame PIC'iga

Elektroonika tundmine lubab ehitada igasuguseid huvitavaid ja kasulikke vidinaid. Sõltuvalt täidetavast ülesandest võib projekteeritav skeem kujuneda üsna suureks. Suurem hulk (loogika-)mikroskeeme tähendab aga suuremat voolutarvet ja vähemat töökindlust. Kunagised algelised terveid hooneid täitvad arvutid olid ju samuti üsna piiratud võimalustega ja olid enamuse ajast rikkis...Sama effekt on muudegi elektroonikaskeemide juures.

Kui seade valmis ning töötab, tekib kindlasti tahtmine talle midagi juurde ehitada. Mõnel juhul läheb see lihtsalt aga nt. loogikaskeemidel ehitatud telefoninumbri valijale mälu lisamine tähendab juba terve skeemi ringi tegemist.

Hulka lihtsamalt saaks hakkama kui asendada kogu lihtloogika ühe programmeeritava mikroskeemi – mikrokontrolleriga. Isegi osa analoogelektroonikast võib kontrolleri sobival valikul kivi sisse toppida.

Kogu töö teeb ära programm. Seega kui tekib vajadus midagi muuta, piirdub ümbertegemine vaid koodi täiendamisega. Skeem ise jääb samaks (vähemasti suures osas).

Kontrollereid on palju, tuleb vaid leida mõni vastavalt maitsele, programmeerimisoskustele ja muidugi vastavalt täidetavale ülesandele.

Käesolev lugu räägib firma Microchip toodetavate kontrollerite (PIC-ide) kasutamisest. Sama hästi võiks kasutada Atmeli, Cygnali jpt protsessoreid. Maitse asi...

Mikrokontroller on suhteliselt odav ühekiviarvuti. See tähendab, et sama mikroskeemi sees on protsessor ise, mälu (RAM, ROM, EEPROM), sisend/väljundseadmed, taimerid, järjestikside seadmed (USART), mõnel kivil isegi analoog-digitaalmuundid jms. ROM ehk mälu osa, kus programmi hoitakse, on enamasti mitu korda ümber kirjutatav (FLASH). Seega saab oma koodi prooviks kivisse kirjutada, võimalikud vead parandada ja lõpuks uus kood jälle prosesse kõrvetada. Mugav, eks ju!

Mingi skeemi välja mõtlemiseks on vaja teada, milliseid mikroskeeme saaks kasutada (mida üks või teine kivi teha suudab). Programmide kirjutamisega on sama lugu, tuleb tunda kasutatava protsessori või kontrolleri võimalusi.Kuskohast infot leida? Eks ikka tootja kodulehelt www.microchip.com kus kõik datasheet'id kenasti saadaval.

Üks lihtsamaid Microchipi PIC-e – PIC16F628 – sisaldab 2 kB koodi mälu, 224 baiti muutmälu (RAM) kus saab muutujaid hoida ja 128 baiti EEPROM-mälu. Perifeeriaseadmetest on kivil järjestikport, 3 taimerit, 2 analoogkomparaatorit, tugipingeallika ja nn. PWM mooduli. Võrreldes lauaarvutitega on mälu häbematult vähe küll aga tuleb välja et siiski piisavalt. Ja lõpuks: PIC-i peal ei ole ju vaja Windowsit jooksutada...

PIC on nn. Harwardi arhitektuuriga protsessor s.t. programmi mälul ja RAM-il on eraldi andmesiinid. Järelikult võib andmesõna pikkus olla mõlemal erinev. PICi puhl nii ongi: koodimälu sõna pikkus on 14 bitti, RAM aga tavaline 8-bitine.Pikem koodimälu sõna lubab teha kõik käsud 1-“baidised“ (bait ei tähenda siin enam 8 bitti !) ja järelikult saab käsu lugeda sisse tunduvalt kiireminie, ühe hingetõmbega. Zilogi Z80-l tuli lugeda mitu baiti.

PIC16F628 sisemuse blokkskeem

PIC on nn. RISC-protsessor ehk tal on üsna vähe käske (35 tk.). Seega peaks tema selgeks õppimine tunduvalt rutem minema.

Põhiosa „karu kõhus“ on aritmeetika-loogikaseade (ALU) vt. joonist.See sõlm oskab teha tehteid andmete ja konstantidega: liita, lahutada, teha loogikatehteid (nihutamine jne). ALU opereerib ka konstantidega, põhiline tööregister on register W.

Programmi mälust loetakse järjest käske, mälu aadresse genereerib taktgeneraatori taktikepi mõjul loendi, mida kutsutakse Program Counteriks. Loendi sisu saab salvestada nn. stack'i, kirjutada counterisse mingi muu aadress ja hiljem jälle eelneva ülesande juurde tagasi pöörduda lugedes stack'ist aadressi. Sellist trikki kasutatakse katkestuste puhul.Stacki maakeelne nimi on pinu, stackpointerit (PICis vaid prose enda poolt muudetav) aga kutsutakse pinuviidaks.

Järjekordne loetud käsk dekodeeritakse instruction decode lülis ja täidetakse. Järelikult on taktigeneraator väga oluline sõlm, nagu vedru vanaaegses äratuskellas. Ilma temata ei tee kivi mitte midagi. Tavaliselt on generaator kivi sees, sagedust määrav element (kvarts) aga väljas. PIC-il saab kasutada ka täielikult sisemist generaatorit, sel juhul jäävad kvartsi ühendamise otsad vabaks muude ülesannete täitmiseks.

RESET

Toitepinge peale lülitamisel alustatakse koodi käskude täitmist alati aadressist 0 (mõnel prosel võib ka mõni muu aadress olla, nt. PIC12F508). Seda aadressi nimetatakse ka reset-vektoriks. Toitehäirete jms. mõjul võib juhtuda, et programmiloendi sisu ei saa nullitud ja alustatakse mingist suvalisest aadressist – programm jookseb kokku. Kindlustamaks alati 0-aadressist alustamist, kasutatakse kavalaid nippe. PIC-il on väljaviik MCLR, mille stardil kondega maha tõmbamisel PC sisu nullitakse. On ka spetsiaalne sisemine taimer (power-up timer), mis starti viivitab lastes toitepingel stabiliseeruda. Seda kasutades võib MCLR-viiku muudeks ülesanneteks kasutada, näiteks mingiks sisendiks.

PIC-ide (ja ka Cygnali prosede) juures on see väga tore omadus – väljaviikude otstarvet saab muuta, isegi programmi töö käigus programmi enese poolt. Nii saab nt. viike RB1 ja RB2 kasutada sisendina ja mingil hetkel nad kivi serialpordiks nimetada ning nende kaudu infovahetust teha.

Mälu

Nagu minitud, on prosel kaks mälu: koodimälu (FLASH enamasti) ja RAM muutujate hoidmiseks. Koodimällu kirjutatakse programm, sellega on kõik selge. RAM on natuke keerukama ehitusega. Andmelehel mainitud 224 baiti pole mitte kõik kasutaja info jaoks, osa mälust hõivavad nn

juhtregistrid (SFR). Juhtregistrite sisu muutmisega saab määrata prose ja tema perifeeriaseadmete käitumist.

PIC16F628 mälu jaotus

Nagu jooniselt näha, on mälu jaotatud 4-ks osaks ehk pangaks. Kuigi igal mälupesal on oma aadress, ei saab mingit konstanti otse mällu kirjutada vaid esimesse panka. Ülejäänud mälu kasutamiseks pruugitakse nn. kaudset adresseerimist.

Näide

movlw	0x04	; kirjutame arvu 4 registrisse W

movwf	0x20	; kopeerime W sisu mällu aadressile 0x20

bsf	STATUS,RP0	; siirdume panka 1

movwf	0xA0	; sama konstant (4) kirjutatakse nüüd aadressile 0xA0

bcf	STATUS,RP0	; tagasi panka 0

Näitest selgub veel et andmete kopeerimine ühest mälupesast teise saab toimuda vaid registri W kaudu, nt. mäluaadressilt 0xA0 otse aadressile 0x20 kopeerimise käsku ja võimalust ei ole olemas (PIC18xxx seerias juba on).

Perifeeriaseadmetest on PIC-il ennekõike olulised väljaviikude juhtskeemid ehk pordid. Ainult nende kaudu saab kivi suhelda välismaailmaga.

Ühte ja sedasama viiku saab defineerida sisendiks või väljundiks (mitte üheaegselt paraku) s.t. viigud on kahesuunalised. Iga viigu suunda saab muuta teistest sõltumatult kirjutades sobiva numbri juhtregistrisse TRISA (port A puhul) või registrisse TRISB. TRIS-registri biti väärtus 0 tähendab, et vastav viik on väljund ja 1 et sisend.

Näide:

movlw	B'00001111' ; laeme registrisse W konstandi 00001111

movwf	TRISA	; kirjutame selle port A juhtregistrisse TRISA

Toodud koodiridade täitmise järel on pordi A viigud 7...4 väljundid ja viigud 3...0 sisendid. Palume nüüd PICil anda väljunditele pinged peale. Tahame saada pordi A viikudele 0 ja 1 pinget 5V (loogilise ühe nivoo) ja viikudele 2 ja 3 madalat nivood (0V). Seda saab teha ühe liigutusega:

Näide:

movlw	B'00000011'

movwf	PORTA,

aga saab ka igat viiku eraldi lülitada:

bsf	PORTA,0	; viik 0-le HIGH nivood

bsf	PORTA,1	; viigule 1 samaks

bcf	PORTA,2	; ülejäänutele madal nivood

bcf	PORTA,3

Kui väljundite külge riputada valgusdioodid, hakkavad PORTA,0 ja PORTA,1 küljes olevad LEDid põlema, ülejäänud 2 aga on kustunud.

Aga mis juhtub viikudega 7...4? Ühe käsu näites kirjutasime neisse nullid, kas lähevadki nulli? Ei lähe, nad on ju sisendid.See käsk ei avalda neile mingit mõju. Pinge sisenditel on määratud väliste seadmetega, näiteks saab koibade külge keevitada surunupud, roboti liikumissuuna andurid või veel midagi. Kuidas sisendite seisu teada saada? Loeme:

Näide:

movf	PORTA,W	; loeme pordi A viikude seisu registrisse W.

Kui sisendid 7 ja 5 on nullis ning 6 ja 4 kõrged, saame tulemuseks 01010011. Viimased 4 numbrit pärinevad eelmistest käskudest kus sundisime väljundeid sobivasse seisu. Väljundid võivad programmi juhtimisel võtta suvalisi väärtusi, meie sisendite lugemise koodi võib see hämmingusse ajada. Mida teha, väljundeid on ju vaja ? Lahenduseks on mittevajalike bittide (väljundite bittide) kustutamine ehk maskeerimine.

Näide:

movf	PORTA,W	; loeme pordi A viikude seisu registrisse W.

andlw	B'11110000'	; maskeerime väljundite bitid.

Selleks teeme loogilise JA tehte pordist loetud baidi ja konstandiga 11110000. Bitikaupa loogilist JA tehet tehet sooritades jäetakse väärtusega 1 tehte puhul pordist loetud bitt muutmata, väärtuse 0 puhul aga on tulemuseks ka null. Tulemuses on sisendibittide väärtus sõltuv vaid sisendite seisust, väljndeid juhtivad bitid saavad aga pidevalt väärtuse 0. Selline number tekib registrisse W, port ise jäetakse puutumata!

Esimene programm

„Sidur on siin, gaas siin. Pane käed roolile ja lase pidur lahti, sõidame,“ alustas minu sõiduõpetaja esimest praktikatundi. Proovime nüüd meiegi teha olemasolevate teadmiste baasil midagi kasulikku. Paneme näiteks Pordi A viigule 0 ühendatud valgusdioodi vilkuma. Skeem oleks järgnev.

Ühe LED'i vilgutaja

LEDi toidame läbi 470 oomise voolu piirava takisti. Taktsagedus on Harju keskmine 4MHz. Prose RESETi viigu RA5 ühendame läbi takisti toitega.Hiljem näeme, kuidas seda takistit ja isegi kvartsi saaks ära jätta.

Kood näeb välja selline.

;===============================================================================

; 1 LED-i vilgutaja

;===============================================================================

;*********************** Raudvärk **********************************************

;*** väljundid ***

#define LED	PORTA,0	; LEDi juhtimine, aktiivne = HIGH

#define LED1	PORTA,1	; teise LEDi juhtimine, aktiivne = HIGH

; ********************** constantsid *******************************************

#define viiteaega	0x02	; määrab ära LED'i vilkumise kestuse

#define viiteaegb	0x04	; sama

#define viiteaegc	.198	; sama

#define viiteaegd	.200	; sama

LIST p=16F628	; Nimetame prose

#include "P16F628.INC"	; siit failist loeb kompilaator protsessori info

errorlevel -302	; Compaileri vingumised ära

errorlevel -305	; Compaileri vingumised ära

; prose konfiguratsioon

__CONFIG _WDT_OFF&_XT_OSC&_PWRTE_ON&_CP_OFF&_MCLRE_ON&_BODEN_OFF&_LVP_OFF

; ************** Mälu jaotus **********

cblock 0x20	; kasutaja mälublokk pangas 0

cnt0

cnt1

cnt2

cnt3

endc

; **** Prose lipukesed ****

#define CARRY	STATUS,C	; vähema kirjutamise huvides nimetame mõned asjad ümber

#define ZERO	STATUS,Z

#define pank	STATUS,RP0

; *****************************

org	0x0000	; programm algab aadressist 0000

;===============================================================================

; ********************** põhiluup **********************************************

;===============================================================================

main:	movlw	0x07	; komparaatorid OFF

movwf	CMCON	; komparaatorite juhtregistrisse

clrf	PORTA	; nullime pordi

bsf	pank	; siirdume mälupanka 1

movlw	0x00	; tugipingeallikas OFF

movwf	VRCON	; kirjutame tugipinge allika juhtregistrisse

movlw	B'11000000'	; Kvarts otsad on sisendid, muud väljundid

movwf	TRISA	; kirjutame pordi juhtregistrisse

bcf	pank	; tagasi mälupanka 0

movlw	B'11000000'	; olgu alguses pordi kõik väljundotsad madalad

movwf	PORTA	; kirjutame porti, LEDid peavad nüüd kustuma

main_1:	call	viide	; molutame umbes 1 sekundi, siis süütame LEDi

bsf	LED	; PORTA väljund 0 kõrgeks (LED süttib)

bcf	LED1

call	viide	; veel 1 sekund viidet

bcf	LED	; kustutame LED-i

bsf	LED1

goto	main_1	; jätkame niiviisi kuni patarei tühjaks saab...

Päris alguses kofigureerime protsessori: lülitame välja vahikoera taimeri (WDT) jne. Programmi alguses jätkame konffimist. Et pordid toimiksid õigesti, lülitame välja kivi sisemised komparaatorid kirjutades nende juhtregistrisse CMCON arvu 7. Järgnevalt puhastame pordi A registri. Põhimõtteliselt peaks see pingestamisel automaatselt toimuma kuid ... usalda aga kontrolli. Lülitame välja ka prose tugipingeallika sest seda meil hetkel vaja ei lähe. Kustutame LED'i kirjutades porti A arvu 0xC0 (ehk lülitame meid huvitava väljundi nulli. Ongi valmis, võib tööle hakata.

Esimese asjana viidame aega umbes sekundi (tahame et LED vilguks sellise perioodiga). Selleks kutsume välja alamprogrammi viide. Aja möödudes lülitame LEDi sisse käsuga bsf LED. Viidame veel ühe sekundi aega ja kustutame LEDi (bcf LED). Ja nüüd hüppame proge alguse lähedale tagasi. Tekib lõputu tsükkel.

Kõik on kena aga mismoodi aja viitmine käib. Sellist käsku ei ole ju? Iga käsu täitmine võtab oma aja. 4MHz-se taktsageduse puhulkulub enamike käskude täitmiseks täpselt 1uS. 1 sekundi saamiseks peaks siis kohutavalt palju tühikäske (nop) üksteise järgi laduma. Praktilisem on laadida mingisse mälupessa sobiv arv ja hakata sama pesa sisu ühe võrra vähendama. Niiviisi:

Näide:

viide3:	MOVLW	viiteaegd	; arv 200 (kulub 1uS)

MOVWF	cnt3	; mälupessa cnt3 (kulub 1uS)

viide4:	DECFSZ	cnt3	; lahuta mälupesa sisust 1 (kulub 1uS)

GOTO	viide4	; tee seda kuni cnt3 sisu on null (kulub 2uS)

.....

Kokku kulub selle tsükli täitmiseks aega 601 uS.

; **** aja viitmise alamprogramm ****

; laeme mälupesad cnt0...cnt3 umbes 1 sekundi andva viite konstantidega

viide:	movlw	viiteaega	; arv 2 (kulub 1uS)

movwf	cnt0	; mälupessa cnt0 (kulub 1uS)

viide1:	MOVLW	viiteaegb	; arv 4 (kulub 1uS)

MOVWF	cnt1	; mälupessa cnt1 (kulub 1uS)

viide2:	MOVLW	viiteaegc	; arv 198 (kulub 1uS)

MOVWF	cnt2	; mälupessa cnt2 (kulub 1uS)

viide3:	MOVLW	viiteaegd	; arv 200 (kulub 1uS)

MOVWF	cnt3	; mälupessa cnt3 (kulub 1uS)

viide4:	DECFSZ	cnt3	; lahuta mälupesa sisust 1 (kulub 1uS)

GOTO	viide4	; tee seda kuni cnt3 sisu on null, siis võta järgmine käsk (kulub 2uS)

DECFSZ	cnt2	; lahuta mälupesa sisust 1 (kulub 1uS)

goto	viide3	; tee seda kuni cnt2 sisu on null, siis võta järgmine käsk	(kulub 2uS)

DECFSZ	cnt1	; lahuta mälupesa sisust 1	(kulub 1uS)

goto	viide2	; tee seda kuni cnt1 sisu on null, siis võta järgmine käsk (kulub 2uS)

DECFSZ	cnt0	; lahuta mälupesa sisust 1	(kulub 1uS)

goto	viide1	; tee seda kuni cnt0 sisu on null, siis võta järgmine käsk (kulub 2uS)

return	; pöördume tagasi põhiprogrammi (kulub 2uS)

Teeme pisikese muudatuse: paneme skeemi juurde ühe LED'i (PORTA viigule 1) ja nõuame, et ta vilguks eelmise valgusdioodiga võrreldes vastupidi. Ki üks põleb, peab teine kustunud olema. Selleks on vaja vaid paar lisarida koodi. Esiteks teavitame proset, et meil nüüd üks hoolealune juures. Kirjutame definitsioonide juurde rea:

#define LED1	PORTA,1	; teise LEDi juhtimine, aktiivne = HIGH

Põhiprogrammi lisame LED'i juhtimise käskude juurde analoogsed read:

bcf	LED1	; kustutame teise LED'i

ja

bsf	LED1	; süütame teise LED'i

Kompileerime koodi, kirjutame kivisse, joodame uue LED'i skeemi ja pinge peale. Näe, vilguvadki nii nagu vaja!

Kompilaator, programmator – mis värk on?

Tõsi ta on – PIC ei saa eespool toodud tekstist mitte mõhkagi aru. Talle peab käsud esitame numbrite, mida kutsutakse masinkoodiks, jadana. Igale käsule vastab oma number. Näiteks esimesele käsule movlw 0x07 vastab kood 3007, teisele käsule aga 009F. Põhimõtteliselt saaks iga käsu vaste leida prose kooditabelist ja vajaliku numbrijada ise kokku kirjutada. Ilmselt esimeste arvutite juures nii ka tehti. Eriti kiire ja mugav selline meetod just pole. Samuti on suur oht, et tekib vigu. Parem on taoline igav aga täpsust nõudev ülesanne anda arvutile. Microchip on teinud mugava ja veebist tasuta tõmmatava programmi MPLAB, mis kirjeldatud tööga mängeldes hakkama saab. Teksti teisendamist koodijadaks nimetatakse kompileerimiseks, tulemusena tekib hex-fail. Antud juhul fail „skeem1.hex“.

Järgnevalt on tarvis hex-fail kuidagi kivi sisse saada (ehk kõrvetada, nagu vahest öeldakse). Selleks kasutatakse seadet, mille nimi on programmaator. Programmaatoreid on lihtsaid ja keerulisi.Üks laialtlevinud skeem asub aadressil: http://www.semis.demon.co.uk/Pics/PICmain.htm . Skeem on suhteliselt lihtne ja ta ühendatakse arvuti LPT-porti. Muidugi, on veelgi lihtsamaid skeeme. Programmatorist üksi on vähe, vaja on ka tema juhtimise programmi.Selleks sobib näiteks kuulus IC-prog (http://www.ic-prog.com/ ).

Taimerid

Näites toodud LED'ide vilgutaja periood määrati ära käskude täitmise kiirusega. Muutes protsessori takti, muutub loomulikult ka käskude täitmise aeg ja järelikult vilkumise periood. Iga kord viiteaegu ümber arvutada pole eriti mugav (kuigi nii saaks ka). Parem oleks kasutada mingit kellataolist värki. PIC-is on vidina nimi taimer. Kivis on lausa 3 taimerit: TRM0, TMR1 ja TMR2.

Taimer on register (mälupesa) nagu iga teinegi. Temasse saab numbreid kirjutada ja saab ka lugeda ning muid tehteid teha. Erinevus on selles, et registri sisu suurendab (vastava loa andmisel) protsessor ise, rauas. Seda tehakse kindla kiirusega, mis on määratud taktsagedusega (tegelikult kiirusega takt/4). Mõne taimeri puhul saab loendamise takti veel vähendada kasutades kivi sees olevaid lisajagureid (prescaler või postscaler).

Taimer 1 on 16-bitine s.t. suudad jagada sisendsignaali kuni 65536-ga. Taimer näeb prose sees välja selline:

Taimer 1

Oletame, et soovime saada viidet 0,5 sekundit (sest 1 sekund ei tule nii lihtsalt välja). Taimeri sisendis on taktsagedus 4MHz/ 4 = 1MHz. See annab perioodiks 1uS. Lülitame vahele eeljaguri jagamisteguriga 1:8, saame resulteerivaks loendussageduseks 125kHz (periood 8uS). Tahame viidet 0,5 sekundit, järelikult peame taimerisse kirjutama arvu 0,5/ 8uS = 62500. Taimeri sisu saab loendamise käigus kontrollida kuid õige aja saabumise kontrolliks on kiirem võimalus. Nimelt hakkab taimer oma sisu suurendama nullist alates kuni (TMR1 puhul) täitumiseni ehk arvuni 65536 (0xFFFF). Edasi läheb registri TMR1H ja TMR1L sisu automaatselt nulli ja kogu tsükkel kordub. Sellel nn. ületäitumise hetkel seab prose (jällegi omaenda tarkusest, ilma mingi lisakoodita) registris PIR1 püsti biti, mida Microchip nimetab TMR1IF. Muide, igasugu sündmustest märku andvaid bitte nimetatakse lippudeks.

Nagu näha, lihtsustub ülesanne tunduvalt: laeme taimeri sobiva jagamisteguriga ja konfime (register T1CON) ning ootame kuni lipp TMR1IF püsti (biti väärtus on 1). Siit tuleb ka soov, et õige aeg saabuks alati siis, kui taimer üle täitub. Järelikult ei pea TMR1H ja TMR1L-i laadima mitte arvu 62500 vaid 65536 – 62500= 3036. Kuueteistkümnendkujul 0x0BDC. Taimeris on 2 registrit, arvu 0x0BDC saab ka 2-ks pooleks jagada: 0B ja DC. 0B läheb registrisse TMR1H ja DC registrisse TMR1L.

Näide

movlw	0x0B	; laeme taimeri jagamisteguriga

movwf	TMR1H

movlw	0xDC

movwf	TMR1L

bcf	PIR1,TMR1IF	; igaks juhuks taimeri ületäitumise lipp nulli

movlw	B'00110001'	; eeljagur 1:8, sisemine takt, taimer käima

movwf	T1CON	; laeme taimeri juhtregistrisse. Ajaarvestus käivitub

v1:	btfss	PIR1,TMR1IF	; ootame kuni lipp TMR1IF = 1

goto	v1	; ei ole veel

return	; aeg täis tiksunud...

Meie LEDide vilgutamise programmis muutub aja viitmise alamprogramm:

; **** aja viitmise alamprogramm ****

viide:	movlw	viiteaegH	; laeme taimeri sobiva jagamisteguriga

movwf	TMR1H

movlw	viiteaegL

movwf	TMR1L

bcf	PIR1,TMR1IF	; igaks juhuks taimeri ületäitumise lipp nulli

bsf	T1CON,TMR1ON	; paneme taimeri käima, ajaarvetus algab sellest hetkest

viide_1:	btfss	PIR1,TMR1IF	; ootame ületäitumist

goto	viide_1

bcf	T1CON,TMR1ON	; taimer seisma

return	; pöördume tagasi põhiprogrammi

Nipi kasutamisel jäävad vabaks enne kasutada olnud mälupesad cnt0...cnt3. Taimeri konfimiseks kirjutame koodi algusesse juurde rea:

; *** konfime viitetaimeri T1 ***

movlw	B'00110000'	; eeljagur 1:8, sisemine takt, taimer hetkel veel seisab

movwf	T1CON	; laeme taimeri juhtregistrisse.

Eelpool arvutatud taimeri laadimise numbrid teeme kompilaatorile ka teatavaks:

#define viiteaegH	0x0B	; määrab ära LED'i vilkumise kestuse

#define viiteaegL	0xDC	; sama

Taimeri loendussagedus tuleb, nagu öeldud, protsessorilt. Kuid juhtregistriga võib taimerit sundida loendama impulsse, mis saabuvad mõnelt väljaviigult. Sedaviisi saaks ehitada näiteks sagedusmõõturi. Kui panna 1 taimeritest andma ületäitumise signaali nt. iga sekundi tagant ja teine kirjeldatud viisilmõõdetava signaali impulsse lugema, saamegi aega määrava taimeri ületäitumisel loenditaimeri registris täpselt sagedusega (HZ-des) võrduva arvu. Muutes loendusaega, saab mõõta kõrgemaid sagedusi. Paraku ei piisa nüüd enam eespool õpitud võtetest sest prose ei saa niisama lihtsalt kahte taimerit korraga kontrollida. Õnneks on prosede tegijad sellele mõelnud ja leiutanud nähtuse nimega katkestused.

Katkestus tähendab seda, et teatud (neid peab eraldi lubama) sündmuste toimumisel jätab prose automaatselt senise programmi täitmise pooleli ja asub täitma teist koodi, mis algab (PIC16F628 puhul) alati aadressilt 0x004. Töö pooleli jätmise koha aadress seivitakse pinusse ja katkestusprogrammi lõppedes jätkatakse samast kohast, kus oldi enne erisündmuse toimumist. Nimetatud võimalus on väga mugav kuna enam ei pea põhikood jälgima sisendite, taimerite või muud vajaliku ja suvalisel ajal toimuda võivat sündmust. Kivi tegeleb põhitööga (nt. akvaariumi kontrolleris jälgib kella ning lülitab vastavalt sellele valgusteid) kuid mingi tähelepanu nõudva sündmuse toimumisel (veetase langes, temperatuur tõusis, kasutaja näpib klaviatuuri)siirdutakse automaatselt nende protsesside juhtimisele (antakse alarm või näppijale särakas vastu näppe ;) ).

Katkestus on mugav asi kuid võib oskamatul kasutamisel põhjustada segadusi. Kuna ta on kood nagu iga teinegi, peab ta kasutama mälu. Programmi kirjutamisel peab hoolega jälgima, et ei kasutataks samu mälupesi, mida põhiprogramm pruugib. Vastasel juhul võib katkestusproge nende sisu rikkuda ja kood jookseb kokku. Samuti tuleb kohe katkestuse alguses seivida prose tööregistri W ja staatust näitava registri STATUS sisu.

Katkestusi on mõistlik kasutada siis, kui programm peab reageerima suvalisel ajal toimuda võivatele sündmustele ja samal ajal veel „majapidamisega“ tegelema. Järjestikpordist tulevat infojada on hea töödelda katkestuse abil. Samuti sobib see trikk seadet toitva patarei pinge jälgimiseks.

Näide järjestikpordi, taimerite ja katkestustega.

Olgu meil vaja reguleerida enam-vähem sujuvalt 7 koormuse pinget. Koormusteks võivad olla alalisvoolu mootorid (nt. ventilaatorid) aga ka LEDid. Sujuvaks reguleerimiseks peab muutma koormusele jäävat pinget. Seda saaks teha kasvõi D/A-muundiga. Otseselt sellise triki jaoks PIC-is vahendid puuduvad kuid püüame kivi üle kavaldada.

Lisame eelmisele skeemile võimsa puhvri ja koormused mootorite ning LEDi näol.

PIC-i väljundeid saab seade vaid kahte seisu – pingele 0 ja pingele 5V (täpsemalt – niipalju kui toitepinge on). Tuleb välja, et sellest on enam kui küll. Muudame sujuvalt mitte koormuse pinget vaid keskmist võimsust. Selleks juhime koormust impulssidega. Olgu pulsside periood jääv. Muutes pulsi kestust, muutub koormusele jääv keskmine võimsus. Mida lühem pulss, seda väiksem võimsus ja seda aeglasemalt mootor pöörleb. Ja vastupidi. Täpselt see, mis vaja!

Mootorite kiirust saab muuta järjestikporti saabuvate käskude abil. Need saabuvad PIC-ile sisendi RS-232 kaudu. Järjestikpordi otsi muuta ei saa, vastuvõtt toimub alati viigul RB1 ja saade (kui vaja) viigult RB2. Kui tahame ühtegi neist otstest mujal kasutada, peab kogu serial-sidest loobuma. Igal asjal on oma hind :(

PIC-i kood antud näite jaoks on failis skeem3.asm. Tööpõhimõte peaks nüüd juba arusaadav olema (sidur, pidur, gaas !). Kommentaarid koodi juures aitavad kaasa.

Head PICutamist!

/Felch

Lisad

LCD ja piiksuja

LCD ja piiksuja juhtimise skeem

PICil on jalgu vähevõitu. Seepärast kasutame LCD-de võimalust anda 8-bitine käsk kahe 4-bitise poolena. Daata söödetakse LCD vanemate bittide pinnidele (D7..D4). Ekraani juhtimiseks tuleb vastav käsk või tähemärk daatasiinile anda määrates enne pinniga Rs (RegisterSelect) ära kas tegemist käsuga või kuvatava tähemärgiga. Kui kõik tehtud, laseme LCD-l info vastu võtta: teeme viiguga En (enable) impulsi.

IR-vastuvõtja

IR- vastuvõtja skeem on lihtne!

Vastuvõtul kasutatakse pordi B0 katkestust. Taimeriga mõõdetakse vastu võetud pulsside kestus ja võrreldakse lubatava/oodatavaga. Tavaline teleka pult pritsib infot välja Philipsi nn. RC-5 koodis. Koodi algus sisaldab juhitava seadme aadressi. Järgneb käsu kood.

Näidisprogramm dekodeerib aadressiga 0 saadetud käsu (kanali nuppude vajutamise) ja paneb vastava LED-i põlema.

RC-5 vastuvõtja koodi põhiosa ei ole minu mõeldud, kasutasin teiste loomingut ja porteerisin algoritmi PIC16F628-le.

Veljo Sinivee

2005-08-21T13:36:31