规则组,注入组
在STM32的ADC模块中,通道复用机制通过灵活的规则组和注入组实现多通道采样,下面详细解释其工作原理和配置方法:
1. 分时复用机制
(1)硬件基础
- 多路开关(MUX):ADC内部有一个电子开关,按顺序将不同通道连接到ADC核心。
- 单次转换:同一时间仅一个通道被采样,12位逐次逼近转换完成后切换下一通道。
(2)触发方式
- 软件触发:手动启动转换(
ADC_SoftwareStartConvCmd()
)。 - 硬件触发:通过定时器、外部中断等自动触发(如PWM同步采样)。
2. 规则组(Regular Group)
(1)功能特点
- 常规多通道采样:按预设顺序依次转换多个通道(最多16个)。
- 顺序可控:通过
ADC_SQRx
寄存器设置通道顺序和总数。 - 典型应用:周期性采集传感器数据(如温度、电压)。
(2)配置步骤
// 设置规则组通道(3个通道)
ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_55Cycles5); // 第1个转换:PA0
ADC_RegularChannelConfig(ADC1, ADC_Channel_5, 2, ADC_SampleTime_55Cycles5); // 第2个转换:PA5
ADC_RegularChannelConfig(ADC1, ADC_Channel_16, 3, ADC_SampleTime_239Cycles5); // 第3个转换:温度传感器// 启用扫描模式
ADC_InitStructure.ADC_ScanConvMode = ENABLE;
ADC_InitStructure.ADC_NbrOfChannel = 3; // 通道数
ADC_Init(ADC1, &ADC_InitStructure);// 启动转换(软件触发)
ADC_SoftwareStartConvCmd(ADC1, ENABLE);
(3)数据读取
- 单次读取:等待EOC标志后读取
ADC_DR
(仅最后通道数据)。 - DMA传输:推荐方式,自动存储所有通道数据到数组。
uint16_t adcValues[3]; // 存储规则组数据 DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&ADC1->DR; DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)adcValues; DMA_InitStructure.DMA_BufferSize = 3; DMA_Init(DMA1_Channel1, &DMA_InitStructure); ADC_DMACmd(ADC1, ENABLE);
3. 注入组(Inject Group)
(1)功能特点
- 高优先级中断采样:可打断规则组转换,立即执行注入组采样。
- 独立数据寄存器:结果存储在
ADC_JDR1~4
(规则组用ADC_DR
)。 - 典型应用:紧急事件检测(如过压、超温)。
(2)配置步骤
// 配置注入组(2个通道)
ADC_InjectedChannelConfig(ADC1, ADC_Channel_1, 1, ADC_SampleTime_55Cycles5); // 第1注入:PA1
ADC_InjectedChannelConfig(ADC1, ADC_Channel_17, 2, ADC_SampleTime_239Cycles5); // 第2注入:VREFINT// 设置触发方式(外部触发)
ADC_ExternalTrigInjectedConvConfig(ADC1, ADC_ExternalTrigInjecConv_Ext_IT15);// 启用注入组中断
ADC_ITConfig(ADC1, ADC_IT_JEOC, ENABLE);
NVIC_EnableIRQ(ADC1_2_IRQn);
(3)中断服务例程
void ADC1_2_IRQHandler(void) {if (ADC_GetITStatus(ADC1, ADC_IT_JEOC)) {uint16_t inj1 = ADC_GetInjectedConversionValue(ADC1, ADC_InjectedChannel_1); // PA1uint16_t inj2 = ADC_GetInjectedConversionValue(ADC1, ADC_InjectedChannel_2); // VREFINTADC_ClearITPendingBit(ADC1, ADC_IT_JEOC);}
}
4. 规则组与注入组对比
特性 | 规则组(Regular) | 注入组(Injected) |
---|---|---|
通道数量 | 最多16通道 | 最多4通道 |
触发方式 | 软件/硬件触发 | 软件/硬件触发(可打断规则组) |
数据寄存器 | ADC_DR(需DMA) | ADC_JDR1~4(独立存储) |
中断标志 | EOC(转换结束) | JEOC(注入组转换结束) |
典型应用 | 周期性多通道采样 | 紧急事件的高优先级采样 |
5. 混合使用示例
// 规则组:循环采样PA0和PA5
ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_55Cycles5);
ADC_RegularChannelConfig(ADC1, ADC_Channel_5, 2, ADC_SampleTime_55Cycles5);
ADC_InitStructure.ADC_ScanConvMode = ENABLE;
ADC_InitStructure.ADC_NbrOfChannel = 2;
ADC_Init(ADC1, &ADC_InitStructure);// 注入组:外部触发紧急采样PA1
ADC_InjectedChannelConfig(ADC1, ADC_Channel_1, 1, ADC_SampleTime_55Cycles5);
ADC_ExternalTrigInjectedConvConfig(ADC1, ADC_ExternalTrigInjecConv_T2_TRGO);// 启动规则组(连续模式)
ADC_ContinuousConvModeCmd(ADC1, ENABLE);
ADC_SoftwareStartConvCmd(ADC1, ENABLE);
6. 关键注意事项
-
优先级管理
- 注入组转换会立即中断规则组,完成后规则组继续。
- 若规则组使用DMA,注入组数据不会影响DMA传输。
-
时序控制
- 硬件触发时,规则组和注入组的触发源需分开(如定时器不同通道)。
-
校准影响
- ADC校准对所有通道(规则+注入)生效,无需单独校准。
通过合理配置规则组和注入组,可实现复杂的多通道采样策略,兼顾常规监测和紧急响应需求。
以下是一个结合 规则组(Regular Group) 和 注入组(Injected Group) 的实际项目示例,用于 电池电压监测(规则组) 和 过压紧急检测(注入组),包含完整代码和注释。
项目需求
- 规则组:循环采集3路外部电压(电池电压、负载电流、温度传感器)。
- 注入组:当电池电压超过阈值时,通过外部中断触发紧急采样(高优先级)。
- 硬件配置:
- STM32F103RC
- ADC1规则组:PA0(电池电压)、PA1(负载电流)、PA2(温度传感器)
- ADC1注入组:PA3(过压检测专用通道)
- 定时器TIM2触发规则组,外部按键(PA8)触发注入组。
完整代码实现
1. 初始化配置
#include "stm32f10x.h"#define BATTERY_ADC_CHANNEL ADC_Channel_0 // PA0
#define CURRENT_ADC_CHANNEL ADC_Channel_1 // PA1
#define TEMP_ADC_CHANNEL ADC_Channel_2 // PA2
#define OVERVOLTAGE_ADC_CHANNEL ADC_Channel_3 // PA3(注入组)uint16_t regularData[3]; // 存储规则组数据(电池、电流、温度)
uint16_t injectedData; // 存储注入组数据(过压值)void ADC_Configuration(void) {ADC_InitTypeDef ADC_InitStructure;GPIO_InitTypeDef GPIO_InitStructure;NVIC_InitTypeDef NVIC_InitStructure;// 1. 启用时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1 | RCC_APB2Periph_GPIOA, ENABLE);RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);// 2. 配置GPIO为模拟输入GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;GPIO_Init(GPIOA, &GPIO_InitStructure);// 3. 规则组配置(循环采样PA0/PA1/PA2)ADC_RegularChannelConfig(ADC1, BATTERY_ADC_CHANNEL, 1, ADC_SampleTime_55Cycles5);ADC_RegularChannelConfig(ADC1, CURRENT_ADC_CHANNEL, 2, ADC_SampleTime_55Cycles5);ADC_RegularChannelConfig(ADC1, TEMP_ADC_CHANNEL, 3, ADC_SampleTime_239Cycles5);ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;ADC_InitStructure.ADC_ScanConvMode = ENABLE; // 扫描模式ADC_InitStructure.ADC_ContinuousConvMode = ENABLE; // 连续转换ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T2_TRGO; // TIM2触发ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;ADC_InitStructure.ADC_NbrOfChannel = 3;ADC_Init(ADC1, &ADC_InitStructure);// 4. 注入组配置(PA3,外部中断触发)ADC_InjectedChannelConfig(ADC1, OVERVOLTAGE_ADC_CHANNEL, 1, ADC_SampleTime_55Cycles5);ADC_ExternalTrigInjectedConvConfig(ADC1, ADC_ExternalTrigInjecConv_Ext_IT15); // PA8按键触发ADC_ITConfig(ADC1, ADC_IT_JEOC, ENABLE); // 启用注入组中断// 5. 启用DMA传输规则组数据DMA_InitTypeDef DMA_InitStructure;RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&ADC1->DR;DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)regularData;DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;DMA_InitStructure.DMA_BufferSize = 3;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_Init(DMA1_Channel1, &DMA_InitStructure);DMA_Cmd(DMA1_Channel1, ENABLE);ADC_DMACmd(ADC1, ENABLE);// 6. 配置注入组中断NVIC_InitStructure.NVIC_IRQChannel = ADC1_2_IRQn;NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; // 高优先级NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;NVIC_Init(&NVIC_InitStructure);// 7. 启动ADC和定时器ADC_Cmd(ADC1, ENABLE);ADC_ResetCalibration(ADC1);while(ADC_GetResetCalibrationStatus(ADC1));ADC_StartCalibration(ADC1);while(ADC_GetCalibrationStatus(ADC1));ADC_SoftwareStartConvCmd(ADC1, ENABLE);// 配置TIM2触发规则组(1kHz采样率)TIM_TimeBaseInitTypeDef TIM_InitStructure;TIM_InitStructure.TIM_Period = 7200 - 1; // 72MHz/7200 = 10kHzTIM_InitStructure.TIM_Prescaler = 0;TIM_InitStructure.TIM_ClockDivision = 0;TIM_InitStructure.TIM_CounterMode = TIM_CounterMode_Up;TIM_TimeBaseInit(TIM2, &TIM_InitStructure);TIM_SelectOutputTrigger(TIM2, TIM_TRGOSource_Update); // 更新事件触发ADCTIM_Cmd(TIM2, ENABLE);
}
2. 注入组中断服务函数
void ADC1_2_IRQHandler(void) {if (ADC_GetITStatus(ADC1, ADC_IT_JEOC)) {injectedData = ADC_GetInjectedConversionValue(ADC1, ADC_InjectedChannel_1);// 过压处理逻辑(例如关闭电源)if (injectedData > 3000) { // 假设3V为阈值GPIO_WriteBit(GPIOB, GPIO_Pin_12, Bit_RESET); // 关闭电源继电器}ADC_ClearITPendingBit(ADC1, ADC_IT_JEOC);}
}
3. 主循环
int main(void) {ADC_Configuration();while (1) {// 规则组数据通过DMA自动更新到regularData数组float batteryVoltage = regularData[0] * 3.3f / 4095; // 转换为电压值float current = regularData[1] * 3.3f / 4095;float temperature = regularData[2] * 3.3f / 4095;// 其他业务逻辑...}
}
关键机制解析
-
规则组:
- 由TIM2定时触发(1kHz),循环采样PA0/PA1/PA2。
- 数据通过DMA自动存入
regularData
数组,无需CPU干预。
-
注入组:
- 由PA8按键(外部中断)触发,立即中断规则组并采样PA3。
- 过压时在中断中紧急切断电源(高优先级响应)。
-
优先级:
- 注入组中断优先级(0)高于DMA传输,确保紧急事件即时处理。
实际应用场景
- 电动汽车BMS:规则组监控电池组电压/电流,注入组在单体过压时紧急切断。
- 工业PLC:规则组采集传感器数据,注入组处理急停信号。
通过此设计,实现了常规监测与紧急响应的完美结合,充分发挥STM32 ADC的灵活性。
PA8按键:
(1)人工紧急检测
场景示例:
工业设备运行中,操作员发现异常(如仪表显示电压波动),手动按下PA8按键,立即触发ADC注入组采集关键信号(如PA3的紧急传感器数据)。
医疗设备中,医生在患者出现异常时手动触发高优先级采样。
特点:
依赖人员主动干预,适合非周期性但需要即时响应的场景。
(2)硬件故障保护
场景示例:
电源系统中,过压保护电路检测到电压超标后,通过硬件信号(如比较器输出)自动触发PA8中断(无需人工按键),注入组快速采集故障信号并执行保护动作(如切断电源)。
特点:
完全由硬件自动触发,响应速度极快(微秒级)。