Python串口编程初探
逸山 2016/8/13 Python
今天在网上购买了一套环境监测板,功能十分强大,支持PM2.5,PM10,TVOC,甲醛以及温湿度测量。模块使用串口TTL向上位机传输数据,协议结构简单,每秒上传一次数据。以下记录一下用PYTHON读取和计算数据的过程,以免下次忘了。
# 安装模块
强大的Python拥有强大的库,几乎可以解决所有问题,而我需要的就是端杯茶,敲几行代码,耶!请出强大的pip工具,在windows命令行下键入以下代码:
pip install pyserial
坐下来喝杯茶,等待模块安装完成,继续下一步。
# 操作串口
先上代码
import serial
ser=serial.Serial(port='COM4',baudrate=9600,bytesize=8,parity=serial.PARITY_NONE,stopbits=1,timeout=5)
两行代码,引入模块,打开串口,下面说一下参数:
- port:不需多做解释,去设备管理器查看
- baudrate:波特率,根据实际情况设定,这里设置为9600
- bytesize:位数,根据实际情况可以设置为5、6、7、8,也可以用模块的常量(FIVEBITS, SIXBITS, SEVENBITS, EIGHTBITS)
- parity:校验位,根据实际情况可以设置为PARITY_NONE, PARITY_EVEN, PARITY_ODD, PARITY_MARK, PARITY_SPACE
- stopbist:停止位,根据实际情况可以设置为STOPBITS_ONE, STOPBITS_ONE_POINT_FIVE, STOPBITS_TWO
- timeout:超时,此参数设计同步和异步编程
- timeout=None, # set a timeout value, None for waiting forever 上面timeout的意思是,如果是none,那么程序永远会死在这里.一直等待
- timeout=0 # non-blocking mode (return immediately on read) timeout = 0: 非阻塞形式 (读完之后就返回,费时的io操作,就直接交给后台处理了)
- timeout=x # set timeout to x seconds (float allowed) 超时时间一到,程序就是继续执行
还有如下一些参数:
- xonxoff=0, # enable software flow control
- rtscts=0, # enable RTS/CTS flow control
- interCharTimeout=None # Inter-character timeout, None to disable
以下代码为读取数据:
print("PM2.5 PM10 TVOC 湿度 温度 甲醛 ")
while ser.isOpen():
n = ser.inWaiting()
if n == 16:
x=ser.readline(n)
z = struct.unpack_from('>3B6HB', x)
if z[0] == 0xAA:
print("{0} {1} {2} {3} {4} {5}".format(z[3],z[4],z[5]/100,z[6]/10,z[7]/10,z[8]/100))
ser.close()
- isOpen():判断串口有没有成功打开
- inWaiting():返回接收缓冲区的数据长度
其他一些方法
- open() # open port
- close() # close port immediately
- setBaudrate(baudrate) # change baud rate on an open port
- inWaiting() # return the number of chars in the receive buffer
- read(size=1) # read "size" characters
- write(s) # write the string s to the port
- flushInput() # flush input buffer, discarding all it's contents
- flushOutput() # flush output buffer, abort output
- sendBreak() # send break condition
- setRTS(level=1) # set RTS line to specified logic level
- setDTR(level=1) # set DTR line to specified logic level
- getCTS() # return the state of the CTS line
- getDSR() # return the state of the DSR line
- getRI() # return the state of the RI line
- getCD() # return the state of the CD line
# 数据处理
以上代码涉及数据处理的方法就一行,使用struct模块,充分体现了python的简洁高效,下面介绍一下Python struct模块的使用。
struct模块为python处理字节流的库,可以很方便的把python数据编辑为字节流,提供给网络或其他通讯模块使用,该库为python默认库,无需安装。
先看一下使用方法:
>>> from struct import *
>>> pack('hhl', 1, 2, 3)
b'\x00\x01\x00\x02\x00\x00\x00\x03'
>>> unpack('hhl', b'\x00\x01\x00\x02\x00\x00\x00\x03')
(1, 2, 3)
>>> calcsize('hhl')
8
>>> record = b'raymond \x32\x12\x08\x01\x08'
>>> name, serialnum, school, gradelevel = unpack('<10sHHb', record)
>>> name, serialnum, school, gradelevel
(b'raymond ', 4658, 264, 8)
- pack():将字符编码
- ‘hhl’:编码规则,具体规则如下,这里前两个为short,后一个为int。连续的类型可以用数字代替,比如“2hi”
Format | C Type | Python type | Standard size | Notes |
---|---|---|---|---|
x | pad byte | no value | ||
c | char | bytes of length 1 | 1 | |
b | signed char | integer | 1 | (1),(3) |
B | unsigned char | integer | 1 | (3) |
? | _Bool | bool | 1 | (1) |
h | short | integer | 2 | (3) |
H | unsigned short | integer | 2 | (3) |
i | int | integer | 4 | (3) |
I | unsigned int | integer | 4 | (3) |
l | long | integer | 4 | (3) |
L | unsigned long | integer | 4 | (3) |
q | long long | integer | 8 | (2), (3) |
Q | unsigned long long | integer | 8 | (2), (3) |
n | ssize_t | integer | (4) | |
N | size_t | integer | (4) | |
f | float | float | 4 | (5) |
d | double | float | 8 | (5) |
s | char[] | bytes | ||
p | char[] | bytes | ||
P | void * | integer | (6) |
- 1,2,3:待编码的数据
- calcsize():计算按此规则编码需要的字节数,‘hhi’需要8个字节,根据上表short为2字节,int为4字节,2*2+4=8。
- unpack():解码数据,第一个参数为编码规则,参考上表,第二个参数为字节数据。
关于编码规则需要注意字节序,熟悉C编程的都知道,计算机有大端序和小端序之分,网络数据统一为大端序。字节序如果不设置为本机序列,此次的传感器模块传输的为大端序,需要在规则前加上“>”,具体规则如下表:
Character | Byte order | Size | Alignment |
---|---|---|---|
@ | native | native | native |
= | native | standard | none |
< | little-endian | standard | none |
> | big-endian | standard | none |
! | network (= big-endian) | standard | none |
另外,还要注意字节对齐的问题,如:
>>> calcsize("3ch")
6
>>> calcsize("4ch")
6
>>> calcsize("=4ch")
6
>>> calcsize("=3ch")
5
‘3ch’:如果使用默认设置需要6个字节,这是由于字节对齐造成的,系统是按照4字节对齐,所以多出一个字符。使用‘=’可以设置系统不按字节对齐,所以需要5个字节。