回到首页 返回首页
回到顶部 回到顶部
返回上一页 返回上一页

Beetle 树莓派RP2350 高精度电压监测系统 简单

头像 十四号花店 2025.05.22 13 0

引言

Beetle RP2350是DFRobot推出的一款高性能微型开发板,尺寸仅25×20.5mm(硬币大小),搭载树莓派RP2350芯片,支持双核架构(Cortex-M33或RISC-V),主频150MHz,配备520KB RAM和2MB Flash,适合嵌入式开发。其高度集成的特性(如锂电池管理、低功耗设计)和丰富的通信接口(UART、I2C、SPI、PWM等),使其成为创客项目的理想选择。

本文将通过一个高精度电压测量项目,结合OLED显示与串口通信,展示Beetle RP2350的硬件能力与编程技巧,并简要解析其多协议通信的实现方法。

一、硬件准备

核心硬件:

Beetle RP2350开发板(SKU: DFR1188)

0.96英寸OLED显示屏(I2C接口,SSD1306驱动)

分压电阻:R1=99.2kΩ、R2=197.2kΩ(用于扩展电压测量范围)

被测电压源(0-30V直流)

连接方式:

OLED:SCL接D5,SDA接D4

分压电路:输入电压接R1与R2串联节点,R2另一端接地,分压输出接A1引脚(D27)

串口:UART2(D8-TX、D9-RX)用于调试输出
关键引脚:

ADC_PIN = 27:模拟输入引脚A1,12位ADC分辨率

I2C引脚:D4(SDA)、D5(SCL)用于驱动OLED

硬件串口:D8(TX2)、D9(RX2)用于数据输出
二、代码深度解析
1. 核心算法:高精度电压测量

readPrecisionVoltage()函数

代码
float readPrecisionVoltage() {
  // 超采样:8次采样取平均,降低噪声
  uint32_t rawSum = 0;
  for(int i=0; i<8; i++) {
    rawSum += analogRead(ADC_PIN);
    delayMicroseconds(150); // 避免采样间隔过短
  }
  float newSample = rawSum / 8.0;

  // 滑动窗口滤波:32点移动平均
  filter.sum -= filter.buffer[filter.index];
  filter.buffer[filter.index] = newSample;
  filter.sum += newSample;
  filter.index = (filter.index + 1) % SAMPLE_WINDOW;

  // 电压计算
  float dividerVoltage = (filter.sum / SAMPLE_WINDOW * VREF_ACTUAL) / 4095.0;
  return dividerVoltage * (R1 + R2) / R2 * CAL_FACTOR;
}


超采样(Oversampling):8次采样取平均,利用统计特性抑制随机噪声。
滑动窗口滤波:32个样本的移动平均,消除短期波动,提升稳定性。
分压计算:通过电阻分压公式 V_actual = V_adc * (R1+R2)/R2,结合校准因子 CAL_FACTOR 修正硬件误差。

2. OLED显示实现 

updateOLED()函数

代码
void updateOLED(float voltage) {
  u8g2.clearBuffer();
  u8g2.setFont(u8g2_font_ncenB14_tr);
  u8g2.setCursor(0, 30);
  u8g2.print("VOL:");
  u8g2.print(voltage, 2); // 显示2位小数
  u8g2.print("V");
  // 状态栏显示项目名称
  u8g2.setFont(u8g2_font_6x10_tr);
  u8g2.setCursor(0, 63);
  u8g2.print("RP2350 ADC");
  u8g2.sendBuffer();
}

使用U8g2库驱动128×64 OLED,支持自定义字体和动态刷新。
双字体设计:主界面大字体突出电压值,底部状态栏显示项目标识。

3. 系统初始化与主循环

setup()函数

配置串口波特率(115200)和ADC分辨率(12位)。

初始化OLED并设置对比度,确保显示清晰。

loop()函数

每秒读取一次电压,通过串口输出原始数据和计算结果。

调用updateOLED()刷新显示,避免频繁刷屏导致的闪烁。

三、硬件连接与参数配置

1. 分压电路设计

电阻值:R1=99.2kΩ,R2=197.2kΩ,分压比约1:3。

校准因子CAL_FACTOR=1.063,用于补偿电阻精度误差或PCB阻抗。

2. OLED连接

Beetle RP2350引脚OLED引脚
D4 (SDA)SDA
D5 (SCL)SCL
3V3VCC
GNDGND

四、优化与改进方向

关键实现

1.超采样与滤波:通过8次ADC采样取平均,降低噪声;结合32点移动平均滤波,提升稳定性。

2.分压计算:根据公式 V_actual = V_adc × (R1+R2)/R2,扩展测量范围至30V。

3.校准优化:通过实测调整CAL_FACTOR(代码中为1.063),修正硬件误差。
动态滤波窗口:根据噪声环境自动调整窗口大小(如SAMPLE_WINDOW值)。

温度补偿:添加温度传感器,修正电阻温漂对分压精度的影响。

数据持久化:利用RP2350的Flash存储历史数据,实现离线记录功能。

无线传输:通过Wi-Fi/蓝牙模块将数据发送至手机或云端。


 

五、实物展示

功能演示

1.串口输出

每秒输出一次电压值及原始数据:VOL:12.345 RAW:2048.3  

2.OLED显示

实时显示电压值,精度保留两位小数(如VOL:12.34V)。

微信图片_20250522220336.jpg

实际测量精度
 

微信图片_20250522220340.jpg


 

代码
#include <Arduino.h>
#include <SoftwareSerial.h>
#include <U8g2lib.h>  // 添加OLED库

// 硬件配置
const int ADC_PIN = 27;          
const float R1 = 99200.0;        
const float R2 = 197200.0;       
const float VREF_ACTUAL = 3.312; 
const int SAMPLE_WINDOW = 32;    
const float CAL_FACTOR = 1.063;  

// 初始化OLED对象(硬件I2C,D5=SCL, D4=SDA)
U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2(
  U8G2_R0, 
  /* reset=*/ U8X8_PIN_NONE, 
  /* clock=*/ 5,  // D5引脚作为SCL
  /* data=*/ 4    // D4引脚作为SDA
);

SoftwareSerial hardwareSerial(9, 8);  // 硬件串口D8/D9

// 改进型滤波结构
struct {
  float buffer[SAMPLE_WINDOW] = {0};
  uint8_t index = 0;
  float sum = 0;
} filter;

float readPrecisionVoltage() {
  // 移除旧样本
  filter.sum -= filter.buffer[filter.index];
  
  // 超采样采集(8次采样取平均)
  uint32_t rawSum = 0;
  for(int i=0; i<8; i++){
    rawSum += analogRead(ADC_PIN);
    delayMicroseconds(150);
  }
  float newSample = rawSum / 8.0;

  // 更新滤波窗口
  filter.buffer[filter.index] = newSample;
  filter.sum += newSample;
  filter.index = (filter.index + 1) % SAMPLE_WINDOW;

  // 计算分压电压
  float dividerVoltage = (filter.sum / SAMPLE_WINDOW * VREF_ACTUAL) / 4095.0;
  
  // 计算实际电压
  return dividerVoltage * (R1 + R2) / R2 * CAL_FACTOR;
}

void updateOLED(float voltage) {
  u8g2.clearBuffer();           // 清除缓冲区
  u8g2.setFont(u8g2_font_ncenB14_tr); 
  
  // 绘制电压值
  u8g2.setCursor(0, 30);
  u8g2.print("VOL:");
  u8g2.print(voltage, 2);
  u8g2.print("V");

  // 绘制状态栏
  u8g2.setFont(u8g2_font_6x10_tr);
  u8g2.setCursor(0, 63);
  u8g2.print("RP2350 ADC");
  
  u8g2.sendBuffer();  // 发送显示数据
}

void setup() {
  Serial.begin(115200);
  hardwareSerial.begin(115200);
  analogReadResolution(12);       

  // 初始化OLED
  u8g2.begin();
  u8g2.setContrast(150);  // 设置对比度
  u8g2.clearDisplay();
  u8g2.setFlipMode(0);    // 根据需要调整显示方向
}

void loop() {
  static uint32_t lastPrint = 0;
  
  if(millis() - lastPrint >= 1000) {
    float voltage = readPrecisionVoltage();
    
    // 串口输出
    char report[40];
    snprintf(report, sizeof(report), "VOL:%.3f RAW:%.1f", voltage, filter.sum/SAMPLE_WINDOW);
    Serial.println(report);
    hardwareSerial.println(report);

    // 更新OLED显示
    updateOLED(voltage);
    
    lastPrint = millis();
  }
}

评论

user-avatar