Raspberry Pi Pico筆記(5):1602LCD顯示時間及板載溫度

上篇文章瞭解如何在 Arduino IDE 開發環境下,撰寫 C 語言控制 Pico,包括初始設定方法及編譯上傳程式的步驟,之後仍繼續 MicroPython 相關的實作,日後有時間再回來深入瞭解 Arduino IDE 搭配 Pico 開發環境的用法。LCD的顯示功能在微控制器的開發上,是很重要的,本篇要實作將日期、時間及開發板的溫度感測值顯示在 LCD1602 螢幕上。這裡同時也會用到呼叫其他程式的功能,透過函式呼叫控制 LCD1602 的各項功能,如顯示、移動游標等,讓撰寫程式變的簡單些。


Pi Pico的開發板上有個溫度傳感器,連接到 ADC(Analog-to-digital converter,或稱 A/D 或 A to D) 類比數位轉換的特殊引腳,在規格圖上,可以看到 Pin 31-35 標記 ADC0, ADC1, AGND, ADC2 和 ADC_VREF(或稱 ADC3,偵測硬體電壓用)從外部接 ADC。Pico 開發板上的溫度傳感器沒有實體的引腳,但可以透過存取 ADC4 得到數值。
ADC 的存取方式和一般的 GPIO 不同,原因是 GPIO 僅顯示高電位和低電位兩種狀態,而 ADC 會取得不同的電壓數值。Pico 的 ADC 使用 12 位元來計算數值,表示偵測的值可以從 0 到 4095。但是 MicroPython 將 ADC 值擴充到 16 位元範圍,有效值從 0 到 65535。Pico的電壓以 3.3V 運行,這表示 ADC 引腳在 3.3V 電壓時,將傳回 65535 的值,若無電壓的情況下,傳回數值 0。當引腳施加的電壓介於 0 至 3.3V 之間時,將獲得介於兩者之間的值。
根據 Pico 開發板上的傳感器規格,溫度在攝氏 27 度時會提供 0.706V 的電壓,每升高攝氏 1 度,電壓就會降低 1.721 毫伏特,即 0.001721 伏特。可以用這個數值來換算當時 ADC 的電壓所得到的溫度。
from machine import ADC
temper_sensor = ADC(4)
temper_volts = temper_sensor.read_u16()
將 temper_volts 的電壓值,換算成 12 位元對應的數值。
temper_volts = temper_volts * 3.3 / 65535
將取得的電壓跟攝氏 27 度時的電壓相減,所得的電壓差,再除以每1度溫度的電壓變化值,就可以算出當時 Pico 開發板上的溫度。
celsius_degrees = 27 - (temper_volts - 0.706) / 0.001721
若要換算成華氏溫度,可以套用以下公式:
fahrenheit_degrees = celsius_degrees * 9 / 5 + 32
LCD1602若要以 I2C 通訊,需要外接一個模組 PCF8574,若不知道這個介面使用的 I2C 編號,可以執行以下程式取得,但是這個值是 10 進位。若要用在程式中,需再換算成 16 進位。
import machine
sda=machine.Pin(0)
scl=machine.Pin(1)
i2c=machine.I2C(0,sda=sda, scl=scl, freq=400000)
print(i2c.scan())
以 LCD1602 為例,得到的是 39,換算成 16 進位為 27,稍後的程式中會用到這個值。

[材料]

  • Raspberry Pi Pico x1
  • LCD1602液晶顯示器 x1
  • PCF8574 LCD連接模組 x1
  • 麵包板 x1
  • 排線 n 條

[接線圖]

LCD1602 需要5V電壓供電,而 Pico 提供的是 3.3V ,LCD1602 可以顯示,但字體及背景亮度不足;但是有一個替代的方案,是接 Pin40 的VBUS,根據「pico-datasheet」的描述,VBUS 是 micro-USB 的輸入電壓,連接到 micro-USB Port 的 Pin 1,通常是 5V,如果沒有接 USB 時,電壓為 0V。
Pi Pico接腳LCD1602 I2C接腳
Pin 1(GP0)SDA
Pin 2(GP1)SCL
Pin 38(GND)GND
Pin 40(VBUS)VCC



[程式]

LCD1602函式庫,我參考 Github 開發人員 Tyler Peppy 的函式,如要執行以下的程式,需要再下載 RPI-PICO-I2C-LCD 的 lcd_api.py 及 pico_i2c_lcd.py 兩個程式。將三個檔案放在同一個目錄內,可以是電腦目錄或 Pico 的虛擬磁碟。要特別注意檔名的大小寫要跟以下程式寫的一模一樣,否則呼叫程式時會出現錯誤,建議是全部都小寫,避免混淆。
程式中用到 utime 的 localtime()函式,說明如下:
  • utime.localtime(secs):取得系統的日期及時間。
如果未填入secs或空白,則使用 RTC 取得目前的日期、時間。這裡提供時間的是作業系統 OS 或 RTOS ,MicroPython 僅使用 OS API來查詢日期/時間。結果回傳8組日期數字,分別是年、月、日、時、分、秒、工作日及年日。採用陣列的方式取得。如以下例子,time = utime.localtime()取得的日期時間值會放在 time 陣列中,可用 time[0]取得年份、time[1]取得月份,於此類推至 time[7]取得年日 。程式所需的函式,包括:
import machine
import utime

from machine import ADC
from machine import I2C
from lcd_api import LcdApi
from pico_i2c_lcd import I2cLcd

I2C_ADDR     = 0x27   #LCD1602的I2C位址 
I2C_NUM_ROWS = 2      #LCD1602列數
I2C_NUM_COLS = 16     #LCD1602行數

i2c = I2C(0, sda=machine.Pin(0), scl=machine.Pin(1), freq=400000)   #設定I2C
lcd = I2cLcd(i2c, I2C_ADDR, I2C_NUM_ROWS, I2C_NUM_COLS)    

utime.sleep(2)
to_volts = 3.3 / 65535
temper_sensor = ADC(4)   #從ADC(4)取得溫度感測器的電壓值

while True:
    lcd.clear()
    time = utime.localtime()
    
    # 顯示日期及時間
    lcd.putstr("{month:>02d}/{day:>02d} {HH:>02d}:{MM:>02d}:{SS:>02d}".format(
        month=time[1], day=time[2], HH=time[3], MM=time[4], SS=time[5]))

    temper_volts = temper_sensor.read_u16() * to_volts  #取得當時溫度的電壓
   
    celsius_degrees = 27 - (temper_volts - 0.706) / 0.001721    #計算攝氏溫度
#   fahrenheit_degrees = celsius_degrees * 9 / 5 + 32           #計算華氏溫度

    lcd.move_to(0,1)      #游標跳至第二列第一行
    lcd.putstr('TEMP:')    
    lcd.putstr(str(round(celsius_degrees,3)))
    lcd.putstr(' oC')       #用小寫O代替度的符號    
    utime.sleep(3)          #暫停3秒鐘

[結果]

[參考資料]


2 留言

  1. 接線圖有誤
    Pin39 & Pin40 為 VSYS 與 VBUS 非 I2C 的 SDA 及 SCL

    回覆刪除
    回覆
    1. 非常感謝您的指正。我看一下原來的接線圖也覺得不太對勁,使用 VBUS 5V的電源,SDA 及 SCL 改接 Pin0 及Pin1,重新接線後 LCD1602 顯示正常,執行程式也沒問題。已經將接線圖、照片及影片更新。謝謝您!!

      刪除

張貼留言

較新的 較舊