Hoofdstuk 6 Teensy

6.1 Wat is een Teensy?

Een Teensy is een microcontroller. Met een microcontroller kan je analoge signalen (voltage ten opzichte van een nulpunt) omzetten naar digitale waarden en andersom. Zo kun je bijvoorbeeld potmeters, infrarood-sensors en temperatuursensoren als input gebruiken en die waarden via zo’n Teensy uitlezen in je computer. Aan de andere kant kan je lichten en motoren aansturen vanuit je computer.

Een Teensy is vergelijkbaar met een Arduino, maar heeft een aantal pluspunten: In vergelijking met de Arduino UNO, de populairste Arduino, heeft de Teensy meer aansluitmogelijkheden, meer rekenkracht en heeft het de mogelijkheid om simpele audiobewerkingen te doen, en dat voor dezelfde prijs.

6.2 Hoe programmeer je een Teensy?

De software die op een Teensy draait wordt geprogrammeerd in C. Je zult veel overeenkomsten zien met Javascript. Om de code te schrijven en te uploaden naar de Teensy heb je twee stuks software nodig. De eerste is de Arduino IDE. Omdat de Teensy qua werking erg op een Arduino lijkt kan deze in dezelfde taal als Arduino’s geprogrammeerd worden. Om dit mogelijk te maken is er wel een extra stuk software nodig: Teensyduino.

6.2.1 Installatie

  1. Je begint met het downloaden van de Arduino software. Deze kun je vinden op www.arduino.cc. Onder het kopje ‘Download The Arduino IDE’ klik je vervolgens op de versie voor jouw computer.
  2. Je installeert de software door de aanwijzingen te volgen na het openen van het installatiebestand.
  3. Vervolgens open je de Arduino IDE voor de eerste keer en sluit deze weer af. Door het eenmalig te openen wordt een folder aangemaakt waar je zometeen de Teensy-software aan kunt toevoegen.
  4. Je kunt nu Teensyduino downloaden. Dit kun je vinden op www.pjrc.com
  5. Download het bestand voor jouw computer en volg de instructies op de pagina.

6.2.2 Gebruik

Als je na de complete installatie de Arduino IDE opstart krijg je het volgende scherm te zien:

De opbouw van de code is vergelijkbaar met een P5js-sketch. In de setup-functie wordt alle code uitgevoerd die eenmalig aan het begin moet draaien. In de loop-functie wordt de code uitgevoerd die continu achter elkaar moet worden uitgevoerd.

De knop links bovenin met de ✔ is bedoeld om de controleren of je code goed werkt. De knop ernaast is om je code naar de Teensy te sturen. Om dit te kunnen doen zal je in het menu het juiste apparaat moeten kiezen: Kies bij Tools onder het submenu boards voor Teensy 3.2/3.1 of Teensy 4.0, afhankelijk van welke Teensy je hebt. Vervolgens kun je de code uploaden. Er verschijnt een tweede window, van Teensyduino. Waar mogelijk staat dat je op de knop van de Teensy moet drukken om het programmeren te voltooien. Als er “Reboot OK” staat, dan is het programmeren gelukt.

6.2.3 Voorbeeldcode

Voor voorbeelden van code kijk je in het menu File → Examples. Of op de website van Arduino / Teensy.

6.3 Hoe sluit je iets aan op een Teensy?

De Teensy heeft aan elke zijkant veertien pinnen die allemaal een of meerdere functies hebben. Om een overzicht te krijgen van deze functies kun je onderstaande afbeelding gebruiken.

Zoals je ziet heeft bijna elke pin veel verschillende functies. De belangrijkste worden hieronder beschreven.

6.3.1 Digitale Pinnen

De getallen met de grijze achtergrond geven aan dat het digitale pinnen zijn. Deze zijn bi-directioneel. Je kunt hier dus bijvoorbeeld een knop op aansluiten en hem als input gebruiken. Je kunt in je programma aangeven of een pin als input of output werkt. Als de knop ingedrukt is en dus 3.3V aan spanning doorlaat, zal de uit te lezen waarde HIGH/1 zijn. Als de knop niet ingedrukt is de spanning gelijk aan 0V en is de uit te lezen waarde LOW/0. Als je een digitale pin als output gebruikt en er via een weerstand een LED op aansluit dan kan je deze LED aan laten gaan door HIGH naar de pin te sturen, en uit laten gaan door LOW naar de pin te sturen.

Om dingen te besturen die meer stroom trekken dan een LED (b.v. een motor) moet je in veel gevallen een schakeling met externe voeding en bijvoorbeeld een transistor gebruiken.

Let op: als je in de software een pin als output instelt kun je er beter geen spanning op zetten omdat je daarmee de Teensy kan beschadigen.

6.3.2 Analoge pinnen

De pinnen met de oranje achtergrond (A0-A9) zijn analoge inputs. Deze meten niet een binaire waarde, zoals de digitale, maar een continue waarde: een spanning ergens tussen 0 en 3.3V. Deze pinnen werken alleen als input. Als je op de juiste manier een potmeter verbindt met één van deze pinnen zal je als aan de potmeter draait een waarde kunnen lezen tussen de 0 en de 1023. Als de waarde 0 is en de potmeter dus helemaal dicht is staat er 0V op de pin. Is de waarde 1023, dan staat er 3.3V op de pin. Meer over hoe je de potmeter precies aansluit verderop in dit hoofdstuk.

6.3.3 PWM

Pulse Width Modulation is niet alleen een synthesetechniek, maar wordt ook gebruikt om een analoog signaal te simuleren. Door de pulsbreedte te veranderen lijkt het alsof de spanning op een van deze uitgangen (met de roze achtergrond op de afbeelding hierboven) verandert. Hiermee kan je bijvoorbeeld een LED in- en uit laten faden door een waarde tussen de 0 en de 1023 de sturen naar zo’n pin.

6.3.4 Voeding

De 3.3V-pin en de GND pin zijn belangrijk. Stroom gaat pas lopen als er een verbinding is met de GND. De Teensy meet vervolgens het spanningsverschil tussen de inkomende waarde en dit nulpunt, de GND. Als je bijvoorbeeld een LED wilt laten branden zal je deze moeten aansluiten tussen een digitale uitgang en de GND. Zorg er daarbij wel voor dat je er altijd een weerstand tussen plaatst, anders kan je de LED opblazen (dat klinkt spannender dan het is). Mocht je voor een bepaalde sensor (bijvoorbeeld een potmeter) voeding nodig hebben, dan kan je deze uit de 3.3V-pin halen.

Let op! De Teensy is gebouwd om om te kunnen gaan met een maximale spanning van 3.3V, kom je hier overheen dan heb je kans dat de Teensy het niet overleeft. Let dus goed op dat je alles op de juiste manier aansluit.

Voor meer informatie over werken met de Teensy kan je kijken op de websites www.pjrc.com, www.arduino.cc en vele tutorials op youtube en andere plekken op het internet.

6.4 Aansluitingen maken

Hieronder volgen een aantal voorbeelden van het aansluiten van bepaalde sensoren. Mocht je een specifieke sensor hebben die hieronder niet wordt beschreven, dan kan je via je favoriete zoekmachine naar + Arduino / Teensy zoeken. Dan krijg je talloze voorbeelden te zien.

6.4.1 Switch

//Inlezen drukknop
int inPin = 10; //de pin waarop de knop is aangesloten
int ledPin = 13; //pin waarop een LED is aangesloten (ingebouwde LED in dit geval)
bool pinState; //houd bij wat de status is van de pin
void setup() {
  //zet de pin op input en zet de pullup-weerstand aan
  pinMode(inPin,INPUT_PULLUP);
 
  //zet de ledPin op output
  pinMode(ledPin,OUTPUT);
}
 
void loop() {
  // put your main code here, to run repeatedly:
  int pinRead = digitalRead(inPin);
 
  //kijk of er verandering is in de staat van de pin (ingedrukt of niet)
  //alleen als de verandering plaatsvindt, wordt dit opgeslagen. 
  if (pinRead != pinState) { 
    pinState = pinRead;
 
    //vervolgens kun je met de waarde doen wat je wilt, bijvoorbeeld een LED aansturen.
    digitalWrite(ledPin,!pinState);
  } 
}

6.4.1.1 Over de pullup weerstand

In de code zie je dat er in de setup een pullup weerstand aangezet wordt. Deze weerstand zit ingebouwd in de Teensy en gaat van de +3.3V naar de desbetreffende pin. Dit zorgt ervoor dat als de knop niet ingedrukt is, de waarde 1 / HIGH is en als de knop wel ingedrukt is 0 / LOW. Op de plek waar de LED wordt aangezet staat er daarom dus ook een ! voor de pinState. Dat geeft aan dat de waarde gelijk is aan het omgekeerde van de pinState. Als de pinState laag is (knop is ingedrukt) gaat de LED aan, als de pinState hoog is (knop niet ingedrukt) gaat de LED uit

6.4.2 potmeter / analoge sensor

int sensorPin = A0; //pin waarop de sensor is aangesloten.
 
void setup() {
  //Start de seriële verbinding, zodat we straks de waarde van de sensor kunnen laten zien  
  Serial.begin(115200);
}
 
void loop() {
  delay(10); //laat de waarde iets minder vaak zien
 
  //Haal de waarde van de sensor op en sla deze op in de variabele *val*
  int val = analogRead(sensorPin);
 
  //Laat de waarde zien in de Serial Monitor (vergrootglasicoon rechtsboven / cdm/ctr+shift+m)
  Serial.print("Sensorwaarde: ");
  Serial.println(val); //println zorgt dat er een nieuwe regel wordt gemaakt na geprint te hebben
}

In het plaatje hierboven zien we hoe een potmeter moet worden aangesloten. Deze manier van aansluiten gaat op voor elke andere analoge sensor, zoals bijvoorbeeld een infrarood afstandmeter, een analoge thermometer, regensensor etc.

6.4.2.1 Spanningsdeler

De manier waarop de analoge sensor is aangesloten zorgt dat het een spanningsdeler wordt. De waarde die wordt uitgelezen vanuit de middelste pin wordt bepaald door de hoeveelheid weerstand die tussen de linkerpin en de middelste pin zit én tussen de rechterpin en de middelste pin.

6.4.3 LED

//pin waarop de led is aangesloten
int ledPin = 4;

void setup() {
  //zorg dat de ledPin in output mode staat:
  pinMode(ledPin,OUTPUT);
}

void loop() {
  //wacht elke iteratie van de loop 500ms voordat ie verder gaat.
  delay(500);

  //kies een willekeurige status voor de led, uit of aan
  int state = random(0,1);

  //Zorg dat de led in de staat komt die hierboven gekozen is,
  digitalWrite(ledPin,state);
}

6.5 Seriële communicatie

6.5.1 Van Teensy naar Max

Om met Max en/of Javascript te communiceren maakt de Teensy gebruik van het seriële protocol. Dit is dezelfde manier als waarom USB-apparaten met je computer communiceren. Via Seriële communicatie verstuur je een aantal waardes achterelkaar door naar de computer, of naar de Teensy. Deze waardes zijn maximaal 1 byte (8 bits) groot en kunnen dus niet groter zijn dan het getal 255.

Om grotere getallen dan 255 te kunnen versturen moet je deze opdelen in twee getallen. Dit doe je door het getal te delen door 256 en af te ronden én de modulo van het getal en 256 te nemen. Voorbeeld:

Je hebt een potmeter aangesloten die waardes tussen de 0 en de 1023 doorstuurt.
De potmeter staat vlak voor de helft en stuurt het getal 501 uit.

501 / 256 = 1
501 % 256 = 245
Als je deze twee getallen, 1 en 245, doorstuurt naar de computer kan je er daar weer het getal 501 van maken.

(1 * 256) + 245 = 501

Omdat de bytes die je wil versturen in een continue stroom verstuurd worden moet je op de één of andere manier identificeren welke bytes bij elkaar horen. Als je de potmeter dichtdraait krijg je de hele tijd twee getallen doorgestuurd:
[1 245 1 244 1 243 .... 1 3 1 2 1 1 0 255]
Op een gegeven moment weet je dan niet meer welk getal je als eerste getal moet zien en welke als tweede.

Om dit probleem op te lossen kan je gebruik maken van identifiers. Door de twee getallen te verpakken in een tweetal andere getallen kun je de berichten filteren en weet je precies welk twee getallen bij elkaar horen.

We nemen opnieuw het voorbeeld van het getal 501, wat opgedeeld is in 1 en 245.
door er een start en stopbyte voor te zetten kunnen we deze twee getallen als één pakket versturen.

[254 1 245 18]
Als we nu aan de potmeter draaien zal de stroom van berichten er alsvolgt uitzien:
[254 1 245 18]
[254 1 244 18]
[254 1 243 18]
[254 1 242 18]
[254 1 241 18]
etc.

De getallen 254 en 18 blijven dus hetzelfde en daarmee kunnen we in bijvoorbeeld Max het pakketje analyseren.

6.5.1.1 Voorbeeld Arduino-code

byte sendArray[4] = {254,0,0,18}; //lijst waarin je de data verstuurt
int potPin = A0; //pin waarop de sensor is aangesloten 

void setup() {
  // Deze code wordt eenmalig uitgevoerd, bij opstarten van de Teensy

  //Start de seriële communicatie, vul hier dezelfde baudrate is als in de Max-patch
  Serial.begin(115200); 
}

void loop() {
  //Deze code wordt herhaaldelijk uitgevoerd, net zo snel als dat de Teensy is.
  //Om dit enigszins te vertragen kan je een delay van 1ms toevoegen,
  //Dan wordt er minder vaak data doorgestuurd.
  delay(1);

  int val = analogRead(potPin); //lees de waarde van de sensor

  //Plaats de bewerkte waardes op de 2e en 3e positie in de lijst.
  //Deel waarde door 256, omdat ik met integers werk wordt het automatisch afgerond.
  sendArray[1] = val/256; 

  //Rest van de waarde. Te verkrijgen door de module van het getal en 256 te nemen.
  sendArray[2] = val % 256;  

  //Stuur de waardes door via de seriële verbinding. 
  //Geef hier de array aan en als tweede argument de lengte van de array.
  Serial.write(sendArray,4); 
 }

6.5.1.2 Voorbeeld Max-code

6.5.2 Van Max naar Teensy

De communicatie van Max naar een Teensy werkt volgens hetzelfde principe. Via Seriële communicatie in een pakketje van 4 bytes om te kunnen identificeren waar het pakketje naar toe moet.

6.5.2.1 Voorbeeld Max-code:

6.5.2.2 Voorbeeld Arduino-code:

byte receiveArray[4] = {0,0,0,0}; //lijst waarin je de data verstuurt
int ledPin = 13; //pin waarop de led is aangesloten
int result; //variabele waar het resultaat in wordt opgeslagen.
 
void setup() {
  // Deze code wordt eenmalig uitgevoerd, bij opstarten van de Teensy
 
  //Start de seriële communicatie, vul hier dezelfde baudrate is als in de Max-patch
  Serial.begin(115200); 
  pinMode(ledPin,OUTPUT);
}
 
void loop() {
  //Deze code wordt herhaaldelijk uitgevoerd, net zo snel als dat de Teensy is.
  //Om dit enigszins te vertragen kan je een delay van 1ms toevoegen,
  //Dan wordt er minder vaak data doorgestuurd.
  delay(1);
  memset(receiveArray,0,4); //zet alle waardes in de receiveArray op 0.
 
  if (Serial.available()) { //als er seriële data beschikbaar is, dan:  
    Serial.readBytes(receiveArray,4); //lees 4 bytes en stop ze in de receiveArray;
  }
 
  //als de eerste waarde van de array gelijk is aan 255 en de laatste aan 17:
  if (receiveArray[0] == 255 && receiveArray[3] == 17) {
    // vermenigvuldig de eerste waarde met 256 en tel daar de 2e bij op. 
    result = (receiveArray[1] * 256) + receiveArray[2];
  }
 
  //als de waarde groter is dan 255, dan gaat de led aan. 
  if (result > 255) {
    digitalWrite(ledPin,HIGH);
  }
  else {
    digitalWrite(ledPin,LOW);
  }
}