lundi 2 décembre 2013

Afficheur Alphanumérique (bonus python)













Dans un précédent billet, on a vu comment s'interfacer avec l'afficheur LCD 2x16 caractères depuis un code écrit en C. On va maintenant s'intéresser à un module python pour afficher des informations sur l'afficheur.
L'un des principaux avantages du python par rapport au langage C est que l'on a pas besoin de compiler le code pour le lancer sur la raspberry pi, donc moins galère pour faire du prototypage.

La base de l'environnement embarqué de travail est :

  • buildroot-2013.08.1
  • kernel 3.12.0
  • chaîne de compilation croisée : buildroot-uclibc



Installation de python 3


Tant qu'à faire, autan utiliser la dernière version de python. :)
Le package python 3 est déjà présent sur l'environnement buildroot, il faut simplement le sélectionner dans via le menu et le tour est joué.

# make menuconfig

Puis de lancer la compilation avec la commande make :

# make

Modification d'un package buildroot


Pour s'interfacer avec le bus I2C via un module python, on va utiliser le package i2c-tools version 3.1.0 déjà présent dans les packages buildroot, mais la librairie python smbus n'est pas compilée par défaut, il va falloir l'activer et modifier le makefile pour faire fonctionner tout ça.

Tout d'abord télécharger les fichiers correctifs (i2c-tools.tar.gz) à désarchiver et à insérer dans le dossier package/i2c-tools :

# rm package/i2c-tools
# tar i2c-tools.tar.gz -C package
# ls package/i2c-tools
Config.in   i2c-tools-001-smbusmodule.patch   i2c-tools.mk

Cette archive comprend :
  • Config.in : Le fichier de configuration pour le menu buildroot
  • i2c-tools-001-smbusmodule.patch : Un patch du fichier source smbusmodule.c pour faire fonctionner smbus avec python 3
  • i2c-tools.mk : Le fichier de fabrication des exécutables pour jouer avec les ports I2C présents et du module python.
Les lignes surlignées sont celles rajoutées par rapport au fichier original.

####################################################################
#
# i2c-tools
#
####################################################################

I2C_TOOLS_VERSION = 3.1.0
I2C_TOOLS_SOURCE = i2c-tools-$(I2C_TOOLS_VERSION).tar.bz2
I2C_TOOLS_SITE = http://dl.lm-sensors.org/i2c-tools/releases
I2C_TOOLS_DEPENDENCIES = python3 host-python3

# LDSHARED and PYTHON VAR ENV from $(HOST_DIR)/usr/bin/python3 -m sysconfig

define I2C_TOOLS_BUILD_CMDS
    $(MAKE) $(TARGET_CONFIGURE_OPTS) -C $(@D) 
    
    (cd $(@D)/py-smbus; \
    PYTHONXCPREFIX="$(STAGING_DIR)/usr" \
    CC="$(TARGET_CC)" \
    CFLAGS="-fno-strict-aliasing -pthread -Wno-unused-result -DNDEBUG -g -fwrapv -O3 -Wall -O2 -I$(STAGING_DIR)/usr/include/python3.3m $(CFLAGS)" \
    CPPFLAGS="$(CPPFLAGS) -I../include" \
    LDFLAGS="-L$(STAGING_DIR)/lib -L$(STAGING_DIR)/usr/lib" \
    LDSHARED="$(TARGET_CC) -pthread -shared $(LDFLAGS) -Wl,-rpath,-L$(STAGING_DIR)/usr/lib" \
    $(HOST_DIR)/usr/bin/python3 setup.py build)
endef

define I2C_TOOLS_INSTALL_TARGET_CMDS
        for i in i2cdump i2cget i2cset i2cdetect; \
        do \
                $(INSTALL) -m 755 -D $(@D)/tools/$$i $(TARGET_DIR)/usr/bin/$$i; \
        done
    (cd $(@D)/py-smbus; \
    PYTHONPATH="$(TARGET_DIR)/usr/lib/python3.3/site-packages" \
    $(HOST_DIR)/usr/bin/python3 setup.py install --prefix=$(TARGET_DIR)/usr)
endef

$(eval $(generic-package))

Une fois la modification faite, il suffit de selectionner le package i2c-tools dans le menu de buildroot grâce à la commande :

# make menuconfig

Puis de lancer la commande :

# make

Normalement, sur le système de fichiers, vous devriez avoir les fichiers dans le dossier /usr/lib/python3.3/site-packages :

  • smbus.cpython-33m.so : La librairie compilée
  • smbus-1.1-py3.3.egg-info : Le module python smbus

Python 3 et module I2C


Pour pouvoir utiliser le nouveau module fraîchement installé, il faut activer le module i2c sur la raspberry pi, pour ceci, la commande modprobe va nous permettre de lancer les modules :

# modprobe -a i2c-bcm2708 i2c-dev

Ce qui va permettre de créer les nœuds /dev/i2c-0 et /dev/i2c-1.
Ensuite pour tester si le bus I2C est fonctionnel, il faut lancer l'exécutable de détection :
# i2cdetect -y 0
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00:          -- -- -- -- -- -- -- -- -- -- -- -- -- 
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
70: -- -- -- -- -- -- 76 --

Notre module LCD est bien vu par la raspberry pi à l'adresse 0x76 sur le bus 0

L'utilisation du module est simple, voici un premier exemple :

#!/usr/bin/python3
from smbus import SMBus
# Adresse de notre module LCD
lcd_addr = 0x76
# Utilisation du bus 0
bus = SMBus(0)
# Clear LCD display
bus.write_i2c_block_data(lcd_addr, 0x01, 0x02)

Suivant la messagerie codée sur le micro-contrôleur PIC pour la gestion de l'écran LCD, j'ai codé cette petite librairie permettant d'avoir accès aux fonctionnalités.

fichier i2c_lib.py :

#############################################################
# Importation de modules externes                           :

import smbus
from time import *

#############################################################
# Class et Methods                                          :

class i2c_device:
 """ I2C Class interface
 """
 
 def __init__(self, addr, port=0):
  self.addr = addr
  self.bus = smbus.SMBus(port)

 def write_cmd(self, cmd):
  """ Write a single command
  """
  self.bus.write_byte(self.addr, cmd)
  sleep(0.01)

 def write_cmd_arg(self, cmd, data):
  """ Write a command and argument
  """
  self.bus.write_byte_data(self.addr, cmd, data)
  sleep(0.01)

 def write_block_data(self, cmd, data):
  """ Write a block of data
  """
  self.bus.write_block_data(self.addr, cmd, data)
  sleep(0.01)

 def write_i2c_datas(self, cmd, datas):
  """ Write datas
  """
  if isinstance(datas, list) and isinstance(cmd, int):
   self.bus.write_i2c_block_data(self.addr, cmd, datas)
   sleep(0.01)

 def read(self):
  """ Read a single byte
  """
  return self.bus.read_byte(self.addr)

 def read_data(self, cmd):
  """ Read
  """
  return self.bus.read_byte_data(self.addr, cmd)

 def read_block_data(self, cmd):
  """ Read a block of data
  """
  return self.bus.read_block_data(self.addr, cmd)

fichier lcd_2x16.py :

#############################################################
# Importation de modules externes                           :

import sys

sys.path.append(".")
from i2c_lib import i2c_device

#############################################################
# Class et Methods                                       :

class lcd_2x16:
 """ Classe de contrôle de l'affichage de l'écran alpha 2x16 caractères
     via le bus i2c
  
     ------------------------------//-------
     | Frame Id | Frame Size | Frame datas |
     ------------------------------//-------

     Identifiants :
     --------------
     0x01 : Clear Display
     0x02 : Return home
     0x03 : Set Cursor
     0x04 : Put character
     0x05 : Put string
     0x06 : Control Display
 """

 LCD_ID_CLEAR_DISPLAY = 0x01
 LCD_ID_RETURN_HOME = 0x02
 LCD_ID_SET_CURSOR = 0x03
 LCD_ID_PUT_CHAR = 0x04
 LCD_ID_PUT_STR = 0x05
 LCD_ID_CONTROL_DISPLAY = 0x06
 
 def __init__(self, addr=0x76, port=0):
  self.i2c_lib_obj = i2c_device(addr, port)

 def clear_display(self):
  """ Efface les informations ecrites sur l'écran LCD
  """
  self.i2c_lib_obj.write_i2c_datas(self.LCD_ID_CLEAR_DISPLAY, [0x02])

 def return_home(self):
  """ Retourne le curseur à la position Row = 1, column = 1
  """
  self.i2c_lib_obj.write_i2c_datas(self.LCD_ID_RETURN_HOME, [0x02])
 
 def set_cursor(self, row, column):
  """ Deplace le curseur à la position souhaitée
  """
  self.i2c_lib_obj.write_i2c_datas(self.LCD_ID_SET_CURSOR, [0x04, row, column])
  
 def put_char(self, char):
  """ Insert un caractère à la position courante du curseur
  """
  if isinstance(char, str) and len(char) is 1:
   self.i2c_lib_obj.write_i2c_datas(self.LCD_ID_PUT_CHAR, [0x03, ord(char)])
  else:
   print('Error with argument ...')
  
 def put_str(self, string):
  """ Insert une chaîne de caractères à la position courante du curseur
  """
  if isinstance(string, str) and len(string) <= 16:
   str_len = 2 + len(string)
   lst_str = [ord(char) for char in string]
   lst_str.insert(0, len(string)  + 2)
   self.i2c_lib_obj.write_i2c_datas(self.LCD_ID_PUT_STR, lst_str)  

 def control_display(self, display, cursor, blink):
  """ Change les paramètres de l'écran
  """
  self.i2c_lib_obj.write_i2c_datas(self.LCD_ID_CONTROL_DISPLAY, [0x05, display, cursor, blink])

Il suffit d'importer le module lcd_2x16.py dans vos sources et d'instancier la classe lcd_2x16 pour interagir avec l'écran LCD.

 Amusez-vous bien ...

Aucun commentaire:

Enregistrer un commentaire