前言
树莓派素有吃灰神器之称,与Kindle齐名(Kindle:我怎么中枪的来着)。虽然树莓派很便宜,但一直把它晾着也不是事儿,正好各种实验材料也到了,是时候弄点小玩意儿出来了。
认识GPIO
树莓派主板上方有两排共40 pin引脚。
在终端执行pinout命令,就可以打印出一个简易的主板布局图,其中包含引脚定义图示。
详细版本的布局图如下。
来自https://pinout.xyz/图中一共有26个名称为“BCMx”或者“GPIOx”的引脚,它们就是GPIO(General Purpose I/O,通用输入输出)引脚。顾名思义,所有GPIO引脚都可以通过编程来实现自定义的输入输出逻辑,用途非常灵活,也是树莓派好吃的精华所在。
GPIO引脚也可以被复用来实现其他特定的功能(图中括号所示),如PWM、I2C、SPI等,之后用到了再说咯。
除去GPIO之外,剩下的就是一些最基本的:
- 2个3.3V电源(1、17);
- 2个5V电源(2、4);
- 8个接地(6、9、14、20、25、30、34、39)。
LCD1602简介及接线
LCD1602是一个点阵液晶屏模块,支持ASCII字符、日文假名和希腊字母的显示,最多能同时显示16*2=32个字符(所以叫1602)。
它一共有16个引脚,定义如下表。
由此可以确定出LCD1602与树莓派之间的接线方案:
- Vss和Vdd是供电,前者接地,后者接5V;
- V0用于调整屏幕的对比度,接10kΩ电位器中间引脚,另外的两侧引脚之一要接地;
- RS是寄存器选择,控制数据输入和指令输入。选择GPIO引脚即可,这里接GPIO7(26号pin),并且记住这些对应关系,后面写程序要用;
- R/W是读写选择,接地,表示写模式;
- E是使能信号,接GPIO8(24号pin);
- DB0~DB7是数据总线,其中DB0~DB3只在8位传输模式下用,这次用简单的4位传输模式,于是空着。DB4~DB7分别接GPIO 25/24/23/18(对应的是22/18/16/12号pin);
- BLA、BLK是背光的阳极和阴极,阳极接5V,阴极接地。
以下几点要注意:
- 接线时必须断电。注意GPIO引脚编号和pinout编号的区别;
- 树莓派不能用于LCD1602的读模式,因为GPIO引脚的标准工作电压是3.3V,而LCD1602输出电压是5V,会烧掉树莓派;
- 如果LCD1602是无背光版本,就不用接BLA、BLK。为了保护背光,也可以给阳极串一个小电阻(1kΩ以下的),不过我就省略了。
写代码,跑起来
由于LCD1602基本都基于日立HD44780主控,所以资料也通用。关于其时序、内存、指令等信息,有大把说明文档可以参考,比如https://wenku.baidu.com/view/a517e38903020740be1e650e52ea551810a6c9ef.html,不再赘述。
LCD1602上电后,应该会等待初始化,背光亮并且第一排显示16个黑方块。如果没有任何显示,就旋转V0引脚上接的电位器,调整一下对比度。
编写如下Python程序,让它以3秒为周期循环显示几条信息。
#!/usr/bin/python
import RPi.GPIO as GPIO
import time
# GPIO to LCD mapping
LCD_RS = 7 # Pi pin 26
LCD_E = 8 # Pi pin 24
LCD_D4 = 25 # Pi pin 22
LCD_D5 = 24 # Pi pin 18
LCD_D6 = 23 # Pi pin 16
LCD_D7 = 18 # Pi pin 12
# Device constants
LCD_CHR = True # Character mode
LCD_CMD = False # Command mode
LCD_CHARS = 16 # Characters per line (16 max)
LCD_LINE_1 = 0x80 # LCD memory location for 1st line
LCD_LINE_2 = 0xC0 # LCD memory location 2nd line
def main():
GPIO.setwarnings(False)
GPIO.setmode(GPIO.BCM) # Use BCM GPIO numbers
GPIO.setup(LCD_E, GPIO.OUT) # Set GPIO's to output mode
GPIO.setup(LCD_RS, GPIO.OUT)
GPIO.setup(LCD_D4, GPIO.OUT)
GPIO.setup(LCD_D5, GPIO.OUT)
GPIO.setup(LCD_D6, GPIO.OUT)
GPIO.setup(LCD_D7, GPIO.OUT)
# Initialize display
lcd_init()
# Loop - send text and sleep 3 seconds between texts
while True:
lcd_text('Hello World!', LCD_LINE_1)
lcd_text('', LCD_LINE_2)
time.sleep(3) # 3 second delay
lcd_text('Raspberry Pi 3B+', LCD_LINE_1)
lcd_text('LCD 1602', LCD_LINE_2)
time.sleep(3)
lcd_text('ABCDEFGHIJKLMNOP', LCD_LINE_1)
lcd_text('qrstuvwxyz345789', LCD_LINE_2)
time.sleep(3)
lcd_text('No tengo dinero', LCD_LINE_1)
lcd_text('Ni nada que dar', LCD_LINE_2)
time.sleep(3)
# Initialize and clear display
def lcd_init():
lcd_write(0x33, LCD_CMD) # Initialize
lcd_write(0x32, LCD_CMD) # Set to 4-bit mode
lcd_write(0x06, LCD_CMD) # Cursor move direction
lcd_write(0x0C, LCD_CMD) # Turn cursor off
lcd_write(0x28, LCD_CMD) # 2 line display
lcd_write(0x01, LCD_CMD) # Clear display
time.sleep(0.0005) # Delay to allow commands to process
def lcd_write(bits, mode):
GPIO.output(LCD_RS, mode) # RS
# High bits
GPIO.output(LCD_D4, False)
GPIO.output(LCD_D5, False)
GPIO.output(LCD_D6, False)
GPIO.output(LCD_D7, False)
if bits & 0x10 == 0x10:
GPIO.output(LCD_D4, True)
if bits & 0x20 == 0x20:
GPIO.output(LCD_D5, True)
if bits & 0x40 == 0x40:
GPIO.output(LCD_D6, True)
if bits & 0x80 == 0x80:
GPIO.output(LCD_D7, True)
# Toggle 'Enable' pin
lcd_toggle_enable()
# Low bits
GPIO.output(LCD_D4, False)
GPIO.output(LCD_D5, False)
GPIO.output(LCD_D6, False)
GPIO.output(LCD_D7, False)
if bits & 0x01 == 0x01:
GPIO.output(LCD_D4, True)
if bits & 0x02 == 0x02:
GPIO.output(LCD_D5, True)
if bits & 0x04 == 0x04:
GPIO.output(LCD_D6, True)
if bits & 0x08 == 0x08:
GPIO.output(LCD_D7, True)
# Toggle 'Enable' pin
lcd_toggle_enable()
def lcd_toggle_enable():
time.sleep(0.0005)
GPIO.output(LCD_E, True)
time.sleep(0.0005)
GPIO.output(LCD_E, False)
time.sleep(0.0005)
def lcd_text(message, line):
# Send text to display
message = message.ljust(LCD_CHARS, ' ')
lcd_write(line, LCD_CMD)
for i in range(LCD_CHARS):
lcd_write(ord(message[i]), LCD_CHR)
# Begin program
try:
main()
except KeyboardInterrupt:
pass
finally:
lcd_write(0x01, LCD_CMD)
GPIO.cleanup()
如果对比度过大出现虚影的话,就再调节一下电位器;如果仍然停在待初始化的状态,就需要检查接线了。正确的效果如下图。
感觉不是很喜欢绿色背光(有蓝色背光的版本),并且没用面包板,看起来乱糟糟的。毕竟第一次搞,就酱紫吧。当然,也可以让它输出一些有意义的字符串,比如系统监控信息。对应的Python代码如下。
# CPU温度
with open('/sys/class/thermal/thermal_zone0/temp', 'r') as cpu_temp:
lcd_text('{:.2f}'.format(float(cpu_temp.read()) / 1000) + ' C', LCD_LINE_1)
# GPU温度
gpu_temp = commands.getoutput('vcgencmd measure_temp | awk -F= \'{print $2}\'').replace('\'C','')
lcd_text('{:.2f}'.format(float(gpu_temp)) + ' C', LCD_LINE_1)
# 当前IP
ip = commands.getoutput('ifconfig wlan0 | grep inet | awk -Faddr: \'{print $2}\' | awk \'{print $1}\'')
lcd_text(ip, LCD_LINE_1)
# 内存
total_mem = commands.getoutput('free -m | grep Mem: | awk \'{print $2}\'')
free_mem = commands.getoutput('free -m | grep Mem: | awk \'{print $4}\'')
lcd_text(free_mem + ' / ' + total_mem + ' M', LCD_LINE_1)
晚安。
网友评论