Les 2: IO Operaties

Basis IO Operaties

  • pinMode
  • DigitalRead
  • DigitalWrite
  • analogRead
  • analogWrite

Programma Structuur


#include "myLib.h"

#define RSTBTN = 3

int POTPIN = A0
int BTNPIN = 5

void setup() {
pinMode(LED_BUILTIN, OUTPUT); 
pinMode(POTPIN, INPUT);
pinMode(BTNPIN, INPUT_PULLUP);

void loop() {
  //doSomething
}
    
  • Top level
    • Libraries
    • Variabelen
    • Globale scope
  • Setup
    • Run once
  • Loop
    • Always Running

PinMode


void setup() {
pinMode(LED_BUILTIN, OUTPUT); 
pinMode(POTPIN, INPUT);
pinMode(BTNPIN, INPUT_PULLUP);

void loop() {
  //doSomething
}
    
  • Een pin kan 3 states aannemen
    • OUTPUT: schrijven naar de pin
    • INPUT: lezen van de pin
    • INPUT_PULLUP: INPUT + voorgeschakelde weerstand
  • Dezelfde functie voor de analoge en digitale pinnen
  • Meer info: klik hier

DigitalWrite


void setup() {
pinMode(LED_BUILTIN, OUTPUT);


void loop() {
  digitalWrite(LED_BUILTIN, HIGH);
  delay(1000);
  digitalWrite(LED_BUILTIN, LOW);
  delay(1000);
}
    
  • Schrijven van constante waarde
    • Hoog (5V)
    • Laag (0V)

Gebruik van digitalwrite

Aansturen van een led

Mosfet als schakelaar

Aansturen LCD

DigitalRead


void setup() {
  pinMode(pushButton, INPUT);
  pinMode(LED_BUILTIN, OUTPUT);
}

void loop() {
  // read the input pin:
  int buttonState = digitalRead(pushButton);
  digitalWrite(LED_BUILTIN, buttonState);
}
    
  • Uitlezen van een pin
  • Specifieke treshold (TLL niveaus) voor de omzetting naar een constante waarde
    • High (1)
    • Low (0)

Gebruik van digitalread

Uitlezen van een button

AnalogWrite


void setup() {
  pinMode(ledPin, OUTPUT);
}

void loop() {
  for (int fadeValue = 0 ; fadeValue <= 255; fadeValue += 5) {
    analogWrite(ledPin, fadeValue);
    delay(30);
  }

  for (int fadeValue = 255 ; fadeValue >= 0; fadeValue -= 5) {
    analogWrite(ledPin, fadeValue);
    delay(30);
  }
}
    
  • Schrijven van een voltage naar een pin
    • max 255 - 5V
    • min 0 - 0V
  • PWM
  • Meer info: klik hier

Gebruik van analogwrite

Aansturen van een led

Mosfet als schakelaar

AnalogRead


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

void loop() {
  int sensorValue = analogRead(A0);
  Serial.println(sensorValue);
  delay(1); 
}
    
  • Uitlezen van een voltage signaal
    • max 1023 - 5V
    • min 0 - 0V
  • PWM

Gebruik van analogread

Uitlezen van potentiometer

Uitlezen van IR Sensor

Analogread met AnalogWrite Combineren


int potPin = A0
int ledPin = 6

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

void loop() {
  int sensorValue = map(analogRead(potPin), 0, 1024, 0, 255);
  Serial.println(sensorValue);
  digitalWrite(ledPin,sensorValue)
  delay(500); 
}
    

Analog vs Digital

  • Digital = True or False
  • Analog = een waarde tussen 0 of 5
  • Analog vs Digital is een concept van Arduino
  • De ATmega bezit alleen een ADC geen DAC

Verdergaan met Digitale Operaties

  • Hoog signaal (5V)
  • Laag signaal (0V)
  • TTL levels
  • Richting
    • Output (Currrent Sourcen)
    • Input (Current Sinken)

Hoeveel waarden kan een digitale input aannemen?

3

High (5V)

Low (0V)

Floating (?)

Hoe komt dit?

Ruis op het systeem

Capacitieve koppeling

Oplossing

Intern

Extern

Hoe kom dit?

Hoe kom dit?

Generiek Diagram GPIO (Niet simpel een draadje aansluiten)

Tri State Logica

A B C
0 1 0
1 1 1
X 0 Z

  • pinMode = INPUT
  • Pin is dan hoog impedant
  • Pin kan dan zweven(Waardes zijn random)

Floating Pin Waardes Vermijden

  • Extern
    • Pull Up Weerstand
    • Pull Down Weerstand
  • Intern
    • Pull Up Weerstand

Extern

  • Pull Up:
    • constant HIGH signaal
    • constant stroom verbruik
  • Pull Down:
    • constant LOW signaal
    • geen stroom verbruik
  • Keuze afhankelijk van je input
  • Voor een simpele push button kan beide

Pull Up Resistor

Pull Down Resistor

Weerstand keuze

  • Input = Current Sinken
  • Stroom wordt in de MCU gestuurd
  • Geen weerstand = Problemen
  • Max Sink Current / Pin = 20mA
  • Veilige keuze weerstand: 10kΩ
  • R = U/I => I=U/R => 5V/10kΩ=0.5mA

Intern

  • Interne Pull Up weerstand
  • Waarde 20kΩ - 50kΩ
  • Goed genoeg voor een pushbutton

        void setup()
        {
          pinMode(pinNumber, INPUT_PULLUP);
        };
    

Digitale Output

  • Geen Tri State logica
  • High of Low signaal
  • Output = Current Sourcen
  • max Current = 40mA
  • max Current alle IOs = 200mA
  • Stuur je iets aan, minimale hoeveelheid stroom aanleveren

Verder gaan met Analoge Operaties

  • Digitaal / Analoge Conversie
  • Analoge Comperator
  • Analoog / Digitale Conversie

Er zijn verschillende analoge operaties maar voor de moment is alleen ADC operatie belangrijk.

Analoge Digitale Conversie (ADC)

  • AnalogRead is een A/D conversie
  • Eigenschappen ADC
  • Resolutie
    • `2^(#Bits ADC)`
    • `1024`
    • Range
      • `0 - 2^(#Bits ADC -1)`
      • `0 - 1023`
    • Accuracy
      • `V_(ref) / (Resolutie)`
      • `(5V) / 1024 ≈ 4,9mV`
  • `analogRead = (V_(IN) * Resolutie)/V_(ref)`

Oefening ADC

Los op voor een 12bits ADC

Geef de volgende eigenschappen

  • Resolutie
  • Range
  • Accuracy
  • Wat is de return waarde van analogRead als we een voltage uitlezen van 1.36v met een referentie voltage van 3,3v?

analogWrite is een oplichter

analogWrite is an analog result with digital means

analogWrite genereert een blokgolf waarbij we de dutycycle manipuleren

Pulse Width Modulation

  • Duty Cycle aanpassen - Pulse Width Modulation (PWM)
  • Het aanroepen van de analogwrite functie genereert een blokgolf van 500Hz
  • De eerste parameter van analogwrite bepaalt de pin
  • De tweede parameter van analogwrite bepaalt de dutycycle
  • Analogwrite slaagt per pin de tweede parameter op in één geheugen locatie
  • Wat is dan de maximale waarde voor de PWM configuratie?
    • 255
    • 8bit Microcontroller

  • Wat is dan maximale nauwkeurigheid voor de dutycycle
    • 100%/255 = 0.39%

PWM Meten

Scope vs Multimeter

Groen - Scope

Rood - Multimeter

PWM Voorbeeld - Fading


      int ledPin = 9;    // LED connected to digital pin 9

      void setup() {
      } 

      void loop() {
        for (int fadeValue = 0 ; fadeValue <= 255; fadeValue += 5) {
             analogWrite(ledPin, fadeValue);
             delay(30);
             }

             for (int fadeValue = 255 ; fadeValue >= 0; fadeValue -= 5) {
          analogWrite(ledPin, fadeValue);
          delay(30);
        }
      }
  

Timers

  • Arduino claimt de timers van de mcu
  • Arduino biedt geen directe acces aan de timers van de mcu
  • Arduino exposed de timers dmv:
    • delay()
    • delayMicros()
    • millis()
    • micros()

  • Blocking vs Non - Blocking

Delay

  • delay(int ms)
  • delayMicros(int µs)

Millis

  • millis()
    • Tijd sinds het opstarten van de mcu
    • Return de tijd in milliseconden
    • Overflow na 50 dagen
    • Referentie
  • micros()
    • ≈ millis()
    • Tijd sinds het opstarten van de mcu
    • Return de tijd in microseconden
    • Referentie

Blocking vs Non - Blocking

Blocking


         const int ledPin =  13; 
         int ledState = LOW;    
         const long interval = 1000;    
      
         void setup() {
           pinMode(ledPin, OUTPUT);
         }
      
         void loop() {
           delay(interval)
           ledstate = !ledstate
           digitalWrite(ledPin, ledState);
         }
      

Non - Blocking


         const int ledPin =  13; 
         int ledState = LOW;    
      
         long previousMillis = 0;
      
         const long interval = 1000;    
      
         void setup() {
           pinMode(ledPin, OUTPUT);
         }
      
         void loop() {
           unsigned long currentMillis = millis();
      
           if (currentMillis > interval + previousMillis ) {
             previousMillis = currentMillis;
             ledstate = !ledstate
             digitalWrite(ledPin, ledState);
           }
         }
      
      

Interrupts

  • Reactie op een event
  • Non - Blocking
  • Interrupt Types
    • Hardware
    • Software (Vereist OS)
  • Interrupt bron
    • Extern
      • Meestal verandering op een pin
      • Pin State Change
      • Seriële communicatie
    • Intern
      • A/D Conversie voltooid
      • Timer afgelopen

Interrupts

  1. Onderbreking huidig processor activiteit
  2. Interne of Externe trigger
  3. Interrupt Service Routine(ISR)
    • Na trigger springt de code naar de ISR
    • ISR een koppeling van event naar een functie

  4. Na de ISR springt de code terug

Interrupts

Wat is de tegenpool van interrupts?

Polling vs. Interrupts

Polling Interrupts
Synchroon Asynchroon
Niet dringend Dringend
Frequent Sporadisch

Polling vs Interrupts

Interrupts & Arduino

  • Interrupts zitten verwerkt in de beschikbare libraries
  • Meest toegankelijke: External Interrupts
    • Interrupts gebaseerd op Inputs
    • Pin specifiek
  • Instellen van van een External Interrupt
  • Interrupt Service Routine(ISR)
    • Good Pratices
    • delay() werkt niet in een ISR

Interrupts & Arduino: Pins

BoardDigital Pins Usable For Interrupts
Uno, Nano, Mini, other 328-based2, 3
Mega, Mega2560, MegaADK2, 3, 18, 19, 20, 21
Micro, Leonardo, other 32u4-based0, 1, 2, 3, 7
Zeroall digital pins, except 4
MKR10000, 1, 4, 5, 6, 7, 8, 9, A1, A2
Dueall digital pins
101all digital pins

Instellen van van een External Interrupt


interrupts()
//Staat standaard aan
//Gebruikt na het uitzetten van interrupts
noInterrupts()
//Uitzetten van interrupts
//Kan nodig zijn bij tijd cruciale acties
attachInterrupt(digitalPinToInterrupt(pin), ISR, mode)
//digitalPinToInterrupt(pin) - mappen van Arduino Pin naar ATmega328p
//ISR - Naam van de functie die wordt aangeroepen als de interrupt optreedt.
//mode - Het soort event waarop de interrupt gaat triggeren
//mode - LOW, CHANGE, RISING, FALLING 
detachInterrupt(digitalPinToInterrupt(pin));
//ontkoppelen van de interrupt
  

Volatile Keyword


        volatile int ButtonState = 0;
  
  • Actie voor de compiler
  • Plaats de variable in het ram geheugen ipv een register
  • Nodig als je een variable aanpast in een interrupt

Voorbeeld interrupts


volatile int state = 0;

void ext_int_callback(){
  state != state
};

void setup() {
  Serial.begin(9600);
  pinMode(LED_BUILTIN, OUTPUT);
  attachInterrupt(digitalPinToInterrupt(2), ext_int_callback, FAILING);
}

void loop() {
  digitalWrite(LED_BUILTIN, state); 
}
    

ISR: Best Practices

  • Hou de ISR zo kort mogelijk
  • Gebruik flags
    • Zet een variabel in de ISR
    • Bepaal de volgende actie gebaseerd op die variabele in de main loop

volatile int state = 0;

void ext_int_callback(){
  state != state
};

void setup() {
  Serial.begin(9600);
  pinMode(LED_BUILTIN, OUTPUT);
  attachInterrupt(digitalPinToInterrupt(2), ext_int_callback, FAILING);
}

void loop() {
  digitalWrite(LED_BUILTIN, state); 
}
      

Bron

ISR: Best Practices

  • Maak gebruik van state machines
    • Defineer een state
    • vermijd if/else als beslissingsstructuur groter is dan twee mogelijkheden

  • Voorkeur gaat naar flags
  • Soms moet de ISR een actie direct uitvoeren voor tijdwinst

const int PERIOD_10ms = 0x01
const int PERIOD_14ms = 0x02
const int PERIOD_19ms = 0x03
volatile int state = 0;

void ext_int_callback(){
 switch(state)
 {
    case PERIOD_10ms:
    {
       // Toggle pin;
       // Timer Stop;
       // Change period to 14ms;
       // Timer Start;
       break;
    }
    case PERIOD_14ms:
    {
       // Toggle pin;
       // Timer Stop;
       // Change period to 19ms;
       // Timer Start;
       break;
    }
    case PERIOD_19ms:
    {
       // Toggle pin;
       // Timer Stop;
       // Change period to 10ms;
       // Timer Start;
       break;
    }
    default:
    {
       /* Timer_ISR entered undefined state */
       // Make default period 10ms
       break;
    }
 }
};

void setup() {
  Serial.begin(9600);
  pinMode(LED_BUILTIN, OUTPUT);
  attachInterrupt(digitalPinToInterrupt(2), ext_int_callback, FAILING);
}

void loop() {
  digitalWrite(LED_BUILTIN, state); 
}
      

Bron

ISR: Best Practices

Global variables – Know when it’s modified

Global variables need to be carefully handled while used with ISRs, because interrupts are generally asynchronous and if a global variable is being written into by an ISR, it can get modified at any time. We need to be careful of the following aspects:

Reading/Writing Global Variables at multiple places

Global variables should be modified at only a few necessary places inside a program. If a global variable is being modified by multiple threads (i.e., the main process, ISRs, and other hardware functions like DMA inside an MCU), there is a chance of the variable getting corrupted.

Reading a global variable at multiple instances

inside a main process is as worrisome as its modification in different threads. Consider the following

Debouncing a Button

Het probleem?

Oplossing

  • Hardware
    • Sequentiële Logica
    • RC Circuit
  • Software

Startpunt

Voor zowel de hard -en software vertrekken we van een ...

Pull Up Resistor

nn

Pull Down Resistor

Hardware: Sequentiële Logica

NAND Poort Oplossing

NOR Poort Oplossing

Bulky oplossing krijgt geen voorkeur

Hardware: RC Debouncer

RC Debounce

Wat gaat er gebeuren met het ingangssignaal?

RC Charging Circuit

RC Charging Circuit

  • Tijd nodig om te laden
  • Tijd nodig om te ontladen
  • Ongevoelig voor snelle veranderingen
    • Filtert de bounce weg
  • Hardwarematige delay

RC Charging Circuit

  • `tau -= R * C`
    • Eenheid τ seconden
  • `V_(C) = V_(S)*(1 - e^(-t/(RC)))`
    • `V_(C)` Uitgangspanning condensator
      • `V_(PIN)`
    • `V_(S)` Ingangsspanning condensator
      • `V_(C C)`
      • 5V indien het een pulldown / up weerstand die gevoed is door de Arduino
  • Arduino TTL Levels
    • Logische Hoog vanaf 2,0V
Time Constant RC Value `% V_(S)``
`0 tau` `0*RC` `0 %`
`0.7 tau` `0.7*RC` `50 %`
`5 tau` `5*RC` `100 %`

Een goede delay?

Een delay tussen de 20 - 50 ms is een goede keuze
Selecteren van een goede condensator waarde
  • Rekening houden met TTL niveaus

Alle signaal problemen opgelost?

Zo goed als

Hysteris

Oplossing:Inverting Schmitt Trigger

Oplossing:Inverting Schmitt Trigger

Waarom de extra stap?

Met gebruik veranderen de mechanische eigenschappen van een knop

Software Oplossing

  • Basic (Blocking)
  • Arduino Example(Non - Blocking)

Basic


const int buttonPin = 2;  

int buttonState;             
int lastButtonState = LOW;   

long debounceDelay = 50;    
void setup() {
  pinMode(buttonPin, INPUT);
}

void loop() {
  int reading = digitalRead(buttonPin);

  if (reading != lastButtonState) {
    delay(debounceDelay)
    lastButtonState = reading;
  }
}
  

Arduino Debounce Example: Variables


const int buttonPin = 2;  
const int ledPin = 13;     

int ledState = HIGH;         
int buttonState;             
int lastButtonState = LOW;   

long lastDebounceTime = 0;  
long debounceDelay = 50;  
  

Arduino Debounce Example: Setup


void setup() {
  pinMode(buttonPin, INPUT);
  pinMode(ledPin, OUTPUT);
  digitalWrite(ledPin, ledState);
}
  

Arduino Debounce Example: Loop


void loop() {
  int reading = digitalRead(buttonPin);

  if (reading != lastButtonState) {
    lastDebounceTime = millis();
  }

  if ((millis() - lastDebounceTime) > debounceDelay) {

    if (reading != buttonState) {
      buttonState = reading;
      if (buttonState == HIGH) {
        ledState = !ledState;
      }
    }
  }

  digitalWrite(ledPin, ledState);

  lastButtonState = reading;
}
  

Oefening: Whack - a - Mole

  • Laat de leds afwisselend branden
    • De leds branden sequentieel afzonderlijk.
    • De snelheid van de sequentie is aanpasbaar.

  • Een button simuleert de hamer van Whack-a-Mole.
    • Als led #3 brand moet je met de hamer slaan
    • De button is interrupt gestuurd

  • Er is een uitbreiding voor het spel waarin 2-player functionaliteit introduceren. De 2de speler bedient een knop die de volgende functionaliteit heeft.
    • Bij het indrukken van de knop veranderd de richting van de sequentie.
    • Je bouwt een non-blocking delay in op deze drukknop.
    • Bij elke druk op deze knop verhoogt de ingebouwde delay.
    • De delay reset als speler mist bij het slaan van de hamer