Arduino/stm32数据采集并使用python实时绘图
准备软硬件:
1.开发板:Nucleo F767Zi
2. Arduino(安装stm32duino扩展开发板)
3. Python3,pySerial
Arduino开发轻量级的STM32应用非常方便,本文使用stm32duino官方的一个读取内部温度传感器的例子,通过串口每隔1s打印一组数据,烧写进stm32f767zi板子的代码为:
#include "stm32yyxx_ll_adc.h"
/* Values available in datasheet */
#define CALX_TEMP 25
#if defined(STM32F1xx)
#define V25 1430
#define AVG_SLOPE 4300
#define VREFINT 1200
#elif defined(STM32F2xx) || defined(STM32F4xx) && !defined(__LL_ADC_CALC_VREFANALOG_VOLTAGE)
#define V25 760
#define AVG_SLOPE 2500
#define VREFINT 1210
#endif
/* Analog read resolution */
#define LL_ADC_RESOLUTION LL_ADC_RESOLUTION_12B
#define ADC_RANGE 4096
//#define ATEMP
// the setup routine runs once when you press reset:
void setup() {
// initialize serial communication at 9600 bits per second:
Serial.begin(9600);
while (!Serial);
analogReadResolution(12);
static int32_t readVref()
#ifdef __LL_ADC_CALC_VREFANALOG_VOLTAGE
return (__LL_ADC_CALC_VREFANALOG_VOLTAGE(analogRead(AVREF), LL_ADC_RESOLUTION));
#else
return (VREFINT * ADC_RANGE / analogRead(AVREF)); // ADC sample to mV
#endif
#ifdef ATEMP
static int32_t readTempSensor(int32_t VRef)
#ifdef __LL_ADC_CALC_TEMPERATURE
return (__LL_ADC_CALC_TEMPERATURE(VRef, analogRead(ATEMP), LL_ADC_RESOLUTION));
#elif defined(__LL_ADC_CALC_TEMPERATURE_TYP_PARAMS)
return (__LL_ADC_CALC_TEMPERATURE_TYP_PARAMS(AVG_SLOPE, V25, CALX_TEMP, VRef, analogRead(ATEMP), LL_ADC_RESOLUTION));
#else
return 0;
#endif
#endif
static int32_t readVoltage(int32_t VRef, uint32_t pin)
return (__LL_ADC_CALC_DATA_TO_VOLTAGE(VRef, analogRead(pin), LL_ADC_RESOLUTION));
// the loop routine runs over and over again forever:
void loop() {
// print out the value you read:
int32_t VRef = readVref();
Serial.printf("VRef(mv)= %i", VRef);
#ifdef ATEMP
Serial.printf("\tTemp(°C)= %i", readTempSensor(VRef));
#endif
#ifdef AVBAT
Serial.printf("\tVbat(mv)= %i", readVoltage(VRef, AVBAT));
#endif
Serial.printf("\tA0(mv)= %i\n", readVoltage(VRef, A0));
delay(1000);
}
电脑端python通过pyserial接收串口数据,并且在matplotlib交互模式下动态绘图:
# -*- coding: utf-8 -*-
Created on Fri Jun 4 10:47:23 2021
@author: Wenqing Zhou ([email protected])
@github: https://github.com/ouening
import serial
import matplotlib.pyplot as plt
import datetime
plt.rcParams.update({
"font.family": "serif",
"font.serif": ["Times New Roman"], #Times New Roman
"font.size":11,
"legend.fancybox": False,
"legend.frameon": True,
"legend.framealpha": 1.0,
"legend.shadow": False,
"legend.facecolor": 'white',
"legend.edgecolor": 'none', # 'none', 0.8
"legend.fontsize": "small", # {'xx-small', 'x-small', 'small', 'medium', 'large', 'x-large', 'xx-large'}
"text.usetex": False,
count = 0
x = []
y = []
data = {}
def process_dataline(data:str):
''''VRef(mv)= 3304\tTemp(°C)= 41\tVbat(mv)= 834\tA0(mv)= 252'''
d = [] # [VRef, Temp, Vbat, A0]
line_split = line.split('\t')
for l in line_split:
k, v = l.split('=')
k, v = k.strip(), v.strip()
d.append(float(v))
return d[1:]
plt.ion()
# plt.legend(labels=['VRef', 'Temp', 'Vbat', 'A0'])
while 1:
plt.clf()
with serial.Serial('COM3', 9600, timeout=1.0) as ser:
line = ser.readline().decode(encoding='utf-8')
if line.startswith('VRef'):
line = line.replace('\n', '').replace(' ','')
d = process_dataline(line)
count+=1
# 只存储100个数据
if (len(x)==100) and (len(y)==100):
x.pop(0)
y.pop(0)
x.append(datetime.datetime.now()) # add timestamp
y.append(d[0]) # add temperature
print('Temp,Vbat,A0,count',d,count)
plt.plot(x,y)
plt.gcf().autofmt_xdate()
plt.xlabel('time')
plt.ylabel('Temperature')
plt.legend(labels=['Temp',])