[Raspberri Pi] Un petit écran LCD pour dire Bonjour !

Voila un petit article qui regroupe plusieurs pages trouvées sur internet. Je vais vous montrer comment relier un écran LCD sur le Raspberry Pi via les GPIOs.

Tout d’abord : l’écran LCD !
Il s’agit d’un hitachi HD44780, ou quelques chose comme ça. =)
voilà la bête :

HD44780


Voici le détail de l’utilisation de chaque broche:
• la broche 1 (VSS) sera reliée à la masse.
• la broche 2 (VDD) sera reliée à l’alimentation positive de 5V.
• la broche 3 (V0) est une entrée analogique qui permet de régler le contraste de l’afficheur. Il faut savoir qu’une tension de 5V correspondra au contraste le plus faible alors qu’une mise à la masse correspondra au contraste le plus élevé. Je vous conseille d’utiliser un potentiomètre pour gérer le contraste (nous verrons cela plus tard).
• la broche 4 (RS pour Register Select) est une entrée numérique qui sert à sélectionner le registre. Cela permettra à l’afficheur de déterminer si une commande (signal niveau bas) ou une donnée (signal niveau haut) lui est envoyée.
• la broche 5 (R/W pour Read/Write) est une entrée numérique qui sert à lire (niveau haut) ou écrire (niveau bas).
• la broche 6 (E pour Enable) est une entrée numérique qui valide la lecture ou l’écriture. La validation est active sur le front descendant d’une impulsion, dont la durée de l’état haut doit être au moins de 450 ns.
• les broches 7 à 14 sont des entrées numériques. Elles représentent le bus de communication. Ce sont des bus de données bidirectionnels qui servent à envoyer ou à recevoir les données ou les commandes via l’afficheur LCD.
• les broches 15 et 16 servent à alimenter le rétroéclairage (backlight). La broche 15 (l’anode) doit être alimentée en +5V et la broche 16 (la cathode) doit être mise à la masse.

Donc si nous souhaitons brancher cet écran sur les GPIOs du Raspberry Pi, je peux vous proposer ce montage :

HD44780schema

Le petit carré bleu représente un potentiomètre. Il permet de régler le contraste de l’affichage des caractères. (j’ai mis un potard de 10kOhms, mais n’importe quelle valeur fera l’affaire puisqu’on l’utilise ici comme diviseur de tension)

Voyons à présent comment utiliser cet écran.

#!/usr/bin/python

############################
# Imports                  #
############################
import threading
import RPi.GPIO as GPIO
from time import sleep
import subprocess

############################
# Class de controle du LCD #
############################
class HD44780(threading.Thread):
	######################
	# Variable Shared    #
	######################
	_PULSE = 0.00005
	_DELAY = 0.00005

	######################
	# Constructeur       #
	######################
	def __init__(self, pin_rs=7, pin_e=8, pins_db=[25, 24, 23, 18], lcd_width=16):
		self.message = ""
		self.currentmessage = "azerty"
		self.stop = False
		self.lcd_width = lcd_width
		self.pin_rs = pin_rs
		self.pin_e = pin_e
		self.pins_db = pins_db
		GPIO.setmode(GPIO.BCM) 				# Use BCM GPIO numbers
		GPIO.setup(self.pin_e, GPIO.OUT)
		GPIO.setup(self.pin_rs, GPIO.OUT)
		for pin in self.pins_db:
			GPIO.setup(pin, GPIO.OUT)

		self.Clear()
		threading.Thread.__init__(self)

	######################
	# Demarrage du Thread# 
	######################
	def run(self):
		while self.stop == False:
			if self.message != self.currentmessage:
				self.currentmessage = self.message
				self.LcdMessage()
			sleep(1)

	######################
	# Arret du Thread    # 
	######################	
	def Stop(self):
		self.stop = True

	######################
	# Initialisation LCD # 
	######################
	def Clear(self):
		""" Blank / Reset LCD """
		self.LcdByte(0x33, False) # $33 8-bit mode
		self.LcdByte(0x32, False) # $32 8-bit mode
		self.LcdByte(0x28, False) # $28 8-bit mode
		self.LcdByte(0x0C, False) # $0C 8-bit mode
		self.LcdByte(0x06, False) # $06 8-bit mode
		self.LcdByte(0x01, False) # $01 8-bit mode

	######################
	#Execution sur le LCD# 
	######################
	def LcdByte(self, bits, mode):
		""" Send byte to data pins """
		# bits = data
		# mode = True  for character
		#        False for command

		GPIO.output(self.pin_rs, mode) # RS

		# High bits
		for pin in self.pins_db:
			GPIO.output(pin, False)
		if bits&0x10==0x10:
			GPIO.output(self.pins_db[0], True)
		if bits&0x20==0x20:
			GPIO.output(self.pins_db[1], True)
		if bits&0x40==0x40:
			GPIO.output(self.pins_db[2], True)
		if bits&0x80==0x80:
			GPIO.output(self.pins_db[3], True)

		# Toggle 'Enable' pin
		sleep(HD44780._DELAY)    
		GPIO.output(self.pin_e, True)  
		sleep(HD44780._PULSE)
		GPIO.output(self.pin_e, False)  
		sleep(HD44780._DELAY)      

		# Low bits
		for pin in self.pins_db:
			GPIO.output(pin, False)
		if bits&0x01==0x01:
			GPIO.output(self.pins_db[0], True)
		if bits&0x02==0x02:
			GPIO.output(self.pins_db[1], True)
		if bits&0x04==0x04:
			GPIO.output(self.pins_db[2], True)
		if bits&0x08==0x08:
			GPIO.output(self.pins_db[3], True)

		# Toggle 'Enable' pin
		sleep(HD44780._DELAY)    
		GPIO.output(self.pin_e, True)  
		sleep(HD44780._PULSE)
		GPIO.output(self.pin_e, False)  
		sleep(HD44780._DELAY) 	

	######################
	#Affichage sur le LCD# 
	######################	
	def LcdMessage(self):
		""" Send string to LCD. Newline wraps to second line"""
		self.Clear()
		text = self.currentmessage
		self.LcdByte(0x80, False)
		for c in text:
			if c == '\n':
				self.LcdByte(0xC0, False) # next line
			else:
				self.LcdByte(ord(c),True)

	######################
	#Definir le message  # 
	######################
	def LcdSetMessage(self, text):
		self.message = text.ljust(self.lcd_width," ")

################################
# Class Informations Systeme   #
################################
class SysInfo(threading.Thread):
	######################
	# Constructeur       #
	######################
	def __init__(self):
		self.count = 0
		self.lcd = HD44780()
		self.stop = False
		threading.Thread.__init__(self)

	######################
	# Demarrage du Thread# 
	######################
	def run(self):
		self.lcd.start()
		while self.stop == False:
			if self.count == 0: #UPTIME
				self.lcd.LcdSetMessage("Uptime:\n"+self.SysUptime())
			elif self.count == 1: #LOAD
				self.lcd.LcdSetMessage("Load:\n"+self.SysLoadAvg())
			elif self.count == 2: #CPU
				self.lcd.LcdSetMessage("Cpu:\n"+self.SysCpu())
			elif self.count == 3: #MEMORY
				self.lcd.LcdSetMessage("Memory:\n"+self.SysMemory())
			elif self.count == 4: #DRIVE
				self.lcd.LcdSetMessage("Disk Root:\n"+self.SysDisk())
			else:
				self.lcd.LcdSetMessage("ZeM.fr    ZeM.fr\nRoxXxXxXxXxXxXxX")
			self.count += 1
			if self.count == 6:
				self.count = 0
			sleep(5)

	######################
	# Arret du Thread    # 
	######################
	def Stop(self):
		self.lcd.Stop()
		self.stop = True	

	######################
	# Memory             # 
	######################		
	def SysMemory(self):
		try:
			command="free -h"
			process=subprocess.Popen(command, shell=True, stdout=subprocess.PIPE)
			stdout_list=process.communicate()[0].split('\n')
			for line in stdout_list:
			  data=line.split()
			  try:
				  if data[0]=="Mem:":
					  total=str(data[1])
					  used=str(data[2])
					  free=str(data[3])
			  except IndexError:
				  continue	
		except:
			return "Error"
		return str(used)+ " / "+str(total)

	######################
	# Disk              # 
	######################		
	def SysDisk(self):
		try:
			command="df -H /"
			process=subprocess.Popen(command, shell=True, stdout=subprocess.PIPE)
			stdout_list=process.communicate()[0].split('\n')
			for line in stdout_list:
			  data=line.split()
			  try:
				  if data[len(data)-1]=="/":
					  total=str(data[1])
					  used=str(data[2])
			  except IndexError:
				  continue	
		except Exception, e:
			print e
			return "Error"
		return str(used)+ " / "+str(total)

	######################
	# CPU                # 
	######################	
	def SysCpuGetTimeList(self):
		statFile = file("/proc/stat", "r")
		timeList = statFile.readline().split(" ")[2:6]
		statFile.close()
		for i in range(len(timeList))  :
			timeList[i] = int(timeList[i])
		return timeList
	def SysCpu(self):
		try:
			x = self.SysCpuGetTimeList()
			sleep(2)
			y = self.SysCpuGetTimeList()
			for i in range(len(x)):
				y[i] -= x[i]
			cpuPct = 100 - (y[len(y) - 1] * 100.00 / sum(y))
		except:
			return "Error"
		return str('%.2f' %cpuPct)+"%"

	######################
	# Load Average       # 
	######################
	def SysLoadAvg(self):
		try:
		 f = open( "/proc/loadavg" )
		 contents = f.read().split()
		 f.close()
		except:
			return "Error"
		return contents[0]+" "+contents[1]+" "+contents[2];		

	######################
	# Systeme Uptime     # 
	######################
	def SysUptime(self):
		try:
			f = open( "/proc/uptime" )
			contents = f.read().split()
			f.close()
			total_seconds = float(contents[0])
			MINUTE  = 60
			HOUR    = MINUTE * 60
			DAY     = HOUR * 24
			days    = int( total_seconds / DAY )
			hours   = int( ( total_seconds % DAY ) / HOUR )
			minutes = int( ( total_seconds % HOUR ) / MINUTE )
			seconds = int( total_seconds % MINUTE )
			string = ""
			if days > 0:
				string += str(days) + "d "
			if len(string) > 0 or hours > 0:
				string += str(hours) + "h "
			if len(string) > 0 or minutes > 0:
				string += str(minutes) + "m "
			string += str(seconds) + "s "
		except:
			return "Error"
		return string;	

######################
# MAIN STARTER       # 
######################	
if __name__ == '__main__':

	si = SysInfo()
	si.start()
	q = str(raw_input('Press ENTER to quit program'))
	si.Stop()

Ce script Python contient 2 classes:

  • la classe HD44780 qui permet de contrôler l’afficheur LCD
  • la classe SysInfo qui permet de récupérer certaines informations propres au système

Que fait concrètement ce programme ?
il récupère les informations systèmes tels que la charge du processeur, la RAM utilisée, l’espace disponible sur la carte mémoire, le temps d’utilisation, etc… et toutes les 5 secondes, il affiche un autre information.

La classe HD44780 qui pilote l’écran LCD est basée sur un Thread.

On initialise toutes les variables nécessaires et les broches à utiliser et on lance le Thread. Toutes les secondes, le processus compare la nouvelle chaîne de caractère à afficher par rapport à celle qui est déja présente. S’il y a une différence, il actualise l’écran.

La fonction Clear() permet d’initialiser l’écran LCD lors du démarrage et d’effacer l’écran quand un nouveau mesage doit être affiché.

La fonction LCDMessage() permet d’envoyer le message à afficher dans la mémoire de l’écran. Pour chaque caractère du message, on envoi le code Unicode correspondant. Quand un retour à la ligne est trouvé dans le message, on passe à la ligne suivante en envoyant l’instruction « ligne suivante » (code 0xC0).

La fonction LCDByte(bits, mode) permet de communiquer avec l’écran LCD. Cette fonction prend 2 paramètres. Le premier (« bits ») correspond au code à envoyer sur le bus de communication. le second, (« mode ») correspond au bit de la broche RS. Cette broche permet de définir comment utiliser les données du bus de communication.
Dans cette fonction, on inscrit les données à envoyer à l’écran. le code « bits » est décomposé pour récupérer les 8 bits qui le compose. et chaque bit est envoyé sur le bus de données.

On utilise l’écran avec le mode 4 bits, cela signifie que l’on utilise seulement 4 broches sur les 8 du bus de communication. Et comme les instructions sont toujours sur 8 bits, elle sont traitées pour être envoyées en 2 fois. On envoie les 4 bits de poids fort (D7, D6, D5 et D4), on envoie un bit sur la broche « Enable » pour valider l’enregistrement de ces 4 bits et on inscrits les 4 derniers bits de l’instruction que l’on valide à nouveau.

fonctionnement4Bits

Publicités

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