python 3 with serial :dynamic update /save MCU uart value with csv file

This article is an implement of:

1. dynamic update chart by matplotlib
2. raw data input by serial (COM port)
3. start/pause function for save value array
4. save as .csv format with system time as file name.

finally, it will be like this:

my Python Settings:

Install Package in Python 3.6:

from __future__ import print_function
import matplotlib
import matplotlib.pyplot as plt
from matplotlib.gridspec import GridSpec
from matplotlib.widgets import Button
import numpy as np

import serial

import datetime
import csv

STEP 0. check your COM port number at Device manager:
my MCU now is COM61

STEP 1. check uart input format
For this example, I define my MCU input in this format:

‘@’ (0x40) as begin, ‘#’ (0x23) as end
5 random values from 0 to 4096 , seperated by ‘,’ (0x2c)

and I want to dynamic show on plot

STEP 2. new Python project file, install package
at the front of this article, I post every package this project need.

from __future__ import print_function
import matplotlib
import matplotlib.pyplot as plt
from matplotlib.gridspec import GridSpec
from matplotlib.widgets import Button
import numpy as np

import serial

import datetime
import csv

STEP 3. add these file into project file path

main.py
replace

COM = ‘COM61’

as your COM number checked in STEP 0.

from __future__ import print_function
import matplotlib
import matplotlib.pyplot as plt
from matplotlib.gridspec import GridSpec
from matplotlib.widgets import Button

import datetime
import csv

import class_serial_input as serial
import class_line as line

UPDATE_INTERVAL_IN_MSEC = 80

SERIAL_DATA_IN = 1
SERIAL_DATA_STOP = 0

serial_data_flag = SERIAL_DATA_IN

COM = ‘COM61’

def start_func(label):
print(” in start func”)

global serial_data_flag
serial_data_flag = SERIAL_DATA_IN

def stop_func(label):
print(” in stop func”)

global serial_data_flag
serial_data_flag = SERIAL_DATA_STOP

def save_chart_csv(label):
print(” save chart as csv”)

i_line_data = i_line.get_i_line()

with open(‘output_%u_%u_%u_%u_%u_%u.csv’ % (now_time.year, now_time.month, now_time.day,
now_time.hour, now_time.minute, now_time.second),
‘w’, newline=”) as csvfile:
writer = csv.writer(csvfile, delimiter=’,’)
writer.writerow(i_line_data)

if __name__ == “__main__”:
print(“start up \r\n”)

#default_port = serial_data.Serial_data(“random_data” sys.argv[1])
default_port = serial.serial_input(“random_data”,com=COM)

#init matplot interface
fig = plt.figure(‘random serial value chart power by Agatha Kuan’, figsize=(10, 8))
gs = GridSpec(14, 14, left=0.01, bottom=0.01, right=1 - 0.01, top=1 - 0.01, wspace=1, hspace=1)

i_chart_axes = plt.subplot(gs[1:8, 6:14])
i_chart_axes.axis([0, 4, 0, 4096])

plt.ion()

plt.ylabel(“random value”, color=’#8d734b’, size=12, family=’monospace’)
plt.title(“signal chart”, color=’#8d734b’, size=15, family=’monospace’)

plt.grid(True)

#init line
i_line = line.Init_line(“line_1”)

#init button
point_start = plt.subplot(gs[1, :4])
button_start = Button(point_start, ‘start’, color=’0.95’, hovercolor=’0.6’)
button_start.label.set_fontsize(11)
button_start.on_clicked(start_func)

point_stop = plt.subplot(gs[2, :4])
button_stop = Button(point_stop, ‘pause’, color=’0.95’, hovercolor=’0.6’)
button_stop.label.set_fontsize(11)
button_stop.on_clicked(stop_func)

point_save_csv = plt.subplot(gs[4, :2])
button_save_csv = Button(point_save_csv, ‘save as .CSV’, color=’0.95’, hovercolor=’0.6’)
button_save_csv.label.set_fontsize(11)
button_save_csv.on_clicked(save_chart_csv)

now_time = datetime.datetime.now()
sys_start_time = datetime.datetime.now()

time_stamp = plt.subplot(gs[7:11, :2])
time_stamp.axis(‘off’)
time_stamp_text = plt.text(0.01, 0.05, ” “, color=’#8d734b’, size=12, family=’monospace’,
transform=time_stamp.transAxes)

while 1 :
if SERIAL_DATA_STOP != serial_data_flag:
default_port.get_serial_data()
i_tmp = default_port.get_data()

i_line.draw_update_thershold()
i_line.draw_update_signal_line(i_tmp)

i_chart_axes.relim(True)
i_chart_axes.autoscale_view(True, ‘y’, True)

now_time = datetime.datetime.now()
time_stamp_text.set_text(“start at %u/%u %u:%u:%u \n\n”
“System Time %u/%u %u:%u:%u \n”%(sys_start_time.month,sys_start_time.day,sys_start_time.hour,
sys_start_time.minute,sys_start_time.second,
now_time.month, now_time.day,now_time.hour,
now_time.minute, now_time.second))

fig.canvas.draw()
plt.pause(float(UPDATE_INTERVAL_IN_MSEC) / 1000.0)

default_port.clear_data()

class_serial_input.py

import serial

import numpy as np

POINT_TO_UPDATE = 5
SEPERATE_SIGN = 0x2C
DATA_MAX_LEN = (2+(1+4)*(POINT_TO_UPDATE+1))*2

__metaclass__ = type

class serial_input:
def __init__(self,name,com=’COM61’,baudrate=115200):

self.ser = serial.Serial(com, baudrate)

self.port = com
self.baudrate = baudrate

self.num_array = np.repeat(0x00, POINT_TO_UPDATE)

def get_serial_data(self):
self.ser.flushInput()

char_in = self.ser.read(DATA_MAX_LEN)
char_in = bytearray(char_in)

temp = np.repeat(0x00, DATA_MAX_LEN)
valid_tmp = np.repeat(0x00, DATA_MAX_LEN)

for i in range (DATA_MAX_LEN):
temp[i] = int(char_in[i])

start_addr = np.argwhere(temp == 0x40)
end_addr = np.argwhere(temp == 0x23)

if(int(start_addr[0]) < int(end_addr[0])):
start = int(start_addr[0])
end = int(end_addr[0])
for i in range (end-start):
valid_tmp[i] = temp[start+1+i]
else:
start = int(start_addr[0])
end = int(end_addr[1])
for i in range(end - start):
valid_tmp[i] = temp[start + 1 + i]

common_addr = np.argwhere(valid_tmp == 0x2c)

for i in range (int(common_addr[0])):
self.num_array[0] = self.num_array[0]+(valid_tmp[i]-0x30)*pow(10, int(common_addr[0])-1-i)

for i in range(1,4):
start = int(common_addr[i-1])
end = int(common_addr[i])

for j in range(0,end-start-1):
self.num_array[i] = self.num_array[i] + (valid_tmp[start+1+j]-0x30)*pow(10,end-start-2-j)

end_addr = np.argwhere(valid_tmp == 0x23)

for i in range (int(end_addr[0])-int(common_addr[3])-1):
self.num_array[4] = self.num_array[4]+(valid_tmp[int(common_addr[3])+1+i]-0x30)*pow(10, int(end_addr[0])-int(common_addr[3])-2-i)

def get_data(self):

print(self.num_array)
return self.num_array

def clear_data(self):
self.num_array = np.repeat(0x00, POINT_TO_UPDATE)

class_line.py

線條的顏色: https://www.cnblogs.com/darkknightzh/p/6117528.html

import matplotlib.pyplot as plt
import numpy as np

__metaclass__ = type

THRESHOLD_VALUE = 2000

TIME_WINDOW_WIDTH_IN_SEC = 2.0

POINTS_IN_ONE_UPDATE = 5
VIEW_POINT_IN_SEC = 1*POINTS_IN_ONE_UPDATE

TIME_STAMP_ARRAY = np.arange(0, VIEW_POINT_IN_SEC, 1)

class Init_line:
def __init__(self,name):
global TIME_STAMP_ARRAY

self.time_window_begin = 0.0
self.time_window_end = self.time_window_begin + TIME_WINDOW_WIDTH_IN_SEC

self.time_line_value = TIME_STAMP_ARRAY
self.thershold_line_value = np.repeat(THRESHOLD_VALUE, len(self.time_line_value))

freq = 5.0
omega = 2.0 * np.pi * freq
constant_for_signal_shift = 1
self.i_raw_line_value = np.sin(omega * self.time_line_value) + constant_for_signal_shift

self.thershold_line, = plt.plot(self.time_line_value, self.thershold_line_value,label=”thershold”,color=’#0080FF’)
self.i_raw_line, = plt.plot(self.time_line_value, self.i_raw_line_value,label=”I raw”, color=’#FF8000’)

plt.legend(loc=’upper right’)

def draw_thershold(self):
self.thershold_line, = plt.plot(self.time_line_value, self.thershold_line_value)

def draw_update_thershold(self):
global TIME_STAMP_ARRAY

self.time_line_value = TIME_STAMP_ARRAY
self.thershold_line.set_data(self.time_line_value, self.thershold_line_value)

def draw_init_signal_line(self):
self.i_raw_line, = plt.plot(self.time_line_value, self.i_raw_line_value)

def draw_update_signal_line(self,update_i_temp):
self.i_raw_line_value = np.roll(self.i_raw_line_value, -POINTS_IN_ONE_UPDATE)
self.i_raw_line_value[-(POINTS_IN_ONE_UPDATE):] = update_i_temp

self.i_raw_line.set_data(self.time_line_value, self.i_raw_line_value)

def get_i_line(self):
return self.i_raw_line_value

STEP 4.run the Python file

when you run this python script, the PLOT start to update.

STEP 5. SAVE as csv file with time stamp as file name

press pause button to pause the update plot, then
press save as csv button

you will see a csv file in project path with time stamp as file name

open the file  in EXCEL, you can see the raw data:

NOTE:

  • this implement only use matplotlib to draw figure and canvas, didn’t use other graphic UI structure like TKinter or PyQT5
  • the speed of COM data update is limited cause I didn’t use multi-thread programming.

reference:

  1. https://www.cnblogs.com/darkknightzh/p/6117528.html
  2. https://zhuanlan.zhihu.com/p/32019813
  3. https://tw.saowen.com/a/aeeef5a75c5a3589f64d9f31953295c1b21a60ff72902f6e93f16327be2d3d78
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值