2014 m. lapkričio 26 d., trečiadienis

AVR mikrovaldiklių programavimas: nuo ko pradėti II


Pats pirmas mano straipsnis apie mikrovaldiklius buvo "AVR mikrovaldiklių programavimas: nuo ko pradėti?", kurį parašiau norėdamas pirmiausia sau priminti visą seką pasiruošimo, reikalingo norint programuoti mikrovaldiklius - patirties buvo mažiau, o mano tokiems projektams būdingos pertraukos, galinčios trukti ir pusmetį. Ir po pusmečio grįžus prie mikrovaldiklio programavimo turėti viską po ranka buvo patogu.Tačiau tas straipsnis iš tikro neatliko savo pagrindinės funkcijos - supažindinimo su pasiruošimu, programavimu ir programos įkėlimu į mikrovaldiklį tiek, kiek turėjo - dėl to supratimo esu dėkingas savo žmonai, kuri paskaitė tą straipsnį. Todėl pabandysiu parašyti antrą straipsnį apie pačią pradžią. Tikiuosi, kad pavyks išbalansuoti ant per didelio gilinimosi ir per didelio paviršutiniškumo ribos. Kaip visada - jei turite pastabų, aš jų lauksiu komentaruose.
Kai kurie dalykai gali kartotis, tačiau ano straisnio visgi netrinsiu. 

KAIP TAI ATRODO?
Pabandysiu paprastų piešinukų pagalba parodyti struktūrą, kaip tai vyksta. Pirmas programavimo etapas - programos teksto (programos kodo) rašymas. Beje, čia kalbėsiu tik apie programavimo C kalba specifiką. Tam reikalinga programavimo aplinka, kurioje tą kodą būtų galima parašyti, išsaugoti, patikrinti, ar nėra klaidų, o tada sukompiliuoti. Mano aptariamu atveju situacija atrodys taip:

Programinė aplinka, pavaizduota debesėliu - ATMEL, gaminančios mikrovaldiklius, produktas AVR studio, beje, visiškai nemokamas (rekomenduoju naudoti seną, 4 versiją - veiks greičiau, o papildomų funkcijų kol kas kaži ar prireiks). Šioje aplinkoje turi būti įvedamas programos kodas - tai pati matomiausia programinės aplinkos dalis. Įvedus norimą programos kodą, t.y. tam tikrą mikrovaldiklio veiksmų tvarką aprašantį tekstą, iškviečiamas kompiliatorius, kurio paskirtis - "apdirbti" C kalbos kodą. Visa tai yra dėl to, kad mikrovaldiklis nesupranta C kalbos teksto tiesiogiai, todėl jo įrašyti nepavyks. Mikrovaldikliui suprantamos tik kita, asemblerio kalba parašytos instrukcijos, kurios programos vykdymo metu nuskaitomos paeiliui. Todėl naudojamas kompiliatorius - vertėjas, kuris programos tekstą, parašytą C kalba "išverčia" į asemblerio komandas mikrovaldikliui, ir tas komandas surašo į specialų failą šešioliktainiu formatu. Programinė aplinka sukuria failą su plėtiniu .HEX, į kurį paeilui ir surašomos asemblerio komandos mikrovaldikliui. Šio failo turinys paprastai nėra lengvai perskaitomas žmogui, skirtingai nuo C kalbos kodo, tačiau puikiai suprantamas mikrovaldikliui.
Sekantis žingsnis - šį asemblerio komandų rinkinį įrašyti į mikrovaldiklio atmintį. Šiai užduočia reikia fizinio įrenginio - programatoriaus, kuris komandų HEX failą įrašytų į mikrovaldiklio programinę atmintį, t.y. ten, iš kur įjungtas mikrovaldiklis paeiliui galėtų skaityti instrukcijas ir jas vykdyti. Pati AVR studio programa gali atlikti šią užduotį tik su tokiu programatoriumi, kurio aš dar nepasigaminau, todėl aprašinėsiu kitą kelią :) Naudosiu programą AVRDUDE bei programatorių USBtiny.
Štai kaip tai atrodys:

AVRDUDE programa per prijungtą programatorių visą mūsų jau parašytą ir sukompiliuotą programą įkelia į mikrovaldiklio FLASH atmintį. Baigus programavimą mikrovaldiklis yra paleidžiamas iš naujo (RESET), ir procesorius iš tos atminties pradeda skaityti įrašytas instrukcijas. Visas tolesnis mikrovaldiklio veikimas priklauso nuo instrukcijų, žinoma, iki kito RESET.
Programos įrašymo į mikrovaldiklį būdas ir naudojama programa priklauso nuo programatoriaus pasirinkimo. Galima nusipirkti jau pagamintus, dauguma iš jų veiks tiesiogiai per AVR studio programinį paketą. Žinoma, galima ir pasigaminti, tačiau veikiantį per AVR studio tiesiogiai padaryti sudėtingiau. Artimiausiuose mano planuose yra programatorius PROTTOSS, kuris veikia iš AVR studio tiesiogiai, tačiau kol kas naudoju USBtiny, kuris veikia puikiai, o ir pasidaryti visai nesudėtinga - šiek tiek info kitame mano straipsnyje. Tačiau naudojant jį teks naudotis AVRDUDE programa, kuri valdoma komandine eilute. Iš pirmo žvilgsnio komandinė eilutė nėra patogu, tačiau pradėjus naudotis negaliu labai skųstis - keletą kartų perprogramuojant mikrovaldiklį visą tekstą suvesti reikia tik kartą, paskui komandinėje aplinkoje spaudžiant rodyklės į viršų klavišą tiesiog išsikviesti paskutinę naudotą komandą.

MIKROVALDIKLIO JUNGIMAS
Visur rasite, kad pačią pirmąją programą smagiausia pradėti nuo šviesos diodų mirksinimo, ir aš su tuo visiškai sutinku. Labai smagu matyti, kaip komandos programavimo aplinkoje virsta apčiuopiamais ir matomais rezultatais.
Pradžiai siūlyčiau nusipirkti ATmega8 mikrovaldiklį, prie kurio dar reikės vieno 10K rezistoriaus ir vieno 0.1mF kondensatoriaus. Naujas mikrovaldiklis veiks nuo vidinio generatoriaus 1MHz dažniu, t.y. vykdys atmintyje esančias instrukcijas milijono instrukcijų per sekundę greičiu. Pradžiai tokio greičio užtenka, o ir schema paprastesnė. Papildomai reikės 8 šviesos diodų (LED) ir 8 rezistorių, kurių nominalas 1K. Žinoma, be jų galima apsieiti, bet tada nepavyks pamatyti programos veikimo.
Mikrovaldiklis su pasauliu bendrauja per prievadus (PORTS) - iš mikrovaldiklio perspektyvos šie prievadai yra mygtukai, kurie gali būti programiškai įjungiami arba išjungiami, o iš mūsų perspektyvos - tai yra tiesiog mikrovaldiklio mikroschemos kojos, prie kurių gaime jungti kažkokius prietaisus. Paprasčiau tariant, mikrovaldiklis su išoriniu pasauliu bendrauja būtent per prievadus. Prievadų pavadinimai AVR mikrovaldikliuose žymimi raidėmis: PORT A, PORT B, PORT C, PORT D ir PORT E. Jų kiekis priklauso nuo mikrovaldiklio modelio, konkretų skaičių galima sužinoti susiradus mikrovaldiklio aprašymą (datasheet). Kiekvienas prievadas turi aštuonias duomenų linijas, t.y. aštuonios kojos mikroschemoje. Kiekviena prievado koja gali būti nepriklausomai viena nuo kitos nustatyta veikti kaip įėjimas arba išėjimas.
Šiam straipsniui nupaišiau schemą, kurioje diodams prijungti panaudotas PORT D prievadas - prie kiekvienos šio prievado kojos prijungtas šviesos diodas, o srovei riboti jis jungiamas per 1K rezistorių. Prievado kojos atskirai žymimos PD0...PD7, kur skaičius atitinka bito numerį - įjungiant bitą šiame prievade LED užsidegs, išjungiant - užges.
Dešinėje - ISP (In-System programming) programatoriaus prijungimas fiziniam mikrovaldiklio prijungimui prie programatoriaus.

Maitinimas tokiai schemai - 5v įtampa. Galima naudoti reguliuojamus maitinimo blokus, jei neturite tokios įtampos maitinimo blokų. Taip pat galima naudoti įtampos stabilizatorių su 7805 mikroschema. Iš kompiuterio USB irgi galima pasiimti +5V maitinimą iki 0,5A, tik su tuo būdu reikia atsargiai, nes nesunku sugadinti ir visą kompiuterį.

PROGRAMAVIMAS
Programų instaliavimo neaprašinėsiu, tik pastebėsiu, kad prieš instaliuojant AVR studio reikia instaliuoti WinAvr programą. Tai aprašiau pirmame straipsnyje, ten irgi rasite nuorodas.
Įjungus AVR studio programą, klausiama, ar sukurti naują projektą, ar naudoti išsaugotą. Kadangi kol kas išsaugotų nėra, pasirenkame "NEW PROJECT". Sekantis žingsnis - pasirinkti programavimo kalbą, pasirenkame "AVR-GCC", įvedami projekto saugojimo vietą ir pavadinimą ir galima spausti FINISH. Jeigu paspaustumėte ne FINISH, o NEXT, būtų galima pasirinkti programatorių arba simuliatorių, tačiau kol kas jo nereikia.
Į esamą langą kopijuojame tokį programos tekstą:

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

int main() {

DDRD=0b11111111; // PORT D visi astuoni bitai nustatomi kaip isejimai

while(1) {
  PORTD=0b11111111; // ijungiami visi PORT D bitai
  _delay_ms(500); // laukia 500 ms
  PORTD=0b00000000; // isjungiami visi PORT D bitai
  _delay_ms(500); // laukia 500 ms 
  }
}

Ši programa kas pusę sekundės įjungs ir išjungs visus šviesos diodus. Laiko skaičiavimui bus naudojama delay.h biblioteka, tačiau tai tik viena iš galimybių - galima daryti nieko neveikiantį ciklą uždelsimui.

12
#include <avr/io.h> #include <util/delay.h>


Šiose eilutėse nurodoma programavimo aplinkai naudoti įejimo išėjimo bibliotekas ir laiko skaičiavimo (uždelsimo) biblioteką. Kol kas gilintis į tai nereikia, tereikia žinoti, kad yra daug visokių standartinių ir internete bendruomenės sukurtų bibliotekų, kurios palengvina gyvenimą programuotojui.
5
DDRD=0b11111111; // PORT D visi astuoni bitai nustatomi kaip isejimai
Ši komanda nurodo procesoriui, kad visus prievado D bitus naudoti kaip išėjimą. Nors gal sakyti, kad taio "komanda" kiek neteisinga - DDRD yra prievado D valdymo registras, į kurį įrašomas skaičius, pagal kurį mikrovaldiklis nusprendžia, kaip veiks prievadas. Rašiau priskyrimą dvejetainiais skaičiais - taip lengviau matyti, kurie bitai yra įjungiami, kurie išjungiami. Šios komandos atveju (DDRD - Data Direction poRt D) įjungtas bitas nustato prievado bitą kaip išėjimą, išjungtas - kaip įėjimą. Pvz., priskyrus skaičių 0b11110000 pusė prievado bitų bus nustatyti kaip įėjimai, pusė - kaip išėjimai. Tačiau lygiai taip pat galima priskirti ir dešimtainį skaičių 255 - tai nieko nepakeis, programa veiks identiškai, tik akivaizdžiai nesimatys, kurie bitai įjungti, kurie išjungti.
7
while(1) {
Pradedamas amžinas ciklas - jo viduej vykdomos komandos, o kai jos pasibaigia, pradedamos vykdyti iš naujo. Programavimo pagrindų čia neaprašinėsiu, nes ne tokia šio straipsnio paskirtis.
891011
  PORTD=0b11111111; // ijungiami visi PORT D bitai  _delay_ms(500); // laukia 500 ms  PORTD=0b00000000; // isjungiami visi PORT D bitai  _delay_ms(500); // laukia 500 ms
8 eilutėje jau pradedamas LED junginėjimas. Prievado bitai įjungiami arba išjungiami prievadui priskiriant skaičių, kurio konkretus bitas yra įjungtas, arba išjungtas - ypač akivaizdžiai tai matosi priskiriant dvejetainius skaičius. Šiuo atveju priskiriamame skaičiuje 0b11111111 visi bitai yra įjungiami. Pavyzdžiui, priskiriant skaičių 0b10101010 būtų įjungiamas kas antras bitas, t.y. atitinkamai įjungiamas kas antras LED.
9 ir 11 eilutėse vykdoma uždelsimo komanda, nurodant laiką milisekundėmis. Galima nurodyti ir mikrosekundėmis, tada komanda bus _delay_us([laikas]);, raidė prieš "s" - u (upė), nes "mju" raidė, reiškianti "mikro" nenaudojama.
10 eilutėje prievadui priskiriamas skaičius 0b00000000, t.y. visi bitai išjungiami.

KOMPILIAVIMAS
Parašius programą, ją reikia sukompiliuoti. AVR studio meniu Build>Build arba spausti F7. Jeigu nepadaryta jokių klaidų, programos lango apačioje atsiras šiek tiek teksto, kurio pabaigoje turi būti parašyta "Build succeeded with 0 Warnings...". Tai reiškia, kad kompiliatorius nerado jokių klaidų programos tekste, ir kad HEX failas yra sukurtas.
Kataloge, kuriame išsaugotas mūsų projektas, turėjo atsirasti katalogas "DEFAULT", o jame tarp kitų failų turi būto failas su plėtiniu .HEX, o pavadinimas - toks pat, kaip ir projekto pavadinimas. Šis failas ir yra tas, kurį reikai įrašyti į mikrovaldiklio atmintį programatoriaus pagalba.

PROGRAMOS ĮKĖLIMAS
Atsidarome komandinę eilutę (Command prompt) - Start Menu rašydami CMD ir spausdami Enter. Komandinėje eilutėje susirandame katalogą, kuriame išsaugotas projektas, ir einame į kataloge "DEFAULT". (Katalogo pasirinkimas komandinėje eilutėje vykdomas komanda cd [katalogas])


Jeigu programatorius teisingai prijungtas prie mikrovaldiklio ir prie kompiuterio, galima bandyti, ar avrdude programa pasiekia mikrovaldiklį.
Komanda atrodo taip: avrdude -p m8 -c usbtiny


Jeigu rezultatas toks pat, kaip šiame paveikslėlyje - mikrovaldiklis pasiekiamas, galima rašyti HEX failą  į mikrovaldiklio atmintį. -p m8 nurodo mikrovaldiklio modelį, -c usbtiny nurodo programatoriaus modelį.
Rašymas į mikrovaldiklio atmintį vykdomas panašia komanda su papildomai nurodytais duomenimis: 
avrdude -p m8 -c usbtiny -U flash:w:"projektas.hex":i
Tekstas po -U nurodo, kad reikia naudoti mikrovaldiklio flash atmintį (flash), kad reikia rašyti į ją (w), failo pavadinimą ir formatą (:i), šiuo atveju intel hex formatą.

Jeigu komandinėje eilutėje atsirado toks tekstas, programa sėkmingai įrašyta į mikrovaldiklio atmintį ir patikrinta. Jeigu LED teisingai sujunginėti - turėtų mirksėti.
Čia aprašiau tik prievadų naudojimą duomenims išvesti. Jei netingėsiu, artimiausiu metu parašysiu įvesties naudojimą. Sėkmės :)

***
Papildymas:
Bandant AVRStudio 4.19 ir naudojant Windows 8.1 OS, kilo dvi problemos. Tiesą sakant, pirma buvo jau žinoma - tai AVRStudio nesugebėjimas automatiškai rasti AVR Toolchain - visokių papildomų programėlių, kurios įdiegiamos kaip WINAVR paketas. Reikėdavo kaskart naujam projektui nurodyti kelią iki avr-gcc.exe (c:\WINAVR\bin) ir make.exe (C:\WINAVRxxx\utils\bin). Pasirodo, ši problema tik 4.19 versijoje. Naudojant 4.18SP3 AVRStudio versiją šios problemos nebelieka - programa pati susiranda įdiegtą WINAVR paketą.
Kita bėda - kompiliuojant atsirandanti klaida apie nerastsu failus. Ištaisymas - į c:\WINAVRxxx\utils\bin reikia nukopijuoti dll failą - http://www.madwizard.org/download/electronics/msys-1.0-vista64.zip

2 komentarai:

  1. sveikas,

    turiu keleta ATMEGA32A, gal zinai kodel vieni ju, esant 3.3v maitinimui, UART'u siuncia gera tvarkinga teksta ,kaip priklauso, o pajungus 5v tekstas iskraipomas, siuncia neaiskius simbolius?

    ka padaryt kad jis tvarkingai veiktu esant 5v?

    aciu

    AtsakytiPanaikinti
    Atsakymai
    1. Nesu susidūręs su tokia problema, tačiau vienas iš variantų - priimanti pusė gal veikia kitais įtampos lygiais? Arba perdavimo schema (buferis etc.) nekorektiškai veikia nuo kitokios įtampos? Jei labai gilintis - galima būtų žiūrėti su loginiu analizatoriumi (http://www.ebay.com/itm/New-USB-Logic-24MHz-8Ch-Logic-Analyzer-for-ARM-FPGA-/271716215743?hash=item3f438c6bbf:g:W3sAAOSwg3FUl8r- ).

      Panaikinti