Skyduino:~#
Articles
arduino, programmation, projet

[Arduino] Code pour cube de leds 8x8x8

Bonjour tout le monde !

Dans l’après-midi, j’ai aidé une personne qui travaille sur un projet de cube de 8x8x8 leds. Son projet est un gros machin plein de leds, qui je l’avoue, m’a donné quelques idées.

Le hardware était bon, malheureusement, son code ne marchait pas et il était vraiment bloqué. Du coup, je lui ai un peu (beaucoup) soufflé la solution.
D’habitude, je ne donne pas de solution toute prête, je donne juste des indices et des conseils pour résoudre le problème. Cela faisait cependant (vraiment) longtemps que je n’avais pas fait un peu d’Arduino, du coup, je me suis offert une petite pause Arduino. Petite pause qui a abouti à la réalisation d’un code Arduino complet pour contrôler un cube de leds, avec les états des leds stockées dans un fichier texte.

Le code ne m’étant d’aucune utilité vu que je n’ai pas le cube de leds qui va avec, je me suis dit qu’il serait intéressant de laisser le code source dans un coin du blog pour les prochains bricoleurs qui en auront besoin 😉

Désolé par avance, il n’y aura pas de jolies photos du montage ou de schéma de câblage détaillé. Je n’ai pas le montage entre les mains, juste une description.
Je m’excuse aussi pour le format un peu brut / télégraphique de cet article. Je l’écris vraiment sur un coin de table, comme un simple pense-bête.


D’un point de vue hardware, le projet est constitué d’une carte Arduino UNO, de trois MCP23S08 (expander I/O 8 bits SPI de Microchip), d’une shield SD et d’un cube de 512 leds (mono couleur).

La carte SD contient à sa racine un fichier nommé « animation.txt » qui décrit l’état des leds du cube au moyen d’une série de caractères ‘1’ et ‘0’. Le format est ultra simpliste : 1 caractère par led, 512 caractères au total pour le cube complet, plusieurs blocs de 512 caractères forme une animation.

Les trois MCP23S08 sont reliés à l’Arduino UNO via le bus SPI sur les broches 13, 12, 11.
Le MCP23S08 gérant l’axe Z (hauteur) est câblé avec A0 = VCC, A1 = GND, SS = D8.
Le MCP23S08 gérant l’axe Y (lignes) est câblé avec A0 = GND, A1 = VCC, SS = D9.
Le MCP23S08 gérant l’axe Z (colonnes) est câblé avec A0 = GND, A1 = GND, SS = D10.
Derrière chaque MCP23S08, il y a une série de 8 transistors de puissance (ULN2803 ou équivalent) pour contrôler les leds (c’est un bête multiplexage ligne/colonne/couche).

La broche SS de la shield SD est câblé sur D4.


Le fichier d’animation a le format suivant (extrait d’un de mes mails):

Une "frame" = une image 3D.
Une image est composée de 8 couches (axe Z), chacune formée de 8 lignes (axe Y), elles-mêmes formées de 8 leds (axe X) chacune.
Au total on obtient 8 x 8 x 8 = 512 pixels par image. Chaque pixel est représenté dans le fichier par un caractère '0' ou '1'.

Ce que fait le programme pour lire le fichier :
1) Pour chaque couche de l'axe Z (8 au total), il lit les 8 lignes de l'axe Y (via les deux boucles imbriquées z et y).
2) Pour chaque ligne, il lit 8 caractères, puis convertit ces 8 caractères en un nombre entier sur 8 bits.
3) Pour chaque série de 8 caractères, le programme stocke le nombre entier dans le buffer d'affichage.

Le fichier sur la carte SD est donc sous la forme (explication un peu plus bas):

X0Y0Z0 X1Y0Z0 X2Y0Z0 X3Y0Z0 X4Y0Z0 X5Y0Z0 X6Y0Z0 X7Y0Z0 
X0Y1Z0 X1Y1Z0 X2Y1Z0 X3Y1Z0 X4Y1Z0 X5Y1Z0 X6Y1Z0 X7Y1Z0 
X0Y2Z0 X1Y2Z0 X2Y2Z0 X3Y2Z0 X4Y2Z0 X5Y2Z0 X6Y2Z0 X7Y2Z0 
X0Y3Z0 X1Y3Z0 X2Y3Z0 X3Y3Z0 X4Y3Z0 X5Y3Z0 X6Y3Z0 X7Y3Z0 
X0Y4Z0 X1Y4Z0 X2Y4Z0 X3Y4Z0 X4Y4Z0 X5Y4Z0 X6Y4Z0 X7Y4Z0 
X0Y5Z0 X1Y5Z0 X2Y5Z0 X3Y5Z0 X4Y5Z0 X5Y5Z0 X6Y5Z0 X7Y5Z0 
X0Y6Z0 X1Y6Z0 X2Y6Z0 X3Y6Z0 X4Y6Z0 X5Y6Z0 X6Y6Z0 X7Y6Z0 
X0Y7Z0 X1Y7Z0 X2Y7Z0 X3Y7Z0 X4Y7Z0 X5Y7Z0 X6Y7Z0 X7Y7Z0 
X0Y0Z1 X1Y0Z1 X2Y0Z1 X3Y0Z1 X4Y0Z1 X5Y0Z1 X6Y0Z1 X7Y0Z1 
X0Y1Z1 X1Y1Z1 X2Y1Z1 X3Y1Z1 X4Y1Z1 X5Y1Z1 X6Y1Z1 X7Y1Z1 
X0Y2Z1 X1Y2Z1 X2Y2Z1 X3Y2Z1 X4Y2Z1 X5Y2Z1 X6Y2Z1 X7Y2Z1 
X0Y3Z1 X1Y3Z1 X2Y3Z1 X3Y3Z1 X4Y3Z1 X5Y3Z1 X6Y3Z1 X7Y3Z1 
X0Y4Z1 X1Y4Z1 X2Y4Z1 X3Y4Z1 X4Y4Z1 X5Y4Z1 X6Y4Z1 X7Y4Z1 
X0Y5Z1 X1Y5Z1 X2Y5Z1 X3Y5Z1 X4Y5Z1 X5Y5Z1 X6Y5Z1 X7Y5Z1 
X0Y6Z1 X1Y6Z1 X2Y6Z1 X3Y6Z1 X4Y6Z1 X5Y6Z1 X6Y6Z1 X7Y6Z1 
X0Y7Z1 X1Y7Z1 X2Y7Z1 X3Y7Z1 X4Y7Z1 X5Y7Z1 X6Y7Z1 X7Y7Z1 
X0Y0Z2 X1Y0Z2 X2Y0Z2 X3Y0Z2 X4Y0Z2 X5Y0Z2 X6Y0Z2 X7Y0Z2 
X0Y1Z2 X1Y1Z2 X2Y1Z2 X3Y1Z2 X4Y1Z2 X5Y1Z2 X6Y1Z2 X7Y1Z2 
X0Y2Z2 X1Y2Z2 X2Y2Z2 X3Y2Z2 X4Y2Z2 X5Y2Z2 X6Y2Z2 X7Y2Z2 
X0Y3Z2 X1Y3Z2 X2Y3Z2 X3Y3Z2 X4Y3Z2 X5Y3Z2 X6Y3Z2 X7Y3Z2 
X0Y4Z2 X1Y4Z2 X2Y4Z2 X3Y4Z2 X4Y4Z2 X5Y4Z2 X6Y4Z2 X7Y4Z2 
X0Y5Z2 X1Y5Z2 X2Y5Z2 X3Y5Z2 X4Y5Z2 X5Y5Z2 X6Y5Z2 X7Y5Z2 
X0Y6Z2 X1Y6Z2 X2Y6Z2 X3Y6Z2 X4Y6Z2 X5Y6Z2 X6Y6Z2 X7Y6Z2 
X0Y7Z2 X1Y7Z2 X2Y7Z2 X3Y7Z2 X4Y7Z2 X5Y7Z2 X6Y7Z2 X7Y7Z2 
X0Y0Z3 X1Y0Z3 X2Y0Z3 X3Y0Z3 X4Y0Z3 X5Y0Z3 X6Y0Z3 X7Y0Z3 
X0Y1Z3 X1Y1Z3 X2Y1Z3 X3Y1Z3 X4Y1Z3 X5Y1Z3 X6Y1Z3 X7Y1Z3 
X0Y2Z3 X1Y2Z3 X2Y2Z3 X3Y2Z3 X4Y2Z3 X5Y2Z3 X6Y2Z3 X7Y2Z3 
X0Y3Z3 X1Y3Z3 X2Y3Z3 X3Y3Z3 X4Y3Z3 X5Y3Z3 X6Y3Z3 X7Y3Z3 
X0Y4Z3 X1Y4Z3 X2Y4Z3 X3Y4Z3 X4Y4Z3 X5Y4Z3 X6Y4Z3 X7Y4Z3 
X0Y5Z3 X1Y5Z3 X2Y5Z3 X3Y5Z3 X4Y5Z3 X5Y5Z3 X6Y5Z3 X7Y5Z3 
X0Y6Z3 X1Y6Z3 X2Y6Z3 X3Y6Z3 X4Y6Z3 X5Y6Z3 X6Y6Z3 X7Y6Z3 
X0Y7Z3 X1Y7Z3 X2Y7Z3 X3Y7Z3 X4Y7Z3 X5Y7Z3 X6Y7Z3 X7Y7Z3 
X0Y0Z4 X1Y0Z4 X2Y0Z4 X3Y0Z4 X4Y0Z4 X5Y0Z4 X6Y0Z4 X7Y0Z4 
X0Y1Z4 X1Y1Z4 X2Y1Z4 X3Y1Z4 X4Y1Z4 X5Y1Z4 X6Y1Z4 X7Y1Z4 
X0Y2Z4 X1Y2Z4 X2Y2Z4 X3Y2Z4 X4Y2Z4 X5Y2Z4 X6Y2Z4 X7Y2Z4 
X0Y3Z4 X1Y3Z4 X2Y3Z4 X3Y3Z4 X4Y3Z4 X5Y3Z4 X6Y3Z4 X7Y3Z4 
X0Y4Z4 X1Y4Z4 X2Y4Z4 X3Y4Z4 X4Y4Z4 X5Y4Z4 X6Y4Z4 X7Y4Z4 
X0Y5Z4 X1Y5Z4 X2Y5Z4 X3Y5Z4 X4Y5Z4 X5Y5Z4 X6Y5Z4 X7Y5Z4 
X0Y6Z4 X1Y6Z4 X2Y6Z4 X3Y6Z4 X4Y6Z4 X5Y6Z4 X6Y6Z4 X7Y6Z4 
X0Y7Z4 X1Y7Z4 X2Y7Z4 X3Y7Z4 X4Y7Z4 X5Y7Z4 X6Y7Z4 X7Y7Z4 
X0Y0Z5 X1Y0Z5 X2Y0Z5 X3Y0Z5 X4Y0Z5 X5Y0Z5 X6Y0Z5 X7Y0Z5 
X0Y1Z5 X1Y1Z5 X2Y1Z5 X3Y1Z5 X4Y1Z5 X5Y1Z5 X6Y1Z5 X7Y1Z5 
X0Y2Z5 X1Y2Z5 X2Y2Z5 X3Y2Z5 X4Y2Z5 X5Y2Z5 X6Y2Z5 X7Y2Z5 
X0Y3Z5 X1Y3Z5 X2Y3Z5 X3Y3Z5 X4Y3Z5 X5Y3Z5 X6Y3Z5 X7Y3Z5 
X0Y4Z5 X1Y4Z5 X2Y4Z5 X3Y4Z5 X4Y4Z5 X5Y4Z5 X6Y4Z5 X7Y4Z5 
X0Y5Z5 X1Y5Z5 X2Y5Z5 X3Y5Z5 X4Y5Z5 X5Y5Z5 X6Y5Z5 X7Y5Z5 
X0Y6Z5 X1Y6Z5 X2Y6Z5 X3Y6Z5 X4Y6Z5 X5Y6Z5 X6Y6Z5 X7Y6Z5 
X0Y7Z5 X1Y7Z5 X2Y7Z5 X3Y7Z5 X4Y7Z5 X5Y7Z5 X6Y7Z5 X7Y7Z5 
X0Y0Z6 X1Y0Z6 X2Y0Z6 X3Y0Z6 X4Y0Z6 X5Y0Z6 X6Y0Z6 X7Y0Z6 
X0Y1Z6 X1Y1Z6 X2Y1Z6 X3Y1Z6 X4Y1Z6 X5Y1Z6 X6Y1Z6 X7Y1Z6 
X0Y2Z6 X1Y2Z6 X2Y2Z6 X3Y2Z6 X4Y2Z6 X5Y2Z6 X6Y2Z6 X7Y2Z6 
X0Y3Z6 X1Y3Z6 X2Y3Z6 X3Y3Z6 X4Y3Z6 X5Y3Z6 X6Y3Z6 X7Y3Z6 
X0Y4Z6 X1Y4Z6 X2Y4Z6 X3Y4Z6 X4Y4Z6 X5Y4Z6 X6Y4Z6 X7Y4Z6 
X0Y5Z6 X1Y5Z6 X2Y5Z6 X3Y5Z6 X4Y5Z6 X5Y5Z6 X6Y5Z6 X7Y5Z6 
X0Y6Z6 X1Y6Z6 X2Y6Z6 X3Y6Z6 X4Y6Z6 X5Y6Z6 X6Y6Z6 X7Y6Z6 
X0Y7Z6 X1Y7Z6 X2Y7Z6 X3Y7Z6 X4Y7Z6 X5Y7Z6 X6Y7Z6 X7Y7Z6 
X0Y0Z7 X1Y0Z7 X2Y0Z7 X3Y0Z7 X4Y0Z7 X5Y0Z7 X6Y0Z7 X7Y0Z7 
X0Y1Z7 X1Y1Z7 X2Y1Z7 X3Y1Z7 X4Y1Z7 X5Y1Z7 X6Y1Z7 X7Y1Z7 
X0Y2Z7 X1Y2Z7 X2Y2Z7 X3Y2Z7 X4Y2Z7 X5Y2Z7 X6Y2Z7 X7Y2Z7 
X0Y3Z7 X1Y3Z7 X2Y3Z7 X3Y3Z7 X4Y3Z7 X5Y3Z7 X6Y3Z7 X7Y3Z7 
X0Y4Z7 X1Y4Z7 X2Y4Z7 X3Y4Z7 X4Y4Z7 X5Y4Z7 X6Y4Z7 X7Y4Z7 
X0Y5Z7 X1Y5Z7 X2Y5Z7 X3Y5Z7 X4Y5Z7 X5Y5Z7 X6Y5Z7 X7Y5Z7 
X0Y6Z7 X1Y6Z7 X2Y6Z7 X3Y6Z7 X4Y6Z7 X5Y6Z7 X6Y6Z7 X7Y6Z7 
X0Y7Z7 X1Y7Z7 X2Y7Z7 X3Y7Z7 X4Y7Z7 X5Y7Z7 X6Y7Z7 X7Y7Z7

Explication du format : 
XnYnZn -> dans le fichier final chaque XnYnZn correspond à un '1' ou à un '0'.
Chaque "n" dans le format correspond à un numéro de broche entre 0 et 7.
Les espaces et retours lignes sont juste là pour rendre le truc lisible par mail, dans le fichier tous les 1/0 se suivent sans espace ni retour lignes.

X0Y0Z0 correspond à la première led, de la première ligne, de la première couche.
X1Y0Z0 correspond à la deuxième led, de la première ligne, de la première couche.
etc etc jusqu'à
X7Y7Z7 qui correspond à la huitième led, de la huitième colonne, de la huitième couche.

Plusieurs blocs de 512 caractères peuvent se suivre pour former une animation.

Pour finir, voici le code, avec les commentaires de rigueur :

Disclaimer : on m’a dit que ça marchait, mais je ne peux pas le certifier vu que je n’ai pas le matériel sous la main. J’ai quand même testé le code à l’oscilloscope et ça semble bon.

/* Dépendances du projet */
#include <SPI.h> // Pour la communication SPI avec la carte SD et les I/O
#include <SD.h>  // Pour la communication avec la carte SD en FAT16


/* Broches pour les I/O */
const byte PIN_DATA_OUT = 11;       // MOSI (Master Out / Slave In)
const byte PIN_DATA_IN = 12;        // MISO (Master In / Slave Out) - non utilisé
const byte PIN_SPI_CLOCK = 13;      // SCK (Serial Clock) 
const byte PIN_SLAVE_SELECT_X = 10; // SS (Slave Select) pour l'axe X
const byte PIN_SLAVE_SELECT_Y = 9;  // SS (Slave Select) pour l'axe Y
const byte PIN_SLAVE_SELECT_Z = 8;  // SS (Slave Select) pour l'axe Z
const byte PIN_SLAVE_SD = 4;        // SS (Slave Select) pour la carte SD

/* Constantes pour la communication SPI avec les I/O (MCP23S08 de Microchip) */
# define SLAVE_ADDRESS_BASE   (B01000 << 3)
# define SLAVE_ADDRESS_BIT_A1 (1 << 2)
# define SLAVE_ADDRESS_BIT_A0 (1 << 1)
# define SLAVE_ADDRESS_X      (SLAVE_ADDRESS_BASE)
# define SLAVE_ADDRESS_Y      (SLAVE_ADDRESS_BASE | SLAVE_ADDRESS_BIT_A1)
# define SLAVE_ADDRESS_Z      (SLAVE_ADDRESS_BASE | SLAVE_ADDRESS_BIT_A0)

# define CONTROL_BIT_READ 1
# define CONTROL_BIT_WRITE 0

# define REG_IODIR   0x00 // Registre de direction des I/O
# define REG_IOPOL   0x01 // Registre de polarité des I/O
# define REG_GPIO    0x09 // Registre de valeur des I/O
# define REG_PULL_UP 0x06 // Registre de configuration de pull-up des I/O

const byte DEVICE_OPCODE_WRITE_X = SLAVE_ADDRESS_X | CONTROL_BIT_WRITE;
const byte DEVICE_OPCODE_WRITE_Y = SLAVE_ADDRESS_Y | CONTROL_BIT_WRITE;
const byte DEVICE_OPCODE_WRITE_Z = SLAVE_ADDRESS_Z | CONTROL_BIT_WRITE;

/* Constantes pour l'affichage */
const unsigned long MILLIS_BETWEEN_FRAME_SYNC = 1000;


/* L'instance du fichier pour lecture */
static File mFile;

/* Variables pour l'affichage */
static byte mDisplayBuffer[8][8] = {
  0};
static byte mDisplayCurrentZ = 0, mDisplayCurrentY = 0;
static unsigned long mPreviousFrameSyncMillis = 0;
static byte mFrameSync = 1;


/** Fonction d'initialisation hardware. */
void setup()
{
  /* Initialisation du port série (pour le debug) */
  Serial.begin(115200);
  Serial.println(F("Initialisation en cours ..."));

  /* Initialisation des I/O */
  pinMode(PIN_SLAVE_SELECT_X, OUTPUT);
  digitalWrite(PIN_SLAVE_SELECT_X, HIGH);
  pinMode(PIN_SLAVE_SELECT_Y, OUTPUT);
  digitalWrite(PIN_SLAVE_SELECT_Y, HIGH);
  pinMode(PIN_SLAVE_SELECT_Z, OUTPUT);
  digitalWrite(PIN_SLAVE_SELECT_Z, HIGH);
  pinMode(PIN_SLAVE_SD, OUTPUT);
  digitalWrite(PIN_SLAVE_SD, HIGH);
  
  /* Initialisation du SPI */
  SPI.begin();

  /* Initialisation de la carte SD */
  if (!SD.begin(PIN_SLAVE_SD)) {
    Serial.println(F("Echec de l'initialisation de la carte SD !"));
    Serial.println(F("Verifier la carte SD puis appuyer sur RESET."));
    for(;;);
  }

  /* Open the file */
  mFile = SD.open("animation.txt", FILE_READ);
  if (!mFile) {
    Serial.println(F("Impossible d'ouvrir le fichier !"));
    Serial.println(F("Verifier la carte SD puis appuyer sur RESET."));
    for(;;);
  }

  /* Initialisation des I/O externes */
  setRegisterX(REG_IODIR, 0x00);
  setRegisterY(REG_IODIR, 0x00);
  setRegisterZ(REG_IODIR, 0x00);
  
  /* Go */
  SPI.setClockDivider(SPI_CLOCK_DIV2);
  Serial.println(F("Initialisation terminee !"));
}

/**
 * Fonction d'écriture d'un registre de l'esclave SPI pour l'axe X.
 *
 * @param registerAddress Adresse du registre à modifier.
 * @param value Nouvelle valeur du registre à écrire.
 */
void setRegisterX(byte registerAddress, byte value) 
{
  digitalWrite(PIN_SLAVE_SELECT_X, LOW);  // Sélectionne l'axe X
  SPI.transfer(DEVICE_OPCODE_WRITE_X);    // Action d’écriture
  SPI.transfer(registerAddress);          // Adresse registre
  SPI.transfer(value);                    // Valeur registre
  digitalWrite(PIN_SLAVE_SELECT_X, HIGH); // Désélectionne l'axe X
}

/**
 * Fonction d'écriture d'un registre de l'esclave SPI pour l'axe Y.
 *
 * @param registerAddress Adresse du registre à modifier.
 * @param value Nouvelle valeur du registre à écrire.
 */
void setRegisterY(byte registerAddress, byte value) 
{
  digitalWrite(PIN_SLAVE_SELECT_Y, LOW);  // Sélectionne l'axe Y
  SPI.transfer(DEVICE_OPCODE_WRITE_Y);    // Action d’écriture
  SPI.transfer(registerAddress);          // Adresse registre
  SPI.transfer(value);                    // Valeur registre
  digitalWrite(PIN_SLAVE_SELECT_Y, HIGH); // Désélectionne l'axe Y
}

/**
 * Fonction d'écriture d'un registre de l'esclave SPI pour l'axe Z.
 *
 * @param registerAddress Adresse du registre à modifier.
 * @param value Nouvelle valeur du registre à écrire.
 */
void setRegisterZ(byte registerAddress, byte value) 
{
  digitalWrite(PIN_SLAVE_SELECT_Z, LOW);  // Sélectionne l'axe Z
  SPI.transfer(DEVICE_OPCODE_WRITE_Z);    // Action d’écriture
  SPI.transfer(registerAddress);          // Adresse registre
  SPI.transfer(value);                    // Valeur registre
  digitalWrite(PIN_SLAVE_SELECT_Z, HIGH); // Désélectionne l'axe Z
}

/** Fonction de travail. */
void loop()
{
  /* Gére deux taches en paralléle : le chargement des frames et l'affichage */
  unsigned long currentMillis = millis();

  /* Gestion du chargement des frames */
  if ((currentMillis - mPreviousFrameSyncMillis) >= MILLIS_BETWEEN_FRAME_SYNC && mFrameSync) {
    mPreviousFrameSyncMillis = currentMillis;
    mFrameSync = 0;

    /* Charge la frame suivante */
	//Serial.println(F(">> Frame suivante >>"));
    loadNextFrame();
  }

  /* Affichage la frame actuelle */
  //Serial.print(F("Z: "));
  //Serial.print(1 << mDisplayCurrentZ, BIN);
  //Serial.print(F(" Y: "));
  //Serial.print(1 << mDisplayCurrentY, BIN);
  //Serial.print(F(" X: "));
  byte value = mDisplayBuffer[mDisplayCurrentZ][mDisplayCurrentY];
  //Serial.println(value, BIN);
  setRegisterZ(REG_GPIO, 1 << mDisplayCurrentZ);
  setRegisterY(REG_GPIO, 1 << mDisplayCurrentY);
  setRegisterX(REG_GPIO, value);
  
  /* Saute à la ligne/colonne suivante */
  mFrameSync = 0;
  if (++mDisplayCurrentY == 8) {
    mDisplayCurrentY = 0;
    if (++mDisplayCurrentZ == 8) {
      mDisplayCurrentZ = 0;
      mFrameSync = 1;
	  //Serial.println(F("++ Sync fin de frame ++"));
    }
  }
}

/** Lit une frame complète et la stock dans le buffer d'affichage. */
void loadNextFrame()
{
  /* Début de communication avec la carte SD */
  digitalWrite(PIN_SLAVE_SD, HIGH);
	
  /* Chaque frame doit faire 512 caractéres */
  if (mFile.available() < 512) {

    /* Detection d'un fichier trop court */
    if (mFile.position() < 512) {
      Serial.println(F("le fichier doit contenir au moins une frame !"));
      Serial.println(F("Verifier le fichier puis appuyer sur RESET."));
      for(;;);
    }

    /* Fin de l'animation, retour au début */
    mFile.seek(0);
  }

  /* Lit une frame complète et l'affiche */

  /* Pour chaque colonne en Z */
  for(byte z = 0; z < 8; ++z) {

    /* Pour chaque ligne en Y */
    for(byte y = 0; y < 8; ++y) {

      /* Pour chaque leds */
      byte value = 0;
      for(byte x = 0; x < 8; ++x) {

        /* Lit un caractére */
        char ch = mFile.read();

        /* Stock la valeur en binaire */
        if (ch == '1') {
          value |= 1 << x;

        } 
        else if (ch == -1) {

          /* Fin de fichier inattendue */
          Serial.println(F("Fin de fichier inattendue au milieu d'une frame !"));
          Serial.println(F("Verifier le fichier puis appuyer sur RESET."));
          for(;;);
        }
      }

      /* Affiche les leds */
      mDisplayBuffer[z][y] = value;
    }
  }
  
  /* Fin de communication avec la carte SD */
  digitalWrite(PIN_SLAVE_SD, HIGH);
}

Discussion

Pas encore de commentaire.

Laisser un commentaire

Entrez vos coordonnées ci-dessous ou cliquez sur une icône pour vous connecter:

Logo WordPress.com

Vous commentez à l'aide de votre compte WordPress.com. Déconnexion / Changer )

Image Twitter

Vous commentez à l'aide de votre compte Twitter. Déconnexion / Changer )

Photo Facebook

Vous commentez à l'aide de votre compte Facebook. Déconnexion / Changer )

Photo Google+

Vous commentez à l'aide de votre compte Google+. Déconnexion / Changer )

Connexion à %s

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.