Denna lektion bygger på samma inkoppling som förra lektionen, men istället för att läsa direkt från en ingång och skriva till en utgång kommer vi här att lägga upp variabler som innehåller vilken I/O pinne som skall användas. Fördelen är att vi behöver bara definiera detta på ett ställe och sedan referera till en variabel istället för ett värde, det är enklare för oss att komma ihåg ett namn som beskriver vad in-/utgången gör istället för en siffra, samt skulle vi ändra I/O pinne framöver så gör vi detta på ett ställe i koden och inte på flera ställen (kan vara lätt att missa ett ställe och till följd får man spendera minuter på att felsöka).
Vidare kommer vi att ändra programmet så att när vi trycker ner tryckknappen första gången så tänds lysdioden och när vi trycker ner den andra gången så släcks den och så vidare. Slutligen kommer vi att förklara vad “debounce” innebär på ingångar. Då elektroniken är den samma som förra lektionen visar vi här inte bilder på det utan koncentrerar oss på programmet.
Koden för den här lektionen hittar du här (vill du ladda hem och inte se den i webläsaren, högerklicka och välj spara som” och visas nedan i sin helhet. Kommentarer i början är lite mer utökad för att visa att man kan skriva lite mer info om vem som gjort koden, version osv.
/* Button & LED Test with variables and button debounce Turns on an LED on Pin 13 when button on Pin 2 is pressed and LED stays on until button is pressed again (with debounce). Created FEB-23, 2012 by Lars Wictorsson LAWICEL AB, http://www.lawicel-shop.se This example code is in the public domain. */
int LEDpin = 13; // LED is attached on I/O pin #13 int BTNpin = 2; // Button is attached on I/O pin #2
boolean LEDstatus = false; // Current LED status, false = OFF, true = ON
void setup() { // initialize the digital pin as an output. // Pin 13 has an LED connected on most Arduino boards. pinMode(LEDpin, OUTPUT); // initialize the digital pin as an input. // Pin 2 is connected to a button tied to GND with external pullup 10K to VCC. pinMode(BTNpin, INPUT); }
void loop() { if (digitalRead(BTNpin) == LOW) { // Check if button is pressed down LEDstatus = !LEDstatus; // Invert LED status digitalWrite(LEDpin, LEDstatus); // Update actual LED to current status delay(150); // Debounce delay 150ms while (digitalRead(BTNpin) == LOW); // Wait until button is released } }
Vi använder som föregående koppling externt pullup-motstånd, så det måste finnas där för att det skall fungera som det skall, annars får man skriva in koden för att aktivera intern pullup (kan ju vara bra att öva på det i ett senare skede).
Låt oss ta en titt på programmet. Före setup() finns 3 rader som är nya, här utanför alla funktioner kan vi definiera variabler och konstanter (konstanter kommer vi till senare). Variabler är något som kan ändra värde och vi kan kalla en variabel precis vad vi vill under förutsättning att det inte är upptaget av fördefinierade funktioner m.m. i C/C++. Försök att namnge dem så att de beskriver vad de är till för. Tidiga programspråk kunde endast hantera en bokstav och då var det inte lätt att komma ihåg vad de gjorde när det bara fanns a, b, c, x, y osv. att tillgå. Idag i moderna språk/kompilatorer kan de skrivas nästan hur som helst. Skall en variabel innehålla en yttertemperatur, så kallar man den inte för “t” utan för t.ex. “TempOut” och gärna på Engelska för det skall vara enklare för andra att ta del av koden om den skall vara öppen. Finns inget värre än att hitta öppen kod på nätet som använder sig av ord och kommentarer på det inhemska språket.
Variabler kan vara heltal, flyttal, booleska. I vårt exempel använder vi heltal (int) och booleska (boolean). Heltal i C/C++ är alla tal som är från -32768 till 32767, dvs. 16 bitar inklusive tecken. Boolean kan bara anta 2 värde “false” eller “true” men även om det bara är en bit, så upptar det ändå en hel byte (8 bits) i C/C++. Avvikelser kan förekomma i andra miljöer/kompilatorer.
Så här i vårt program definierar vi upp 2 variabler av typen int (heltal) och tilldelar dem den utgång vi har lysdioden ansluten på samt den ingång där vi har knappen ansluten på. Sedan kan vi referera till dessa variabelnamn senare i koden och släppa vilket nummer de var anslutna på. Slutligen definierar vi en boolean variabel och tilldelar den värdet “false” som i detta fallet betyder att lysdioden är släckt.
I setup() funktionen har vi bytat ut 13 och 2 med variabelnamnen, likaså använder vi variabelnamnen i loop() funktionen. Det är här vi skall titta mer på vad programmet gör.
void loop() { if (digitalRead(BTNpin) == LOW) { // Check if button is pressed down LEDstatus = !LEDstatus; // Invert LED status digitalWrite(LEDpin, LEDstatus); // Update actual LED to current status delay(150); // Debounce delay 150ms while (digitalRead(BTNpin) == LOW); // Wait until button is released } }
Första raden (if satsen) är precis som innan, vi kollar om knappen är nedtryckt, är den inte det sker ingenting och programmet snurrar runt och väntar bara på att knappen skall tryckas ned. När den väl trycks ned, så sker allt inom if satsens krullparenteser {} och en rad i taget. Första raden LEDstatus = !LEDstatus; kan se lite konstig ut, men i C/C++ betyder utropsteckenet det booleska operatorn “NOT” och tilldelar LEDstatus det värde som den inte har. Så false blir true och true blir false. I denna variabel LEDstatus lagras alltså värdet på utgången där lysdioden sitter, så det koms ihåg till nästa runda. Raden efter skriver vi ut detta värde på utgången där lysdioden sitter. Har lysdioden tidigare varit släckt, blir den nu tänd. På tredje raden har vi en liten fördröjning på 150mS, detta kallas “debounce” och en knapp studsar till flera gånger snabbt innan den blir nedtryckt och skulle vi inte ha denna fördröjning skulle det näst intill vara omöjligt att tända eller släcka lysdioden med en nedtryckning. Vissa knappar är bättre och kan ha kortare s.k. debouncetid medan andra kräver längre, vi väntar helt enkelt tills att knappen slutat att studsa på kontaktbläcket. Prova dig fram och se resultatet. Den fjärde och sista raden (while satsen) väntar helt enkelt på att vi skall släppa knappen. Notera semikolonet sist på den raden, det är det som utförs (dvs ingenting) medan knappen är nedtryckt. När väl knappen släpps så börjar loopen om och vi väntar på att knappen skall tryckas ner igen. I vissa fall kan det krävas ytterligare en fördröjning efter while satsen om det är så att knappen kan studsa till och sluta sig när man släpper den. gör den det, då är det bara att lägga till en fördröjning där med.