dimanche 21 septembre 2014

mardi 16 septembre 2014

Arduino : encodeur rotatif (KY040)

Je vous propose de voir une première utilisation simple d'un encodeur rotatif : le KY040 avec un arduino UNO.



Un exemple courant d'utilisation est le bouton d'un autoradio qui permet le réglage du volume mais aussi d'allumer et d'éteindre la radio. Il ressemble beaucoup à un potentiomètre mais contrairement à lui il n'est pas limité dans ça rotation et envoie un signal à chaque "crans". Il y a 30 crans par tour et l'on est capable de déterminer le sens de rotation de l'encodeur. Pour cela, l'encodeur nous envoie 2 signaux (on parlera du signal A et B) comme suit :


Source : Arduino UNO Tutorial 6 - Rotary Encoder
Pour faire simple, lorsque l'on est sur un cran, A et B ont le même niveau logique (0 ou 1). Si on tourne dans le sens horaire, on reçoit le changement d'état de A avant B et si on tourne dans le sens contraire on reçoit B avant A.

Mise en place du hardware

Pour "capturer" la rotation nous utiliserons les "interruptions" disponibles sur les entrées 2 et 3 de l'arduino. L'Uno ne disposant que de 2 entrées avec gestion des interruptions, le switch sera géré dans la fonction "loop".

Au niveau hardware, rien de compliqué :
  • DT   --> pin 2
  • CLK --> pin 3
  • SW  --> pin 4
Nous utiliserons l'écran LCD pour afficher le compteur ainsi que l'état des 3 entrées :
  • rs (LCD pin 4) --> Arduino pin 12
  • enable (LCD pin 6) --> Arduino pin 10
  • LCD D4 --> Arduino pin 8
  • LCD D5 --> Arduino pin 7
  • LCD D6 --> Arduino pin 6
  • LCD D7 --> Arduino pin 5

Le programme correspondant

On utiliser un "unsigned int" pour stocker un compteur que l'on incrémente ou décrémente suivant le sens de rotation de l'encodeur. Un appuis dessus remettra à 0 ce compteur.

De part l'utilisation d'un "unsigned int", ce compteur est forcement compris entre 0 et 65535.

Dernier point important, ce type de bouton génère des rebonds aux niveaux des entrées de l'arduino. Il faut donc un système d'anti-rebond. il existe plusieurs possibilités, soit hardware en utilisant par exemple des condensateurs (0.1µF devrait être bon), soit logique via un peu de code. C'est cette dernière solution que j'ai utilisé.

 

include <liquidcrystal.h>

LiquidCrystal lcd(12, 11, 10, 8, 7,6,5);

// définition des pin pour le KY040
enum PinAssignments {
  encoderPinA = 2,   // right (DT)
  encoderPinB = 3,   // left (CLK)
  clearButton = 4    // switch (SW)
};

volatile unsigned int encoderPos = 0;  // un compteur
unsigned int lastReportedPos = 1;   // gestion du changement
static boolean rotating=false;      // gestion de l'anti-rebonds

// variable pour les routines d'interruption
boolean A_set = false;             
boolean B_set = false;
boolean A_change = false;
boolean B_change= false;

void setup() {
  lcd.begin(20,4);
  lcd.clear();

  pinMode(encoderPinA, INPUT_PULLUP); // utilisation du pullup
  pinMode(encoderPinB, INPUT_PULLUP); // utilisation du pullup
  pinMode(clearButton, INPUT_PULLUP); // utilisation du pullup
  // activation de l'interruption 0 (pin 2)
  attachInterrupt(0, doEncoderA, CHANGE);
  // activation de l'interruption 1 (pin 3)
  attachInterrupt(1, doEncoderB, CHANGE);
}

void loop(){
  if (lastReportedPos != encoderPos) {
    lcd.clear();
    lcd.setCursor(0,0);
    lcd.print("Index: ");
    lcd.print(encoderPos, DEC);
    lastReportedPos = encoderPos;
    lcd.setCursor(0,1);
    lcd.print(digitalRead(encoderPinA));
    lcd.print(digitalRead(encoderPinB));
    lcd.print(digitalRead(clearButton));
  }
    lcd.setCursor(0,1);
    lcd.print(digitalRead(encoderPinA));
    lcd.print(digitalRead(encoderPinB));
    lcd.print(digitalRead(clearButton));
   
  if (digitalRead(clearButton) == LOW )  {
    encoderPos = 0;
    A_change = false;
    B_change= false;
    lcd.print(encoderPos);
  }

  delay (100);
}

// Interruption sur changement d'état de A
void doEncoderA(){
  // debounce
  if ( rotating ) delay (1);  // attendre un petit peut
  rotating = true; //activation de l'anti-rebond
  // Confirmation du changement
  if( digitalRead(encoderPinA) != A_set ) {
    A_set = !A_set;

    if (B_change) {
      encoderPos += 1;
      B_change = false;
    } else
      A_change = true;

    rotating = false;  //libération de l'anti-rebond
  }
}

// Interruption sur changement d'etat de B
void doEncoderB(){
  if ( rotating ) delay (1);
  rotating = true;
  if( digitalRead(encoderPinB) != B_set ) {
    B_set = !B_set;

    if (A_change) {
      encoderPos -= 1;
      A_change = false;
    } else
      B_change = true;

    rotating = false;
  }
}


Source : ArduinoArduino UNO Tutorial 6 - Rotary EncoderUsing a Rotary Encoder with the Arduino

vendredi 8 août 2014

Arduino : Afficher la date et l'heure sur un LCD

Pour afficher l'heure et la date et surtout ne pas perdre ces informations si l'arduino UNO n'est plus alimenté, on a besoin d'un module RTC à base de DS1307 (datasheets). On en trouve facilement sur internet à des prix très bas.


Ce module embarque, en plus du composant DS1307, une pile qui permet de sauvegarder l'heure. Cette pile (CR2032) à une durée de vie de plusieurs années.

Pour utiliser ce module on va avoir besoin d'une librairie non fournie avec l'IDE Arduino. Celle-ci peut être téléchargée ici (il suffit de faire "Download Zip" et de décompressé l'archive directement dans le répertoire librairies de l'IDE).

Cette librairie propose un exemple ("ds1307") permettant de mettre à jour le module avec l'heure de votre ordinateur (attention : l'heure utilisée est UTC). Pour cela, il suffit de décommenter la ligne "RTC.adjust(DateTime(__DATE__, __TIME__));".

Tout d'abord le branchement

Le branchement est relativement simple. On se base sur le montage du LCD vu précédemment.
Le module RTC DS1307 ce branche comme suit:

  • Gnd --> GND
  • Vcc --> 5 V
  • Sda --> analog pin A4
  • Scl --> analog pin A5

Le programme correspondant

/************************************************************
Horloge Arduino
Horloge simple avec un Arduino Duo, un module RTC DS1307
et un afficheur LCD 20x4.

Branchements du RTC DS1307:
Gnd --> GND
Vcc --> 5 V
Sda --> analog pin A4
Scl --> analog pin A5

Branchements de l'afficheur LCD:
rs (LCD pin 4) --> Arduino pin 12
enable (LCD pin 6) --> Arduino pin 10
LCD D4 --> Arduino pin 5
LCD D5 --> Arduino pin 4
LCD D6 --> Arduino pin 3
LCD D7 --> Arduino pin 2

***************************************************************/

#include <liquidcrystal.h>
#include <wire.h>
#include <rtclib.h>

LiquidCrystal lcd(12, 11, 10, 5, 4,3,2);
RTC_DS1307 rtc;

void setup() {
    lcd.begin(20,4);
    lcd.clear();

    Wire.begin();
    rtc.begin();
}

void loop(){
    DateTime now = rtc.now();

    lcd.setCursor(0,0);
    lcd.print(now.year());
    lcd.print("/");
    if (now.month()<10) lcd.print="0";
    lcd.print(now.month());
    lcd.print("/");
    if (now.day()<10) lcd.print="0";
    lcd.print(now.day());
    lcd.print(" ");
    if (now.hour()<10) lcd.print="0";
    lcd.print(now.hour());
    lcd.print(":");
    if (now.minute()<10) lcd.print="0";
    lcd.print(now.minute());
    lcd.print(":");
    if (now.second()<10) lcd.print="0";
    lcd.print(now.second());

    delay(900);
}

Source : Arduino, Librairie RTC, Datasheet du DS1307

samedi 5 avril 2014

Arduino: 1er pas avec un LCD

Voila un premier programme qui permet l'utilisation d'un écran LCD 20x4 (20 caractères sur 4 lignes).
Cette écran sera très utile par la suite pour afficher des informations lors d'exécution de programme.

Tout d'abord le branchement

Dans ce premier programme, nous brancherons l'écran LCD directement sur l'Arduino UNO. Nous verrons plus tard qu'il est possible d'utiliser un module I2C pour libérer les ports de l'Arduino.


Le programme correspondant

#include <liquidcrystal.h>

// Connections:
// rs (LCD pin 4) to Arduino pin 12
// enable (LCD pin 6) to Arduino pin 10
// LCD pins d4, d5, d6, d7 to Arduino pins 5, 4, 3, 2
LiquidCrystal lcd(12, 11, 10, 5, 4, 3, 2);

void setup()
{
  lcd.begin(20,4);           // Initialisation du lcd : 20 columns, 4 rows.
  lcd.clear();                   // Effacer le LCD
  lcd.setCursor(0,0);      // Positionner le curseur sur le 1er caractere de la 1er ligne
  lcd.print("Hello, World"); // Ecrire
  lcd.setCursor(0,1);     // Positionner le curseur sur le 1er caractere de la 2eme ligne
  lcd.print("Row 2");
  lcd.setCursor(0,2);     // Positionner le curseur sur le 1er caractere de la 3eme ligne
  lcd.print("Row 3");
  lcd.setCursor(0,3);     // Positionner le curseur sur le 1er caractere de la 4eme ligne
  lcd.print("Row 4");
}

void loop()
{
}

Source : Arduino