Skyduino:~#
Articles
arduino, programmation, tutoriel

[Tutoriel] Arduino + écran de nokia 5110

Bonjour tout le monde !

Aujourd’hui je vous ai préparé un article sur comment utiliser un écran de nokia 5110 avec une carte arduino.

Dans ce tutoriel je vais tous faire avec des fonctions « bas niveau », mais il existe une librairie toute prête pour les féniasses 😉
La librairie -> http://code.google.com/p/pcd8544/

Pour ceux qui voudraient plus de détails sur l’écran : https://skyduino.wordpress.com/2011/08/05/test-ecran-nokia-5110/
(Vous remarquerez surement que le code que je vais vous présenter ressemble beaucoup à celui fourni par sparkfun, en faite j’ai juste modifier le code de base pour y intégrer quelques fonctions bien sympathique ;))

Tout d’abord le matos :
1 arduino UNO,
1 breakout nokia-5110 de sparkfun,
des câbles M/F

(il n’y a besoin de rien d’autre)

Ensuite le câblage :
LCD -> arduino
SCE -> D7
RESET -> D6
DC -> D5
SDIN -> D4
SCLK -> D3
VCC -> 5v
GND -> GND
LED -> 3v3 (!! pas 5v !!)

Passons maintenant à la partie programmation 😉

Tout d’abord nous allons avoir besoin de convertir une petite image n&b en une suite d’octets, pour ce faire il existe des logiciels comme celui ci :
http://en.radzio.dxp.pl/bitmap_converter/ (Pour windows uniquement, amis linuxien il faudra chercher sur google)
File -> Open
Width -> 84
Height -> 48
8 pixels par byte

Avec l’image d’exemple de sparkfun (le smiley awesome) cela donne ceci :

//This is awesome in bitmap form
PROGMEM prog_uchar awesome[] = {
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xC0, 0xE0, 0x70, 0x30, 0x18, 0x1C,
  0x0C, 0x0C, 0x06, 0x06, 0x07, 0x07, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x07,
  0x07, 0x07, 0x0E, 0x06, 0x1C, 0x1C, 0x38, 0x70, 0x70, 0xE0, 0xE0, 0xC0, 0x80, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xF0, 0x3C, 0xCE, 0x67, 0x33, 0x18, 0x08,
  0x08, 0xC8, 0xF8, 0xF0, 0xE0, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0,
  0x70, 0x38, 0x18, 0x18, 0x08, 0x08, 0x08, 0xF8, 0xF0, 0xF0, 0xE0, 0xC0, 0x00, 0x00, 0x01, 0x07,
  0x0F, 0x3C, 0xF8, 0xE0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0xFF, 0x0F, 0x00, 0x0C, 0x7F,
  0x60, 0x60, 0x60, 0x60, 0x60, 0x61, 0x61, 0x61, 0x61, 0x61, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x7F, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x61, 0x61, 0x61, 0x61, 0x63,
  0x7E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF,
  0xF0, 0x00, 0x00, 0x00, 0x08, 0x08, 0xFC, 0x8C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C,
  0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C,
  0x0C, 0x0C, 0x0C, 0xF8, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xFF, 0x1F, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x07, 0x0F, 0x3C, 0x70, 0xE0, 0x80, 0x00, 0x07, 0x0C, 0x38, 0x60, 0xC0,
  0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF0, 0xF0, 0xF8, 0xF8, 0xF8, 0xF8, 0xF0,
  0xF0, 0xE0, 0xC0, 0x80, 0xC0, 0x30, 0x18, 0x0F, 0x00, 0x00, 0x80, 0xC0, 0x70, 0x3C, 0x1F, 0x07,
  0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x06,
  0x0E, 0x1C, 0x18, 0x38, 0x31, 0x73, 0x62, 0x66, 0x64, 0xC7, 0xCF, 0xCF, 0xCF, 0xCF, 0xCF, 0xCF,
  0xC7, 0xC7, 0xC7, 0x67, 0x63, 0x63, 0x71, 0x30, 0x38, 0x18, 0x1C, 0x0C, 0x06, 0x03, 0x03, 0x01,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  
};

(Remarque: j’ai remplacé le « char » par « PROGMEM prog_uchar » afin de stocker l’image en flash au lieu de la stocker en ram)

Au passage il va nous falloir afficher du texte, soit des caractéres, ils nous faut donc une table ascii, table que voici :

 // Table ascii des carateres, sur 5 pixels de large par 8 pixels de haut
PROGMEM prog_uchar asciiTable[] = {
   0x00, 0x00, 0x00, 0x00, 0x00 // 20  
  ,0x00, 0x00, 0x5f, 0x00, 0x00 // 21 !
  ,0x00, 0x07, 0x00, 0x07, 0x00 // 22 "
  ,0x14, 0x7f, 0x14, 0x7f, 0x14 // 23 #
  ,0x24, 0x2a, 0x7f, 0x2a, 0x12 // 24 $
  ,0x23, 0x13, 0x08, 0x64, 0x62 // 25 %
  ,0x36, 0x49, 0x55, 0x22, 0x50 // 26 &
  ,0x00, 0x05, 0x03, 0x00, 0x00 // 27 '
  ,0x00, 0x1c, 0x22, 0x41, 0x00 // 28 (
  ,0x00, 0x41, 0x22, 0x1c, 0x00 // 29 )
  ,0x14, 0x08, 0x3e, 0x08, 0x14 // 2a *
  ,0x08, 0x08, 0x3e, 0x08, 0x08 // 2b +
  ,0x00, 0x50, 0x30, 0x00, 0x00 // 2c ,
  ,0x08, 0x08, 0x08, 0x08, 0x08 // 2d -
  ,0x00, 0x60, 0x60, 0x00, 0x00 // 2e .
  ,0x20, 0x10, 0x08, 0x04, 0x02 // 2f /
  ,0x3e, 0x51, 0x49, 0x45, 0x3e // 30 0
  ,0x00, 0x42, 0x7f, 0x40, 0x00 // 31 1
  ,0x42, 0x61, 0x51, 0x49, 0x46 // 32 2
  ,0x21, 0x41, 0x45, 0x4b, 0x31 // 33 3
  ,0x18, 0x14, 0x12, 0x7f, 0x10 // 34 4
  ,0x27, 0x45, 0x45, 0x45, 0x39 // 35 5
  ,0x3c, 0x4a, 0x49, 0x49, 0x30 // 36 6
  ,0x01, 0x71, 0x09, 0x05, 0x03 // 37 7
  ,0x36, 0x49, 0x49, 0x49, 0x36 // 38 8
  ,0x06, 0x49, 0x49, 0x29, 0x1e // 39 9
  ,0x00, 0x36, 0x36, 0x00, 0x00 // 3a :
  ,0x00, 0x56, 0x36, 0x00, 0x00 // 3b ;
  ,0x08, 0x14, 0x22, 0x41, 0x00 // 3c <
  ,0x14, 0x14, 0x14, 0x14, 0x14 // 3d =
  ,0x00, 0x41, 0x22, 0x14, 0x08 // 3e >
  ,0x02, 0x01, 0x51, 0x09, 0x06 // 3f ?
  ,0x32, 0x49, 0x79, 0x41, 0x3e // 40 @
  ,0x7e, 0x11, 0x11, 0x11, 0x7e // 41 A
  ,0x7f, 0x49, 0x49, 0x49, 0x36 // 42 B
  ,0x3e, 0x41, 0x41, 0x41, 0x22 // 43 C
  ,0x7f, 0x41, 0x41, 0x22, 0x1c // 44 D
  ,0x7f, 0x49, 0x49, 0x49, 0x41 // 45 E
  ,0x7f, 0x09, 0x09, 0x09, 0x01 // 46 F
  ,0x3e, 0x41, 0x49, 0x49, 0x7a // 47 G
  ,0x7f, 0x08, 0x08, 0x08, 0x7f // 48 H
  ,0x00, 0x41, 0x7f, 0x41, 0x00 // 49 I
  ,0x20, 0x40, 0x41, 0x3f, 0x01 // 4a J
  ,0x7f, 0x08, 0x14, 0x22, 0x41 // 4b K
  ,0x7f, 0x40, 0x40, 0x40, 0x40 // 4c L
  ,0x7f, 0x02, 0x0c, 0x02, 0x7f // 4d M
  ,0x7f, 0x04, 0x08, 0x10, 0x7f // 4e N
  ,0x3e, 0x41, 0x41, 0x41, 0x3e // 4f O
  ,0x7f, 0x09, 0x09, 0x09, 0x06 // 50 P
  ,0x3e, 0x41, 0x51, 0x21, 0x5e // 51 Q
  ,0x7f, 0x09, 0x19, 0x29, 0x46 // 52 R
  ,0x46, 0x49, 0x49, 0x49, 0x31 // 53 S
  ,0x01, 0x01, 0x7f, 0x01, 0x01 // 54 T
  ,0x3f, 0x40, 0x40, 0x40, 0x3f // 55 U
  ,0x1f, 0x20, 0x40, 0x20, 0x1f // 56 V
  ,0x3f, 0x40, 0x38, 0x40, 0x3f // 57 W
  ,0x63, 0x14, 0x08, 0x14, 0x63 // 58 X
  ,0x07, 0x08, 0x70, 0x08, 0x07 // 59 Y
  ,0x61, 0x51, 0x49, 0x45, 0x43 // 5a Z
  ,0x00, 0x7f, 0x41, 0x41, 0x00 // 5b [
  ,0x02, 0x04, 0x08, 0x10, 0x20 // 5c backslash
  ,0x00, 0x41, 0x41, 0x7f, 0x00 // 5d ]
  ,0x04, 0x02, 0x01, 0x02, 0x04 // 5e ^
  ,0x40, 0x40, 0x40, 0x40, 0x40 // 5f _
  ,0x00, 0x01, 0x02, 0x04, 0x00 // 60 `
  ,0x20, 0x54, 0x54, 0x54, 0x78 // 61 a
  ,0x7f, 0x48, 0x44, 0x44, 0x38 // 62 b
  ,0x38, 0x44, 0x44, 0x44, 0x20 // 63 c
  ,0x38, 0x44, 0x44, 0x48, 0x7f // 64 d
  ,0x38, 0x54, 0x54, 0x54, 0x18 // 65 e
  ,0x08, 0x7e, 0x09, 0x01, 0x02 // 66 f
  ,0x0c, 0x52, 0x52, 0x52, 0x3e // 67 g
  ,0x7f, 0x08, 0x04, 0x04, 0x78 // 68 h
  ,0x00, 0x44, 0x7d, 0x40, 0x00 // 69 i
  ,0x20, 0x40, 0x44, 0x3d, 0x00 // 6a j 
  ,0x7f, 0x10, 0x28, 0x44, 0x00 // 6b k
  ,0x00, 0x41, 0x7f, 0x40, 0x00 // 6c l
  ,0x7c, 0x04, 0x18, 0x04, 0x78 // 6d m
  ,0x7c, 0x08, 0x04, 0x04, 0x78 // 6e n
  ,0x38, 0x44, 0x44, 0x44, 0x38 // 6f o
  ,0x7c, 0x14, 0x14, 0x14, 0x08 // 70 p
  ,0x08, 0x14, 0x14, 0x18, 0x7c // 71 q
  ,0x7c, 0x08, 0x04, 0x04, 0x08 // 72 r
  ,0x48, 0x54, 0x54, 0x54, 0x20 // 73 s
  ,0x04, 0x3f, 0x44, 0x40, 0x20 // 74 t
  ,0x3c, 0x40, 0x40, 0x20, 0x7c // 75 u
  ,0x1c, 0x20, 0x40, 0x20, 0x1c // 76 v
  ,0x3c, 0x40, 0x30, 0x40, 0x3c // 77 w
  ,0x44, 0x28, 0x10, 0x28, 0x44 // 78 x
  ,0x0c, 0x50, 0x50, 0x50, 0x3c // 79 y
  ,0x44, 0x64, 0x54, 0x4c, 0x44 // 7a z
  ,0x00, 0x08, 0x36, 0x41, 0x00 // 7b {
  ,0x00, 0x00, 0x7f, 0x00, 0x00 // 7c |
  ,0x00, 0x41, 0x36, 0x08, 0x00 // 7d }
  ,0x10, 0x08, 0x08, 0x10, 0x08 // 7e ~
  ,0x78, 0x46, 0x41, 0x46, 0x78 // 7f DEL
};

Nous allons aussi définir certaines constantes qui nous seront utile par la suite :

// La broche DC permet de dire à l'écran si on envoi une commande ou une donnée
#define LCD_COMMAND LOW
#define LCD_DATA HIGH

// Définir ici la hauteur / largeur de l'écran en pixel
#define LCD_X 84
#define LCD_Y 48

Avant toute chose il nous faut une fonction très bas niveau pour transmettre des octets de commandes ou de données à l’écran :

/* Envoi une commande ou un octet de donnée à l'écran */
void lcd_write(byte mode, byte data) {
  digitalWrite(PIN_DC, mode); // Place DC suivant le mode voulu (COMMAND ou DATA)
  digitalWrite(PIN_SCE, LOW);
  shiftOut(PIN_SDIN, PIN_SCLK, MSBFIRST, data); // Envoi la commande / donnée
  digitalWrite(PIN_SCE, HIGH);
}

Avant d’utiliser l’écran il faut l’initialiser en lui envoyant une séquence « magique » de commandes le faisant passer dans un mode que nous pouvons contrôler.
Voici la fonction qui s’en occupe :

/* Initialise l'écran en envoyant la séquence "magique" d'initialisation au PCD8544 */
void lcd_init(void) {
  // Place les broches de contrôle en sorties
  pinMode(PIN_SCE, OUTPUT);
  pinMode(PIN_RESET, OUTPUT);
  pinMode(PIN_DC, OUTPUT);
  pinMode(PIN_SDIN, OUTPUT);
  pinMode(PIN_SCLK, OUTPUT);

  // Reset l'écran pour être sur de son état intial
  digitalWrite(PIN_RESET, LOW);
  digitalWrite(PIN_RESET, HIGH);

  // Séquence magique
  lcd_write(LCD_COMMAND, 0x21); // Extended Commands
  lcd_write(LCD_COMMAND, 0xBF); // LCD VOP (contrast) - 0xB1 @ 3v3 ou 0xBF @ 5v
  lcd_write(LCD_COMMAND, 0x04); // Temp coefficent
  lcd_write(LCD_COMMAND, 0x14); // LCD bias mode = 1:48
  lcd_write(LCD_COMMAND, 0x20); // Commit change
  lcd_write(LCD_COMMAND, 0x0C); // Display control = normal mode (0x0D pour mode "négatif")
}

Maintenant nous pouvons passer au commandes plus « graphiques », tout d’abord les fonctions d’affichage d’image :

/* Affiche sur l'écran un image stocké en RAM */
void lcd_image_ram(char data[]){
  for (int i = 0 ; i < (LCD_X * LCD_Y / 8) ; i++)
    lcd_write(LCD_DATA, data[i]);
}

/* Affiche sur l'écran un image stocké en PROGMEM */
void lcd_image_flash(prog_uchar *data){
  for (int i = 0 ; i < (LCD_X * LCD_Y / 8) ; i++)
    lcd_write(LCD_DATA, pgm_read_byte_near(data +i));
}

Puis d’affichage de caractéres et de texte :

/* Affiche sur l'écran un caractére passé en argument, avec un colonne vide de "pagination" pour plus de lisibilité */
void lcd_putChar(char chr) {
  lcd_write(LCD_DATA, 0x00); // Colonne vide de pagination
  unsigned int val = (pchr - 0x20) * 5; // 0x20 -> 1er caractéres de notre table ascii
  lcd_write(LCD_DATA, pgm_read_byte_near(asciiTable + val)); 
  lcd_write(LCD_DATA, pgm_read_byte_near(asciiTable + val + 1));
  lcd_write(LCD_DATA, pgm_read_byte_near(asciiTable + val + 2));
  lcd_write(LCD_DATA, pgm_read_byte_near(asciiTable + val + 3));
  lcd_write(LCD_DATA, pgm_read_byte_near(asciiTable + val + 4));
  lcd_write(LCD_DATA, 0x00); // Colonne vide de pagination
}

/* Affiche sur l'écran une chaine de caratéres stocké en RAM */
void lcd_string_ram(char *str) {
  while(*str)
    lcd_putChar(*str++);
}

/* Affiche sur l'écran une chaine de caratéres stocké en PROGMEM */
void lcd_string_flash(prog_char *str) {
  char c = pgm_read_byte_near(str);
  while(c) {
    lcd_putChar(c);
	c = pgm_read_byte_near(++str);
  }
}

Il va aussi nous falloir une fonction pour déplacer le curseur de dessin et une autre fonction pour effacer l’écran :

/* Déplace le curseur aux coordonnées xy donnée en arguments */
void lcd_goto(byte x, byte y) {
  lcd_write(LCD_COMMAND, 0x80 | x);  // Colonne
  lcd_write(LCD_COMMAND, 0x40 | y);  // Ligne
}

/* Efface l'écran */
void lcd_clear() {
  for (int i = 0 ; i < (LCD_X * LCD_Y / 8) ; i++)
    lcd_write(LCD_DATA, 0x00);
  lcd_goto(0, 0); // Place le curseur à (0, 0)
}

Allez on rassemble le tous !

// La broche DC permet de dire à l'écran si on envoi une commande ou une donnée
#define LCD_COMMAND LOW
#define LCD_DATA HIGH

// D�finir ici la hauteur / largeur de l'écran en pixel
#define LCD_X 84
#define LCD_Y 48

/* Envoi une commande ou un octet de donnée à l'écran */
void lcd_write(byte mode, byte data) {
  digitalWrite(PIN_DC, mode); // Place DC suivant le mode voulu (COMMAND ou DATA)
  digitalWrite(PIN_SCE, LOW);
  shiftOut(PIN_SDIN, PIN_SCLK, MSBFIRST, data); // Envoi la commande / donn�e
  digitalWrite(PIN_SCE, HIGH);
}

/* Initialise l'écran en envoyant la séquence "magique" d'initialisation au PCD8544 */
void lcd_init(void) {
  // Place les broches de contrôle en sorties
  pinMode(PIN_SCE, OUTPUT);
  pinMode(PIN_RESET, OUTPUT);
  pinMode(PIN_DC, OUTPUT);
  pinMode(PIN_SDIN, OUTPUT);
  pinMode(PIN_SCLK, OUTPUT);

  // Reset l'écran pour être sur de sont état initial
  digitalWrite(PIN_RESET, LOW);
  digitalWrite(PIN_RESET, HIGH);

  // Séquence magique
  lcd_write(LCD_COMMAND, 0x21); // Extended Commands
  lcd_write(LCD_COMMAND, 0xBF); // LCD VOP (contrast) - 0xB1 @ 3v3 ou 0xBF @ 5v
  lcd_write(LCD_COMMAND, 0x04); // Temp coefficent
  lcd_write(LCD_COMMAND, 0x14); // LCD bias mode = 1:48
  lcd_write(LCD_COMMAND, 0x20); // Commit change
  lcd_write(LCD_COMMAND, 0x0C); // Display control = normal mode (0x0D pour mode "négatif")
}

/* Affiche sur l'écran un image stockée en RAM */
void lcd_image_ram(char data[]){
  for (int i = 0 ; i < (LCD_X * LCD_Y / 8) ; i++)
    lcd_write(LCD_DATA, data[i]);
}

/* Affiche sur l'écran un image stockée en PROGMEM */
void lcd_image_flash(prog_uchar *data){
  for (int i = 0 ; i < (LCD_X * LCD_Y / 8) ; i++)
    lcd_write(LCD_DATA, pgm_read_byte_near(data +i));
}

/* Affiche sur l'écran un caractére passé en argument, avec un colonne vide de "pagination" pour plus de lisibilité */
void lcd_putChar(char pchr) {
  lcd_write(LCD_DATA, 0x00); // Colonne vide de pagination
  unsigned int val = (pchr - 0x20) * 5;
  lcd_write(LCD_DATA, pgm_read_byte_near(asciiTable + val)); 
  lcd_write(LCD_DATA, pgm_read_byte_near(asciiTable + val + 1));
  lcd_write(LCD_DATA, pgm_read_byte_near(asciiTable + val + 2));
  lcd_write(LCD_DATA, pgm_read_byte_near(asciiTable + val + 3));
  lcd_write(LCD_DATA, pgm_read_byte_near(asciiTable + val + 4));
  lcd_write(LCD_DATA, 0x00); // Colonne vide de pagination
}

/* Affiche sur l'écran une chaine de caractéres stocké en RAM */
void lcd_string_ram(char *str) {
  while(*str)
    lcd_putChar(*str++);
}

/* Affiche sur l'écran une chaine de caractéres stocké en PROGMEM */
void lcd_string_flash(prog_char *str) {
  char c = pgm_read_byte_near(str);
  while(c) {
    lcd_putChar(c);
    c = pgm_read_byte_near(++str);
  }
}

/* Déplace le curseur aux coordonnées xy donnée en arguments */
void lcd_goto(byte x, byte y) {
  lcd_write(LCD_COMMAND, 0x80 | x);  // Colonne
  lcd_write(LCD_COMMAND, 0x40 | y);  // Ligne
}

/* Efface l'écran */
void lcd_clear() {
  for (int i = 0 ; i < (LCD_X * LCD_Y / 8) ; i++)
    lcd_write(LCD_DATA, 0x00);
  lcd_goto(0, 0); // Place le curseur à (0, 0)
}

Et maintenant un petit sketch de démo 😉

#include <avr/pgmspace.h>
#include "ascii_table.h"
#include "image.h"

/* Definition des broches du lcd */
#define PIN_SCE   7
#define PIN_RESET 6 
#define PIN_DC    5
#define PIN_SDIN  4
#define PIN_SCLK  3

void setup(void) {
  lcd_init(); // Initialisation de l'écran
  
  lcd_clear(); // Efface l'écran
  lcd_image_flash(awesome); // Affiche le smiley "awesome"
  delay(5000); // Delai de 2sec avant d'afficher le texte
  
  lcd_clear(); // Efface l'écran
  lcd_string_ram("Hello World! (RAM)"); // Affiche "Hello World !"
  delay(5000); // Delai de 2sec avant d'afficher le texte
  
  lcd_clear(); // Efface l'écran
  lcd_string_flash(PSTR("Hello World! (PROGMEM)")); // Affiche "Hello World !"
}

void loop(void) {
  // Rien, c'est juste une démo 😉
}

Et « In Real Life » voila ce que ça donne :

« finger in the nose » hein 😉

Et oui c’est déja la fin de cet article *sniff*, j’ai pas montrer grand chose, juste deux trois fonctions, à vous de trouver les idées qui vont bien pour les utiliser au mieux 😉
Plein de truc marrant sont possible, afficher un gif animé, faire une horloge, … à vous de trouver THE idée 😉

Advertisements

Discussion

67 réflexions sur “[Tutoriel] Arduino + écran de nokia 5110

  1. J’ai justement un 5110 dans mon tiroir.
    Ca va hacker ce week-end
    Je vais l’essayer sur ma Panda II puisque le NetMF intègre un driver SPI.

    Félicitations pour le site, j’adore

    Publié par Barbudor | 1 février 2012, 22 h 53 min
  2. Je m’étonne du branchement. Le PCD 8544 accepte du 3,3V maxi, normalement (la doc dit 2,7 à 3,3V).
    Est-ce que ce montage a survécu ?
    Au passage : le « shiftOut » simule par soft un port SPI. Il semble en effet que les broches du SPI *hard* soient ailleurs, si l’on en croit la doc du Uno. Pareil sur le 2560 (vérifié sur le mien).

    Bonnes manips,

    Publié par Laurent | 4 avril 2012, 17 h 30 min
    • >> Je m’étonne du branchement. Le PCD 8544 accepte du 3,3V maxi, normalement (la doc dit 2,7 à 3,3V).
      >> Est-ce que ce montage a survécu ?
      Il a survécu et il survi toujours, si le câblage était foireux je l’aurai pas publié 😉

      Il y a un convertisseur DC / DC intégré dans le lcd qui s’active ou non suivant la tension d’alimentation.
      Le 3v3 maximum c’est pour la led du rétro éclairage.

      Publié par skywodd | 4 avril 2012, 18 h 51 min
  3. Slt j’arrive pas du tou,même avec ce tuto à utiliser mon écran Nokia 5110 que je viens de recevoir.
    Pouvez vous m’aider s’il vous plaît !!!

    Publié par Fabien | 27 avril 2012, 20 h 46 min
  4. En faite quand je compile il me dit que ASCII n’est pas déclaré et ce même en faisant un copier collé.
    J’ajoute que le câblage est bon et que le rétro éclairage fonctionne.Le but est au niveau du code mais où ?
    De plus je n’arrive pas à faire les manips pour transformer l’image en suite d’octets.ma config est windows xp.
    Au pire pas grave pour l’image mais je veux au moin afficher du texte : )
    P.S:J’ai acheté l’afficheur sur lextronic et je remarque que sur le tient il y à une diode passante aux soudures D1,ce composant est absent sur mon écran alors que je l’ai reçu hier.Est-normale ?

    Publié par Fabien | 28 avril 2012, 8 h 56 min
    • Tu peut mettre ton code sur pastebin avec un commentaire pour situer l’erreur svp ?

      Pour l’image il faut lancer le petit prog dont je donne le lien et rentrer les paramètres comme indiqué, normalement ça marche sans probléme.
      Qu’est ce qui ne marche pas chez toi ?

      Pour la diode c’est bizarre mais je ne pense pas que ce soit critique.

      Publié par skywodd | 28 avril 2012, 9 h 32 min
  5. ok je voudrais bien t’envoyer une capture d’écran mais comment je fais ???

    Publié par Fabien | 28 avril 2012, 9 h 56 min
  6. Ok mais tu sais,je fais le copier collé de ce que tu as écris.De plus,en cherchant un peu sur Google,j’ai réussi à afficher du texte mais pour les images toujours rien.Pourrais tu donner le code qui permet seulement d’afficher l’image ??

    Publié par Fabien | 28 avril 2012, 11 h 30 min
  7. ok je vais essayer

    Publié par Fabien | 28 avril 2012, 13 h 27 min
  8. Et sinon est ce que tu sais comment je peux faire pour afficher une valeur au lieu du texte ?

    Publié par Fabien | 28 avril 2012, 13 h 47 min
  9. Sinon je sais,aucun rapport avec l’écran mais j’ai aussi un capteur infrarouge SHARP GP1U5 que je sais ni brancher ni programmer pour décrypter le signal.Mon but serai d’allumer ou d’éteindre une LED avec une télécommande.Sais-tu comment je peux faire ça ?

    Publié par Fabien | 29 avril 2012, 12 h 23 min
  10. Mais je ne sais pas brancher ce capteur tu peux m’aider ?

    Publié par Fabien | 2 mai 2012, 13 h 30 min
  11. Ok et sais tu s’il il existe une librairie pour le shield jeux vidéo disponible chez sparkfun ou sur l’extronic ?

    Publié par Fabien | 20 mai 2012, 9 h 39 min
  12. ok et pour gérer les nunchuks ?? en faite je voudrais recup les infos accelerometre pour les retranscrire avec des servomoteurs.Mais il me faut recupérer les infos des nunchuks !! Il existe surement une librairie mais la quelle!!!

    Publié par Fabien | 21 mai 2012, 12 h 56 min
  13. J’ai le meme problème 🙂

    Publié par laurent | 21 mai 2012, 12 h 58 min
  14. ok mais il parait qu’il existe une librairie spécial pour ce genre de capteur, je voudrais savoir si c’était vrai, si ça marche pour le shield jeux video de sparkfun, et le nom de la librairie STP.
    PS: Ce site set cool, j’y trouve plein d’aide grâce à toi 🙂

    Publié par Fabien | 29 mai 2012, 12 h 37 min
  15. sais-tu la commande pour afficher une image ou faire un texte en « scroll » grâce à la librairie que tu donnes au début de l’article ?? Y’aurait-il une possibilité d’éffectuer une compatibilité entre la librairie PCD8544 et la librairie liquide crystal ?

    Merci de ton aide

    Publié par Fabien | 14 juillet 2012, 13 h 56 min
    • >> sais-tu la commande pour afficher une image ou faire un texte en “scroll” grâce à la librairie que tu donnes au début de l’article ?

      Non pas de base, pour faire défiler une image il suffit de re-dessiner tout l’écran en décalant le tableau servant à stocker l’image d’une colonne (ou ligne) de n pixels.

      Cf le principe du « buffer circulaire » :
      http://fr.wikipedia.org/wiki/Buffer_circulaire
      (ici en lecture uniquement)

      >> Y’aurait-il une possibilité d’effectuer une compatibilité entre la librairie PCD8544 et la librairie liquide crystal ?

      Non les deux sont beaucoup trop différente d’un point de vue matériel et logiciel.
      Tu ne pourras pas trouver d’équivalence entre les fonctions des deux librairies pour en faire une troisième qui serait un mélange.

      Publié par skywodd | 14 juillet 2012, 14 h 18 min
  16. ca fait cher Sparkfun avec les frais de port

    Publié par Simon | 3 juillet 2013, 13 h 54 min
  17. Salut, je reviens t’embêter une dernière fois puisque je n’arrive pas a utiliser la fonction lcd.drawBitmap de la librairie dont tu donnes le lien. En fait je marque ça : lcd.drawBitmap(awesome, 0, 0);
    Et l’erreur est celle ci : invalid conversion from ‘char*’ to ‘const unsigned char*’

    Je t’envoie le code dès que je suis sur mon Pc.

    Publié par Fabien | 8 juillet 2013, 11 h 05 min
  18. Bonjour, je souhaiterais mettre cet écran sur un système d’arrosage automatique que j’ai démarré, mais mon pin 5v et le 3.3 sont déja utilisé par un relais ainsi qu’un capteur d’humidité, comment puis-je alimenter l’écran? merci!

    Romain.

    Publié par Romain | 13 juillet 2013, 17 h 50 min
    • Je ne suis pas tres sur que cela soit judiscieux d’alimenter un relais directement avec la carte , ta carte alimenterait elle un shield qui lui pilote un relais ?? Ensuite , il n’y a pas de soucis pour alimenter l’ecran , car il consomme peut , moi meme je l’ai inclu dans un montage avec pas mal de Led et de l’electronique externe , cela n’a pas posé de probleme …

      Publié par Laurent | 7 décembre 2013, 18 h 28 min
  19. Hum pas vraiment Finger in the noze … JE viens de m’arracher le peut de cheveux qu’il me reste a essayer de debugger le sketch , il y a des trucs que je ne pige pas … ( j’ai fait un copy/paste des bout de code , mais il y a des variables qui ne sont pas definies , ascii_table.h serait il un fichier que l’on doit creer et poser dans le repertoire du sketch ? Egalement la carte hexa du smile aussi ? Quand a ../avr/pgmspace.h j’ai beau faire un find sur mon PC impossible de le trouver … pourrais tu m’en dire d’avantage la dessus ? LOL …
    ca ne doit pas etre grand chose , mais voila j’apprend le maniement de ce petit ecran et je m’eclate comme un fou , d’autant que la en plus je tourne avec un ecran de 3410 fonctionnel donc il va me falloire adapter la resolution de 84×48 vers 96×65 et faire la modif partout ou il y a lieu d’en faire 🙂 mais bon faudrait deja que le code source soit d’equerre 🙂
    En attendant de te lire a nouveau , merci pour les Infos 😉

    Publié par Laurent | 7 décembre 2013, 22 h 22 min
    • Edit du post Au dessus :
      Finalement si ca va , je m’en suis sortis, en fouillant dans les librairies pour trouver l’origine des fonctions ( lcd_clear();, setBitmap etc etc ).
      Je pense que je vais pouvoir avancer sur le reste du projet , ca me parait moins enorme 🙂
      Et J’avoue la qualité d’affichage du 3410 , et bien sympas , mis a part peut etre le fait que si j’utilise des array ( pour les images ), en byte() ET en progmem en meme temps , la seconde image est legerement altérée , genre la derniere ligne ne se fini pas , alors que c’est une ligne droite … Gros mistere , mais je pense que le jeux de commande du 3410 differe un peut du 5110 car je n’arrive pas a regler le contraste …

      Publié par Dj_Garfield | 12 décembre 2013, 3 h 27 min
      • Le jeu de commandes doit être commun pour les trucs vraiment de bases mais pour le reste il y a forcément des différences propres à chaque écran.

        Publié par skywodd | 15 décembre 2013, 12 h 47 min
  20. Je suis tombé par hasard sur la librairie : U8G , et Woaw … ca tourne du tonnerre !
    En fait je suis un Gros boulet , je suis resté sur une Info qui parlait d’une resolution « ecran » de 102×72 , alors que le 3410 est un 96×65 , du coup essayer d’envoyer un array de 102×72/8=918 sur un ecran qui ne supporte que 95×64/8=760 ca a du mal a passer 🙂 Raison pour laquelle je devais faire des images en 102×72 , et ne dessiner que sur une surface de 95×64 . Et puis je suis tombé sur la librairie U8G , et la je me suis appercu qu’il y avait le PCF8812 , j’ai fouillé dans les datasheets .. et hooo surprise , le PCF8812 drive une matrice de 95×64 … j’ai testé et youpy ! en fait j’avais tout faux des le depart a ne pas regarder plus loin que la queue d’une resistance.
    Je me suis fié a la majorité des post dans des fofo qui a priori n’ont pas forcement été verifié ou testé en cas concret , sauf ici ou j’ai eu les bonnes pistes pour fouiller le web en quete d’info 🙂 ici ou sur le forum arduino.cc Krr Krrr Krr 😉

    Publié par Dj_Garfield | 16 décembre 2013, 1 h 28 min
    • oups , il va falloire que j’aille dormir un peut je m’emboruille avec mes notes : NOKIA 3410 : PCF8814 mais la librairie PCF8812 fonctionne car ils sont sensiblement les memes , a la seul difference : PCF8812 = 95×65 ( et pas 64 pffff someil ), et le PCF8814 : 102×65 on y arrive , et la je vais me pieuter je suis HS !!

      Publié par Dj_Garfield | 16 décembre 2013, 1 h 41 min
  21. Merci pour ce tuto !
    propre et net impec !

    perso j’ai changé l’ordre de lecture de lcd_write pour les données pour que le 1er bit envoyé au LCD soit le premier pixel – c’est plus facile pour moi lorsque je modifi les valeur en hexa :

    shiftOut(PIN_SDIN, PIN_SCLK, MSBFIRST, data); // Envoi la commande / donnée

    est devenue

    if(LCD_COMMAND == mode)
    shiftOut(PIN_SDIN, PIN_SCLK, MSBFIRST, data); // Envoi la commande
    else
    shiftOut(PIN_SDIN, PIN_SCLK, LSBFIRST, data); // Envoi la donnée

    ca retourne le texte et les images du tuto mais ca permet de dessiner en brut (je me pencherait sur les lib haut niveau plus tard .. )

    TFlorian

    Publié par Tflorian | 18 décembre 2013, 0 h 11 min
  22. Bonjour !

    Tout d’abord super article, merci beaucoup ! J’ai donc utilisé ton code. Tout fonctionne bien … sauf que j’ai un rectangle plein (noir plus clair) qui s’affiche tout le temps sur presque tout l’écran. Il y a juste une marge de qqs pixels tout autour. L’image s’affiche dans ce rectangle, et les chaines de caractères aussi.

    Est-ce un problème électronique ? Ou une config dans le code à faire ?

    Merci beaucoup !

    Publié par Anthony | 2 janvier 2014, 23 h 00 min
  23. Bonjour,

    Merci pour cet article.
    Ce blog est un vrai plaisir : bien écrit, bien documenté.

    Concernant le nokia5110, j’ai le problème suivant : je peux seulement écrire sur la partie inférieure de mon écran.
    C.a.d que les lignes 0,1,2 restent vierges mais que les lignes 3,4,5 fonctionnent correctement (mon ‘hello world’ apparait).
    Même le contraste sur la partie supérieure semble absent comme si l’écran était éteint sur cette partie ?

    J’ai mis mon code ici : http://pastebin.com/JPukukJk .
    Mon écran est celui ci : http://dx.com/p/140226 .

    Ma borne led est branchée sur le 3.3v, mon vcc sur le 5v.
    J’ai soudé les pattes de mon composant moi même : c’est pas super propre mais je n’ai pas l’impression que ce soit la source de mon problème.

    Voila, toute aide est la bienvenue 🙂

    Cordialement,
    Erwan

    Publié par erwan l (@erwan2212) | 24 février 2014, 10 h 12 min
    • T’as testé avec une autre carte arduino ?
      A mon avis t’est juste tomber sur un écran HS.

      Fait une demande de RMA à DealExtreme avec une photo du problème, il te le remplacerons 😉

      Publié par skywodd | 1 mars 2014, 16 h 19 min
  24. very good tutorial.
    i need to repair my nokia 5110.
    my old and lovely phone, hahaha…

    Publié par Halra | 29 mars 2014, 7 h 17 min
  25. Bonjour,

    Juste pour faire avancer le truc…
    J’avais un contraste extrêmement fort, bref on voyait rien.
    J’avait bien changer la valeur suivant le voltage (je suis en 5V) mais les 2 valeurs préconisées ne donnaient rien.
    J’ai donc mis 0xA0. Et nickel 🙂

    Publié par phenix | 15 avril 2014, 0 h 07 min
  26. Salut
    J ai suivit ton tutoriel bien mené j’ai tout compris à un détail prés dans ton code final (après ton « Et maintenant un petit sketch de démo ») tu appelle l’image et le texte qui ont ete tous les deux définis par les tables au début mais a quel moment on les envois dans l’arduino? Est ce qu il faut copier ces tables en début du programme?
    Merci

    Publié par Dalton | 16 avril 2014, 21 h 22 min
    • Si tu veut afficher du texte le second tableau est obligatoire, sinon le 1er est juste là pour l’image.
      Pas besoin de copier un tableau si tu ne l’utilise pas dans le code.

      Regarde dans le setup() pour voir où est comment j’utilise les tableaux 😉

      Publié par skywodd | 21 avril 2014, 14 h 50 min
  27. Bonjour skywodd, je voudrais connecter un écran lcd graphique sur ma carte Arduino Ethernet rev 3, je voulais savoir si ton écran (nokia 5110) pouvais se connecter dessus, en effet j’ai remarqué sur les sites internet que ce dernier utilisait une interface SPI qui est déjà reservée par le port ethernet de ma carte arduino (broche 10, 11, 12 et 13 et 4 pour la SD Card) donc ma question est : est-ce qu’il y a une possibilité de le connecter quand même ?? si oui, comment faire ?? si non, si ta une autre solution avec un glcd solide qui utilise une communication i²c par exemple, ca sera sympa (car je ne peux pas travailler avec un écran qui communique en parallèle vu que j’utilise quasiment toute les broches de ma carte)

    Merci.

    Publié par Ferhat Drum | 2 mai 2014, 9 h 33 min
  28. Salut,
    j’utilise un arduino Uno R3, un lcd 5110 que j’ai pû testé avec un programme « texte » classique.
    J’ai copié ton code dans le sketch de l’arduino et lorsque je le compile, j’ai des messages d’erreur.
    Voilà le code que j’ai: http://pastebin.com/ZziqFxZ3
    Et les messages: sketch_oct05a.ino:231:24: error: asciiTable.h: No such file or directory
    sketch_oct05a.ino:232:19: error: image.h: No such file or directory
    Peux-tu m’aider à trouver d’où viens mon problème?
    Merci.

    Publié par texs | 5 octobre 2014, 18 h 11 min
    • Bonjour,
      le code demande des fichiers asciiTable.h et image.h
      ces fichiers sont demandés grace aux instruction « includes » :
      de la demo :
      #include « ascii_table.h »
      #include « image.h »

      Il faut soit les crées (idéalement) -> leur contenus est cités plus an amon dans la page « Avec l’image d’exemple de sparkfun (le smiley awesome) cela donne ceci  » pour le fichier « image.h » et juste dessous « il va nous falloir afficher du texte, soit des caractéres » c’est le fichier « ascii_table.h »

      l’autre solution plus sal car moins lisible c’est de coller les gros tableau definis jusqu’a la fermeture « } »
      PROGMEM prog_uchar awesome[] = {
      PROGMEM prog_uchar asciiTable[] = {

      ca devrait marcher …

      TFlorian

      Publié par TFlorian | 5 octobre 2014, 20 h 41 min
      • j’oubliais de présiser qu’il faut retirer
        #include « asciiTable.h »
        #include « image.h »

        dans le code lorsque on fusionne tout …
        => c’est ce que tu as oublié de faire semble t’il

        Publié par TFlorian | 5 octobre 2014, 20 h 42 min
    • Le tableau avec « asciitable » -> à mettre dans un fichier nommé « asciiTable.h »
      Le tableau avec l’image -> à mettre dans un fichier nommé « image.h »
      C’est pas sensé être tout à la suite dans un même fichier.

      Publié par Skywodd | 6 octobre 2014, 19 h 16 min
  29. Bonjour et merci pour ce tuto. Vraiment excellent !
    Impossible de trouver le moyen d’inserer des caractères spéciaux. J’aimerai étendre la table ascii jusqu’a 255 même s’il faut redessiner chaque caractère.. Pouvez vous m’aider ?

    Publié par damien | 13 janvier 2015, 2 h 03 min
    • Bonjour Damien,
      ce n’est pas très compliqué d’étendre la table de caractère

      Approche pour comprendre le fonctionnement :
      prenons un exemple simple avec
      // Table ascii des carateres, sur 5 pixels de large par 8 pixels de haut
      PROGMEM prog_uchar asciiTable[] = {

      maintenant prenons un cas d’école :
      ,0x00, 0x00, 0x5f, 0x00, 0x00 // 21 !

      tu trouve 5 « mots » de 8 bits (donc un octet)
      Chaque mot correspond donc à une colonne de ton caractère
      on vois dans la cas d’école 0x00 -> donc tout est à 0 (chaque bit est à 0) -> on retrouve cela 4 fois donc il ne reste qu’un mot à étudier : 0x5F
      si on regarde le commentaire on vois que c’est le point d’exclamation … donc une série de pixel au noir et un transparent …
      si on utilise la calculatrice (en mode scientifique) de windows pour convertir 5f en binaire on a 0101 1111
      Vue que le mot est écrit en colonne (c’est dis dans la définition de la table : 5 pixels de large par 8 pixels de haut – un mot fait 8bits donc c’est par déduction et analogie avec le caractère « ! » que on trouve que chaque mot fait une colonne du caractère )
      et si on lit le mot avec le bit de poids faible en premier on a alors :
      1 -> H
      1 -> H
      1 -> H
      1 -> H
      0 ->
      1 -> H
      0 ->

      bon .. c’est « cool » de faire des barres .. mais ca vas vite devenir galère de dessiner vraiment les caractères …
      après on a envie d’aller vite .. et là j’ai chercher un truc tout fait (une application) .. après deux recherches j’ai trouvé ce lien :
      http://tiptopboards.free.fr/arduino_forum/viewtopic.php?f=2&t=21
      (je me sent un peu ridicule avec mon explication du coup .. 😦 )

      il propose l’utilisation de l’application LCDAssistant :
      http://en.radzio.dxp.pl/bitmap_converter/

      j’ai testé en créant une image de 5×8 pixel en noir et blanc avec paint (utilisation du zoom personnalisé 800% pour voir ce que je faisais) .
      j’ai enfin demander de générer la sortie et hop j’ai mon caractère 🙂

      const unsigned char test [] = {
      0x81, 0x7E, 0x81, 0x7E, 0x81,
      };

      ca e fait un caractère (une image dans mon cas )
      H_H_H
      _H_H_
      _H_H_
      _H_H_
      _H_H_
      _H_H_
      _H_H_
      H_H_H

      J’espère avoir été claire …
      (si ce n’est pas le cas, toute mes excuses.. -> merci de me préciser ce qui n’est pas claire que j’y revienne 😉 )

      TFlorian.

      Publié par TFlorian | 13 janvier 2015, 20 h 35 min
      • Le plus simple c’est de faire une image bitmap de 5 pixels de large et 256 * 8 pixels de haut (soit 5 x 2048 pixels), de dessiner chaque lettres possibles dedans (une lettre = 5 x 8 pixels) et pour finir d’utiliser bitmap_converter (lien au dessus) pour convertir le tout en binaire.
        A noter que les 32 première emplacement (0x00 à 0x20) sont inutiles et non inclut dans la table de l’article, c’est des caractères ASCII de contrôle non imprimable.

        Pour ceux que ça intéresse voici une image bitmap de base pour faire sa propre table ASCII graphique : https://dl.dropboxusercontent.com/u/53604363/ascii_table.bmp
        Et le code python qui l’a généré :

        # Coded with/for python 3.x only
        
        from PIL import Image
        
        # Base ASCII table for import
        # Format: 5x8 pixels per character
        ASCII_TABLE = [
            0x00, 0x00, 0x00, 0x00, 0x00, # 0x20 SPACE
            0x00, 0x00, 0x5f, 0x00, 0x00, # 0x21 !
            0x00, 0x07, 0x00, 0x07, 0x00, # 0x22 "
            0x14, 0x7f, 0x14, 0x7f, 0x14, # 0x23 #
            0x24, 0x2a, 0x7f, 0x2a, 0x12, # 0x24 $
            0x23, 0x13, 0x08, 0x64, 0x62, # 0x25 %
            0x36, 0x49, 0x55, 0x22, 0x50, # 0x26 &
            0x00, 0x05, 0x03, 0x00, 0x00, # 0x27 '
            0x00, 0x1c, 0x22, 0x41, 0x00, # 0x28 (
            0x00, 0x41, 0x22, 0x1c, 0x00, # 0x29 )
            0x14, 0x08, 0x3e, 0x08, 0x14, # 0x2a *
            0x08, 0x08, 0x3e, 0x08, 0x08, # 0x2b +
            0x00, 0x50, 0x30, 0x00, 0x00, # 0x2c ,
            0x08, 0x08, 0x08, 0x08, 0x08, # 0x2d -
            0x00, 0x60, 0x60, 0x00, 0x00, # 0x2e .
            0x20, 0x10, 0x08, 0x04, 0x02, # 0x2f /
            0x3e, 0x51, 0x49, 0x45, 0x3e, # 0x30 0
            0x00, 0x42, 0x7f, 0x40, 0x00, # 0x31 1
            0x42, 0x61, 0x51, 0x49, 0x46, # 0x32 2
            0x21, 0x41, 0x45, 0x4b, 0x31, # 0x33 3
            0x18, 0x14, 0x12, 0x7f, 0x10, # 0x34 4
            0x27, 0x45, 0x45, 0x45, 0x39, # 0x35 5
            0x3c, 0x4a, 0x49, 0x49, 0x30, # 0x36 6
            0x01, 0x71, 0x09, 0x05, 0x03, # 0x37 7
            0x36, 0x49, 0x49, 0x49, 0x36, # 0x38 8
            0x06, 0x49, 0x49, 0x29, 0x1e, # 0x39 9
            0x00, 0x36, 0x36, 0x00, 0x00, # 0x3a :
            0x00, 0x56, 0x36, 0x00, 0x00, # 0x3b ;
            0x08, 0x14, 0x22, 0x41, 0x00, # 0x3c <
            0x14, 0x14, 0x14, 0x14, 0x14, # 0x3d =
            0x00, 0x41, 0x22, 0x14, 0x08, # 0x3e >
            0x02, 0x01, 0x51, 0x09, 0x06, # 0x3f ?
            0x32, 0x49, 0x79, 0x41, 0x3e, # 0x40 @
            0x7e, 0x11, 0x11, 0x11, 0x7e, # 0x41 A
            0x7f, 0x49, 0x49, 0x49, 0x36, # 0x42 B
            0x3e, 0x41, 0x41, 0x41, 0x22, # 0x43 C
            0x7f, 0x41, 0x41, 0x22, 0x1c, # 0x44 D
            0x7f, 0x49, 0x49, 0x49, 0x41, # 0x45 E
            0x7f, 0x09, 0x09, 0x09, 0x01, # 0x46 F
            0x3e, 0x41, 0x49, 0x49, 0x7a, # 0x47 G
            0x7f, 0x08, 0x08, 0x08, 0x7f, # 0x48 H
            0x00, 0x41, 0x7f, 0x41, 0x00, # 0x49 I
            0x20, 0x40, 0x41, 0x3f, 0x01, # 0x4a J
            0x7f, 0x08, 0x14, 0x22, 0x41, # 0x4b K
            0x7f, 0x40, 0x40, 0x40, 0x40, # 0x4c L
            0x7f, 0x02, 0x0c, 0x02, 0x7f, # 0x4d M
            0x7f, 0x04, 0x08, 0x10, 0x7f, # 0x4e N
            0x3e, 0x41, 0x41, 0x41, 0x3e, # 0x4f O
            0x7f, 0x09, 0x09, 0x09, 0x06, # 0x50 P
            0x3e, 0x41, 0x51, 0x21, 0x5e, # 0x51 Q
            0x7f, 0x09, 0x19, 0x29, 0x46, # 0x52 R
            0x46, 0x49, 0x49, 0x49, 0x31, # 0x53 S
            0x01, 0x01, 0x7f, 0x01, 0x01, # 0x54 T
            0x3f, 0x40, 0x40, 0x40, 0x3f, # 0x55 U
            0x1f, 0x20, 0x40, 0x20, 0x1f, # 0x56 V
            0x3f, 0x40, 0x38, 0x40, 0x3f, # 0x57 W
            0x63, 0x14, 0x08, 0x14, 0x63, # 0x58 X
            0x07, 0x08, 0x70, 0x08, 0x07, # 0x59 Y
            0x61, 0x51, 0x49, 0x45, 0x43, # 0x5a Z
            0x00, 0x7f, 0x41, 0x41, 0x00, # 0x5b [
            0x02, 0x04, 0x08, 0x10, 0x20, # 0x5c BACKSLASH
            0x00, 0x41, 0x41, 0x7f, 0x00, # 0x5d ]
            0x04, 0x02, 0x01, 0x02, 0x04, # 0x5e ^
            0x40, 0x40, 0x40, 0x40, 0x40, # 0x5f _
            0x00, 0x01, 0x02, 0x04, 0x00, # 0x60 `
            0x20, 0x54, 0x54, 0x54, 0x78, # 0x61 a
            0x7f, 0x48, 0x44, 0x44, 0x38, # 0x62 b
            0x38, 0x44, 0x44, 0x44, 0x20, # 0x63 c
            0x38, 0x44, 0x44, 0x48, 0x7f, # 0x64 d
            0x38, 0x54, 0x54, 0x54, 0x18, # 0x65 e
            0x08, 0x7e, 0x09, 0x01, 0x02, # 0x66 f
            0x0c, 0x52, 0x52, 0x52, 0x3e, # 0x67 g
            0x7f, 0x08, 0x04, 0x04, 0x78, # 0x68 h
            0x00, 0x44, 0x7d, 0x40, 0x00, # 0x69 i
            0x20, 0x40, 0x44, 0x3d, 0x00, # 0x6a j 
            0x7f, 0x10, 0x28, 0x44, 0x00, # 0x6b k
            0x00, 0x41, 0x7f, 0x40, 0x00, # 0x6c l
            0x7c, 0x04, 0x18, 0x04, 0x78, # 0x6d m
            0x7c, 0x08, 0x04, 0x04, 0x78, # 0x6e n
            0x38, 0x44, 0x44, 0x44, 0x38, # 0x6f o
            0x7c, 0x14, 0x14, 0x14, 0x08, # 0x70 p
            0x08, 0x14, 0x14, 0x18, 0x7c, # 0x71 q
            0x7c, 0x08, 0x04, 0x04, 0x08, # 0x72 r
            0x48, 0x54, 0x54, 0x54, 0x20, # 0x73 s
            0x04, 0x3f, 0x44, 0x40, 0x20, # 0x74 t
            0x3c, 0x40, 0x40, 0x20, 0x7c, # 0x75 u
            0x1c, 0x20, 0x40, 0x20, 0x1c, # 0x76 v
            0x3c, 0x40, 0x30, 0x40, 0x3c, # 0x77 w
            0x44, 0x28, 0x10, 0x28, 0x44, # 0x78 x
            0x0c, 0x50, 0x50, 0x50, 0x3c, # 0x79 y
            0x44, 0x64, 0x54, 0x4c, 0x44, # 0x7a z
            0x00, 0x08, 0x36, 0x41, 0x00, # 0x7b {
            0x00, 0x00, 0x7f, 0x00, 0x00, # 0x7c |
            0x00, 0x41, 0x36, 0x08, 0x00, # 0x7d }
            0x10, 0x08, 0x08, 0x10, 0x08, # 0x7e ~
            0x78, 0x46, 0x41, 0x46, 0x78, # 0x7f DEL
        ]
        
        ASCII_UNKNOWN = [
            0, 0, 0, 0, 0,
            0, 255, 255, 255, 0,
            0, 255, 255, 255, 0,
            0, 255, 255, 255, 0,
            0, 255, 255, 255, 0,
            0, 255, 255, 255, 0,
            0, 255, 255, 255, 0,
            0, 0, 0, 0, 0
        ]
        
        ASCII_UNSET = [
            0, 0, 0, 255, 0,
            0, 255, 255, 255, 0,
            0, 255, 255, 255, 0,
            0, 255, 255, 255, 0,
            0, 255, 255, 255, 0,
            0, 255, 255, 255, 0,
            0, 255, 255, 255, 0,
            0, 255, 0, 0, 0
        ]
        
        # ASCII table sanity assertion
        assert (0 == len(ASCII_TABLE) % 5), 'ASCII_TABLE must be a multiple of 5!'
        
        # Output image size
        IMG_SIZE = 5, 256 * 8
        ## 5x8 pixels per character, 8 bits character codes space
        ## Caracters 0-31 are ASCII control codes (can be used for custom char)
        ## Caracters 32-127 are standard ASCII codes
        ## Caracters 128-255 are extended ASCII codes
        
        # Create the output B&W image (white filled by default)
        output_img = Image.new('L', IMG_SIZE, 'white')
        
        # Fill the 0-31 ASCII control char codes space white black
        output_img.putdata(ASCII_UNKNOWN * 32)
        
        def compile_ASCII_char(c1, c2, c3, c4, c5):
            """ Turn 5 bytes into a 5x8 pixels B&W image data array """
            result = []
            for bit_index in range(0, 8):
                bit_mask = 1 << bit_index
                result.append(255 if c1 & bit_mask else 0)
                result.append(255 if c2 & bit_mask else 0)
                result.append(255 if c3 & bit_mask else 0)
                result.append(255 if c4 & bit_mask else 0)
                result.append(255 if c5 & bit_mask else 0)
            return result
        
        def compiled_ASCII_table():
            """ Turn the whole ASCII_TABLE array into a big B&W image data array """
            result = []
            for index in range(0, len(ASCII_TABLE), 5):
                c1 = ASCII_TABLE[index]
                c2 = ASCII_TABLE[index + 1]
                c3 = ASCII_TABLE[index + 2]
                c4 = ASCII_TABLE[index + 3]
                c5 = ASCII_TABLE[index + 4]
                result.extend(compile_ASCII_char(c1, c2, c3, c4, c5))
            return result
        
        # Fill the 32-127 ASCII char codes space with the ASCII_TABLE
        ASCII_TABLE_BOX = (0, 31 * 8, 5, ((len(ASCII_TABLE) // 5) + 31) * 8)
        ascii_table_part = output_img.crop(ASCII_TABLE_BOX)
        ascii_table_part.putdata(compiled_ASCII_table())
        output_img.paste(ascii_table_part, ASCII_TABLE_BOX)
        
        # Fill the 128-255 ASCII char codes space with B&W cross
        ASCII_USER_TABLE_BOX = (0, ((len(ASCII_TABLE) // 5) + 31) * 8, 5, 256 * 8)
        ascii_user_table_part = output_img.crop(ASCII_USER_TABLE_BOX)
        ascii_user_table_part.putdata(ASCII_UNSET * 128)
        output_img.paste(ascii_user_table_part, ASCII_USER_TABLE_BOX)
        
        output_img.save('ascii_table.bmp', 'BMP')
        output_img.show()
        

        Publié par Skywodd | 14 janvier 2015, 11 h 05 min
      • Merci à Skywodd pour l’idée de l’image en un seul morceau !

        J’ai fait un script php (exécuté avec easyphp) pour faire les image de 5 x 2048 à partir des polices windows ..
        bon .. ca fait des PNG donc il faut convertir en BMP monochrome avant de donner à bitmap_converter .. :-S
        et je trouve le résultat médiocre a mon idée.. mais ca fait une base ….

        Pour le resultat voici ce que me donne de l’arial et du courier
        http://floriantmonsite.free.fr/ PourSkyduino/arial.png
        http://floriantmonsite.free.fr/ PourSkyduino/test_courier6.png
        http://floriantmonsite.free.fr/ PourSkyduino/test_courier7.png
        Edit de skywodd: J’ai volontairement ajouté un espace pour empêcher wordpress d’afficher les images directement dans le commentaire.

        Pour les intéréssés voici le code PHP :

        <?php
        //source basé sur http://php.net/manual/fr/function.imagettftext.php
        // Définition du content-type
        header('Content-Type: image/png');

        // Création de l'image
        $im = imagecreatetruecolor(5, 2048);//imagecreatetruecolor(largeur,hauteur)

        // Création de quelques couleurs
        $white = imagecolorallocate($im, 255, 255, 255);
        $black = imagecolorallocate($im, 0, 0, 0);
        //clean le buffuer
        imagefilledrectangle($im, 0, 0, 49, 2047, $white);

        // copier la police dans le même dossier que le script php
        $font = 'arial.ttf';

        // Ajout du texte
        $posX=0;
        $posy=10;
        $indideLettre=1;
        //parcour l'ensemble des lettre
        while($indideLettre++

        Ce code peut bien sur être utilisé pour faire des textes plus gros.. (il faut alors augmenter la taille de l’image (imagecreatetruecolor), la taille du remplissage (imagefilledrectangle), la taille du texte et l’incrément de position (respectivement le 6 et le 8 de imagettftext) )

        TFlorian

        Publié par TFlorian | 14 janvier 2015, 22 h 19 min
      • A voir ce que ça donnerait avec python + module PIL en rendu de police :
        http://pillow.readthedocs.org/en/latest/reference/ImageFont.html

        En général les polices sont générées à partir d’une sorte de format vectoriel. Sans antialiasing, en pure pixel N&B, ça risque de donner des trucs ignobles.

        Publié par Skywodd | 14 janvier 2015, 22 h 25 min
      • Bon j’arrive pas à faire mieux que ça : https://dl.dropboxusercontent.com/u/53604363/ascii_table_cour.ttf.bmp
        (j’ai utilisé la police « courrier » car chaque caractère fait la même taille)

        Conclusion : rien ne vaut une police « pixel perfect » fait main.

        Le code :

        # Coded with/for python 3.x only
        
        from os.path import basename
        from PIL import Image, ImageFont, ImageDraw
        
        def get_font_size(font_name, font_size):
            """ Get the given font size in pixels """
        
            # Load the TrueType font
            font = ImageFont.truetype(font_name, font_size)
        
            # Render and get size of 'a' and 'A', then check for difference in size
            s1 = font.getsize('a')
            s2 = font.getsize('A')
            if s1 != s2:
                print("Warning: non constant size font!")
                return [s1, s2]
            else:
                return s1
        
        def render_font(font_name, font_size=9, expected_font_size_px=(5,8)):
            """" Render the given font to bitmap """
            
            # Load the TrueType font
            font = ImageFont.truetype(font_name, font_size)
        
            # Assert char size
            assert font.getsize('a') == expected_font_size_px, "Bad font size :("
        
            # Output image size
            IMG_SIZE = expected_font_size_px[0], 256 * expected_font_size_px[1]
        
            # Create the output B&W image (white filled by default)
            output_img = Image.new('1', IMG_SIZE, 'white')
             
            # Fill the 32-255 ASCII char codes space with the Fonnt TTF data
            img_draw = ImageDraw.Draw(output_img)
            x, y = 0, 0
            for ascii_code in range(0, 256):
                img_draw.text((x, y), chr(ascii_code), font=font, fill='black')
                y += expected_font_size_px[1]
        
            # Save the resulting image
            output_img.save('ascii_table_%s.bmp' % basename(font_name), 'BMP')
            output_img.show()
        
        # Demo code
        if __name__ == '__main__':
            render_font("cour.ttf", 9, (5,8))
        

        Publié par Skywodd | 14 janvier 2015, 23 h 15 min
  30. Merci à vous 2
    Je me suis surement mal exprimé car j’ai réussi à faire tout ce qui est expliqué dans ce tuto. J’ai créé des petites icones de 1 ou plusieurs caractères. Pas de problème… Cependant je n’arrive pas à ajouter des caractères spéciaux dans la table « asciiTable[] ». Pour l’utiliser avec lcd_putChar(‘é’) ou lcd_string_ram(« évènement »). Bon je sais qu’il faut passer en référence un objet char *, mais bon vous m’avez compris 😉
    Encore merci et continuez comme ca

    Publié par damien | 15 janvier 2015, 0 h 51 min
    • Pour utiliser un caractère spécial dans toute la plage 0-255, transforme void lcd_putChar(char chr) en void lcd_putChar(unsigned char chr) puis utilise directement le code ASCII du caractère voulu.
      NB Il faudra bien sur qu’il soit présent dans la table, sinon ça ne marchera pas.

      Exemple :
      lcd_putChar(‘é’) -> lcd_putChar(130)

      Publié par Skywodd | 15 janvier 2015, 11 h 29 min
  31. Bonjour,
    je voudrai savoir comment peut on agrandir les caracteres.
    Merci pour vos tuto

    Publié par Simon | 13 mars 2015, 23 h 12 min
    • Bonjour Simon,
      dans l’idée il faut reprendre et essayer de comprendre mon post à Damien https://skyduino.wordpress.com/2012/01/24/tutoriel-arduino-ecran-de-nokia-5110/?replytocom=6001#comment-5765 et le lien http://tiptopboards.free.fr/arduino_forum/viewtopic.php?f=2&t=21 qui explique comment sont afficher les textes

      a cela il faut prendre en compte le fonctionnement de l’afficheur.

      Il me semble « relativement » simple de faire une image (enfin une lettre) de 10 pixel de large et 16 pixel de haut.
      mais pour cela il faut écrire les lettres en deux fois (et faire des déplacements)

      Le problème :
      l’afficheur travaille sur 8 bis (8 pixel de haut) , si on veut agrandir de 1 pixel de plus en hauteur le texte, il faut « revenir à la ligne » pour terminer la lettre.
      => il est donc plus simple de faire des lettre de 8 pixel de haut que de 9 et il est plus simple de faire des lettre de 16 pixel de haut que de 9 (car on peut écraser ce qui est derrière le texte sans se poser de question si la lettre fait 16 alors que ce n’est pas « logique » de le faire si elle fait 9)

      L’approche :
      tu vas commencer à écrire la partie du haut d’une lettres (10 * 8 bits)
      déplacer le pointeur « au bon endroit » en dessous
      puis écrire la partie du bas de la lettre (10 * 8 bits)
      enfin te repositionner « au bon endroit » à la suite pour le caractère suivant
      il te faut aussi régénérer l’ensemble de la table de caractère

      => déjà test avec une image pour savoir si un texte composé de lettre de 16 pixel de haut et 10 de large n’est pas trop gros pour ton utilisation

      TFlorian

      Publié par TFlorian | 14 mars 2015, 8 h 45 min
    • Pour agrandir la taille des caractères, il faut refaire complètement le tableau de caractères/pixels. C’est pas un truc trivial à faire.

      Publié par Skywodd | 17 mars 2015, 13 h 20 min

Rétroliens/Pings

  1. Pingback: Outils, services, sites à (re)découvrir 2012 S04 | La Mare du Gof - 29 janvier 2012

  2. Pingback: Bombeduino – un gadget Airsoft DIY | Le Petit Monde de Galaad - 29 juillet 2013

  3. Pingback: Console-z | Electroshock - 2 août 2013

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.