Procedur för programmering av avr-mikrokontroller. Råd för nybörjare mikrokontroller programmerare. Nödvändig uppsättning program

Så vi sorterade ut kärnans arbete angående övergångar och adressering. Det är dags att vända vår uppmärksamhet mot ett annat område - minnet.

Det finns två typer av det (EEPROM räknas inte eftersom det i allmänhet är en perifer, men mer om det senare):

  • RAM - RAM
  • ROM - ROM, aka flash, aka programminne

Eftersom vår arkitektur är Harvard, har operatören sin egen adressering och blixten sin egen. I databladet kan du se RAM-adresseringsstrukturen.

Var uppmärksam på adresserna direkt! RON och perifera register samt RAM finns i samma adressutrymme. De där. adresser från 0000 till 001F upptar våra register, sedan upp till adress 005F finns det I/O-celler - portar. Genom portarna konfigureras allt som finns ombord på styrenheten. Och först då, från adress 0060 kommer vårt RAM, som vi kan använda för sitt avsedda syfte.

Observera dessutom att I/O-registren också har sin egen adressering - adressutrymmet för I/O-registren (från 00 till 3F), det indikeras på vänster sida av figuren. IO/Register Block Denna adressering fungerar ENDAST i OUT och IN instruktioner.Detta leder till en intressant funktion.

Perifera register kan nås på två olika sätt:

  • Via IN/OUT-kommandon på en kort adress i I/O-adressutrymmet
  • Genom en grupp LOAD/STORE-kommandon på en fullständig adress i RAM-adressutrymmet

Exempel. Låt oss ta ingångsregistret för den asynkrona transceivern UDR; den har adressen 0x0C (0x2C); adressen i det allmänna adressutrymmet anges inom parentes.

LDI R18,10; Vi laddade in siffran 10 i register R18. Precis sådär OUT UDR,R18 ; Deducerad på det första sättet, kompilatorn själv; Ersätter värdet 0x0C istället för UDR STS 0x2C,R18 ; De tog ut mig andra vägen. Via kommandot Store; Genom att ange adressen direkt.

Båda metoderna ger identiska resultat. MEN! De som fungerar genom att adressera i input/output-utrymmet (OUT/IN) är två byte kortare. Detta är förståeligt - de behöver inte lagra dubbelbyteadressen för en godtycklig minnescell, och den korta adressen för input-output-utrymmet passar in i dubbelbyte-instruktionskoden.

Det är sant att det finns ett annat skämt här. Faktum är att det varje år dyker upp fler och fler stenar från AVR och det blir mer och mer kött i dem. Och varje sprakande behöver sina egna perifera I/O-register. Och nu har vi kommit till slutsatsen att ATMega88 (som ersatte Mega8) redan har så många kringutrustning att dess I/O-register inte längre passar in i 3F-adressutrymmesgränsen.

Oj, de har kommit. Och det är här de som byter från gamla stenar till nya börjar uttrycka förbryllade uttryck - varför fungerar UT/IN-kommandona på vissa perifera register, men inte på andra?

Och det är enkelt - det fanns inte tillräckligt med bitkapacitet.

Men kärnan är en, den kan inte längre göras om. Och här agerade ATMEL-folket listigt - de introducerade de så kallade minneskartade registren. De där. alla de register som inte passade in i 3F-gränsen är nu tillgängliga på bara ett sätt - genom Load/Store.

Vilket skämt. Om du öppnar några m88def.inc kan du se vilka av I/O-registren som är "korrekta" och vilka som är minnesmappade.

Det kommer att bli något sånt här:

; ***** I/O REGISTER DEFINITIONER **************************************** ******** * ; NOTERA: ; Definitioner märkta "MEMORY MAPPED" är utökade I/O-portar; och kan inte användas med IN/OUT-instruktioner .equ UDR0 = 0xc6 ; MINNET MAPPAT .equ UBRR0L = 0xc4 ; MINNET MAPPAT .equ UBRR0H = 0xc5 ; MINNE MAPPAT .equ UCSR0C = 0xc2 ; MINNE MAPPAT .equ UCSR0B = 0xc1; MINNET MAPPAT .equ UCSR0A = 0xc0; MINNET MAPPAT bla bla bla, och mycket mer.equ OSCCAL = 0x66 ; MINNET MAPPAT .equ PRR = 0x64; MINNE MAPPAT .equ CLKPR = 0x61; MINNET MAPPAT .equ WDTCSR = 0x60; MINNET MAPPAT .equ SREG = 0x3f ;<------ А тут пошли обычные.equ SPL = 0x3d .equ SPH = 0x3e .equ SPMCSR = 0x37 .equ MCUCR = 0x35 .equ MCUSR = 0x34 .equ SMCR = 0x33 .equ ACSR = 0x30

Det här är pajerna.

Och inom det här fältet förstår du att en stor lurvig orgel flyger mot korsmodellkompatibiliteten för monteringskoden med målet att tätt täcka den. Det är trots allt en sak att korrigera alla möjliga makrodefinitioner och definitioner som beskriver register, och en annan att sitta och, som Askungen, separera rätt portar från fel.

Det finns dock en lösning. Makrospråk! Gillar du inte kommandosystemet? Gör din egen med blackjack och horor!
Låt oss bygga vårt eget team UOUT, som en universell OUT

På samma sätt för IN-kommandot. Generellt sett kan du med sådana makron diversifiera assemblern MYCKET, och förvandla den till ett kraftfullt programmeringsspråk som kan slita isär alla sorters C och Pascal som en trasa.

Tja, vad pratar jag om... om RAM.

Så vi fixade adresseringen. Nu vet du var du ska leta efter minnesadresserna där användarens RAM-celler börjar - i databladet, avsnittet Memory Map. Men där för referens att veta.

Och i vår kod börjar RAM-minnet med direktivet. DSEG Kommer du ihåg vår mall?

Inkludera "m16def.inc" ; Vi använder ATMega16 ;= Starta macro.inc ================================ ; Makron here;= End macro.inc ========================================================================== RAM ================================================= ============ .DSEG ; RAM-segment; FLASH ================================================== ========== .CSEG ; Kodsegment; EEPROM ================================================== ======== .ESEG ; EEPROM-segment

Efter .DSEG kan vi ställa in våra variabler. Och här har vi helt enkelt en explosion av celler - ockupera vilken som helst. Ange adressen och var nöjd. Men varför räkna adresser manuellt? Låt kompilatorn tänka här.

Därför kommer vi att ta och sätta en etikett

0x0060 ## ;Variables 0x0061 ## 0x0062 ## 0x0063 ## ;Variables2 0x0064 ## 0x0065 ## ;Variables4 kunde börja här

Som ## vilken byte som helst. Som standard FF. Naturligtvis behöver man inte prata om någon typning av variabler, initial initiering, spillkontroll och andra borgerliga glädjeämnen. Det här är Sparta! Jag menar, montör. Allt för hand.
Om vi ​​drar en analogi med C, så är det som att arbeta med minnet enbart genom tomrumspekare. Sishniks kommer att förstå. De kommer att förstå och bli förskräckta. Därför att denna värld är grym och förrädisk. Jag räknade lite fel på indexet och tappade andra data. Och fan, du kommer att fånga det här felet om det inte dyker upp direkt.

Så uppmärksamhet, uppmärksamhet och åter uppmärksamhet. Vi kör alla minnesoperationer genom spårning och ingenting kommer att misslyckas eller svämma över.

ORG-direktivet fungerar också i datasegmentet, det fungerar på exakt samma sätt - det överför adresser, i detta fall märken, härifrån till slutet av minnet. Bara en subtilitet - ORG 0000 kommer att ge oss själva början av RAM, och detta är R0 och andra register. Och noll kilometer RAM med Mega16 som exempel kommer att ge ORG 0x0060. Och i andra kontroller finns det något annat värde. Det är lat att gå igenom databladet varje gång, så det finns en sådan makrodefinition som SRAM_START, som indikerar starten av RAM för en specifik MK.

Så om vi vill att början av RAM-minnet, säg 100 byte, ska finnas kvar under någon slags skräpbuffert, då gör vi det här tricket.

1 2 3 4 .DSEG .ORG SRAM_START+100 Variabler: .byte 3

DSEG .ORG SRAM_START+100 Variabler: .byte 3

Klart, vi rensade vår buffertzon från början till 100.

Okej, vi har ordnat adressen. Hur arbetar man med minnesceller? Och för dessa ändamål finns det två grupper av kommandon. LOAD och STORE är den största gruppen av kommandon.

Faktum är att ingenting kan göras med en RAM-cell annat än att ladda en byte in i den från RON, eller att ladda ur en byte från den till RON.

Lagringskommandon (ST**) skrivs till RAM och ladda (LD**) kommandon läses.

Avläsningen går till register R16…R31, och celladressen anges antingen direkt i kommandot. Här är ett enkelt exempel. Det finns en variabel variabel på tre byte, den måste ökas med 1. Det vill säga. utföra Variables++ operation

DSEG-variabler: .byte 3 Variables2: .byte 1 .CSEG ; Variabeln finns i minnet, först måste du skaffa den. LDS R16, Variabler ; Läs den första variabelbyten i R16 LDS R17, Variables+1 ; Läs den andra variabelbyten i R17 LDS R18, Variables+2 ; Tja, den tredje byten i R18; Låt oss nu lägga till 1 till det, eftersom AVR kan inte lägga till med en konstant, bara; för att subtrahera måste du förvränga. Det orsakar dock inga särskilda problem. SUBI R16,(-1); i allmänhet är SUBI en subtraktion, men -(- ger + SBCI R17,(-1) ; Och här tas hänsyn till överföringen. Men mer om det senare. SBCI R18,(-1) ; Matematik i assembler är en annan historia STS Variables, R16 ; Spara allt är som det var STS Variables+1,R17 STS Variables+2,R18

Eller så kan du använda en annan metod. Indirekt registrering via indexregister.

DSEG-variabler: .byte 3 Variables2: .byte 1 .CSEG ; Ta adressen till vår variabel LDI YL,low(Variables) LDI YH,High(Variables) ; Variabeln finns i minnet, först måste du skaffa den. LD R16, Y+; Läs den första variabelbyten i R16 LD R17, Y+ ; Läs den andra variabelbyten i R17 LD R18, Y+ ; Tja, den tredje byten i R18; Låt oss nu lägga till 1 till det, eftersom AVR kan inte lägga till med en konstant, bara; för att subtrahera måste du förvränga. Det orsakar dock inga särskilda problem. SUBI R16,(-1); egentligen är SUBI en subtraktion, men -(- ger + SBCI R17,(-1) ; Och här tas hänsyn till överföringen. Men mer om det senare. SBCI R18,(-1) ; Matematik i assembler är en annan historia ST -Y,R18 ; Vi behåller allt som det var. ST -Y,R17 ; Men i omvänd ordning ST -Y,R16

Operationer med efterökning och förminskning används redan här. I den första läser vi först, lägger sedan till 1 till adressen. I den andra subtraherar vi först 1 från adressen och sparar sedan.

Det är bekvämt att använda sådana inkrementella kommandon för att iterera genom arrayer i minnet eller tabeller.
Och det finns också en indirekt relativ skriv/läs LDD/STD och andra alternativ för alla tre typer av index (X,Y,Z). I allmänhet rök databladet och kommandosystemet.

Stack
Åh, stacken är en fantastisk sak. Det jag älskar med det är att stackstörningar förvandlar ett fungerande program till en komplett röra. Eftersom stackoperationer kräver ökad uppmärksamhet, för om en stack är trasig någonstans och du inte kan spåra den direkt, kommer du att fånga den senare... I allmänhet är det en skönhet, inte en pryl.

Varför älskar jag dig? Tja, om C är ett dumt hantverk, snabbt och effektivt, så är montering en filigrankonst. Hur galningar som Jim nitar mästerverk från papper och bara från papper, även om det verkar som att du kan köpa en färdig prefabricerad modell och limma för ditt eget nöje. Så även här – själva processen är överväldigande. Inklusive från besväret med att felsöka :))))

Så, om traven. Vad det är? Och detta är minnesområdet. Fungerar enligt principen om en stack. De där. Den sista han lade ner, han tog den första.

Högen har en pekare som pekar mot toppen av högen. Ett speciellt register SP ansvarar för stackpekaren, eller snarare är det ett registerpar SPL och SPH. Men i mikrokontroller med en liten mängd RAM, till exempel i Tini2313, finns det bara SPL

När styrenheten startar är vanligtvis det första de gör att initialisera stacken och skriva i SP adressen till dess botten, varifrån den kommer att växa. Vanligtvis är detta slutet på RAM-minnet, och det växer mot början.

Detta görs så här, i början av programmet:

1 2 3 4 5 LDI R16,Låg(RAMEND) OUT SPL,R16 LDI R16,Hög(RAMEND) OUT SPH,R16

LDI R16,Låg(RAMEND) OUT SPL,R16 LDI R16,Hög(RAMEND) OUT SPH,R16

Där RAMEND är en makrodefinition som indikerar slutet på RAM i den aktuella MK.

Det är det, stacken är redo att gå. Data skjuts upp i stacken med kommandot PUSH Rn och hämtas via POP Rn.
Rn är vilken som helst av RON.

Kommandona CALL, RCALL, ICALL, RET, RETI och calling a interrupt fungerar också med stacken, men mer om det senare.

Låt oss leka med stacken för att känna hur den fungerar, för att förstå hur och var den rör sig.

Ange följande kod i studion:

CSEG; LDI-kodsegment R16,Låg(RAMEND) ; Stackinitiering OUT SPL,R16 LDI R16,Hög(RAMEND) OUT SPH,R16 LDI R17,0 ; Laddningsvärden LDI R18.1 LDI R19.2 LDI R20.3 LDI R21.4 LDI R22.5 LDI R23.6 LDI R24.7 LDI R25.8 LDI R26.9 PUSH R17 ; Vi lägger värdena på stacken PUSH R18 PUSH R19 PUSH R20 PUSH R21 PUSH R22 PUSH R23 PUSH R24 PUSH R25 PUSH R26 POP R0 ; Popvärden från stacken POP R1 POP R2 POP R3 POP R4 POP R5 POP R6 POP R7 POP R8 POP R9

Kör nu studion steg för steg och se hur SP förändras. Stack Pointer kan ses i studion på samma plats som Program Counter.

Först initialiserar vi stacken och laddar registren med data. Resultatet blir följande bild:

Därefter, med POP-kommandot, hämtar vi data från stacken. Observera att det inte spelar någon roll för oss var vi lägger data på stacken och var vi laddar den. Det viktigaste är installationsordningen! Vi lägger in det från de högre registren och kommer att få det i de lägre. Detta kommer att öka stackpekaren.

PUSH R16 PUSH R17 POP R16 POP R17

Till exempel har jag redan pratat om begränsningen av lägre RON - de tillåter dig inte att skriva ett nummer direkt i dig själv. Endast genom seniorgruppens register. Men det här är obekvämt!

Problemet löses med hjälp av ett makro. Jag kallade det LDIL - LDI låg

MAKRO LDIL PUSH R17; Låt oss spara värdet på ett av de högre registren i stacken. LDI R17,1; Låt oss ladda vårt omedelbara värde MOV @0,R17 i den; Låt oss överföra värdet till registret för den låga gruppen. POP R17; Låt oss återställa värdet på det högsta registret från stacken. .ENDM

Nu kan du enkelt använda vårt hemgjorda kommando.

1 LDIL R0,18

Med tiden får filen med makron sådana hemmagjorda kommandon och arbetet blir enkelt och trevligt.

Stackfel
Stacken växer mot datan, och föreställ dig nu att vi har en tillståndsvariabel i minnet och den finns på adressen, till exempel, 0x0450. Farligt nära toppen av stapeln. Variabeln lagrar till exempel tillståndet för den finita tillståndsmaskinen som programmets vidare logik beror på. Låt oss säga att om det finns 3, så går vi och gör en sak, om det finns 4 så är det något annat, om det finns 5 då något annat och så vidare upp till 255 tillstånd. Och enligt arbetslogiken, efter 3 borde det finnas 4re, men inte 10

Och så var det 3. Och sedan, i ett fruktansvärt ögonblick, sammanföll förhållandena så mycket att stapeln växte och dess topp nådde denna variabel, angav ett värde där, säg 20, och sedan föll vinthunden tillbaka. Att lämna muck bakom sig är ett klassiskt exempel på stack overflow. Och logiken i programmet kollapsade helt på grund av detta.

Eller det motsatta exemplet - stacken sköts upp till variablerna, men i det ögonblicket uppdaterades variablerna och skrev över stackdata. Som ett resultat togs något fel bort från stacken (vanligtvis sneda returadresser) och programmet kraschade. Det här alternativet är förresten mycket mer ofarligt, eftersom... i det här fallet är jamben synlig direkt och den dyker inte upp PLÖTSLIGT efter gud vet hur länge.

Dessutom kan detta fel dyka upp och försvinna. Beroende på hur programmet fungerar och hur djupt det laddar stacken. Men en sådan bummer är vanligare när du skriver i C, där du inte kan se hur aktivt arbete med stacken pågår. På ASMA är allt mycket mer transparent. Och här kan detta uppstå på grund av en ärligt talat sned algoritm.

Montörer stöter ofta på andra stackfel. Först av allt, glömska. Jag stoppade in något och glömde ta ut det. Om problemet låg i en subrutin eller ett avbrott, så förvrängs returadressen (mer om det lite senare), stacken rivs av och programmet kollapsar omedelbart. Eller ouppmärksamhet - jag sparade data i en ordning och hämtade den i en annan. Oj, innehållet i registren har bytts ut.

För att undvika sådana fel måste du först och främst övervaka stacken och för det andra att korrekt planera placeringen av variabler i minnet. Hålla de mest kritiska områdena och variablerna (som tillståndsmaskiner eller programlogikflaggor) borta från toppen av stacken, närmare början av minnet.

Vissa människor kommer att tro att de kan ta stacken och placera den inte i slutet av RAM-minnet, utan någonstans närmare, vilket lämnar efter sig en ficka för kritiska data. Inte riktigt en bra idé. Faktum är att stacken kan skjutas både nedåt med kommandot PUSH och uppåt med POP-kommandona. Det andra, även om det händer mycket mindre ofta, eftersom... Detta är mer en synd med krokiga händer än en krånglig algoritm, men det händer också.
Men huvudsaken är att själva stacken är en mycket viktig struktur. Hela mekanismen för subrutiner och funktioner vilar på den. Så ett stackfel är en nödsituation i alla fall.

Stack perversioner
Mitt favoritämne. =)))) Trots att själva stackpekaren beräknas under kommandona PUSH och POP, är det ingen som hindrar oss från att välja den ur SP och använda dess värden för att manuellt beräkna adressen till data som ligger på stapeln. Eller korrigera stackdata som vi vill.
För vad? Tja, du kan hitta många applikationer om du anstränger din hjärna och börjar tänka utanför ramarna :))))

Dessutom skickas parametrar genom stacken i klassisk C och Pascal på x86-arkitekturen och lokala variabler fungerar. De där. Innan en funktion anropas, skjuts först alla variabler till stacken, och sedan, efter anrop av funktionen, skjuts bytes av framtida lokala variabler till stacken.

Sedan, med hjälp av SP som referenspunkt, kan vi behandla dessa variabler som vi vill. Och när stacken frigörs med POP-kommandot, förintas de, vilket frigör minne.

I AVR är allt något annorlunda (uppenbarligen på grund av den lilla mängden minne, där du inte riktigt kan trycka in i stacken, men det finns mycket RON), men du kan också försöka använda den här mekanismen.

Det är sant att detta redan liknar neurokirurgi. Jag gjorde ett litet misstag och patienten är död.

Tack vare stacken och RAM-minnet kan du klara dig med bara två eller tre register, utan mycket stress över deras brist.

Flashminne

EEPROM-minnet är litet, bara några byte, och ibland måste du spara mycket data, till exempel ett meddelande till utomjordingar eller en sinustabell, för att inte slösa tid på att beräkna det. Du vet aldrig vad som behöver lagras i minnet i förväg. Därför kan data lagras i programminnet, i samma kilobyte flash som styrenheten har ombord.

Vi kommer att skriva ner det, men hur kan vi få det? För att göra detta måste du först lägga något där.
Lägg därför till en etikett i slutet av programmet, inom .CSEG-segmentet, till exempel data, och efter det, med hjälp av .db-operatorn, anger du dina data.

DB-operatorn innebär att vi använder en byte för varje konstant. Det finns också operatorer som anger dubbelbytekonstanter DW (liksom DD och DQ).

1 data: .db 12,34,45,23

data: .db 12,34,45,23

Nu pekar dataetiketten på adressen för den första byten i arrayen, de återstående byten är lokaliserade med offset, helt enkelt lägga till en till adressen.

En subtilitet är att kompilatorn ersätter markadressen, och den betraktar den som hoppadressen för programräknaren. Och han, om du kommer ihåg, adresserar dubbelbyte-ord - trots allt kan längden på kommandot vara antingen 2 eller 4 byte.

Och vår data är byte-för-byte och när den får åtkomst till den adresserar kontrollern den också byte-för-byte. Adressen i ord är dubbelt så liten som adressen i byte, och detta måste man ta hänsyn till när man multiplicerar adressen med två.

För att ladda data från programminnet, använd kommandot från gruppen Ladda programminne

Till exempel, LPM Rn,Z

Det går in i register Rn numret från cellen som registerparet Z pekar på. Låt mig påminna dig om att Z är två register, R30 (ZL) och R31 (ZH). Adressens låga byte skrivs in i R30 och den höga byten i R31.

I koden ser det ut så här:

LDI ZL,låg(data*2) ; Vi matar in adressens låga byte i registerparet Z LDI ZH,high(data*2) ; Vi matar in adressens höga byte i registerparet Z; multiplikation med två beror på att adressen anges i; i dubbelbyteord, men vi behöver dem i byte. ; Därför multiplicerar vi med två; Efter att ha laddat adressen kan du ladda numret från minnet LPM R16, Z; i register R16 efter detta kommando kommer det att finnas siffran 12, ; hämtad från programminnet. ; någonstans i slutet av programmet, men i .CSEG-datasegmentet: .db 12,34,45,23

Nu när vi redan är bekanta med en del av mikrokontrollers möjligheter och funktioner uppstår naturligtvis en logisk fråga: vad behövs för att programmera mikrokontroller? Vilka program och enheter behövs, och var kan jag få tag på dem?


För att en mikrokontroller ska kunna lösa problem och utföra vissa funktioner måste den vara programmerad, det vill säga ett program eller programkod måste skrivas in i den.

Struktur och ordning för att skriva ett program

Först och främst, innan du börjar skriva något program, eller snarare programkod, bör du tydligt förstå vilka funktioner mikrokontrollern kommer att utföra. Därför måste du först bestämma det slutliga målet för programmet. När det är definierat och helt förstått, så upprättas en algoritm för programmet. En algoritm är en sekvens av kommandoexekvering. Användningen av algoritmer gör att du kan strukturera processen att skriva kod tydligare, och när du skriver komplexa program kan du ofta minska tiden som läggs på utveckling och felsökning av dem.

Nästa steg efter att ha kompilerat algoritmen är att direkt skriva programkoden. Program för mikrokontroller är skrivna på språket Si eller assemblerare . Only Assembly är mer en uppsättning instruktioner än ett programmeringsspråk och är ett lågnivåspråk.


Vi kommer att skriva program i C, som är ett högnivåspråk. Program i C skrivs mycket snabbare jämfört med liknande program i Assembly. Dessutom skrivs alla komplexa program främst i C.

Här kommer vi inte att jämföra fördelarna och nackdelarna med att skriva program i Assembly och C. Med tiden, efter att ha fått lite erfarenhet av MK-programmering, kommer du att dra användbara slutsatser för dig själv.

Själva programkoden kan skrivas i vilken vanlig textredigerare som helst, till exempel Anteckningar. Men i praktiken använder de mer bekväma redigerare, vilket kommer att diskuteras nedan.

Att sammanställa ett program

C-koden vi skrev är ännu inte förståelig för mikrokontrollern, eftersom MK bara förstår kommandon i det binära (eller hexadecimala) systemet, som är en uppsättning nollor och ettor. Därför måste C-koden omvandlas till nollor och ettor. För detta ändamål används ett speciellt program, kallat kompilator och själva processen kodtransformation kallas kompilering.

För att flasha MK firmware, anropade en enhet programmerare. Beroende på typen av programmerare är dess ingång ansluten till en COM- eller USB-port, och dess utgång är ansluten till vissa stift på mikrokontrollern.


Det finns ett stort urval av programmerare och utvecklingskort, men vi är ganska nöjda med den enklaste programmerare, som i Kina inte kostar mer än $3.


Efter att mikrokontrollern har blinkat, felsöks programmet och testas på en riktig enhet eller, som de också säger, på hårdvara.

Låt oss nu sammanfatta stegen för att programmera mikrokontroller.


När du skriver enkla program kan du klara dig utan den andra punkten, d.v.s. utan att rita upp en algoritm på papper; det räcker med att hålla den i huvudet.

Det bör noteras att felsökning och testning av programmet också utförs innan MK-firmware flashas.

Nödvändig uppsättning program

Det finns många användbara och bekväma program för programmering av MK. De är både betalda och gratis. Bland dem finns det tre huvudsakliga:

1) Atmel Studio

2) CodeVisionAVR

3) WinAVR

Alla dessa program är relaterade till IDjag integrerad D utveckling E nvironment – ​​integrerad utvecklingsmiljö. Du kan skriva kod i dem, kompilera och felsöka den.

Du bör vara uppmärksam på Code Vision AVR. Denna IDE gör det enklare och snabbare att skriva kod. Programmet är dock betalt.

I det inledande skedet av programmeringen är det bättre att skriva alla program manuellt, utan några förenklingar. Detta kommer att hjälpa dig att snabbt skaffa dig nödvändiga färdigheter, och i framtiden kan du väl förstå och redigera koder skrivna av någon annan för att passa dina behov. Därför rekommenderar jag att du använder Atmel Studio. För det första är det helt gratis och ständigt uppdaterat, och för det andra utvecklades det av ett företag som tillverkar mikrokontroller som vi ska lära oss att programmera på.

Firmware och programfelsökning

Vi kommer att flasha mikrokontroller med ett extra program.

Om en mikrokontroller inte är tillgänglig kan dess funktion emuleras med hjälp av programmet. Det förenklar avsevärt processen att felsöka ett program även om du har en mikrokontroller, så du behöver inte uppdatera den ofta, eftersom alla mikrokontroller har ett begränsat antal omskrivningar, även om detta antal är ganska stort.

När du blinkar och felsöker MK är det bekvämt att placera det på en brödbräda, men det är inte alls nödvändigt. Därför, för större bekvämlighet, är en brödbräda också användbar. Det finns ett stort utbud av breadboards, men jag rekommenderar att du tar den som har så många hål som möjligt. När vi börjar ansluta sjusegmentsskärmar kommer du att börja uppskatta fördelarna med större breadboards.

Ett annat viktigt element som kommer att vara användbart för oss är den tekniska dokumentationen för MK, kallad datablad. I allmänhet måste du ladda ner datablad för ATmega8 mikrokontroller.

Kiselev Roman, maj 2007 Artikel uppdaterad 26 maj 2014

Så, vad är en mikrokontroller (nedan kallad MK)? Detta är, relativt sett, en liten dator inrymd i en enda integrerad krets. Den har en processor (arithmetic logic unit, eller ALU), flashminne, EEPROM-minne, många register, I/O-portar, samt ytterligare klockor och visselpipor som timers, räknare, komparatorer, USARTs, etc. Efter att strömmen har lagts på , startar mikrokontrollern och börjar köra programmet som är lagrat i dess flashminne. Samtidigt kan den styra en mängd olika externa enheter via I/O-portar.

Vad betyder det här? Detta innebär att du i MK kan implementera vilken logisk krets som helst som kommer att utföra vissa funktioner. Detta betyder att MK är en mikrokrets, vars inre innehåll vi i själva verket skapar själva. Detta gör det möjligt att, efter att ha köpt flera helt identiska MKs, montera helt olika kretsar och enheter på dem. Om du vill göra några ändringar i driften av en elektronisk enhet behöver du inte använda en lödkolv, du behöver bara programmera om MK. I det här fallet behöver du inte ens ta bort den från din enhet om du använder en AVR, eftersom dessa MK:er stöder in-circuit-programmering. Således överbryggar mikrokontroller gapet mellan programmering och elektronik.

AVR:er är 8-bitars mikrokontroller, det vill säga deras ALU kan utföra enkla operationer med endast 8-bitars nummer i en klockcykel. Nu är det dags att prata om vilken MK vi ska använda. Jag arbetar med en ATMega16 MK. Det är mycket vanligt och kan köpas i nästan alla radiodelarbutiker för cirka 100 rubel. Om du inte hittar den kan du köpa vilken annan MK som helst i MEGA-serien, men i det här fallet måste du leta efter dokumentation för den, eftersom samma "ben" av olika MK:er kan utföra olika funktioner, och genom att ansluta, verkar det, Om alla slutsatser är korrekta, kan du få en fungerande enhet, eller kanske bara ett moln av illaluktande rök. När du köper en ATMega16, se till att den kommer i ett stort 40-stifts DIP-paket och köp även ett uttag för den som den kan sättas in i. För att arbeta med det behöver du också ytterligare enheter: lysdioder, knappar, kontakter, etc.

ATMega16 har ett mycket stort antal olika funktioner. Här är några av dess egenskaper:

  • Maximal klockfrekvens – 16 MHz (8 MHz för ATMega16L)
  • De flesta kommandon exekveras i en klockcykel
  • 32 8-bitars arbetsregister
  • 4 fulla 8-bitars I/O-portar
  • två 8-bitars timer/räknare och en 16-bitars
  • 10-bitars analog-till-digital-omvandlare (ADC)
  • intern klockgenerator på 1 MHz
  • analog komparator
  • gränssnitt SPI, I2C, TWI, RS-232, JTAG
  • kretsprogrammering och självprogrammering
  • pulsbreddsmoduleringsmodul (PWM).

Fullständiga egenskaper för denna enhet, såväl som instruktioner för deras användning, finns i referensboken (Datablad) för denna MK. Det är sant att det är på engelska. Om du kan engelska, se till att ladda ner detta datablad, det innehåller mycket användbar information.

Låt oss äntligen komma igång. Jag rekommenderar att du gör ett speciellt utvecklings- och felsökningskort för mikrokontrollern, där du kan montera vilken elektrisk krets som helst med en mikrokontroller utan lödkolv (eller nästan utan den). Att använda en sådan styrelse kommer att avsevärt underlätta arbetet med MK och påskynda processen att lära sig dess programmering. Det ser ut så här:

Vad kommer du att behöva för detta?

Först behöver du själva tavlan. Jag köpte en färdig i en radiobutik för 115 rubel. Sedan lödde jag alla nödvändiga delar till den. Resultatet är en otroligt bekväm sak, på vilken du kan montera vilken elektrisk krets som helst på några minuter genom att ansluta kablar och installera mikrokretsar och indikatorer.

För att ansluta kretselement är det mycket bekvämt att använda kablar med kontakter i ändarna. Dessa kontakter sätts på "benen" som sticker ut bredvid varje port på MK. Mikrokontrollern ska installeras i uttaget och inte lödas till kortet, annars blir det mycket svårt att ta bort den om du av misstag bränner den. Nedan är pinouten för ATMEGA16 MK:

Låt oss förklara vilka ben vi är intresserade av nu.

  • VCC - ström tillförs här (4,5 - 5,5 V) från en stabiliserad källa
  • GND – mark
  • RESET – återställ (vid låg spänningsnivå)
  • XTAL1, XTAL2 – här ansluts en kvartsresonator
  • PA, PB, PC, PD – in-/utgångsportar (A, B, C respektive D).

Allt som producerar 7-11 V DC kan användas som strömkälla. För stabil drift av MK krävs en stabiliserad strömförsörjning. Som stabilisator kan du använda mikrokretsar i serien 7805. Dessa är linjärt integrerade stabilisatorer, vars ingång matas med 7-11 V lik ostabiliserad ström, och utgången är 5 V stabiliserad ström. Före och efter 7805 måste du installera filterkondensatorer (elektrolytisk för filtrering av lågfrekvent störning och keramik för högfrekvent). Om du inte kan hitta en stabilisator kan du använda ett 4,5 V-batteri som strömkälla. MK måste drivas direkt från den.

Nedan är ett diagram över MK-anslutningen:

Låt oss nu ta reda på vad som är vad här.

BQ1 är en kvartsresonator som ställer in driftsfrekvensen för MK. Du kan ställa in valfri upp till 16 MHz, men eftersom vi planerar att arbeta i framtiden med en COM-port rekommenderar jag att du använder resonatorer för följande frekvenser: 14,7456 MHz, 11,0592 MHz, 7,3725 MHz, 3,6864 MHz eller 1,8432 MHz (senare) det kommer att framgå varför). Jag använde 11,0592 MHz. Det är tydligt att ju högre frekvens, desto högre hastighet har enheten.

R1 är ett pull-up-motstånd som håller en spänning på 5 V vid RESET-ingången. En låg spänningsnivå på denna ingång indikerar en återställning. Efter återställningen startar MK upp (10 - 15 ms) och börjar köra programmet igen. Eftersom detta är en ingång med hög impedans kan du inte låta den "dingla i luften" - en liten pickup på den kommer att leda till en oväntad återställning av MK. Det är precis vad R1 är till för. För pålitlighet rekommenderar jag också att du installerar kondensator C6 (högst 20 µF).

SB1 – återställningsknapp.

Kvartsresonatorn och filterkondensatorn C3 bör placeras så nära MK som möjligt (inte längre än 5-7 cm), eftersom störningar annars kan uppstå i ledningarna, vilket leder till funktionsfel i MK.

Den blå rektangeln i diagrammet visar själva programmeraren. Det är bekvämt att göra det i form av en tråd, vars ena ände är ansluten till LPT-porten och den andra i en viss kontakt bredvid MK. Tråden bör inte vara för lång. Om det uppstår problem med den här kabeln (vanligtvis inte, men allt kan hända), måste du löda Altera ByteBlaster-adaptern. Hur man gör detta finns skrivet i beskrivningen av AVReal-programmeraren.

Nu när vi har tagit itu med hårdvaran är det dags att gå vidare till mjukvaran.

Det finns flera utvecklingsmiljöer för AVR-programmering. För det första är detta AVR Studio - det officiella programmeringssystemet från Atmel. Det låter dig skriva i assembler och felsöka program skrivna i assembler, C och C++. IAR är ett kommersiellt programmeringssystem i C, C++ och assemblerspråk. WinAVR är en kompilator med öppen källkod. AtmanAVR är ett programmeringssystem för AVR med ett gränssnitt nästan exakt samma som Visual C++ 6. AtmanAVR låter dig även felsöka program och innehåller många hjälpfunktioner som gör det lättare att skriva kod. Det här programmeringssystemet är kommersiellt, men enligt licensen kan du använda det gratis i en månad.

Jag föreslår att börja arbeta med IAR som den mest transparenta utvecklingsmiljön. I IAR skapas ett projekt helt för hand; därför kommer du redan efter att ha slutfört flera projekt tydligt veta vad varje rad med kod betyder och vad som kommer att hända om du ändrar den. När du arbetar med AtmanAVR måste du antingen använda en förskapad mall, som är mycket krånglig och svår att förstå för en person utan erfarenhet, eller ha en hel del problem med header-filer när du sätter ihop projektet från grunden. Efter att ha behandlat IAR kommer vi att titta på andra kompilatorer.

Så först, skaffa lite IAR. Det är väldigt vanligt och att hitta det borde inte vara något problem. Efter att ha laddat ner IAR 3.20 någonstans, installera kompilatorn/arbetsmiljön och starta den. Efter detta kan du börja arbeta.

Efter att ha startat IAR, välj fil/ny/arbetsyta, välj sökvägen till vårt projekt och skapa en mapp för det och ge det ett namn, till exempel "Prog1". Låt oss nu skapa ett projekt: Projekt / Skapa nytt projekt... Låt oss också kalla det "Prog1". Högerklicka på projekttiteln i projektträdet och välj "Alternativ"

Här kommer vi att konfigurera kompilatorn för en specifik MK. Först måste du välja processortypen ATMega16 på fliken Mål, markera kryssrutan Aktivera bitdefinitioner i I/O-inkludera filer på fliken Bibliotekkonfiguration (så att du kan använda bitnamnen för olika MK-register i programkoden ), och välj C-bibliotekstypen där /EU++. I ICCAVR-kategorin måste du markera kryssrutan Aktivera multibyte-stöd på fliken Språk och stänga av optimering på fliken Optimering (annars kommer det att förstöra vårt första program).

Välj sedan kategorin XLINK. Här måste du bestämma formatet på den kompilerade filen. Eftersom vi nu ställer in alternativ för felsökningsläget, som beskrivs i rubriken, måste vi få en felsökningsfil som utdata. Senare kommer vi att öppna den i AVR Studio. För att göra detta måste du välja extension.cof, och filtypen är ubrof 7.

Klicka nu på OK och ändra sedan Debug till Release.

Gå till Alternativ igen, där alla parametrar utom XLINK är inställda på samma. I XLINK ändrar du filtillägget till .hex och filformatet till intel-standart.

Det är allt. Nu kan du börja skriva ditt första program. Skapa en ny källa/text och ange följande kod i den:

#omfatta"iom16.h" kort osignerad int i; tomhet huvud( tomhet) (DDRB = 255; PORTB = 0; medan(1) { om(PORTB == 255) PORTB = 0; annan PORTB++; för(i=0; i

Filen "iom16.h" finns i mappen (C:\Program Files)\IAR Systems\Embedded Workbench 3.2\avr\inc. Om du använder en annan MK, till exempel ATMega64, välj sedan filen "iom64.h". Dessa rubrikfiler lagrar information om MK:n: namnen på register, bitar i register och namnen på avbrott. Varje enskilt stift på port A, B, C eller D kan fungera som antingen en ingång eller en utgång. Detta bestäms av Data Direction Register (DDR). 1 gör benet till en utgång, 0 till en ingång. Genom att till exempel ställa in DDRA = 13, gör vi "benen" PB0, PB2, PB3-utgångarna, resten - ingångar, eftersom 13 i binär är 00001101.

PORTB är ett register som bestämmer tillståndet för portstiften. Efter att ha skrivit 0 där ställer vi in ​​spänningen vid alla utgångar till 0 V. Sedan finns det en ändlös slinga. Vid programmering av MK gör de alltid en ändlös loop där MK utför någon åtgärd tills den återställs eller tills ett avbrott inträffar. I denna cykel skriver de så att säga "bakgrundskod", som MK exekverar som det sista. Det kan till exempel vara att visa information på en display. I vårt fall utökas innehållet i PORTB-registret tills det är fullt. Efter det börjar allt om igen. Äntligen en tiotusen cykel för loop. Det behövs för att bilda en synlig fördröjning vid byte av tillståndet för port B.



Nu sparar vi den här filen i projektmappen som Prog1.c, kopierar filen iom16.h till projektmappen, väljer Projekt/Lägg till filer och lägger till "iom16.h" och "Prog1.c". Välj Release, tryck på F7, programmet kompileras och meddelandet ska visas:


Totalt antal fel: 0
Totalt antal varningar: 0

Här är en bild på min programmerare:

Ladda ner AVReal-programmeraren. Kopiera den (AVReal32.exe) till mappen Release/exe, där filen Prog1.hex ska finnas. Vi levererar ström till MK, anslut programmeringskabeln. Öppna Far Manager (det är mest bekvämt att flasha MK), gå till den här mappen, tryck Ctrl+O. Eftersom vi har en helt ny MK så grejar vi

avreal32.exe +MEGA16 -o11.0592MHZ -p1 -fblev=0,jtagen=1,cksel=F,sut=1 –w

Glöm inte att ange rätt frekvens om du inte använder 11059200 Hz! Samtidigt har den sk säkringar – register som styr dess funktion (användning av en intern generator, Jtag, etc.). Efter detta är den redo att ta emot det första programmet. Programmeraren får den använda LPT-porten, frekvensen, filnamnet och andra som parametrar (alla listas i beskrivningen av AVReal). Vi ringer:

Avreal32.exe +Mega16 -o11.0592MHz -p1 -e -w -az -% Prog1.hex

Om anslutningen är korrekt kommer programmeraren att rapportera lyckad programmering. Det finns ingen garanti för att detta kommer att fungera första gången (första gången du ringer programmet). Själv blir jag ibland programmerad andra gången. Kanske är LPT-porten defekt eller så finns det störningar i kabeln. Om problem uppstår, kontrollera din kabel noggrant. Av egen erfarenhet vet jag att 60% av felfunktionerna är förknippade med bristande kontakt på rätt plats, 20% med närvaron av en onödig sådan och ytterligare 15% med felaktig lödning av fel sak till fel sak. Om allt annat misslyckas, läs beskrivningen av programmeraren och försök bygga Byte Blaster.

Låt oss anta att allt fungerar för dig. Om du nu ansluter åtta lysdioder till port B på MK (gör detta med MK avstängd, och det är tillrådligt att inkludera 300-400 Ohm motstånd i serie med lysdioderna) och sätter på ström, kommer ett litet mirakel att hända - ett " våg” kommer att springa igenom dem!

© Kiselev Roman
maj 2007

december 2015

1. Fördelar med den föreslagna metoden

Enhetskretsar baserade på mikrokontroller (MCU) kännetecknas vanligtvis av en kombination av två svårkombinerade egenskaper: maximal enkelhet och hög funktionalitet. Dessutom kan funktionaliteten ändras och utökas i framtiden utan att göra några ändringar i kretsen - bara genom att byta ut programmet (blinkar). Dessa funktioner förklaras av det faktum att skaparna av moderna mikrokontroller försökte placera på ett chip allt som en utvecklare av en elektronisk enhet kunde behöva - åtminstone så mycket som möjligt. Som ett resultat av detta skedde en förskjutning i tyngdpunkten från kretsar och installation till mjukvara. Med användningen av MK är det nu mindre behov av att "ladda" kretsen med delar, och det finns färre kopplingar mellan komponenter. Detta gör naturligtvis kretsen mer attraktiv för upprepning av både erfarna och nybörjare elektronikingenjörer. Men som vanligt måste du betala för allt. Inte heller detta var utan svårigheter. Om du köper en ny MK, installerar den i en krets som är korrekt monterad av delar som kan repareras och sätter på ström, då kommer ingenting att fungera - enheten fungerar inte. Mikrokontrollern behöver ett program.

Det verkar som att allt är enkelt med detta också - på Internet kan du hitta många system med gratis firmware. Men här finns det en hake: den fasta programvaran måste på något sätt "laddas upp" till mikrokontrollern. För någon som aldrig har gjort det här förut blir en sådan uppgift ofta ett problem och den främsta avstötande faktorn, vilket ofta tvingar dem att överge nöjen med att använda MK och leta efter system baserade på "lös" och stel logik. Men allt är inte så komplicerat som det kan verka vid första anblicken.

Efter att ha analyserat publikationer på Internet kan du se att detta problem oftast löses på ett av två sätt: att köpa en färdig programmerare eller göra en hemmagjord. Samtidigt är publicerade kretsar av hemmagjorda programmerare väldigt ofta orimligt komplexa - mycket mer komplexa än vad som egentligen är nödvändigt. Naturligtvis, om du planerar att flasha MK varje dag, är det bättre att ha en "cool" programmerare. Men om behovet av en sådan procedur uppstår sällan, då och då, kan du klara dig utan en programmerare helt och hållet. Nej, vi pratar förstås inte om att lära oss göra detta med tankens kraft. Det betyder att genom att förstå hur programmeraren interagerar med mikrokontrollern när han skriver och läser information i dess programmeringsläge kan vi nöja oss med tillgängliga verktyg för ett bredare syfte. Dessa verktyg måste ersätta både mjukvaru- och hårdvarudelar av programmeraren. Hårdvaran måste tillhandahålla en fysisk anslutning till MK-mikrokretsen, förmågan att tillämpa logiska nivåer på dess ingångar och läsa data från dess utgångar. Mjukvarudelen måste säkerställa driften av algoritmen som kontrollerar alla nödvändiga processer. Vi noterar också att kvaliteten på inspelningsinformation i MK inte beror på hur "cool" din programmerare är. Det finns inget som heter "bättre inspelad" eller "sämre". Det finns bara två alternativ: "registrerad" och "ej registrerad". Detta förklaras av det faktum att inspelningsprocessen inuti kristallen styrs direkt av MK själv. Du behöver bara förse den med högkvalitativ ström (ingen störning eller krusning) och organisera gränssnittet ordentligt. Om resultaten av testavläsningen inte visar några fel, är allt i sin ordning - du kan använda styrenheten för dess avsedda syfte.

För att kunna skriva ett program i MK utan att ha en programmerare behöver vi en USB-RS232TTL portomvandlare och, likaså. USB-RS232TTL-omvandlaren låter dig använda en USB-port för att skapa en COM-port som skiljer sig från den "riktiga" endast genom att dess ingångar och utgångar använder logiska TTL-nivåer, det vill säga spänning i området från 0 till 5 volt ( du kan läsa mer i artikeln " "). I vilket fall som helst är en sådan omvandlare användbar att ha i ditt "hushåll", så om du inte redan har en, är den definitivt värd att köpa. När det gäller de logiska nivåerna är TTL i vårt fall till och med en fördel jämfört med en vanlig COM-port, eftersom ingångarna och utgångarna på en sådan port kan anslutas direkt till vilken mikrokontroller som helst som drivs av 5 V, inklusive ATtiny och ATmega. Men försök inte använda en vanlig COM-port - de använder spänningar i intervallet från -12 till +12 V (eller -15...+15V). I detta fall är direktanslutning till mikrokontrollern oacceptabel!!!

Idén att skapa ett skript för Perpetuum M-programmet, som implementerar programmerarens funktioner, uppstod efter att ha läst ett antal publikationer på Internet som erbjuder vissa lösningar för MK-firmware. I varje fall upptäcktes allvarliga brister eller alltför stora svårigheter. Ofta stötte jag på programmeringskretsar som innehöll en mikrokontroller, och samtidigt gavs råd på allvar som: "... och för att programmera mikrokontrollern för den här programmeraren kommer vi att behöva... det stämmer - en annan programmerare!" Därefter föreslogs det att gå till en vän, leta efter en betaltjänst osv. Kvaliteten på programvaran som distribuerades på nätverket för dessa ändamål var inte heller imponerande - många problem märktes både med funktionalitet och med "molnigheten" i användargränssnittet. Det tar ofta mycket tid att förstå hur man använder ett program - det måste studeras även för att utföra de enklaste åtgärderna. Ett annat program kan göra något under lång tid och flitigt, men användaren lär sig att ingenting skrivs till MK först efter att hela den fasta programvaran har slutförts helt och efterföljande testläsning. Följande problem uppstår också: användaren försöker välja sin MK från listan över kristaller som stöds, men den finns inte i listan. I det här fallet kommer du inte att kunna använda programmet - inkludering i listan över saknade MKs tillhandahålls som regel inte. Att manuellt välja en styrenhet från listan ser dessutom konstigt ut, med tanke på att programmeraren i många fall själv kan bestämma typen av MK. Allt detta sägs inte för att kasta lera på befintliga produkter, utan för att förklara orsaken till utseendet på manuset för Perpetuum M-programmet, som beskrivs i den här artikeln. Problemet finns verkligen, och det gäller framför allt nybörjare som inte alltid lyckas ta sig över denna "vägg" för att ta sitt första steg in i mikrokontrollernas värld. Det föreslagna manuset tar hänsyn till de brister som finns i andra program. Maximal "transparens" av algoritmens funktion har implementerats, ett extremt enkelt användargränssnitt som inte kräver inlärning och ger ingen chans att bli förvirrad och "klicka på fel sak." Om den nödvändiga MK inte är bland de som stöds kan du lägga till dess beskrivning själv, ta nödvändiga data från dokumentationen som laddats ner från MK-utvecklarens webbplats. Och, viktigast av allt, manuset är öppet för studier och modifiering. Vem som helst kan öppna den i en textredigerare, studera och redigera den efter eget gottfinnande, ändra befintliga funktioner efter sin smak och lägga till saknade.

Den första versionen av manuset skapades i juni 2015. Den här versionen ger endast stöd för Atmels ATtiny- och ATmega-mikrokontroller med funktioner för att skriva/läsa flashminne, ställa in konfigurationsbitar och automatiskt detektera styrenhetstypen. Skriva och läsa EEPROM är inte implementerat. Det fanns planer på att komplettera skriptets funktionalitet : lägg till att skriva och läsa EEPROM, implementera stöd för PIC-kontroller etc. Av denna anledning har skriptet ännu inte publicerats.Men på grund av tidsbrist försenades genomförandet av planen, och för att det bästa inte ska bli fienden till det goda, beslutades det att publicera den befintliga versionen. Om de redan implementerade funktionerna inte kommer att räcka, var snäll och bli inte upprörd. I det här fallet kan du försöka lägga till den önskade funktionen själv. Jag kommer inte att dölja: idén att skapa det här skriptet har till en början också en pedagogisk betydelse. Efter att ha förstått algoritmen och lagt till något eget till den, kommer du att kunna bättre förstå hur MK fungerar i programmeringsläge, så att i i framtiden kommer du inte att befinna dig i positionen som en tjej framför en trasig bil, eftertänksamt titta på dess insida och inte förstå varför det "inte fungerar".

2. MK-gränssnitt i programmeringsläge

Det finns flera olika sätt att försätta regulatorn i programmeringsläge och arbeta med den i detta läge. Det enklaste att implementera för styrenheter i ATtiny- och ATmega-serien är kanske SPI. Vi kommer att använda den.

Men innan vi börjar överväga de signaler som är nödvändiga för att generera SPI kommer vi att göra ett antal reservationer. Mikrokontrollern har konfigurationsbitar. Dessa är något som vippbrytare, omkoppling som låter dig ändra vissa egenskaper hos mikrokretsen i enlighet med projektets behov. Fysiskt sett är dessa icke-flyktiga minnesceller, som de som ett program skrivs in i. Skillnaden är att det finns väldigt få av dem (upp till tre byte för ATmega), och de är inte en del av adressutrymmet i något minne. Att skriva och läsa konfigurationsdata utförs av separata kommandon i MK-programmeringsläget. Nu är det viktigt att notera att vissa konfigurationsbitar påverkar själva förmågan att använda SPI. Med några av deras värden kan det visa sig att SPI inte kan användas. Om du stöter på en sådan mikrokontroller hjälper inte metoden som föreslås i den här artikeln. I det här fallet måste du antingen ändra inställningarna för konfigurationsbitarna i programmeraren, som stöder ett annat programmeringsläge, eller använda en annan mikrokontroller. Men det här problemet gäller bara begagnade MKs, eller de som någon redan utan framgång har "lekat med". Faktum är att nya MCU:er kommer med konfigurationsbitinställningar som inte hindrar användningen av SPI. Detta bekräftas av testresultaten av programmeringsskriptet för Perpetuum M-programmet, under vilket fyra olika MK:er (ATmega8, ATmega128, ATtiny13, ATtiny44) framgångsrikt flashades. De var alla nya. Den initiala inställningen av konfigurationsbitarna överensstämde med dokumentationen och störde inte användningen av SPI.

Med tanke på ovanstående bör du vara uppmärksam på följande bitar. SPIEN-biten tillåter eller förnekar uttryckligen användningen av SPI, därför måste i vårt fall dess värde vara aktiverande. RSTDISBL-biten kan vända en av utgångarna på mikrokretsen (förutbestämd) till ingången för "återställnings"-signalen, eller inte vända den (beroende på värdet som skrivits till denna bit). I vårt fall är "återställning"-ingången nödvändig (om den saknas kommer det inte att vara möjligt att växla MK till programmeringsläge via SPI). Det finns också bitar i CKSEL-gruppen som specificerar källan för klocksignalen. De förhindrar inte användningen av SPI, men de måste också hållas i åtanke, för om det inte finns några klockpulser alls, eller om deras frekvens är lägre än vad som är acceptabelt för en given SPI-hastighet, kommer inget bra att hända heller. Vanligtvis har nya MCU:er som har en intern RC-oscillator CKSEL-gruppbitarna konfigurerade för att använda den. Detta passar oss ganska bra - klockning tillhandahålls utan extra ansträngning från vår sida. Det finns inget behov av att löda kvartsresonatorn eller ansluta en extern generator. Om de angivna bitarna innehåller en annan inställning måste du ta hand om klockningen i enlighet med inställningen. I det här fallet kan det vara nödvändigt att ansluta en kvartsresonator eller en extern klockgenerator till MCU:n. Men i den här artikeln kommer vi inte att överväga hur detta görs. Exemplen på att ansluta en MK för programmering i den här artikeln är utformade för det enklaste fallet.

Ris. 1. Datautbyte via SPI i programmeringsläge

Låt oss nu gå till figur 1, hämtad från dokumentationen för ATmega128A MK. Den visar processen att sända en byte till MK och samtidigt ta emot en byte från MK. Båda dessa processer, som vi ser, använder samma klockpulser som levereras från programmeraren till mikrokontrollern vid dess SCK-ingång - en av mikrokretsens stift, för vilken en sådan roll är tilldelad i SPI-programmeringsläget. Ytterligare två signallinjer ger datamottagning och överföring en bit per klockcykel. Genom MOSI-ingången kommer data in i mikrokontrollern och läsdata tas från MISO-utgången. Lägg märke till de två prickade linjerna från SCK till MISO och MOSI. De visar i vilket ögonblick mikrokontrollern "sväljer" databiten som ställts in på MOSI-ingången, och vid vilken tidpunkt den själv ställer in sin egen databit till MISO-utgången. Allt är ganska enkelt. Men för att föra in MK i programmeringsläge behöver vi fortfarande en RESET-signal. Låt oss inte heller glömma den vanliga GND-kabeln och VCC-strömförsörjningen. Totalt visar det sig att endast 6 ledningar behöver anslutas till mikrokontrollern för att flasha dess firmware via SPI. Nedan kommer vi att analysera detta mer i detalj, men för nu kommer vi att lägga till att datautbyte med MK i programmeringsläge via SPI utförs i paket om 4 byte. Den första byten av varje paket är i princip helt tillägnad instruktionskodning. Den andra byten, beroende på den första, kan vara en fortsättning på kommandokoden, eller en del av adressen, eller kan ha ett godtyckligt värde. Den tredje byten används främst för att överföra adresser, men kan ha ett godtyckligt värde i många instruktioner. Den fjärde byten sänder vanligtvis data eller har ett godtyckligt värde. Samtidigt med överföringen av den fjärde byten tar vissa kommandon emot data som kommer från mikrokontrollern. Detaljer för varje kommando finns i styrenhetens dokumentation i tabellen "SPI Serial Programming Instruction Set". För närvarande noterar vi bara att hela utbytet med styrenheten är byggt av en sekvens av 32-bitars paket, i vart och ett av vilka inte mer än en byte med användbar information överförs. Detta är inte särskilt optimalt, men överlag fungerar det bra.

3. Anslutning av MK för programmering

För att säkerställa att alla nödvändiga signaler tillförs mikrokontrollerns ingångar för att organisera SPI-gränssnittet och läsa data från dess MISO-utgång, är det inte nödvändigt att skapa en programmerare. Detta kan enkelt göras med den vanligaste USB-RS232TTL-omvandlaren.

På Internet kan man ofta hitta information om att sådana omvandlare är sämre och att inget allvarligt kan göras med dem. Men när det gäller de flesta omvandlarmodeller är denna åsikt felaktig. Ja, det finns omvandlare till försäljning som inte har alla ingångar och utgångar tillgängliga jämfört med en standard COM-port (till exempel endast TXD och RXD), samtidigt som de har en icke-separerbar design (mikrokretsen är fylld med plast - det är omöjligt att nå sina stift). Men dessa är inte värda att köpa. I vissa fall kan du få de saknade portingångarna och utgångarna genom att löda kablarna direkt till chippet. Ett exempel på en sådan "förbättrad" omvandlare visas i figur 2 (chip PL-2303 - mer information om syftet med dess stift i artikeln ""). Detta är en av de billigaste modellerna, men har sina egna fördelar när den används i hemlagad design. Fullständiga adapterkablar med en standard niostiftskontakt i änden, som en COM-port, är också utbredda. De skiljer sig från en vanlig COM-port endast i TTL-nivåer och inkompatibilitet med äldre mjukvara och viss äldre hårdvara. Det kan också noteras att sladdarna på CH34x-chippet visar sig vara mycket mer pålitliga och stabila i olika extrema tester jämfört med omvandlare på PL-2303. Men vid normal användning är skillnaden inte märkbar.

När du väljer en USB-RS232TTL-omvandlare bör du också vara uppmärksam på dess drivrutins kompatibilitet med versionen av operativsystemet du använder.

Låt oss ta en närmare titt på principen för att ansluta en mikrokontroller och en USB-RS232TTL-omvandlare med hjälp av exemplet med fyra olika MK-modeller: ATtiny13, ATtiny44, ATmega8 och ATmega128. Figur 3 visar det allmänna diagrammet för en sådan anslutning. Det kan förvåna dig att veta att RS232-signalerna (RTS, TXD, DTR och CTS) används på ett olämpligt sätt. Men oroa dig inte för det: Perpetuum M-programmet kan arbeta med dem direkt - ställ in utvärden och läs ingångstillstånd. I vilket fall som helst ger de mycket använda USB-RS232TTL-omvandlarna på CH34x- och PL-2303-chips denna förmåga - detta har verifierats. Det bör inte heller vara några problem med andra populära omvandlare, eftersom standard Windows-funktioner används för att komma åt porten.

Motstånden som visas i det allmänna diagrammet kan i princip inte installeras, men det är fortfarande bättre att installera dem. Vad är deras syfte? Genom att använda omvandlarens TTL-ingångar och -utgångar och mikrokontrollerns fem-volts strömförsörjning slipper vi därmed behovet av att koordinera logiska nivåer - allt är redan helt korrekt. Detta betyder att anslutningarna kan vara direkta. Men under experiment , allt kan hända. Till exempel, enligt elakhetens lag, kan en skruvmejsel falla precis på den plats där den omöjligt kunde falla och kortsluta något som inte i något fall bör kortslutas. Naturligtvis kan vad som helst visa sig vara en "skruvmejsel". Motstånd i det här fallet minskar ibland konsekvenserna. ett av deras syften är att eliminera en möjlig utgångskonflikt.Faktum är att efter att programmeringen är klar går mikrokontrollern in i normalt driftläge, och det kan hända att dess stift kopplat till omvandlarens utgång (RTS, TXD eller DTR) också blir en utgång, enligt programmet som just spelades in i MK. I det här fallet blir det mycket dåligt om två direktanslutna utgångar "bråkar" - försök att ställa in olika logiska nivåer. I en sådan "kamp" kan någon "förlora", men det vill vi inte.

Värdena för de tre motstånden väljs på nivån 4,3 KOhm. Detta gäller anslutningar mellan omvandlarens utgång och mikrokontrollerns ingång. Noggrannheten hos motstånden spelar ingen roll: du kan minska deras motstånd till 1 KOhm eller öka det till 10 KOhm (men i det andra fallet ökar risken för störningar när du använder långa ledningar på väg till MK). När det gäller kopplingen mellan omvandlaringången (CTS) och mikrokontrollerutgången (MISO) används här ett 100 Ohm motstånd. Detta förklaras av särdragen hos ingången på den använda omvandlaren. Under testerna användes en omvandlare på mikrokretsen PL-2303, vars ingångar uppenbarligen är anslutna till strömförsörjningen positiv med ett relativt lågt motstånd (i storleksordningen flera hundra ohm). För att "bryta uppdraget" var jag tvungen att installera ett motstånd med så litet motstånd. Du behöver dock inte installera det alls. På omvandlaren är detta alltid ingången. Det kan inte bli en utväg, vilket innebär att det inte kommer att uppstå någon konflikt mellan utgångar i någon händelseutveckling.

Om chipet har ett separat AVCC-stift för att driva analog-till-digital-omvandlaren (till exempel ATmega8 eller ATmega128), ska det anslutas till det gemensamma VCC-strömstiftet. Vissa IC:er har mer än ett VCC-strömstift eller mer än en GND. Till exempel har ATmega128 3 GND-stift och 2 VCC-stift. I en permanent design är det bättre att ansluta stift med samma namn till varandra. I vårt fall, under programmering, kan du använda en VCC- och GND-stift vardera.

Och här är hur ATtiny13-anslutningen ser ut. Figuren visar stifttilldelningarna som används vid programmering via SPI. Bredvid bilden ser du hur en tillfällig anslutning ser ut i verkligheten.


Vissa kanske säger att detta inte är allvarligt - anslutningar på ledningarna. Men du och jag är förnuftiga människor. Vårt mål är att programmera mikrokontrollern, spendera ett minimum av tid och andra resurser på den, och inte att visa upp sig inför någon. Kvaliteten blir inte lidande. Metoden "på ledningar" i det här fallet är ganska effektiv och motiverad. Att flasha styrenhetens firmware är en engångsprocedur, så det är ingen idé att täcka den med strass. Om det är avsett att ändra firmware i framtiden utan att ta bort styrenheten från kretsen (i den färdiga produkten), så tas detta i beaktande under installationen under tillverkningen av enheten. Vanligtvis installeras en kontakt (RESET, SCK, MOSI, MISO, GND) för detta ändamål, och MK kan blinka även efter installation på kortet. Men det här är kreativa nöjen. Vi överväger det enklaste fallet.

Låt oss nu gå vidare till ATtiny44 MK. Allt är ungefär sig likt här. Baserat på ritningen och fotot kommer inte ens en nybörjare att ha några svårigheter att ta reda på sambandet. Precis som ATtiny44 kan du ansluta ATtiny24 och ATtiny84 mikrokontroller - stifttilldelningarna för dessa tre är desamma.


Ett annat exempel på att tillfälligt ansluta en styrenhet för att programmera den är ATmega8. Det finns fler stift här, men principen är densamma - några ledningar, och nu är styrenheten redo att "fylla" information i den. Den extra svarta tråden på bilden som kommer från stift 13 deltar inte i programmeringen. Den är utformad för att ta bort en ljudsignal från den efter att MK lämnar programmeringsläget. Detta beror på det faktum att under felsökningen av manuset för "Perpetuum M" laddades musikboxprogrammet ner till MK.


Ofta finns en styrenhet tillgänglig i olika höljen. I det här fallet fördelas tilldelningen av stift för varje fall annorlunda. Om höljet på din kontroller inte liknar det som visas i figuren, kontrollera syftet med stiften i den tekniska dokumentationen, som kan laddas ner från MK-utvecklarens webbplats.

För att komplettera bilden, låt oss titta på att ansluta en MK-mikrokrets med ett stort antal "ben". Syftet med den extra svarta tråden på bilden som kommer från stift 15 är exakt samma som i fallet med ATmega8.


Du är förmodligen redan övertygad om att allt är ganska enkelt. Alla som vet hur man räknar stiften på mikrokretsar (från märket i en cirkel moturs) kommer att räkna ut det. Och glöm inte noggrannheten. Mikrokretsar älskar snygga människor och förlåter inte slarvig behandling.

Innan du går vidare till mjukvarudelen, se till att USB-RS232TTL-omvandlardrivrutinen är korrekt installerad (kontrollera Windows Enhetshanteraren). Kom ihåg eller skriv ner numret på den virtuella COM-porten som visas när du ansluter omvandlaren. Detta nummer kommer att behöva skrivas in i texten i manuset, som du kan läsa om nedan.

4. Script - programmerare för "Perpetuum M"

Vi kom på hårdvarudelen av "programmeraren". Detta är redan halva striden. Nu återstår det att ta itu med mjukvarudelen. Dess roll kommer att utföras av Perpetuum M-programmet under kontroll av ett skript, som implementerar alla nödvändiga funktioner för att interagera med mikrokontrollern.

Arkivet med skriptet ska packas upp i samma mapp där programmet perpetuum.exe finns. I det här fallet, när du kör filen perpetuum.exe, kommer en meny att visas på skärmen med en lista över installerade skript, bland vilka det kommer att finnas raden "AVR MK Programmer" (det kan vara den enda). Det här är linjen vi behöver.

Skriptet finns i PMS-mappen i filen "MK Programmer AVR.pms". Den här filen kan ses, studeras och redigeras vid behov i en vanlig textredigerare som Windows Notepad. Innan du använder skriptet kommer du troligen behöva göra ändringar i texten som är relaterad till portinställningar. För att göra detta, kontrollera namnet på porten som används i Windows Device Manager och, om nödvändigt, gör lämpliga ändringar på raden "PortName="COM4";" - istället för siffran 4 kan det finnas ett annat nummer. När du använder en annan USB-RS232TTL-omvandlarmodell kan du också behöva ändra inställningarna för signalinvertering (skriptrader som börjar med ordet "Hög"). Du kan kontrollera inverteringen av signaler med USB-RS232TTL-omvandlaren med hjälp av ett av exemplen i instruktionerna för Perpetuum M-programmet (avsnitt med funktioner för att arbeta med porten).

Undermappen MK_AVR innehåller filer med beskrivningar av styrenheter som stöds. Om kontrollern du behöver inte finns bland dem kan du lägga till den du behöver själv, enligt en analogi. Ta en av filerna som ett exempel och använd en textredigerare för att ange nödvändiga data, ta dem från dokumentationen för din mikrokontroller. Det viktigaste är att vara försiktig, ange data utan fel, annars kommer MK inte att programmeras eller programmeras felaktigt. Den ursprungliga versionen stöder 6 mikrokontroller: ATtiny13, ATtiny24, ATtiny44, ATtiny84, ATmega8 och ATmega128. Skriptet implementerar automatisk igenkänning av den anslutna styrenheten - du behöver inte specificera det manuellt. Om identifieraren som lästs från MK inte finns bland de tillgängliga beskrivningarna visas ett meddelande om att styrenheten inte kunde kännas igen.

Arkivet med manuset innehåller också ytterligare information. Mappen AVR controller inc files innehåller en mycket användbar och omfattande samling av controller definitionsfiler. Dessa filer används när du skriver dina egna program för MK. Ytterligare fyra mappar "MusicBox_..." innehåller filer med ett program i Assembly-språk och firmware redo för nedladdning till MK separat för ATtiny13, ATtiny44, ATmega8 och ATmega128. Om du redan har anslutit en av dessa MKs för programmering, som föreslås i den här artikeln, kan du flasha den just nu - du kommer att få en speldosa. Mer om detta nedan.

När du väljer raden "MK AVR Programmer" i skriptmenyn börjar skriptet att köras. Samtidigt öppnar den porten, skickar ett kommando till MK att byta till programmeringsläge, får bekräftelse från MK om den lyckade övergången, begär MK-identifierare och söker efter en beskrivning av denna MK med dess identifierare bland de tillgängliga filer med beskrivningar. Om den inte hittar den önskade beskrivningen visar den ett motsvarande meddelande. Om en beskrivning hittas öppnas programmerarens huvudmeny. Du kan se dess skärmdump i figur 8. Ytterligare förståelse är inte svårt - menyn är mycket enkel.

I den första versionen av skriptet är vissa funktioner hos en fullfjädrad programmerare inte implementerade. Det finns till exempel inget sätt att läsa och skriva till EEPROM. Men om du öppnar skriptet i en textredigerare kommer du att se att det är väldigt litet, trots att det viktigaste redan är implementerat i det. Detta tyder på att det inte är så svårt att lägga till de saknade funktionerna - språket är väldigt flexibelt, det låter dig implementera rik funktionalitet i ett litet program. Men i de flesta fall räcker även de befintliga funktionerna.

Vissa funktionsbegränsningar beskrivs direkt i skripttexten:
//implementerade inspelning endast från nolladressen (Utökad segmentadresspost ignoreras, LOAD OFFSET - också)
//ordningen och kontinuiteten för poster i HEX-filen kontrolleras inte
//kontrollsumma är inte markerad
Detta gäller att arbeta med en HEX-fil, från vilken firmwarekoden för MK:n är hämtad. Om den här filen inte är skadad kommer det inte att ha någon effekt att kontrollera kontrollsumman. Om det är förvrängt kommer det inte att vara möjligt att upptäcka det med skriptet. I de flesta fall kommer de återstående begränsningarna inte att skada, men du måste fortfarande ha dem i åtanke.

5. Speldosa - ett enkelt hantverk för nybörjare

Om du har en av dessa mikrokontroller: ATtiny13, ATtiny44, ATmega8 eller ATmega128, kan du enkelt förvandla den till en speldosa eller musikkort. För att göra detta räcker det att skriva motsvarande firmware i MK - en av de fyra som finns i mapparna "MusicBox_..." i samma arkiv med skriptet. Firmware-koder lagras i filer med tillägget ".hex". Att använda ATmega128 för ett sådant hantverk är naturligtvis "fett", precis som ATmega8. Men detta kan vara användbart för att testa eller experimentera, med andra ord i utbildningssyfte. Texterna till programmen i Assembler bifogas också. Programmen skapades inte från grunden - musikboxprogrammet från A.V. Belovs bok "AVR Microcontrollers in Amateur Radio Practice" togs som grund. Det ursprungliga programmet har genomgått ett antal betydande förändringar:
1. anpassad för var och en av de fyra MK:erna: ATtiny13, ATtiny44, ATmega8 och ATmega128
2. knappar har tagits bort - ingenting behöver anslutas till kontrollern förutom ström och en ljudsändare (melodierna spelas en efter en i en oändlig loop)
3. varaktigheten för varje ton reduceras med varaktigheten av pausen mellan tonerna för att eliminera störningar i musikalisk rytm
4. den åttonde melodin är kopplad, används inte i bokversionen
5. från det subjektiva: några "förbättringar" för att optimera och göra algoritmen lättare att förstå

I vissa melodier kan man höra falskhet och till och med grova fel, speciellt i "Smile" - i mitten. Ringsignalkoderna togs från boken (eller snarare, laddades ner från bokens författares webbplats tillsammans med den ursprungliga asm-filen) och har inte ändrats. Tydligen finns det fel i kodningen av melodierna. Men det här är inget problem - alla som är "vänliga" med musik kan enkelt lista ut det och fixa allt.

I ATtiny13, på grund av avsaknaden av en 16-bitarsräknare, måste en 8-bitarsräknare användas för att reproducera toner, vilket ledde till en liten minskning av tonernas noggrannhet. Men detta märks knappt på gehör.

Om konfigurationsbitarna. Deras inställningar måste motsvara tillståndet för den nya mikrokontrollern. Om din MK har använts någonstans tidigare måste du kontrollera tillståndet för dess konfigurationsbitar och, om nödvändigt, anpassa dem till inställningarna för den nya mikrokontrollern. Du kan ta reda på tillståndet för konfigurationsbitarna för den nya mikrokontrollern från dokumentationen för denna MK (avsnittet "Säkringsbitar"). Undantaget är ATmega128. Denna MCU har M103C-biten, som möjliggör kompatibilitetsläge med den äldre ATmega103. Aktivering av M103C-biten minskar avsevärt kapaciteten hos ATmega128, och denna bit är aktiv på den nya MK. Du måste återställa M103C till ett inaktivt tillstånd. För att manipulera konfigurationsbitar, använd motsvarande sektion av programmerarens skriptmeny.

Det är ingen idé att ge ett diagram över speldosan: den innehåller bara en mikrokontroller, strömförsörjning och en piezo-ljudsändare. Strömförsörjningen sker på exakt samma sätt som vi gjorde vid programmering av MK. Ljudsändaren ansluts mellan den gemensamma ledningen (regulatorns GND-stift) och en av MK-stiften, vars nummer finns i filen med programsammansättningskoden (*.asm). I början av programtexten för varje MK i kommentarerna finns en rad: "ljudsignalen genereras vid stift XX." När programmeringsskriptet är klart, lämnar mikrokontrollern programmeringsläget och går in i normal drift. Uppspelning av melodier börjar omedelbart. Genom att ansluta en ljudsändare kan du kontrollera detta. Du kan lämna ljudsändaren ansluten medan du programmerar kristallen endast om ljudet tas från ett stift som inte används i SPI, annars kan den extra kapacitansen på stiftet störa programmeringen.