Arduino UNO3 är en open-source elektronikplattform baserad på lättanvänd hårdvara och mjukvara. Man "berättar" för Arduinon vad den ska göra genom att skicka en uppsättning instruktioner till processorn på kretskortet.
Programmeringen av Arduino sker med en flexibel mjukvara, och ett enkelt språk, "Processing", som från början togs fram för att lära ut programmering inom ramen för olika konstproject ("visual arts").
Till Arduinokortet finns en gratis IDE (Integrated Development Environment), för operativsystemen Windows MAC och Linux.
Så här enkelt gör man ett Arduino-program som blinkar med den lysdiod som finns inbyggd på kretskortet. (Bara 5 enkla kodrader!)
void setup() { pinMode(LED_BUILTIN, OUTPUT); } void loop() { digitalWrite(LED_BUILTIN, HIGH); // turn the LED on (HIGH is the voltage level) delay(1000); // wait for a second digitalWrite(LED_BUILTIN, LOW); // turn the LED off by making the voltage LOW delay(1000); // wait for a second }
Arduinomiljön är mycket användbar när man snabbt vill prova olika ideér för att visa andra hur man tänkt, och när kraven på en ekonomisk lösning inte är så höga.
Arduinos enkelhet kommer emellertid med en kostnad.
Den genererade koden kan bli onödigt stor och ineffektiv.
Den enkla Arduino koden döljer vad som egentligen utförs och detta gör det svårt att hitta fel i programmen.
När det hela inte fungerar som tänkt är det detaljkunskaper om processorn och dess programmering som behövs.
Den som går på en programmeringsutbildning behöver därför lära sig att programmera processorn direkt -
exempelvis med programspråket C.
Detta krävs för att man ska kunna hitta svårfunna programmeringsfel,
och för att kunna skapa en effektiv programkod.
Arduino UNO 3 är byggd kring microcontrollern ATmega328/P från Atmel. Den beskrivs detaljerat i kretsens datablad ATmega328P.zip.
De flesta av ATmega chippets pinnar är direkt anslutna till Arduinokortets kontakter. Det går därför enkelt att koppla in yttre komponenter till uno3-kortet. Det finns också mängder av färdiga kretskort med extra utrustning att ansluta direkt till uno3-kortets kontakter (så kallade Shields).
Den som vill kan i stället för ett färdigt Arduinokort placera processorn ATmega328P direkt på ett kopplingsdäck. Det finns i många beskrivningar på webben om hur man gör detta och vilka övriga komponenter som då behövs.
En Arduinokopia på kopplingsdäck, dokumenterat med Fritzing: Arduino UNO 3.
![]() |
![]() |
För att programmera AVR processorer effektivt med programspråket C kan man använda en komplett miljö med en GCC kompilator
Arduino IDE är i själva verket byggd kring exakt samma C-miljö som den man laddar ned som "Atmel AVR Toolchain". Har man en Arduino kan man helt enkelt skriva ren C-kod direkt i Arduino texteditorn, genom att undvika alla Arduino specifika kommandon ( använd inga "Processing-funktioner" ).
(En skillnad mot en ren C miljö är att källkodsfilerna i en Arduino miljö får filnamnstillägget *.ino och att dom hamnar inuti mappar med samma namn som filnamnet.)
TIPS! Arduino texteditor visar radnumret i nedre vänstra hörnet för den rad markören råkar stå på. Detta behöver man känna till när kompilatorn rapporterar fel på någon specifik rad!
Man börjar med att placera kretsdokumentationen direkt i källkodsfilen!
Då blir det lätt att hitta rätt bland pinnarna.
Kopiera ASCII-grafiken som visar ATmega processorns pinnplacering och
anslutningarna till Arduino kontakterna (stackable header).
Uppdatera sedan grafiken varje gång Du ändrar - kopplar in något!
/* *********************************** */ /* HARDWARE */ /* *********************************** */ /* Chip ATMega328 Arduino Uno R3 stackable header _______ Digital: _____/ \__ Analog: ______________ ______________ -|D00 >RXD A5|- | \/ | -|D01 <TXD A4|- Res---|01 PC6/RES' ATM328 SCL/PC5 28|-(A5)- -|D02 A3|- -(D00)-|02 PD0/RXD SDA/PC4 27|-(A4)- -|D03~ A2|- -(D01)-|03 PD1/TXD PC3 26|-(A3)- -|D04 A1|- -(D02)-|04 PD2/INT0 PC2 25|-(A2)- -|D05~ A0|- -(D03)-|05 PD3/INT1/PWM PC1 24|-(A1)- -|D06~ | Power: -(D04)-|06 PD4 PC0 23|-(A0)- -|D07 Vin|- +5V ---|07 VCC GND 22|--- Gnd | GND|- Gnd ---|08 GND AREF 21|--- Vin -|D08 GND|- Xtal |X|--|09 PB6/OSC1 AVCC 20|--- +5V -|D09~ +5V|- 16MHz |X|--|10 PB7/OSC2 SCK/PB5 19|-(D13)- -|D10~ +3.3V|- -(D05)-|11 PD5/PWM MISO/PB4 18|-(D12)- -|D11~ Res|- -(D06)-|12 PD6/PWM PWM/MOSI/PB3 17|-(D11)- -|D12 IOREF|- -(D07)-|13 PD7 PWM/SS'/PB2 16|-(D10)- -|D13 LED --- | -(D08)-|14 PB0 PWM/PB1 15|-(D09)- -|GND | |______________________________| -|AREF | -|SCL | -|SDA | |________________| */
ATmega328 har 28 pinnar. De är fördelade på tre portar med register PORTB och PORTC och PORTD. Till varje register finns också ett riktningsregister, Data Direction Register DDRB DDRC DDRD. De bitpositioner i riktningsregistren som är 1 gör motsvarande pinne till en utgång, annars förblir den en ingång.
För att kunna använda de namn på bitar och register som förekommer i databladet behöver man ta med includefilen:
#include <avr/io.h>
ATmega328 processorns portar B C D.
För att blinka med Arduino kortets inbyggda lysdiod, som är kopplad till pinne 19 (PB5, PORTB bit 5),
måste den pinnen ställas in som utgång.
DDRB bit 5 ska vara 1.
Man kan skriva DDRB = 0b01000000; men då påverkar man samtidigt riktningen för alla andra pinnar på porten.
Bättre är att skriva DDRB |= ( 1 << 5 ); som innebär att man maskar (or) med en bitmask
med bit 5 ettställd. Övriga bitar påverkas inte av detta.
Ändå bättre är att skriva DDRB |= ( 1 << PB5 );
här utnyttjar vi att includefilen innehåller information om vilka nummer bitarnas namn motsvarar!
För att "tända" lysdioden måste portpinnen PORTB bit 5 bli 1. PORTB |= ( 1 << PB5 );.
För att sedan "släcka" lysdioden maskar (and) man med en bitmask med alla bitar ettställda utom bit 5 som är nollställd. PORTB &= ~( 1 << PB5 );.
Man kan också "toggla" (varannan gång 1 och varannan gång 0) en portpinne genom att maska (xor). PORTB ^= ( 1 << PB5 );.
För att vänta kan man låta processorn utföra en lång meningslös beräkning.
void wait(void) { long unsigned int local_delay; for (local_delay = 0; local_delay < 400000; local_delay++ ) /* empty loop */ ; }
ATmega är en 8-bitars processor.
En for-loop med en long som räknevariabel räcker till ett mycket stort tidsintervall. Med ett startvärde 40000 blir tiden av storleksordningen sekund ( vid vår klockfrekvens 16 MHz ).
MEN TYVÄRR! det visar sig att denna räkne-loop inte fungerar!?
Problemet är att kompilatorn upptäcker att loopen inte gör något, att den är meningslös, så den optimerar helt enkelt bort koden! Så hur gör man för att tala om för kompilatorn att man menar allvar och vill ha kvar koden?
volatile long unsigned int local_delay;
Nyckelordet volatile innebär att variabeln kan komma att ändras utanför kompilatorns kontroll och att den därför inte får optimeras bort. Nu fungerar koden!
Bekväma fördröjningsloopar. Parametern är antalet ms eller us angivet som en flyttalskonstant.
Antalet varv som behövs i loopen räknar kompilatorn ut med ett makro,
och använder sedan den grundläggande delay loopen till fördröjningen.
(Viktigt att parametern är en konstant och inte en variabel.
Är parametern en variabel kan antalet varv i fördröjningsloopen inte räknas ut i förväg under kompileringen,
utan måste beräknas av processorn - som då måste inkludera alla flyttals bibliotek bara för detta!)
För att kunna beräkna korrekta tider måste kompilatorn veta vilken klockfrekvens processorn arbetar med. I Arduinomiljön avgörs det av vilken typ av Arduino man valt, men informationen kan också skrivas i koden med #define F_CPU 16000000UL.
#define F_CPU 16000000UL #include <util/delay.h> void _delay_ms (double); void _delay_us (double);
William Sandqvist willsandqvist@gmail.com