1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194
| #!/usr/bin/python3
# -*-coding:Utf-8 -*
import threading
from random import randrange
from time import sleep
from time import time
from unicodedata import normalize
import tymsoft.lcd.i2c_lib as i2c_lib
from tymsoft.interruptable import Interruptable
# commands
LCD_CLEARDISPLAY = 0x01
LCD_RETURNHOME = 0x02
LCD_ENTRYMODESET = 0x04
LCD_DISPLAYCONTROL = 0x08
LCD_CURSORSHIFT = 0x10
LCD_FUNCTIONSET = 0x20
LCD_SETCGRAMADDR = 0x40
LCD_SETDDRAMADDR = 0x80
# flags for display entry mode
LCD_ENTRYRIGHT = 0x00
LCD_ENTRYLEFT = 0x02
LCD_ENTRYSHIFTINCREMENT = 0x01
LCD_ENTRYSHIFTDECREMENT = 0x00
# flags for display on/off control
LCD_DISPLAYON = 0x04
LCD_DISPLAYOFF = 0x00
LCD_CURSORON = 0x02
LCD_CURSOROFF = 0x00
LCD_BLINKON = 0x01
LCD_BLINKOFF = 0x00
# flags for display/cursor shift
LCD_DISPLAYMOVE = 0x08
LCD_CURSORMOVE = 0x00
LCD_MOVERIGHT = 0x04
LCD_MOVELEFT = 0x00
# flags for function set
LCD_8BITMODE = 0x10
LCD_4BITMODE = 0x00
LCD_2LINE = 0x08
LCD_1LINE = 0x00
LCD_5x10DOTS = 0x04
LCD_5x8DOTS = 0x00
# flags for backlight control
LCD_BACKLIGHT = 0x08
LCD_NOBACKLIGHT = 0x00
En = 0b00000100 # Enable bit
Rw = 0b00000010 # Read/Write bit
Rs = 0b00000001 # Register select bit
class LCD(Interruptable):
"""Classe permettant d'utiliser des afficheurs LCD de type 1602, 1604, 2002, 2004 contrôlés par une puce
de type Hitachi HD44780.
"""
def __init__(self, i2c_address=0x27, height=2, width=16):
"""Crée un objet permettant l'initialisation et l'utilisation d'un afficheur LCD."""
self.address = i2c_address
self.height = height
self.width = width
self.device = i2c_lib.I2CDevice(self.address)
self.lock = threading.RLock()
self.last_ticket = 0.
self.write(0x03)
self.write(0x03)
self.write(0x03)
self.write(0x02)
self.write(LCD_FUNCTIONSET | LCD_2LINE | LCD_5x8DOTS | LCD_4BITMODE)
self.write(LCD_DISPLAYCONTROL | LCD_DISPLAYON)
self.write(LCD_CLEARDISPLAY)
self.write(LCD_ENTRYMODESET | LCD_ENTRYLEFT)
sleep(0.2)
self.backlight_on(False)
Interruptable.__init__(self)
def take_a_ticket(self):
"""Crée un nombre unique et le stock dans l'objet comme étant l'identifiant du dernier ordre envoyé."""
new_ticket = time()
new_ticket += randrange(0, 9999) / 10000
self.last_ticket = new_ticket
return new_ticket
def strobe(self, data):
"""Envoi une impulsion EN pour relâcher une commande."""
self.device.write_cmd(data | En | LCD_BACKLIGHT)
sleep(.0005)
self.device.write_cmd(((data & ~En) | LCD_BACKLIGHT))
sleep(.0001)
def write_four_bits(self, data):
self.device.write_cmd(data | LCD_BACKLIGHT)
self.strobe(data)
def write(self, cmd, mode=0):
"""Envoi une commande à l'afficheur LCD."""
self.write_four_bits(mode | (cmd & 0xF0))
self.write_four_bits(mode | ((cmd << 4) & 0xF0))
def display_string(self, string, line=1):
"""Affiche une chaîne de caractères sur une ligne de l'afficheur."""
if line not in range(1, self.height):
line = 1
def run():
norm_string = normalize('NFKD', string).encode('ascii', 'ignore').decode("utf-8")
with self.lock:
if line == 1:
self.write(0x80)
elif line == 2:
self.write(0xC0)
elif line == 3:
self.write(0x94)
elif line == 4:
self.write(0xD4)
for char in norm_string:
self.write(ord(char), Rs)
thread = threading.Thread(target=run)
thread.start()
def display_scrolling_string(self, string, line=1, pause=0.25):
"""Affiche une chaîne de caractères sur une ligne de l'afficheur.
Ce texte défilera s'il est plus long que la largeur de l'afficheur.
"""
if len(string) <= self.width:
self.display_string(string, line)
else:
if line not in range(1, self.height):
line = 1
ticket = self.take_a_ticket()
def run():
norm_string = normalize('NFKD', string).encode('ascii', 'ignore').decode("utf-8")
offset = 0
while ticket == self.last_ticket and not self.interrupted():
substring = norm_string[offset:offset + self.width]
with self.lock:
if line == 1:
self.write(0x80)
elif line == 2:
self.write(0xC0)
elif line == 3:
self.write(0x94)
elif line == 4:
self.write(0xD4)
for char in substring:
self.write(ord(char), Rs)
offset += 1
offset %= len(norm_string) - self.width + 1
sleep(pause)
thread = threading.Thread(target=run)
thread.start()
def clear(self):
"""Efface le contenu de l'afficheur et ramène le curseur à l'origine."""
with self.lock:
self.write(LCD_CLEARDISPLAY)
self.write(LCD_RETURNHOME)
def backlight_on(self, state=True):
"""Allume ou éteint le rétro-éclairage."""
with self.lock:
if state:
self.device.write_cmd(LCD_BACKLIGHT)
else:
self.device.write_cmd(LCD_NOBACKLIGHT)
def load_custom_chars(self, custom_charset):
"""Charge un jeu de caractères spéciaux dans la CGRAM du contrôleur."""
with self.lock:
self.write(LCD_SETCGRAMADDR)
for char in custom_charset:
self.write(char, Rs) |
Partager