电信号的波形进行图形化显示。借助示波器,技术人员可以对信号的频率、幅度、相位等参数展开分析,进而对电路的工作状态进行评估和调试。
本项目旨在利用 Beetle RP2350 开发板设计一款简易示波器,来实现对电压的测量与波形显示。

硬件介绍
1、Beetle RP2350 开发板
Beetle RP2350 是一款基于RP2350芯片设计的高性能迷你体积的开发板,有2路ADC,分别是A0对应IO26,A1对应IO27。
2、0.96 OLED屏

0.96寸OLED显示模块采用SSD1306驱动芯片,有128x64个自发光的白色像素点,采用I2C通信。
连接电路

程序编写
1、 安装Beetle RP2350 开发板
步骤 1:添加开发板管理器网址
打开 Arduino IDE 后,点击菜单栏中的 文件 -> 首选项。
在弹出的 首选项 窗口中,找到 附加开发板管理器网址 输入框。
输入 Beetle RP2350 开发板的支持包链接。通常可以在开发板的官方文档或者社区中找到对应的链接。对于 RP2350 开发板,一般使用的链接是 https://github.com/earlephilhower/arduino-pico/releases/download/global/package_rp2040_index.json。
点击 确定 保存设置。

步骤 2:安装 Beetle RP2350 开发板支持
点击菜单栏中的 工具 -> 开发板 -> 开发板管理器,在开发板管理器窗口中,等待索引更新完成。
在搜索框中输入 RP2350。
在搜索结果中找到 Raspberry Pi Pico/RP2040/RP2350 并点击 安装 按钮。

等待安装过程完成,这可能需要一些时间,具体取决于你的网络速度。
步骤 3:选择 Generic RP2350 开发板
安装完成后,点击菜单栏中的 工具 -> 开发板,在开发板列表中选择 Generic RP2350。

步骤 4:选择端口
将 Beetle RP2350 开发板通过 USB 线连接到计算机。点击菜单栏中的 工具 -> 端口,选择与开发板对应的端口。
完成以上步骤后,你就可以在 Arduino IDE 中使用 Beetle RP2350 开发板进行编程和开发了。你可以编写代码并上传到开发板上运行。
2、安装 Adafruit GFX Library库
在库管理器的搜索框中输入 Adafruit GFX Library,然后在搜索结果中找到对应的库。点击 安装 按钮,等待安装完成。这个库是 Adafruit 图形库,提供了基本的图形绘制功能,许多 Adafruit 的显示设备都会依赖这个库。

3、安装 Adafruit SSD1306库
在库管理器的搜索框中输入 Adafruit SSD1306,在搜索结果中找到该库后,点击 安装 按钮进行安装。这个库专门用于驱动基于 SSD1306 芯片的 OLED 显示屏,项目中使用的 0.96 寸 OLED 显示屏正是基于此芯片。

主要程序代码及说明
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
// OLED屏幕定义
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET -1
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
// 引脚定义
#define ADC_PIN A0
#define SDA_PIN 4
#define SCL_PIN 5
// 存储电压值的数组
float voltage_values[SCREEN_WIDTH] = {0};
// 波形偏移
const int WAVEFORM_OFFSET = 10;
// ADC校准参数
const float ADC_MAX_VALUE = 4095.0;
float ADC_ZERO_OFFSET = 0;
const float ZERO_DISPLAY_THRESHOLD = 0.005; // 低于此值显示为0V
const float ADC_CALIBRATION_FACTOR = 4.141742; // 校准因子
// 卡尔曼滤波参数
float kalman_x = 0; // 状态估计
float kalman_P = 1.0; // 估计误差协方差
const float kalman_Q = 0.001; // 过程噪声方差
const float kalman_R = 0.01; // 测量噪声方差
void setup() {
Wire.setSDA(SDA_PIN);
Wire.setSCL(SCL_PIN);
Wire.begin();
Serial.begin(115200);
if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
Serial.println(F("SSD1306初始化失败"));
for(;;);
}
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(SSD1306_WHITE);
display.setCursor(0, 0);
display.println("精密ADC校准中...");
display.display();
// 初始校准
calibrate_adc_zero();
// 微调零点补偿
ADC_ZERO_OFFSET += 24; // 补偿约0.02V的残余电压
display.clearDisplay();
display.setCursor(0, 0);
display.print("零点校准: ");
display.println(ADC_ZERO_OFFSET);
display.println("开始监测...");
display.display();
delay(1000);
}
// 初始零点校准
void calibrate_adc_zero() {
const int calibration_samples = 500;
unsigned long sum = 0;
for (int i = 0; i < calibration_samples; i++) {
sum += analogRead(ADC_PIN);
delay(1);
}
ADC_ZERO_OFFSET = sum / (float)calibration_samples;
Serial.print("零点校准值: ");
Serial.println(ADC_ZERO_OFFSET);
}
// 应用零点校准
int apply_zero_calibration(int raw_value) {
int calibrated = raw_value - ADC_ZERO_OFFSET;
return max(0, calibrated);
}
// 卡尔曼滤波
float kalman_filter(float measurement) {
// 预测
float x_pred = kalman_x;
float P_pred = kalman_P + kalman_Q;
// 更新
float K = P_pred / (P_pred + kalman_R); // 卡尔曼增益
kalman_x = x_pred + K * (measurement - x_pred);
kalman_P = (1 - K) * P_pred;
return kalman_x;
}
// 绘制电压曲线
void draw_voltage_curve(float values[]) {
display.clearDisplay();
for(int x = 0; x < SCREEN_WIDTH - 1; x++) {
int y1 = SCREEN_HEIGHT - 1 - (int)(values[x] * (SCREEN_HEIGHT - WAVEFORM_OFFSET - 1));
int y2 = SCREEN_HEIGHT - 1 - (int)(values[x + 1] * (SCREEN_HEIGHT - WAVEFORM_OFFSET - 1));
display.drawLine(x, y1, x + 1, y2, SSD1306_WHITE);
}
float voltage = values[SCREEN_WIDTH - 1] * 3.3;
// 低于阈值时强制显示为0
if (voltage < ZERO_DISPLAY_THRESHOLD) {
voltage = 0.0;
}
display.setCursor(0, 0);
display.print("V: ");
display.print(voltage, 3); // 显示3位小数
display.print("V ");
display.display();
}
void loop() {
// 读取原始ADC值
int raw_adc = analogRead(ADC_PIN);
// 应用零点校准
int calibrated_adc = apply_zero_calibration(raw_adc);
// 应用卡尔曼滤波
float filtered_adc = kalman_filter(calibrated_adc);
// 计算最终电压
float voltage = (filtered_adc / ADC_MAX_VALUE) * 3.3 * ADC_CALIBRATION_FACTOR;
// 串口打印
Serial.print("原始ADC值: ");
Serial.print(raw_adc);
Serial.print(" 零点校准后ADC值: ");
Serial.print(calibrated_adc);
Serial.print(" 卡尔曼滤波后ADC: ");
Serial.print(filtered_adc);
Serial.print(" 计算最终电压: ");
Serial.print(voltage, 4); // 串口显示4位小数用于调试
Serial.println("V");
// 限制电压比例在0-1范围内
float voltage_ratio = voltage / 3.3;
voltage_ratio = constrain(voltage_ratio, 0.0, 1.0);
// 更新电压值数组
memmove(voltage_values, voltage_values + 1, (SCREEN_WIDTH - 1) * sizeof(float));
voltage_values[SCREEN_WIDTH - 1] = voltage_ratio;
// 绘制电压曲线
draw_voltage_curve(voltage_values);
delay(50); // 提高采样率
}
评论