AVR62: išsamiau

Buvo toks komentaras:

Būtų labai šaunu jeigu šitą straipsnį išplėstum ir padarytum kažką panašaus į “Levas for dummies’. T.y. nieko arba mažai ‘raukiantiems’ paaiškintum daugiau apie jungtis, kaip sąveikauja plokštės elementai vienas su kitu, koks ten softas naudojamas, kodėl būtent jungi tą su anuo ir t.t.

Net nežinau nuo ko pradėti. Gal pradesiu nuo ideologijos. 🙂 Man nepatinka Arduino mintis- kad ‘dummiai’ pasiima kažkokią overpriced plokšte ir net nežinodami kaip kas veikia pradeda programuoti kažkokia iškreitpta makrosais kalba. AVR serijos mikroschemos yra labai jau low-level, todėl reikia programuoti viską nuo pradžių arba bent išsinagrinėti kaip kas veikia, kad netyčia nesigautu hardwarinių konfliktų.
Mano softas irgi susideda iš modulių, tačiau tai grynas C ir jį žymiai lengviau konvertuoti kitam procesoriukui. Ta patvirtino eksperimentas su ARMu.
Mano naudojami moduliai promityvūs, dažniausiai surasti internete. Nėra jie tokie optimalūs ar teisingi, bet tikrai lengvai suprantami jei jau yra pradinės programavimo žinios.
Tačiau ką aš galėčiau pasakyti “for dummies”? Manau, kad nelabai ką. Kaip programuojasi čipas? Nu naudojam iš eBay nupirkta programatorių (usbasp). Programavimo softas? Avrdude. Pačio čipo programavimo softas? Nemokamas iš interneto- WinAVR paketas (kuris jau senai nepalaikomas, avr-gcc (WinAVR 20100110) 4.3.3).

Gal parašyti kaip aš pradėjau kurti šį projektą? Gerai. Tik neaiškinsiu kaip kuriau hardwarę.

Pirmiausiai, pagal esamą hardwarę reikia užsiprogramuoti mikroschemos kojytes. Ant pačios plokštės jau pajungtos kelios detalės- tai RS485, RTC, raktas ir drėgmės-temperatūros jutiklis.
Pas AVRą kojos turi po kelis panaudojimus- bendrinis I/O dažnai dubliuojamas su specialiom užduotim. Todėl UARTas pririštas prie tam tikrų kojų. Todėl RS485 prijungiam prie UART kojų ir dar panaudojam artimiausią koją duomenų krypčiai valdyti. Taip susinaudojo PD0, PD1 ir PD3.
RTC (real time clock) laikrodukas yra I2C protokolo mikroschema (Holtekai kuriuos anskčiau naudojau- yra supaprastinti, todėl jungiasi bet kur, tačiau reikia visą protokolą rašyti softe). Dar laikrodukas turi aliarmo išėjmą kuris gali dirbti kaip žadintuvas arba tick signalas. Todėl šiai mikroschemai reikia I2C kojų (PC4 ir PC5) bei kojos su kuria galima sužadinti procesoriaus pertraukimą- šiuo atveju aš pasirinkau INT0. Taip susinaudojo PD2 koja.
Temperatūros ir drėgmės sensorius DHT11 naudoja tik vieną koją informacijos perdavimui. Ir tai grynai softwarinis sprendimas, todėl pasirinkau artimiausią laisvą koją- PD7.
Softe nenaudojamas raktas IPS511G pajungtas prie PD4 ir PD5. Pajungtos kaip standartinės I/O kojos.

Dabar mums reikia pajungti Nixių bloką. Lempos turi 10 segmentų kurie valdomi per dešifratorių. Taip sumažėja kojų iki 4. Pačių lempučių gali būti iki 6 vienetų. Čia reikia dar 6 kojų arba jungti per papildomą mikroschemą- SER/PAR keitiklį (tada bet kokiam lempų kiekiui užtektu 2 laidų). Tačiau šioje schemoje lempos jungiasi “tiesiogiai” prie procesoriuko ir jų pasirinkimas grynai programinis.
Teoriškai galima pasinaudoti bet kuriom laisvom kojom, tačiau atsitiktinių kojų pasirinkimas padaro programą labai sudėtingą.
Keturis bitus naudojamus lempų segmentams paėmiau iš eilės- PORTC pirmus 4 bitus. Dabar, kad paduoti lempos segmento kodą užtenka tiesiogiai į pusę porto įrašyti vieną niblą.
Maždaug taip: PORTC=pozicija & 0x0F;
Tai kiek nekorektiška vyresnio niblo atžvilgiu, nes vyresni bitai pildomi nuliais, tačiau mano softe ir hardwarėje ten yra tik I2C SDA ir SCL bei du ADC. I2C tvarkosi bitus savo laiku ir paprastai ten yra įėjimas su išorinių pull-up. Tai mano komanda įnulinti šias kojas netrukdo. O ADC ten ir taip stovi visada į nulį.
Tačiau, jei tos kojos būtų naudojamos kam nors dar, tektu kiek pavargti- nusiskaityti registro vidinę būklę ir atitinkamai keisti tik leidžiamus bitus. Kažkas tokio:
tmp=PORTC & 0xF0; //nuskaitom baitą ir išvalom jaunesnį niblą.
PORTC=tmp | (pozicija & 0x0F); // paimam pozicijos jaunesnį niblą, pridedam prie seno vyrensio niblo ir dedam atgal į portą.

Dabar pačios lempos pasirinkimas- pasinaudojam laisvu portu B. Ten mums kaip tik lieka 6 laisvi bitai. (6 ir 7 nenaudojami- ten stovi kvarcas). Todėl reikiamos lempos bitas programuojamas tiesiogiai.

Kai visos kojos žinomos, atitinkamai suprogramuojamas procesoriaus I/O registras(-ai). Tam ir naudojamos DDRn komandos. Mūsų atvejų:
DDRB= visi leidžiami bitai, nuo 0 iki 5.
DDRC=15, t.y. visas mažasis niblas. Dėl spec kojų nesivarginam, universalūs moduliai susitvarkys savo kojas korektiškai.
DDRD= mano schemoje užprogramuotos taip, kad veiktu RS485 kryptis ir dar vieną koją naudojau debuginimui. Kad ten “pamirgėti” ir pamatuoti kai kurių procesų veiklą (makrosas TEST_TOGLE ). DHT11 čipas tą pačia koją naudoja tiek siusti tiek priimti duomenim. Todėl šios kojos kryptis dažnai perprogramuojama DHT11 modulio. Jo autorius ir žino kaip tai padaryti 🙂

Kai susitvarkėm su kojom, reikia užprogramuoti vidinius įrenginius. Mums reikia taimerio, I2C, išorinio pertraukimo ir jei reikia UARTo.
UARTą ir I2C užprogramuoja “canned” paprogramės iš senesnių projektų. Jos beja beveik ne mano rašytos.

O štai taimerius ir INT0 reikia užrpgramuoti rankutėmis.
Taimerį panaudojau patį paprasčiausią- 8 bitų “overflow” t.y. kai tik taimerio skaitliukas persirita per max reikšmę iškviečiama paprogramė. Registras TCCR0 aprašo ant kiek dalintą clock signalą naudojam maitinti taimeriui, o registru TIMSK įjungiam taimerio suveikimą.

Pertraukimas pagal signalą ant INT0 programuojamas irgi paprastai- vienas registras nurodo, kokia tipo pasikeitimas sukels pertraukimą, kitas registras įjungia tą pertraukimą.

Dar, aš užprogramavau ADC per koją 6 ir ADC pabaigos pertraukimą- aš per ten nuskaitinėsiu mygtukus. Tačiau pavyzdiniam softe to nėra.

Ir įjungiam pertraukimus komanda sei().
Visa šita inicializacija sudėta į paprogramę inithardware(). Paprasčiausiai, kad programa būtų lengviau suskaitoma ir inicializacija nemaišytu pagrindinei programai. Pakeliui ten surašytos komandos kurios užprogramuoja RTC mikroschemą- tai yra paleidžia jos generatorių ir užprogramuoja jos išėjimą 1Hz signalui.

Paleidus programą ir jei viekia RTC turėtume gauti 1Hz pertraukimus (kas pusę sekundės) pagal INT0 ir net nežinau kokio dažnio greitus pertraukimus pagal taimerį.

Taimerio overflow (ISR(TIMER0_OVF_vect) pertraukimo aptarnavimo paprogramė bus atsakinga už dinaminę indikaciją. Kiekvieno pertraukimo metu, mes pasirinksim vieną lempą ir ją uždegsim pagal “video atminties” turinį. Video atmintis tai trijų baitų masyvas- po vieną niblą kiekvienai lemputei. Ten gana paprasta matematika ir globaliniai kintamieji leidžia viską atlikti gana greitai.
Programoje likę sei() ir cli() nereikalingi, čia jie išliko iš kitos softo vietos, tai aš analizavau visai kitą softo veikimo ideologija ir pamiršau ištrinti. Jie netrukdo. Pats segmento pasirinkimo algoritmas toks kreivas nes kažka ne taip sumasčiau. Viską ten galima padaryti paprasčiau- arba perkelti kelis lempos sujungimo laidus arba rasti tą bugą 🙂 Tačiau tai tik softo eskizas.
Dabar paleidus programą net be RTC laikrodžio turi užsidegti nixie lempos ir jos rodytu video atminties turinį (mano atveju 123456).

Kitas pertraukimas gauna signalą iš RTC, sinchronizuota su laikrodžiu. Čia INT0 pertraukimas (ISR (INT0_vect)) nuskaito per I2C laikrodžio kelis registrus. Galima nuskaityti laikrodžio visą atmintį. Aš pasitenkinu arba 2 ar 3 baitais. Nuskaitai sekundes, minutes (ir dar valandas). Toliau per jėga sukeliu I2C STOP komandą.
Dar 1Hz greičiu iškviečiams ADC kuris nuskaito mygtukų būklę. Kai tik bus paruoštas ADC rezultatas, ADC pertraukimas atliks reikiamus skaičiavimus. Taip mes nuskanuojam mygtukas du kartus per sekundę. (gal kiek per retai)
Pakeliui, kas maždaug 2,5 sekundes pažymiu “softwarinio pertraukimo” žymę.
Kam to reikia? Todėl, kad nėra prasmės dažnai nuskaityti drėgmės parodymus. Praktiškai galima skaityti dar didesniais intervalais. Dar vienas momentas- DHT11 skaitymas grynai programinis ir labai lėtas. Jei tą skaityma daryti kokiam nors pertraukime, algoritmo veikimo metu trumpam užgęstu viena iš nixie lempų. Todėl ir imituojamas “low level software interupt”. Tai paprasčiausia paprogramė kuri iškviečiama iš dar nenaudoto pagrindinio programos ciklo ir tą paprogramę gali pertraukti visi kiti pertraukimai (ką jie ir sėkmingai daro). DHT11 nėra labai jautrus skaitymo intervalų tikslumui ir mano naudojamų pertraukimų laikai neiškraipo parodymų.

Nuskaitėm laiką, nuskaitėm drėgmę, nuskaitėm mygtukus, indikuojam vaizdą. Dabar belieka tik parašyti pačio laikrodžio valdymą ir kitą “human interface”. Tam ir mums liko pagrindinis programos ciklas, kuri “amžinai” sukasi programos main for(;;) cikle.

Ar atsakiau į komentaro klausimą? Nu gal biški aiškiau kaip čia viskas veikia ir kaip aš čia suprogramavau. Realiai programavimas perėjo keletą neteisingų etapų- pvz. indikacijos ciklas buvo pagrindiniam cikle. Dar buvau neteisingai supratęs indikacijos valdymą per kondikus ir biški per daug prigudravau su “kintamos” įtampos generavimu. Tas privedė prie “ghost” indikacijos, su kuria dar buvo kovojama neteisingom priemonėm. Buvo ir kitokių klaidų. Ir tikriausiai dar liko. Kad ir tos nereikalingos komandos ar du kartus tas pats užprogramuotas registras.

8 replies on “AVR62: išsamiau”

  1. Dėkui už išsamų straipsnį ir paaukotą laiką jam parašyti.

    Aiškiau, bet iki “aišku” dar toli. Dabar jau mano eilė kabintis už nežinomų terminų, akronimų ir gilintis pačiam.

  2. Dėl Arduino nevisai pritariu… jei jo nebūtų, tai daugybė žmonių realiai net ir nepasinertų į mikrovaldiklių pasaulį — bo ta „hardkorinė“ pradžia yra nelengva. Aš irgi pradėjau nuo superbrangaus Arduino, o dabar SMD Atmegas lituoju ir registrais žongliruoju. Vienok, be Arduino turbūt nebūčiau pradėjęs. Užtai dabar ARM tyrinėjimas su datašytais nebebaisus, nes vienas kelias jau praeitas.

  3. Tačiau procentaliai kiek tokių žmonių kaip Saulius, kuris nepatingėjo pažiūrėti kas slepiasi už arduino makrosu? O kiek žmonių atsirėmė į tai, kad užduočiai neužtenka esamų resursų ir perka didesnį procesoriuką? Nes visiškai neįdomu kaip ten iš tikro viskas veikia.
    Poto prasideda kad “mirksiukui” reikia linux ar kokio nors kitokio OS?

Leave a Reply

Your email address will not be published. Required fields are marked *