1、PCF8574T
PCF8574T是由恩智浦(NXP)半导体生产的I²C总线接口的8位并行I/O端口扩展器。该芯片的主要特性与功能包括:
I²C总线接口:PCF8574T通过I²C总线(也称作IIC总线)与主控制器(如MCU)通信,仅需占用两根信号线(SCL和SDA),即可实现与主控制器之间的数据传输。
8个准双向口:芯片内含8个准双向I/O口(P0-P7),每个端口既可以作为输出端口驱动外部负载,也可以作为输入端口读取外部设备的状态。当作为输入口使用时,为了获得正确的输入状态,需要将对应的内部输出驱动设置为高电平(上拉),这样在外部设备不驱动的情况下,端口就能通过内部上拉电阻检测到高电平输入。
中断线:PCF8574T还有一个中断输出引脚(INT),当任一输入口的状态发生变化时,可以触发此中断信号,告知主控制器有输入状态的变化,方便系统做出及时响应。
3个地址线:通过不同的地址线配置,可以实现多个PCF8574T芯片挂在同一个I²C总线上,并且每个芯片都有独立的地址,使得主控制器可以区别并单独访问每个芯片。
综上所述,PCF8574T芯片非常适用于需要扩展I/O资源的嵌入式系统,特别适合在I/O口有限或者布线困难的场合,通过一根I²C总线就可轻松管理和控制大量的外围设备。
2、PCF8574T特性
PCF8574 是 CMOS 电路。它通过两条双向总线(I2C)可使大多数 MCU 实现远程 I/O 口扩展。该器件包含一个 8 位准双向口和一个 I2C 总线接口。PCF8574 电流消耗很低,且口输出锁存具有大电流驱动能力,可直接驱动 LED。它还带有一条中断接线(INT)可与 MCU 的中断逻辑相连。通过 INT 发送中断信号,远端 I/O 口不必经过 I2C 总线通信就可通知 MCU 是否有数据从端口输入。这意味着 PCF8574可以作为一个单被控器。
上图的黄色跳线帽就是用来设置A0-A2的值,如果将跳线帽都短接到右边两个引脚,则为VSS,地址0x20,短接左边两个引脚,为VDD,地址为0x27
3、LCD1602
凡是学过51单片机的同学对这个器件应该不会陌生,我们就简单的介绍下。
1602液晶也叫1602字符型液晶,它是一种专门用来显示字母、数字、符号等的点阵型液晶模块。它由若干个5X7或者5X11等点阵字符位组成,每个点阵字符位都可以显示一个字符,每位之间有一个点距的间隔,每行之间也有间隔,起到了字符间距和行间距的作用,正因为如此所以它不能很好地显示图形(用自定义CGRAM,显示效果也不好)。
1602LCD是指显示的内容为16X2,即可以显示两行,每行16个字符液晶模块(显示字符和数字)。市面上字符液晶大多数是基于HD44780液晶芯片的,控制原理是完全相同的,因此基于HD44780写的控制程序可以很方便地应用于市面上大部分的字符型液晶。
4、PCF8574与LCD1602的连接
这里要说明一点,我之前买的PCF8574T扩展板,并不是专门针对LCD1602的扩展板,这样只有8根线接LCD,因涉及背光,电源等,最好用专门接1602的8574。我这边没有买专门驱动LCD1602的成套的8574+LCD1602+IIC,手头没有可调电阻,所以只能用这个不能调整对比度的PCF8574连接。
5、实验代码与现象
import time
import smbus
BUS = smbus.SMBus(1)
LCD_ADDR = 0x27
BLEN = 1 #turn on/off background light
def turn_light(key):
global BLEN
BLEN = key
if key ==1 :
BUS.write_byte(LCD_ADDR ,0x08)
else:
BUS.write_byte(LCD_ADDR ,0x00)
def write_word(addr, data):
global BLEN
temp = data
if BLEN == 1:
temp |= 0x08
else:
temp &= 0xF7
BUS.write_byte(addr ,temp)
def send_command(comm):
# Send bit7-4 firstly
buf = comm & 0xF0
buf |= 0x04 # RS = 0, RW = 0, EN = 1
write_word(LCD_ADDR ,buf)
time.sleep(0.002)
buf &= 0xFB # Make EN = 0
write_word(LCD_ADDR ,buf)
# Send bit3-0 secondly
buf = (comm & 0x0F) << 4
buf |= 0x04 # RS = 0, RW = 0, EN = 1
write_word(LCD_ADDR ,buf)
time.sleep(0.002)
buf &= 0xFB # Make EN = 0
write_word(LCD_ADDR ,buf)
def send_data(data):
# Send bit7-4 firstly
buf = data & 0xF0
buf |= 0x05 # RS = 1, RW = 0, EN = 1
write_word(LCD_ADDR ,buf)
time.sleep(0.002)
buf &= 0xFB # Make EN = 0
write_word(LCD_ADDR ,buf)
# Send bit3-0 secondly
buf = (data & 0x0F) << 4
buf |= 0x05 # RS = 1, RW = 0, EN = 1
write_word(LCD_ADDR ,buf)
time.sleep(0.002)
buf &= 0xFB # Make EN = 0
write_word(LCD_ADDR ,buf)
def init_lcd():
try:
send_command(0x33) # Must initialize to 8-line mode at first
time.sleep(0.005)
send_command(0x32) # Then initialize to 4-line mode
time.sleep(0.005)
send_command(0x28) # 2 Lines & 5*7 dots
time.sleep(0.005)
send_command(0x0C) # Enable display without cursor
time.sleep(0.005)
send_command(0x01) # Clear Screen
BUS.write_byte(LCD_ADDR ,0x08)
except:
return False
else:
return True
def clear_lcd():
send_command(0x01) # Clear Screen
def print_lcd(x, y, str):
if x < 0:
x = 0
if x > 15:
x = 15
if y <0:
y = 0
if y > 1:
y = 1
# Move cursor
addr = 0x80 + 0x40 * y + x
send_command(addr)
for chr in str:
send_data(ord(chr))
if __name__ == '__main__':
init_lcd()
print_lcd(0, 0, 'Hello, world!')
简单的显示个Helloworld!因为没有调整对比度,所以显示效果有点差。