Skyduino:~#
Articles
arduino, Corrigé, programmation

[Arduino] Carte TM1638 (7 segments + leds + boutons)

Bonjour tout le monde !

Aujourd’hui j’ai enfin eu le temps de terminer un morceau de code que j’avais en projet depuis déjà pas mal de temps.
Cet article vient en complément d’un de mes précédent article sur le TM1640, sauf qu’ici je vais parler de son petit frère le TM1638.

La carte de démo :

Avant de parler plus en détails du TM1638 je voulais d’abord vous parler de la carte de démonstration sur laquelle je travaille.

Il s’agit d’une carte du fabricant chinois JY-MCU, celle ci est disponible chez DealExtreme, ebay ou tout autre marchant en provenance de chine 😉
Elle comporte tout le nécéssaire pour bricoler avec un TM1638, à savoir :
– 8 afficheurs 7 segments,
– 8 leds bi-colors (rouge + vert),
– 8 boutons poussoirs.

Remarque : le TM1638 est capable de controler 3 séries de 8 boutons (sous forme de matrice).
Sur la carte de démo seul une série de bouton est disponible, on comprend aisément que 3 rangées de 8 boutons seraient un peu encombrantes.

Le chipset TM1638 :

Voici les divers points importants tirés du datasheet officiel du TM1638.
(désolé pas de lien direct vers le datasheet, je n’arrive plus à mettre la main dessus …)

Edit: Site du fabricant (mais lien vers le datasheet HS apparemment) :
http://www.titanmec.com/doce/product-detail-182.html

Datasheet (lien google doc, merci SEB pour le lien) :
https://docs.google.com/file/d/0B84N2SrJaybwZTgxYjM4ZmEtY2EyZi00YjVjLWIzOTctYTlhMjJkM2MxMTBl/edit

Les timings de communication :

Les commandes d’écriture / lecture :

Les commandes d’affichage :

Les commandes d’adressage :

La mémoire RAM pour l’affichage :

Note : Les huit premiers bits correspondent aux 7 segments de l’afficheur + point décimal, les deux derniers bits correspondent aux leds bi-color.

La mémoire RAM pour les boutons :

Note : Les boutons de la carte de démonstration sont sur KS2.

Le montage :

Pour cet exemple vous aurez besoin :
- une carte arduino
- une carte TM1638
- des fils (minimum 5)

Le TM1638 se contrôle via un port à 3 broches (une sorte de port SPI avec les lignes MISO et MOSI en une seul ligne).

Celui ci se compose :
– DIO : ligne de données bidirectionnelle (entrante ou sortante)
– CLK : ligne d’horloge
– STB : ligne de sélection (équivalent du CS ou SS en SPI) (permet de chaîner plusieurs TM1638)

Comme je le disais plus haut les boutons de la carte de démonstration sont sur K2.
Les lignes K1 et K3 sont disponible à l’arrière de la carte si besoin.

Concernant le câblage de l’exemple :
TM1638 -> Arduino (UNO)
STB -> D11
DIO -> D12
CLK -> D13

VCC -> +5V
GND -> GND

Le code :

Ce code d’exemple se contente d’afficher un compteur sur les afficheurs 7 segments et de changer la couleur des led suivant l’état des boutons.

/* Brochage du TM1638 */
#define PORT_OUT_REG PORTB // Port de sortie sur lequel est cablé le TM1640
#define PORT_IN_REG PINB   // Port d'entrée sur lequel est cablé le TM1640
#define DDR_REG DDRB       // Registre DDR associé aux d'entrée / sortie
#define PIN_STB 3          // Broche STB : PB3 -> D11 (arduino UNO)
#define PIN_DIO 4          // Broche DIO : PB4 -> D12
#define PIN_CLK 5          // Broche CLK : PB5 -> D13

/* Macro de manipulation de la broche DIO */
// Macro pour données sortantes
#define dataLow() PORT_OUT_REG &= ~(1 << PIN_DIO)
#define dataHigh() PORT_OUT_REG |= (1 << PIN_DIO)
#define dataSet(x) (x) ? dataHigh() : dataLow()
// Macro pour données entrantes
#define dataRead() (PORT_IN_REG & (1 << PIN_DIO))
#define dataPinInput() dataHigh(); DDR_REG &= ~(1 << PIN_DIO) // Use pull-up
#define dataPinOutput() DDR_REG |= (1 << PIN_DIO)

/* Macro de manipulation de la broche CLK */
#define clockLow() PORT_OUT_REG &= ~(1 << PIN_CLK)
#define clockHigh() PORT_OUT_REG |= (1 << PIN_CLK)

/* Macro de manipulation de la broche STB */
#define latchEnable() PORT_OUT_REG &= ~(1 << PIN_STB)
#define latchDisable() PORT_OUT_REG |= (1 << PIN_STB)

/* Table de correspondance chiffre / lettre -> 7 segments */
const uint8_t numericTable[] = {
  /* dp, g, f, e, d, c, b, a */
  B00111111, // 0
  B00000110, // 1
  B01011011, // 2
  B01001111, // 3
  B01100110, // 4
  B01101101, // 5
  B01111101, // 6
  B00000111, // 7
  B01111111, // 8
  B01101111, // 9
  B01110111, // A
  B01111100, // B
  B00111001, // C
  B01011110, // D
  B01111001, // E
  B01110001  // F
};

/* Macro pour ajouter le point décimal à une valeur de numericTable[]  */
#define ADD_DECIMAL_POIN(x) (x | 128)

/* ----- Fonctions bas niveau ----- */

/* Initialise les broches de contrôle du TM1638 */
void TM1638_setup(void) {
  DDR_REG |= (1 << PIN_STB) | (1 << PIN_CLK); // Broches STB et CLK en sorties
  dataPinInput(); // Broche DIO en entrée (-> haute impédance)
  clockHigh();    // Broche CLK à LOW
  latchDisable(); // Broche STB à HIGH
}

/* Envoi un octet vers le TM1638 */
void TM1638_write(uint8_t data) {
  dataPinOutput();     // Broche DIO en sortie
  for(uint8_t i = 0; i < 8; ++i) { // Pour chaque bit
    clockLow();        // Broche CLK à LOW
    dataSet(data & 1); // Broche DIO = valeur du bit
    data >>= 1;        // Traitement du bit suivant
    clockHigh();       // Broche CLK à HIGH
  }
}

/* Reçoit un octet depuis le TM1638  */
uint8_t TM1638_read(void) {
  uint8_t answer = 0;   // Valeur reçu depuis le TM1638
  dataPinInput();       // Broche DIO en entrée
  for(uint8_t i = 0; i < 8; ++i) { // Pour chaque bit
    clockLow();         // Broche CLK à LOW
    if(dataRead())      // Lecture de la broche DIO
      answer |= 1 << i; // Stockage du bit
    clockHigh();        // Broche CLK à HIGH
  }
  return answer;
}

/* Fixe l'adresse de base des opérations d'écriture */
void TM1638_set_address(uint8_t address) {
  address &= 0x0F;
  TM1638_write(0xC0 | address);
}

/* Liste des différents mode de données possibles */
enum {
  WRITE_MODE,
  READ_MODE,
  FIXED_ADDRESS,
  INCREMENTIAL_ADDRESS
};

/* Fixe le mode de données à utiliser
 *
 * op_mode : mode d’opération (WRITE_MODE ou READ_MODE)
 * addr_mode : mode d'adressage (FIXED_ADDRESS ou INCREMENTIAL_ADDRESS)
 */
void TM1638_data_mode(uint8_t op_mode, uint8_t addr_mode) {
  TM1638_write(0x40 | ((op_mode == WRITE_MODE) ? 0x00 : 0x02) | ((addr_mode == FIXED_ADDRESS) ? 0x00 : 0x04));
}

/* ----- High level functions ----- */

/* Configure le niveau de luminosité des digits / leds */
void TM1638_set_brightness(uint8_t level) {  
  latchEnable();              // Début de communication
  level &= 0x07;              // Limite 0~7 pour "level"
  TM1638_write(0x88 | level); // Envoi de la commande SET_BRIGHTNESS + level
  latchDisable();             // Fin de communication
}

/* Efface les valeurs des digits et des led */
void TM1638_clear_display(void) {
  latchEnable(); // Début de communcation
  TM1638_data_mode(WRITE_MODE, INCREMENTIAL_ADDRESS);
  latchDisable(); // Fin de communcation

  latchEnable();            // Début de communication
  TM1638_set_address(0x00); // Début à l'adresse 0x00
  for (uint8_t i = 0; i < 16; ++i) // Pour chaque digits / leds
    TM1638_write(0x00);     // Valeur = 0x00 (éteint)
  latchDisable();           // Fin de communication
}

/* Éteint (physiquement) le TM1638 */
void TM1638_set_display_off(void) {
  latchEnable();      // Début de communication
  TM1638_write(0x80); // Envoi de la commande DISPLAY_OFF
  latchDisable();     // Fin de communication
}

/* Fixe la valeur (value) d'un digit à l'index voulu (0 = digit le plus à gauche) */
void TM1638_set_digit(uint8_t index, uint8_t value) {
  uint8_t address = index * 2; // Calcul de l'adresse en fonction de l'index
  latchEnable();               // Début de communication
  TM1638_data_mode(WRITE_MODE, FIXED_ADDRESS);
  latchDisable();              // Fin de communication

  latchEnable();       // Début de communication
  TM1638_set_address(address); // Sélection de l'adresse
  TM1638_write(value); // Envoi de la valeur
  latchDisable();      // Fin de communication
}

/* Fixe l'état d'une led bicolor (color_1 et color_2) en fonction à l'index voulu (0 = led la plus à gauche) */
inline void TM1638_set_led(uint8_t index, uint8_t color_1, uint8_t color_2) {
  TM1638_set_led_raw(index, color_1 | (color_2 << 1));
}

/* Fixe l'état d'une led bicolor (value) en fonction à l'index voulu (0 = led la plus à gauche) */
void TM1638_set_led_raw(uint8_t index, uint8_t value) {
  uint8_t address = (index * 2) + 1; // Calcul de l'adresse en fonction de l'index
  latchEnable();                     // Début de communication
  TM1638_data_mode(WRITE_MODE, FIXED_ADDRESS);
  latchDisable();                    // Fin de communication

  latchEnable();       // Début de communication
  TM1638_set_address(address); // Sélection de l'adresse
  TM1638_write(value); // Envoi de la valeur (2 bits de couleur + 6 bits ignoré)
  latchDisable();      // Fin de communcation
}

/* Lit l'état des boutons (platine TM1638 JY-MCU (DealExtreme, ebay, ...) uniquement) */
void TM1638_get_button(uint8_t *buffer) { // uint8_t buffer[8];
  uint8_t memory[4]; // Octet recu depuis le TM1638
  latchEnable();     // Début de communcation
  TM1638_data_mode(READ_MODE, INCREMENTIAL_ADDRESS); // 4 READ_MODE consécutif maximum
  delayMicroseconds(10);     // Delai avant lecture (obligatoire, >1µs)
  memory[0] = TM1638_read(); // Lecture des valeurs "key scan"
  memory[1] = TM1638_read(); // (KS1, KS2, KS3)
  memory[2] = TM1638_read(); // (Seul KS2 est utilisé sur la platine JY-MCU)
  memory[3] = TM1638_read(); // 
  latchDisable();            // Fin de communcation

  // Calcul des différents états (brochage spécifique à la platine JY-MCU)
  buffer[0] = (memory[0] & 2) ? 1 : 0;
  buffer[1] = (memory[1] & 2) ? 1 : 0;
  buffer[2] = (memory[2] & 2) ? 1 : 0;
  buffer[3] = (memory[3] & 2) ? 1 : 0;
  buffer[4] = (memory[0] & 32) ? 1 : 0;
  buffer[5] = (memory[1] & 32) ? 1 : 0;
  buffer[6] = (memory[2] & 32) ? 1 : 0;
  buffer[7] = (memory[3] & 32) ? 1 : 0;
}

/* Lit l'état des boutons sous forme d'un octet sur 8 bits (1 bit = 1 bouton) */
uint8_t TM1638_get_button_raw(void) {
  uint8_t buffer[8], raw_button = 0; // Buffer pour les états, valeur brute résultante
  TM1638_get_button(buffer);         // Lecture des états des boutons
  for(uint8_t i = 0; i < 8; ++i)     // Pour chaque bits
    raw_button |= buffer[i] << i;    // Convertion du buffer en valeur 8 bits
  return raw_button;

}

/* setup() */
void setup() {
  TM1638_setup();           // Initialisation du TM1638
  TM1638_set_brightness(5); // Luminosité à 5/7
}

/* loop() */
void loop() {
  static uint32_t counter = 0; // Compteur 32 bits
  uint8_t bp_states[8];        // Etats des boutons

  // Affichage de la valeur du compteur (en décimal)
  TM1638_set_digit(7, numericTable[counter % 10]);
  TM1638_set_digit(6, numericTable[(counter / 10) % 10]);
  TM1638_set_digit(5, numericTable[(counter / 100) % 10]);
  TM1638_set_digit(4, numericTable[(counter / 1000) % 10]);
  TM1638_set_digit(3, numericTable[(counter / 10000) % 10]);
  TM1638_set_digit(2, numericTable[(counter / 100000) % 10]);
  TM1638_set_digit(1, numericTable[(counter / 1000000) % 10]);
  TM1638_set_digit(0, numericTable[(counter / 10000000) % 10]);

  // Lecture des boutons
  TM1638_get_button(bp_states);
  
  // Affichage de l'état des boutons en couleur
  for(uint8_t i = 0; i < 8; ++i) {
    if(bp_states[i])
      TM1638_set_led(i, 0, 1);
    else
      TM1638_set_led(i, 1, 0);
  }

  // Incrémentation du compteur (+ limite)
  if(++counter > 99999999) counter = 0;

  // Delai de rafraichissement
  delay(250);
}

Le résultat :

(J’ai figé le compteur à 1234567 pour pouvoir faire la photo ;))

Bon bidouillage à tous ! 🙂

Discussion

6 réflexions sur “[Arduino] Carte TM1638 (7 segments + leds + boutons)

  1. Pas mal la carte, y en a des I/O 🙂
    Pour le lien du datasheet TM1638, j’ai trouvé ça: https://docs.google.com/file/d/0B84N2SrJaybwZTgxYjM4ZmEtY2EyZi00YjVjLWIzOTctYTlhMjJkM2MxMTBl/edit

    Publié par seb | 1 août 2012, 9 h 44 min
  2. Bonjour,
    Il y a des ) en trop à partir de la ligne 215…

    Publié par Manu | 26 Mai 2014, 18 h 46 min
  3. bonsoir, c’est un tres bon boulo.
    mais ca ne marchera pas avec les afficheur 7 segment a Anode commune.

    Publié par Ibrahim Eric | 28 octobre 2018, 10 h 50 min

Rétroliens/Pings

  1. Pingback: Iot | Pearltrees - 23 octobre 2017

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.