Programmeeromgeving Arduino

Arduino start-up layout:

Een Arduino programma bestaat steeds uit twee hoofddelen, namelijk de Void Setup en de Void Loop. Deze twee elementen zijn de kern van elk programma. Hoewel men altijd meer voids kan creëren, is het onmogelijk om zonder deze twee fundamenten te werken. De eenvoudigste, maar ook de meest gecompliceerde programma’s starten vanuit dit principe. Men kan het begin en einde van deze, en alle andere, voids herkennen aan de gebruikelijke accolades.

Declareren:

Vóór de VoidSetup kan je jouw eigen gekozen woorden gelijkstellen aan waarden die Arduino begrijpt. Dit noemen we declareren. Het is zeer belangrijk dat je dit niet vergeet. Het zorgt ervoor dat je gemakkelijk een poortverandering in je schakeling kan doorschakelen naar een verandering in je programma. Je hoeft dan namelijk maar één getal te veranderen, terwijl je zonder deze tool je volledig programma zou moeten herschrijven.

Bijkomend maak je het voor jezelf veel duidelijker, overzichtelijker. Bij een lange code is het soms gemakkelijk te vergeten wat er geschakeld is aan welke poort. Als je voor jezelf een duidelijke variabele kiest om deze poort aan gelijk te stellen, dan is dit gebruiksvriendelijker. Ook voor andere die jouw code bekijken, en begrijpen, zorgt dit voor veel verheldering.

Programmeeromgeving
De Setup:

De Setup kan men zien als de voorbereidingsfase in onze programmeeromgeving. Hoewel deze slechts eenmaal doorlopen wordt, bij het starten van het programma, speelt de Setup een belangrijke rol in het programma. Hier wordt aan de Arduino duidelijk gemaakt welke pin een INPUT is en welke een OUTPUT. Ze worden dus gedeclareerd, vaak voor een tweede keer. Zo zal bijvoorbeeld poort 12 gedeclareerd worden als ‘ledRood’ voor de void setup en daarna als ‘OUTPUT’ in de void setup. Arduino weet dan dat ‘ledRood’ gelijkstaat aan de uitvoerende poort 12. Tot slot wordt hier ook de Seriële communicatie opgestart. Dit is nodig om te kunnen werken met onze seriële monitor. Meer uitleg vindt je bij het commando Serial.begin();.

De Loop:

Zoals de naam al doet vermoeden is dit deel de oneindige lus van je programma. De code hier zal steeds opnieuw doorlopen worden. Hier komt dus je programma die de werking van je project bepaalt. Alle (commando’s), berekeningen, uitvoeringen … worden hier geschreven.

Voids:

Met voids kan je stukken code opslaan in één woord. Je kan dit woord dan oproepen in de loop. Wanneer het programma dit woord tegenkomt, voert hij de overeenkomstige code uit. Dit komt vooral van pas bij lange programma’s. In deze programma’s is het namelijk vaak zo dat één bepaald stuk code, meerder malen doorlopen moet worden in één cyclus. Je kan natuurlijk ook de code gewoon het gewenst aantal maal achter elkaar schrijven, maar dit onoverzichtelijk, moeilijk aan te passen bij eventuele fouten en ook zeer belastend voor het geheugen van de arduino.

  • Als men vele malen eenzelfde code moet schrijven sluipen de foutjes gemakkelijk naar binnen. Achteraf, wanneer je de foutmelding krijgt, moet men in een ellenlange tekst controleren op een piepklein foutje.
  • Ook moet men elk stukje aanpassen om deze fout te elimineren. Dit vergt tijd en is zeer frustrerend.
  • Arduino bepaald te grote van zijn bestand op het aantal geschreven regels en de commando's geschreven in die regels. Als men het aantal regels tot het minimum kan beperken kan men grotere programma's schrijven. In het begin is dit zeker niet van toepassing, maar het is iets om in het achterhoofd te houden.

Voids helpen deze problemen de wereld uit. Bijkomend heb je grote voordeel dat je zelf eenzelfde stuk code, maar met andere variabelen ook kunt maken met één void. Je kan namelijk in de code van de void bepaalde variabelen zetten, in plaats van waarden. Deze variabelen kunnen dan steeds verandert worden wanneer de void aangeroepen wordt in de loop.

Voorbeeldcode:

// zet je jouw eigen gekozen woorden gelijk aan uitgangen van de arduino.

const int lichtGroen = 12;

const int lichtOranje = 11;

const int lichtRood = 10;

void setup() {

// Deze ” loop ” doorloopt hij eenmaal. Hier declareer je jouw poorten.

pinMode ( lichtGroen, OUTPUT);

pinMode ( lichtOranje, OUTPUT);

pinMode ( lichtRood , OUTPUT);

Serial.println ( 9600);

}

void loop() {

// hier zet je de opdrachten die uitgevoerd moeten worden.Deze “loop” wordt steeds herhaald.

verkeersLicht(lichtRood, lichtGroen);

delay ( 1000);

verkeersLicht(lichtGroen, lichtOranje );

delay (200);

verkeersLicht(lichtOranje, lichtRood);

delay ( 1000);

}

void verkeersLicht(int licht1, int licht2){

digitalWrite( licht1 , LOW);

digitalWrite( licht2 , HIGH);

}

// zet je jouw eigen gekozen woorden gelijk aan uitgangen van de arduino.

const int lichtGroen = 12;

const int lichtGeel = 11;

const int lichtRood = 10;

void setup() {

// Deze ” loop ” doorloopt hij eenmaal. Hier declareer je jouw poorten.

pinMode ( lichtGroen, OUTPUT);

pinMode ( lichtGeel , OUTPUT);

pinMode ( lichRood , OUTPUT);

Serial.println ( 9600);

}

void loop() {

// hier zet je de opdrachten die uitgevoerd moeten worden. Deze “loop” wordt steeds herhaald.

digitalWrite(lichtRood, LOW);

digitalWrite(lichtGroen, HIGH);

delay ( 1000);

digitalWrite(lichtGroen, LOW);

digitalWrite(lichtGeel, HIGH);

delay (200);

digitalWrite ( lichtGeel , LOW);

digitalWrite ( lichtRood , HIGH);

delay ( 1000);

}

Variabelen:

Variabelen worden gebruikt om een logische structuur in het programma te krijgen. We stellen zelfgekozen, logische verwijzingen gelijk aan getallen , bewerkingen , gelezen waarden… We vervangen lange , ingewikkelde “arduino-taal” door functionele woorden zodat ook anderen gemakkelijk het programma kunnen lezen en begrijpen. 

We maken een onderscheid tussen normale en zogenoemde constante variabelen. Hun waardes zijn onveranderlijk doorheen het hele programma. Constanten worden meestal gebruikt om pinnen een logische naam te geven. Wanneer programma’s langer worden,  wordt het vaak onmogelijk om de functie van “pin 12“ te onthouden. Hier komen constante variabelen aan de pas! Voor de Setup kan men “pin 12“ hernoemen naar bijvoorbeeld “ LedRood “. Dit zorgt niet alleen voor een aangename manier van werken, maar bij later aanpassing van de schakeling ( bv: de rode led verandert van “pin 12”  naar “pin 11” ) kan dit ook eenvoudig aangepast worden in het programma. Variabelen worden vermeld boven de Setup. Constanten worden samen met hun vaste waarde vermeld.

Programmeeromgeving
Notities:

De arduino-taal gebruikt steeds een hoofdletter bij een volgend ‘woord’ in het commando. Het is aan te raden om eenzelfde structuur is je gekozen variabelen te verwerken. Bijvoorbeed pinMode(); -> ledRood.

Types variabelen:

Voor arduino zijn niet alle variabelen gelijk. Door ze in verschillende soorten op te delen, weet de arduino-processor waar hij mee te maken heeft. We onderscheiden hier vier soorten , elk met zijn maximale groottes. Waarom gebruiken we niet steeds de grootste? Wel , hoe groter de soort variabele , hoe meer tijd dat de verwerker nodig zal hebben om deze te
lezen. Om lange programma’s soepel te laten lezen, is het belangrijk dat je steeds de juist soort variabele kiest. De variabele kan gekozen worden voor elke onderdeel apart. Kies dus zeker niet een grote variabele voor al je onderdelen als slechts één onderdeel het echt nodig heeft.

Byte: een byte word gebruikt om een 8-numerieke waarde ( in bytes) zonder een decimale punt op te slaan. Deze heeft een bereik van 0-255.

Int: staat voor integer en wordt het meeste gebruikt. De vertraging is bijna onbestaande , maar in vergelijking met de byte heeft deze een veel groter bereik en kan het ook negatieve waarden opslaan. Daarom worden ook voor constante variabelen integers gebruikt. Integer kunnen een getal zonder decimale punt met een 16-bit waarde opslaan. Het bereik van een integer bedraagt -32768 tot 32767.

Long: datatype voor extreem grote getallen zonder decimale punt. Deze heeft een 32-bit waarde en een bereik van -2 147 483 648 tot 2 147 483 647.

Float: Het zwaarste datatype met een zeer groot bereik. Bewerkingen met dit datatype duurt het langst , maar een float is de enigste soort variabele die een getal met een decimale punt kan opslaan. Een float wordt dus gebruikt voor kommagetallen op te slaan voor later gebruik. Gebruik deze variabele niet altijd, want je reactietijd van je programma zal hierdoor drastisch veranderen. Zeker als je niet 1 maar bijvoorbeeld 20 Float’s in je programma verwerkt hebt.

Programmeeromgeving
Unsigned variabelen:

Elke variabele kan verandert worden in een ‘unsigned’ variabele. Bij standaard variabelen zijn de minimale en maximale waarden ‘gespiegeld’ rond 0. Nul bevindt zich in het midden van het inteval! Bij ‘unsigned’ variabelen wordt nul het minima van de variabele. Zo zal de maximale waarde verdubbelen in waarde, want het interval blijft gelijk. Echter ‘unsigned’ variabele zullen geen negatieve waarden meer kunnen opslaan!

int

long

Standaard:

[ – 32 768; 32 767]

[ -2 147 483 648 ; 2 147 483 647]

unsigned:

[0 ; 65 534]

[0 ; 4 294 967 296]

Een speciaal soort variabele is de ‘String’. Deze declaratie is eigenlijk geen getal, maar een lijst van tekens. Je kan er woorden en getallen in opslaan om later te gebruiken. Een ‘String’ en een ‘char’ zijn in feite zo goed als gelijk. Bij een ‘String’ wordt er echter automatisch een extra nul-byte achter de lijst toegevoegd. Hierdoor is het vaker gebruikt bij meerdere tekens, terwijl ‘char’ meer gebruikt wordt voor één teken op te slaan. Veel belangrijker is dat er voor een ‘String’ meer commando’s beschikbaar zijn.

Functies:

Deze functies zijn onze tools om te coderen! Door de verwerker te manipuleren kunnen we ons gewenst resultaat behalen. Met deze functie dwingen we de verwerker keuzes te maken. Welke keuze de verwerker zal maken en het resultaat van deze keuze kunnen we vooraf bepalen. Deze keuzes geven ons te kans om onze code te variëren naargelang de input dat de Arduino krijgt van de sensoren.

Betekenis:

Test een variabele of variabelen en voer de code uit als en slechts als er aan de voorwaarde voldaan is. De genoemde code is geschreven tussen de acculades, maar volgt wel de normale Arduino-taal. Zou de voorwaarde niet voldaan zijn, slaat Arduino deze code over en leest verder in het programma. Het geeft je dus de mogelijkheid om te bepalen welke stukken wanneer worden uitgevoerd. In plaats van een stuk code die altijd doorlopen wordt, krijg je een basiscode die steeds doorlopen wordt en een aanvullende code die slechts gelezen wordt onder bepaalde omstandigheden. Deze aanvullende code biedt vele mogelijkheden, kan in verschillende delen opgedeeld zijn en hoeft zeker niet onder eenzelfde voorwaarde gecodeerd te staan.

Notities:

We gebruiken steeds ‘ == ‘ als we willen testen of een variabele gelijk is aan de gekozen waarde. Wanneer je het gelijkheidsteken niet verdubbeld, dan verandert je commando. Een enkel gelijkheidsteken ‘ = ‘ zet de waarde gelijk aan de gekozen waarde, terwijl ‘ == ‘ test of de waarde opgeslagen in de variabele gelijk is aan de gekozen waarde.

Context:

if ( Variabele overeerkomst waarde ){

aanvullende code

}

Voorbeeldcode:

if( knopStatus == HIGH){

// code
}


if ( sensorStatus == 1000){

// code

}


if ( 800 < sensorStatus < 1200){

// code

}

 

if ( 800 =< sensorStatus =< 1200){

// code

}


if ( knopStatus == HIGH && a == 1){

// code

}


if ( knopSatus == HIGH or a == 1){

// code

}

 

Betekenis:

De if-else is een uitbreiding op de if-functie. Het verschil treed op als de code in de if-functie doorlopen is. Bij een if-functie leest de verwerker direct verder, terwijl bij de if-else functie de verwerker na de gelezen code het andere deel van de if-else-functie ook overslaat. Het heeft ons de mogelijkheid om twee stukken code van elkaar te scheiden. Dit wil zeggen dat deze codes nooit, in eenzelfde verwerking van de voidLoop, beiden uitgevoerd zullen worden. Deze codes hebben geen limieten. We kunnen dus na een if-else-functie weer een if-functie gebruiken.

Context:

If ( Variabele overeerkomst waarde ){

aanvullende code

}

else {

secundaire code

}

Voorbeeldcode:

if( knopStatus == HIGH){
// code
}
else{
// secundaire code
}

 

if ( 800 < sensorStatus < 1200 ){

// code

}

else if ( sensorStatus < 800 ){

// secundaire code

}

else if ( sensorStatus > 1200){
// tertiaire code
}

 

if ( Voorwaarde == Waarde ){

// Toegang
}
else {
// Foutmelding
}

 

Betekenis:

De For-functie wordt gebruikt om een stuk aanvullende code een vooraf gekozen aantal keer te herhalen. Je kan dus eenzelfde code meerdere malen laten doorlopen in éénzelfde cyclus. De aanvullend code wordt dus een eindig aantal keer doorlopen.

Eerst wordt de variabele gekozen, en zou het nodig zijn gedeclareerd. Deze stap omvat tevens de startwaarde, aangezien de gekozen variabele een waarde heeft. Daarna wordt de voorwaarde bepaalt. Deze wordt steeds getest en bepaalt dus of de code wel of niet nogmaals doorlopen wordt. Tot slot hebben we de stap. Dit is de bewerking die de gekozen variabele ondergaat nadat deze gecontroleerd is aan de voorwaarde. De interactie tussen de startwaarde, de stap en de voorwaarde bepaalt het aantal uitvoeringen van de aanvullende code.

Context:

for ( variabele; voorwaarde, stap){

aanvullende code

}

Voorbeeldcode:

for( int a =0 ; a < 5 ; a ++ ){

//code

}

 

int b=0 ;

for ( b ; b<10 ; b++ ){

// code

}

 

int c = 0;

int d = 15;

for ( c ; c < d ; c++ ){

//code

}

 

int e = 0;

int f = analogRead( sensor);

for ( e; e < f ; e ++ ){

// code

}

 

int g = 15;

for ( g ; g > 0 ; g– ){
// code
}

 

int h = 0;
for ( h ; h< 20 ; h+2 ){
// code
}

 

int i=0;
int j= 4;
for ( i ; i < 100; i+j ){
// code
}

 

int k = 0;
int l = random(5,20);
for ( k ; k < 1000 ; k+l ){
// code
}

 

Betekenis:

Deze functie is de variant van de for-functie. Bij de for-functie is er altijd een vooraf geweten tijdsinterval bepaalt door de stap en de voorwaarde. Echter bij een while-loop is deze ‘stap-voorwaarde’-structuur vervangen door een ‘variabel-overeenkomst-waarde’-structuur. Deze doet wat de naam omschrijft: voer de aanvullende code uit zolang de voorwaarde klopt. Bij de while-functie is er du geen verplichting tot een ‘stap-voorwaarde’-structuur, maar deze functie kan wel zo gebruikt worden.

Zoals je weet heeft de if-functie eenzelfde ‘variabel-overeenkomst-waarde’-structuur. Echter de if-functie voert de code slechts eenmaal uit om dan verder te gaan in de code. De while-functie neemt de verwerker ‘gevangen’ zolang de voorwaarde geldt. Dit wil zeggen dat wanneer de verwerker in de while-functie begint te lezen, deze pas weer verder gaat als de voorwaarde niet meer geldt.

Notities:

Deze functie is zeer gevaarlijk om fouten in te maken. In code 1 bijvoorbeeld zal de led nooit uitgaan. Dit komt omdat in de functie zelf, de sensorwaarde niet opnieuw gelezen wordt. Arduino onthoud echter de waarde die hij las wanneer hij de laatste keer het commando ‘analogRead();’ tegenkwam. Doordat arduino de while-functie niet zal breken zonder dat de voorwaarde niet meer geldt, zal de sensor-waarde niet meer gelezen worden vanaf de verwerker eenmaal in de while-functie ‘gevangen’ zit. We kunnen dus stellen dat de variabele ‘sensorWaarde’ vanaf dan een constante wordt. Met gevolg dat de while-functie nooit doorbroken zal worden.

Bij code 2 zal de sensorwaarde bij elke uitvoering van de while-functie gelezen worden. Hierdoor verandert de variabele ‘sensorWaarde’ steeds en kan de while-functie doorbroken worden wanneer de waarde niet meer voldoet aan de voorwaarde.

Code 1: 

void loop() {
sensorWaarde = analogRead( sensor);
while ( sensorWaarde < 1200){
digitalWrite( ledRood , HIGH);
}
digitalWrite ( ledRood, LOW);
}

Code 2:

void loop() {
sensorWaarde = analogRead( sensor);
while ( sensorWaarde < 1200){
digitalWrite( ledRood , HIGH);
sensorWaarde = analogRead( sensor);
}
digitalWrite ( ledRood, LOW);
}

Context:

While ( Variabele overeerkomst waarde ){

aanvullende code

}

Voorbeeldcode:

int a = 0;
while ( a < 5){
// code
a ++
}

 

sensorWaarde = analogRead( sensor);
while ( sensorWaarde < 1200){
// code
sensorWaarde = analogRead( sensor);
}

Betekenis:

Do-while-functies zijn een uitbreiding op de while-functie. Net zoals while-functie werken do-while met een ‘variabel-overeenkomst-waarde’-structuur. Net zoals de while-functie wordt de aanvullende code hier doorlopen zolang de voorwaarde geldt. Echter bij de do-while-functie wordt de voorwaarde achter de code geschreven. Dit lijkt misschien niet erg nuttig, maar het wordt natuurlijke gedaan om een reden. Door deze subtiele verandering wordt er een groot verschil, voor de verwerker, gemaakt. Hij zal namelijk nu, ongeacht of de voorwaarde voldaan is, altijd de code éénmaal per cyclus doorlopen. De aanvullende is nu eigenlijk geen aanvulling meer. Deze code behoort tot de hoofdcode, want hij wordt altijd eenmaal gelezen per cyclus, net zoals de hoofdcode. Deze code kunnen we beschouwen als een additionele code. Hij namelijke vele malen doorlopen worden, maar nooit overgeslagen worden.

Context:

Do {

additionele code

} while ( Variabele overeerkomst waarde );

Voorbeeldcode:

int a = 0;
do {
// code
a ++;
}while ( a < 5);

 

sensorWaarde = analogRead( sensor);
do {
// code
sensorWaarde = analogRead( sensor);
}while ( sensorWaarde < 1200);

Betekenis:

Als in een code een variabele slechts bepaalde waarden kan aannemen, maar bij elke waarde toch een andere code moet worden uitgevoerd, dan komt de switch … case functie aan de pas! Zo kan bijvoorbeeld een deel van de code geactiveerd worden wanneer ‘a’ gelijk is aan 1, en een ander deel wanneer ‘a’ gelijk is aan 2. Dit werkt niet met intervallen, maar je kan je code zo programmeren dat dit niet nodig is! Dit doe je door bijvoorbeeld deze functie te combineren met een if-functie of een map-commando.

if-functie:

if ( 1000 < sensorWaarde < 2000 ) {
a = 1; 
}

map-commando:

map ( sensorWaarde , 0, 3000, 0,3);

Context:

switch (variabele){

case constante :
eerste code
break;

case constante :
tweede code
break


}

Voorbeeldcode:

sensorWaarde = analogRead ( sensor);
map ( sensorWaarde , 0, 1023 , 0 , 3 );
switch (sensorWaarde){
case 1:
digitalWrite ( ledRood, HIGH);
break;
case 2:
digitalWrite ( ledGroen, HIGH);
break; 
case 3:
digitalWrite ( ledGeel, HIGH); 
break; 
}