zoukankan      html  css  js  c++  java
  • 使用Python控制1602液晶屏实时显示时间(附PyCharm远程调试)

    前言

    原创文章,转载引用务必注明链接。水平有限,如有疏漏,欢迎指正。

    本文介绍一下UP板的GPIO资源使用,以及一个使用Python演示一个简单的demo。

    本文使用Markdown写成,为获得更好的阅读体验和正常的图片、链接,请访问我的博客:

    http://www.cnblogs.com/sjqlwy/p/up_1602.html

    本文环境:ublinux 3.0;Win7_x64

    通过阅读本文你可以学到:

    • UP Board GPIO 接口的介绍以及使用
    • PyCharm 远程调试 UP上的Python代码
    • Lemaker LN IO 拓展板的使用
    • 使用RPi.GPIO这个Python库控制1602液晶屏

    UP板载GPIO接口介绍

    UP板的GPIO接口兼容树莓派40 Pin。实现起来比较复杂,部分从Intel Atom Z8350引出(需要电平转换),部分由板载CPLD实现。

    操作GPIO

    官方提供了三种方式:用户空间sysfs (shell)、RPi.GPIO库(Python)和libMRAA(多种编程语言)。

    Lemaker LN IO拓展板介绍

    之前在云汉社区试用Lemaker Guitar开发板时一并入手的。兼容树莓派引脚。个人非常喜欢乐美客公司的产品,包括BananaPi、BananaPi Pro、Lemaker Guitar、96boards Hikey (Lemaker Version),以及包括LN IO在内的三款拓展板,做工优良,可以在官方微店买到。LN IO 介绍页面电路原理图

    【下面是Lemaker Guitar开发板,上面就是LN IO 拓展板】我们下面将会利用板载的4个按键、LED灯以及1602接口。

    Python控制LN IO 扩展板按键和LED

    最近在学习Python,恰巧ubilinux移植了RPi.GPIO库,让我们可以非常方便地操作GPIO资源。吐槽一下,由于被动散热片的存在,使用转接线等会卡到无法完全贴合。

    Blink!——控制发光二极管闪烁

    我们以点亮LN IO上的led2为例:

    【LED电路原理图】LCD和LED是切换显示的。可以看到LED2连接到GPIO0,那么GPIO0是对应树莓派是哪个引脚呢?

    【底板对应引脚】GPIO0对应物理引脚11。

    【UP Board 引脚定义图】为了方便起见,我们统一使用BOARD物理引脚编号而非BCM引脚编号。

    • 关于树莓派GPIO的操作可以参考芒果爱吃胡萝卜这个博客,写的非常不错,由浅入深。本文部分以他的博文为基础进行演示。
    • ubilinux移植的RPi.GPIO库仅兼容Python 2.x版本
    • 为方便转换,我们以BOARD编码GPIO引脚顺序(物理顺序)
    • LN IO Board的LED和LCD可以切换显示,连接帽导通不同引脚即可。

    下面创建一个文件lcd.py,内容如下,然后运行看看:sudo python lcd.py

    #!/usr/bin/env python
    # encoding: utf-8
    
    import RPi.GPIO as GPIO
    import time
    
    # 为保持兼容性,选择GPIO引脚主板编号模式,也就是物理引脚编号
    GPIO.setmode(GPIO.BOARD)
    LedPin = 11
    # 指定11引脚(就是LED长针连接的GPIO针脚)的模式为输出模式
    # LN IO 的GPIO0,主板编号是11,对应BCM模式引脚为17
    GPIO.setup(LedPin, GPIO.OUT)
    
    # 循环10次
    for i in range(0, 10):
    	# 让11引脚输出高电平(LED灯亮)
    	GPIO.output(LedPin, True)
    	# 持续一段时间
    	time.sleep(0.5)
    	# 让11引脚输出低电平(LED灯灭)
    	GPIO.output(LedPin, False)
    	# 持续一段时间
    	time.sleep(0.5)
    
    # 最后清理GPIO口(不做也可以,建议每次程序结束时清理一下,好习惯)
    GPIO.cleanup()
    

    效果如图所示:

    按键控制LED开关

    有了上面的我们再来试试用按键控制LED,很多用过Arduino的应该轻车熟路啦。

    #!/usr/bin/env python
    # encoding: utf-8
    
    import RPi.GPIO as GPIO
    import time
    
    # 为保持兼容性,选择GPIO引脚主板编号模式,也就是物理引脚编号
    GPIO.setmode(GPIO.BOARD)
    GPIO.setwarnings(False)
    LedPin = 11
    BtnPin = 13
    
    # 11引脚(LED2)为输出模式,13引脚(Key1)为输入模式
    GPIO.setup(LedPin, GPIO.OUT)
    GPIO.setup(BtnPin, GPIO.IN)
    
    try:
        GPIO.output(LedPin, True)
        while True:
            time.sleep(0.01)
            if (GPIO.input(BtnPin)) == False:
                GPIO.output(LedPin, False)
            else:
                GPIO.output(LedPin, True)
    except KeyboardInterrupt:
        pass
    
    # 最后清理GPIO口(不做也可以,建议每次程序结束时清理一下,好习惯)
    GPIO.cleanup()
    

    有兴趣的可以做一个防按键抖动(Debounce)版本。

    Python控制1602液晶屏显示当前时间

    感谢Hugo Zhu的这篇《如何使用Raspberry Pi在1602液晶屏上显示当前时间--电子钟》博文,他的博客非常棒,受益匪浅。以下仍然以BOARD编码为例。

    硬件包括LN IO 拓展板;1602液晶屏;USB无线网卡;UPBoard。注意LN IO拓展板将连接帽切换到LCD引脚。

    1602液晶屏的引脚定义:

    1. VSS,接地
    2. VDD,接3.3V电源
    3. VO,液晶对比度调节,接电位器中间的引脚(板载R2)
    4. RS,寄存器选择,接PB 03,Pin 29
    5. RW,读写选择,接地,表示写模式
    6. EN,使能信号,接PB 13,Pin 33
    7. D0,数据位0,4位工作模式下不用,不接
    8. D1,数据位1,4位工作模式下不用,不接
    9. D2,数据位2,4位工作模式下不用,不接
    10. D3,数据位3,4位工作模式下不用,不接
    11. D4,数据位4,接GPIO 4,Pin 16
    12. D5,数据位5,接GPIO 5,PIN 18
    13. D6,数据位6,接GPIO 6,PIN 22
    14. D7,数据位7,接GPIO 7,PIN 7
    15. A,液晶屏背光+,接3.3v
    16. K,液晶屏背光-,接地

    源代码可以从github页面下载,修改相关引脚序号,如下:

    #!/usr/bin/python
    
    #
    # based on code from lrvick and LiquidCrystal
    # lrvic - https://github.com/lrvick/raspi-hd44780/blob/master/hd44780.py
    # LiquidCrystal - https://github.com/arduino/Arduino/blob/master/libraries/LiquidCrystal/LiquidCrystal.cpp
    #
    
    from time import sleep
    from datetime import datetime
    from time import sleep
    
    class Adafruit_CharLCD:
    
        # commands
        LCD_CLEARDISPLAY            = 0x01
        LCD_RETURNHOME              = 0x02
        LCD_ENTRYMODESET            = 0x04
        LCD_DISPLAYCONTROL          = 0x08
        LCD_CURSORSHIFT             = 0x10
        LCD_FUNCTIONSET             = 0x20
        LCD_SETCGRAMADDR            = 0x40
        LCD_SETDDRAMADDR            = 0x80
    
        # flags for display entry mode
        LCD_ENTRYRIGHT              = 0x00
        LCD_ENTRYLEFT               = 0x02
        LCD_ENTRYSHIFTINCREMENT     = 0x01
        LCD_ENTRYSHIFTDECREMENT     = 0x00
    
        # flags for display on/off control
        LCD_DISPLAYON               = 0x04
        LCD_DISPLAYOFF              = 0x00
        LCD_CURSORON                = 0x02
        LCD_CURSOROFF               = 0x00
        LCD_BLINKON                 = 0x01
        LCD_BLINKOFF                = 0x00
    
        # flags for display/cursor shift
        LCD_DISPLAYMOVE             = 0x08
        LCD_CURSORMOVE              = 0x00
    
        # flags for display/cursor shift
        LCD_DISPLAYMOVE             = 0x08
        LCD_CURSORMOVE              = 0x00
        LCD_MOVERIGHT               = 0x04
        LCD_MOVELEFT                = 0x00
    
        # flags for function set
        LCD_8BITMODE                = 0x10
        LCD_4BITMODE                = 0x00
        LCD_2LINE                   = 0x08
        LCD_1LINE                   = 0x00
        LCD_5x10DOTS                = 0x04
        LCD_5x8DOTS                 = 0x00
    
    
    # LN IO Board: RS=PB03=29, EN=PB13=33; DB4-7=GPIO4-7=16,18,22,7
        def __init__(self, pin_rs=29, pin_e=33, pins_db=[16,18,22,7], GPIO = None):
            # Emulate the old behavior of using RPi.GPIO if we haven't been given
            # an explicit GPIO interface to use
            if not GPIO:
                import RPi.GPIO as GPIO
            GPIO.setwarnings(False)
    
            self.GPIO = GPIO
            self.pin_rs = pin_rs
            self.pin_e = pin_e
            self.pins_db = pins_db
    
            self.GPIO.setmode(GPIO.BOARD)
            self.GPIO.setup(self.pin_e, GPIO.OUT)
            self.GPIO.setup(self.pin_rs, GPIO.OUT)
    
            for pin in self.pins_db:
                self.GPIO.setup(pin, GPIO.OUT)
    
            self.write4bits(0x33) # initialization
            self.write4bits(0x32) # initialization
            self.write4bits(0x28) # 2 line 5x7 matrix
            self.write4bits(0x0C) # turn cursor off 0x0E to enable cursor
            self.write4bits(0x06) # shift cursor right
    
            self.displaycontrol = self.LCD_DISPLAYON | self.LCD_CURSOROFF | self.LCD_BLINKOFF
    
            self.displayfunction = self.LCD_4BITMODE | self.LCD_1LINE | self.LCD_5x8DOTS
            self.displayfunction |= self.LCD_2LINE
    
            """ Initialize to default text direction (for romance languages) """
            self.displaymode =  self.LCD_ENTRYLEFT | self.LCD_ENTRYSHIFTDECREMENT
            self.write4bits(self.LCD_ENTRYMODESET | self.displaymode) #  set the entry mode
    
            self.clear()
    
    
        def begin(self, cols, lines):
    
            if (lines > 1):
                    self.numlines = lines
                    self.displayfunction |= self.LCD_2LINE
                    self.currline = 0
    
    
        def home(self):
    
            self.write4bits(self.LCD_RETURNHOME) # set cursor position to zero
            self.delayMicroseconds(3000) # this command takes a long time!
    
    
        def clear(self):
    
            self.write4bits(self.LCD_CLEARDISPLAY) # command to clear display
            self.delayMicroseconds(3000)    # 3000 microsecond sleep, clearing the display takes a long time
    
    
        def setCursor(self, col, row):
    
            self.row_offsets = [ 0x00, 0x40, 0x14, 0x54 ]
    
            if ( row > self.numlines ): 
                    row = self.numlines - 1 # we count rows starting w/0
    
            self.write4bits(self.LCD_SETDDRAMADDR | (col + self.row_offsets[row]))
    
    
        def noDisplay(self): 
            """ Turn the display off (quickly) """
    
            self.displaycontrol &= ~self.LCD_DISPLAYON
            self.write4bits(self.LCD_DISPLAYCONTROL | self.displaycontrol)
    
    
        def display(self):
            """ Turn the display on (quickly) """
    
            self.displaycontrol |= self.LCD_DISPLAYON
            self.write4bits(self.LCD_DISPLAYCONTROL | self.displaycontrol)
    
    
        def noCursor(self):
            """ Turns the underline cursor on/off """
    
            self.displaycontrol &= ~self.LCD_CURSORON
            self.write4bits(self.LCD_DISPLAYCONTROL | self.displaycontrol)
    
    
        def cursor(self):
            """ Cursor On """
    
            self.displaycontrol |= self.LCD_CURSORON
            self.write4bits(self.LCD_DISPLAYCONTROL | self.displaycontrol)
    
    
        def noBlink(self):
            """ Turn on and off the blinking cursor """
    
            self.displaycontrol &= ~self.LCD_BLINKON
            self.write4bits(self.LCD_DISPLAYCONTROL | self.displaycontrol)
    
    
        def noBlink(self):
            """ Turn on and off the blinking cursor """
    
            self.displaycontrol &= ~self.LCD_BLINKON
            self.write4bits(self.LCD_DISPLAYCONTROL | self.displaycontrol)
    
    
        def DisplayLeft(self):
            """ These commands scroll the display without changing the RAM """
    
            self.write4bits(self.LCD_CURSORSHIFT | self.LCD_DISPLAYMOVE | self.LCD_MOVELEFT)
    
    
        def scrollDisplayRight(self):
            """ These commands scroll the display without changing the RAM """
    
            self.write4bits(self.LCD_CURSORSHIFT | self.LCD_DISPLAYMOVE | self.LCD_MOVERIGHT);
    
    
        def leftToRight(self):
            """ This is for text that flows Left to Right """
    
            self.displaymode |= self.LCD_ENTRYLEFT
            self.write4bits(self.LCD_ENTRYMODESET | self.displaymode);
    
    
        def rightToLeft(self):
            """ This is for text that flows Right to Left """
            self.displaymode &= ~self.LCD_ENTRYLEFT
            self.write4bits(self.LCD_ENTRYMODESET | self.displaymode)
    
    
        def autoscroll(self):
            """ This will 'right justify' text from the cursor """
    
            self.displaymode |= self.LCD_ENTRYSHIFTINCREMENT
            self.write4bits(self.LCD_ENTRYMODESET | self.displaymode)
    
    
        def noAutoscroll(self): 
            """ This will 'left justify' text from the cursor """
    
            self.displaymode &= ~self.LCD_ENTRYSHIFTINCREMENT
            self.write4bits(self.LCD_ENTRYMODESET | self.displaymode)
    
    
        def write4bits(self, bits, char_mode=False):
            """ Send command to LCD """
    
            self.delayMicroseconds(1000) # 1000 microsecond sleep
    
            bits=bin(bits)[2:].zfill(8)
    
            self.GPIO.output(self.pin_rs, char_mode)
    
            for pin in self.pins_db:
                self.GPIO.output(pin, False)
    
            for i in range(4):
                if bits[i] == "1":
                    self.GPIO.output(self.pins_db[::-1][i], True)
    
            self.pulseEnable()
    
            for pin in self.pins_db:
                self.GPIO.output(pin, False)
    
            for i in range(4,8):
                if bits[i] == "1":
                    self.GPIO.output(self.pins_db[::-1][i-4], True)
    
            self.pulseEnable()
    
    
        def delayMicroseconds(self, microseconds):
            seconds = microseconds / float(1000000) # divide microseconds by 1 million for seconds
            sleep(seconds)
    
    
        def pulseEnable(self):
            self.GPIO.output(self.pin_e, False)
            self.delayMicroseconds(1)               # 1 microsecond pause - enable pulse must be > 450ns 
            self.GPIO.output(self.pin_e, True)
            self.delayMicroseconds(1)               # 1 microsecond pause - enable pulse must be > 450ns 
            self.GPIO.output(self.pin_e, False)
            self.delayMicroseconds(1)               # commands need > 37us to settle
    
    
        def message(self, text):
            """ Send string to LCD. Newline wraps to second line"""
    
            for char in text:
                if char == '
    ':
                    self.write4bits(0xC0) # next line
                else:
                    self.write4bits(ord(char),True)
    
    
    if __name__ == '__main__':
    
        lcd = Adafruit_CharLCD()
        lcd.noBlink()
        # lcd.clear()
        # lcd.message("Hello, Jessica!
    How are you? .....abcdefghijg ")
        # lcd.scrollDisplayRight()
    
        while True:
            sleep(1)
            lcd.clear()
            lcd.message(datetime.now().strftime('  %I : %M : %S 
    %a %b %d %Y'))
    

    每秒更新,显示当前时间,效果如图所示:

    进阶

    分析代码可知,该代码段可作为1602驱动库,支持1602的基本显示控制。后面可以自定义显示自己的信息,例如做一个小闹钟。

    PyCharm远程调试UP Board上的Python程序

    由于在UP Board上使用终端界面调试Python确实不很方便(其实是PyCharm用起来太爽了),所以使用Windows 上的PyCharm调试UP Board上的程序,可以直接使用UP的GPIO硬件资源,并且可以非常方便地安装各种库,简直停不下来,当然前文提到的cloud9也不错。远程调试功能只有专业版(Professional)可用,免费的社区版(Community)无此功能。通过edu邮箱验证可以免费使用专业版。

    参考这篇文章pycharm 远程调试进行设置即可,注意点如下:

    • 因为我们使用ubilinux移植的RPi.GPIO库,所以解释器只能选择python2
    • 需要启用root账户并更改ssh设置允许root登录
    • 可以通过PyCharm更新UP板上的Python库
    sudo passwd root #启用root账户
    sudo nano /etc/ssh/sshd_config # 添加 PermitRootLogin yes,Ctrl+O保存,Ctrl+X退出
    sudo systemctl restart sshd # 重启SSH服务,使更改生效
    

    效果如图所示:

  • 相关阅读:
    va_start和va_end使用详解
    Visual Assist X设置
    google 快捷键
    /bin/sh^M: bad interpreter: No such file or directory 异常
    动态链接库的学习(一)
    sprintf函数的用法详解
    错误:在 C99 模式之外使用‘for’循环初始化声明
    VC6.0在win7下显示行号的插件
    错误: 程序中有游离的‘\302’ ‘\240’等
    Linux Shell编程笔记一:相关命令
  • 原文地址:https://www.cnblogs.com/sjqlwy/p/up_1602.html
Copyright © 2011-2022 走看看