Skyduino:~#
Articles
arduino, programmation, test

[Test] Rotary encoder LED Ring (Mayhew Labs)

Salut à tous !

Aujourd’hui je vais vous parler du « Rotary encoder LED Ring » de Mayhew Labs.

La « Rotary encoder LED Ring » a pas mal de petit truc sympa, comme :
– un emplacement pour un encodeur rotatif
– un controleur de led TLC5925 (16 canaux)
– 16 led (format cms)

Alors le truc bête selon moi c’est qu’il ne fournisse pas un encodeur rotatif avec la board, ni même un petit capuchon en plastique m’enfin bon on peut pas tout avoir !

Sinon pas grand chose à dire, c’est une breakout faite pour ceux qui veulent faire une retour visuelle sur leur encodeur rien de plus.

Au niveau du câblage j’utilise celui du code d’exemple :

GND -> GND
VCC -> VCC
SDI -> D2
CLK -> D3
LE -> D4
OE -> GND
ENC_A -> D8
ENC_B -> D9
ENC_SW -> D10

L’exemple est un peu bizarre je trouve, il utilise shiftOut à la place du SPI hardware m’enfin chacun ses gout !

Pour l’exemple j’ai pris le pde fourni par Mayhew Labs, c’est un exemple qui affiche divers effet lumineux en fonction de la position de l’encodeur et de ce qui est envoyé sur le port série.

/*
          Rotary_Encoder_LED_Ring_Example
          www.mayhewlabs.com/products/rotary-encoder-led-ring 
          Copyright (c) 2011 Mayhew Labs.
          Written by Mark Mayhew
          
This example shows 3 sequences that are possible on the ring of LEDs around the encoder based on rotation of an encoder.  The 3 sequences are 
selected by entering 1, 2, or 3 in the serial command prompt.  The serial window shows the current rotary encoder count.  As the encoder is turned, 
the serial display shows a raw count of the rotary encoder's value and the LEDs show a scaled version of the value.  If the button on the rotary 
encoder is pushed, the bottom LED will come on.  Each section of code below discusses the process required to do this. 

A note on setting the output sequence:
Think of each LED as a single bit in a 16-bit long binary string.  If a bit is 1, the LED is on, if a bit is 0, the LED is off.  
By making a string of ones and zeros, we choose which LEDs to have on and off, and then send this string to the shift register to display it.
For example 1000000000000001 binary (0x8001 in hex) will have the fist and last LEDs on, the rest off.  

CREDIT:
Reading the rotary encoder is performed with Oleg's example code:a
http://www.circuitsathome.com/mcu/reading-rotary-encoder-on-arduino
*/

//These are the pins that will talk to the shift register through SPI
#define SDI    2    //Data
#define CLK    3    //Clock
#define LE     4    //Latch

//These are the rotary encoder pins A, B, and switch
#define ENC_A    8
#define ENC_B    9
#define ENC_SW   10
#define ENC_PORT PINB  //The port that the rotary encoder is on (see http://www.arduino.cc/en/Reference/PortManipulation)

// Global variables
int scaledCounter = 0;  //The LED output is based on a scaled veryson of the rotary encoder counter
int sequenceNumber=0;   //The output sequence for the LEDs
int incomingByte = 0;   //Serial input to select LED output sequence


/*This is a 2 dimensional array with 3 LED sequences.  The outer array is the sequence; 
  the inner arrays are the values to output at each step of each sequence.  The output values
  are 16 bit hex values (hex math is actually easier here!).  An LED will be on if its 
  corresponding binary bit is a one, for example: 0x7 = 0000000000000111 and the first 3 LEDs 
  will be on.
  
  The data type must be 'unsigned int' if the sequence uses the bottom LED since it's value is 0x8000 (out of range for signed int).
*/
unsigned int sequence[3][16] = {{0x0,0x1,0x2,0x4,0x8,0x10,0x20,0x40,0x80,0x100,0x200,0x400,0x800,0x1000,0x2000,0x4000},
                                {0x0,0x1,0x3,0x7,0xf,0x1f,0x3f,0x7f,0xff,0x1ff,0x3ff,0x7ff,0xfff,0x1fff,0x3fff,0x7fff},
                                {0x0,0x7fff,0x3ffe,0x1ffc,0xff8,0x7f0,0x3e0,0x1c0,0x80,0x1c0,0x3e0,0x7f0,0xff8,0x1ffC,0x3ffe,0x7fff},
                               };

void setup()
{
  //Set SPI pins to output
  pinMode(SDI, OUTPUT);
  pinMode(CLK, OUTPUT);
  pinMode(LE,OUTPUT);
  //Set encoder pins to input, turn internal pull-ups on
  pinMode(ENC_A, INPUT);
  digitalWrite(ENC_A, HIGH);
  pinMode(ENC_B, INPUT);
  digitalWrite(ENC_B, HIGH);
  pinMode(ENC_SW, INPUT);
  digitalWrite(ENC_SW, HIGH);
  //Set serial rate, prompt for desired sequence
  Serial.begin(115200);
  Serial.println("Enter 1, 2, or 3 to change the LED sequence");
}


void loop()
{ 
  //Local Variables
  static uint8_t counter = 0;      //this variable will be changed by encoder input
  int8_t tmpdata;
  
  //Get any serial input
  if (Serial.available() > 0) 
  {
    incomingByte = Serial.read();
  }
  
  //if the serial input is valid, set the LED output sequence appropriately 
  if (incomingByte == '1')
    sequenceNumber=0;
  if (incomingByte == '2')
    sequenceNumber=1;
  if (incomingByte == '3')
    sequenceNumber=2;
    
  //Call read_encoder() function    
  tmpdata = read_encoder();
  
  //if the encoder has moved
  if(tmpdata) 
    {
      //Print out the counter value
      Serial.print("Counter value: ");
      Serial.println(counter, DEC);
      //Set the new counter value of the encoder
      counter += tmpdata;      
      
      //Scale the counter value for referencing the LED sequence
      //***NOTE: Change the map() function to suit the limits of your rotary encoder application.
      //         The first two numbers are the lower, upper limit of the rotary encoder, the 
      //         second two numbers 0 and 14 are limits of LED sequence arrays.  This is done
      //         so that the LEDs can use a different scaling than the encoder value. 
      scaledCounter = map(counter,0,100,0,15);
      
      //Send the LED output to the shift register 
      digitalWrite(LE,LOW);
      shiftOut(SDI,CLK,MSBFIRST,(sequence[sequenceNumber][scaledCounter] >> 8));    //High byte first
      shiftOut(SDI,CLK,MSBFIRST,sequence[sequenceNumber][scaledCounter]);           //Low byte second
      digitalWrite(LE,HIGH);
    }
  
  //If the encoder switch is pushed, this will turn on the bottom LED.  The bottom LED is turned
  //on by 'OR-ing' the current display with 0x8000 (1000000000000000 in binary)
  if (!digitalRead(ENC_SW))
  {
    digitalWrite(LE,LOW);  
    shiftOut(SDI,CLK,MSBFIRST,((sequence[sequenceNumber][scaledCounter]|0x8000) >> 8));
    shiftOut(SDI,CLK,MSBFIRST,sequence[sequenceNumber][scaledCounter]);              
    digitalWrite(LE,HIGH);   
  }
}



/*************************************************************************
*    read_encoder() function as provided by Oleg:                        *
*    http://www.circuitsathome.com/mcu/reading-rotary-encoder-on-arduino *
*                                                                        *
*    Returns change in encoder state (-1,0,1)                            *
************************************************************************ */
int8_t read_encoder()
{
  int8_t enc_states[] = {0,-1,1,0,1,0,0,-1,-1,0,0,1,0,1,-1,0};
  static uint8_t old_AB = 0;
  /**/
  old_AB <<= 2;                   //remember previous state
  old_AB |= ( ENC_PORT & 0x03 );  //add current state
  return ( enc_states[( old_AB & 0x0f )]);
}

La version avec les led bleu est plutôt pas mal !

Conclusion :
C’est une board simple mais qui peut s’avéré bien pratique si on veux faire un systéme d’encodeur avec retour visuelle sans rien avoir à cabler.
Pour le reste rien de bien innovant, juste un petit faible pour la version bleu.

Discussion

8 réflexions sur “[Test] Rotary encoder LED Ring (Mayhew Labs)

  1. as tu trouvé comment faire pour le bloquer sur une seul séquence ?
    merci

    Publié par anthology | 11 septembre 2011, 15 h 30 min
    • La séquence est sous la forme d’une array de byte, qui est affiché via le shiftOut.
      Pour bloquer sur la même séquence avec le code d’exemple il suffirai de changer sequence[sequenceNumber][scaledCounter] ligne 112, 113 par sequence[0][scaledCounter] par exemple (0, 1 ou 2 selon la séquence voulu)
      ou mieux refaire un sketch soi même avec une séquence perso.

      Publié par skywodd | 11 septembre 2011, 18 h 21 min
  2. merci a toi
    je penche aussi vers un sketch perso mais pas trop le temps
    donc je vais utilisé le leur pour le moment

    Publié par anthology | 11 septembre 2011, 18 h 29 min
  3. Bonjour,
    je débute en électronique programmable et pour se faire, j’ai acheté un carte arduino uno. J’ai réussi sans problème à commander un potentiomètre numérique via le bus SPI, grâce aux sketchs d’exemple.
    Je ne connais pas encore shiftOut, donc je voudrais savoir comment on commande le tlc5925 via SPI.
    Si j’essai SPI.transfer(0000000000000001);
    Je peut espérer allumer la première des 16 leds ? (sans parler des histoires de chip select qui vont de soit)
    Merci d’avance pour votre aide.

    Publié par sub49 | 24 mars 2012, 2 h 02 min
    • >> Je ne connais pas encore shiftOut, donc je voudrais savoir comment on commande le tlc5925 via SPI.
      >> Si j’essai SPI.transfer(0000000000000001);
      >> Je peut espérer allumer la première des 16 leds ? (sans parler des histoires de chip select qui vont de soit)

      SPI.transfer() ne permet d’envoyer qu’un octet sur 8bits et non sur 16bits 😉
      Ensuite pour les chiffres en binaires il faut mettre B devant.

      Pour allumer la 1er led :
      SPI.transfer(B00000000); // MSB -> led 9 à 16
      SPI.transfer(B00000001); // LSB -> led 1 à 8

      Publié par skywodd | 24 mars 2012, 13 h 23 min
  4. Salut,
    Au final je n’ai eu aucun résultat aves SPI.transfer(), mais j’ai réussi à me débrouiller avec shiftOut() et sa fonctionne impec’. Mais c’est aussi grâce à toi Skywodd, car sans savoir qu’il fallait envoyer les 16bits sur 2 Octets successifs, je me serait planté en beauté ! Merci à toi 😉
    Voilà ma fonction qui m’a permis de faire le test avec succès. 🙂

    void led_on()
    {
    digitalWrite (LE, LOW); //Set all LEDs ON.
    shiftOut (SDI, CLK, MSBFIRST, B11111111); //LEDs 9 à 16.
    shiftOut (SDI, CLK, MSBFIRST, B11111111); //LEDs 1 à 8.
    digitalWrite (LE, HIGH);
    }

    Publié par sub49 | 8 avril 2012, 2 h 42 min
    • Pas de quoi 😉

      Pour le SPI hardware retente le coup avec :

      SPI.setClockDivider(SPI_CLOCK_DIV32);
      SPI.setBitOrder(MSBFIRST);
      

      dans setup().

      Normalement ça devrai marcher sans soucis 😉

      Publié par skywodd | 8 avril 2012, 18 h 23 min

Skyduino devient Carnet du Maker

Le site Carnet du Maker remplace désormais le blog Skyduino pour tout ce qui touche à l'Arduino, l'informatique et au DIY.