ADC高效采集方案:规则/注入组 + DMA双缓冲 + 定时器/PWM触发
本课详解ADC两种高效采集方案:规则组+DMA双缓冲+定时器触发:通过双缓冲机制实现高速连续采样,避免数据竞争,适合温度、电压等常规信号采集;注入组+PWM触发:利用硬件事件触发中断,精准控制采样点避开开关噪声,适用于电机相电流、过流保护等实时性要求高的场景。对比分析轮询、中断等传统方案的弊端,提供代码抽象与设计逻辑,助力嵌入式开发中的ADC优化应用。
文章目录
大家好!这节课我们来讲ADC的两种实用方案:
①“ADC规则组+DMA双缓冲+定时器更新触发”
②“ADC注入组+PWM触发”
一、初学者常见方案
1. 轮询
在主循环里一直读取ADC采样值
while(1) {
value = ADC_Read();
process_data(value);
}
而ADC_Read()的底层实现为:启动转换 --> 等待转换完成 --> 返回
SET_BIT(hadc->Instance->CR2, ADC_CR2_SWSTART);
while(!__HAL_ADC_GET_FLAG(hadc, ADC_FLAG_EOC));
return READ_REG(hadc->Instance->DR);
如果读取多个采样值,那么其他任务也就只能一级一级死等待。
while(1) {
temp = read_adc(TEMP_CH);
current = read_adc(CURR_CH);
voltage = read_adc(VOLT_CH);
func_control();
}
问题本质: 阻塞,实时性差
2. 中断
指每次采样转换都需要进中断处理(这里指ADC规则组采样模式)
void ADC_IRQHandler() {
value = ADC->DR;
buffer[i++] = value;
if(i >= BUF_SIZE) i=0;
}
那么高频率采样下中断的开销就大了
如果数据处理的时间>采样间隔时间,这样新数据就会覆盖旧数据
时间轴示例:
|--中断1--|-------处理-------|--中断2--|--中断3--|
↑ ↑ ↑
数据未处理完 新数据覆盖旧数据
问题本质: 高频中断会拉高CPU负载,并且存在数据覆盖风险
3. 单缓冲DMA传输
指将DMA配置为循环模式,缓冲区为一维数组buf[N],通过该缓冲区去存储采样值
DMA_Config_Circular(ADC->DR, buffer, BUF_SIZE);
但存在一个可能性问题,“数据竞争”
因为DMA是硬件行为,会自动往缓冲区写数据,如果某时刻DMA在往缓冲区的A地址写数据时,这时CPU也同时在处理A地址数据,就会出现同一块地址下的数据冲突。
问题本质: DMA与CPU访问同一内存区域会存在数据竞争
二、本节课方案
1. ADC规则组 + DMA双缓冲 + 定时器更新触发
-
名词解释
(1)ADC规则组定义:指ADC一种多通道采样模式,可以设定通道的采样顺序并按照该顺序采样。特点:所有规则通道共用一个数据寄存器,可以用DMA缓冲区指向这块地址实现采样搬运。触发方式:支持软件触发(手动启动)和硬件触发(定时器、外部引脚等)应用场景:常用于采集温度、母线电压、母线电流等(2)DMA双缓冲
定义:所谓双缓冲是指两个缓冲区,这里用二维数组buf[2][N],即buf[0]表示第一个缓冲区,buf[1]表示第二个缓冲区,DMA会在后台自动切换这两个缓冲区。缓冲区处理:当触发DMA半传输中断时表示buf[0]已经存满了,这时DMA会转到buf[1]中存储,即这时可以去处理buf[0]中数据;当触发DMA全传输中断时表示buf[1]已经存满了,这时DMA会转到buf[0]重新开始存,即这时可以去处理buf[1]中数据。(3)定时器更新触发
定义:指将ADC触发源配置为外部触发,也就是定时器的更新事件(计数器溢出/重载),即当定时器计数溢出时触发ADC采样。采样逻辑:定时器计数到ARR值后溢出 → 生成触发信号 → ADC启动一次规则组采样 -
工作流程
step1:配置外设初始化(定时器、ADC、DMA这些)step2:定时器溢出触发ADC采样step3:DMA搬运采样数据到当前缓冲区step4:触发DMA半传输中断,处理buf[0]数据step5:触发DMA全传输中断,处理buf[1]数据 -
抽象代码设计
// 1. 定时器基础配置(TIMx为例)
TIM_TimeBaseInit(TIMx, &TIM_TimeBaseStruct); // 设置周期/预分频
TIM_SelectOutputTrigger(TIMx, TIM_TRGOSource_Update); // TRGO由更新事件触发
TIM_Cmd(TIMx, ENABLE); // 启动定时器
// 2. ADC规则组配置(ADCx为例)
ADC_Init(ADCx, &ADC_InitStruct); // ADC基础模式设置
ADC_RegularChannelConfig(ADCx, ADC_Channel_0, 1, ADC_SampleTime); // 规则通道配置
ADC_DMACmd(ADCx, ENABLE); // 使能ADC DMA请求
// 3. DMA双缓冲配置(DMAx为例)
DMA_Init(DMAx, &DMA_InitStruct); // DMA基础配置
DMA_DoubleBufferModeConfig(DMAx, buf, DMA_Memory_0); // 双缓冲初始化
DMA_DoubleBufferModeCmd(DMAx, ENABLE); // 使能双缓冲模式
DMA_Cmd(DMAx, ENABLE); // 启动DMA
// 4. 中断处理
void DMAx_IRQHandler(void ){
if(DMA_GetIntStatus(DMAx_INT_HTX3, DMAx)){ //DMA半传输中断
Process_Data(buf[0]);
DMA_ClearFlag(DMAx_FLAG_HT3, DMAx);
}
if(DMA_GetIntStatus(DMAx_INT_TXC3, DMAx)){ //DMA全传输中断
Process_Data(buf[1]);
DMA_ClearFlag(DMAx_FLAG_TC3, DMAx);
}
}
2. ADC注入组 + PWM触发
-
名词解释
(1)ADC注入组定义:ADC的一种高优先级采样模式,可以打断当前规则组转换,优先执行注入组转换。特点:同规则组一样都可以设置通道的采样顺序,但每个注入组通道有独立的数据寄存器,所以一般不结合DMA使用。并且每个ADC模块最多4个注入通道,即ADC1、ADC2、ADC3一共12个注入通道触发方式:同规则组一样,支持软件触发+硬件触发。应用场景:FOC相电流采样、过流/过压紧急检测、传感器突发信号采集等(2)触发分析
例如配置PWM周期(Period)= 1ms(1000us)
占空比(Duty Cycle)= 10% → Pulse = 100(100us高电平)
PWM信号波:高电平 _ _ _ _ _ 低电平 | |_ _ _ _ _ _ _ _ _ ↑ ↑ t=0 t=100us (上升沿) (下降沿)①如果配置ADC为PWM上升沿触发,那么ADC就会在PWM信号的上升沿(t=0) 时开始采样
②如果配置ADC为PWM比较事件触发,那么ADC就会在“PWM上升沿+Pulse值 对应的时间”(t=100us)时开始采样,在实际应用中,一般用PWM的比较事件 触发方式比较多。问:
为什么选PWM的比较事件触发方式比较多?
答: 因为这种方式可以精确控制采样时刻,也就是通过设置PWM的Pulse值(占空比),去控制ADC采样点在PWM周期内的位置;还可以避开开关噪声,像在电机驱动或DC-DC这种功率电路中,MOSFET开关切换瞬间会产生瞬态电压电流,形成振荡噪声,所以PWM比较事件触发可以将采样点延迟到开关噪声之后,确保采集到稳定信号。 -
抽象代码设计
// 1. PWM定时器基础配置(TIMx为例)
TIM_TimeBaseInit(TIMx, &TIM_TimeBaseStruct); // 设置周期/预分频
TIM_OC1Init(TIMx, &TIM_OCStruct); // 配置PWM占空比
TIM_SelectOutputTrigger(TIMx, TIM_TRGOSource_OC1Ref); // TRGO由比较匹配触发
TIM_Cmd(TIMx, ENABLE); // 启动定时器
// 2. ADC注入组配置(ADCx为例)
ADC_Init(ADCx, &ADC_InitStruct); // ADC基础模式设置
ADC_InjectedSequencerLengthConfig(ADCx, 1); // 注入组通道数
ADC_InjectedChannelConfig(ADCx, ADC_Channel_0, 1, ADC_SampleTime); // 通道配置
ADC_ExternalTrigInjectedConvConfig(ADCx, ADC_ExternalTrigInjecConv_T1_TRGO); // PWM触发
ADC_Cmd(ADCx, ENABLE); // 启动ADC
// 3. ADC注入组中断服务函数
void ADC_IRQHandler(void) {
if (ADC_GetITStatus(ADCx, ADC_IT_JEOC)) { // 检查注入组转换完成中断
g_adc_value = ADC_GetInjectedConversionValue(ADCx, ADC_InjectedChannel_1);
ADC_ClearITPendingBit(ADCx, ADC_IT_JEOC); // 清除中断标志
}
}
问: 为什么上面刚说完初学者用的中断使用不合理,反而现在又要用中断方式了?
答: 上面说的中断不合理指的是规则组,因为规则组连续采样时频率很高,存在数据覆盖风险,而这里用的是注入组中断方式,它不是连续采样,是由外部事件触发,用于处理关键数据采样,对实时性要求高,必须通过中断立即响应,并且中断频率是我们自己可控的,其次每个注入组通道有独立的数据寄存器,不用担心数据覆盖风险,所以这里采用中断方式。
三、视频讲解
ADC高效采集方案:规则/注入组 + DMA双缓冲 + 定时器/PWM触发
ADC高效采集方案:规则/注入组 + DMA双缓冲 + 定时器/PWM触发
四、技术交流
那么,ADC这节课就先讲到这里,我们下节课再见!
感兴趣同学欢迎加入嵌入式技术交流群,联系主页wx:Lntt-xbc
更多推荐



所有评论(0)