1. ADC采集值绘制曲线#
1.1. 主要完以以下功能:#
从串口接收MCU发送的ADC采集数据
将ADC数据以图表的形式显示出来
1.2. MCU串口上传数据协议#
发送ADC值:
以
"/*"
开头以
"*/\r\n"
结尾中间ADC数据可以是ADC的16进制数据或ADC值转换后的ascii码 ascii码发送时以
","
做为数据分隔符
发送MCU计算后的数据
以
"$ "
开头以
" $\r\n"
结尾
1.3. 源代码#
import serial
from serial.tools.list_ports import comports
import time
from matplotlib import pyplot as plt
import matplotlib
import numpy as np
matplotlib.rc("font",family='MicroSoft YaHei',weight="bold")
port = 'COM12'
ports = [i.name for i in comports()]
adc_data_prefix = '/*'.encode()
adc_data_suffix = '*/\r\n'.encode()
mcu_calc_prefix = adc_data_suffix + '$ '.encode()
mcu_calc_suffix = ' $\r\n'.encode()
adc_send_by_buffer = 1
def get_bytes_with_prefix_suffix(data:bytes,prefix:bytes=adc_data_prefix,suffix:bytes=adc_data_suffix) -> bytes:
"""
从字节数据中截取指定开头和结尾的字节数据 -> bytes
prefix: 开始字节数据
suffix: 结尾字节数据
"""
start = data.find(prefix)
result = data[start+len(prefix):]
end = result.find(suffix)
# print("start:",start,"end:",end)
if start < 0 or end < 0:
raise Exception("\r\n{0}\r\n中没找到以{1}开头且{2}结尾的数据".format(data,prefix,suffix))
else:
return result[:end]
def draw_curves(data:list):
x = np.linspace(1,len(data),len(data))
y = np.array(data)
print("ADC max:{0} min:{1}\r\n{0}-{1}={2}".format(max(y),min(y),(max(y)-min(y))))
# print(f'DC:{np.average(y)}')
# print(f'AC:{np.sqrt(np.sum([(x-np.average(y)) **2 for x in y])/len(y))}')
# print(f'方差:{np.var(y)}')
# print(f'标准差:{np.std(y)}')
y1 = np.convolve(y,np.ones(4)/4,'same')
# for i in range(4):
# print(f'{i}:y[{i}]{y[i]},y1[{i}]{y1[i]}')
# # y1[i] = y[i]
# for i in range(len(y)-4,len(y),1):
# print(f'{i}:y[{i}]{y[i]},y1[{i}]{y1[i]}')
# y1[i] = y[i]
# y1 = y1[2:-1]
plt.figure(figsize=(20,10))
# plt.axes((0,65,1800,3000))
# plt.ylim(1500,2500)
plt.xlabel('采样点')
plt.ylabel('ADC值')
plt.title("MCU ADC采集值绘制的曲线")
plt.plot(x,y)
plt.plot(x,y1)
plt.show()
def adc_print_process(data:bytes) -> None:
if (data != b''):
adc_list = data.decode().split(',')
# 末尾可能有空字符,先去掉
adc_list = filter(lambda x: not x== '',adc_list)
# 字符串列表转换成数值列表
adc_list = list(map(int,adc_list))
draw_curves(adc_list)
def adc_buffer_process(data:bytes) -> None:
if(data != b''):
adc_list = np.frombuffer(data,np.uint32)
# print(adc_list)
draw_curves(adc_list)
if port not in ports:
raise Exception(f"seril port[{port}] error, Please select port in {ports}")
ser = serial.Serial()
ser.port = port
ser.baudrate = 115200
# 如果使用readlines来读取所有串口数据,需要设置一个超时时间这里是1ms,不设将一直接收
ser.timeout = 0.001
try:
ser.open()
# 如果用readall来读所有串口数据,在打开串后需等待一段时间用于接收数据。不然返回的都是空表
time.sleep(0.1)
seril_data = ser.read_all()
# seril_data = ser.readlines()
# print(seril_data)
seril_data = adc_data_prefix + get_bytes_with_prefix_suffix(seril_data,adc_data_prefix,mcu_calc_suffix) + mcu_calc_suffix
print(seril_data)
adc_data = get_bytes_with_prefix_suffix(seril_data,adc_data_prefix,adc_data_suffix)
# print(adc_data)
if adc_send_by_buffer:
# MCU 直接发送ADC内存区
adc_buffer_process(adc_data)
else:
# MCU 使用printf("%d,",adcValue[i])的形式上传ADC值
adc_print_process(adc_data)
mcu_calc = get_bytes_with_prefix_suffix(seril_data,mcu_calc_prefix,mcu_calc_suffix)
print("MCU calcutale:",mcu_calc.decode())
finally:
ser.close()
---------------------------------------------------------------------------
ModuleNotFoundError Traceback (most recent call last)
Cell In[1], line 1
----> 1 import serial
2 from serial.tools.list_ports import comports
3 import time
ModuleNotFoundError: No module named 'serial'
1.4. 待改进之处#
🛠️ 做成图形界面
🛠️ 多线程或异步IO模式
import numpy as np
import matplotlib.pyplot as plt
# plt.figure(figsize=(40,20))
# plt.plot([1, 2, 3, 4], [1, 4, 9, 16], 'ro')
x = np.linspace(0,2*np.pi,64)
y = 5*np.sin(x+np.deg2rad(0))
# y = [0,0,0,0,0,1,0,0,0,6,4,0,0,0,0,0,0,0,0,0,1,0,0,0,0,1,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,2,6,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0]
plt.plot(x,y,label='输入信号')
y1 = [np.average(y) for i in x]
plt.plot(x,y1,label=f'平均值:{y1[0]}')
y2 = [np.std(y) for i in x]
plt.plot(x,y2,label=f'标准差:{y2[0]}')
y3 = [np.var(y) for i in x]
plt.plot(x,y3,label=f'方差:{y3[0]}')
plt.plot(x,np.abs(y),'r')
# plt.text(2, 9, r'$\mu=100,\ \sigma=15$')
# plt.ylabel('some numbers')
plt.legend()
plt.show()
print(np.average(np.abs(y)))
import numpy as np
import matplotlib.pyplot as plt
x = np.linspace(0, 10, 1000)
y = 5*np.sin(2*np.pi*5*x) + 3*np.sin(2*np.pi*20*x) + np.random.normal(0, 0.5, 1000)
plt.figure(figsize=(50,10))
plt.plot(x, y)
def rms_smoothing(x, window_size):
window = np.ones(int(window_size))/float(window_size)
return np.sqrt(np.convolve(x**2, window, 'same'))
y_rms_5 = rms_smoothing(y, 1)
y_rms_20 = rms_smoothing(y, 20)
y_rms_100= rms_smoothing(y, 100)
plt.plot(x, y_rms_5, label='RMS窗口=5')
plt.plot(x, y_rms_20, label='RMS窗口=20')
plt.plot(x, y_rms_100, label='RMS窗口=100')
plt.title('不同RMS窗口下的平滑信号')
plt.legend()
plt.show()
# 实现数据可视化中的数据平滑
import numpy as np
import matplotlib.pylab as plt
'''
其它的一些知识点:
raise:当程序发生错误,python将自动引发异常,也可以通过raise显示的引发异常
一旦执行了raise语句,raise语句后面的语句将不能执行
'''
def moving_average(interval, windowsize):
window = np.ones(int(windowsize)) / float(windowsize)
re = np.convolve(interval, window, 'same')
return re
def LabberRing():
t = np.linspace(-4, 4, 100) # np.linspace 等差数列,从-4到4生成100个数
# print('t=', t)
# np.random.randn 标准正态分布的随机数,np.random.rand 随机样本数值
y = np.sin(t) + np.random.randn(len(t)) * 0.1 # 标准正态分布中返回1个,或者多个样本值
# print('y=', y)
plt.plot(t, y, 'k') # plot(横坐标,纵坐标, 颜色)
y_av = moving_average(y, 10)
plt.plot(t, y_av, 'b')
plt.xlabel('Time')
plt.ylabel('Value')
# plt.grid() #网格线设置
plt.grid(True)
plt.show()
return
LabberRing() # 调用函数
# https://blog.csdn.net/weixin_42782150/article/details/107176500