使用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 == '\n':
                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!\nHow are you? .....abcdefghijg ")
    # lcd.scrollDisplayRight()

    while True:
        sleep(1)
        lcd.clear()
        lcd.message(datetime.now().strftime('  %I : %M : %S \n%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服務,使更改生效

效果如圖所示:


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM