Założenia:
- Cubietruck
- DVK570 (niewymagana, jednak jeśli nie masz kitu - musisz sam zadbać o odpowiednie parametry prądowe np dla diod LED)
- CTdebian 4.1 (do pobrania ze strony Igora Pecovnik-a lub z działu Wsady)
Przestroga 1.
Wszystkie operacje wykonuję jako uprzywilejowany użytkownik root . Nie jest to dobra praktyka więc proponuję używać sudo i wykonywać wszystkie komendy z poziomu normalnego użytkownika...
Uwaga.
Dystrybucja, której używam to kompilacja ze źródeł CTDebian Igora Pecovnik-a. Możesz pobrać najnowszą wersję ze strony Igora lub skorzystać z mojej kompilacji.
Przestroga 2
Wszystko co robisz - robisz na własną odpowiedzialność. W trakcie tutoriala wykonywane są czynności, które mogą uszkodzić twoje urządzenie...
Z czego korzystamy: Podstawowe sterowanie - odczyt i zapis z PCF8574
Zapiszmy wszelkie możliwe wartości do naszego ekspandera (write.py):
Code: Select all
import smbus
import time
bus = smbus.SMBus(1)
bus.write_byte(0x38,0x00)
while(1):
for a in range(0,256):
bus.write_byte(0x38,a)
time.sleep(0.5)
i odczytajmy (read.py) np w drugim oknie konsoli:
Code: Select all
import smbus
I2C_ADDRESS = 0x38
bus = smbus.SMBus(1)
while(1):
#Read all the unput lines
value=bus.read_byte(I2C_ADDRESS)
print "%02X" % value
Dodajmy obsługę wyświetlacza HD44780 poprzez nasz ekspander...
Kilka słów wyjaśnienia, otóż PCF8574 nie wymaga napięcia 5V ale jest ono wymagane do zasilania naszego wyświetlacza... egzemplarz przedstawiony na zdjęciu działa przy zasilaniu 3V3 lecz uzyskany kontrast jest mniej niż zadowalający... to samo tyczy się podświetlenia. Dlatego zdecydowałem się zastosować dwukanałowy, dwukierunkowy konwerter napięć 3V3<->5V. Można je nabyć na eBay-u lub zbudować samemu. Podobnie sprawa się ma z gotowymi ekspanderami, można je nabyć w serwisie aukcyjnym osobno lub już zintegrowane z wyświetlaczem. Należy zwrócić uwagę na sposób połączenia PCF8574 z wyświetlaczem (jest kilka wersji). Mając notę katalogową PCF-a i rozpiskę złącza wyświetlacza jesteśmy w stanie 'wykminić' co autor danego rozwiązania miał na myśli. Przedstawiony poniżej program/biblioteka pozwala na sterowanie wyświetlaczem z dowolnie podpiętym PCF-em po drobnych modyfikacjach.
Sprawdźmy pod jakim adresem nasz ekspander jest dostępny... Stwórz i zapisz plik hd44870_lib.py:
Code: Select all
#!/usr/bin/python
#--------------------------------------
# hd44870_lib.py
# LCD script using I2C based on PCF8574.
# Supports 16x2 and 20x4 screens.
#
# Author : based on Matt's Hawkins work
# Date : 20/09/2015#
# http://www.raspberrypi-spy.co.uk/
#
# Cubieboard version : Blazej Biernat
#
# The wiring for the LCD is as follows:
# 1 : GND
# 2 : 5V
# 3 : Contrast (0-5V)*
# 4 : RS (Register Select)
# 5 : R/W (Read Write) - GROUND THIS PIN
# 6 : Enable or Strobe
# 7 : Data Bit 0 - NOT USED
# 8 : Data Bit 1 - NOT USED
# 9 : Data Bit 2 - NOT USED
# 10: Data Bit 3 - NOT USED
# 11: Data Bit 4
# 12: Data Bit 5
# 13: Data Bit 6
# 14: Data Bit 7
# 15: LCD Backlight +5V**
# 16: LCD Backlight GND
#--------------------------------------
import smbus
from itertools import cycle
import time
backlite = 1
bus = smbus.SMBus(1)
I2C_ADDR = 0x27
#LCD_SIG = PORT(BIT)
LCD_RS = 0
LCD_RW = 1
LCD_E = 2
LCD_BL = 3
LCD_D4 = 4
LCD_D5 = 5
LCD_D6 = 6
LCD_D7 = 7
# Define some device constants
LCD_WIDTH = 20 # Maximum characters per line
LCD_CHR = True
LCD_CMD = False
# Some commands
LCD_CLRSCR = 0x01
LCD_LINE_1 = 0x80 # LCD RAM address for the 1st line
LCD_LINE_2 = 0xc0 # LCD RAM address for the 2nd line
LCD_LINE_3 = 0x94 # LCD RAM address for the 1st line
LCD_LINE_4 = 0xd4 # LCD RAM address for the 2nd line
# Timing constants
INIT_DELAY = 0.00100
E_PULSE = 0.00005
E_DELAY = 0.00005
def lcd_init():
#read actual PCF8574 variable
i2c_value = bus.read_byte(I2C_ADDR)
i2c_value = clearBit(i2c_value,LCD_RW)
bus.write_byte(I2C_ADDR,i2c_value)
# Initialise display sequense
lcd_byte(0x03,LCD_CMD)
time.sleep(INIT_DELAY)
lcd_byte(0x03,LCD_CMD)
time.sleep(INIT_DELAY)
lcd_byte(0x03,LCD_CMD)
time.sleep(INIT_DELAY)
lcd_byte(0x02,LCD_CMD)
time.sleep(INIT_DELAY)
lcd_byte(0x02,LCD_CMD)
time.sleep(E_DELAY)
lcd_byte(0x08,LCD_CMD)
time.sleep(E_DELAY)
lcd_byte(0x01,LCD_CMD)
time.sleep(E_DELAY/2)
lcd_byte(0x06,LCD_CMD)
time.sleep(E_DELAY)
lcd_byte(0x0c,LCD_CMD)
def lcd_clean():
lcd_byte(LCD_CLRSCR, LCD_CMD)
def lcd_backlite(mode):
i2c_value = bus.read_byte(I2C_ADDR)
if (mode):
i2c_value = setBit(i2c_value,LCD_BL)
else:
i2c_value = clearBit(i2c_value,LCD_BL)
bus.write_byte(I2C_ADDR,i2c_value)
def lcd_write_lines(msg1, msg2):
if(msg1)<>"":
lcd_byte(LCD_LINE_1, LCD_CMD)
lcd_string(msg1)
if(msg2)<>"":
lcd_byte(LCD_LINE_2, LCD_CMD)
lcd_string(msg2)
def lcd_write_4lines(msg1, msg2, msg3, msg4):
if(msg1)<>"":
lcd_byte(LCD_LINE_1, LCD_CMD)
lcd_string(msg1)
if(msg2)<>"":
lcd_byte(LCD_LINE_2, LCD_CMD)
lcd_string(msg2)
if(msg3)<>"":
lcd_byte(LCD_LINE_3, LCD_CMD)
lcd_string(msg3)
if(msg4)<>"":
lcd_byte(LCD_LINE_4, LCD_CMD)
lcd_string(msg4)
def lcd_string(message):
# Send string to display
message = message.ljust(LCD_WIDTH," ")
for i in range(LCD_WIDTH):
lcd_byte(ord(message[i]),LCD_CHR)
def lcd_byte(bits, mode):
global backlite
# Send byte to PCF8574 data register
# bits = data
# mode = True for character
# mode = False for command
# i2c_value = actually data from PCF8574
i2c_value=bus.read_byte(I2C_ADDR)
if (mode):
i2c_value = setBit(i2c_value,LCD_RS)
else:
i2c_value = clearBit(i2c_value,LCD_RS)
if (backlite):
i2c_value = setBit(i2c_value,LCD_BL)
bus.write_byte(I2C_ADDR,i2c_value)
# High bits
i2c_value = clearBit(i2c_value,LCD_D4)
i2c_value = clearBit(i2c_value,LCD_D5)
i2c_value = clearBit(i2c_value,LCD_D6)
i2c_value = clearBit(i2c_value,LCD_D7)
if bits&0x10==0x10:
i2c_value = setBit(i2c_value,LCD_D4)
if bits&0x20==0x20:
i2c_value = setBit(i2c_value,LCD_D5)
if bits&0x40==0x40:
i2c_value = setBit(i2c_value,LCD_D6)
if bits&0x80==0x80:
i2c_value = setBit(i2c_value,LCD_D7)
bus.write_byte(I2C_ADDR,i2c_value)
# Toggle 'Enable' pin
time.sleep(E_DELAY)
i2c_value = setBit(i2c_value,LCD_E)
bus.write_byte(I2C_ADDR,i2c_value)
time.sleep(E_PULSE)
i2c_value = clearBit(i2c_value,LCD_E)
bus.write_byte(I2C_ADDR,i2c_value)
time.sleep(E_DELAY)
# Low bits
i2c_value = clearBit(i2c_value,LCD_D4)
i2c_value = clearBit(i2c_value,LCD_D5)
i2c_value = clearBit(i2c_value,LCD_D6)
i2c_value = clearBit(i2c_value,LCD_D7)
if bits&0x01==0x01:
i2c_value = setBit(i2c_value,LCD_D4)
if bits&0x02==0x02:
i2c_value = setBit(i2c_value,LCD_D5)
if bits&0x04==0x04:
i2c_value = setBit(i2c_value,LCD_D6)
if bits&0x08==0x08:
i2c_value = setBit(i2c_value,LCD_D7)
bus.write_byte(I2C_ADDR,i2c_value)
# Toggle 'Enable' pin
time.sleep(E_DELAY)
i2c_value = setBit(i2c_value,LCD_E)
bus.write_byte(I2C_ADDR,i2c_value)
time.sleep(E_PULSE)
i2c_value = clearBit(i2c_value,LCD_E)
bus.write_byte(I2C_ADDR,i2c_value)
time.sleep(E_DELAY)
# testBit() returns a nonzero result, 2**offset, if the bit at 'offset' is one.
def testBit(int_type, offset):
mask = 1 << offset
return(int_type & mask)
# setBit() returns an integer with the bit at 'offset' set to 1.
def setBit(int_type, offset):
mask = 1 << offset
return(int_type | mask)
# clearBit() returns an integer with the bit at 'offset' cleared.
def clearBit(int_type, offset):
mask = ~(1 << offset)
return(int_type & mask)
# toggleBit() returns an integer with the bit at 'offset' inverted, 0 -> 1 and 1 -> 0.
def toggleBit(int_type, offset):
mask = 1 << offset
return(int_type ^ mask)
def lcd_log2file(fp,line):
pattern = "[LCD]: "
logfile = open(fp, "a+")
line = str(ticks) + '|' + pattern + line +'\n'
logfile.write(line)
logfile.close()
Code: Select all
#!/usr/bin/python
import smbus
import time
import hd44870_lib as lcd
lcd.lcd_init()
lcd.lcd_clean()
while(1):
backlite = 1
lcd.lcd_write_lines("test1","test2")
#lcd.lcd_backlite(1)
time.sleep(1)
lcd.lcd_write_lines("test2","test1")
#lcd.lcd_backlite(1)
time.sleep(1)
lcd.lcd_write_lines("test1","test2")
time.sleep(1)
lcd.lcd_write_lines("test2","test1")
time.sleep(1)