一、项目概述
基于STM32的正点原子示波器是一个开源的单片机学习项目,通过正点原子开发板实现简易数字示波器功能。该项目能够采集、显示和分析模拟信号,测量信号的频率、幅值等参数,是学习STM32和嵌入式系统开发的优秀实践项目。
二、硬件平台选择
正点原子提供了多款STM32开发板,均可用于示波器项目:
| 开发板型号 | 主控芯片 | 核心特点 | 适用场景 |
|---|---|---|---|
| 精英板 | STM32F103ZET6 | 性价比高,资源丰富 | 初学者入门,基础示波器 |
| MiniSTM32 | STM32F103RCT6 | 小巧便携,成本低 | 简化版示波器 |
| 战舰版 | STM32F103ZET6 | 功能全面,接口丰富 | 功能完整的示波器 |
| 探索者 | STM32F407ZGT6 | 高性能,带FPU | 高级示波器,支持复杂算法 |
三、核心功能特性
3.1 基本功能
- 信号采集:通过ADC采集0-3.3V范围内的模拟信号
- 波形显示:在TFTLCD上实时显示波形
- 参数测量:
- 频率测量(支持FFT算法提高精度)
- 幅值测量(最大值、最小值、峰峰值)
- 电压测量
- 采样控制:
- 可调节采样频率(通过按键控制)
- 波形暂停/继续功能
3.2 高级功能(部分实现)
- 多波形支持:正弦波、三角波、方波、锯齿波、噪声等
- 数据导出:通过串口将测量数据发送到PC
- 触发功能:边沿触发、电平触发
- 自动量程:自动调整显示范围
四、硬件连接与配置
4.1 基本连接方式
信号输入 → PA6(ADC1通道6)
或PA5(ADC1通道5)
或PA1(ADC1通道1)
TFTLCD → FSMC接口(战舰版/探索者)
或并口/SPI接口(精英版/Mini版)
控制按键:
KEY_UP → 波形更新/暂停
KEY0 → 提高采样率
KEY1 → 降低采样率
4.2 测试信号连接
- 正弦波测试:PA6与PA4相连
- 三角波/噪声测试:PA6与PA5相连
五、软件架构与关键技术
5.1 核心采集方案:ADC+TIMER+DMA
// 关键配置代码示例(基于精英板)
void Adc_Init(void)
{
ADC_InitTypeDef ADC_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
// 使能ADC1和GPIOA时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_ADC1, ENABLE);
RCC_ADCCLKConfig(RCC_PCLK2_Div6); // 72M/6=12MHz
// 配置PA6为模拟输入
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
// ADC配置
ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
ADC_InitStructure.ADC_ScanConvMode = DISABLE;
ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T2_CC2;
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
ADC_InitStructure.ADC_NbrOfChannel = 1;
ADC_Init(ADC1, &ADC_InitStructure);
// 配置ADC通道6
ADC_RegularChannelConfig(ADC1, ADC_Channel_6, 1, ADC_SampleTime_1Cycles5);
// 使能ADC和DMA
ADC_Cmd(ADC1, ENABLE);
ADC_DMACmd(ADC1, ENABLE);
// 校准ADC
ADC_ResetCalibration(ADC1);
while(ADC_GetResetCalibrationStatus(ADC1));
ADC_StartCalibration(ADC1);
while(ADC_GetCalibrationStatus(ADC1));
}
5.2 定时器触发配置
// 定时器2配置为PWM模式,触发ADC采样
void TIM2_PWM_Init(u16 arr, u16 psc)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_OCInitTypeDef TIM_OCInitStructure;
// 使能TIM2时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
// 定时器基础配置
TIM_TimeBaseStructure.TIM_Period = arr;
TIM_TimeBaseStructure.TIM_Prescaler = psc;
TIM_TimeBaseStructure.TIM_ClockDivision = 0;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
// PWM模式配置
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_Pulse = arr/2; // 50%占空比
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
TIM_OC2Init(TIM2, &TIM_OCInitStructure);
// 使能TIM2
TIM_Cmd(TIM2, ENABLE);
TIM_CtrlPWMOutputs(TIM2, ENABLE);
}
5.3 DMA数据传输配置
// DMA配置,用于ADC数据自动传输
void DMA_Config(void)
{
DMA_InitTypeDef DMA_InitStructure;
// 使能DMA1时钟
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
// DMA配置
DMA_DeInit(DMA1_Channel1);
DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)&ADC1->DR;
DMA_InitStructure.DMA_MemoryBaseAddr = (u32)ADC_ConvertedValue;
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
DMA_InitStructure.DMA_BufferSize = 1024; // 采样点数
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular; // 循环模式
DMA_InitStructure.DMA_Priority = DMA_Priority_High;
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
DMA_Init(DMA1_Channel1, &DMA_InitStructure);
// 使能DMA
DMA_Cmd(DMA1_Channel1, ENABLE);
}
六、项目文件结构
oscilloscope_project/
├── Hardware/
│ ├── adc.c/h # ADC配置
│ ├── timer.c/h # 定时器配置
│ ├── dma.c/h # DMA配置
│ ├── lcd.c/h # LCD驱动
│ ├── key.c/h # 按键处理
│ └── usart.c/h # 串口通信
├── System/
│ ├── delay.c/h # 延时函数
│ ├── sys.c/h # 系统配置
│ └── usart.c/h # 串口配置
├── User/
│ ├── main.c # 主程序
│ ├── oscilloscope.c/h # 示波器核心逻辑
│ ├── waveform.c/h # 波形处理
│ └── fft.c/h # FFT频率计算
└── README.md # 项目说明
参考代码 基于stm32的正点原子的示波器 www.youwenfan.com/contentalh/135927.html
七、主要技术指标
| 参数 | 指标 | 说明 |
|---|---|---|
| 输入电压范围 | 0-3.3V | 由STM32的ADC参考电压决定 |
| 采样频率 | 可调,最高约1MHz | 取决于定时器配置和CPU频率 |
| 采样点数 | 1024点/帧 | 保证波形显示完整性 |
| 频率测量范围 | 几Hz到几百Hz | 实际范围取决于采样率 |
| 显示分辨率 | 320×240或更高 | 取决于TFTLCD型号 |
| 测量精度 | 12位ADC | 理论分辨率约0.8mV |
八、使用步骤
8.1 硬件准备
- 开发板选择:正点原子精英板/战舰版/探索者
- LCD连接:将TFTLCD模块连接到开发板对应接口
- 信号输入:将待测信号连接到PA6(或其他ADC引脚)
- 电源连接:确保3.3V供电稳定
8.2 软件烧录
- 获取源码:从开源仓库下载项目代码
- 环境配置:安装Keil MDK或STM32CubeIDE
- 编译工程:根据开发板型号选择对应配置
- 下载程序:通过ST-Link或J-Link下载到开发板
8.3 操作使用
- 上电启动:系统自动初始化,显示示波器界面
- 信号连接:将待测信号连接到指定ADC引脚
- 参数调节:
- KEY_UP:暂停/继续波形更新
- KEY0:提高采样率
- KEY1:降低采样率
- 数据查看:波形和测量参数实时显示在LCD上
九、性能优化建议
9.1 提高采样率
- 降低ADC采样时间:使用
ADC_SampleTime_1Cycles5 - 提高系统时钟:合理配置PLL,提升系统频率
- 优化DMA传输:使用双缓冲机制减少数据传输时间
9.2 提高测量精度
- ADC校准:每次上电后进行ADC校准
- 软件滤波:添加数字滤波算法(均值滤波、中值滤波)
- FFT优化:使用查表法加速FFT计算
9.3 增强功能
- 多通道支持:扩展为双通道示波器
- 存储功能:添加SD卡存储波形数据
- 网络通信:通过以太网或WiFi传输数据到PC
十、常见问题与解决方案
| 问题现象 | 可能原因 | 解决方案 |
|---|---|---|
| 无波形显示 | LCD未正确初始化 | 检查LCD连接和初始化代码 |
| 波形失真 | 采样率过低 | 提高定时器频率,降低分频系数 |
| 测量误差大 | ADC未校准 | 添加ADC校准程序 |
| 按键无响应 | 外部中断配置错误 | 检查按键GPIO和中断配置 |
| 内存溢出 | 采样数组过大 | 优化内存使用,使用外部SRAM |
十一、项目总结
基于STM32的正点原子示波器项目是一个综合性很强的嵌入式系统实践项目,涵盖了:
- 硬件接口:ADC、定时器、DMA、GPIO、外部中断
- 软件算法:信号处理、FFT变换、波形显示
- 系统设计:实时数据采集、人机交互、性能优化
该项目不仅可以帮助初学者深入理解STM32的各种外设工作原理,还能掌握数字示波器的基本设计方法。