Hopp til innhold

Fagstoff

Analyse av programkode for ultralydsensor

En kode for Arduino kan se uoversiktlig ut. Her skal vi analysere en kode som er generert gjennom blokkodeprogrammering, og som styrer en avstandsmåler med ultralydsensor.

Programkode C++

Vi bruker programmeringsverktøyet når vi skal programmere Arduino-mikrokontrollere. Dette verktøyet har programmeringsspråket C++ som grunnkode, men i en variant som er spesialtilpassa Arduinoene. I tillegg er det utvikla ulike grafiske programmeringsverktøy for Arduino, såkalte blokkprogrammeringsverktøy.

Eksempelet vi skal gå gjennom, er programmert i Tinkercad Circuits. I dette verktøyet kan vi få henta ut Arduino-koden automatisk. (Når du står inne i Tinkercad, kan du klikke på rullegardinmenyen til venstre og velge menypunktet "Blocks + Text", så får du Arduino-koden generert av kodeblokkene.)

Eksempel

Eksempelet vårt er en programkode for en ultraydsensor. Programmet er koda med blokkprogrammering i TinkerCad Circuits og deretter konvertert til Arduino IDE kodespråk.

Eksempelkode

// C++ code

// Sett startverdi på variabel

int cm = 0;

long readUltrasonicDistance(int triggerPin, int echoPin)

{

pinMode(triggerPin, OUTPUT);

digitalWrite(triggerPin, LOW);

delayMicroseconds(2);

// Aktiver triggerPin i 10 mikrosekunder

digitalWrite(triggerPin, HIGH);

delayMicroseconds(10); // Vent 10 mikrosekunder

digitalWrite(triggerPin, LOW);

pinMode(echoPin, INPUT);

// Send og motta ultralydsignal på echoPin og lagre verdien i millisekunder i variabelen pulseIn

return pulseIn(echoPin, HIGH);

}

void setup()

{

Serial.begin(9600);

pinMode(2, OUTPUT);

pinMode(3, OUTPUT);

pinMode(4, OUTPUT);

}

void loop()

{

// Les verdi fra sensor og skriv verdien på

// skjermen

cm = 0.01723 * readUltrasonicDistance(7, 7);

// Skriv verdi på skjerm (Serial monitor)

Serial.print("Avstanden er: ");

Serial.print(cm);

Serial.println(" cm");

// Beskriv hva som skal skje hvis avstanden er

// over 300 cm

if (cm > 300) {

digitalWrite(2, LOW);

digitalWrite(3, LOW);

digitalWrite(4, LOW);

}

// Hva skal skje hvis avstanden er mellom 200 og

// 300 cm?

if (cm <= 300 && cm > 200) {

digitalWrite(2, HIGH);

digitalWrite(3, LOW);

digitalWrite(4, LOW);

}

// Hva skal skje hvis avstanden er mellom 100 og

// 200 cm?

if (cm <= 200 && cm > 100) {

digitalWrite(2, LOW);

digitalWrite(3, HIGH);

digitalWrite(4, LOW);

}

// Hva skal skje hvis avstanden er 100 cm eller mindre?

if (cm <= 100) {

digitalWrite(2, LOW);

digitalWrite(3, LOW);

digitalWrite(4, HIGH);

}

// Hvor ofte skal avstanden sjekkes?

delay(100); // Vent i 100 microsekund

}

Analyse av koden

Nå skal vi se nærmere på hvordan de enkelte delene av programmet er bygd opp.

Variabler

I starten av programmet lager vi en variabel for å lagre verdien som ultralydsensoren leser av.

Mikrokontrolleren kan programmeres til å lagre ulike typer verdier i variablene. I eksempelet vårt er koden benytta fordi vi vil at verdiene skal være heltall, altså tall uten desimaler. Med int kan vi handtere heltall fra –32 768 til +32 767.

// Sett startverdi på variabel

int cm = 0;

Lese verdier

Den neste delen er en spesiell kodebit for lesing av ultralydavstandssensoren. Denne kodebiten er et lite program inni programmet, og den kan seinere ved å skrive ei enkel kodelinje.

Enkelte sensorer kan for øvrig også ha egne programkoder som kan hentes inn fra et bibliotek.

long readUltrasonicDistance(int triggerPin, int echoPin)

{

pinMode(triggerPin, OUTPUT); // Definer pinne for trigger, og sett den til utgang

digitalWrite(triggerPin, LOW); // Slå av trigger ved å sette den til LOW

delayMicroseconds(2); // Vent i 2 mikrosekunder

// Skru på trigger i 10 mikrosekunder

digitalWrite(triggerPin, HIGH);

delayMicroseconds(10);

digitalWrite(triggerPin, LOW); // Skru av trigger

pinMode(echoPin, INPUT); // Definer pinne for ekko, og sett den til INPUT

// Les verdi på ekkopinne, og lagre hvor lang tid i mikrosekunder signalet tok, i variabelen pulseIn

return pulseIn(echoPin, HIGH);

}

readUltrasonicDistance()

I eksempelet over har vi brukt funksjonen readUltrasonicDistance() for å beskrive sensorkoden og holde den atskilt fra hoveddelen av programmet.

long

Funksjonen starter med at vi oppgir hvilken type data den skal sende tilbake til hovedprogrammet. I dette tilfellet returnerer funksjonen en verdi av typen long, som er et heltall med mange sifre.

En long-variabel bruker 4 byte i minnet, og den kan representere heltall fra
–2 147 483 648 til +2 147 483 647 (inkludert null). Variabeltypen er særlig nyttig når vi for eksempel arbeider med tid og tellere, der store verdier må lagres eller beregnes nøyaktig.

Navn på funksjonen

Valg av navn på funksjonen er i grunnen opp til programmereren. Det er vanlig med engelske navn fordi engelsk brukes i kodinga, men det går fint an å lage norske navn.

pin

I parentesen etter navnet står argumentene funksjonen tar. Her er det int triggerPin og int echoPin som er de variable for tilkoplingsstiftene til sensoren.

Pin-numrene vil bli spesifisert når du kaller opp funksjonen i loop(). Inne i denne funksjonen brukes de lokale variablene triggerPin og echoPin til å referere til informasjonen vi sendte til den fra hoved-loopen (eller fra en annen funksjon).

Selve funksjonen gir ultralydsensoren beskjed om å sende ut et signal gjennom triggerPin og å "lytte etter" signalets ekko gjennom echoPin (som i eksempelet vårt er samme pinne). Programmet starter ei avansert stoppeklokke når signalet sendes ut, og stopper denne når signalet returnerer og kommer tilbake til Arduinoen. Så blir avstanden kalkulert.

Vi kan selv velge hvilke navn vi vil gi de enkelte pinnene.

digitalWrite

digitalWrite beskriver hvilken verdi pinnen skal sende, altså LOW (0, Av) eller High (1, På).

delayMicroseconds

Denne koden forteller mikrokontrolleren at den skal ta en pause på et angitt antall mikrosekunder før den går videre i programmet.

Denne pausen må tilpasses avstanden vi skal måle, for vi må ta hensyn til hvor raskt lyden beveger seg gjennom lufta (ca. 340 m/s). Måler vi lange avstander, kan vi ha lange pauser, måler vi korte avstander, må pausen være kort.

pinMode

Vi bruker kommandoen pinMode for å programmere den aktuelle pinnen til å sende ut eller motta signaler.

I eksempelet vårt har ultralydsensoren kun 3 pinner (triggerPin, echoPin og Spenning), og pinnene kan både sende og motta signaler. Mikrokontrolleren må da få instruks om når pinnen skal motta signal, når den skal sende, og hvor lenge den skal gjøre dette.

return pulseIn

Denne funksjonen får mikrokontrolleren til å lese avstandsverdien fra ultralydsensoren. Ultralydsensoren har da kalkulert avstanden ut fra når signalet blei sendt, og når det blei tatt imot.

Setup

Setup bruker vi for å angi innstillinger mikrokontrolleren skal bruke.

void setup()

{

Serial.begin(9600); // Start kommunikasjon med omverdenen

pinMode(2, OUTPUT); // Sett pinne 2 til utgang

pinMode(3, OUTPUT); // Sett pinne 3 til utgang

pinMode(4, OUTPUT); // Sett pinne 4 til utgang

}

I void setup() gir vi mikrokontrolleren noen faste parametere den skal forholde seg til. I eksempelet vårt får mikrokontrolleren beskjed om at den skal kommunisere med datamaskin og andre komponenter med en hastighet på 9600 .

I tillegg forteller vi mikrokontrolleren at den skal benytte pinnene 2, 3 og 4, og at disse pinnene skal benyttes til å sende signaler ut. Her skal mikrokontrolleren sende signaler fram til diodene slik at disse lyser.

void loop

void loop() er selve hovedprogrammet som gjentas om og om igjen. Det går "i løkke".

void loop()

{

// Les verdi fra sensor og skriv verdien på skjermen

cm = 0.01723 * readUltrasonicDistance(7, 7);

// Skriv verdi på skjerm (Serial monitor)

Serial.print("Avstanden er: ");

Serial.print(cm);

Serial.println(" cm");

Her er det lagt inn en som beregner vår variabel cm ved å benytte verdien fra ultralydsensoren i forhold til lydhastigheten i luft. I tillegg får mikrokontrolleren beskjed om at den skal benytte pinne 7 både til å sende og til å motta signaler.

Mikrokontrolleren får beskjed om å oppdatere variablen cm ved å hente inn delprogrammet readUltrasonicDistance (skriv og les på pinne 7) og kalkulerer denne verdien ved å multiplisere med .

Til slutt følger en instruks om at programmet skal skrive verdien på skjermen sammen med fast tekst.

Om vi hadde en ultralydsensor med separate pinner for sending og mottak, kunne vi for eksmpel brukt pinnene 6 og 7. Da måtte vi ha begge pinnene og satt den ene som utgang og den andre som inngang.

serial.print

Serial.print forteller mikrokontrolleren at den skal skrive tekst og variabler på skjermen. Vanlig tekst settes i hermetegn, mens variabler angis med kun variabelnavnet.

Funksjoner

// Hva skal skje hvis avstanden er mellom 200 og

// 300 cm?

if (cm <= 300 && cm > 200) {

digitalWrite(2, HIGH); // Aktiver pinne 2

digitalWrite(3, LOW); // La pinne 3 være avslått

digitalWrite(4, LOW); // La pinne 4 være avslått

}

Vi vil at verdiene vi avleser, skal sette i gang noe. For å få til dette bruker vi logiske funksjoner du kanskje kjenner igjen fra matematikken.

I koden over gir vi mikrokontrolleren instruks om hva den skal gjøre hvis verdien den lagrer i variabelen cm, er større enn 200 og mindre eller lik 300. I så fall skal den aktivere pinne 2 (HIGH), mens pinne 3 og 4 fortsatt skal være avslått (LOW). Bare dioden som er kopla til pinne 2, skal lyse.

Vi kan selv velge hvilke verdier som skal benyttes som referansetall. I ruta under finner du eksempler for alle diodene, med definerte verdier for når de skal lyse eller være avslått.

Samla kode for alle avstandsnivåer

// Beskriv hva som skal skje hvis avstanden er

// over 300 cm

if (cm > 300) {

digitalWrite(2, LOW); // La pinne 2 være avslått

digitalWrite(3, LOW); // La pinne 3 være avslått

digitalWrite(4, LOW); // La pinne 4 være avslått

}

// Hva skal skje hvis avstanden er mellom 200 og

// 300 cm?

if (cm <= 300 && cm > 200) {

digitalWrite(2, HIGH); // Aktiver pinne 2

digitalWrite(3, LOW); // La pinne 3 være avslått

digitalWrite(4, LOW); // La pinne 4 være avslått

}

// Hva skal skje hvis avstanden er mellom 100 og

// 200 cm?

if (cm <= 200 && cm > 100) {

digitalWrite(2, LOW); // La pinne 2 være avslått

digitalWrite(3, HIGH); // Aktiver pinne 3

digitalWrite(4, LOW); // La pinne 4 være avslått

}

// Hva skal skje hvis avstanden er 100 cm eller mindre?

if (cm <= 100) {

digitalWrite(2, LOW); // La pinne 2 være avslått

digitalWrite(3, LOW); // La pinne 3 være avslått

digitalWrite(4, HIGH); // Aktiver pinne 4

}

Målehyppighet

Hvor ofte vi trenger å få et måleresultat, avhenger av hva vi skal måle. Måler vi noe som beveger seg raskt, bør vi velge en kort pause, skal vi måle noe som beveger seg sakte, kan vi eksempelvis måle hvert femte minutt.

I eksempelet vårt nedenfor måles verdien 10 ganger i sekundet (100 millisekunder = 0,1 sekund).

// Hvor ofte skal avstanden sjekkes?

delay(100); // Vent i 100 millisekunder før programmet kjøres igjen

}

CC BY-SASkrevet av Roger Rosmo.
Sist faglig oppdatert 07.08.2023

Læringsressurser

Programmering