添加链接
link管理
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接

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',])