基于 STM32 的示波器实现

一、系统总体架构

复制代码
被测信号
   ↓
信号调理电路(分压 + 偏置 + 跟随)
   ↓
STM32 ADC
   ↓
DMA 传输(核心)
   ↓
RAM 缓存(波形缓冲区)
   ↓
触发判断(上升沿/下降沿)
   ↓
TFT 显示(网格 + 波形)
   ↓
按键/编码器(时基/电压档位)

二、硬件选型与参数

项目 基础版 (F103) 进阶版 (F407/H743)
主控 STM32F103C8T6 STM32F407ZGT6 / H743
ADC 1Msps (12bit) 2.4Msps+ (12bit)
带宽 200KHz 10MHz+
屏幕 320x240 TFT (SPI/FSMC) 480x320 TFT (LTDC/FSMC)
存储深度 1K ~ 4K 点 32K ~ 1M 点

三、核心硬件设计(至关重要)

STM32 的 IO 口只能承受 0~3.3V。示波器必须有过压保护和信号调理。

1. 衰减与分压
  • 1x 档:直接进 ADC(0-3.3V)。
  • 10x 档 :使用 1MΩ + 9MΩ 电阻分压网络,将 ±30V 信号衰减到 ±3.3V。
2. 直流偏置(最关键)

STM32 ADC 不能采负电压。

  • 使用运放(如 LM358 或 AD8065)搭建加法器
  • -3.3V ~ +3.3V 的信号抬升到 0 ~ 3.3V
  • 公式:Vout=Vin+1.65VV_{out} = V_{in} + 1.65VVout=Vin+1.65V
3. 阻抗匹配
  • 输入串联 1kΩ 电阻 保护 ADC。
  • 并联 TVS 管 防静电。

四、STM32 软件核心(F103 示例)

1. ADC + 定时器 + DMA(黄金三角)

严禁 使用软件循环采样,必须使用定时器触发 ADC,保证采样间隔严格相等。

c 复制代码
// 定时器配置(触发 ADC)
void TIM_ADC_Init(void) {
    TIM_HandleTypeDef htim3;
    htim3.Instance = TIM3;
    htim3.Init.Prescaler = 0;
    htim3.Init.CounterMode = TIM_COUNTERMODE_UP;
    htim3.Init.Period = 72; // 72MHz / 72 = 1MHz 采样率
    HAL_TIM_Base_Init(&htim3);
    
    TIM_MasterConfigTypeDef sMasterConfig;
    sMasterConfig.MasterOutputTrigger = TIM_TRGO_UPDATE; // 更新事件触发 ADC
    sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
    HAL_TIMEx_MasterConfigSynchronization(&htim3, &sMasterConfig);
    
    HAL_TIM_Base_Start(&htim3);
}

// ADC 配置
void ADC_Init(void) {
    ADC_HandleTypeDef hadc1;
    hadc1.Instance = ADC1;
    hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
    hadc1.Init.ScanConvMode = DISABLE;
    hadc1.Init.ContinuousConvMode = DISABLE; // 关闭连续,由定时器触发
    hadc1.Init.ExternalTrigConv = ADC_EXTERNALTRIGCONV_T3_TRGO; // 定时器3触发
    HAL_ADC_Init(&hadc1);
    
    // 启动 DMA
    HAL_ADC_Start_DMA(&hadc1, (uint32_t*)adc_buffer, ADC_BUFFER_SIZE);
}
2. 触发逻辑(示波器灵魂)

触发是为了让波形"稳定"下来。

c 复制代码
typedef enum {
    TRIGGER_RISING,
    TRIGGER_FALLING
} TriggerMode;

uint8_t Check_Trigger(uint16_t *buf, uint16_t size, uint16_t threshold) {
    static uint8_t triggered = 0;
    for (int i = 1; i < size; i++) {
        // 上升沿触发
        if (buf[i-1] < threshold && buf[i] >= threshold) {
            triggered = 1;
            return 1; // 触发成功
        }
    }
    return 0; // 未触发
}
3. 波形显示(TFT 绘制)

将 ADC 的 0~4095 映射到屏幕坐标。

c 复制代码
void Draw_Waveform(uint16_t *adc_data, uint16_t size) {
    uint16_t x, y;
    uint16_t prev_x = 0, prev_y = 0;
    
    for (x = 0; x < size; x++) {
        // 将 ADC 值 (0~4095) 映射到屏幕高度 (0~239)
        y = LCD_HEIGHT - (adc_data[x] * LCD_HEIGHT / 4096);
        
        if (x > 0) {
            LCD_DrawLine(prev_x, prev_y, x, y, WHITE);
        }
        prev_x = x;
        prev_y = y;
    }
}

五、主循环逻辑

c 复制代码
uint16_t adc_buffer[1024];
uint8_t wave_ready = 0;

int main(void) {
    HAL_Init();
    SystemClock_Config();
    
    LCD_Init();
    TIM_ADC_Init();
    ADC_Init();
    
    while (1) {
        // 等待 DMA 传输完成一半或全满(双缓冲思想)
        if (wave_ready) {
            // 1. 触发检测
            if (Check_Trigger(adc_buffer, 1024, 2048)) {
                // 2. 清除屏幕
                LCD_Clear(BLACK);
                // 3. 画网格
                Draw_Grid();
                // 4. 画波形
                Draw_Waveform(adc_buffer, 1024);
            }
            wave_ready = 0;
        }
        HAL_Delay(1);
    }
}

// DMA 传输完成中断
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc) {
    wave_ready = 1; // 通知主循环处理数据
}

参考代码 基于stm32的示波器 www.youwenfan.com/contentcsu/69855.html

六、瓶颈与突破

瓶颈 现象 解决方案
ADC 速度 测不了高频 使用 STM32F4/F7
屏幕刷新 波形闪烁 使用 FSMC 并行屏(比 SPI 快 10 倍)
存储深度 看不到细节 使用 SRAM 扩展内存
FFT 卡死 降低点数或使用 DSP 库

七、进阶功能(炫技用)

  1. FFT 频谱分析 :使用 CMSIS-DSP 库的 arm_rfft_q15
  2. 自动测量:峰峰值(Vpp)、频率、占空比。
  3. 波形冻结:按下按键保存当前波形。
  4. USB 导出:将 CSV 数据通过 USB 虚拟串口发给电脑。

八、避坑指南

  1. 不要用 Delay 采样:会导致采样率不准。
  2. 输入电压必须隔离:新手最容易烧芯片。
  3. 地线要接好:示波器探头地和 STM32 地必须共地,否则波形乱飘。
  4. 刷新率优先:如果屏幕刷新太慢,宁可降低采样点数,也要保证画面流畅。
相关推荐
黑白园2 小时前
STM32F103ZET6移植-电机2804(星型接法)-驱动板SimpleFOC Mini实现速度开环_位置开环控制(四、功能演示)
stm32·单片机·嵌入式硬件
Hello_Embed2 小时前
libmodbus 移植到 STM32H5
笔记·stm32·单片机·嵌入式硬件·嵌入式·ai编程
山木嵌入式4 小时前
【STM32进阶】中断体系全解析:从核心原理到实战(含面试高频考点)
stm32·嵌入式硬件·面试·中断·nvic
puamac4 小时前
c#打开cmd然后输入claude
stm32·单片机·c#
LCG元4 小时前
STM32实战:基于STM32F103的智能晾衣架(光控+雨控)
stm32·单片机·嵌入式硬件
Sean_VIP5 小时前
Bootloader+APP调试技巧
stm32
星夜夏空996 小时前
STM32单片机学习(11)——GPIO输入实验
stm32·单片机·学习
黑白园6 小时前
STM32F103ZET6移植-电机2804-驱动板SimpleFOC Mini实现速度开环_位置开环控制(二、代码移植及功能实现)
stm32·单片机·嵌入式硬件