树莓派折腾记#2:使用GPIO驱动LCD1602液晶屏模块

前言

树莓派素有吃灰神器之称,与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)

晚安。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 218,284评论 6 506
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,115评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,614评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,671评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,699评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,562评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,309评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,223评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,668评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,859评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,981评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,705评论 5 347
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,310评论 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,904评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,023评论 1 270
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,146评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,933评论 2 355

推荐阅读更多精彩内容