我們在上一節《【ODYSSEY-STM32MP157C】驅動 GPIO 實作呼吸燈》 已經驅動 GPIO 實作呼吸燈功能,本節我們將在 Linux 上操作 STM32MP157C 的 UART2 串口與傳感器進行通信,并將傳感器資料列印出來,

準備材料
- Seeed:ODYSSEY-STM32MP157C 開發板
- 攀藤:PMS5003ST 傳感器
PMS5003ST 簡介
PMS5003ST 是攀藤科技的一款空氣質量傳感器,可以同時監測空氣中顆粒物濃度(PM1.0、PM2.5、PM10)、甲醛濃度和環境溫濕度,由于采用激光散射原理,因此可以連續采集,并且有較高的精度和穩定性,

同時,傳感器模塊以通用數字介面形式輸出,簡化了控制端的開發,

PMS5003ST 的數字介面定義如下:
| 管腳 | 功能 | 說明 | STM32MP157C |
|---|---|---|---|
| PIN1 | VCC | 電源正(+5V) | ④ 5V |
| PIN2 | GND | 電源負 | ⑥ GND |
| PIN3 | SET | 設定管腳(3.3V) | |
| PIN4 | RXD | 串口接收管腳(3.3V) | ⑧ PF5/USART2_TX |
| PIN5 | TXD | 串口發送管腳(3.3V) | ⑩ PD6/USART2_RX |
| PIN6 | RESET | 模塊復位信號(3.3V,低復位) | |
| PIN7 | NC | - | |
| PIN8 | PWM/NC | PWM輸出 |
在本案例,我們只需要將傳感器的 PIN1、PIN2、PIN4、PIN5 與 ODYSSEY-STM32MP157C 擴展介面的 pin 4、6、8、10 連接即可,

安裝 usart2 驅動
-
在編譯之前,需要下載對應版本的內核頭檔案,
sudo apt update sudo apt install linux-headers-$(uname -r) -y注意:這一步可能需要開啟代理才能完成!
-
下載 seeed-linux-dtoverlays 倉庫,編譯并安裝 stm32p1 驅動,
git clone https://github.com/Seeed-Studio/seeed-linux-dtoverlays編譯、安裝
cd seeed-linux-dtoverlays make all_stm32mp1 CUSTOM_MOD_FILTER_OUT="jtsn-wm8960" sudo make install_stm32mp1 CUSTOM_MOD_FILTER_OUT="jtsn-wm8960"對應的 ko 檔案將安裝到 /lib/modules/4.19.9-stm32-r1/extra/seeed/ 目錄,dtbo 檔案將安裝到 /lib/firmware/ 目錄,
-
修改 /boot/uEnv.txt 檔案,在該檔案末尾添加一行,加載 usart2 驅動,
uboot_overlay_addr2=/lib/firmware/stm32mp1-seeed-usart2-overlay.dtbo -
reboot 重啟系統,可以看到系統增加了
/dev/ttySTM2設備節點,執行
dmesg | grep ttySTM*查看啟動資訊:[ 0.000000] Kernel command line: console=ttySTM0,115200 root=/dev/mmcblk0p6 ro rootfstype=ext4 rootwait coherent_poot [ 1.060447] 4000e000.serial: ttySTM2 at MMIO 0x4000e000 (irq = 25, base_baud = 4000000) is a stm32-usart [ 1.062277] 40010000.serial: ttySTM0 at MMIO 0x40010000 (irq = 27, base_baud = 4000000) is a stm32-usart [ 1.062366] console [ttySTM0] enabled [ 1.064147] 5c000000.serial: ttySTM1 at MMIO 0x5c000000 (irq = 70, base_baud = 4000000) is a stm32-usart [ 1.064420] serial serial0: tty port ttySTM1 registered執行
cat /proc/tty/driver/stm32-usart查看串口驅動:serinfo:1.0 driver revision: 0: uart:stm32-usart mmio:0x40010000 irq:27 tx:1141 rx:63 RTS|CTS|DTR|DSR|CD 1: uart:stm32-usart mmio:0x5C000000 irq:70 tx:44691 rx:2274 RTS|CTS|DTR|DSR|CD 2: uart:stm32-usart mmio:0x4000E000 irq:25 tx:0 rx:0 CTS|DSR|CD
讀取傳感器資料
實際上,只要我們在串口2連接上傳感器,就可以通過 cat /dev/ttySTM2 獲取傳感器的資料了,但是,這些是二進制格式的資料,我們看不懂,因此,我們需要對其進行決議,
測驗串口
我選擇用 Python 來編程,首先安裝 serial 和 pyserial 庫,
pip3 install serial
pip3 install pyserial
之后,我們可以在 Python 互動環境中進行測驗:
>>> import serial
>>> port = serial.Serial('/dev/ttySTM2', 9600)
>>> port.isOpen()
True
>>> port.close()
OK,沒問題,我們就可以開始寫個決議程式了!
決議資料
新建一個 show_pms5003st.py 檔案,添加代碼框架:
import sys
import glob
import serial
import time
dev_name = '/dev/ttySTM2'
baudrate = 9600
CMD_READ = bytearray([0x42, 0x4d, 0xe2, 0x00, 0x00, 0x01, 0x71])
CMD_PASS = bytearray([0x42, 0x4d, 0xe1, 0x00, 0x00, 0x01, 0x70])
CMD_ACTI = bytearray([0x42, 0x4d, 0xe1, 0x00, 0x01, 0x01, 0x71])
CMD_STAN = bytearray([0x42, 0x4d, 0xe4, 0x00, 0x00, 0x01, 0x73])
CMD_NORM = bytearray([0x42, 0x4d, 0xe4, 0x00, 0x01, 0x01, 0x74])
def loop(serial):
pass
def main():
print("Run ODYSSEY-uart demo")
s = serial.Serial(dev_name, baudrate)
if not s.isOpen():
s.open()
try:
s.write(CMD_PASS)
except Exception as err:
print(err)
finally:
time.sleep(1)
loop(s)
s.close()
if __name__ == '__main__':
main()
PMS5003ST 默認進入主動模式,即傳感器會周期地主動向外發送資料,因此我在打開串口之后做的第一件事就是將其設定為被動模式,由程式主動去查詢資料,回傳的資料格式如下:

由于一個有效資料由兩個位元組構成,因此我增加了一個函式來處理:
def pms_value(hByte, lByte):
return (hByte << 8 | lByte)
然后決議的重點就在 loop 函式中啦,因為每一個有效幀都是 0x42 + 0x4d 開頭,所以只要識別出來,并且獲取幀的長度進行決議即可,為了方便(偷懶),我沒有增加狀態記錄,只有資料長度為 36 位元組的才決議,然后進行校驗,抽取有效資料并列印出來,
loop 函式代碼如下:
def loop(serial):
while True:
serial.write(CMD_READ)
start1 = serial.read(1)
if (start1[0] == 0x42):
start2 = serial.read(1)
if (start2[0] == 0x4d):
print("Is a frame")
else:
continue
else:
continue
len1 = serial.read(1)
len2 = serial.read(1)
size = pms_value(len1[0], len2[0])
if (size == 36):
print("Is a response")
resp = serial.read(size)
for i in resp:
print("{:x}".format(i), end=' ')
print("")
checksum = pms_value(resp[size-2], resp[size-1])
dsum = start1[0] + start2[0] + len1[0] + len2[0]
for i in range(0, size - 2):
dsum = dsum + resp[i]
dsum = dsum & 0xffff
if (checksum != dsum):
print("Checksum invalid. {} != {}".format(checksum, dsum))
continue
PM1_0_CF1 = pms_value(resp[0], resp[1])
PM2_5_CF1 = pms_value(resp[2], resp[3])
PM10_0_CF1 = pms_value(resp[4], resp[5])
PM1_0_atm = pms_value(resp[6], resp[7])
PM2_5_atm = pms_value(resp[8], resp[9])
PM10_0_atm = pms_value(resp[10], resp[11])
air_0_3um = pms_value(resp[12], resp[13])
air_0_5um = pms_value(resp[14], resp[15])
air_1_0um = pms_value(resp[16], resp[17])
air_2_5um = pms_value(resp[18], resp[19])
air_5_0um = pms_value(resp[20], resp[21])
air_10_0um = pms_value(resp[22], resp[23])
hcho = pms_value(resp[24], resp[25])
temp = pms_value(resp[26], resp[27])/10
humi = pms_value(resp[28], resp[29])/10
version = resp[32]
errorCode = resp[33]
print("\nResponse => len: {} bytes, version: {:0>2x}, Error: {:0>2x}".format(size+4, version, errorCode))
print("+-----------------------------------------------------+")
print("| CF=1 | PM1.0 = {:<4d} | PM2.5 = {:<4d} | PM10 = {:<4d} |".format(PM1_0_CF1, PM2_5_CF1, PM10_0_CF1))
print("| atm. | PM1.0 = {:<4d} | PM2.5 = {:<4d} | PM10 = {:<4d} |".format(PM1_0_atm, PM2_5_atm, PM10_0_atm))
print("| | 0.3um = {:<4d} | 0.5um = {:<4d} | 1.0um = {:<4d} |".format(air_0_3um, air_0_5um, air_1_0um))
print("| | 2.5um = {:<4d} | 5.0um = {:<4d} | 10um = {:<4d} |".format(air_2_5um, air_5_0um, air_10_0um))
print("| extra | hcho = {:<4d} | temp = {:<.1f} | humi = {:<.1f} |".format(hcho, temp, humi))
print("+-----------------------------------------------------+\n")
time.sleep(3)
運行效果
執行 python3 show_pms5003st.py,運行情況如下:

非常棒,我們已經得到傳感器資料了,下一節我們將學習如何將這些資料上傳到云端,

轉載請註明出處,本文鏈接:https://www.uj5u.com/qianduan/151926.html
標籤:其他
上一篇:ADC實驗之光敏傳感器
