oplossing looplicht met twee schuifregisters (16 bit)

 

const int patroon[]={1,2,4,8,16,32,64,128,256,512,1024,2048,4096,8192,16384,32768};
const int ds = 2;
const int stclk = 3;
const int shclk = 4;

void setup()
{
  for(int i=2; i<=4;i++) {
      pinMode(i, OUTPUT);
  }
}

void loop()
{
  int aantal=sizeof(patroon)/sizeof(patroon[0]);
  for(int i=0; i<aantal;i++) {
    for(int bit=0;bit<16;bit++) {
      if(bitRead(patroon[i],bit)==1) {
        digitalWrite(ds,1);}
      else {
        digitalWrite(ds,0);}
      // puls op shiftklok
      digitalWrite(shclk,HIGH);
      digitalWrite(shclk,LOW);
    }
    // puls op storage klok
    digitalWrite(stclk,HIGH);
    digitalWrite(stclk,LOW);
    delay(500);
  }
}

Oplossing looplicht met schuifregister.

In onderstaande code maken we een algemene oplossing die niet alleen voor een looplicht kan dienen, maar voor gelijk welke combinatie van patronen, zolang het maar beperkt blijft tot 8 leds.

Deze oplossing is een combinatie van een datastructuur (een array) en een programmastructuur die met deze datastructuur aan de slag gaat. Helemaal onderaan vind je het totaalprogramma, maar we bekijken eerst stuk per stuk de code.

definitie van de constanten

const int patroon[]={1,2,4,8,16,32,64,128};
const int ds = 2; 
const int stclk = 3; 
const int shclk = 4;

de array

Zoals eerder gezegd maken we gebruik van een array om de te tonen patronen op te slaan. Bij een array definiëren we een variabele of constante die uit een reeks van waarden bestaat. Elk element wordt aangegeven met een indexnummer.

In ons programma maken we op de eerste lijn een array aan. De variabele heet patroon en het type van de variabele is integer. Door de vierkante haakjes na de naam geven we aan dat het om een reeks van integer waarden gaat. Aan deze reeks wordt een verzameling van waarden toegekend. Deze worden opgesomd tussen accolades.

Er staan 8 waarden opgesomd tussen de accolades, dus wordt in het geheugen plaats gereserveerd voor 8 integers. Aangezien een integer twee geheugenplaatsen inneemt, zal in het geheugen 16 byte gereserveerd worden voor deze array.

Eenmaal deze definitie gebeurd is, beschikken we over 8 constante waarden, aangegeven als patroon[0], patroon[1],... patroon[7], waarbij patroon[0]=1, patroon[1]=2, patroon[3]=4,... en patroon[7]=128.

Wanneer we een array van variabelen (dus geen constanten) definiëren, weten we soms op  voorhand niet welke waarden in elke variabele zullen terechtkomen. Dan is het mogelijk om een definitie te maken op volgende manier:

int resultaat[8];

Hierbij worden ook 8 waarden gedefinieerd. Merk op dat het aantal elementen hier tussen de vierkante haakjes staat, terwijl er bij een opsomming niets tussen de vierkante haakjes staat.

Zo zal een definitie zoals

int waarde[3]={1,2,3};

een foutmelding geven bij het compileren, omdat de waarde tussen de vierkante haken mogelijks niet kan overeenkomen met het aantal elementen in de opsomming. We moeten dus altijd de ene of de andere manier gebruiken, maar geen combinatie.

de pinnummers

In lijnen 2 tot 4 van de definitie geven we betekenisvolle namen aan de gebruikte pinnen die de verbinding met het schuifregister maken. Zo wordt pin 2 vanaf nu aangeduid met ds, pin 3 met stclk en pin 4 met shclk. Deze namen zijn respectievelijk data-serial, storage clock en shift clock.

de setup() functie

Tijdens de setup worden pinnen 2 tot en met 4 als output ingesteld. We doen dit met behulp van een lus.

void setup() { 
for(int i=2; i<=4;i++) {
 pinMode(i, OUTPUT);
 }
}

de loop() functie

In de loop() functie beginnen we met het bepalen van het aantal elementen in de array. Op die manier kunnen we achteraf patronen aan de array toevoegen zonder dat we elke keer in het programma het aantal elementen moeten aanpassen. We maken daarvoor gebruik van de functie sizeof(). Deze functie geeft aan hoeveel bytes de aangegeven variabele inneemt in het geheugen. Het resultaat van sizeof(patroon) zal 16 zijn, zoals we eerder reeds hebben uitgelegd. Als we dit resultaat delen door de grootte van 1 element bekomen we het aantal elementen in de array. Een integer is 2 bytes groot, dus delen we het resultaat van de sizeof() functie door 2.

Opmerkingen

Wanneer we de array aanvullen met extra waarden, zal deze berekening automatisch het aantal elementen weergeven. Als we echter het type van de patroon variabele veranderen zal deze uitdrukking een fout resultaat geven. Een truc om dit te vermijden is om gebruik te maken van volgende uitdrukking:

int aantal = sizeof(patroon)/sizeof(patroon[0]);

Door de grootte van de array te delen door de grootte van het eerste element krijgen we een resultaat, onafhankelijk van het type van de elementen van de array. Het enige type waarbij dit niet werkt is uiteraard de string, aangezien deze zelf een variabele lengte heeft.

Vervolgens maken we een lus met een teller i die de elementen van de array doorloopt. In deze lus maken we een tweede (geneste) lus, die voor elk van de elementen van de array de 8 bits doorloopt. Hier gebruiken we als teller de variabele bit.
We gaan in deze lus de waarde van de opeenvolgende bits op de seriële ingang van het schuifregister (=ds) plaatsen en na elke bit een klokpuls op de shiftclock (=shclk) geven om de bit in het schuifregister te schuiven. Aangezien deze lus 8 keer doorlopen wordt zullen de 8 bits van de waarde na het doorlopen van de lus in het schuifregister staan. Daarna wordt een puls op de storage clock (=stclk) gegeven, waardoor de inhoud van het schuifregister in het storage register gekopieerd wordt, en tegelijkertijd ook op de uitgangen van het schuifregister zichtbaar wordt.
Daarna wordt 500 ms gewacht waarna het volgende element uit de array dezelfde behandeling krijgt.
Wanneer de volledige array werd doorlopen begint alles opnieuw van voor af aan.
Om de juiste bit van het juiste patroon op de ingang van het schuifregister te plaatsen maken we gebruik van een bit-functie bitRead(). Deze functie heeft twee parameters nodig: de waarde waaruit de bit moet worden gelezen, en de bitpositie die moet worden gelezen. Resultaat van deze functie is 0 of 1, afhankelijk van de waarde op de gevraagde bitpositie.
Bij de eerste doorloop van de lussen is teller i gelijk aan 0, en is teller bit ook gelijk aan 0. De uitdrukking patroon[0] is in dit geval gelijk aan 1 (eerste element uit de array). Binair uitgeschreven is dit 00000001.
bitRead(patroon[0],0) geeft dus de waarde van de meest rechtse bit in 00000001 en is dus 1.
De if-functie zorgt er dan voor dat op de ds-ingang een 1 geplaatst wordt.
void loop() {
 int aantal=sizeof(patroon)/2;
 for(int i=0; i<aantal;i++) {
   for(int bit=0;bit<8;bit++) {
     if(bitRead(patroon[i],bit)==1) {
       digitalWrite(ds,1);
       } else {
       digitalWrite(ds,0);
       }
     // puls op shiftklok
     digitalWrite(shclk,HIGH);
     digitalWrite(shclk,LOW);
     } 
    // puls op storage klok
   digitalWrite(stclk,HIGH);
   digitalWrite(stclk,LOW);
   delay(500);
  }
}

de totale oplossing

const int patroon[]={1,2,4,8,16,32,64,128};
const int ds = 2;
const int stclk = 3;
const int shclk = 4;

void setup()
{
  for(int i=2; i<=4;i++) {
      pinMode(i, OUTPUT);
  }
}

void loop()
{
  int aantal=sizeof(patroon)/2;
  for(int i=0; i<aantal;i++) {
    for(int bit=0;bit<8;bit++) {
      if(bitRead(patroon[i],bit)==1) {
        digitalWrite(ds,1);}
      else {
        digitalWrite(ds,0);}
      // puls op shiftklok
      digitalWrite(shclk,HIGH);
      digitalWrite(shclk,LOW);
    }
    // puls op storage klok
    digitalWrite(stclk,HIGH);
    digitalWrite(stclk,LOW);
    delay(500);
  }
}

Oefeningen basis 1

Maak een schakeling waarbij met een schuifregister (74HCT595) een 8-bit looplicht gemaakt wordt. Maak het programma zo kort en efficiënt mogelijk.

 

Oefeningen basis 2

Breid oefening 1 uit naar 16 bit met behulp van een extra schuifregister.

Oefeningen gevorderd 1

Maak een schakeling waarbij de stand van een potentiometer op een analoge ingang wordt gelezen, en geef afhankelijk van de waarde een patroon weer op een schuifregister-ledbar.

0-127         : 1 LED
128-255       : 2 LED
256-383       : 3 LED
384-511       : 4 LED
512-639       : 5 LED
640-767       : 6 LED
768-895       : 7 LED
896-1023      : 8 LED

Maak ook dit programma zo kort en efficiënt mogelijk.

Oefeningen gevorderd 2

Maak een universeel programma waarbij de ledbar op het schuifregister een sequentie van patronen doorloopt die gedefinieerd zijn in een array.

De patronen moeten kunnen worden aangepast door enkel de inhoud van de array te wijzigen. Verwerking van de patronen in de array moet automatisch gebeuren.

De snelheid waarmee de patronen na elkaar op de ledbar verschijnen moet kunnen worden ingesteld met een potentiometer.

Opmerkingen

Wanneer je met aparte bits aan de slag moet gaan kun je natuurlijk gebruik maken van de logische functies, maar er bestaan ook een aantal functies voor bitmanipulatie zoals bitRead(), bitWrite(), bitSet() en bitClear().

Meer info over deze functies is te vinden op www.arduino.cc

 

Labo 2

Oefeningen basis 1: analoge waarden lezen

Maak een schakeling waarbij de waarde op een potentiometer ingelezen wordt, en stuur de waarde naar de PC via seriële communicatie.

Gebruik de analogRead() instructie om een analoge waarde te lezen.

vragen

  • kan men op elke pin van de Leonardo een analoge spanning inlezen? Indien niet, op welke dan wel?
  • Tussen welke spanningen mag de in te lezen spanning liggen?
  • Welke waarden krijgt men terug in het programma?
  • Uitgaande van een voedingsspanning van 5V, met welke waarde moet ik gelezen waarde vermenigvuldigen om de werkelijke spanning te bekomen?
  • Uitgaande van een voedingsspanning van 5V, met welke spanning komt een waarde = 255 overeen?

Oefeningen basis 2: analoge waarden schrijven

Maak een programma waarbij een LED langzaam van gedoofd naar volle sterkte gaat, en terug naar gedoofd.

Gebruik de analogWrite() instructie om een analoge waarde op de pin te zetten.

vragen

  • Kan men naar elke pin van de Arduino een analoge spanning sturen?
  • Wordt op de pin echt een analoge spanning aangeboden?
  • Verloopt het dimmen lineair? Hoe zou dat komen?
  • Wat is de maximale spanning die men op een pin kan plaatsen?
  • Welke spanning zal er op de pin staan wanneer ik de waarde 128 gebruik in een analogWrite?
  • Hoe kan men de bekomen spanning stabieler maken?
  • Wat als de analoge pin meer dan 40mA moet leveren aan de aan te sturen schakeling?

Oefeningen basis 3:

Maak een dimmer waarbij de potentiometer de LED regelt. Plaats ook hier een weerstand in serie met potentiometer.

Oefeningen basis 4:

Voeg een schakelaar toe aan vorige schakeling en pas het programma aan zodat de gedimde led ook in- en uitgeschakeld kan worden.

Oefeningen basis 5:

Gebruik een LDR is serie met een weerstand om een lichtmeting te doen, en laat de led meer oplichten naarmate het donkerder wordt.

Oefeningen basis 6:

Maak een nachtlamp, die een LED zal inschakelen zodra het donker(der) wordt, maar na een minuut de LED terug zal uitschakelen.

Oefeningen gevorderd 1:

Gebruik de TMP36GT9Z om de temperatuur uit te lezen, en stuur deze naar de PC.
Gebruik de RGB-LED om een toestand aan te duiden:

  • Rood: temperatuur is te hoog (>30°C)
  • Groen:temperauur is OK
  • Blauw:temperatuur is te laag (<25°C)

Oefeningen gevorderd 2:

Maak de temperatuur zichtbaar op het dual 7-segment display.