1、从串口读取循环读取如同$4567.0,12.3,12.3#的字符串,字符串开始符、分隔符、结束符是规定好的
2、将字符串分割为如同4567.0、12.3、12.3的浮点型数据
3、将数据保存到csv文件中
4、按esc结束运行
Python 3.8.2
Python库:
multiprocessing, csv, serial, os(python自带)
keyboard 0.13.5
numpy 1.19.2
此程序原本开发的目的是将航模机载数据通过数传(串口)传到电脑上,供后期处理分析。
为了使串口调试方便,可以通过使用arduino或者其他单片机向串口按固定时间间隔输入数据,来模仿真实数传环境。如果有其他模拟方式也可,这不是重点。
为了便于终止程序、保存文档(强制终止可能导致csv文件损坏),采用双线程的方式同时保存数据和监听键盘输入。(才疏学浅,没有找到python中断的方法,并且目前了解到的键盘监听不是很麻烦就是拓展性不强,因此选用双线程通信的方法解决退出的问题。)
现在期末烤漆太紧张,有空再回来完善。
from multiprocessing import Process, Queue
import keyboard, csv, serial, os
import numpy as np
def get_numbers_from_serial(target_com, begin='\r\n', end='$', cut=','):
'''
从串口获得float类型数据列表
如果两个分隔符cut相邻或分隔符中间为无效字符串(无法转换为float的字符串),在中间位置补-32768
若起始符begin不符则返回空列表
'''
data = target_com.read_until(bytes(end, encoding='utf-8')) #一直读取直到遇到截止符end
data = data.decode('utf-8','ignore')
#print('gotten:', data)
begin_len=len(begin)
if (data[0:begin_len]!=begin): #检测begin是否与字符串开头相符
return []
cut_len = len(cut)
pos = begin_len
num_list = []
label = True
while (data[pos:] != end):
num_str = ''
#确认目标位及其后方不为cut和end
while (data[pos:] != end and data[pos:pos+cut_len] != cut):
label = True #至少采集到了一个有效字符
num_str = num_str+data[pos]
pos = pos+1
#根据label和num_str向num_list中赋值
if label:
try:
num_list.append(float(num_str))
except Exception:
num_list.append(-32768) #num_str为无效字符串
else:
num_list.append(-32768) #label为负,两个cut相邻
if data[pos:] != end:
pos = pos+cut_len
label = False
return num_list
def deal_with_csv_file(file_path='save_csv.csv', csv_head=[], mode='new'):
'''
csv文件预处理
file_path:文件保存的路径
mode两种模式:
'new'删除原同名文件(如果有)并新建文件
'add'在原文件后续写
csv_head是以列表形式给出的csv文件每列标题,只有在'new'模式才有用
'''
def create_csv(csv_head=[], path='save_csv.csv'):
'''
新建csv文件
'''
with open(path, 'w', newline='') as f:
csv_write = csv.writer(f)
if csv_head!=[]:
csv_write.writerow(csv_head)
if mode=='new': #新建模式
if os.path.isfile(file_path):
os.remove(file_path)
create_csv(csv_head, file_path)
elif mode=='add': #续写模式
if os.path.isfile(file_path)==False:
print('源文件缺失,自动新建')
create_csv(csv_head, file_path)
def serial_to_csv(q):
'''
第一进程,从串口保存数据到csv文件
'''
#初始设置
file_path = 'save_csv.csv' #保存文件名称
csv_head = ['速度A', '速度B', '速度C'] #数据含义
mode = 'new' #新建文件还是在原有文件上续写
# mode = 'add'
ser = serial.Serial('COM4', baudrate=115200) #串口信息(名称,波特率)
ser_msg = ['\r\n$', '#', ','] #串口符号规定,若有换行则需在原有开始符前加\r\n
show = True #是否实时展示数据
#csv文件预处理
deal_with_csv_file(file_path, csv_head, mode)
#开始读数并保存
with open(file_path,'a+', newline='') as f:
csv_write = csv.writer(f)
n = 0
while q.empty():
num_list=get_numbers_from_serial(ser, begin=ser_msg[0], end=ser_msg[1], cut=ser_msg[2])
csv_write.writerow(num_list)
if show:
print('\r', num_list, end='')
n = n+1
print('\n总共保存了', n-1, '个数据')
def key_board_listen(q):
'''
第二进程,键盘监听充当中断函数
'''
keyboard.wait('esc')
q.put(1)
if __name__ == "__main__":
'''
从串口保存数据到csv文件,具体参数设置在serial_to_csv中。
按下esc停止保存,程序退出
'''
q = Queue()
p1 = Process(target=serial_to_csv, args=(q,))
p2 = Process(target=key_board_listen, args=(q,))
p1.start()
p2.start()
p1.join()
p2.join()
from multiprocessing import Process, Queue
import keyboard, csv, serial, os
import numpy as np
def get_numbers_from_serial(target_com, begin='\r\n', end='$', cut=','):
'''
从串口获得float类型数据列表
如果两个分隔符cut相邻或分隔符中间为无效字符串(无法转换为float的字符串),在中间位置补-32768
若起始符begin不符则返回空列表
'''
data = target_com.read_until(bytes(end, encoding='utf-8')) #一直读取直到遇到截止符end
data = data.decode('utf-8','ignore')
#print('gotten:', data)
begin_len=len(begin)
if (data[0:begin_len]!=begin): #检测begin是否与字符串开头相符
return []
cut_len = len(cut)
pos = begin_len
num_list = []
label = True
while (data[pos:] != end):
num_str = ''
#确认目标位及其后方不为cut和end
while (data[pos:] != end and data[pos:pos+cut_len] != cut):
label = True #至少采集到了一个有效字符
num_str = num_str+data[pos]
pos = pos+1
#根据label和num_str向num_list中赋值
if label:
try:
num_list.append(float(num_str))
except Exception:
num_list.append(-32768) #num_str为无效字符串
else:
num_list.append(-32768) #label为负,两个cut相邻
if data[pos:] != end:
pos = pos+cut_len
label = False
return num_list
def deal_with_csv_file(file_path='save_csv.csv', csv_head=[], mode='new'):
'''
csv文件预处理
file_path:文件保存的路径
mode两种模式:
'new'删除原同名文件(如果有)并新建文件
'add'在原文件后续写
csv_head是以列表形式给出的csv文件每列标题,只有在'new'模式才有用
'''
def create_csv(csv_head=[], path='save_csv.csv'):
'''
新建csv文件
'''
with open(path, 'w', newline='') as f:
csv_write = csv.writer(f)
if csv_head!=[]:
csv_write.writerow(csv_head)
if mode=='new': #新建模式
if os.path.isfile(file_path):
os.remove(file_path)
create_csv(csv_head, file_path)
elif mode=='add': #续写模式
if os.path.isfile(file_path)==False:
print('源文件缺失,自动新建')
create_csv(csv_head, file_path)
def serial_to_csv(q):
'''
第一进程,从串口保存数据到csv文件
'''
#初始设置
file_path = 'save_csv.csv' #保存文件名称
csv_head = ['速度A', '速度B', '速度C'] #数据含义
mode = 'new' #新建文件还是在原有文件上续写
# mode = 'add'
ser = serial.Serial('COM4', baudrate=115200) #串口信息(名称,波特率)
ser_msg = ['\r\n$', '#', ','] #串口符号规定,若有换行则需在原有开始符前加\r\n
show = True #是否实时展示数据
#csv文件预处理
deal_with_csv_file(file_path, csv_head, mode)
#开始读数并保存
with open(file_path,'a+', newline='') as f:
csv_write = csv.writer(f)
n = 0
while q.empty():
num_list=get_numbers_from_serial(ser, begin=ser_msg[0], end=ser_msg[1], cut=ser_msg[2])
csv_write.writerow(num_list)
if show:
print('\r', num_list, end='')
n = n+1
print('\n总共保存了', n-1, '个数据')
def key_board_listen(q):
'''
第二进程,键盘监听充当中断函数
'''
keyboard.wait('esc')
q.put(1)
if __name__ == "__main__":
'''
从串口保存数据到csv文件,具体参数设置在serial_to_csv中。
按下esc停止保存,程序退出
'''
q = Queue()
p1 = Process(target=serial_to_csv, args=(q,))
p2 = Process(target=key_board_listen, args=(q,))
p1.start()
p2.start()
p1.join()
p2.join()
进程间的通信:multiprocessing库下的Pipe类与Queue类
python多进程的理解 multiprocessing Process join run
【python】详解multiprocessing多进程-process模块(一)
Python 键盘/鼠标监听及控制
Python 之 Serial串口通信 (可能不全)
python 读写csv文件(创建,追加,覆盖)
python读写、创建文件、文件夹等等