基于STM32F407的示波器兼信号发生器设计
一、项目概述
本项目基于STM32F407ZGT6微控制器设计一款双功能仪器,兼具示波器(信号采集与显示)和信号发生器(波形生成)功能。示波器支持实时波形采集、触发控制、时基/幅度调节;信号发生器支持正弦波、方波、三角波、锯齿波等波形输出,可调节频率、幅度、占空比。系统采用TFT LCD触摸显示,通过DMA+ADC/DAC实现高速数据处理,兼顾性能与成本,适合电子实验、教学演示等场景。
二、系统架构
+-----------------------+
| STM32F407 | // 核心:Cortex-M4@168MHz,1MB Flash,192KB RAM
| +-------------------+ |
| | 示波器模块 | | // ADC采集+触发+显示
| +-------------------+ |
| +-------------------+ |
| | 信号发生器模块 | | // DAC输出+波形生成
| +-------------------+ |
| +-------------------+ |
| | 人机交互模块 | | // LCD触摸+按键
| +-------------------+ |
| +-------------------+ |
| | 电源管理模块 | | // 3.3V/5V稳压
| +-------------------+ |
+-----------------------+
| | | | | | | | | | | | |
v v v v v v v v v v v v
+----------+--------+--------+--------+--------+--------+--------+--------+
| 信号调理 | TFT LCD | 触摸控制 | ADC采集 | DAC输出 | DMA传输 | Flash | SRAM |
| (放大/衰减) | (FSMC驱动) | (I2C/FSMC) | (12位@2.4MSPS) | (12位@1MSPS) | (双缓冲) | (存储波形) | (缓存数据) |
+----------+--------+--------+--------+--------+--------+--------+--------+
三、硬件设计
1. 核心资源分配
| 外设 | 功能描述 | 关键参数 |
|---|---|---|
| ADC1/2 | 示波器信号采集(单通道/双通道) | 12位分辨率,2.4MSPS@单通道 |
| DAC1/2 | 信号发生器波形输出(单通道/双通道) | 12位分辨率,1MSPS@单通道 |
| TIM2/3/4 | 触发控制、DAC更新、时基生成 | 168MHz主频,分频后1ns精度 |
| DMA1/2 | ADC/DAC数据传输(双缓冲) | 16流DMA,支持循环模式 |
| FSMC | TFT LCD驱动(8080并行接口) | 16位数据总线,最高100MHz |
| I2C1 | 触摸芯片(如XPT2046)通信 | 400kHz速率 |
2. 关键电路设计
(1)示波器信号调理电路
-
输入范围:-5V+5V(通过运放调理至03.3V供ADC采集)
-
调理电路:
- 衰减网络:10:1分压(R1=90kΩ,R2=10kΩ),将±5V衰减至±0.5V
- 偏置电路:加法器将±0.5V抬升至0~3.3V(Vref=1.65V)
- 低通滤波:截止频率1MHz(RC=160Ω+1nF),滤除高频噪声
-
保护电路:TVS管(SMAJ5.0A)防过压,ESD保护二极管
(2)信号发生器输出电路
-
输出范围:03.3V(通过运放放大至±5V或010V)
-
放大电路:
- 同相放大:增益2倍(OPA2350,带宽10MHz),输出0~6.6V(需限幅)
- 偏置调整:通过电位器设置直流偏置(0V/1.65V/3.3V)
-
阻抗匹配:50Ω输出阻抗(串联50Ω电阻)
(3)TFT LCD接口
- 型号:2.8寸TFT(ILI9341驱动,320×240分辨率)
- 接口:FSMC 8080并行(D0~D15,WR/RD/RS/CS)
- 触摸:XPT2046电阻屏控制器(I2C接口)
四、软件设计
1. 主程序框架
int main(void) {
HAL_Init();
SystemClock_Config(); // 168MHz HSE+PLL
Peripherals_Init(); // ADC/DAC/TIM/DMA/LCD/触摸初始化
UI_Init(); // 界面绘制(主菜单、参数显示)
while (1) {
if (system_mode == OSCILLOSCOPE_MODE) {
Oscilloscope_Run(); // 示波器模式
} else if (system_mode == SIGNAL_GEN_MODE) {
SignalGen_Run(); // 信号发生器模式
}
UI_Update(); // 界面刷新
Touch_Process(); // 触摸事件处理
}
}
2. 示波器核心功能实现
(1)信号采集(ADC+DMA双缓冲)
// 双缓冲数组(每缓冲1024点,共2048点)
#define BUFFER_SIZE 1024
uint16_t adc_buffer[2][BUFFER_SIZE];
uint8_t active_buffer = 0; // 当前活动缓冲(0/1)
void ADC_Init(void) {
ADC_HandleTypeDef hadc1;
hadc1.Instance = ADC1;
hadc1.Init.Resolution = ADC_RESOLUTION_12B;
hadc1.Init.ScanConvMode = DISABLE;
hadc1.Init.ContinuousConvMode = DISABLE; // 单次转换+DMA触发
hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_RISING;
hadc1.Init.ExternalTrigConv = ADC_EXTERNALTRIGCONV_T2_TRGO; // TIM2触发
HAL_ADC_Init(&hadc1);
// DMA配置(双缓冲模式)
DMA_HandleTypeDef hdma_adc1;
hdma_adc1.Instance = DMA2_Stream0;
hdma_adc1.Init.Channel = DMA_CHANNEL_0;
hdma_adc1.Init.MemBurst = DMA_MBURST_SINGLE;
hdma_adc1.Init.PeriphBurst = DMA_PBURST_SINGLE;
hdma_adc1.Init.Mode = DMA_CIRCULAR; // 循环模式
hdma_adc1.Init.DoubleBufferMode = DMA_DOUBLE_BUFFER_MODE_ENABLE;
hdma_adc1.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_adc1.Init.MemInc = DMA_MINC_ENABLE;
hdma_adc1.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
hdma_adc1.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
HAL_DMA_Init(&hdma_adc1);
__HAL_LINKDMA(&hadc1, DMA_Handle, hdma_adc1);
// 启动ADC+DMA
HAL_ADC_Start_DMA(&hadc1, (uint32_t*)adc_buffer, 2*BUFFER_SIZE);
}
(2)触发控制(边沿触发+电平触发)
typedef enum { TRIGGER_EDGE_RISE, TRIGGER_EDGE_FALL, TRIGGER_LEVEL } TriggerMode;
TriggerMode trigger_mode = TRIGGER_EDGE_RISE;
uint16_t trigger_level = 2048; // 触发电平(12位中点)
// 触发检测(在DMA半传输/全传输中断中执行)
void HAL_ADC_ConvHalfCpltCallback(ADC_HandleTypeDef* hadc) {
if (active_buffer == 0) Check_Trigger(adc_buffer[0], BUFFER_SIZE);
}
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc) {
if (active_buffer == 1) Check_Trigger(adc_buffer[1], BUFFER_SIZE);
}
void Check_Trigger(uint16_t* buffer, uint16_t size) {
for (int i=1; i<size; i++) {
if (trigger_mode == TRIGGER_EDGE_RISE) {
if (buffer[i-1] < trigger_level && buffer[i] >= trigger_level) {
// 找到触发点,更新显示缓冲区
memcpy(display_buffer, buffer+i, (size-i)*2);
break;
}
}
// 其他触发模式类似
}
}
(3)波形显示(LCD绘制)
// 将ADC采样点(0~4095)映射到LCD坐标(0~239行,0~319列)
#define VERT_SCALE 0.1f // 垂直缩放因子(点/像素)
#define HORZ_SCALE 1.0f // 水平缩放因子
void Draw_Waveform(uint16_t* data, uint16_t len) {
LCD_Clear(BLACK);
int prev_x = 0, prev_y = 240 - (data[0] - 2048) * VERT_SCALE; // 垂直居中
for (int i=1; i<len; i++) {
int x = i * HORZ_SCALE;
int y = 240 - (data[i] - 2048) * VERT_SCALE;
LCD_DrawLine(prev_x, prev_y, x, y, GREEN); // 绘制连线
prev_x = x; prev_y = y;
}
// 显示时基/幅度参数
LCD_ShowString(10, 10, "Timebase: 1ms/div", WHITE, BLACK);
LCD_ShowString(10, 30, "Voltage: 1V/div", WHITE, BLACK);
}
3. 信号发生器核心功能实现
(1)波形生成(查表法+DMA循环输出)
// 正弦波表(1024点,12位精度)
#define WAVE_TABLE_SIZE 1024
const uint16_t sine_table[WAVE_TABLE_SIZE] = {
2048, 2098, 2148, ..., 2048 // 预先计算的正弦值
};
// DAC输出配置(DMA循环模式)
void DAC_Init(void) {
DAC_HandleTypeDef hdac1;
hdac1.Instance = DAC1;
HAL_DAC_Init(&hdac1);
// DMA配置(循环输出波形表)
DMA_HandleTypeDef hdma_dac1;
hdma_dac1.Instance = DMA1_Stream5;
hdma_dac1.Init.Channel = DMA_CHANNEL_7;
hdma_dac1.Init.Mode = DMA_CIRCULAR;
hdma_dac1.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_dac1.Init.MemInc = DMA_MINC_ENABLE;
hdma_dac1.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
hdma_dac1.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
HAL_DMA_Init(&hdma_dac1);
__HAL_LINKDMA(&hdac1, DMA_Handle1, hdma_dac1);
// 启动DAC+DMA
HAL_DAC_Start_DMA(&hdac1, DAC_CHANNEL_1, (uint32_t*)sine_table, WAVE_TABLE_SIZE, DAC_ALIGN_12B_R);
}
(2)参数调节(频率/幅度/占空比)
-
频率调节:通过TIM2控制DAC更新频率(更新率=波形表大小×频率)
void Set_Freq(float freq) { uint32_t arr = (SystemCoreClock / (WAVE_TABLE_SIZE * freq)) - 1; __HAL_TIM_SET_AUTORELOAD(&htim2, arr); // TIM2控制DAC更新 } -
幅度调节:通过DAC输出乘以幅度系数(0.1~1.0)
void Set_Amplitude(float amp) { for (int i=0; i<WAVE_TABLE_SIZE; i++) { dac_buffer[i] = sine_table[i] * amp; // 调整幅度 } } -
占空比调节(方波):修改方波表中高/低电平点数
void Set_DutyCycle(float duty) { uint16_t high_len = WAVE_TABLE_SIZE * duty; for (int i=0; i<high_len; i++) square_table[i] = 4095; // 高电平 for (int i=high_len; i<WAVE_TABLE_SIZE; i++) square_table[i] = 0; // 低电平 }
参考代码 基于STM32F407开发的一款示波器,还可作信号发生器 www.youwenfan.com/contentcns/182611.html
四、关键功能实现
1. 示波器核心功能
- 触发控制:支持边沿触发(上升/下降)、电平触发,触发位置可调(预触发/后触发)
- 时基调节:1μs/div~1s/div(通过调节ADC采样率实现,1MSPS时1μs/点=10μs/div)
- 幅度调节:10mV/div~5V/div(通过软件缩放ADC采样值)
- 测量功能:自动测量频率、峰峰值、平均值(基于FFT或时域分析)
2. 信号发生器核心功能
- 波形类型:正弦波(1Hz100kHz)、方波(1Hz200kHz)、三角波(1Hz~50kHz)、锯齿波
- 参数调节:频率(1Hz200kHz,精度0.1Hz)、幅度(03.3V,软件可调)、占空比(10%~90%)
- 调制功能:AM(调幅)、FM(调频)(通过叠加调制信号实现)
五、系统优化
1. 性能优化
- ADC采集:双ADC交替采样(2.4MSPS@双通道),DMA双缓冲避免数据丢失
- 显示优化:局部刷新(仅更新波形变化区域),使用画点而非画线减少计算量
- 低功耗:空闲时进入睡眠模式,关闭非必要外设时钟
2. 抗干扰设计
-
硬件:ADC输入加π型滤波(10μF+100nF),电源端加磁珠隔离
-
软件:中值滤波(去除野点)+滑动平均滤波(平滑波形)
#define FILTER_LEN 5 uint16_t filter_buf[FILTER_LEN]; uint16_t Median_Filter(uint16_t new_val) { // 中值滤波实现 }
六、测试与验证
1. 示波器测试
-
输入信号:1kHz正弦波(幅值1Vpp),用标准示波器(如Tektronix TBS1102)对比
-
指标:
- 采样率:1MSPS时,时基1ms/div可显示1个周期(10点/周期)
- 垂直精度:±2LSB(12位ADC)
- 触发抖动:<1μs
2. 信号发生器测试
-
输出信号:1kHz正弦波(幅值3.3Vpp),用示波器测量
-
指标:
- 频率精度:±0.1%(基于TIM定时器分频)
- 总谐波失真(THD):<1%(1kHz时)
- 幅度精度:±1%
七、项目资源
1. 硬件清单
| 模块 | 型号/规格 | 数量 | 功能 |
|---|---|---|---|
| 主控 | STM32F407ZGT6 | 1 | 核心控制 |
| ADC | 内置12位ADC | 2 | 信号采集 |
| DAC | 内置12位DAC | 2 | 波形输出 |
| LCD | 2.8寸TFT(ILI9341) | 1 | 显示波形/参数 |
| 触摸芯片 | XPT2046 | 1 | 触摸控制 |
| 运放 | OPA2350(双运放) | 2 | 信号调理 |
| 电源 | LM1117-3.3V + LM2596-5V | 1 | 3.3V/5V供电 |
2. 开发环境
- IDE:STM32CubeIDE
- 库:HAL库+FreeRTOS(任务调度:示波器采集/显示/处理分3个任务)
- 工具:STM32CubeMX(外设配置)、Saleae Logic(信号分析)
八、总结
本设计基于STM32F407实现了示波器+信号发生器双功能,通过高速ADC/DAC+DMA完成信号采集与生成,结合TFT触摸显示提供友好交互。示波器支持实时触发、时基/幅度调节,信号发生器支持多波形输出与参数控制,可满足基础电子实验需求。系统采用模块化设计,便于扩展(如增加FFT分析、I2S音频输出等),具有较高实用价值。