STM32 ADC中断读取调整函数及实验

一、ADC规则组与注入组的区别

1. 基本概念对比

规则组
定位:常规测量通道
优先级:较低
数据寄存器:1个共享数据寄存器(DR)
通道数量:最多16个通道
转换顺序:按预设序列顺序转换

注入组
定位:紧急/高优先级测量通道  
优先级:较高,可中断规则组转换
数据寄存器:4个独立数据寄存器(JDR1~JDR4)
通道数量:最多4个通道
转换顺序:可配置的独立序列

2. 详细区别分析

中断能力与优先级

规则组:
不能中断其他转换
可被注入组中断
适合常规的顺序数据采集

注入组:
可以中断规则组的转换
具有"插队"能力
适合紧急事件检测和快速响应

数据存储方式

规则组:

// 所有规则通道共享一个数据寄存器
uint32_t value = HAL_ADC_GetValue(&hadc1);
// 多通道时需要及时读取或使用DMA

注入组:

// 每个注入通道有独立的数据寄存器
uint32_t value1 = HAL_ADCEx_InjectedGetValue(&hadc1, ADC_INJECTED_RANK_1);
uint32_t value2 = HAL_ADCEx_InjectedGetValue(&hadc1, ADC_INJECTED_RANK_2);
uint32_t value3 = HAL_ADCEx_InjectedGetValue(&hadc1, ADC_INJECTED_RANK_3);
uint32_t value4 = HAL_ADCEx_InjectedGetValue(&hadc1, ADC_INJECTED_RANK_4);

触发方式

规则组触发:
软件触发
硬件触发(定时器、外部事件等)
连续转换模式

注入组触发:
软件触发
硬件触发
自动注入:在规则组转换结束后自动开始注入组转换

典型应用场景

规则组适用场景:
多路传感器数据采集(温度、压力、电压等)
周期性数据监测
顺序扫描多个检测点

注入组适用场景:
过压/过流保护
紧急停机信号检测
关键参数实时监控
需要立即响应的安全检测

二、ADC中断读取配置函数

1. HAL_ADCEx_InjectedStart_IT(&hadc1)

功能:以中断方式启动ADC注入组转换

特点:
启动注入组通道的转换
转换完成后会产生中断,调用相应的回调函数
注入组通常用于高优先级的紧急测量,可以中断正在进行的规则组转换
支持多个注入通道,按配置的序列顺序转换

2. HAL_ADCEx_InjectedConvCpltCallback(ADC_HandleTypeDef* hadc)

功能:注入组转换完成中断回调函数

特点:
当注入组转换完成时自动调用
需要用户在代码中重写这个函数
在函数内部可以安全地读取注入组转换结果
通常在此函数中处理注入组的测量数据

3. HAL_ADCEx_InjectedGetValue(ADC_HandleTypeDef* hadc, uint32_t InjectedRank)

功能:读取指定注入通道的转换结果

参数:
hadc:ADC句柄指针
InjectedRank:注入通道等级(ADC_INJECTED_RANK_1~4)
返回值:指定注入通道的ADC转换值
注意:注入组有独立的数据寄存器,可以同时保存多个通道的转换结果

4. HAL_ADC_Start_IT(&hadc1)

功能:以中断方式启动ADC规则组转换

特点:
启动规则组通道的转换
转换完成后会产生中断,调用规则组转换完成回调函数
规则组用于常规的顺序测量
适合多通道扫描转换

5. HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)

功能:规则组转换完成中断回调函数

特点:
当规则组转换完成时自动调用
需要用户在代码中重写这个函数
在函数内部可以安全地读取规则组转换结果
规则组所有通道转换完成后才会调用此函数

6. HAL_ADC_GetValue(&hadc1)

功能:读取规则组转换结果

特点:
读取规则组数据寄存器中的值
在规则组多通道转换时,通常返回序列中最后一个通道的值
建议在转换完成回调函数中调用此函数

三、示例实验

1. 实验现象

每隔500毫秒同时启动ADC规则组和注入组转换,通过中断方式分别采集两个通道的模拟信号,将规则组转换结果转换为电压值显示为"输出1",注入组转换结果转换为电压值显示为"输出2",并通过串口以每行一个电压值的形式输出这两个电压值,电压范围在0.000V到3.300V之间。

2. 示例代码

ADC初始化

void MX_ADC1_Init(void)
{
  ADC_ChannelConfTypeDef sConfig = {0};           // 定义规则通道配置结构体
  ADC_InjectionConfTypeDef sConfigInjected = {0}; // 定义注入通道配置结构体
  /** ADC通用配置 */
  hadc1.Instance = ADC1;                                // 设置ADC实例为ADC1
  hadc1.Init.ScanConvMode = ADC_SCAN_DISABLE;           // 禁用扫描模式(单通道)
  hadc1.Init.ContinuousConvMode = DISABLE;              // 禁用连续转换模式(单次转换)
  hadc1.Init.DiscontinuousConvMode = DISABLE;           // 禁用间断模式
  hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;     // 使用软件触发转换
  hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;           // 数据右对齐
  hadc1.Init.NbrOfConversion = 1;                       // 转换序列数为1
  // 初始化ADC,如果失败则调用错误处理函数
  if (HAL_ADC_Init(&hadc1) != HAL_OK)
  {
    Error_Handler();
  }
  /** 配置规则通道 */
  sConfig.Channel = ADC_CHANNEL_4;          // 设置ADC规则通道4
  sConfig.Rank = ADC_REGULAR_RANK_1;        // 设置通道在规则组中的排名为第1个
  sConfig.SamplingTime = ADC_SAMPLETIME_1CYCLE_5;  // 设置采样时间为1.5个ADC时钟周期
  // 配置ADC规则通道,如果失败则调用错误处理函数
  if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
  {
    Error_Handler();
  }
  /** 配置注入通道 */
  sConfigInjected.InjectedChannel = ADC_CHANNEL_5;      // 设置ADC注入通道5
  sConfigInjected.InjectedRank = ADC_INJECTED_RANK_1;   // 设置注入通道等级为第1个
  sConfigInjected.InjectedNbrOfConversion = 1;          // 注入组转换序列数为1
  sConfigInjected.InjectedSamplingTime = ADC_SAMPLETIME_1CYCLE_5;  // 设置采样时间
  sConfigInjected.ExternalTrigInjecConv = ADC_INJECTED_SOFTWARE_START;  // 软件触发注入转换
  sConfigInjected.AutoInjectedConv = DISABLE;           // 禁用自动注入模式
  sConfigInjected.InjectedDiscontinuousConvMode = DISABLE;  // 禁用注入间断模式
  sConfigInjected.InjectedOffset = 0;                   // 设置注入偏移量为0
  // 配置ADC注入通道,如果失败则调用错误处理函数
  if (HAL_ADCEx_InjectedConfigChannel(&hadc1, &sConfigInjected) != HAL_OK)
  {
    Error_Handler();
  }
}

主函数

uint16_t get[2] = {0};    // 存储ADC原始值的数组:[0]规则组结果,[1]注入组结果
float aaa[2] = {0.0f};    // 存储电压值的数组:[0]规则组电压,[1]注入组电压
// 系统时钟配置函数声明
void SystemClock_Config(void);
/**
  * @brief  应用程序主函数
  * @retval int
  */
int main(void)
{
  // HAL库初始化
  HAL_Init();
  // 系统时钟配置
  SystemClock_Config();
  // 初始化所有配置的外设
  MX_GPIO_Init();           // GPIO初始化
  MX_ADC1_Init();           // ADC1初始化(配置规则通道4和注入通道5)
  MX_USART1_UART_Init();    // USART1串口初始化
  HAL_ADCEx_Calibration_Start(&hadc1);  // 执行ADC校准
  // 主循环
  while (1)
  {
    // 以中断方式启动规则组转换
    HAL_ADC_Start_IT(&hadc1);
    // 以中断方式启动注入组转换
    HAL_ADCEx_InjectedStart_IT(&hadc1);
    // 将ADC原始值转换为电压值(12位分辨率,参考电压3.3V)
    aaa[0] = (float)get[0] / 4095 * 3.3f;  // 规则组通道4的电压值
    aaa[1] = (float)get[1] / 4095 * 3.3f;  // 注入组通道5的电压值
    // 通过串口输出两个通道的电压值
    printf("\r\n输出1:%.3f\r\n输出2:%.3f\r\n", aaa[0], aaa[1]);
    // 延时500ms
    HAL_Delay(500);
  }
}

中断回调函数

/**
  * @brief  规则组转换完成中断回调函数
  * @param  hadc: ADC句柄指针
  */
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)
{
  if(hadc->Instance == ADC1)
  {
    // 读取规则组转换结果(通道4)并存储到get[0]
    get[0] = HAL_ADC_GetValue(hadc);
  }
}
/**
  * @brief  注入组转换完成中断回调函数
  * @param  hadc: ADC句柄指针
  */
void HAL_ADCEx_InjectedConvCpltCallback(ADC_HandleTypeDef* hadc)
{
  if(hadc->Instance == ADC1)
  {
    // 读取注入组转换结果(通道5)并存储到get[1]
    get[1] = HAL_ADCEx_InjectedGetValue(hadc, ADC_INJECTED_RANK_1);
  }
}
posted @ 2025-12-19 19:14  clnchanpin  阅读(94)  评论(0)    收藏  举报