树莓派串口
根据官方文档,树莓派0、1、2、3均有2个UARTS:UART、mini UART,其中 mini UART的不足:
- No break detection
- No framing errors detection
- No parity bit
- No receive timeout interrupt
- No DCD, DSR, DTR or RI signals
这时如果有多台外设需要通过串口采集数据该怎么办?
- 买usb转uart硬件,增加硬件串口数量;
- 用pigpio库模拟软串口。
软串口的不足是波特率高时,误包率偏高,不过根据测试,19200及以下波特率是可靠的,不需要做错误检测和恢复。
软串口可以利用26个BCM GPIO中的任意两个,除了14、15这一对自带uart,一个树莓派最多可以增加12个软串口!
PIGPIO
是一个利用CPU中断模拟脉冲的库,中文和安装方法可参考这篇博文。
//安装
sudo apt-get update
sudo apt-get install pigpio python-pigpio python3-pigpio
//设置pigpiod自启动
sudo systemctl enable pigpiod
软串口python代码
参考pyserial的调用方式,对pigpio的python方法进行了封装,增加了timeout,命名为softuart
import os
import time
import pigpio
class softuart(object):
"""soft uart(ttl) based on pigpio wiht Rx & Tx GPIO need to be set"""
def __init__(self, rxPin, txPin, baud=9600, timeout=5):
self._rxPin = rxPin
self._txPin = txPin
self._baud = baud#according to https://www.raspberrypi.org/forums/viewtopic.php?p=694626, bard>19200 is not reliable
self._timeout = timeout
# PIGPIO
self._pi = pigpio.pi()
if not self._pi.connected:
os.system('sudo pigpiod')
self._pi = pigpio.pi()
self._pi.set_mode(self._rxPin, pigpio.INPUT)
self._pi.set_mode(self._txPin, pigpio.OUTPUT)
def flushInput(self):
pigpio.exceptions = False#fatal exceptions off (so that closing an unopened gpio doesn't error)
self._pi.bb_serial_read_close(self._rxPin)
pigpio.exceptions = True
self._pi.bb_serial_read_open(self._rxPin, self._baud, 8)#open a gpio to bit bang read, 1 byte each time.
def write(self, msg):
self._pi.wave_clear()
self._pi.wave_add_serial(self._txPin, self._baud, msg)#create a waveform representing msg
wid = self._pi.wave_create()
start = time.time()
self._pi.wave_send_once(wid)
succeed=True
while self._pi.wave_tx_busy():# wait until all data sent or timeout
pass
if (time.time()-start)>self._timeout:
succeed=False
break
self._pi.wave_delete(wid)
return succeed
def read(self, size):
count=1
text=""
lt=0
start = time.time()
while count:
(count,data)=self._pi.bb_serial_read(self._rxPin)
if count:
text = text+data
lt = lt+count
if (time.time()-start)>self._timeout:
break
if len(text)==size:
break
time.sleep(0.1)# enough time to ensure more data
return text
软串口测试
利用BCM 6(GPIO.22) 13(GPIO.23)分别作为Rx和Tx,替换噪声一文中的GPIO.15、GPIO.14,测试代码修改为:
import time
#import serial
import softuart
import sys
import RPi.GPIO as GPIO
#port="/dev/ttyAMA0"
#usart=serial.Serial(port,9600,timeout=None)
usart=softuart.softuart(6,13,9600)
usart.flushInput()
sendbuf = bytearray.fromhex("01 03 00 00 00 01 84 0A")
while True:
usart.write(sendbuf)
recvbuf = bytearray(usart.read(7))
b1 = int(recvbuf[3])
b0 = int(recvbuf[4])
result = (b1<<8) | b0
print(result/10.0)
#time.sleep(.05)
time.sleep(1)
头2次调用之后可以正常读到数据。
sudo top可以看到,pigpiod进程占用cpu 9%左右。