Programmera mikrokontroller i C från grunden. CodeVisionAVR. Allmän information för nybörjare i programmering i C-språket. Vilken mikrokontroller att välja för jobbet

På något sätt kände jag mig omedelbart tvungen att ge råd om att välja en programmeringsmiljö för AVR-kontroller. Kasta bara inte tofflor på mig. Jag är bara lite :)

Det finns många programmeringsspråk för mikrokontroller. Det finns också en hel del programmeringsmiljöer och det är felaktigt att jämföra dem med varandra. Bästa språken programmering finns inte. Det betyder att du måste välja det språk och programmeringsmiljö som passar dig bäst.

Om du för närvarande står inför ett val av vad du ska börja arbeta med, så kommer här några rekommendationer för dig.

Tidigare erfarenhet av programmering. Försumma inte din tidigare programmeringserfarenhet. Även om det var BASIC. Även om det var länge sedan i skolan. Programmering är som att cykla – när du väl börjar kommer du snabbt ihåg allt du har glömt. Börja med BASIC - behärska det - senare blir det lättare att välja något mer lämpligt för dina ändamål.

Hjälp från omgivningen. Skriver dina vänner i Pascal? Problemet är löst för dig - skriv i Pascal! De hjälper dig alltid med råd, ger dig bibliotek och ger dig färdiga projekt att studera. I allmänhet kommer de gärna att välkomna dig till deras community. Om du gör tvärtom får du motsatt resultat. Vänner till CIS-industrin kommer att hacka dig om du bestämmer dig för att studera Assembler. Förvänta dig inte hjälp.

Bra bok på AVR programmering kommer att hjälpa mycket. Tyvärr är det väldigt få av dem. Om du stöter på en bok och du tycker att allt är förklarat på ett mycket lättillgängligt sätt, prova den. Jag rekommenderar inte att du studerar från e-böcker; som en sista utväg, skriv ut dem. Det är väldigt obekvämt att växla mellan miljön och bokfilens text. Det är mycket trevligare att läsa en bok och prova den direkt, utan att bli distraherad av att byta; dessutom kan du göra anteckningar i marginalen och skriva ner de idéer som dyker upp.

Programmeringsmiljön är enklare. Om det finns flera programmeringsmiljöer för ditt språk att välja mellan, tveka inte, välj den som är enklare. Låt det vara mindre funktionellt. Låt henne sammanställa fruktansvärt uppsvälld kod. Huvudsaken är att bara börja jobba. När du väl blivit bekväm i en enkel miljö kan du enkelt flytta till en mer avancerad och "korrekt" miljö. Och lyssna inte på de som säger att du kommer att förlora mer tid - de har fel. Grundskoleelever ombeds inte läsa "Krig och fred", de får enklare böcker - med bilder.

Bibliotek. Tillgången till bibliotek är kontroversiell för språkinlärning. Naturligtvis kommer de senare att göra livet mycket lättare, men till en början är "Black Box"-bibliotek obegripliga och bidrar inte riktigt till att förstå språket. Å andra sidan gör de program lättare att läsa och låter en nybörjare bygga komplexa program utan större ansträngning. Så bry dig inte för mycket om deras närvaro. Åtminstone till en början.

Effektiv kod. Att välja en programmeringsmiljö för att lära sig programmering baserat enbart på hur effektiv koden den kompilerar är en dålig idé. Huvudsaken är att du känner dig bekväm när du börjar plugga – det som kommer ut av det är det tionde. Naturligtvis kan du arbeta med detta senare.

Trollkarlar. Alla enheter ombord på chippet måste konfigureras med portar. Proceduren är ganska tråkig och datablad krävs. Dessutom finns det nyanser som inte är lätta för en nybörjare att förstå. Därför är det mycket önskvärt att ha trollkarlar i miljön. Vyzards är automatiska tuners för SPI, I2C, USART, etc. Ju fler enheter som stöds, desto bättre. Du ställer in de nödvändiga perifera parametrarna, och guiden genererar själv kod som kommer att tillhandahålla de angivna parametrarna. Gör livet mycket lättare.


Allmänna rekommendationer sådan - programmering i inledningsskedet bör vara så enkel som möjligt (även primitiv). Programmeringsmiljön ska vara lätt att lära sig (eftersom du först måste behärska programmering och inte slösa tid på att pilla med inställningarna). Helst russifierad. En rysk manual och exempel på program skulle också vara till hjälp. Förmågan att flasha kristallen från omgivningen är önskvärd. Sedan, när du behärskar grunderna i programmering, kan du gå vidare till mer komplexa skal.


En sista rekommendation: arbeta med en riktig kristall. Var inte rädd för att bränna den. Skaffa praktisk erfarenhet. Att arbeta med emulatorer (till exempel Proteus), även om det kommer att befria dig från att krångla med en lödkolv, kommer aldrig att kunna ge dig den tillfredsställelse som du kommer att få från arbetsprogrammet och den första blinkningen av lysdioden! Att förstå att du har gjort ett riktigt arbetsdiagram med dina egna händer ger dig självförtroende och incitament att gå vidare!

(Besökt 7 377 gånger, 1 besök idag)

Hej, kära Habrazhitel!

I den här artikeln vill jag prata om hur jag en gång bestämde mig för att börja programmera mikrokontroller, vad som behövdes för detta och vad som slutade hända.

Ämnet mikrokontroller intresserade mig för länge sedan, redan 2001. Men då visade det sig vara problematiskt att skaffa en programmerare på min bostad, och det var inte tal om att köpa den via Internet. Jag var tvungen att skjuta upp denna fråga till bättre tider. Och så, en vacker dag, upptäckte jag att bättre tider hade kommit utan att lämna hemmet, jag kunde köpa allt jag behövde. Jag bestämde mig för att prova. Så vad vi behöver:

1. Programmerare
Det finns många alternativ på marknaden - från de billigaste ISP-programmerarna (In-System Programming) för några dollar, till kraftfulla programmerare-debuggers för ett par hundra. Jag hade inte mycket erfarenhet i den här frågan, först bestämde jag mig för att prova en av de enklaste och billigaste - USBasp. Jag köpte den på eBay en gång för $12, nu kan du hitta den för till och med $3-4. Detta är faktiskt en kinesisk version av programmeraren från Thomas Fischl. Vad kan jag säga om honom? Bara en sak - det fungerar. Dessutom stöder den en hel del AVR-kontroller i ATmega- och ATtiny-serien. Under Linux kräver ingen drivrutin.

För att flasha den fasta programvaran måste du ansluta programmeringsutgångarna VCC, GND, RESET, SCK, MOSI, MISO med motsvarande utgångar på mikrokontrollern. För enkelhetens skull monterade jag hjälpkretsen direkt på brödbrädan:

Till vänster på kortet finns samma mikrokontroller som vi ska flasha.

2. Mikrokontroller
Jag brydde mig inte så mycket om valet av mikrokontroller och tog ATmega8 från Atmel - 23 I/O-stift, två 8-bitars timer, en 16-bit, frekvens upp till 16 MHz, låg förbrukning (1-3,6 mA) , billigt ($2). I allmänhet, till en början - mer än tillräckligt.

Under Linux fungerar kombinationen avr-gcc + avrdude bra för att kompilera och ladda inbyggd programvara på styrenheten. Installationen är trivial. Genom att följa instruktionerna kan du installera all nödvändig programvara på några minuter. Den enda nyansen som du bör vara uppmärksam på är att avrdude (programvara för inspelning till styrenheten) kan kräva superanvändarrättigheter för att komma åt programmeraren. Lösningen är att köra den via sudo (ingen bra idé), eller registrera speciella udev-rättigheter. Syntaxen kan skilja sig åt i olika OS-versioner, men i mitt fall ( Linux Mint 15) att lägga till följande regel i filen /etc/udev/rules.d/41-atmega.rules fungerade:

# USBasp programmerare SUBSYSTEM=="usb", ATTR(idVendor)=="16c0", ATTR(idProduct)=="05dc", GROUP="plugdev", MODE="0666"

Efter detta måste du naturligtvis starta om tjänsten
service udev omstart
Du kan kompilera och flasha utan problem direkt från kommandorad(vem skulle tvivla på det), men om det finns många projekt så är det bekvämare att installera ett plugin och göra allt direkt från Eclipse-miljön.

För Windows måste du installera en drivrutin. Annars är det inga problem. För det vetenskapliga intressets skull provade jag kombinationen AVR Studio + eXtreme Burner på Windows. Återigen, allt fungerar utmärkt.

Låt oss börja programmera

AVR-kontroller kan programmeras både i assembler (AVR assembler) och i C. Här tycker jag att alla ska göra sitt eget val beroende på den specifika uppgiften och sina preferenser. Själv började jag först mixtra med assembler. Vid programmering i assembler blir enhetens arkitektur tydligare och man får en känsla av att man fördjupar sig direkt i kontrollerns insida. Dessutom tror jag att i program som är särskilt kritiska till storlek och prestanda kan kunskap om assembler vara mycket användbar. Efter att ha bekantat mig med AVR-montören kröp jag till C.

Efter att ha bekantat mig med arkitekturen och grundläggande principer bestämde jag mig för att sätta ihop något användbart och intressant. Här hjälpte min dotter mig, hon spelar schack och en vacker kväll sa hon att hon ville ha en klocka för tidsinställda spel. BAM! Här är den - idén med det första projektet! Du kan såklart beställa dem på eBay, men jag ville göra min egen klocka, med svarta... eh... indikatorer och knappar. Inte tidigare sagt än gjort!

Det beslutades att använda två 7-segments diodindikatorer som display. För kontroll räckte 5 knappar - "Spelare 1", "Spelare 2", "Återställ", "Inställningar" och "Paus". Tja, glöm inte ljudindikationen för slutet av spelet. Ser ut som det är det. Bilden nedan visar ett allmänt diagram för att ansluta mikrokontrollern till indikatorer och knappar. Vi kommer att behöva det när vi analyserar programmets källkod:

Debriefing

Låt oss börja, som förväntat, från programmets startpunkt - huvudfunktionen. I själva verket finns det inget anmärkningsvärt med det - att sätta upp portar, initiera data och en oändlig slinga av bearbetningsknapptryckningar. Jo, anropar sei() - möjliggör avbrottsbehandling, mer om dem lite senare.

Int main(void) ( init_io(); init_data(); sound_off(); sei(); while(1) ( handle_buttons(); ) return 0; )
Låt oss titta på varje funktion separat.

Void init_io() ( // set output DDRB = 0xFF; DDRD = 0xFF; // set input DDRC = 0b11100000; // pull-up resistors PORTC |= 0b00011111; // timer avbryter TIMSK = (1)<

Att ställa in I/O-portar är mycket enkelt - ett nummer skrivs in i DDRx-registret (där x är bokstaven som anger porten), som varje bit betyder om motsvarande stift kommer att vara en inmatningsenhet (motsvarar 0) eller en utenhet (motsvarar 1). Genom att skicka numret 0xFF till DDRB och DDRD skapade vi B- och D-utgångsportar. Följaktligen är DDRC-kommandot = 0b11100000; omvandlar de första 5 stiften i port C till ingångsstift och de återstående till utgångsstift. PORTC-kommando |= 0b00011111; inkluderar interna pull-up-motstånd på 5 styringångar. Enligt diagrammet är knappar anslutna till dessa ingångar, som när de trycks ned kortsluter dem till jord. På så sätt förstår styrenheten att knappen är nedtryckt.

Därefter kommer inställningen av två timers, Timer0 och Timer1. Vi använder den första för att uppdatera indikatorerna och den andra för att räkna ner tiden, efter att vi tidigare har konfigurerat den för att avfyras varje sekund. En detaljerad beskrivning av alla konstanter och metoden för att ställa in timern till ett specifikt intervall finns i ATmega8-dokumentationen.

Avbryt hanteringen

ISR (TIMER0_OVF_vect) ( display(); if (_buzzer > 0) ( _buzzer--; if (_buzzer == 0) sound_off(); ) ) ISR(TIMER1_COMPA_vect) ( if (ActiveTimer == 1 && Timer1 > 0) ( Timer1--; if (Timer1 == 0) process_timeoff(); ) if (ActiveTimer == 2 && Timer2 > 0) ( Timer2--; if (Timer2 == 0) process_timeoff(); ) )

När timern utlöses överförs kontrollen till lämplig avbrottshanterare. I vårt fall är detta TIMER0_OVF_vect-hanteraren, som anropar proceduren för att visa tid på indikatorer, och TIMER1_COMPA_vect, som bearbetar nedräkningen.

Utdata till indikatorer

Void display() ( display_number((Timer1/60)/10, 0b00001000); _delay_ms(0.25); display_number((Timer1/60)%10, 0b00000100); _delay_ms(0.25); display_number((Timer)/10%6 , 0b00000010); _delay_ms(0.25); display_number((Timer1%60)%10, 0b00000001); _delay_ms(0.25); display_number((Timer2/60)/10, 0b100000000);(0b100000000);(0b100000000);(0b100000000);(rnumber.delay_5); 60)%10, 0b01000000); _delay_ms(0,25); display_number((Timer2%60)/10, 0b00100000); _delay_ms(0.25); display_number((Timer2%60)%10, 0b0001);(0b0001); = 0; ) void display_number(int nummer, int mask) ( PORTB = nummer_mask(nummer); PORTD = mask; )

Visningsfunktionen använder en dynamisk visningsmetod. Faktum är att varje enskild indikator har 9 kontakter (7 för segmentstyrning, 1 för punkt och 1 för effekt). För att styra 4 siffror skulle 36 kontakter behövas. För slösaktigt. Därför är utmatningen av siffror till en indikator med flera siffror organiserad enligt följande princip:

Spänning tillförs växelvis var och en av de gemensamma kontakterna, vilket gör att du kan markera önskat nummer på motsvarande indikator med samma 8 kontrollkontakter. Vid en tillräckligt hög utfrekvens ser det ut som en statisk bild för ögat. Det är därför alla 8 strömkontakter för båda indikatorerna i diagrammet är anslutna till 8 utgångar på port D, och 16 segmentstyrande kontakter är kopplade i par och anslutna till 8 utgångar på port B. Displayen fungerar alltså med en fördröjning på 0,25 ms visar växelvis önskat nummer på var och en av indikatorerna. Slutligen stängs alla utgångar som matar spänning till indikatorerna av (kommando PORTD = 0;). Om detta inte görs, kommer den senast visade siffran att fortsätta att lysa tills nästa anrop till displayfunktionen, vilket kommer att leda till dess starkare sken jämfört med resten.

Hantera klick

Void handle_buttons() ( handle_button(KEY_SETUP); handle_button(KEY_RESET); handle_button(KEY_PAUSE); handle_button(KEY_PLAYER1); handle_button(KEY_PLAYER2); ) void handle_button(int nyckel) (int bit; switch (nyckel) (case KEY_SETUP) = SETUP_BIT; break; case KEY_RESET: bit = RESET_BIT; break; case KEY_PAUSE: bit = PAUSE_BIT; break; case KEY_PLAYER1: bit = PLAYER1_BIT; break; case KEY_PLAYER2: bit = PLAYER2_BIT; bryta om (standard: bit return_; är_) BUTTON_PIN, bit)) ( if (_pressed == 0) ( _delay_ms(DEBOUNCE_TIME); if (bit_is_clear(BUTTON_PIN, bit)) ( _pressed |= tangent; // tangentåtgärdsomkopplare (key) (case KEY_SETUP: process_setup(); break; case KEY_RESET: process_reset(); break; case KEY_PAUSE: process_pause(); break; case KEY_PLAYER1: process_player1(); break; case KEY_PLAYER2: process_player2(); break; ) sound_on(15); ) ) ) else ( _pressed &= ~nyckel; ) )

Denna funktion kontrollerar alla 5 knapparna i tur och ordning och bearbetar klicket, om det finns något. Klicket registreras genom att markera bit_is_clear(BUTTON_PIN, bit) , dvs. knappen trycks in om motsvarande ingång är ansluten till jord, vilket kommer att ske, enligt diagrammet, när knappen trycks ned. En fördröjning på DEBOUNCE_TIME och upprepad kontroll krävs för att undvika flera onödiga operationer på grund av kontaktstuds. Att spara den intryckta statusen i motsvarande bitar av variabeln _pressed används för att förhindra upprepad triggning när knappen trycks ned länge.
Funktionerna för att bearbeta klick är ganska triviala och jag anser att de inte behöver ytterligare kommentarer.

Hela programmets text

#define F_CPU 4000000UL #inkludera #omfatta #omfatta #define DEBOUNCE_TIME 20 #define BUTTON_PIN PINC #define SETUP_BIT PC0 #define RESET_BIT PC1 #define PAUSE_BIT PC2 #define PLAYER1_BIT PC3 #define PLAYER2_BIT PC4 #define KEY_SETUP 0b000000 #define #define KEY_SETUP 0b000000 #define fin KEY_PAUSE 0b00000100 #define KEY_PLAYER1 0b00001000 #define KEY_PLAYER2 0b00010000 flyktig int ActiveTimer = 0; flyktig int Timer1 = 0; flyktig int Timer2 = 0; volatil int _buzzer = 0; volatile int _pressed = 0; // funktionsdeklarationer void init_io(); void init_data(); int nummer_mask(int antal); void handle_buttons(); void handle_button(int-nyckel); void process_setup(); void process_reset(); void process_pause(); void process_timeoff(); void process_player1(); void process_player2(); void display(); void display_number(int mask, int number); void sound_on(int interval); void sound_off(); // avbryter ISR (TIMER0_OVF_vect) ( display(); if (_buzzer > 0) ( _buzzer--; if (_buzzer == 0) sound_off(); ) ) ISR(TIMER1_COMPA_vect) ( if (ActiveTimer == 1 && Timer1 > 0) ( Timer1--; if (Timer1 == 0) process_timeoff(); ) if (ActiveTimer == 2 && Timer2 > 0) ( Timer2--; if (Timer2 == 0) process_timeoff(); ) ) int main (void) ( init_io(); init_data(); sound_off(); sei(); while(1) ( handle_buttons(); ) return 0; ) void init_io() ( // set output DDRB = 0xFF; DDRD = 0xFF ; // ställ in ingång DDRC = 0b11100000; // pull-up motstånd PORTC |= 0b00011111; // timer avbryter TIMSK = (1<5940 || Timer2 > 5940) ( Timer1 = 0; Timer2 = 0; ) ) void process_reset() ( init_data(); ) void process_timeoff() ( init_data(); sound_on(30); ) void process_pause() ( ActiveTimer = 0; ) void process_player1() ( ActiveTimer = 2; ) void process_player2() ( ActiveTimer = 1; ) void handle_button(int nyckel) ( int bit; switch (nyckel) ( case KEY_SETUP: bit = SETUP_BIT; break; case KEY_RESET: bit = RESET_BIT ; break; case KEY_PAUSE: bit = PAUSE_BIT; break; case KEY_PLAYER1: bit = PLAYER1_BIT; break; case KEY_PLAYER2: bit = PLAYER2_BIT; break; default: return; ) if (bit_is_clear(BUTTON_PIN, bit)) ( om (_pressad 0) ( _delay_ms(DEBOUNCE_TIME); if (bit_is_clear(BUTTON_PIN, bit)) ( _pressed |= tangent; // tangentåtgärdsomkopplare (key) ( case KEY_SETUP: process_setup(); break; case KEY_RESET: process_reset(); break; case KEY_PAUSE: process_pause(); break; case KEY_PLAYER1: process_player1(); break; case KEY_PLAYER2: process_player2(); break; ) sound_on(15); ) ) ) else ( _tryckte på &= ~tangenten; ) ) void handle_buttons() ( handle_button(KEY_SETUP); handle_button(KEY_RESET); handle_button(KEY_PAUSE); handle_button(KEY_PLAYER1); handle_button(KEY_PLAYER2); ) void display() ( display_number((Timer1/60)/0b000, 0b ; _delay_ms(0.25); display_number((Timer1/60)%10, 0b00000100); _delay_ms(0.25); display_number((Timer1%60)/10, 0b00000010); _delay_ms(0.25) display_ms(0.25) 10, 0b00000001); _delay_ms(0.25); display_number((Timer2/60)/10, 0b10000000); _delay_ms(0.25); display_number((Timer2/60)%10, 0b0100000ms;layTimer_number_de.( %60)/10, 0b00100000); _delay_ms(0.25); display_number((Timer2%60)%10, 0b00010000); _delay_ms(0.25); PORTD = 0; ) void display_number (int tal, int B mask) nummer (mask) (nummer); PORTD = mask; ) void sound_on(int interval) ( _buzzer = intervall; // put buzzer pin high PORTC |= 0b00100000; ) void sound_off() ( // put buzzer pin low PORTC &= ~0b00100000; )

Prototypen monterades på en brödbräda.

Lektion 0.

Så idag öppnar vi en serie lektioner om programmering av mikrokontroller i AVR-familjen.

Idag kommer följande frågor att behandlas:

  1. Vad är en mikrokontroller?
  2. Var används mikrokontroller?

Introduktion.

Mikrokontroller finns överallt. I telefoner, tvättmaskiner, ”smarta hem”, verktygsmaskiner i fabriker och även i otaliga andra tekniska apparater. Deras utbredda användning gör det möjligt att ersätta komplexa analoga kretsar med mer komprimerade digitala.

Så vad är en mikrokontroller?

Mikrokontroller (Micro Controller Unit, MCU) - en mikrokrets designad för att styra elektroniska enheter. Du kan föreställa dig den som en enkel dator som kan interagera med externa enheter. Till exempel öppna och stänga transistorer, ta emot data från temperatursensorer, visa data på LCD-skärmar, etc. Dessutom kan mikrokontrollern utföra olika behandlingar av indata, precis som din persondator.

Det vill säga, mikrokontroller erbjuder oss nästan obegränsade möjligheter att styra alla enheter, tack vare närvaron av I/0-portar (ingångs-/utgångsportar), samt möjligheten att programmera dem.

Var används mikrokontroller?

  1. Hushållsapparater (tvättmaskiner, mikrovågsugnar etc.).
  2. Mobil teknik (Robotar, robotsystem, kommunikationsutrustning etc.).
  3. Industriell utrustning (maskinstyrsystem).
  4. Datorteknik (moderkort, styrsystem för kringutrustning).
  5. Underhållningsutrustning (barnleksaker, dekorationer).
  6. Transport (kontrollsystem för bilmotorer, säkerhetssystem)

Detta är inte en komplett lista över applikationer för mikrokontroller. Ofta är det mycket lönsamt att ersätta en uppsättning kontrollchips med en mikrokontroller, på grund av förenklad produktion och minskad strömförbrukning.

Komma igång med AVR

AVR- en familj av mikrokontroller från Atmel.De har tillräcklig prestanda för de flesta amatörenheter. De används också i stor utsträckning inom industrin.

Det finns olika programmeringsspråk för AVR-mikrokontroller, men de kanske mest lämpliga är assembler och C, eftersom dessa språk bäst implementerar alla nödvändiga funktioner för att hantera mikrokontrollerhårdvara.

Assembly language är ett programmeringsspråk på låg nivå som använder den direkta instruktionsuppsättningen från mikrokontrollern. Att skapa ett program på detta språk kräver goda kunskaper om det programmerbara chipets kommandosystem och tillräckligt med tid för att utveckla programmet. Assembly-språket är sämre än C i hastighet och enkel programutveckling, men har märkbara fördelar i storleken på den slutliga körbara koden och följaktligen hastigheten på dess exekvering.

C låter dig skapa program med mycket större komfort, vilket ger utvecklaren alla fördelar med ett språk på hög nivå.
Det bör återigen noteras att arkitekturen och kommandosystemet för AVR skapades med direkt deltagande av utvecklarna av C-språkkompilatorn och det tar hänsyn till funktionerna i detta språk. Att kompilera C-källkod går snabbt och ger kompakt, effektiv kod.

De viktigaste fördelarna med C framför assembler: hög hastighet på programutveckling; universalitet som inte kräver en grundlig studie av mikrokontrollerns arkitektur; bättre dokumenterbarhet och läsbarhet för algoritmen; tillgänglighet av funktionsbibliotek; stöd för flyttalsberäkningar.

C-språket kombinerar harmoniskt lågnivåprogrammeringsmöjligheter med egenskaperna hos ett högnivåspråk. Möjligheten till lågnivåprogrammering gör att du enkelt kan arbeta direkt på hårdvara, och egenskaperna hos högnivåspråket gör att du kan skapa lättläsbar och modifierbar programkod. Dessutom har nästan alla C-kompilatorer möjlighet att använda assembler-inlägg för att skriva programavsnitt som är kritiska när det gäller exekveringstid och resursförbrukning.

Med ett ord, C är det mest bekväma språket för både nybörjare som bekantar sig med AVR-mikrokontroller och seriösa utvecklare.

Kompilatorer används för att konvertera källkoden för ett program till en firmwarefil för mikrokontroller.

Atmel tillhandahåller en kraftfull sammanställningskompilator som ingår i Atmel Studios utvecklingsmiljö som körs på Windows. Tillsammans med kompilatorn innehåller utvecklingsmiljön en debugger och en emulator.
Atmel Studio är helt gratis och tillgänglig på Atmels webbplats.

För närvarande finns det ganska många C-kompilatorer för AVR. Den kraftfullaste av dem anses vara kompilatorn från IAR Systems från Stockholm. Det var dess anställda som deltog i utvecklingen av AVR-ledningssystemet i mitten av 90-talet. IAR C Compiler har omfattande kodoptimeringsmöjligheter och kommer som en del av den integrerade utvecklingsmiljön IAR Embedded Workbench (EWB), som även inkluderar en assembler-kompilator, länkare, projekt- och bibliotekshanterare och debugger. Priset för den fullständiga versionen av paketet är 2820 EUR. På företagets hemsida kan du ladda ner en gratis utvärderingsversion i 30 dagar eller en obegränsad version med en kodstorleksgräns på 4 KB.

Det amerikanska företaget Image Craft från Palo Alto, Kalifornien producerar en C-språkkompilator som har fått ganska stor popularitet. JumpStart C för AVR har acceptabel kodoptimering och ett inte för högt pris (från $50 till $499 beroende på version). Demoversionen av JumpStart C för AVR är fullt fungerande i 45 dagar.

Den rumänska Code Vision AVR C-kompilatorn har vunnit inte mindre popularitet; priset för den fullständiga versionen av denna kompilator är relativt lågt och uppgår till 150 EUR. Kompilatorn kommer med en integrerad utvecklingsmiljö, som, förutom standardfunktioner, innehåller en ganska intressant funktion - CodeWizardAVR Automatic Program Generator. Närvaron av en seriell terminal i utvecklingsmiljön gör att du kan felsöka program med hjälp av den seriella porten på mikrokontrollern. Du kan ladda ner en gratis utvärderingsversion från utvecklarna med en kodstorleksgräns på 4 KB och inaktiverad lagring av den genererade källkoden i C.

Företaget MikroElektronika, beläget i den serbiska staden Belgrad, producerar en hel familj av kompilatorer för AVR-mikrokontroller. En kompilator för C-språket som heter mikroC PRO för AVR kostar $249. Det finns även mikroBasic och mikroPascal för samma pris. Det finns demoversioner på utvecklarens webbplats med en kodstorleksgräns på 4096 byte. Fördelen med denna familj av kompilatorer är en enda plattform och en enda ideologi, som kan ge en enkel övergång inte bara mellan språk, utan även mellan mikrokontroller (det finns kompilatorversioner för PIC, STM32, 8051...).

Den integrerade utvecklingsmiljön har blivit verkligt ikonisk. Den innehåller kraftfulla C- och assembler-kompilatorer, AVRDUDE-programmeraren, en debugger, en simulator och många andra stödjande program och verktyg. WinAVR integreras sömlöst med Atmels AVR Studio-utvecklingsmiljö. Assembleren är identisk i ingångskod med AVR Studio assembler. C- och assembler-kompilatorer har förmågan att skapa felsökningsfiler i COFF-format, vilket gör att du inte bara kan använda inbyggda verktyg utan också använda den kraftfulla AVR Studio-simulatorn. En annan viktig fördel är att WinAVR distribueras gratis utan begränsningar (tillverkare stödjer GNU General Public License).

Som en sammanfattning är det värt att säga att WinAVR är ett idealiskt val för dem som börjar behärska AVR-mikrokontroller. Det är denna utvecklingsmiljö som anses vara den huvudsakliga i denna kurs.

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 behö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


Topp