Software og Udviklingsmiljø

Fra HTX-Arduino
Skift til: navigering, søgning
Video med forklaring til kapitlet

For at skrive software skal man have et sted at skrive programkoden, man skal kunne oversætte programkoden til noget som mikroprocessoren på Arduinoboardet forstår, og så skal man kunne afvikle det oversatte program. Til Arduino ligger alle disse funktioner i ét samlet program; Arduino IDE (Integrated Development Environment). Dette program skal downloades herfra: arduino.cc/en/Main/Software, og installeres på computeren.

Der downloades og installeres den version der passer til ens styresystem.

Når man starter programmet kommer man ind i et skærmbillede som vist i figur 1.

Starten på programmet til Arduino’en - et tomt program
Figur 1. Starten på programmet til Arduino’en - et tomt program.

Arbejder man på en maskine hvor man ikke ønsker at installere softwaren, så kan man hente en version der kan fungere uden at man installerer noget[1].

Kommunikation med Arduinoen

Arduinoboardet forbindes til computeren med et USB-kabel. På computeren fremkommer der en COM-port, som kommunikationen mellem IDE’et og Arduino’en foregår igennem. En del styresystemer finder ud af det automatisk, men som også kan drille lidt, alt efter styresystem og hvilken type Arduino det er. Det kan man søge hjælp til her: Arduino Driver.

Det er værd at bemærke, at originale Arduino UNO R3 altid har lettere ved at koble op mod IDE’et.

Programmet Arduino IDE startes på computeren, med et Arduinoboard koblet på en USB-port. Først tjekker man om IDE’et kan finde den COM-port som Arduino’en har fået på computeren. Det gøres ved at vælge: Værktøjer – Port og se, om COM-porten som Arduinoboardet har fået, er med på listen over COM-porte. Hvis den er, vælge den som man kan se det på figur 2. I dette eksempel er det COM5 som Arduinoboardet har fået tildelt af computeren.

Indstilling af den rigtige port på computeren
Figur 2. Indstilling af den rigtige port på computeren.

Der kan være én eller flere COM-porte på computeren i forvejen, som ikke har noget med Arduino at gøre. På figur 2 ses det, at der ud for COM5 står “Arduino/Genuino Uno”. Benytter man et originalt Arduinoboard, vil der ud for COM-porten stå hvilket board det er, og dermed kan man hurtigt vælge det rigtige.

Hvis der ikke kommer en port frem, når man forbinder sit Arduinoboard til computeren, kan man bl.a. søge hjælp her: Arduino Driver.

Som man også kan se på figur 2, så kan man også indstille hvilken type Board man anvender. Pt. (2018) hedder et Arduino UNO board “Arduino/Genuino Uno”. Man kan også indstille hvilken type programmer man anvender, hvor den i dag hedder “AVRISP mkII”.

Start for eksempel med at lægge Blink-eksemplet på, for at teste om kommunikationen og det grundlæggende i board og udviklingsmiljøet virker. De fleste Arduinoer har en indbygget LED der vil blinke, når programkoden er korrekt oversat og overført til Arduinoen.

I dokumentet Blink Eksempel beskrives hvordan man finder koden og får den lagt over på Arduinoboardet. Man kan godt springe til dette dokument og afprøve Blink-eksemplet med det samme, for derefter at vende tilbage til dette dokument; resten af dette dokument beskriver selve programoversættelsesprocessen der foregår, når man ønsker at uploade programkode til Arduinoboardet, samt håndtering af eventuelle fejl i programkoden.

Basal kode Den helt basale programkode for Blink-eksemplet ses herunder:

void setup() {
  pinMode(13, OUTPUT);
}

void loop() {
  digitalWrite(13, LOW);
  delay(300);
  digitalWrite(13, HIGH);
  delay(300);
}

Programmet består af to dele; void setup() og void loop(). Setup-delen køres kun én gang, mens loop-delen køres igen og igen.

Funktionen pinMode() sætter portben 13 til at være et output, mens funktionen digitalWrite() bruges til at sætte portben 13 henholdsvis LOW (0V) og HIGH (+5V). delay() får programafviklingen til at stå stille i det antal millisekunder man specificerer.

Alle Arduinoprogrammer består af en setup-del og en loop-del, og hvor setup-delen kun køres én gang - når der lige er sat strøm til Arduinoboardet, afvikles loop-delen indtil strømmen tages fra Arduinoboardet igen. Programkoden afvikles linje for linje.

En nærmere gennemgang af Blink-eksemplet findes i dokumentet Blink Eksempel, mens en beskrivelse af et Arduinoboards opbygning findes i dokumentet Programafvikling i Arduino.

Kodeeksempler

Til dette kapitel er der nogle kodeeksempler man kan anvende. De er samlet i en ZIP-fil.

Oversættelse

Når man har skrevet sin programkode i editoren, eller har hentet et eksempel, som beskrevet i Anvendelse af Eksempler, så skal programkoden oversættes fra programmeringssproget C, til den maskinkode som Arduinoen kan forstå. Denne process kaldes også for “compilering”.

Når man har hentet koden ind i udviklingsmiljøet, så skal det oversættes og uploades til Arduinoen som vist i figur 3.

Oversættelse og Upload af koden til Arduinoen. Dette gøres ved at trykke på ➔ knappen
Figur 3 Oversættelse og Upload af koden til Arduinoen. Dette gøres ved at trykke på ➔ knappen.

Når man har trykket på Upload-ikonet ➔, så starter udviklingsmiljøet med at oversætte programkoden, som det ses i figur 4, hvor den skriver “Compiling sketch” i status baren (det blå-grønne felt).

Besked i statusbaren “Compiling sketch” under oversættelse. Bemærk progress baren i højre side, der viser hvor langt processen er kommet
Figur 4 Besked i statusbaren “Compiling sketch” under oversættelse. Bemærk progress baren i højre side, der viser hvor langt processen er kommet.

Hvis oversættelsen går godt, så der kommer en maskinkode ud af det, skifter status baren til “Uploading”. Hvis dette også går godt, så skriver den “Done uploading” i statusbaren, som det kan ses i figur 5.

Oversættelse og Upload af koden til Arduinoen gik godt, og programmet er nu uploadet til Arduinoboardet
Figur 5 Oversættelse og Upload af koden til Arduinoen gik godt, og programmet er nu uploadet til Arduinoboardet.

Når man uploader koden til Arduinoen som vist i figur 3, så sker der først en oversættelse af programkoden til maskinkode, som Arduinoen kan forstå.

Denne oversættelse kan selvfølgelig fejle, hvis man ikke har skrevet programkoden korrekt - her er C-sproget meget kontant; fejlene skal rettes, ellers kommer man ikke videre.

Hvis man arbejder med oversættelsesfejl, så kan man nøjes med kun at oversætte programkoden (dvs. at man ikke også skal uploade koden). Det er ved at bruge knappen til venstre for Upload-knappen. På figur 3 ses dette ikon ✓. Dette er specielt anvendeligt, hvis man ikke har tilsluttet en Arduino.

Fejl i programkoden

Hvis der er fejl i programkoden, så vil der komme en fejlmelding, der forsøger at angive hvad det er compileren (oversætteren) ikke kan forstå, som for eksempel fejlen vist på figur 6.

Eksempel på oversættelsesfejl
Figur 6 Eksempel på oversættelsesfejl.

Får man en fejlmelding ved compileringen, så er det en god ide at tolke hvad det er den skriver i fejlmeldingen - den fejl der vises i figur 6 er ret ligetil: der mangler et ; i koden, og den mangler før }. Men det kan godt forvirre lidt, at der oppe i koden er markeret med pink på den linje hvor } står - især nu hvor ; mangles som afslutning i linjen ovenfor det der er markeret med pink.

Der er selvfølgelig mange fejlmuligheder når man skriver programkode, hvor typiske fejl kan være: variabel og funktionsnavne er erklæret forskelligt (forskel på store og små bogstaver), forkert anvendelse af biblioteker, rod i indramninger med {, ( og [.

Upload af maskinkoden

Når man klikker Upload som vist i figur 3, så vil udviklingsmiljøet altid starte med at compilere programkoden, så man er sikker på at det er det rigtige der ligger i Arduinoen.

For at kunne uploade den maskinkode der laves ud fra programkoden, så skal der selvfølgelig være tilsluttet en Arduino, og den skal komme op som en COM-port. Den letteste måde at kontrollere hvilken port det er den optræder som, er ved at kigge under port, som vist i figur 2 inden man slutter Arduinoen til, og så gøre det igen efter man har sluttet den til, så man kan se hvilken port der så dukker op.

Fejl i kommunikationsporten

Hvis der ikke kommer en ny port, så er der sandsynligvis problemer med driveren eller en hardwarefejl på Arduinoen - se beskrivelse i afsnittet #Kommunikation med Arduinoen.

Der kan også opstå problemer i udviklingsmiljøet, hvor der er kommet en port op, men at den alligevel ikke vil uploade. Nogle gange kan det løses ved at lukke udviklingsmiljøet, og starte det igen. Andre gange kan det hjælpe at genstarte maskine, specielt hvis det er Windows styresystemet. Under alle omstændigheder skal man være sikker på at porten står indstillet til den rigtige COM-port, og at man har indstillet til den rigtige Arduino-type og programmer, som det vises på figur 2.

Test af softwaren

Det at teste software kan være meget komplekst. Selvfølgelig er det ikke så svært at teste om et program som Blink fungerer, da funktionen af programmet er ret simpel, men hvis man fx har et program med 3 funktioner der skal spille sammen, og hver funktion har bare 10 forskellige tilstande/indstillinger, så bliver det til 1000 forskellige situationer der skal testes igennem, hvis man skal være helt sikker.

Det er måske ikke nødvendig at teste for alle kombinationer, hvis man er sikker på at tingene ikke påvirker hinanden, men i software kan det være svært at være helt sikker på at at forskellige dele af softwaren ikke har en eller anden form for indvirkning, om ikke andet så med tidsmæssige påvirkninger.


C-kode

Et Arduinoprogram skrives i programmeringssproget C/C++. Det betyder, at hvis man i forvejen har skrevet software i ét eller begge af disse programmeringssprog, kan man gøre brug af sine erfaringer til Arduinoprogrammeringen. En del andre sprog som java, javaScript og PHP har den samme grundlæggende syntaks, så her kan man også trække erfaringer ind.

Variabel typer

Man har en række variabeltyper man kan vælge imellem:

bool Boolean værdi; enten HIGH eller LOW.
byte Heltal, 8-bit, værdi mellem 0 og 255.
char Heltal, 8-bit, værdi mellem -127 og 128. Bruges til at gemme ét enkelt tegn (bogstaver eller tal) i.
unsigned char Heltal, 8-bit, værdi mellem 0 og 255.
int Heltal, 16-bit, værdi mellem -32.768 og 32.767.
unsigned int Heltal, 16-bit, værdi mellem 0 og 65.535.
long Heltal, 32-bit, værdi mellem -2.147.483.648 og 2.147.483.647.
unsigned long Heltal, 32-bit, værdi mellem 0 og 4.294.967.295.
float Decimaltal, 32-bit.

Løkker

Man har følgende løkke-typer at arbejde med:

for En for-løkke er beregnet til brug ved en række gentagne operationer. Man definerer en tælle-variabel i for-løkken, og løkken kører indtil tælle-variablen har nået den værdi man ønsker. Man kan både tælle op eller ned med tællevariablen, og man bestemmer også selv hvor meget man ønsker at tælle op eller ned for hver tur i løkken.
Eksempel:
for (int i=0; i<10; i=i+1)
   {
      // Kode der skal køres i løkken
   }
while En while-løkke kører så længe den angivne betingelse er opfyldt. Man skal med while-løkker sikre sig, at man ikke hænger fast inde i løkken (uendeligt loop), ved at sørge for, at ens betingelse rent faktisk kan ændres når loopet køres. I eksemplet nedenfor er der i betingelsen en læsning på portben 10; dermed vil man fange hvis der læses LOW, og while-løkken afsluttes. Havde man derimod sat læsningen fra portben 10 før while-løkken, og i betingelsen kun kigget på den værdi der blev læst før whilen-løkken startede, får man aldrig opfanget hvis portben 10 ændrer sig.
Eksempel:
while (digitalRead(10) == HIGH)
    {
      // Kode der skal køres i løkken
    }
do..while Næsten som while-løkken, bortset fra, at løkken altid kører mindst én gang, da betingelsen først testes i bunden af løkken.
Eksempel:
do
{
   // Kode der skal køres i løkken
} while (analogRead(A0) < 100);

Betingelser

Man har følgende betingelser:

if..else Simpel betingelse, hvor kode afvikles hvis betingelsen er opfyldt. Kan bruges i kombination med else if (), hvorved flere forskellige betingelser kan medføre forskellig kodeafvikling. Man kan kombinere betingelser, således man ved at bruge && kan sige BÅDE den ene OG den anden betingelse skal være opfyldt. Bruges || er det ENTEN den ene ELLER den anden betingelse der skal være opfyldt.
Eksempel:
if (digitalRead(2) == HIGH)
    {
      // Kode hvis betingelse opfyldt
    }
    else
    {
      // Kode hvis betingelse ikke er opfyldt    
    }
switch..case Bruges ofte hvis man har opbygget sin kode med tilstande (se dokumentet Dokumentation med State-machines)
Eksempel:
//   der testes på variablen state
   switch (state)
   {
      case 1:
         // Kode hvis state er 1
         break;
      case 2:
         // Kode hvis state er 2
         break;
      default:
         // Kode hvis state hverken er 1 eller 2
   }

Sammenligninger

Man har følgende muligheder for at sammenligne værdier. Dette anvendes sammen med betingelserne.

== Lig med. Bemærk, at der anvendes 2 lighedstegn når man ønsker at sammenligne to værdier. Anvendes kun ét lighedstegn sætter man noget lig med (altså tildeler en værdi).
Eksempel:
if (state == 1)
!= Ikke lig med. Betingelsen er opfyldt når en værdi ikke er lig med en anden.
Eksempel:
if (state != 1)
> Større end
< Mindre end
>= Større end eller lig med
<= Mindre end eller lig med

Arduino-kode

Sammen med Arduino IDE får man en række funktioner man kan anvende i sin programkode. En komplet liste over funktionerne findes på Arduinos hjemmeside [2] beskrives nogle af de mest gængse funktioner.

Digital I/O

pinMode() Sætter en port op til enten at være INPUT eller OUTPUT.
Eksempel:
pinMode(13, OUTPUT);
digitalWrite() Sætter et portben HIGH eller LOW - dvs. sætter +5V eller 0V på portbenet. Kræver, at portbenet er sat til OUTPUT med pinMode(). Kan anvendes på portbenene 0 til 13, samt A0 til A5
Eksempel:
digitalWrite(13, HIGH);
digitalRead() Læser et portben, og returnerer 1 for HIGH eller 0 for LOW. Man kan vælge at gemme resultatet af et digitalRead() i en variabel, der enten er oprettet som en bool (boolean) eller en int (integer). Bemærk, at man læser portbenet som HIGH ved +5V og LOW ved 0V. Kan anvendes på portbenene 0 til 13.
Eksempel:
int knapTryk;
knapTryk = digitalRead(11);

Analog I/O

analogRead() Læser en analog spænding og konverterer denne til en talværdi mellem 0 og 1023 (10-bit A/D converter). Kan anvendes på portbenene A0 til A5.
Eksempel:
int analogValue;
analogValue = analogRead(A0);

Tid

delay() Holder en pause i afviklingen af programkoden. Pausens længde specificeres i millisekunder. Er en let måde at få pauser ind i koden, men man skal være opmærksom på, at man ikke kan læse eventuelle knaptryk så længe der er et delay (se mere i dokumentet 13 - Tid og Samtidighed i software).
Eksempel:
delay(500);
millis() Funktionen returnerer antallet af millisekunder der er gået siden programkodeafviklingen startede (der blev sat strøm til Arduinoboardet). Bruges ofte i forbindelse med tidsstyring ved for eksempel state maskiner (se dokumentet 13 - Tid og samtidighed i software).
Eksempel:
long currentTime;
currentTime = millis();
pulseIn() Bruges til at registrere tiden mellem to pulser detekteres på et portben. Returnerer antal mikrosekunder der går mellem et portben sættes HIGH efter hinanden eller LOW efter hinanden. Kræver, at portbenet er sat som INPUT med pinMode().
Eksempel:
long duration;
duration = pulseIn(5, HIGH);

Referencer