Track 4

Inmiddels heb je wat ervaring opgedaan in de basis van eht Arduino programmeren. Tijd om eens wat diepere onderwerpen te gaan bespreken. We gaan je leren hoe je Arduio statusmeldingen op het scherm kan tonen, Gebruikt kunt maken van Pulse-With-Modulation, analoge input en we leren je de 4-Digit LED Display en de LED-matrix te programmeren. Let's go!

Arduino serieel

Soms wil de de Arduino wat status mededelingen op het scherm laten tonen. Vaal gebruik je dit op het moment dat je de Aruino wilt debuggen. Op het moment dat we de code werkend hebben, kunnen we via de Seriële verbinding gebruiken om via de USB-kabel berichten naar onze computer te sturen en op het scherm te tonen. Onderstaande code krijgt dat voor elkaar, daaronder zullen we de code uitleggen.

void setup() {
 Serial.begin(9600);
}

void loop() {
 Serial.println("hello world");
}

In de setup() functie moeten we de Seriële verbinding aanmaken. In de Serial.begin() functie geven we een parameter mee. Deze parameter noemen we de baudrate. Dit getal houdt verband met hoeveel bits er per seconde over de verbinding worden verstuurd. Het getal is de uitkomst van een wiskundige berekening. Hoe dit getal tot stand komt, is voor jouw project niet belangrijk om te weten, maar weet dat het bestaat en dat we het kunnen instellen.

Vervolgens kunnen we met de functie Serial.println() een stuk tekst via de Seriële verbinding versturen. In de Arduino IDE zit een zogenaamde Serial Monitor. Deze monitor kan gebruikt worden om de tekst die de Arduino stuurt op het scherm te tonen, maar ook om teksten naar de Arduino toe te sturen. Hier heb je dan wel weer andere code voor nodig en laten we voor nu even buiten beschouwing. Als je de Ardino IDE opent, zie je rechtsboven een vergrootglas knopje. Zorg ervoor dat je Ardiuno aan je computer is gekoppeld en dat de instellingen van de IDE juist staan. Als je vervolgens op het knopje klikt, open je de Seriële monitor.

Figuur 4.1: De Arduino IDE

Vervolgens opent zich een wit scherm, waar de output die door de Arduino wordt verstuurd op verschijnt. Daarvoor is het wel belangrijk dat de baudrate van de monitor goed staat. Die kun je rechtsonder in de monitor instellen door middel van een dropdown box. In deze lijst is ook te zien wat de mogelijke baudrates zijn. In de meeste gevallen wordt de 9600 baudrate gebruikt.

Download de Arduino serieel opdracht
Om deze .zip te kunnen uitpakken, is de code nodig die op het ticket van Track 4 staat.

Arduino PWM

Tot nu toe hebben we de Arduino alleen gebruikt om output signalen handmatig hoog of laag te zetten. Een andere vorm van output kan worden gerealiseerd met PWM (Pulse With Modulation). Met PWM kun je het output signaal dat uit een pin gaat beïnvloeden. Deze techniek wordt bijvoorbeeld toegepast om bepaalde type motoren harder en zachter te laten draaien of om leds minder fel te laten branden of te laten pulseren. Hoe het werkt is dat we kunnen zeggen dat de output bijvoorbeeld 25% van de tijd aan moet staan en 75% van de tijd uit moet staan, maar iedere andere verdeling is ook mogelijk. Doordat het signaal heel snel wisselt, is deze wisseling met het blote oog niet te zien, maar krijgen we wel een zwakker signaal en zal een motor minder snel draaien, of een led minder fel branden. In figuur 4.2 is schematisch te zien hoe het output-signaal er uit kan zien.

Figuur 4.2: Schematische weergave van PWM

In het schema zie je de term Duty Cycle staan. Deze term geeft aan hoeveel procent van één cyclus het signaal hoog is. Hoe lang één cyclus is noemen we de frequentie. Als we een frequentie van 100Hz (Hertz) hebben, zal het output signaal 100 keer per seconden wisselen van hoog naar laag en weer terug. De duty cycle geeft dus de verhouding weer tussen hoog en laag per cyclus.

Om PWM te kunnen toepassen hebben we slechts één simpele functie nodig.

analogWrite(pin, value);

Met de pin parameter geven we aan welke pin we willen aanspreken en in value geven we door middel van een waarde tussen de 0 en 255 aan wat de duty cycle moet zijn. Bij een waarde van 0 staat deze altijd uit, bij een waarde van 127 staat deze 50% aan en 50% uit en bij een waarde van 255 staat deze altijd aan. De frequentie van het signaal (hoeveel cyclussen er in 1 seconde zitten) is ook aan te passen, maar daarvoor moet je knoeien met de interne klok van de Arduino. Als je dit aanpast heeft dat effect op de volledige timing van je Arduino, dus ook op hoe lang een delay duurt! Wij raden het dus zeer sterk af en het is voor je project ook niet nodig.

PWM werkt niet op alle poorten. Zoals je in het pinout diagram van de Nano in figuur 4.3 kunt zien, zijn er bij sommige pinnen golflijntjes tussen de pin en de labels getekend. Alleen op deze pinnen is het mogelijk PWM toe te passen. Voor de Nano zijn dit dus pinnen 3, 5, 6, 9, 10 en 11.

Figuur 4.3 Het pinout diagram van de Arduino Nano
(Klik op het plaatje voor een grotre weergave)

Let op! We kunnen het niet vaak genoeg blijven zeggen, maar denk bij het maken van deze opdracht weer aan de weerstanden!

Download de PWM opdracht
Om deze .zip te kunnen uitpakken, is de code nodig die op het ticket van Track 4 staat.

Analoge input

Zoals we in de eerste Track al kort even bespraken, kunnen we de Arduino gebruiken om analoge sensoren uit te lezen. Alle andere dingen die we tot nu toe hebben behandeld, kunnen ook met de Pi gedaan worden. Voor analoge sensoren hebben we echt de Arduino nodig. Een analoge sensor is niets anders dan een component dat een waarde uit de omgeving meet en aan de hand daarvan een variabele spanning teruggeeft. En temperatuur sensor kan bijvoorbeeld naarmate de temperatuur hoger wordt, meer spanning aan de Arduino doorgeven. Als we die spanning kunnen uitlezen en weten hoeveel spanning de temperatuur sensor geeft bij welke temperatuur, kunnen we op die manier uitrekenen hoe warm het is.

Nu kunnen we heel simpel zo'n sensor nabootsen met een potmeter. (Of voluit: een potentiometer) Een potmeter is een schuifweerstand, wat betekend dat we de weerstand kunnen instellen en daarmee ook de spanning die op de Arduino komt te staan. In figuur 4.4 is zo'n potmeter op de Arduino aangesloten en je vindt er ook een terug in je hardware kit.

Figuur 4.4: Fritzing tekening van een aangesloten potmeter

Een potmeter heeft drie pinnen. De ene buitenste pin sluit je aan op de 5V van de Arduino en de andere sluit je aan op een Ground. Het maakt nu even niet uit welke pin je waarop aansluit. Het verschil zit hem erin dat je als je de knop van de potmeter naar links draait je de potmeter in de ene situatie 'dicht' draait en in de andere situatie 'open' draait.

De middelste pin sluit je aan op een analoge-input-pin. Dit zijn in het pinout diagram (te zien in afbeelding 4.3) de pinnen waar er naast de groene labels met een A-getal staan. Ook naast de pinnen op de fysieke Arduino zie je bij de analoge pinnen A getallen staan.

In de Arduino zit een 10 bits analoog naar digitaal converter. Dit houdt in dat een voltage op de pin wordt omgezet naar een getal tussen de 0 en 1023. Deze waarde kan worden uitgelezen met de onderstaande code:

const int SENSORPIN = A0; 
int sensorValue = 0;

void setup() {
 pinMode(SENSORPIN, INPUT);
}

void loop() {
 sensorValue = analogRead(SENSORPIN);
 delay(100);
}

Zoals je in de code al ziet, kun je de analoge pinnen letterlijk aanspreken met het label. Denk wel aan de hoofdletter A! Vervolgens wordt deze pin gewoon ingesteld als een INPUT pin zonder pull-up resistor.

Maar hoe wordt die analoge waarde nu omgezet? Op het moment dat de potmeter dicht is en er geen spanning op de pin staat, zal de functie de waarde 0 teruggeven. Als er 5V op de pin staat, zal de functie 1023 teruggeven. Maar als er 2,5V op de pin staat, zal de functie 512 teruggeven. Iedere stap omhoog, betekend een verschil van 5V / 1023 ≈ 0,00488758...V omhoog. Je kunt deze omrekening dus beter opslaan in een constante.

const double STAPGROOTTE = 5.0 / 1023;

Goed, dit is weer voldoende informatie over analoge sensoren uitlezen. Tijd om hier een opdracht mee te maken.

Hoe gek het misschien ook klinkt, hoef je hier niet nog een extra weerstand in je schakeling op te nemen. Bij knopjes moet dit wel altijd. De rede hiervoor is natuurlijk dat een schuifweerstand zelf al een weerstand is!

Download de analoge input opdracht
Om deze .zip te kunnen uitpakken, is de code nodig die op het ticket van Track 4 staat.

LDR

Nu je kennis hebt hoe je een potmeter kunt uitlezen, is de stap om een LDR (Light-Dependent Resistor) te kunnen uitlezen een hele kleine. Een LDR is een weerstand, waarvan de weerstand afhangt van de hoeveelheid licht dat op het membraam valt. In figuur 4.5 zie je hoe je de LDR op je Arduino moet aansluiten.

Figuur 4.5: Fritzing tekening van een aangesloten LDR

De blauwe kabel sluit je dus aan op een analoge pin die je vervolgens kunt uitlezen. Als weerstand kun je het beste de weerstanden van 10kΩ uit je kit gebruiken. Deze zorgen ervoor dat de minimale en maximale waarde die de Arduino ontvangt wat groter zijn. De weerstand van de LDR veranderd wanneer er meer of minder licht op valt. Daardoor veranderd de spanning die over de LDR staat ook mee. Deze spanning kunnen we vervolgens meten in de blauwe kabel.

De schakeling die in figuur 4.5 is gemaakt, noemen we een spanningsdeler. Het gaat te diep voor de stof die jullie moeten kennen om precies te gaan uitleggen waarom dit werkt. Maar je bent natuurlijk altijd vrij om zelf eens op Google onderzoek te doen naar spanningsdelers als je het interessant vind!

Het uitlezen van de potmeter gaf een bereik van 0 als de potmeter dicht zat tot 1023 als de potmeter volledig open stond. Ik kreeg met de opstelling in de afbeelding en een weerstand van 10kΩ een bereik van ongeveer 500 op het moment dat ik mijn vinger op de LDR legde en 820 als deze zonder bedekking onder een lamp stond. Genoeg marge dus om af te lezen of er wel of geen voorwerp op de LDR staat.

Download de LDR opdracht
Om deze .zip te kunnen uitpakken, is de code nodig die op het ticket van Track 4 staat.

4-Digit LED Display

Op een gegeven moment moet je bordspel een viercijferige code kunnen tonen, die de gebruiker op je website kan invoeren. Dit gaan we doen met behulp van de 4-Digit LED Display die je in je kit vindt.

Figuur 4.6: De 4-Digit LED Display

Zoals je ziet zijn er maar vier pinnen nodig om dit display aan te sturen. Onder het display zie je dat dit display zelf een microprocessor heeft die het display aanstuurt. Om de Arduino te laten communiceren met deze microprocessor maakt dit display gebruikt van het I2C (Inter-Integrated Circuit) communicatie protocol. Een veel gebruikt protocol binnen de hardware communicatie. Gelukkig kunnen we gebruik maken van een library die deze communicatie voor ons regelt. Als je benieuwd bent hoe I2C onderwater werkt, kun je de Wikipediapagina over I2C eens raadplegen of kijken naar het IPMEDT5 gedeelte van deze site. In latere jaren gaan we ons hier namelijk iets meer in verdiepen.

De link naar de I2C pagina op Wikipedia:
https://nl.wikipedia.org/wiki/I%C2%B2C-bus

Zoals we net al even zeiden, kunnen we gelukkig gebruik gaan maken van een library voor dit display. Surf naar de library via onderstaande link.

De library is te vinden op deze pagina:
https://github.com/bremme/arduino-tm1637

Navigeer op de GitHub pagina die je ziet naar de src map. In deze map die je zes verschillende files staan. Drie .h files en drie .cpp files. Voor ons project hebben we de SevenSegmentTM1637.cpp en .h files nodig en daarnaast ook nog de SevenSegmentAsciiMap.cpp en .h files. Klik deze aan. Je ziet dat de code in de files getoond wordt. Klik in de section waar de code staat op de button met het woord RAW erop. Nu zie je de ruwe tekst die in deze file staat. Door vervolgens met je rechtermuisknop op de pagina te klikken en te kiezen voor 'Opslaan als...' kunnen we de file op onze computer opslaan. Sla de bestanden in dezelfde map op als de .ino file van je project. Zorg er ook voor dat je de .txt toevoeging achter de bestandsnaam weghaalt en de files als .cpp en .h opslaat. Anders gaat onze Arduino sketch ze niet herkennen. Uiteindelijk heb je dus de volgende files in een folder staan:

  • naam_project.ino
  • SevenSegmentAsciiMap.cpp
  • SevenSegmentAsciiMap.h
  • SevenSegmentTM1637.cpp
  • SevenSegmentTM1637.h

Als je dit gedaan hebt, kunnen we het display aansluiten op de Arduino. Op de onderkant van het display is te zien wat de functie is van de verschillende pinnen. Sluit de 5V pin aan op een 5V pin van je Arduino en de GND pin op een Ground pin van je Arduino. De CLK (clock) en de DIO (Data input-output) pinnen sluit je aan op twee digitale pinnen van je Arduino. In het voorbeeld hieronder heb ik de CLK op pin 3 en de DIO op pin 2 van de Arduino aangesloten. Vervolgens kunnen we met onderstaande code het display aansturen.

#include "SevenSegmentTM1637.h"

const int DISPLAY_CLK = 3;
const int DISPLAY_DIO = 2;

SevenSegmentTM1637 display(DISPLAY_CLK, DISPLAY_DIO);

void setup() {
 display.begin();
 display.setBacklight(100);
 display.clear();
 display.print("2458");
 delay(1000);
}

void loop() {
 //Do something
}

Bovenaan de code zie je het #include keyword. Hiermee importeren we de library in ons project en kunnen we van de functies uit deze library gebruik maken in ons project. Omdat we op dit moment met een lokale library werken (hij is immers opgeslagen in de map waar onze .ino file zich bevindt) moeten we gebruikmaken van dubbele accolades om de naam heen. Als we gebruik willen maken van libraries die door Arduino zijn voor geïnstalleerd, dan moeten we de naam van de library omgeven door een kleiner-dan teken < en groter-dan teken >. Om een library te importeren in ons project is het importeren van de .h file voldoende. De IDE zoekt tijdens het compileren automatisch de bijbehorende .cpp file op. Wat het verschil is tussen een .h en een .cpp file, leer je in latere jaren.

Vervolgens slaan we de CLK pin en de DIO pin op in hun eigen constante. Deze geven we mee in de constructor van het display.

Vervolgens kunnen we het display aanspreken door de naam display, gevolgd door de functie die we willen aanroepen. De .begin() functie is nodig om de display startklaar te maken. Met setBacklight(100) zetten we de lichtsterkte van de display op volledig. Met de .clear() functie maken we het display leeg en tot slot kunnen we met de .print() functie een getal naar het display sturen om deze te tonen. Via de .print() functie kun je ook teksten op het display tonen, maar die vind ik persoonlijk erg slecht leesbaar. Probeer deze functionaliteiten maar eens uit. Op de Github pagina van de library is terug te vinden welke functionaliteiten het display nog meer ondersteund, maar dit zijn voor nu de belangrijkste.

Download de 4-Digit LED Display opdracht
Om deze .zip te kunnen uitpakken, is de code nodig die op het ticket van Track 4 staat.

LED-matrix

In dit laatste onderdeel van de Hardware Heaven gaan we je leren hoe je een led-matrix moet aansluiten. En bereid je maar vast voor op de code die gaat komen, want we gaan in dit laatste stukje van de hardware heaven wat ingewikkelder programmeerwerk doen! In Figuur 4.7 staat onze led-matrix afgebeeld.

Figuur 4.7: De LED-matrix

Voordat we gaan beginnen met programmeren, eerst even een stukje uitleg hoe een LED-matrix werkt. Zoals de naam al doet vermoeden, is een led-matrix een matix van allemaal leds. In ons geval telt de matrix acht rijen en acht kolommen. Hoe de matrix intern geschakeld is, is te zien in figuur 4.8.

Figuur 4.8: De schematische tekening van een led-matrix

Stel we willen in deze matrix het ledje links bovenaan aanspreken. Dan zetten we spanning op R1 en halen we de spanning weg van C1. Dan kan de stroom, via het ledje links bovenin, van R1 naar C1 lopen en gaat dat ledje branden. Als we nog meers leds op die rij willen laten branden, dan kunnen we ook van die C-pinnen de spanning weghalen, zodat ook daar de stroom doorheen gaat lopen en ook die leds aangaan. Op de rest van de C-pinnen zetten we de spanning hoog, zodat daar de stroom niet doorheen kan lopen en die leds uit blijven.

Vervolgens moeten we de spanning van R1 afhalen en gaan we op dezelfde manier alle leds van R2 die we aan willen hebben aansturen. Hiervoor zetten zetten we dus spanning op R2 en halen we van de juiste C-pinnen de spanning weer af. Dit herhalen we net zo lang totdat we rij acht hebben gehad. Echter zal er op deze manier telkens maar één rij branden. Als we dit echter heel snel doen, dan zullen we met het blote oog niet kunnen zien dat de rijen eigenlijk één voor één aan en uit worden gezet. Gelukkig hoeven we dit niet allemaal zelf te programmeren en is er een library gemaakt die dit allemaal voor ons regelt. De link hieronder stuurt je naar de pagina waar de library is te downloaden.

De library is te vinden op deze pagina:
https://www.arduinolibraries.info/libraries/led-control

Deze keer zit de library in een .zip bestand opgeslagen. Maak een Arduino project aan en sla deze ergens op. Ga nu naar de map waar je de .ino hebt staan en pak daar de map uit. Open de map, ga vervolgens naar de src map en kopieer de LedControl.cpp en .h file weer naar de map waar je .ino bestand staat. Zo kan ons Arduino project, net als bij het 4-Digit LED Display, de library weer vinden. De onderstaande link stuurt je naar de pagina waar de functies uit de library staan uitgelegd, maar die zullen we hier ook verder toelichten.

De uitleg is te vinden op deze pagina:
http://wayoda.github.io/LedControl/pages/software

Goed, de hoogste tijd om de matrix eens aan te sluiten. Hiervoor moeten we de pinnen gebruiken die naast de zwarte chip zitten. De pinnen die onder de matrix zelf uitkomen kunnen gebruikt worden om een volgende matrix op aan te sluiten. Sluit de VCC en de GND pinnen van de matrix respectievelijk aan op de 5V en Ground pin van de Arduino. De andere pinnen gaan naar een digitale pin van de Arduino. In het komende voorbeeld sluiten we de DIN aan op pin 12, CS op pin 11 en CLK op pin 10. Hieronder wordt de code getoond om vervolgens een smiley op het display te tonen. Onder de code wordt weer uitgelegd hoe de verschillende onderdelen werken.

#include "LedControl.h"
const int DIN = 12;
const int CS = 11;
const int CLK = 10;
const int AANT = 1;

const int smiley[8] = {
 B00111100,
 B01000010,
 B10100101,
 B10000001,
 B10100101,
 B10011001,
 B01000010,
 B00111100
};

LedControl matrix = LedControl(DIN, CLK, CS, AANT);

void setup() {
 matrix.shutdown(0, false);
 matrix.setIntensity(0, 8);
 matrix.clearDisplay(0);

 showArray(matrix, smiley);
}

void loop() {
 //Do something
}

void showArray(LedControl lc, const int arr[8]) {
 for (int i = 0; i < 8; i++){
  lc.setRow(0, i, arr[i]);
 }
}

Allereest importeren we de library en maken we voor de verschillende pinnen een constante aan. Je kunt dus ook eventueel andere pinnen gebruiken voor deze library. Vervolgens is eer ook een constante die AANT heet. Dit is het aantal LED-matrixen die we aan elkaar hebben gekoppeld. In ons geval maar 1, maar als je meerdere matrixen op elkaar aan wilt sluiten, kun je dat via deze constante instellen.

Daaronder staat een enorme array van 8 bytes. De B voor de getallen geeft aan dat we deze getallen als een byte opslaan. Ieder bit in deze array komt overeen met het bij behorende led op de led matrix. Als we een byte in de driver zetten, wordt voor iedere 1 de corresponderende led aan gezet en voor iedere 0 de led uit gezet. De bovenste rij, 0 0 1 1 1 1 0 0 zorgt er dus voor dat de leds op die rij opeenvolgend UIT - UIT - AAN - AAN - AAN - AAN - UIT - UIT staan. Door dit voor iedere rij in de matrix te doen, kunnen we via bytes de representatie van de afbeelding op de matrix meegeven. Als je goed kijkt, kun je in de 1-en al een beetje een lachende smiley zien.

Vervolgens maken we een LedControl object aan. Deze funcite halen we uit de library. Zoals je ziet geven we daar de verschillende pinnen mee die we al eerder hebben gedefinieerd.

In de setup moeten we met de shutdown() functie aangeven welke matrix we aan of uit willen zetten. Onder water maakt de library namelijk een array van acht mogelijke matrixen aan, omdat je in totaal acht matrixen op elkaar kunt aansluiten. Echter gebruiken wij er maar één, dus spreken we altijd de matrix op plek 0 aan. Allereerst zetten we via de shutdown() functie onze driver op false, wat inhoud dat hij aan wordt gezet (niet geshutdowned). Vervolgens stellen we via setIntensity() de lichtsterke van onze matrix (0) volledig aan (8) en maken we met de clearDisplay() display 0 leeg.

Vervolgens roepen we de showArray functie aan waar we het LedControl object aan meegeven en de array waar we de smiley in hebben aangemaakt. Dit is een functie die we zelf nog moeten gaan schrijven. Op deze manier kunnen we met één regel code heel makkelijk andere afbeeldingen naar onze matrix sturen.

Onder de lege loop() functie, is de showArray() functie gedeclareerd. Het is een void functie, want hij hoeft niets terug te geven en krijgt een LedControl object (lc) mee en een constante array van integers (arr) mee. In de functie zien we een for loop die 8 keer doorlopen wordt en op die manier de 8 rijen van de matrix langs loopt. voor iedere rij wordt de setRow() functie uit de library aangeroepen om die rij van de matrix in te stellen. Vervolgens wordt uit de array de juiste 'rij' van bytes gepakt om voor die rij klaar te zetten. Op deze manier wordt onze afbeelding in het LedControl object gezet, waarna dit object zorgt dat dit op de juiste manier in de matrix wordt gezet.

Puf. Dat was een hoop code om door te lopen. De hoogste tijd om je eens een opdracht mee te geven met deze stof!

Download de LED-matrix opdracht
Om deze .zip te kunnen uitpakken, is de code nodig die op het ticket van Track 4 staat.

Track 4 eindopdracht

Nu heb je voldoende informatie om de eindopdracht van Track 4 en daarmee ook de eindopdracht van de Hardware Heaven te maken. Dit is een opdracht die je deels thuis moet afmaken, omdat er een stukje afwerking bij komt kijken. Neem je 'prototype' de eerst volgende les mee. Dan worden de schakelingen namelijk individueel gecontroleerd. Als deze opdracht door de docent wordt goedgekeurd, krijg je tevens een echt Hardware-helden certificaat! Het individueel laten aftekenen van deze opdracht is tevens een voorwaarde om een voldoende te halen voor je project. Zorg er dus voor dat je deze opdracht laat aftekenen!

Download de Track 4 eindopdracht
Om deze .zip te kunnen uitpakken, is de code nodig die op het ticket van Track 4 staat.