#include <Wire.h>
// --- 定义与常量 ---
#define OLED_ADDR 0x3C
#define FILTER_SIZE 8
#define LED_PIN PA11
#define BTN_PIN PA12
// --- 全局静态存储 (省内存) ---
uint32_t adc_buffer[FILTER_SIZE];
uint32_t filter_index = 0;
uint32_t rolling_sum = 0;
volatile bool btn_pressed = false; // 中断标志
// 极简 5x7 数字字库
const uint8_t PROGMEM tinyFont[10][5] = {
{0x3E, 0x51, 0x49, 0x45, 0x3E}, {0x00, 0x42, 0x7F, 0x40, 0x00},
{0x42, 0x61, 0x51, 0x49, 0x46}, {0x21, 0x41, 0x45, 0x4B, 0x31},
{0x18, 0x14, 0x12, 0x7F, 0x10}, {0x27, 0x45, 0x45, 0x45, 0x39},
{0x3C, 0x4A, 0x49, 0x49, 0x30}, {0x01, 0x71, 0x09, 0x05, 0x03},
{0x36, 0x49, 0x49, 0x49, 0x36}, {0x06, 0x49, 0x49, 0x29, 0x1E}
};
// --- OLED 底层指令函数 ---
void oled_cmd(uint8_t cmd) {
Wire.beginTransmission(OLED_ADDR);
Wire.write(0x00); Wire.write(cmd);
Wire.endTransmission();
}
void setup_oled() {
Wire.begin();
uint8_t init[] = {0xAE, 0xD5, 0x80, 0xA8, 0x3F, 0xD3, 0x00, 0x40, 0x8D, 0x14, 0x20, 0x00, 0xA1, 0xC8, 0xAF};
for(uint8_t c : init) oled_cmd(c);
}
void draw_num(uint16_t val, uint8_t x, uint8_t p) {
uint8_t digits[4] = {(val/1000)%10, (val/100)%10, (val/10)%10, val%10};
for(int d=0; d<4; d++) {
// 1. 定义列范围 (X轴)
oled_cmd(0x21); oled_cmd(x + d*7); oled_cmd(x + d*7 + 4);
// 2. 显式定义页范围 (Y轴)
// p 取值 0-7,代表垂直方向的 8 个分区
oled_cmd(0x22); oled_cmd(p); oled_cmd(p);
Wire.beginTransmission(OLED_ADDR);
Wire.write(0x40);
for(int i=0; i<5; i++) {
Wire.write(pgm_read_byte(&tinyFont[digits[d]][i]));
}
Wire.endTransmission();
}
}
// --- 中断回调 ---
void handle_btn() {
static uint32_t last_irq = 0;
if(millis() - last_irq > 200) { // 消抖
btn_pressed = true;
last_irq = millis();
}
}
// --- 核心初始化 ---
void setup() {
setup_oled();
pinMode(LED_PIN, OUTPUT);
pinMode(BTN_PIN, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(BTN_PIN), handle_btn, FALLING);
}
// --- 主循环 (多任务调度) ---
void loop() {
uint32_t now = millis();
static uint32_t t_adc = 0, t_oled = 0;
// 任务 1: ADC 采样与滑动滤波 (每 20ms)
if(now - t_adc >= 20) {
t_adc = now;
uint32_t raw = analogRead(A0);
uint32_t pos = filter_index % FILTER_SIZE;
rolling_sum = rolling_sum - adc_buffer[pos] + raw;
adc_buffer[pos] = raw;
filter_index++;
// PWM 联动
analogWrite(LED_PIN, (rolling_sum / (filter_index < FILTER_SIZE ? filter_index : FILTER_SIZE)) / 16);
}
// 任务 2: OLED 刷新 (每 150ms)
if(now - t_oled >= 150) {
t_oled = now;
uint32_t avg = rolling_sum / (filter_index < FILTER_SIZE ? filter_index : FILTER_SIZE);
draw_num(avg, 20, 1); // 在屏幕 x=20 位置显示
}
// 任务 3: 中断事件处理
if(btn_pressed) {
static uint32_t bitnum = 0;
draw_num(bitnum, 40, 4);
bitnum++;
// 可以在屏幕上画个标记或者切换模式
btn_pressed = false;
}
}