美文网首页玩转树莓派
树莓派折腾记#2:使用GPIO驱动LCD1602液晶屏模块

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

作者: LittleMagic | 来源:发表于2019-07-12 23:58 被阅读39次

    前言

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

    晚安。

    相关文章

      网友评论

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

        本文链接:https://www.haomeiwen.com/subject/vvlykctx.html