以下是一个基于 STM32 微控制器的 ADC 中断配置与结果处理的典型例程示例。
该示例展示了如何通过中断方式触发 ADC 转换,并在中断服务函数(ISR)中获取并处理转换结果。
适用于大多数 STM32 系列芯片(如 STM32F1/F4)。
核心步骤概览
1. 初始化 ADC 外设
2. 配置 ADC 中断
3. 编写中断服务函数 (IRQ Handler)
4. 启动首次转换
5. 在 ISR 中处理转换结果
所需头文件依赖
```c
#include "stm32f1xx.h" // 根据实际使用的 MCU 系列替换
#include "stm32f1xx_hal.h" // HAL 库
```
1. ADC 初始化函数
```c
void ADC_Init(void) {
__HAL_RCC_ADC1_CLK_ENABLE(); // 使能 ADC1 时钟
// 初始化 ADC 句柄结构体
ADC_HandleTypeDef hadc;
hadc.Instance = ADC1; // 使用 ADC1
hadc.Init.ContinuousConvMode = DISABLE; // 单次转换模式
hadc.Init.DiscontinuousConvMode = DISABLE; // 禁用非连续模式
hadc.Init.ExternalTrigConvEdge = EXTI_RISING; // 外部触发边沿(可选)
hadc.Init.ExternalTrigConv = ADC_SOFTWARE_START; // 软件启动转换
hadc.Init.DataAlign = ADC_DATAALIGN_RIGHT; // 右对齐
hadc.Init.ScanConvMode = DISABLE; // 单通道扫描
hadc.Init.NbrOfConversion = 1; // 仅一个通道
HAL_ADC_Init(&hadc); // 初始化 ADC
// 配置通道映射到 PA0 (Channel 0)
ADC_ChannelConfTypeDef sConfig = {0};
sConfig.Channel = ADC_CHANNEL_0; // PA0 -> ADC Channel 0
sConfig.Rank = 1; // 排名靠前
sConfig.SamplingTime = ADC_SAMPLETIME_7CYCLES_5; // 采样时间
HAL_ADC_ConfigChannel(&hadc, &sConfig); // 配置通道
// 使能 ADC 中断
HAL_ADC_StartIT(&hadc); // 启动中断模式
}
```
2. ADC 中断服务函数 (IRQ Handler)
此函数会在每次 ADC 转换完成后自动调用。
```c
volatile uint32_t adcValue = 0; // 用于存储最新的 ADC 值
void ADC1_IRQHandler(void) {
// 检查是否是 EOC(End Of Conversion)中断
if (__HAL_ADC_GET_FLAG(&hadc, ADC_FLAG_EOC) != RESET) {
adcValue = HAL_ADC_GetValue(&hadc); // 获取当前 ADC 值
__HAL_ADC_CLEAR_FLAG(&hadc, ADC_FLAG_EOC); // 清除中断标志
// TODO: 在这里添加你的数据处理逻辑
// 例如:显示数值、控制 PWM 占空比、发送 UART 数据等
}
}
```
注意:`hadc` 是在 `ADC_Init()` 中定义的局部变量,若要在 ISR 中使用,需将其声明为全局变量或将指针传入。
3. 主函数 main()
```c
int main(void) {
HAL_Init(); // 初始化 HAL 库
SystemClock_Config(); // 系统时钟配置(可选)
ADC_Init(); // 初始化 ADC
while (1) {
// 主循环可以做其他事情,ADC 会自动通过中断更新 adcValue
// 如需手动启动下一次转换,可调用:
// HAL_ADC_Start(&hadc); // 如果设置为单次模式且未启用自动重启
}
}
```
关键注意事项
| 要点 | 说明 |
|------|------|
| 中断优先级 | 确保 ADC 中断优先级足够高,避免被其他低优先级中断阻塞。可通过 `HAL_NVIC_SetPriority()` 设置。 |
| 去抖动处理 | 如果连接的是传感器(如电位器),建议加入滤波算法(均值滤波、中值滤波)。 |
| 多通道支持 | 若需多通道采样,可将 `ScanConvMode` 设为 `ENABLE`,并按顺序配置多个通道。 |
| DMA 替代方案 | 对于大数据量采集,推荐使用 DMA + 双缓冲区,减少 CPU 负载。 |
| 电压范围匹配 | 确保输入电压不超过 Vref+,否则会导致读数饱和。 |
扩展建议
校准功能:调用 `HAL_ADCEx_CalibrationStart()` 提高精度。
温度补偿:结合内部温度传感器实现动态校正。
低功耗模式:在空闲时关闭 ADC 电源以节能。
完整示例整合版(简化版)
```c
#include "stm32f1xx.h"
#include "stm32f1xx_hal.h"
ADC_HandleTypeDef hadc;
volatile uint32_t adcValue = 0;
void ADC_Init(void) {
__HAL_RCC_ADC1_CLK_ENABLE();
hadc.Instance = ADC1;
hadc.Init.ContinuousConvMode = DISABLE;
hadc.Init.DiscontinuousConvMode = DISABLE;
hadc.Init.ExternalTrigConvEdge = EXTI_RISING;
hadc.Init.ExternalTrigConv = ADC_SOFTWARE_START;
hadc.Init.DataAlign = ADC_DATAALIGN_RIGHT;
hadc.Init.ScanConvMode = DISABLE;
hadc.Init.NbrOfConversion = 1;
HAL_ADC_Init(&hadc);
ADC_ChannelConfTypeDef sConfig = {0};
sConfig.Channel = ADC_CHANNEL_0;
sConfig.Rank = 1;
sConfig.SamplingTime = ADC_SAMPLETIME_7CYCLES_5;
HAL_ADC_ConfigChannel(&hadc, &sConfig);
HAL_ADC_StartIT(&hadc); // 启动中断模式
}
void ADC1_IRQHandler(void) {
if (__HAL_ADC_GET_FLAG(&hadc, ADC_FLAG_EOC)) {
adcValue = HAL_ADC_GetValue(&hadc);
__HAL_ADC_CLEAR_FLAG(&hadc, ADC_FLAG_EOC);
// 此处可添加自定义处理逻辑
}
}
int main(void) {
HAL_Init();
ADC_Init();
while (1) {
// 主循环可访问 adcValue 进行进一步处理
}
}
```
提示
如果使用的是其他 MCU(如 AVR、ESP32),原理类似,但寄存器名和 API 会有所不同。
建议查阅对应芯片的数据手册和参考手册,了解具体的 ADC 模块特性。
实际开发中建议使用 CubeMX 图形化工具生成初始代码框架,再在此基础上修改。