A mikrokontrollerek programozásának sorrendje avr. avr mikrokontroller programozás

Jó napot kedves rádióamatőrök!
Üdvözlöm a "" oldalon

Mi az a mikrokontroller és miért van rá szükség. Nézzük a definícióját:

- elektronikus eszközök vezérlésére tervezett mikroáramkör, vagy más módon - egyszerű számítógép (mikroszámítógép), amely képes egyszerű feladatok elvégzésére.

Azaz valójában a mikrokontroller egy olyan eszköz, amivel megvalósíthatjuk elképzeléseinket (akár őrülteket is), de természetesen a lehetőségein belül. És ami a legfontosabb, egy ötlet megvalósítását nem kifinomult elektronikus struktúrák létrehozásával érjük el, hanem alapvetően csak gondolataink erejével (szeretnél varázsló lenni?).
A rádióamatőrök körében a legnépszerűbb kétféle mikrokontroller:
PIC- Mikrochip technológia
AVR- Atmeltől

Szeretnék egy rövid kitérőt tenni, és tisztázni az egyik álláspontomat. Nem fogok az ilyen típusú mikrokontrollerek, az ilyen vagy olyan szoftverek és általában a mikrokontrollerekkel kapcsolatos dolgok előnyeiről tárgyalni, hogy tanácsot adjak, és még inkább, hogy rákényszerítsem az olvasókat. Mindez ízlés, személyes preferenciák és a mikrokontrollerek tanulásának végső céljaitól függ. Nos, mivel „a mérhetetlenséget nem lehet magáévá tenni”, minden további narrációmat az AVR mikrokontrollerekkel és a nem túl gyakori, de kedvencem, az „Algoritmusépítő” programmal kapcsolatban fogom levezetni. A különböző típusú mikrokontrollereknek, programoknak természetesen vannak különbségei, de sok közös is van bennük. A mikrokontrollerek világát pedig úgy tanuljuk meg, hogy a későbbiekben a megszerzett tudást gond nélkül alkalmazni lehessen PIC-ekre és bármilyen szoftverre. És hadd emlékeztesselek még egyszer arra, hogy ez a cikksorozat az a kísérletem, hogy segítsek azoknak, akik először hallottak a mikrokontrollerek létezéséről, és szeretnének megérteni, hogyan kell velük dolgozni.

Mire van szüksége a mikrokontrollerekkel való munkavégzéshez? Véleményem szerint néhány fő feltételt emelnék ki:
1. Vágy és kitartás .
Itt minden nagyon egyszerű: van vágy - minden sikerülni fog. És a vágy a kitartással általában szuper dolog.
2. A mikrokontroller eszköz ismerete.
A mély tudás itt nem fontos (és lehet, hogy egyáltalán nem is), de tudni kell, hogy mi van a mikrokontrollerben. Csak annak tudatában, hogy miből áll a mikrokontroller, milyen eszközei vannak, milyen képességei vannak, hogyan működnek – csak akkor tudjuk a mikrokontroller képességeit maximálisan kihasználni.
3. A programozási nyelv és a mikrokontroller vezérlőparancsainak ismerete.
A mikrokontroller működését, milyen feladatokat rendel hozzá, és hogyan fogja azokat végrehajtani, a beleágyazott program határozza meg - az a program, amelyet Ön saját maga állít össze a mikrokontroller számára. Ezen a ponton pedig részletesebben fogunk foglalkozni, hogy megvizsgáljuk a jövőben felmerülő kérdéseket.

Program(fordításban ez a szó „előírást” jelent) - a közelgő események vagy akciók előzetes leírása.

Például azt akarjuk, hogy a mikrokontroller villogjon egy LED-en. Egy egyszerű feladat, de ahhoz, hogy a mikrokontroller elvégezhesse ezt a feladatot, először lépésről lépésre le kell írnunk a mikrokontroller összes műveletét, írnunk kell egy programot, amelyet végre kell hajtania, hogy megkapja a kívánt eredményt - egy villogó LED-et. . Valami ilyesmi:
♦ A LED világítása:
- konfigurálja azt a kimenetet, amelyhez a LED csatlakozik, hogy az információ kimenetén működjön
- alkalmazzon logikai szintet erre a tűre, amely lehetővé teszi a LED megvilágítását
♦ Várj egy kicsit:
- lépjen a szünetet képző szubrutinra (amit szintén „rá kell rágni”)
- a szünet szubrutin befejeztével térjünk vissza a főprogramhoz
♦ Kapcsolja ki a LED-et:
- logikai szintet alkalmazni a kimenetre, kioltva a LED-et
stb.
kifejezéssel Program egy másik kifejezés elválaszthatatlanul összekapcsolódik - Algoritmus(mint a Farkas és a nyúl, Tom és Jerry).

Algoritmus- utasításkészlet, amely leírja a kívánt eredmény elérésének eljárását.

Ha a programban vagyunk a legrészletesebben intézkedéseket ír elő mikrokontroller, akkor az algoritmusban mi meghatározza a cselekvés menetét mikrokontroller, ami alapján majd készítünk egy programot. Hasonló a fenti példához:
♦ Gyújtsa be a LED-et
♦ Várj egy kicsit
♦ Kapcsolja ki a LED-et
stb.
Ily módon az algoritmus a program előfutára. És minél körültekintőbben és átgondoltabban hozunk létre egy algoritmust, annál könnyebb lesz egy programot létrehozni.

Összességében a mikrokontroller programja a mikrokontroller műveleteinek sorozata, parancsok és utasítások halmaza formájában, amelyeket végre kell hajtania céljaink elérése érdekében.

A mikrokontroller parancsai egyesek és nullák halmazának tűnnek:
00110101 011000100
úgy hívják - parancskódok, a parancskódok pedig az a nyelv, amelyet a mikrokontroller megért. És annak érdekében, hogy az algoritmusunkat oroszról a mikrokontroller nyelvére lefordíthassuk - ezekre a nullák és egyesek készleteire, speciális programok vannak.
Ezek a programok lehetővé teszik, hogy egy számunkra többé-kevésbé érthető nyelven leírjuk a mikrokontroller munkarendjét, majd ezt a sorrendet lefordítsuk a mikrokontroller számára érthető nyelvre, ami az ún. gépi kód- parancsok és utasítások sorozata (a nullák és egyesek), amelyeket a mikrokontroller csak megért. A programozó által írt program szövegét ún forráskód. A program le van fordítva a programozási nyelvről (forráskód) a mikrokontroller nyelvére (gépi kód) fordítók. A fordító a programszöveget gépi kódokká alakítja, amelyeket aztán a mikrokontroller memóriájába írnak.
Az ilyen programokban a mikrokontroller működési sorrendjét egy speciális nyelv írja le - a programozási nyelv. A programozási nyelv különbözik a mi emberi nyelvünktől. Ha a kommunikációs nyelvünk elsősorban az információcserét szolgálja, akkor:

Programozási nyelv - ez a parancsok, utasítások továbbításának módja, egyértelmű cselekvési útmutató a mikrokontroller számára.

Számos programozási nyelv létezik, és két típusra oszthatók:
alacsony szintű programozási nyelvek
magas szintű programozási nyelvek
Mi a különbség. És különböznek a mikrokontrollerhez való közelségükben.
A mikroprocesszoros technológia megjelenésének hajnalán a programokat gépi kódokban írták, vagyis a teljes munkaalgoritmust egymás után nullák és egyesek formájában írták fel. Így nézett ki a program:

01000110
10010011
01010010

Nem valószínű, hogy bárki képes lesz kitalálni egy ilyen két szám kombinációját, és az első programozók munkája nagyon fáradságos volt. Életük megkönnyítése érdekében a programozók elkezdték létrehozni az első programozási nyelveket. Tehát minél közelebb van a programozási nyelv egy ilyen nullák és egyesek halmazához, annál „alacsonyabb”, és minél távolabb van tőlük, annál „magasabb”.
A mikrokontrollerek leggyakoribb programozási nyelvei:
- alacsony szintű nyelvtudás - szerelő
– magas szintű nyelvtudás – C (Ci)
Nézzünk egy példát a különbségükre (ezek a példák elvont).
Tegyük fel, hogy két számot kell összeadnunk: 25-öt és 35-öt.
A natív kódban ez a parancs így nézhet ki:
00000101 1101001
Alacsony szintű nyelven:
ADD Rd, Rr
Magas szintű nyelven:
25+35
Az alacsony és a magas szintű nyelvek közötti különbség szabad szemmel látható, a megjegyzések, mint mondják, feleslegesek.
De ássunk mélyebbre ezekben a példákban. A gépi kód példáját nem elemezzük, mivel az megegyezik az assembler példájával. Lényegében az Assembly utasítások ugyanazok a gépi kódok (parancsok), amelyekhez egyszerűen betűrövidítések vannak hozzárendelve, hogy ne vesszenek el a nullák és egyesek között. Az ADD Rd, Rr assembler utasítással beállítjuk a mikrokontrollert, hogy összeadja a talált két számot (és ehhez először oda kell írni) - az elsőt Rd-ben, a másodikat Rr-ben, és az összeadás eredményét elhelyezni. az Rd. Amint látható, nagyon konkrét feladatot tűztünk ki a mikrokontroller számára: hol lehet beszerezni, mit kell vele csinálni, és hova kell tenni az eredményt. Ebben az esetben közvetlenül a mikrokontrollerrel dolgozunk.
Parancs magas szintű nyelven: 25+35 , számunkra ismerős, szemünknek tetsző matematikai jelölés. De ebben az esetben nem közvetlenül a mikrokontrollerrel dolgozunk, egyszerűen csak két szám összeadásának feladatát tesszük neki. Az eredmény és a műveletek sorrendje ebben az esetben ugyanaz lesz, mint az assembler parancs végrehajtásakor: először ezt a két számot írjuk valahova, majd összeadjuk, és az eredményt elhelyezzük valahová.
És itt van a fő különbség a magas és az alacsony szintű nyelvek között. Ha az Assemblerben az egész folyamatot irányítjuk (akár akarjuk, akár nem): tudjuk, hogy ez a két szám hol van írva, és tudjuk, hogy hol lesz az eredmény, akkor egy magas szintű nyelvben nem mi irányítjuk a folyamatot. A program maga dönti el, hogy hova írja előre a számokat, és hova helyezze az eredményt. A legtöbb esetben ezt nem kell tudnunk, mert számunkra a fő eredmény a 60-as szám a kimenetben. Ennek eredményeként a magas szintű nyelvű programok olvashatóbbak, tetszetősebbek a szemnek és kisebb méretűek – elvégre nem kell „minden lyukba bemásznunk” és a mikrokontroller, a program minden lépését kifesteni. ezt később megteszi nekünk, amikor lefordítja – lefordítja gépi kódokká. De van egy árnyoldala is. Két azonos Assemblerben és C-ben írt algoritmus gépi kódokká alakítása után eltérő méretű lesz: az Assemblerben írt program 20-40%-kal rövidebb lesz, mint egy C-ben írt program - az ördög tudja, merre megy C elérjük a szükséges eredményt. És van, hogy nincs bizalom egy magas szintű nyelvben, és egy C programba beszúrnak Assemblerben írt kódot.
A professzionális programozók általában több programozási nyelvet ismernek (vagy olyan csapatban dolgoznak, amelyben különböző nyelvek szakemberei vannak), kreatívan kombinálva funkcióikat és előnyeiket egy programban. Nos, nekünk, amatőröknek tudnunk kell legalább egy nyelvet (kezdetnek), és el kell kezdenünk (és erről határozottan meg vagyok győződve, és senki sem fog meggyőzni) egy alacsony szintű nyelvből - az Assembly-ből.

Nos, azt hiszem, és itt minden világos számunkra - meg kell tanulnia egy programozási nyelvet, más módon - semmiképpen.

Parancsok és utasítások a mikrokontroller vezérléséhez.
Az AVR mikrokontrollerek több mint 130 különböző paranccsal rendelkeznek, amelyek lehetővé teszik az összes benne rejlő lehetőség megvalósítását. De rögtön azt mondom, hogy kevés amatőr ismeri mindet, nemhogy mindet használja. Általában az amatőr gyakorlaton van elég tudás és a csapatok fele, vagy még kevesebb. De meg kell tanulnod a parancsokat. Minél több parancsot ismersz, annál kifinomultabbak (a szó jó értelmében) és elegánsabbak lesznek.

Aritmetikai logikai egység és memóriaszervezés - programmemória, adatmemória, nem felejtő memória



Ebben az avr-ről szóló oktatóanyagban megpróbáltam leírni a legalapvetőbb dolgokat a kezdők számára a mikrokontrollerek programozásához. avr. Minden példa mikrokontrollerre épül atmega8. Ez azt jelenti, hogy az összes lecke megismétléséhez csak egy MK-ra lesz szüksége. Elektronikus áramkör-emulátorként a Proteust használják - véleményem szerint a kezdők számára a legjobb lehetőség. Az összes példában szereplő programok az avr CodeVision AVR C fordítójára vannak írva. Miért nem valamelyik assemblerben? Mert a kezdő már tele van információval, és a két számot szorzó program az assemblerben kb száz sort foglal, és bonyolult, félkövér projektekben C-t használnak.A CodeVision AVR fordítója atmel mikrokontrollerekre van kihegyezve, kényelmes kódgenerátorral rendelkezik, a jó interfész és közvetlenül onnan lehet flashelni a mikrokontrollerrel.

Ez az oktatóanyag bemutatja és egyszerű példákkal elmagyarázza, hogyan:

  • Kezdje el a mikrokontrollerek programozását, hol kezdje, mire van szüksége ehhez.
  • Milyen programokat kell használni az avr firmware-jének írásához, a kód szimulálásához és hibakereséséhez a számítógépen,
  • Milyen perifériás eszközök vannak az MK-ban, hogyan vezérelheti őket a program segítségével
  • Hogyan írjuk a kész firmware-t a mikrokontrollerre, és hogyan lehet hibakeresni
  • Hogyan készítsünk PCB-t az eszközhöz
Az első lépések megtételéhez az MK programozás felé mindössze két programra van szüksége:
  • A Proteus egy emulátor program (valódi forrasztás nélkül fejleszthet benne áramkört, majd tesztelheti programunkat ezen az áramkörön). Először a Proteusban indítunk el minden projektet, aztán már forraszthatunk is egy igazi készüléket.
  • A CodeVisionAVR egy C programozási nyelv fordítója az AVR-hez. Ebben a mikrokontrollerhez fogunk programokat fejleszteni, és közvetlenül lehet majd belőle flashelni egy igazi MK-t.
A Proteus telepítése után futtassa
Felajánlja, hogy lássuk a vele járó projekteket, udvariasan visszautasítjuk. Most hozzuk létre benne a legegyszerűbb áramkört. Ehhez kattintson az ikonra vizuálisan nem történik semmi. Most rá kell kattintania a kis betűre R (választás a könyvtárból) a komponenslista panelen megnyílik a komponensválasztó ablak
a maszk mezőbe írja be a könyvtárban keresni kívánt összetevő nevét. Például hozzá kell adnunk egy mega8-as mikrokontrollert
a találati listában bökd meg a mega8-at és nyomd meg a gombot rendben. Van egy mega8 mikrokontrollerünk a komponensek listájában
Így a maszk mezőbe beírva újabb ellenállást adunk az összetevők listájához resés LED vezette

Az alkatrészek diagramon való elhelyezéséhez kattintson az alkatrészre, majd kattintson a diagrammezőre, válassza ki az alkatrész helyét, és kattintson újra. Földelés vagy közös mínusz hozzáadásához a bal oldali áramkörhöz kattintson a "Terminál" gombra, és válassza a Föld lehetőséget. Így az összes komponenst összeadva és összekapcsolva egy ilyen egyszerű áramkört kapunk
Minden, most elkészült az első programunk! De talán azt kérdezed, mit tehet? De semmi. Semmi, mert ahhoz, hogy a mikrokontroller működjön, programot kell írni hozzá. A program a mikrokontroller által végrehajtandó utasítások listája. A lábra szereléshez szükségünk van a mikrokontrollerre PC0 logikai 0 (0 volt) és logikai 1 (5 volt).

Program írása mikrokontrollerhez

A programot C nyelven írjuk meg a CodeVisionAVR fordító segítségével. Az önéletrajz elindítása után megkérdezi, hogy mit szeretnénk létrehozni: Forrást vagy Projektet Ez utóbbit választjuk, és megnyomjuk az OK gombot. Ezután megkérjük, hogy futtassuk a CVAVR CodeWizard-ot (ez egy felbecsülhetetlen értékű eszköz egy kezdő számára, mert ez képes előállítani a program fő vázát) választ Igen
A varázsló aktív Chip füllel indul, itt kiválaszthatjuk az MK-nk modelljét - ez a mega8, és az MK működési frekvenciáját (a mega8 alapértelmezés szerint 1 megahertzre van állítva), így mindent a képen látható módon állítunk be. a fenti képernyőképet. Lépjen a Portok fülre
Az atmega8 mikrokontroller 3 porttal rendelkezik: Port C, Port D, Port B. Mindegyik portnak 8 érintkezője van. A port érintkezők két állapotúak lehetnek:
  • Kijárat
A DDRx.y regiszter segítségével a pin-t be- vagy kimenetként állíthatjuk be. Ha be
  • DDRx.y = 0 - a kimenet úgy működik, mint BEMENET
  • DDRx.y = 1 érintkező működik KIJÁRAT
Ha a láb kimenetként van konfigurálva, beállíthatjuk logikai 1-re (+5 volt) és logikai 0-ra (0 volt). Ez úgy történik, hogy írunk a PORTx.y regiszterbe. A továbbiakban a bemeneti-kimeneti portokról lesz szó. És most mindent beállítunk a képernyőképen látható módon, és kattintsunk a Fájl->Létrehozás, Mentés és kilépés gombra. Ezután a CodeWizard felajánlja, hogy mentsük el a projektet, elmentjük és megnézzük a kódot:

#beleértve //könyvtár az időkésleltetések létrehozásához void main(void) ( PORTB=0x00; DDRB=0x00; PORTC=0x00; DDRC=0x01; // PC0 láb kimenete PORTD=0x00; DDRD=0x00; // Timer/Counter 0 inicializálása TCCR0=0x00; TCNT0=0x00; // Időzítő/Számláló 1 inicializálása TCCR1A=0x00; TCCR1B=0x00; TCNT1H=0x00; TCNT1L=0x00; ICR1H=0x00; ICR1L=0x00; ICR1L=0xCR01CR00; OxCR1L=0xCR01AH0; ; OCR1BL=0x00; // Időzítő/2. számláló inicializálása ASSR=0x00; TCCR2=0x00; TCNT2=0x00; OCR2=0x00; // Külső megszakítás(ok) inicializálása MCUCR=0x00; // Időzítő(k)/Számláló(k) ) Megszakítás(ok) inicializálása TIMSK=0x00; // Analóg komparátor inicializálása ACSR=0x80; SFIOR=0x00; míg (1) ( ); )


Itt minden ijesztőnek és ismeretlennek tűnhet számodra, de a valóságban minden nem így van. A kód egyszerűsíthető, ha kidobjuk az általunk nem használt MK perifériák inicializálását. Egyszerűsítés után így néz ki:

#beleértve //könyvtár a mikrokontrollerrel való munkavégzéshez mega8 #include //könyvtár az időkésleltetések létrehozásához void main(void) ( DDRC=0x01; /* a PC0 láb 0x01 kimeneti bejegyzése ismeretlennek tűnhet számodra, és ez csak az 1 hexadecimális szám, ez a sor 0b00000001 lesz binárisan, akkor pontosan így fogok írni. */ miközben (1) ( ); )


Minden rendben. De ahhoz, hogy a LED villogjon, meg kell változtatnunk a logikai szintet a PC0 lábon. Ehhez adjon hozzá néhány sort a fő hurokhoz:

#beleértve //könyvtár a mikrokontrollerrel való munkavégzéshez mega8 #include //könyvtár az időkésleltetések létrehozásához void main(void) ( DDRC=0x01; /* a PC0 láb 0x01 kimeneti bejegyzése ismeretlennek tűnhet számodra, és ez csak az 1 hexadecimális szám, ez a sor 0b00000001 lesz binárisban, akkor pontosan így fogok írni.*/ while (1)//a fő programhurok (// a fő programhurok operátori zárójele megnyitja a PORTC.0=1-et; //a C 1 portot állítsa pinre 0 delay_ms(500); //késleltetés 500 ezredmásodpercben PORTC.0=0; // a C 0 port beállítása 0 késleltetés_ms(500); // 500 ezredmásodperces késleltetés );// az operátor zárójelének bezárása a fő programhurokból )


Minden, a kód készen áll. A Build all Project files ikonra kattintva lefordítjuk (lefordítjuk az MK processzor utasításaira) programunkat. A projektünkben található Exe mappában meg kell jelennie egy hex kiterjesztésű fájlnak, ez a mi firmware fájlunk az MK-hoz. Ahhoz, hogy a firmware-ünket a Proteus virtuális mikrokontrolleréhez továbbíthassa, duplán kell kattintania a Proteus mikrovezérlőjének képére. Megjelenik egy ehhez hasonló ablak
kattintson a mappa ikonra a Program File mezőben, válassza ki a hex-et - firmware-ünk fájlját, majd nyomja meg az OK gombot. Most már lefuttathatjuk az áramkörünk szimulációját. Ehhez kattintson a "Play" gombra a Proteus ablak bal alsó sarkában.

Nem egyszer vagy kétszer mondtam, hogy az MK tanulmányozását az assemblerrel kell kezdeni. Az oldalon egy egész tanfolyamot szenteltek ennek (bár nem túl konzisztens, de fokozatosan átfésülöm a megfelelő megjelenésre). Igen, nehéz, az eredmény nem az első napon lesz, de megtanulod megérteni, mi történik a vezérlőben. Tudni fogja, hogyan működik, és nem másolja mások forrásait, mint egy majom, és megpróbálja megérteni, miért állt le hirtelen. Ráadásul a C sokkal könnyebben vacakol a redneck kóddal, amely a legalkalmatlanabb pillanatban fog kijönni.

Sajnos mindenki azonnali eredményt akar. Ezért úgy döntöttem, hogy a másik utat választom - készítek egy bemutatót C-ről, de a fehérnemű bemutatásával. Egy jó beágyazó programozó mindig szorosan tartja a vasdarabot a tepertőnél, megakadályozva, hogy engedély nélkül egyetlen lépést is tegyen. Tehát mi lesz először a C kód, aztán mit szült a fordító és hogyan működik mindez a valóságban :)

Másrészt a C erőssége a kódhordozhatóság. Ha persze mindent helyesen írni. A munkaalgoritmusok és vasmegvalósításaik szétválasztása a projekt különböző részeire. Ezután az algoritmus másik MK-ra való átviteléhez elegendő csak az interfész réteget átírni, ahol a hardverhez való összes hozzáférés meg van írva, és az összes működő kódot úgy hagyni, ahogy van. És persze az olvashatóság. A Sish forráskódját egy pillantásra könnyebb megérteni (bár .. például nem érdekel, hogy mit pöccintsek - legalább si, legalább asm :)), de ismét, ha minden helyesen van megírva. Ezekre a pontokra is figyelni fogok.

Kísérleti vasdarabként, amelyre az összes példa oroszlánrésze kerül, az én hibakereső táblám lesz.

Az első C program az AVR-hez

Fordítóprogram kiválasztása és környezet telepítése
Számos különböző C fordító létezik az AVR-hez:
Először is ezt IAR AVR C- szinte egyértelműen az AVR legjobb fordítójaként ismerik el, tk. maga a vezérlő az Atmel és az IAR szakemberei szoros együttműködésében jött létre. De mindenért fizetni kell. És ez a fordító nem csak drága kereskedelmi szoftver, hanem olyan rengeteg beállítással is rendelkezik, hogy csak keményen kell dolgozni, hogy lefordítsák benne. Igazából nem volt barátságom vele, a projekt a linkelési szakaszban történt furcsa hibák miatt elrohadt (később rájöttem, hogy egy ferde repedés volt).

Második megy WinAVR GCC egy hatékony optimalizáló fordító. Teljesen nyílt forráskódú, cross-platform, általában az élet minden öröme. Tökéletesen integrálódik az AVR Stúdióba is, lehetővé téve a hibakeresést ott, ami pokolian kényelmes. Általában azt választottam.

Szintén van CodeVision AVR C nagyon népszerű fordítóprogram. Egyszerűsége miatt vált népszerűvé. Néhány perc alatt működő programot kaphat benne - ehhez nagyban hozzájárul az indítókód varázsló, amely lebélyegzi az esetleges uart inicializálásának szabványait. Hogy őszinte legyek, valahogy gyanakodva bánok vele - egyszer szét kellett szednem egy programot, amit ez a fordító írt, valami zabkása és nem kód lett belőle. Rettenetes mennyiségű felesleges gesztus és művelet, ami meglehetősen nagy mennyiségű kódot és lassú teljesítményt eredményezett. Lehetséges azonban, hogy hiba volt az eredeti firmware-író ​​DNS-ében. Ráadásul pénzt akar. Nem annyira, mint az IAR, de észrevehető. Demó módban pedig legfeljebb 2 kb kódot tesz lehetővé.
Persze van repedés, de ha lopsz, akkor egymillió, IAR értelmében :)

Van még Image Craft AVR Cés MicroC a mikroelektronikából. Egyiket sem kellett használni, de... SWG nagyon sok dicséret micropascal, azt mondják, borzasztóan kényelmes programozási környezet és könyvtárak. Szerintem a MicroC nem lesz rosszabb, de fizetős is.

Mint mondtam, én választottam WinAVR három okból: ingyenes, integrálható az AVR Stúdióba, és csak egy csomó kész kódot írnak rá minden alkalomra.

Tehát töltse le a WinAVR-t az AVR Studio segítségével. Ezután először a stúdiót telepítik, majd felülről a WinAVR felgördül, és plug-in formájában a stúdióhoz tapad. Erősen javaslom, hogy a WinAVR-t egy rövid útvonalra tegyük, például a C:\WinAVR-hez, így sok problémát elkerülhetünk az elérési utakkal.

Projekt létrehozása
Szóval, a stúdió be van állítva, a C be van csavarva, ideje megpróbálni programozni valamit. Kezdjük az egyszerűvel, a legegyszerűbbel. Futtassa a stúdiót, válasszon ki egy új projektet az AVR GCC fordítójaként, és adja meg a projekt nevét.

A munkaterület egy üres *.c fájllal nyílik meg.

Most már nem árt beállítani az útvonalak megjelenítését a stúdió könyvjelzői között. Ehhez lépjen a következő helyre:
Menü Eszközök - Beállítások - Általános - Fájllapok, és válassza a "Csak fájlnév" lehetőséget a legördülő listából. Ellenkező esetben lehetetlen lesz dolgozni - a lap tartalmazza a fájl teljes elérési útját, és nem lesz több, mint két vagy három lap a képernyőn.

Projekt beállítása
Általában klasszikusnak tekinthető egy make fájl létrehozása, amelyben minden függőséget leírnak. És ez valószínűleg helyes. De nekem, aki teljesen integrált IDE-kben nőttem fel, mint pl uVision vagy AVR Stúdió ez a megközelítés mélyen idegen. Ezért a magam módján fogom csinálni, a stúdió minden eszközével.

Kattintson a fogaskerék gombra.


Ezek a projekt beállításai, vagy inkább a make fájl automatikus létrehozásának beállításai. Az első oldalon csak azt a frekvenciát kell megadnia, amelyen az MK működni fog. Ez a biztosítékbitektől függ, ezért feltételezzük, hogy a frekvencia 8000000Hz.
Ügyeljen az optimalizálási vonalra is. Most van -Os a méretoptimalizálás. Hagyja egyenlőre, aztán megpróbálhatja eljátszani ezt a paramétert. -O0 egyáltalán nem optimalizálás.

A következő lépés az utak beállítása. Mindenekelőtt adja hozzá a projektje könyvtárát - ott harmadik féltől származó könyvtárakat helyez el. A ".\" elérési út megjelenik a listában

A make fájl generálódik, megtekintheti a projekt alapértelmezett mappájában, csak nézze meg, mi van ott.


Ez minden most. Kattintson az OK gombra mindenhol, és lépjen a forráshoz.

A probléma megfogalmazása
Az üres lap csábító valami ravasz ötlet megtestesítésére, hiszen a dióda banális villogása már nem jön be. Azonnal ragadjuk meg a bikát a szarvánál, és hozzuk létre a kapcsolatot a számítógéppel – ez az első dolgom.

Ez így fog működni:
Amikor egy egység megérkezik a COM portra (0x31 kód), bekapcsoljuk a diódát, ha pedig nulla érkezik (0x30 kód), akkor eloltjuk. Sőt, minden megszakításokon fog megtörténni, a háttérfeladat pedig egy másik dióda villogása lesz. Egyszerű és értelmes.

A séma összeállítása
Csatlakoztatnunk kell az USB-USART átalakító modult a mikrokontroller USART érintkezőihez. Ehhez veszünk egy két vezetékből álló jumpert, és keresztben helyezzük a csapokra. Vagyis a vezérlő Rx-ét a konverter Tx-ével, a konverter Tx-ét pedig a vezérlő Rx-ével kötjük össze.

Kiderül, hogy végül ez a séma:


Nem tartom a maradék kimenetek csatlakoztatását, tápegységet, reset-et, az alap

Írjuk a kódot

Azonnal leszögezem, hogy magának a C nyelvnek a leírásában nem mélyedek el. Ehhez egyszerűen kolosszális mennyiségű anyag áll rendelkezésre, a klasszikus "C programozási nyelvtől" a K&R-től a különféle kézikönyvekig.

Egy ilyen módszert találtam a rejtekemben, egyszer tanultam is ezt a nyelvet a segítségével. Minden rövid, világos és lényegre törő. Fokozatosan beírom és a webhelyemre húzom.

Igaz, hogy még nem minden fejezet került át oda, de szerintem nem sokáig.

Nem valószínű, hogy jobban leírom, ezért a képzési kurzusból a Cish bonyolultságának részletes magyarázata helyett egyszerűen közvetlen hivatkozásokat adok a kézikönyv egyes oldalaira.

Könyvtárak hozzáadása.
Először is hozzáadjuk a szükséges könyvtárakat és fejléceket definíciókkal. Végül is a C univerzális nyelv, és el kell magyarázni, hogy AVR-rel dolgozunk, ezért írja be a sort a forráskódba:

1 #beleértve

#beleértve

Ez a fájl a mappában található WinAVRés tartalmazza a vezérlő összes regiszterének és portjának leírását. És ott minden trükkös, egy konkrét vezérlőre hivatkozva, amelyet a fordító továbbít készítsenek fájl a paraméterben MCUés e változó alapján egy fejlécfájl csatlakozik a projekthez, amely tartalmazza az adott vezérlő összes portjának és regiszterének címét. Hogyan! Enélkül te is megteheted, de akkor nem használhatsz olyan szimbolikus regiszterneveket, mint a SREG vagy az UDR, és emlékezned kell mindegyik címére, például "0xC1", és ezen töröd a fejed.

Ugyanaz a csapat #beleértve<имя файла> lehetővé teszi bármilyen szöveges fájl tartalmának hozzáadását a projekthez, például egy funkciók leírását tartalmazó fájlt vagy egy másik kódrészletet. És hogy a direktíva megtalálja ezt a fájlt, megadtuk a projektünk elérési útját (a WinAVR könyvtár alapértelmezés szerint már regisztrálva van ott).

fő funkció.
A C program a függvényekről szól. Tetszőleges sorrendben és sokféle módon egymásba ágyazhatók és egymásból hívhatók. Minden funkciónak három kötelező paramétere van:

  • Visszatérési érték pl. bűn(x) x szinuszának értékét adja vissza. Mint a matematikában, röviden.
  • Az átvitt paraméterek, ugyanaz az x.
  • Funkciótest.

Minden átadott és visszaadott értéknek valamilyen típusúnak kell lennie, az adatoktól függően.

Minden C programnak tartalmaznia kell egy függvényt fő- mint belépési pont a főprogramhoz, különben egyáltalán nem C :). A main jelenléte valaki más millió fájl forrásában megértheti, hogy ez a program fő része, ahonnan minden kezdődik. Itt állítjuk be:

1 2 3 4 5 int main(void ) ( return 0 ; )

int main(void) ( return 0; )

Ennyi, megírták az első legegyszerűbb programot, nem számít, hogy nem csinál semmit, még csak most kezdtük.

Lássuk, mit csináltunk.
int az az adattípus, amelyet a fő függvény visszaad.

Természetesen a mikrokontrollerben fő- elvileg semmit nem lehet visszaadni, és elméletileg annak is kell lennie void main(void), de a GCC eredetileg a PC-n van kiélezve és ott a program a befejezés után vissza tudja adni az értéket az operációs rendszernek. Ezért a GCC be void main(void) a Figyelmeztetésre esküszik.

Ez nem hiba, működni fog, de nem szeretem a figyelmeztetéseket.

üres ebben az esetben ilyen típusú adatokat adunk át a függvénynek fő- kívülről, a költőtől sem tud elfogadni semmit üres- üres. A csonkot akkor használjuk, ha semmit sem kell átadni vagy visszaadni.

Itt vannak ezek { } A curly brackets egy programblokk, jelen esetben a függvény törzse fő-, a kód ott lesz.

Visszatérés- ez a visszatérési érték, amit a főfüggvény ad a befejezéskor, mivel van egy int, azaz egy szám, akkor számot kell visszaadnunk. Bár ennek még mindig nincs értelme, mert. a mikrokontrolleren a main-ról csak sehova sem tudunk menni. nullát adok vissza. Nefig számára. A fordító pedig általában okos és nem generál kódot erre az esetre.
Bár ha perverz, akkor attól fő- mehetsz az MK-hoz - például kieshetsz a bootloader részbe és végrehajthatod, de itt már alacsony szintű firmware-választásra lesz szükséged az átmeneti címek kijavításához. Az alábbiakban látni fogja és megérti, hogyan kell csinálni. Minek? Ez most egy másik kérdés, az esetek 99.999%-ában erre nincs is szükség :)

Kész, lépj tovább. Adjunk hozzá változót, nincs is rá igazán szükségünk és nem is kellene változókat bevezetni nélküle, de tanulunk. Ha változókat adunk hozzá a függvénytörzsbe, akkor azok lokálisak, és csak ebben a függvényben léteznek. Amikor kilép a funkcióból, ezek a változók törlődnek, és a RAM-memória fontosabb igényekhez kerül. .

1 2 3 4 5 6 int main(void) (előjel nélküli karakter; return 0; )

int main(void) ( unsigned char i; return 0; )

aláírás nélküli aláíratlant jelent. A helyzet az, hogy a bináris ábrázolásban a legjelentősebb bit az előjelhez van hozzárendelve, ami azt jelenti, hogy a +127/-128 szám belefér egy bájtba (char), de ha az előjelet eldobjuk, akkor 0-tól 255. Általában nincs szükség a jelre. Szóval azt aláírás nélküli.
én csak egy változónév. Nem több.

Most inicializálnunk kell a portokat és UART. Természetesen felveheti és csatlakoztathatja a könyvtárat, és meghívhat valamilyen UartInit-et (9600); de akkor nem fogod tudni, mi történt valójában.

Ezt csináljuk:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 int main(void ) ( unsigned char i; #define XTAL 8000000L #define baudrate 9600L #define bauddivider (XTAL/(16*baudrate)-1)#define HI(x) ((x)>>8) #define LO(x) ((x)& 0xFF) UBRRL = LO(baudosztó) ; UBRRH = HI(baudosztó) ; UCSRA = 0; UCSRB=1<< RXEN| 1 << TXEN| 1 << RXCIE| 0 << TXCIE; UCSRC = 1 << URSEL| 1 << UCSZ0| 1 << UCSZ1; }

int main(void) ( unsigned char i; #define XTAL 8000000L #define baudrate 9600L #define bauddivider (XTAL/(16*baudrate)-1) #define HI(x) ((x)>>8) #define LO( x) ((x)& 0xFF) UBRRL = LO (baudosztó); UBRRH = HI (baudosztó); UCSRA = 0; UCSRB = 1<

Ijedős? Valójában csak öt utolsó sor van a valódi kódban. Minden, ami #define ez egy előfeldolgozó makrónyelv. Majdnem ugyanazok a csúcsok, mint az Assemblerben, de a szintaxis némileg más.

Ezek megkönnyítik a szükséges együtthatók kiszámításának rutinműveleteit. Az első sorban azt mondjuk, hogy ahelyett XTAL nyugodtan helyettesítheti 8000000, ill L- típusjelzés, azt mondják long a processzor órajele. Azonos átviteli sebesség- az UART-on keresztüli adatátvitel gyakorisága.

baudosztó már bonyolultabb, helyette az előző kettő képletével számított kifejezés lesz behelyettesítve.
Jól és LOés SZIA ebből az eredményből az alacsony és a magas bájt lesz kivéve, mert nyilván nem fér bele egy bájtba. NÁL NÉL SZIA x eltolódik (a makró bemeneti paramétere) nyolcszor jobbra, ennek következtében csak a magas bájt marad meg belőle. És be LO bitenkénti ÉS-t csinálunk a 00FF számmal, így csak az alacsony bájt marad meg.

Tehát minden, ami történt, olyan #define nyugodtan kidobhatja, és kiszámolhatja a szükséges számokat a számológépen, és azonnal beírhatja az UBBRL = ... sorokba. és UBBRH=…..

Tud. De! Csináld ezt SZIGORÚAN LEHETETLEN!

Ez így is, úgy is működni fog, de lesz ún mágikus számok- a semmiből vett értékek, és nem világos, hogy miért, és ha pár év múlva megnyit egy ilyen projektet, akkor rohadt nehéz lesz megérteni, hogy mik ezek az értékek. És most, ha meg akarja változtatni a sebességet, vagy megváltoztatni a kvarc frekvenciáját, és mindent újra kell számolnia, és így megváltoztatott néhány számot a kódban, és ennyi. Általánosságban elmondható, hogy ha nem akarod, hogy rossz kódolónak tartsanak, akkor készítsd el a kódot úgy, hogy könnyen olvasható, érthető és könnyen módosítható legyen.

Akkor minden egyszerű:
Mindezek az "UBRLL és Co" az UART adó konfigurációs regiszterei, amelyekkel kommunikálni fogunk a világgal. És most hozzárendeltük a szükséges értékeket, beállítva őket a kívánt sebességre és a kívánt üzemmódra.

Rekord megtekintése 1< A következőket jelenti: vegyen 1-et és tegye a helyére RXEN egy bájtban. RXEN ez a regiszter 4. bitje UCSRB, így 1< a 00010000 bináris számot alkotja, TXEN a 3. bit, és 1< 00001000. Egyetlen "|" ez bitesen van VAGY, tehát 00010000 | 00001000 = 00011000. Ugyanígy a fennmaradó szükséges konfigurációs bitek beállítása és hozzáadása a közös kupachoz. Ennek eredményeként az összegyűjtött szám beírásra kerül az UCSRB-be. Részletesebben le van írva az MK adatlapján az USART részben. Tehát ne zavarja el a figyelmét a technikai részletek.

Kész, ideje megnézni, mi történik. Kattintson a fordításra, és indítsa el az emulációt (Ctrl+F7).

Hibakeresés
Mindenféle folyamatjelző sáv futott át, a stúdió megváltozott, és egy sárga nyíl jelent meg a fő funkció bejárata közelében. Itt van jelenleg a processzor, és a szimuláció szünetel.

A helyzet az, hogy eredetileg az UBRRL = LO(bauddivider) sorban volt; Hiszen ami a define-ban van, az nem kód, hanem egyszerűen csak előzetes számítások, így a szimulátor kicsit unalmas. De most rájött, hogy az első utasítás teljesült, és ha felmászik egy fára I/O nézet, az USART részhez és ott nézd meg az UBBRL bájtot, látni fogod, hogy ott már van érték! 0x33.

Tegyen még egy lépést. Nézze meg, hogyan fog változni egy másik regiszter tartalma. Tehát menjen végig mindegyiken, ügyeljen arra, hogy az összes megadott bit be van állítva, ahogy mondtam, és egyszerre vannak beállítva a teljes bájtra. A dolgok nem mennek tovább, mint a Visszatérés - a programnak vége.

Nyítás
Most állítsa vissza a szimulációt nullára. Kattintson ide Visszaállítás (Shift+F5). Nyissa meg a szétszerelt listát, most látni fogja, mi történik valójában a vezérlőben. View -> Disassembler. És nem YYAAAA!!! Szerelő!!! SZÖRNYŰ!!! DE KELL. Hogy később, ha valami elromlik, ne hülyéskedjen a kódban, és ne tegyen fel bénább kérdéseket a fórumokon, hanem azonnal szálljon be a zsaruba, és nézze meg, hol van dugó. Nincs ott semmi szörnyű.

Először a sorozat topjai lesznek:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 +00000000: 940C002A JMP 0x0000002A Jump +00000002: 940C0034 JMP 0x00000034 Jump +00000004: 940C0034 JMP 0x00000034 Jump +00000006: 940C0034 JMP 0x00000034 Jump +00000008: 940C0034 JMP 0x00000034 Jump +0000000A: 940C0034 JMP 0x00000034 Jump +0000000C: 940C0034 JMP 0x00000034 Jump + 0000000E: 940C0034 JMP 0x00000034 Jump +00000010: 940C0034 JMP 0x00000034 Jump +00000012: 940C0034 JMP 0x00000034 Jump +00000014: 940C0034 JMP 0x00000034 Jump +00000016: 940C0034 JMP 0x00000034 Jump +00000018: 940C0034 JMP 0x00000034 Jump +0000001A: 940C0034 JMP 0x00000034 Jump +0000001C : 940C0034 JMP 0x00000034 Jump +0000001E: 940C0034 JMP 0x00000034 Jump +00000020: 940C0034 JMP 0x00000034 Jump +00000022: 940C0034 JMP 0x00000034 Jump +00000024: 940C0034 JMP 0x00000034 Jump +00000026: 940C0034 JMP 0x00000034 Jump +00000028: 940C0034 JMP 0x00000034 Jump

00000000: 940C002A JMP 0x0000002A Jump +00000002: 940C0034 JMP 0x00000034 Jump +00000004: 940C0034 JMP 0x00000034 Jump +00000006: 940C0034 JMP 0x00000034 Jump +00000008: 940C0034 JMP 0x00000034 Jump +0000000A: 940C0034 JMP 0x00000034 Jump +0000000C: 940C0034 JMP 0x00000034 Jump +0000000E : 940C0034 JMP 0x00000034 Jump +00000010: 940C0034 JMP 0x00000034 Jump +00000012: 940C0034 JMP 0x00000034 Jump +00000014: 940C0034 JMP 0x00000034 Jump +00000016: 940C0034 JMP 0x00000034 Jump +00000018: 940C0034 JMP 0x00000034 Jump +0000001A: 940C0034 JMP 0x00000034 Jump +0000001C: 940C0034 JMP 0x00000034 Jump +0000001E: 940C0034 JMP 0x00000034 Jump +00000020: 940C0034 JMP 0x00000034 Jump +00000022: 940C0034 JMP 0x00000034 Jump +00000024: 940C0034 JMP 0x00000034 Jump +00000026: 940C0034 JMP 0x00000034 Jump +00000028: 940C0034 JMP 0x00000034 Jump

Ez a megszakítási vektor tábla. Később visszatérünk rá, egyelőre csak nézz és ne feledd, hogy ott van. Az első oszlop a flash cella címe, amelyben a parancs található, a második a parancs kódja, a harmadik parancs mnemonika, ugyanaz az assembler utasítás, a parancs harmadik operandusa. Ja, és az automatikus megjegyzés.
Tehát, ha megnézzük, akkor folyamatos átmenetek vannak. A JMP parancskód pedig négy bájtos, tartalmazza a visszafelé írt ugrási címet - az alacsony címnél az alsó bájtot és a 940C ugrási parancs kódját.

0000002B: BE1F OUT 0x3F, R1 kimenet az I/O helyre

Írja ezt a nullát a 0x3F címre. Ha megnézi az I / O nézet oszlopot, látni fogja, hogy a 0x3F cím a SREG regiszter címe - a vezérlő jelzőregisztere. Azok. visszaállítjuk a SREG-et, hogy a program nulla feltételek mellett futhasson.

1 2 3 4 +0000002C: E5CF LDI R28,0x5F Azonnali betöltés +0000002D: E0D4 LDI R29,0x04 Azonnali betöltés +0000002E: BFDE OUT 0x3E,R29 Ki az I/O helyre +0000002F: BFCD - I/O hely

0000002C: E5CF LDI R28,0x5F Azonnali betöltés +0000002D: E0D4 LDI R29,0x04 Azonnali betöltés +0000002E: BFDE OUT 0x3E,R29 Ki az I/O helyre +0000002F: BFCD - I/O hely

Ez betölti a veremmutatót. Közvetlenül nem tölthet be regisztereket az I / O-ba, csak egy köztes regiszteren keresztül. Ezért először az LDI-t a közteshez, majd onnan OUT az I / O-hoz. A veremről is mesélek bővebben. Addig is tudd, hogy ez egy ilyen dinamikus memóriaterület, a RAM végén lóg, és magában tárolja a címeket és a köztes változókat. Most jeleztük, honnan indul a verem.

00000032: 940C0041 JMP 0x00000041 Ugrás

Egy ugrás a program saaaaamy végére, és ott letiltottuk a megszakításokat, és szorosan hurkoltuk önmagát:

1 2 +00000041: 94F8 CLI Global Interrupt Disable +00000042: CFFF RJMP PC-0x0000 Relatív ugrás

00000041: 94F8 CLI Global Interrupt Disable +00000042: CFFF RJMP PC-0x0000 Relatív ugrás

Ez előre nem látható körülmények, például a fő funkcióból való kilépés esetén történik. A vezérlőt hardveres alaphelyzetbe állítással, vagy valószínűbb, hogy egy watchdogból történő visszaállítással ki lehet hozni egy ilyen hurokból. Nos, vagy ahogy fentebb mondtam, javítsuk ki ezeket a helyeket a hex editorban, és menjünk, ahova akarunk. Vegye figyelembe azt is, hogy kétféle JMP és RJMP ugrás létezik, az első egy közvetlen ugrás egy címre. Négy bájtot foglal el, és közvetlen ugrást végezhet a teljes memóriaterületen. A második típusú átmenet - RJMP - relatív. Parancsa két bájtot vesz igénybe, de az aktuális pozícióról (címről) 1024 lépést ugrik előre vagy hátra. A paraméterei pedig az aktuális ponttól való eltolást jelzik. Gyakrabban használt, tk. A vakuban a hely felét foglalja el, és ritkán van szükség hosszú átmenetekre.

1 +00000034: 940C0000 JMP 0x00000000 Ugrás

00000034: 940C0000 JMP 0x00000000 Ugrás

És ez egy ugrás a kód legelejére. Egyfajta újraindítás. Itt ellenőrizheti, hogy az összes vektor ugrik-e. Ebből a következtetésből - ha most engedélyezed a megszakításokat (alapértelmezés szerint le vannak tiltva), és van megszakításod, de nincs kezelő, akkor szoftveres reset lesz - a program a legelejére kerül.

fő funkció. Minden ugyanaz, nem is lehet leírni. Nézze csak a regiszterekben a már kiszámított számot beírja. Fordító előfeldolgozó sziklák!!! Szóval nincsenek "varázslatos" számok!

1 2 3 4 5 6 7 8 9 10 11 12 <

00000036: E383 LDI R24,0x33 Azonnali betöltés +00000037: B989 OUT 0x09,R24 Ki a 15. I/O helyre: UBRRH = HI (baudosztó); +00000038: BC10 OUT 0x20,R1 Kimenet a 16. I/O helyre: UCSRA = 0; +00000039: B81B OUT 0x0B,R1 Kimenet a 17. I/O helyre: UCSRB = 1<

És íme a jamb:

1 2 3 +0000003E: E080 LDI R24,0x00 Azonnali betöltés +0000003F: E090 LDI R25,0x00 Azonnali betöltés +00000040: 9508 RET Szubrutin visszatérés

0000003E: E080 LDI R24,0x00 Azonnali betöltés +0000003F: E090 LDI R25,0x00 Azonnali betöltés +00000040: 9508 RET Szubrutin visszatérés

A kérdés az, hogy a fordító miért ad hozzá ilyen csúcsokat? Ez pedig nem más, mint a Return 0, akkor a függvényt int main-nak (void) definiáltuk, így még négy bájtot szartunk el, nem értem mit :) És ha a void main-t (void) csinálod, akkor csak a RET marad, de megjelenik egy figyelmeztetés, hogy ezek szerint a fő funkciónk nem ad vissza semmit. Általában azt csinálsz amit akarsz :)

Nehéz? Úgy tűnik, nem. Kattintson a lépésről lépésre történő végrehajtásra disassembler módban, és nézze meg, hogyan hajtja végre a processzor az egyes utasításokat, ami a regiszterekkel történik. Hogyan zajlik a mozgás a parancsokon és a végső hurokoláson keresztül?

Folytatás pár nap múlva...

Offtop:
Alekszej78 Csináltam egy bővítményt a firefoxhoz, amely megkönnyíti a navigációt a webhelyemen és a fórumon.
Beszélgetés és letöltés,

Az AVR mikrokontrollerekhez különféle programozási nyelvek léteznek, de talán az assembler és a C a legalkalmasabb, mivel ezek a nyelvek biztosítják a mikrokontroller hardverének vezérléséhez szükséges összes képesség legjobb megvalósítását.

Az Assembler egy alacsony szintű programozási nyelv, amely a mikrokontroller közvetlen utasításkészletét használja. Egy program ezen a nyelven történő létrehozásához a programozható chip parancsrendszerének alapos ismerete és elegendő idő szükséges a program fejlesztéséhez. Az Assembler veszít a C-vel szemben a programfejlesztés sebessége és kényelme tekintetében, de észrevehető előnye van a végső végrehajtható kód méretében, és ennek megfelelően a végrehajtás sebességében.

A C segítségével sokkal nagyobb kényelemmel hozhat létre programokat, így a fejlesztő a magas szintű nyelv minden előnyét biztosítja.
Még egyszer meg kell jegyezni, hogy az AVR architektúra és parancsrendszer a C fordító fejlesztőinek közvetlen közreműködésével készült, és figyelembe veszi ennek a nyelvnek a sajátosságait. A C nyelven írt forráskód fordítása gyors, és kompakt, hatékony kódot állít elő.

A C fő előnyei az assemblerrel szemben: nagy sebességű programfejlesztés; sokoldalúság, amely nem igényli a mikrokontroller architektúrájának alapos tanulmányozását; az algoritmus jobb dokumentálhatósága és olvashatósága; funkciókönyvtárak elérhetősége; a lebegőpontos számítások támogatása.

A C nyelv harmonikusan ötvözi az alacsony szintű programozás képességeit a magas szintű nyelv jellemzőivel. Az alacsony szintű programozási képesség megkönnyíti a közvetlen hardveren történő működést, a magas szintű nyelvi tulajdonságok pedig könnyen olvasható és módosítható programkód létrehozását teszik lehetővé. Ezen túlmenően, szinte minden C fordító képes assembler beillesztésekkel írni a program kritikus szakaszait a végrehajtási idő és erőforrások szempontjából.

Egyszóval a C a legkényelmesebb nyelv az AVR mikrokontrollerekkel való ismerkedéshez kezdőknek és komoly fejlesztőknek egyaránt.

A fordítók segítségével a program forráskódját mikrokontroller firmware-fájllá alakítják át.

Az Atmel egy hatékony assembler fordítóprogramot biztosít, amely a Windows-alapú Atmel Studio fejlesztői környezet része. A fordítóval együtt a fejlesztői környezet egy hibakeresőt és egy emulátort is tartalmaz.
Az Atmel Studio teljesen ingyenes, és elérhető az Atmel webhelyéről.

Jelenleg jó néhány C fordító létezik az AVR-hez. Közülük a legerősebb az IAR Systems stockholmi fordítója. Alkalmazottai voltak azok, akik a 90-es évek közepén részt vettek az AVR parancsnoki rendszerének fejlesztésében. Az IAR C Compiler kiterjedt kódoptimalizálási képességekkel rendelkezik, és az IAR Embedded Workbench (EWB) integrált fejlesztői környezet részeként érkezik, amely egy assembler fordítót, egy linkert, egy projekt- és könyvtárkezelőt és egy hibakeresőt is tartalmaz. A csomag teljes verziójának ára 2820 EUR. A cég weboldaláról letölthető egy 30 napos ingyenes kiértékelő verzió, vagy egy korlátlan verzió 4 KB-os kódméret korláttal.

A kaliforniai Palo Altóból származó Image Craft amerikai cég a C nyelv fordítóprogramját állítja elő, amely meglehetősen nagy népszerűségre tett szert. Az AVR-hez készült JumpStart C elfogadható kódoptimalizálással rendelkezik, és nem túl drága (verziótól függően 50 és 499 dollár között). A JumpStart C demóverziója AVR-hez teljesen működőképes 45 napig.

A román Code Vision AVR C Compiler nem kisebb népszerűségnek örvend, ennek a fordítónak a teljes verziójának ára viszonylag alacsony, és 150 EUR-t tesz ki. A fordító integrált fejlesztői környezettel érkezik, amely a szabványos szolgáltatások mellett egy meglehetősen érdekes funkciót is tartalmaz - a CodeWizardAVR Automatic Program Generatort. A soros terminál jelenléte a fejlesztői környezetben lehetővé teszi a programok hibakeresését a mikrokontroller soros portján keresztül. A fejlesztők ingyenes kiértékelő verziót tölthetnek le 4 KB-os kódhatárral, és letiltják a generált C forráskód mentését.

A szerbiai Belgrád városában található MikroElektronika fordítóprogramok egész családját gyártja AVR mikrokontrollerekhez. A mikroC PRO nevű C fordító az AVR-hez 249 dollárba kerül. Ugyanazon áron van mikroBasic és mikroPascal is. A fejlesztő webhelyén demók találhatók, 4096 bájtos kódmérettel. Ennek a fordítóprogram-családnak az előnye az egyetlen platform és egyetlen ideológia, amely nem csak a nyelvek, hanem a mikrokontrollerek közötti könnyű átmenetet is lehetővé teszi (vannak fordítói változatok PIC, STM32, 8051 ... számára).

Az integrált fejlesztői környezet igazán ikonikussá vált. Tartalmaz erőteljes C és assembler fordítókat, egy AVRDUDE programozót, egy hibakeresőt, egy szimulátort és sok más támogató programot és segédprogramot. A WinAVR tökéletesen integrálható az Atmel AVR Studio fejlesztői környezetébe. Az assembler bemeneti kódja megegyezik az AVR Studio assemblerével. A C és assembler fordítók képesek COFF formátumban debug fájlokat létrehozni, ami lehetővé teszi, hogy ne csak a beépített eszközöket használja, hanem a nagy teljesítményű AVR Studio szimulátort is. Egy másik fontos plusz, hogy a WinAVR ingyenes, korlátozások nélkül kerül terjesztésre (a gyártók támogatják a GNU General Public License-t).

Összefoglalva, a WinAVR ideális választás azok számára, akik most kezdik elsajátítani az AVR mikrokontrollereket. Ebben a kurzusban ezt a fejlesztői környezetet tekintjük főnek.

A bitenkénti műveletek logikai műveleteken alapulnak, amelyeket korábban már tárgyaltunk. Kulcsszerepet játszanak az AVR mikrokontrollerek és más típusok programozásában. Szinte egyetlen program sem nélkülözheti a bitenkénti műveleteket. Eddig szándékosan kerültük őket, hogy megkönnyítsük az MK-programozás elsajátítását.

Az összes korábbi cikkben csak az I / O portokat programoztuk, és nem használtunk további beépített csomópontokat, például időzítőket, analóg-digitális átalakítókat, megszakításokat és egyéb belső eszközöket, amelyek nélkül az MK elveszíti teljes erejét.

Mielőtt rátérne a beépített MK-eszközök elsajátítására, meg kell tanulnia az AVR MK regiszterek egyes bitjei vezérlését vagy ellenőrzését. Korábban a teljes regiszter bitjeit egyszerre ellenőriztük vagy beállítottuk. Lássuk, mi a különbség, majd folytassuk tovább.

Bitenkénti műveletek

Leggyakrabban az AVR mikrokontrollerek programozásakor használtuk, mivel a kezdő MK programozókhoz képest jobban érthető és érthetőbb. Például csak a D port 3. bitjét kell beállítanunk. Ehhez, mint már tudjuk, a következő bináris kódot használhatjuk:

PORTD = 0b00001000;

Ezzel a paranccsal azonban a 3. bitet egyre állítjuk, a többit pedig (0, 1, 2, 4, 5, 6 és 7.) nullára állítjuk. És most képzeljük el azt a helyzetet, hogy a 6. és 7. számjegyet ADC bemenetként használják, és ekkor valamilyen eszköz jele érkezik az MK megfelelő kimeneteire, és ezeket a jeleket a fenti parancs segítségével visszaállítjuk. Ennek eredményeként a mikrokontroller nem látja őket, és úgy véli, hogy a jelek nem jöttek. Ezért egy ilyen parancs helyett használjunk egy másikat, amely csak a 3. bitet állítja be egyre, miközben a többi bitet nem érinti. Ehhez általában a következő bitenkénti műveletet használják:

PORT |= (1<<3);

Az alábbiakban részletesen elemezzük a szintaxisát. És most egy másik példa. Tegyük fel, hogy ellenőriznünk kell a PIND regiszter 3. bitjének állapotát, ezzel ellenőrizve a gomb állapotát. Ha ezt a bitet nullára állítjuk, akkor tudjuk, hogy megnyomjuk a gombot, majd lefut a parancskód, amely megfelel a lenyomott gomb állapotának. Korábban a következő jelölést használtuk volna:

if (pind == 0b00000000)

(bármilyen kód)

Segítségével azonban nem egyet, a 3.-at, hanem a PIND regiszter összes bitjét egyszerre ellenőrizzük. Ezért hiába nyomjuk meg a gombot és a kívánt bitet alaphelyzetbe állítjuk, de ekkor bármely másik D porton jel érkezik, a megfelelő bit egyre lesz állítva, és a zárójelben lévő feltétel hamis lesz. Ennek eredményeként a kapcsos zárójelben lévő kód még a gomb megnyomásakor sem kerül végrehajtásra. Ezért a PIND regiszter egyes 3. bitjének állapotának ellenőrzéséhez bitenkénti műveletet kell használni:

if (~PIND & (1<<3))

(bármilyen kód)

Az egyes mikrokontroller bitekkel való munkához a C programozási nyelv arzenálja van, amellyel egyszerre módosíthatja vagy ellenőrizheti egy vagy több egyedi bit állapotát.

Egyetlen bit beállítása

Egy bit, például a D port beállításához bitenkénti VAGY műveletet kell használni. Ezt használtuk a cikk elején.

PORTD = 0b00011100; // kezdő érték

PORTD = PORTD | (egy<<0); применяем побитовую ИЛИ

PORT |= (1<<0); // сокращенная форма записи

PORTD == 0b00011101; // eredmény

Ez a parancs a bitet nullára állítja, a többit pedig változatlanul hagyja.

Például állítsuk be a D port 6. bitjét.

PORTD = 0b00011100; // kezdeti portállapot

PORT |= (1<<6); //

PORTD == 0b01011100; // eredmény

Egy vagy több különálló bit egyszerre írásához, például nulla, hatodik és hetedik porthoz B a következő jelölés érvényes.

PORTB = 0b00011100; // kezdő érték

PORTB |= (1<<0) | (1<<6) | (1<<7); //

PORTB == 0b1011101; // eredmény

Az egyes bitek visszaállítása (nullázása).

Egy bit alaphelyzetbe állításához három korábban tárgyalt parancsot használunk egyszerre: .

Állítsuk vissza a PORTC regiszter 3. bitjét, a többit hagyjuk változatlanul.

PORTC = 0b00011100;

PORTC &= ~(1<<3);

PORTC == 0b00010100;

Végezzünk el hasonló műveleteket a 2. és 4. számjegyre:

PORTC = 0b00111110;

PORTC &= ~((1<<2) | (1<<4));

PORTC == 0b00101010;

Ütemezés váltása

A beállításon és visszaállításon kívül egy hasznos parancs is használatos, amely egyetlen bitet az ellenkező állapotba kapcsol: egyet nullára és fordítva. Ezt a logikai műveletet széles körben használják különféle fényeffektusok, például újévi füzér készítésénél. Nézzük a PORTA példáját

PORTA = 0b00011111;

PORTA ^= (1<<2);

PORTA == 0b00011011;

Módosítsa a nulla, második és hatodik bit állapotát:

PORTA = 0b00011111;

PORTA ^= (1<<0) | (1<<2) | (1<<6);

PORTA == 0b01011010;

Egyedi bit állapotának ellenőrzése. Hadd emlékeztesselek arra, hogy az I/O port ellenőrzése (az írással ellentétben) a PIN-regiszter adatainak kiolvasásával történik.

A legáltalánosabb tesztet két ciklusutasítás valamelyikével hajtják végre: if és while. Ezeket az operátorokat már korábban is ismerjük.

A kisülés ellenőrzése logikai nulla jelenlétére (reset) a következővel: ha

if (0==(PIND & (1<<3)))

Ha a D port harmadik bitje törlődik, a Code1 végrehajtásra kerül. Ellenkező esetben a Code2 végrehajtásra kerül.

Hasonló műveleteket hajtanak végre a rögzítéssel és ebben a formában:

if (~PIND & (1<<3))

A kisülés ellenőrzése logikai egység jelenlétére (beállítás) a ha

if (0 != (PIND & (1<<3)))

if (PIND & (1<<3))

A fenti két ciklus hasonlóan működik, de a C programozási nyelv rugalmassága miatt eltérően is írhatók. A != művelet azt jelenti, hogy nem egyenlő. Ha a PD I/O port harmadik bitje be van állítva (egy), akkor a Code1 kerül végrehajtásra, ha nem, a Code2.

Várok egy kis reset-re míg

while (PIND & (1<<5))

A Code1 mindaddig végrehajtódik, amíg a PIND regiszter 5. bitje be van állítva. A visszaállítás megkezdi a Code2 végrehajtását.

Várakozás a bit beállítására míg

Itt a C nyelv szintaxisa lehetővé teszi a kód írását a két leggyakoribb módon. A gyakorlatban mindkét típusú rögzítést alkalmazzák.