当前位置: 首页 > article >正文

ADC(三):注入组的使用

有关ADC的基础知识请参考标准库入门教程

ADC(三):注入组的使用

  • 1、规则组软件触发+注入组自动注入
  • 2、规则组外部触发+注入组自动注入
  • 3、规则组软件触发+注入组外部触发(TIM2_CC1)
  • 4、规则组软件触发+注入组外部触发(EXTI15)+间断模式
  • 5、模拟看门狗的使用

1、规则组软件触发+注入组自动注入

自动注入模式:就是跟随规则组转换,等待规则组转换完成后,在转换注入组,不会抢占规则组的转换。自动注入模式是由注入组的软件触发,不能由注入组的外部触发
在这里插入图片描述

①ADC.c文件的代码如下

#include "ADC.h"

uint16_t ADC1_Buffer[4] = {0};             //数据缓冲区
/**
 * @brief:ADC1初始化函数
 */
RCC_PeriphCLKInitTypeDef PeriphClkInit; //ADC时钟配置结构体
ADC_HandleTypeDef hadc1;                //ADC1配置结构体
ADC_ChannelConfTypeDef sConfig1;        //规则组通道配置结构体
ADC_InjectionConfTypeDef sConfigInjected;//注入组通道配置结构体
void ADC_Init(void)
{
    /* 1、ADC的时钟配置 < 14MHz  */
    PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_ADC; //需要配置的外设:ADC
    PeriphClkInit.AdcClockSelection = RCC_ADCPCLK2_DIV6;    //设置ADC分频值:6分频 = 12MHz
    HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit);
        
    /* 2、ADC1的初始化 */
    __HAL_RCC_ADC1_CLK_ENABLE();                        //使能ADC1时钟
    hadc1.Instance = ADC1;                              //选择ADC1
    hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;         //数据对齐方式:右对齐
    hadc1.Init.ScanConvMode = ADC_SCAN_ENABLE;          //扫描模式:开启扫描(多个通道)
    hadc1.Init.ContinuousConvMode = ENABLE;             //转换模式:连续转换
    hadc1.Init.NbrOfConversion = 4;                     //扫描模式下规则组的数量
  //hadc1.Init.DiscontinuousConvMode = ENABLE;          //扫描模式规则组间断模式
  //hadc1.Init.NbrOfDiscConversion = 2;                 //规则组间断模式下每次间断的通道数:2队为1组
    hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;   //ADC触发:软件触发
    HAL_ADC_Init(&hadc1);
    
    /* 3、规则组通道配置 */
    sConfig1.Channel = ADC_CHANNEL_0;                    //通道选择:通道0
    sConfig1.Rank = ADC_REGULAR_RANK_1;                  //规则组盒子序号:1号
    sConfig1.SamplingTime = ADC_SAMPLETIME_41CYCLES_5;   //采样时间:41.5T
    HAL_ADC_ConfigChannel(&hadc1, &sConfig1);
    
    sConfig1.Channel = ADC_CHANNEL_1;                    //通道选择:通道1
    sConfig1.Rank = ADC_REGULAR_RANK_2;                  //规则组盒子序号:2号
    sConfig1.SamplingTime = ADC_SAMPLETIME_41CYCLES_5;   //采样时间:41.5T
    HAL_ADC_ConfigChannel(&hadc1, &sConfig1);
    
    sConfig1.Channel = ADC_CHANNEL_2;                    //通道选择:通道2
    sConfig1.Rank = ADC_REGULAR_RANK_3;                  //规则组盒子序号:3号
    sConfig1.SamplingTime = ADC_SAMPLETIME_41CYCLES_5;   //采样时间:41.5T
    HAL_ADC_ConfigChannel(&hadc1, &sConfig1);
    
    sConfig1.Channel = ADC_CHANNEL_3;                    //通道选择:通道3
    sConfig1.Rank = ADC_REGULAR_RANK_4;                  //规则组盒子序号:4号
    sConfig1.SamplingTime = ADC_SAMPLETIME_41CYCLES_5;   //采样时间:41.5T
    HAL_ADC_ConfigChannel(&hadc1, &sConfig1);
    
    /* 4、组入组通道配置 */
    sConfigInjected.InjectedChannel = ADC_CHANNEL_4;                    //通道选择:通道4
    sConfigInjected.InjectedRank = ADC_INJECTED_RANK_1;                 //注入组盒子序号:1号
    sConfigInjected.InjectedSamplingTime = ADC_SAMPLETIME_41CYCLES_5;   //采样时间:41.5T
    sConfigInjected.InjectedOffset = 0;                                 //偏移值:0,即:数据寄存器值=	测量值 - 偏移值
    sConfigInjected.InjectedNbrOfConversion = 4;                        //组入组通道数量:4个
    sConfigInjected.InjectedDiscontinuousConvMode = DISABLE;            //关闭间断模式
    sConfigInjected.AutoInjectedConv = ENABLE;                          //自动注入:开启
    sConfigInjected.ExternalTrigInjecConv = ADC_INJECTED_SOFTWARE_START;//触发:软件触发
    HAL_ADCEx_InjectedConfigChannel(&hadc1, &sConfigInjected);
    
    sConfigInjected.InjectedChannel = ADC_CHANNEL_5;                    //通道选择:通道5
    sConfigInjected.InjectedRank = ADC_INJECTED_RANK_2;                 //注入组盒子序号:2号
    sConfigInjected.InjectedSamplingTime = ADC_SAMPLETIME_41CYCLES_5;   //采样时间:41.5T
    sConfigInjected.InjectedOffset = 0;                                 //偏移值:0
    HAL_ADCEx_InjectedConfigChannel(&hadc1, &sConfigInjected);
    
    sConfigInjected.InjectedChannel = ADC_CHANNEL_6;                    //通道选择:通道6
    sConfigInjected.InjectedRank = ADC_INJECTED_RANK_3;                 //注入组盒子序号:3号
    sConfigInjected.InjectedSamplingTime = ADC_SAMPLETIME_41CYCLES_5;   //采样时间:41.5T
    sConfigInjected.InjectedOffset = 0;                                 //偏移值:0
    HAL_ADCEx_InjectedConfigChannel(&hadc1, &sConfigInjected);
    
    sConfigInjected.InjectedChannel = ADC_CHANNEL_7;                    //通道选择:通道7
    sConfigInjected.InjectedRank = ADC_INJECTED_RANK_4;                 //注入组盒子序号:4号
    sConfigInjected.InjectedSamplingTime = ADC_SAMPLETIME_41CYCLES_5;   //采样时间:41.5T
    sConfigInjected.InjectedOffset = 0;                                 //偏移值:0
    HAL_ADCEx_InjectedConfigChannel(&hadc1, &sConfigInjected);
    
    /* 5、ADC1校准 */
    HAL_ADCEx_Calibration_Start(&hadc1);                //ADC1自校准
    
    /* 6、开启ADC规则组转换 */
    HAL_ADC_Start_DMA(&hadc1,(uint32_t*)ADC1_Buffer,4); //开启转换:DMA方式,转换完成DMA执行搬运,
                                                        //开启了DMA中断,搬运2后执行DMA中断
    HAL_NVIC_SetPriority(DMA1_Channel1_IRQn,3,0);       //配置优先级
    HAL_NVIC_EnableIRQ(DMA1_Channel1_IRQn);             //使能中断源
    
    /* 7、开启ADC注入组转换 */
    HAL_ADCEx_InjectedStart_IT(&hadc1);                 //开启转换:注入组设置的通道全部转换完成中断
    HAL_NVIC_SetPriority(ADC1_2_IRQn,3,0);              //配置优先级
    HAL_NVIC_EnableIRQ(ADC1_2_IRQn);                    //使能中断源
}

/**
 * @brief:HAL_ADC_Init()调用函数
 */
DMA_HandleTypeDef hdma1_ADC1;               //ADC1的DMA1的通道配置结构体
void HAL_ADC_MspInit(ADC_HandleTypeDef* hadc)
{
    GPIO_InitTypeDef GPIO_Init;             //IO口配置的结构体
    if(hadc->Instance == ADC1)
    {
        /* 配置ADC1通道0:PA0,通道1:PA1,通道2:PA2,通道3:PA3 */
        __HAL_RCC_GPIOA_CLK_ENABLE();       //使能GPIOA时钟
        GPIO_Init.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3
                       |GPIO_PIN_4 | GPIO_PIN_5 | GPIO_PIN_6 | GPIO_PIN_7;
        GPIO_Init.Mode = GPIO_MODE_ANALOG;  //选择模拟输入模式
        HAL_GPIO_Init(GPIOA, &GPIO_Init);
        
        /* 1、初始化DMA1的通道1配置 */
        __HAL_RCC_DMA1_CLK_ENABLE();                                    //使能DMA1的时钟
        hdma1_ADC1.Instance = DMA1_Channel1;                            //选择DMA1的通道1
        hdma1_ADC1.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;  //外设站点数据宽度:16位
        hdma1_ADC1.Init.PeriphInc = DMA_PINC_DISABLE;                   //外设地址是否递增:选择不自增
        hdma1_ADC1.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;     //内存站点数据宽度:16位
        hdma1_ADC1.Init.MemInc = DMA_MINC_ENABLE;                       //内存地址是否递增:选择自增
        hdma1_ADC1.Init.Direction = DMA_PERIPH_TO_MEMORY;               //传输方向:这里选择外设---->内存
        hdma1_ADC1.Init.Mode = DMA_CIRCULAR;                            //计数器传输模式:自动重装
        hdma1_ADC1.Init.Priority = DMA_PRIORITY_MEDIUM;                 //通道1传输优先级:选择中等
        __HAL_LINKDMA(&hadc1,DMA_Handle,hdma1_ADC1);                    //ADC1和DMA1构建链接
        HAL_DMA_Init(&hdma1_ADC1);
        
    }
    else if(hadc->Instance == ADC2)
    {
        
    }    
}

②ADC.h文件的代码如下

#ifndef __ADC_H
#define __ADC_H

#include "stm32f1xx_hal.h"
extern uint16_t ADC1_Buffer[4];
extern ADC_HandleTypeDef hadc1;                //ADC1配置结构体
extern DMA_HandleTypeDef hdma1_ADC1;           //ADC1的DMA1的通道配置结构体
void ADC_Init(void);

#endif

③main.c文件的代码如下

#include "stm32f1xx_hal.h"
#include "STM32_RCC_Init.h"
#include "ADC.h"
#include "UART.h"
 
int main(void){
    
	HAL_Init();
	HSE_RCC_Init(); 
	UART1_Init(115200);
    ADC_Init();
	printf("启动判断!\r\n");
    
	while(1){
       
	}	
}

④stm32f1xx_it.c文件的代码如下

#include "stm32f1xx_hal.h"   
#include "stm32f1xx_it.h" 
#include "ADC.h" 
#include "UART.h"
/**
 * @brief:DMA通道1中断服务函数
 */
void DMA1_Channel1_IRQHandler(void)
{
    HAL_DMA_IRQHandler(&hdma1_ADC1);//DMA中断服务总函数
}

/**
 * @brief:ADC中断服务函数
 */
void ADC1_2_IRQHandler(void)
{
     HAL_ADC_IRQHandler(&hadc1);//ADC中断服务总函数
}
/******************* 下面的中断的回调函数 ***************************/
/**
 * @brief:规则组的DMA通道1传输完成的中断服务函数
 */
float ADC_Value = 0;
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)
{
    if(hadc->Instance == ADC1)
    {
        ADC_Value = ADC1_Buffer[0] * 3.3 / 4095;            //将二进制计数为电压电压值
        printf("通道0电压值 = %f\r\n",ADC_Value);            //输出电压值
        
        ADC_Value = ADC1_Buffer[1] * 3.3 / 4095;            //将二进制计数为电压电压值
        printf("通道1电压值 = %f\r\n",ADC_Value);           //输出电压值
        
        ADC_Value = ADC1_Buffer[2] * 3.3 / 4095;            //将二进制计数为电压电压值
        printf("通道2电压值 = %f\r\n",ADC_Value);            //输出电压值
        
        ADC_Value = ADC1_Buffer[3] * 3.3 / 4095;            //将二进制计数为电压电压值
        printf("通道3电压值 = %f\r\n",ADC_Value);           //输出电压值
    }else if(hadc->Instance == ADC2)
    {
    
    }
}

/**
 * @brief:ADC注入组中断服务函数
 */
void HAL_ADCEx_InjectedConvCpltCallback(ADC_HandleTypeDef* hadc)
{
    uint32_t Data = 0;
    if(hadc->Instance == ADC1)
    {
        Data = HAL_ADCEx_InjectedGetValue(hadc, ADC_INJECTED_RANK_1);   //获取注入组盒子序列1的数据寄存器的值
        ADC_Value = Data * 3.3 / 4095;                                  //将二进制计数为电压电压值
        printf("通道4电压值 = %f\r\n",ADC_Value);                        //输出电压值
        
        Data = HAL_ADCEx_InjectedGetValue(hadc, ADC_INJECTED_RANK_2);   //获取注入组盒子序列2的数据寄存器的值
        ADC_Value = Data * 3.3 / 4095;                                  //将二进制计数为电压电压值
        printf("通道5电压值 = %f\r\n",ADC_Value);                        //输出电压值
        
        Data = HAL_ADCEx_InjectedGetValue(hadc, ADC_INJECTED_RANK_3);   //获取注入组盒子序列3的数据寄存器的值
        ADC_Value = Data * 3.3 / 4095;                                  //将二进制计数为电压电压值
        printf("通道6电压值 = %f\r\n",ADC_Value);                        //输出电压值
        
        Data = HAL_ADCEx_InjectedGetValue(hadc, ADC_INJECTED_RANK_4);   //获取注入组盒子序列4的数据寄存器的值
        ADC_Value = Data * 3.3 / 4095;                                  //将二进制计数为电压电压值
        printf("通道7电压值 = %f\r\n",ADC_Value);                        //输出电压值
        __HAL_ADC_ENABLE_IT(hadc, ADC_IT_JEOC);                         //重新开启注入组中断,由于在自动注入时HAL_ADC_IRQHandler()
        																//会关闭注入组ADC中断,所以需要重新打开
    }
}

2、规则组外部触发+注入组自动注入

修改的代码如下:
将规则组修改为单次转换,且外部触发即可,注入组的代码不用修改
①ADC.c文件需要修改的代码如下

#include "ADC.h"

uint16_t ADC1_Buffer[4] = {0};             //数据缓冲区
/**
 * @brief:ADC1初始化函数
 */
RCC_PeriphCLKInitTypeDef PeriphClkInit; //ADC时钟配置结构体
ADC_HandleTypeDef hadc1;                //ADC1配置结构体
ADC_ChannelConfTypeDef sConfig1;        //规则组通道配置结构体
ADC_InjectionConfTypeDef sConfigInjected;//注入组通道配置结构体
void ADC_Init(void)
{
    /* 1、ADC的时钟配置 < 14MHz  */
    PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_ADC; //需要配置的外设:ADC
    PeriphClkInit.AdcClockSelection = RCC_ADCPCLK2_DIV6;    //设置ADC分频值:6分频 = 12MHz
    HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit);
        
    /* 2、ADC1的初始化 */
    __HAL_RCC_ADC1_CLK_ENABLE();                        //使能ADC1时钟
    hadc1.Instance = ADC1;                              //选择ADC1
    hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;         //数据对齐方式:右对齐
    hadc1.Init.ScanConvMode = ADC_SCAN_ENABLE;          //扫描模式:开启扫描(多个通道)
    hadc1.Init.ContinuousConvMode = DISABLE;            //转换模式:单次转换
    hadc1.Init.NbrOfConversion = 4;                     //扫描模式下规则组的数量
  //hadc1.Init.DiscontinuousConvMode = ENABLE;          //扫描模式规则组间断模式
  //hadc1.Init.NbrOfDiscConversion = 2;                 //规则组间断模式下每次间断的通道数:2队为1组
    hadc1.Init.ExternalTrigConv = ADC_EXTERNALTRIGCONV_EXT_IT11;   //ADC触发:外部中断EXTI11触发
    HAL_ADC_Init(&hadc1);
    
    /* 3、规则组通道配置 */
    sConfig1.Channel = ADC_CHANNEL_0;                    //通道选择:通道0
    sConfig1.Rank = ADC_REGULAR_RANK_1;                  //规则组盒子序号:1号
    sConfig1.SamplingTime = ADC_SAMPLETIME_41CYCLES_5;   //采样时间:41.5T
    HAL_ADC_ConfigChannel(&hadc1, &sConfig1);
    
    sConfig1.Channel = ADC_CHANNEL_1;                    //通道选择:通道1
    sConfig1.Rank = ADC_REGULAR_RANK_2;                  //规则组盒子序号:2号
    sConfig1.SamplingTime = ADC_SAMPLETIME_41CYCLES_5;   //采样时间:41.5T
    HAL_ADC_ConfigChannel(&hadc1, &sConfig1);
    
    sConfig1.Channel = ADC_CHANNEL_2;                    //通道选择:通道2
    sConfig1.Rank = ADC_REGULAR_RANK_3;                  //规则组盒子序号:3号
    sConfig1.SamplingTime = ADC_SAMPLETIME_41CYCLES_5;   //采样时间:41.5T
    HAL_ADC_ConfigChannel(&hadc1, &sConfig1);
    
    sConfig1.Channel = ADC_CHANNEL_3;                    //通道选择:通道3
    sConfig1.Rank = ADC_REGULAR_RANK_4;                  //规则组盒子序号:4号
    sConfig1.SamplingTime = ADC_SAMPLETIME_41CYCLES_5;   //采样时间:41.5T
    HAL_ADC_ConfigChannel(&hadc1, &sConfig1);
    
    /* 4、组入组通道配置 */
    sConfigInjected.InjectedChannel = ADC_CHANNEL_4;                    //通道选择:通道4
    sConfigInjected.InjectedRank = ADC_INJECTED_RANK_1;                 //注入组盒子序号:1号
    sConfigInjected.InjectedSamplingTime = ADC_SAMPLETIME_41CYCLES_5;   //采样时间:41.5T
    sConfigInjected.InjectedOffset = 0;                                 //偏移值:0
    sConfigInjected.InjectedNbrOfConversion = 4;                        //组入组通道数量:4个
    sConfigInjected.InjectedDiscontinuousConvMode = DISABLE;            //关闭间断模式
    sConfigInjected.AutoInjectedConv = ENABLE;                          //自动注入:开启
    sConfigInjected.ExternalTrigInjecConv = ADC_INJECTED_SOFTWARE_START;//触发:软件触发
    HAL_ADCEx_InjectedConfigChannel(&hadc1, &sConfigInjected);
    
    sConfigInjected.InjectedChannel = ADC_CHANNEL_5;                    //通道选择:通道5
    sConfigInjected.InjectedRank = ADC_INJECTED_RANK_2;                 //注入组盒子序号:2号
    sConfigInjected.InjectedSamplingTime = ADC_SAMPLETIME_41CYCLES_5;   //采样时间:41.5T
    sConfigInjected.InjectedOffset = 0;                                 //偏移值:0
    HAL_ADCEx_InjectedConfigChannel(&hadc1, &sConfigInjected);
    
    sConfigInjected.InjectedChannel = ADC_CHANNEL_6;                    //通道选择:通道6
    sConfigInjected.InjectedRank = ADC_INJECTED_RANK_3;                 //注入组盒子序号:3号
    sConfigInjected.InjectedSamplingTime = ADC_SAMPLETIME_41CYCLES_5;   //采样时间:41.5T
    sConfigInjected.InjectedOffset = 0;                                 //偏移值:0
    HAL_ADCEx_InjectedConfigChannel(&hadc1, &sConfigInjected);
    
    sConfigInjected.InjectedChannel = ADC_CHANNEL_7;                    //通道选择:通道7
    sConfigInjected.InjectedRank = ADC_INJECTED_RANK_4;                 //注入组盒子序号:4号
    sConfigInjected.InjectedSamplingTime = ADC_SAMPLETIME_41CYCLES_5;   //采样时间:41.5T
    sConfigInjected.InjectedOffset = 0;                                 //偏移值:0
    HAL_ADCEx_InjectedConfigChannel(&hadc1, &sConfigInjected);
    
    /* 5、ADC1校准 */
    HAL_ADCEx_Calibration_Start(&hadc1);                //ADC1自校准
    
    /* 6、开启ADC规则组转换 */
    HAL_ADC_Start_DMA(&hadc1,(uint32_t*)ADC1_Buffer,4); //开启转换:DMA方式,转换完成DMA执行搬运,
                                                        //开启了DMA中断,搬运4后执行DMA中断
    HAL_NVIC_SetPriority(DMA1_Channel1_IRQn,3,0);       //配置优先级
    HAL_NVIC_EnableIRQ(DMA1_Channel1_IRQn);             //使能中断源
    
    /* 7、开启ADC注入组转换 */
    HAL_ADCEx_InjectedStart_IT(&hadc1);                 //开启转换:注入组设置的通道全部转换完成中断
    HAL_NVIC_SetPriority(ADC1_2_IRQn,3,0);              //配置优先级
    HAL_NVIC_EnableIRQ(ADC1_2_IRQn);                    //使能中断源
}

/**
 * @brief:HAL_ADC_Init()调用函数
 */
DMA_HandleTypeDef hdma1_ADC1;               //ADC1的DMA1的通道配置结构体
void HAL_ADC_MspInit(ADC_HandleTypeDef* hadc)
{
    GPIO_InitTypeDef GPIO_Init;             //IO口配置的结构体
    if(hadc->Instance == ADC1)
    {
        /* 配置ADC1通道0:PA0,通道1:PA1,通道2:PA2,通道3:PA3 */
        __HAL_RCC_GPIOA_CLK_ENABLE();       //使能GPIOA时钟
        GPIO_Init.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3
                       |GPIO_PIN_4 | GPIO_PIN_5 | GPIO_PIN_6 | GPIO_PIN_7;
        GPIO_Init.Mode = GPIO_MODE_ANALOG;  //选择模拟输入模式
        HAL_GPIO_Init(GPIOA, &GPIO_Init);
        
        /* 1、初始化DMA1的通道1配置 */
        __HAL_RCC_DMA1_CLK_ENABLE();                                    //使能DMA1的时钟
        hdma1_ADC1.Instance = DMA1_Channel1;                            //选择DMA1的通道1
        hdma1_ADC1.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;  //外设站点数据宽度:16位
        hdma1_ADC1.Init.PeriphInc = DMA_PINC_DISABLE;                   //外设地址是否递增:选择不自增
        hdma1_ADC1.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;     //内存站点数据宽度:16位
        hdma1_ADC1.Init.MemInc = DMA_MINC_ENABLE;                       //内存地址是否递增:选择自增
        hdma1_ADC1.Init.Direction = DMA_PERIPH_TO_MEMORY;               //传输方向:这里选择外设---->内存
        hdma1_ADC1.Init.Mode = DMA_CIRCULAR;                            //计数器传输模式:自动重装
        hdma1_ADC1.Init.Priority = DMA_PRIORITY_MEDIUM;                 //通道1传输优先级:选择中等
        __HAL_LINKDMA(&hadc1,DMA_Handle,hdma1_ADC1);                    //ADC1和DMA1构建链接
        HAL_DMA_Init(&hdma1_ADC1);
        
        /* 2、配置EXTI11 */
        __HAL_RCC_AFIO_CLK_ENABLE();            //使能AFIO时钟
        GPIO_Init.Pin = GPIO_PIN_11;            //选择PA11
        GPIO_Init.Mode = GPIO_MODE_IT_RISING;   //选择上升沿触发中断
        GPIO_Init.Pull = GPIO_PULLDOWN;         //选择下拉输入
        HAL_GPIO_Init(GPIOA, &GPIO_Init);
        
        /* 3、配置外部中断EXTI11的NVIC*/
        HAL_NVIC_SetPriority(EXTI15_10_IRQn,3,0);
        HAL_NVIC_EnableIRQ(EXTI15_10_IRQn);
        
    }
    else if(hadc->Instance == ADC2)
    {
        
    }    
}

3、规则组软件触发+注入组外部触发(TIM2_CC1)

在这里插入图片描述①注入组的外部触发与自动注入不同,他会抢占规则组的转换,等待注入组通道转换完成后,才能转换规则组通道。
②外部信号触发,ADC的注入组只转换1个通道。
③只有当注入组设置的通道全部转换完成后才会触发ADC中断。即需要4次外部触发才会进入中断服务函数,将测量的结果输出。
①ADC.c文件的代码如下

#include "ADC.h"

uint16_t ADC1_Buffer[4] = {0};             //数据缓冲区
/**
 * @brief:ADC1初始化函数
 */
RCC_PeriphCLKInitTypeDef PeriphClkInit; //ADC时钟配置结构体
ADC_HandleTypeDef hadc1;                //ADC1配置结构体
ADC_ChannelConfTypeDef sConfig1;        //规则组通道配置结构体
ADC_InjectionConfTypeDef sConfigInjected;//注入组通道配置结构体
void ADC_Init(void)
{
    /* 1、ADC的时钟配置 < 14MHz  */
    PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_ADC; //需要配置的外设:ADC
    PeriphClkInit.AdcClockSelection = RCC_ADCPCLK2_DIV6;    //设置ADC分频值:6分频 = 12MHz
    HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit);
        
    /* 2、ADC1的初始化 */
    __HAL_RCC_ADC1_CLK_ENABLE();                        //使能ADC1时钟
    hadc1.Instance = ADC1;                              //选择ADC1
    hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;         //数据对齐方式:右对齐
    hadc1.Init.ScanConvMode = ADC_SCAN_ENABLE;          //扫描模式:开启扫描(多个通道)
    hadc1.Init.ContinuousConvMode = ENABLE;             //转换模式:连续转换
    hadc1.Init.NbrOfConversion = 4;                     //扫描模式下规则组的数量
  //hadc1.Init.DiscontinuousConvMode = ENABLE;          //扫描模式规则组间断模式
  //hadc1.Init.NbrOfDiscConversion = 2;                 //规则组间断模式下每次间断的通道数:2队为1组
    hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;   //ADC触发:软件触发
    HAL_ADC_Init(&hadc1);
    
    /* 3、规则组通道配置 */
    sConfig1.Channel = ADC_CHANNEL_0;                    //通道选择:通道0
    sConfig1.Rank = ADC_REGULAR_RANK_1;                  //规则组盒子序号:1号
    sConfig1.SamplingTime = ADC_SAMPLETIME_41CYCLES_5;   //采样时间:41.5T
    HAL_ADC_ConfigChannel(&hadc1, &sConfig1);
    
    sConfig1.Channel = ADC_CHANNEL_1;                    //通道选择:通道1
    sConfig1.Rank = ADC_REGULAR_RANK_2;                  //规则组盒子序号:2号
    sConfig1.SamplingTime = ADC_SAMPLETIME_41CYCLES_5;   //采样时间:41.5T
    HAL_ADC_ConfigChannel(&hadc1, &sConfig1);
    
    sConfig1.Channel = ADC_CHANNEL_2;                    //通道选择:通道2
    sConfig1.Rank = ADC_REGULAR_RANK_3;                  //规则组盒子序号:3号
    sConfig1.SamplingTime = ADC_SAMPLETIME_41CYCLES_5;   //采样时间:41.5T
    HAL_ADC_ConfigChannel(&hadc1, &sConfig1);
    
    sConfig1.Channel = ADC_CHANNEL_3;                    //通道选择:通道3
    sConfig1.Rank = ADC_REGULAR_RANK_4;                  //规则组盒子序号:4号
    sConfig1.SamplingTime = ADC_SAMPLETIME_41CYCLES_5;   //采样时间:41.5T
    HAL_ADC_ConfigChannel(&hadc1, &sConfig1);
    
    /* 4、组入组通道配置 */
    sConfigInjected.InjectedChannel = ADC_CHANNEL_4;                    //通道选择:通道4
    sConfigInjected.InjectedRank = ADC_INJECTED_RANK_1;                 //注入组盒子序号:1号
    sConfigInjected.InjectedSamplingTime = ADC_SAMPLETIME_41CYCLES_5;   //采样时间:41.5T
    sConfigInjected.InjectedOffset = 0;                                 //偏移值:0
    sConfigInjected.InjectedNbrOfConversion = 4;                        //组入组通道数量:4个
    sConfigInjected.InjectedDiscontinuousConvMode = DISABLE;            //关闭间断模式
    sConfigInjected.AutoInjectedConv = DISABLE;                         //自动注入:关闭
    sConfigInjected.ExternalTrigInjecConv = ADC_EXTERNALTRIGINJECCONV_T2_CC1;//触发:TIM2的CC1触发
    HAL_ADCEx_InjectedConfigChannel(&hadc1, &sConfigInjected);
    
    sConfigInjected.InjectedChannel = ADC_CHANNEL_5;                    //通道选择:通道5
    sConfigInjected.InjectedRank = ADC_INJECTED_RANK_2;                 //注入组盒子序号:2号
    sConfigInjected.InjectedSamplingTime = ADC_SAMPLETIME_41CYCLES_5;   //采样时间:41.5T
    sConfigInjected.InjectedOffset = 0;                                 //偏移值:0
    HAL_ADCEx_InjectedConfigChannel(&hadc1, &sConfigInjected);
    
    sConfigInjected.InjectedChannel = ADC_CHANNEL_6;                    //通道选择:通道6
    sConfigInjected.InjectedRank = ADC_INJECTED_RANK_3;                 //注入组盒子序号:3号
    sConfigInjected.InjectedSamplingTime = ADC_SAMPLETIME_41CYCLES_5;   //采样时间:41.5T
    sConfigInjected.InjectedOffset = 0;                                 //偏移值:0
    HAL_ADCEx_InjectedConfigChannel(&hadc1, &sConfigInjected);
    
    sConfigInjected.InjectedChannel = ADC_CHANNEL_7;                    //通道选择:通道7
    sConfigInjected.InjectedRank = ADC_INJECTED_RANK_4;                 //注入组盒子序号:4号
    sConfigInjected.InjectedSamplingTime = ADC_SAMPLETIME_41CYCLES_5;   //采样时间:41.5T
    sConfigInjected.InjectedOffset = 0;                                 //偏移值:0
    HAL_ADCEx_InjectedConfigChannel(&hadc1, &sConfigInjected);
    
    /* 5、ADC1校准 */
    HAL_ADCEx_Calibration_Start(&hadc1);                //ADC1自校准
    
    /* 6、开启ADC规则组转换 */
    HAL_ADC_Start_DMA(&hadc1,(uint32_t*)ADC1_Buffer,4); //开启转换:DMA方式,转换完成DMA执行搬运,
                                                        //开启了DMA中断,搬运4后执行DMA中断
    HAL_NVIC_SetPriority(DMA1_Channel1_IRQn,3,0);       //配置优先级
    HAL_NVIC_EnableIRQ(DMA1_Channel1_IRQn);             //使能中断源
    
    /* 7、开启ADC注入组转换 */
    HAL_ADCEx_InjectedStart_IT(&hadc1);                 //开启转换:注入组设置的通道全部转换完成中断
    HAL_NVIC_SetPriority(ADC1_2_IRQn,3,0);              //配置优先级
    HAL_NVIC_EnableIRQ(ADC1_2_IRQn);                    //使能中断源
}

/**
 * @brief:HAL_ADC_Init()调用函数
 */
DMA_HandleTypeDef hdma1_ADC1;               //ADC1的DMA1的通道配置结构体
void HAL_ADC_MspInit(ADC_HandleTypeDef* hadc)
{
    GPIO_InitTypeDef GPIO_Init;             //IO口配置的结构体
    if(hadc->Instance == ADC1)
    {
        /* 配置ADC1通道0:PA0,通道1:PA1,通道2:PA2,通道3:PA3 */
        __HAL_RCC_GPIOA_CLK_ENABLE();       //使能GPIOA时钟
        GPIO_Init.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3
                       |GPIO_PIN_4 | GPIO_PIN_5 | GPIO_PIN_6 | GPIO_PIN_7;
        GPIO_Init.Mode = GPIO_MODE_ANALOG;  //选择模拟输入模式
        HAL_GPIO_Init(GPIOA, &GPIO_Init);
        
        /* 1、初始化DMA1的通道1配置 */
        __HAL_RCC_DMA1_CLK_ENABLE();                                    //使能DMA1的时钟
        hdma1_ADC1.Instance = DMA1_Channel1;                            //选择DMA1的通道1
        hdma1_ADC1.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;  //外设站点数据宽度:16位
        hdma1_ADC1.Init.PeriphInc = DMA_PINC_DISABLE;                   //外设地址是否递增:选择不自增
        hdma1_ADC1.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;     //内存站点数据宽度:16位
        hdma1_ADC1.Init.MemInc = DMA_MINC_ENABLE;                       //内存地址是否递增:选择自增
        hdma1_ADC1.Init.Direction = DMA_PERIPH_TO_MEMORY;               //传输方向:这里选择外设---->内存
        hdma1_ADC1.Init.Mode = DMA_CIRCULAR;                            //计数器传输模式:自动重装
        hdma1_ADC1.Init.Priority = DMA_PRIORITY_MEDIUM;                 //通道1传输优先级:选择中等
        __HAL_LINKDMA(&hadc1,DMA_Handle,hdma1_ADC1);                    //ADC1和DMA1构建链接
        HAL_DMA_Init(&hdma1_ADC1);        
    }
    else if(hadc->Instance == ADC2)
    {
        
    }    
}

②ADC.h文件的代码如下

#ifndef __ADC_H
#define __ADC_H

#include "stm32f1xx_hal.h"
extern uint16_t ADC1_Buffer[4];
extern ADC_HandleTypeDef hadc1;                //ADC1配置结构体
extern DMA_HandleTypeDef hdma1_ADC1;           //ADC1的DMA1的通道配置结构体
void ADC_Init(void);

#endif

③Time.c文件的代码如下

#include "Time.h"

/**
 * 定时器TIM2的配置
 * psc: 时钟预分频数(1~65536)
 * arr: 自动重装值(1~65536)
 */
TIM_HandleTypeDef htim2_OC;                             //TIM2输出比较时基单元配置结构体
TIM_OC_InitTypeDef sConfig_OC;                          //比较通道配置结构体
void TIM2_Init(uint16_t psc, uint16_t arr)
{
    /* 2、配置TIM2的时基单元 */
    __HAL_RCC_TIM2_CLK_ENABLE();                            //使能TIM2时钟
    htim2_OC.Instance = TIM2;                               //选择定时器TIM2
    htim2_OC.Init.Prescaler = psc - 1;                      //预分频器
    htim2_OC.Init.CounterMode = TIM_COUNTERMODE_UP;         //向上计数
    htim2_OC.Init.Period = arr - 1;                         //自动重装载值
    htim2_OC.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;   //时钟分频因子,用于防干扰,与定时无关
    htim2_OC.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE; //禁止预加载
    HAL_TIM_OC_Init(&htim2_OC);
    __HAL_TIM_CLEAR_FLAG(&htim2_OC,TIM_FLAG_UPDATE);        //清除更新标志位
    
    /* 3、TIM2输出比较通道1的配置 */
    sConfig_OC.OCMode = TIM_OCMODE_PWM1;                    //输出比较模式:PWM1模式(小于比较值输出低电平)
    sConfig_OC.Pulse = 1000;                                //比较值:1000
    sConfig_OC.OCPolarity = TIM_OCPOLARITY_LOW;             //有效电平:低电平
    HAL_TIM_OC_ConfigChannel(&htim2_OC,&sConfig_OC,TIM_CHANNEL_1);
    
    /* 4、启动TIM2 */
    HAL_TIM_OC_Start(&htim2_OC,TIM_CHANNEL_1);              //启动TIM2的通道1
}

/**
 * @brief:HAL_TIM_OC_Init()调用函数
 */
void HAL_TIM_OC_MspInit(TIM_HandleTypeDef *htim)
{
    GPIO_InitTypeDef GPIO_Init;             //IO口配置结构体
    if (htim->Instance == TIM1)                   
    {     

    }else if(htim->Instance == TIM2)
    {
        /* TIM2的CC1的引脚为PA0 */
        __HAL_RCC_GPIOA_CLK_ENABLE();       //开启GPIOA时钟
        
        /* 配置PA0 */
        GPIO_Init.Mode = GPIO_MODE_AF_PP;   //模式:输出模式
        GPIO_Init.Pin = GPIO_PIN_0;         //选择PA0
        GPIO_Init.Speed = GPIO_SPEED_FREQ_MEDIUM;//最大输出速度:中等
        HAL_GPIO_Init(GPIOA, &GPIO_Init);
    }
    else if(htim->Instance == TIM3)
    {
        
    }
}

④Time.h文件的代码如下

#ifndef __Time_H
#define __Time_H

#include "stm32f1xx_hal.h"
extern TIM_HandleTypeDef htim2_OC;                         //TIM2输出比较的时基单元配置结构体
void TIM2_Init(uint16_t psc, uint16_t arr);

#endif

⑤main.c文件的代码如下

#include "stm32f1xx_hal.h"
#include "STM32_RCC_Init.h"
#include "ADC.h"
#include "Time.h"
#include "UART.h"
 
int main(void){
    
	HAL_Init();
	HSE_RCC_Init(); 
	UART1_Init(115200);
    TIM2_Init(7200,10000);//0.1ms计数一次,PWM周期为1s,即1s触发一次注入组
    ADC_Init();
	printf("启动判断!\r\n");
    
	while(1){
       
	}	
}

⑥stm32f1xx_it.c文件的代码如下

#include "stm32f1xx_hal.h"   
#include "stm32f1xx_it.h" 
#include "ADC.h" 
#include "UART.h"

/**
 * @brief:DMA通道1中断服务函数
 */
void DMA1_Channel1_IRQHandler(void)
{
    HAL_DMA_IRQHandler(&hdma1_ADC1);//DMA中断服务总函数
}

/**
 * @brief:ADC中断服务函数
 */
void ADC1_2_IRQHandler(void)
{
     HAL_ADC_IRQHandler(&hadc1);//ADC中断服务总函数
}
/******************* 下面的中断的回调函数 ***************************/
/**
 * @brief:规则组的DMA通道1传输完成的中断服务函数
 */
float ADC_Value = 0;
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)
{
    if(hadc->Instance == ADC1)
    {
        ADC_Value = ADC1_Buffer[0] * 3.3 / 4095;            //将二进制计数为电压电压值
        printf("通道0电压值 = %f\r\n",ADC_Value);            //输出电压值
        
        ADC_Value = ADC1_Buffer[1] * 3.3 / 4095;            //将二进制计数为电压电压值
        printf("通道1电压值 = %f\r\n",ADC_Value);           //输出电压值
        
        ADC_Value = ADC1_Buffer[2] * 3.3 / 4095;            //将二进制计数为电压电压值
        printf("通道2电压值 = %f\r\n",ADC_Value);            //输出电压值
        
        ADC_Value = ADC1_Buffer[3] * 3.3 / 4095;            //将二进制计数为电压电压值
        printf("通道3电压值 = %f\r\n",ADC_Value);           //输出电压值
    }else if(hadc->Instance == ADC2)
    {
    
    }
}

/**
 * @brief:ADC注入组中断服务函数
 */
void HAL_ADCEx_InjectedConvCpltCallback(ADC_HandleTypeDef* hadc)
{
    uint32_t Data = 0;
    if(hadc->Instance == ADC1)
    {
        Data = HAL_ADCEx_InjectedGetValue(hadc, ADC_INJECTED_RANK_1);   //获取注入组盒子序列1的数据寄存器的值
        ADC_Value = Data * 3.3 / 4095;                                  //将二进制计数为电压电压值
        printf("通道4电压值 = %f\r\n",ADC_Value);                        //输出电压值
        
        Data = HAL_ADCEx_InjectedGetValue(hadc, ADC_INJECTED_RANK_2);   //获取注入组盒子序列2的数据寄存器的值
        ADC_Value = Data * 3.3 / 4095;                                  //将二进制计数为电压电压值
        printf("通道5电压值 = %f\r\n",ADC_Value);                        //输出电压值
        
        Data = HAL_ADCEx_InjectedGetValue(hadc, ADC_INJECTED_RANK_3);   //获取注入组盒子序列3的数据寄存器的值
        ADC_Value = Data * 3.3 / 4095;                                  //将二进制计数为电压电压值
        printf("通道6电压值 = %f\r\n",ADC_Value);                        //输出电压值
        
        Data = HAL_ADCEx_InjectedGetValue(hadc, ADC_INJECTED_RANK_4);   //获取注入组盒子序列4的数据寄存器的值
        ADC_Value = Data * 3.3 / 4095;                                  //将二进制计数为电压电压值
        printf("通道7电压值 = %f\r\n",ADC_Value);                        //输出电压值
    }
}

4、规则组软件触发+注入组外部触发(EXTI15)+间断模式

【注意】
①注入组的间断队伍只有1个通道,已经规定好了。而规则组的间断队伍通道数由用户自己定义。
②不能同时使用自动注入+间断模式
③尽可能避免同时使用规则组的间断模式+注入组的间断模式
①ADC.c文件的代码如下

#include "ADC.h"

uint16_t ADC1_Buffer[4] = {0};             //数据缓冲区
/**
 * @brief:ADC1初始化函数
 */
RCC_PeriphCLKInitTypeDef PeriphClkInit; //ADC时钟配置结构体
ADC_HandleTypeDef hadc1;                //ADC1配置结构体
ADC_ChannelConfTypeDef sConfig1;        //规则组通道配置结构体
ADC_InjectionConfTypeDef sConfigInjected;//注入组通道配置结构体
void ADC_Init(void)
{
    /* 1、ADC的时钟配置 < 14MHz  */
    PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_ADC; //需要配置的外设:ADC
    PeriphClkInit.AdcClockSelection = RCC_ADCPCLK2_DIV6;    //设置ADC分频值:6分频 = 12MHz
    HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit);
        
    /* 2、ADC1的初始化 */
    __HAL_RCC_ADC1_CLK_ENABLE();                        //使能ADC1时钟
    hadc1.Instance = ADC1;                              //选择ADC1
    hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;         //数据对齐方式:右对齐
    hadc1.Init.ScanConvMode = ADC_SCAN_ENABLE;          //扫描模式:开启扫描(多个通道)
    hadc1.Init.ContinuousConvMode = ENABLE;             //转换模式:连续转换
    hadc1.Init.NbrOfConversion = 4;                     //扫描模式下规则组的数量
  //hadc1.Init.DiscontinuousConvMode = ENABLE;          //扫描模式规则组间断模式
  //hadc1.Init.NbrOfDiscConversion = 2;                 //规则组间断模式下每次间断的通道数:2队为1组
    hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;   //ADC触发:软件触发
    HAL_ADC_Init(&hadc1);
    
    /* 3、规则组通道配置 */
    sConfig1.Channel = ADC_CHANNEL_0;                    //通道选择:通道0
    sConfig1.Rank = ADC_REGULAR_RANK_1;                  //规则组盒子序号:1号
    sConfig1.SamplingTime = ADC_SAMPLETIME_41CYCLES_5;   //采样时间:41.5T
    HAL_ADC_ConfigChannel(&hadc1, &sConfig1);
    
    sConfig1.Channel = ADC_CHANNEL_1;                    //通道选择:通道1
    sConfig1.Rank = ADC_REGULAR_RANK_2;                  //规则组盒子序号:2号
    sConfig1.SamplingTime = ADC_SAMPLETIME_41CYCLES_5;   //采样时间:41.5T
    HAL_ADC_ConfigChannel(&hadc1, &sConfig1);
    
    sConfig1.Channel = ADC_CHANNEL_2;                    //通道选择:通道2
    sConfig1.Rank = ADC_REGULAR_RANK_3;                  //规则组盒子序号:3号
    sConfig1.SamplingTime = ADC_SAMPLETIME_41CYCLES_5;   //采样时间:41.5T
    HAL_ADC_ConfigChannel(&hadc1, &sConfig1);
    
    sConfig1.Channel = ADC_CHANNEL_3;                    //通道选择:通道3
    sConfig1.Rank = ADC_REGULAR_RANK_4;                  //规则组盒子序号:4号
    sConfig1.SamplingTime = ADC_SAMPLETIME_41CYCLES_5;   //采样时间:41.5T
    HAL_ADC_ConfigChannel(&hadc1, &sConfig1);
    
    /* 4、组入组通道配置 */
    sConfigInjected.InjectedChannel = ADC_CHANNEL_4;                    //通道选择:通道4
    sConfigInjected.InjectedRank = ADC_INJECTED_RANK_1;                 //注入组盒子序号:1号
    sConfigInjected.InjectedSamplingTime = ADC_SAMPLETIME_41CYCLES_5;   //采样时间:41.5T
    sConfigInjected.InjectedOffset = 0;                                 //偏移值:0
    sConfigInjected.InjectedNbrOfConversion = 4;                        //组入组通道数量:4个
    sConfigInjected.InjectedDiscontinuousConvMode = ENABLE;             //开启间断模式
    sConfigInjected.AutoInjectedConv = DISABLE;                         //自动注入:关闭
    sConfigInjected.ExternalTrigInjecConv = ADC_EXTERNALTRIGINJECCONV_EXT_IT15;//触发:EXTI15触发
    HAL_ADCEx_InjectedConfigChannel(&hadc1, &sConfigInjected);
    
    sConfigInjected.InjectedChannel = ADC_CHANNEL_5;                    //通道选择:通道5
    sConfigInjected.InjectedRank = ADC_INJECTED_RANK_2;                 //注入组盒子序号:2号
    sConfigInjected.InjectedSamplingTime = ADC_SAMPLETIME_41CYCLES_5;   //采样时间:41.5T
    sConfigInjected.InjectedOffset = 0;                                 //偏移值:0
    HAL_ADCEx_InjectedConfigChannel(&hadc1, &sConfigInjected);
    
    sConfigInjected.InjectedChannel = ADC_CHANNEL_6;                    //通道选择:通道6
    sConfigInjected.InjectedRank = ADC_INJECTED_RANK_3;                 //注入组盒子序号:3号
    sConfigInjected.InjectedSamplingTime = ADC_SAMPLETIME_41CYCLES_5;   //采样时间:41.5T
    sConfigInjected.InjectedOffset = 0;                                 //偏移值:0
    HAL_ADCEx_InjectedConfigChannel(&hadc1, &sConfigInjected);
    
    sConfigInjected.InjectedChannel = ADC_CHANNEL_7;                    //通道选择:通道7
    sConfigInjected.InjectedRank = ADC_INJECTED_RANK_4;                 //注入组盒子序号:4号
    sConfigInjected.InjectedSamplingTime = ADC_SAMPLETIME_41CYCLES_5;   //采样时间:41.5T
    sConfigInjected.InjectedOffset = 0;                                 //偏移值:0
    HAL_ADCEx_InjectedConfigChannel(&hadc1, &sConfigInjected);
    
    /* 5、ADC1校准 */
    HAL_ADCEx_Calibration_Start(&hadc1);                //ADC1自校准
    
    /* 6、开启ADC规则组转换 */
    HAL_ADC_Start_DMA(&hadc1,(uint32_t*)ADC1_Buffer,4); //开启转换:DMA方式,转换完成DMA执行搬运,
                                                        //开启了DMA中断,搬运4后执行DMA中断
    HAL_NVIC_SetPriority(DMA1_Channel1_IRQn,3,0);       //配置优先级
    HAL_NVIC_EnableIRQ(DMA1_Channel1_IRQn);             //使能中断源
    
    /* 7、开启ADC注入组转换 */
    HAL_ADCEx_InjectedStart_IT(&hadc1);                 //开启转换:设置通道全部转换完成中断
    HAL_NVIC_SetPriority(ADC1_2_IRQn,3,0);              //配置优先级
    HAL_NVIC_EnableIRQ(ADC1_2_IRQn);                    //使能中断源
}

/**
 * @brief:HAL_ADC_Init()调用函数
 */
DMA_HandleTypeDef hdma1_ADC1;               //ADC1的DMA1的通道配置结构体
void HAL_ADC_MspInit(ADC_HandleTypeDef* hadc)
{
    GPIO_InitTypeDef GPIO_Init;             //IO口配置的结构体
    if(hadc->Instance == ADC1)
    {
        /* 配置ADC1通道0:PA0,通道1:PA1,通道2:PA2,通道3:PA3 */
        __HAL_RCC_GPIOA_CLK_ENABLE();       //使能GPIOA时钟
        GPIO_Init.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3
                       |GPIO_PIN_4 | GPIO_PIN_5 | GPIO_PIN_6 | GPIO_PIN_7;
        GPIO_Init.Mode = GPIO_MODE_ANALOG;  //选择模拟输入模式
        HAL_GPIO_Init(GPIOA, &GPIO_Init);
        
        /* 1、初始化DMA1的通道1配置 */
        __HAL_RCC_DMA1_CLK_ENABLE();                                    //使能DMA1的时钟
        hdma1_ADC1.Instance = DMA1_Channel1;                            //选择DMA1的通道1
        hdma1_ADC1.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;  //外设站点数据宽度:16位
        hdma1_ADC1.Init.PeriphInc = DMA_PINC_DISABLE;                   //外设地址是否递增:选择不自增
        hdma1_ADC1.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;     //内存站点数据宽度:16位
        hdma1_ADC1.Init.MemInc = DMA_MINC_ENABLE;                       //内存地址是否递增:选择自增
        hdma1_ADC1.Init.Direction = DMA_PERIPH_TO_MEMORY;               //传输方向:这里选择外设---->内存
        hdma1_ADC1.Init.Mode = DMA_CIRCULAR;                            //计数器传输模式:自动重装
        hdma1_ADC1.Init.Priority = DMA_PRIORITY_MEDIUM;                 //通道1传输优先级:选择中等
        __HAL_LINKDMA(&hadc1,DMA_Handle,hdma1_ADC1);                    //ADC1和DMA1构建链接
        HAL_DMA_Init(&hdma1_ADC1);
        
        /* 2、配置EXTI15:注入组外部触发 */
        __HAL_RCC_GPIOB_CLK_ENABLE();           //使能GPIOB时钟
        __HAL_RCC_AFIO_CLK_ENABLE();            //使能AFIO时钟
        GPIO_Init.Pin = GPIO_PIN_15;            //选择PB15
        GPIO_Init.Mode = GPIO_MODE_IT_RISING;   //选择上升沿触发中断
        GPIO_Init.Pull = GPIO_PULLDOWN;         //选择下拉输入
        HAL_GPIO_Init(GPIOB, &GPIO_Init);
        
        /* 3、配置外部中断EXTI15的NVIC*/
        HAL_NVIC_SetPriority(EXTI15_10_IRQn,3,0);
        HAL_NVIC_EnableIRQ(EXTI15_10_IRQn);
        
    }
    else if(hadc->Instance == ADC2)
    {
        
    }    
}

②ADC.h文件的代码如下

#ifndef __ADC_H
#define __ADC_H

#include "stm32f1xx_hal.h"
extern uint16_t ADC1_Buffer[4];
extern ADC_HandleTypeDef hadc1;                //ADC1配置结构体
extern DMA_HandleTypeDef hdma1_ADC1;           //ADC1的DMA1的通道配置结构体
void ADC_Init(void);

#endif

③main.c文件的代码如下

#include "stm32f1xx_hal.h"
#include "STM32_RCC_Init.h"
#include "ADC.h"
#include "UART.h"
 
int main(void){
    
	HAL_Init();
	HSE_RCC_Init(); 
	UART1_Init(115200);
    ADC_Init();
	printf("启动判断!\r\n");
    
	while(1){
       
	}	
}

④stm32f1xx_it.c文件的代码如下

#include "stm32f1xx_hal.h"   
#include "stm32f1xx_it.h" 
#include "ADC.h" 
#include "UART.h"

/**
 * @brief:DMA通道1中断服务函数
 */
void DMA1_Channel1_IRQHandler(void)
{
    HAL_DMA_IRQHandler(&hdma1_ADC1);//DMA中断服务总函数
}

/**
 * @brief:ADC中断服务函数
 */
void ADC1_2_IRQHandler(void)
{
     HAL_ADC_IRQHandler(&hadc1);//ADC中断服务总函数
}
/******************* 下面的中断的回调函数 ***************************/
/**
 * @brief:规则组的DMA通道1传输完成的中断服务函数
 */
float ADC_Value = 0;
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)
{
    if(hadc->Instance == ADC1)
    {
        ADC_Value = ADC1_Buffer[0] * 3.3 / 4095;            //将二进制计数为电压电压值
        printf("通道0电压值 = %f\r\n",ADC_Value);            //输出电压值
        
        ADC_Value = ADC1_Buffer[1] * 3.3 / 4095;            //将二进制计数为电压电压值
        printf("通道1电压值 = %f\r\n",ADC_Value);           //输出电压值
        
        ADC_Value = ADC1_Buffer[2] * 3.3 / 4095;            //将二进制计数为电压电压值
        printf("通道2电压值 = %f\r\n",ADC_Value);            //输出电压值
        
        ADC_Value = ADC1_Buffer[3] * 3.3 / 4095;            //将二进制计数为电压电压值
        printf("通道3电压值 = %f\r\n",ADC_Value);           //输出电压值
    }else if(hadc->Instance == ADC2)
    {
    
    }
}

/**
 * @brief:ADC注入组中断服务函数
 */
void HAL_ADCEx_InjectedConvCpltCallback(ADC_HandleTypeDef* hadc)
{
    uint32_t Data = 0;
    if(hadc->Instance == ADC1)
    {
        Data = HAL_ADCEx_InjectedGetValue(hadc, ADC_INJECTED_RANK_1);   //获取注入组盒子序列1的数据寄存器的值
        ADC_Value = Data * 3.3 / 4095;                                  //将二进制计数为电压电压值
        printf("通道4电压值 = %f\r\n",ADC_Value);                        //输出电压值
        
        Data = HAL_ADCEx_InjectedGetValue(hadc, ADC_INJECTED_RANK_2);   //获取注入组盒子序列2的数据寄存器的值
        ADC_Value = Data * 3.3 / 4095;                                  //将二进制计数为电压电压值
        printf("通道5电压值 = %f\r\n",ADC_Value);                        //输出电压值
        
        Data = HAL_ADCEx_InjectedGetValue(hadc, ADC_INJECTED_RANK_3);   //获取注入组盒子序列3的数据寄存器的值
        ADC_Value = Data * 3.3 / 4095;                                  //将二进制计数为电压电压值
        printf("通道6电压值 = %f\r\n",ADC_Value);                        //输出电压值
        
        Data = HAL_ADCEx_InjectedGetValue(hadc, ADC_INJECTED_RANK_4);   //获取注入组盒子序列4的数据寄存器的值
        ADC_Value = Data * 3.3 / 4095;                                  //将二进制计数为电压电压值
        printf("通道7电压值 = %f\r\n",ADC_Value);                        //输出电压值
    }
}

5、模拟看门狗的使用

在这里插入图片描述
①ADC.c文件的代码如下

#include "ADC.h"

uint16_t ADC1_Buffer[4] = {0};             //数据缓冲区
/**
 * @brief:ADC1初始化函数
 */
RCC_PeriphCLKInitTypeDef PeriphClkInit;     //ADC时钟配置结构体
ADC_HandleTypeDef hadc1;                    //ADC1配置结构体
ADC_ChannelConfTypeDef sConfig1;            //规则组通道配置结构体
ADC_InjectionConfTypeDef sConfigInjected;   //注入组通道配置结构体
ADC_AnalogWDGConfTypeDef AnalogWDGConfig;   //模拟看门狗配置结构体
void ADC_Init(void)
{
    /* 1、ADC的时钟配置 < 14MHz  */
    PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_ADC; //需要配置的外设:ADC
    PeriphClkInit.AdcClockSelection = RCC_ADCPCLK2_DIV6;    //设置ADC分频值:6分频 = 12MHz
    HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit);
        
    /* 2、ADC1的初始化 */
    __HAL_RCC_ADC1_CLK_ENABLE();                        //使能ADC1时钟
    hadc1.Instance = ADC1;                              //选择ADC1
    hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;         //数据对齐方式:右对齐
    hadc1.Init.ScanConvMode = ADC_SCAN_ENABLE;          //扫描模式:开启扫描(多个通道)
    hadc1.Init.ContinuousConvMode = ENABLE;             //转换模式:连续转换
    hadc1.Init.NbrOfConversion = 4;                     //扫描模式下规则组的数量
  //hadc1.Init.DiscontinuousConvMode = ENABLE;          //扫描模式规则组间断模式
  //hadc1.Init.NbrOfDiscConversion = 2;                 //规则组间断模式下每次间断的通道数:2队为1组
    hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;   //ADC触发:软件触发
    HAL_ADC_Init(&hadc1);
    
    /* 3、规则组通道配置 */
    sConfig1.Channel = ADC_CHANNEL_0;                    //通道选择:通道0
    sConfig1.Rank = ADC_REGULAR_RANK_1;                  //规则组盒子序号:1号
    sConfig1.SamplingTime = ADC_SAMPLETIME_41CYCLES_5;   //采样时间:41.5T
    HAL_ADC_ConfigChannel(&hadc1, &sConfig1);
    
    sConfig1.Channel = ADC_CHANNEL_1;                    //通道选择:通道1
    sConfig1.Rank = ADC_REGULAR_RANK_2;                  //规则组盒子序号:2号
    sConfig1.SamplingTime = ADC_SAMPLETIME_41CYCLES_5;   //采样时间:41.5T
    HAL_ADC_ConfigChannel(&hadc1, &sConfig1);
    
    sConfig1.Channel = ADC_CHANNEL_2;                    //通道选择:通道2
    sConfig1.Rank = ADC_REGULAR_RANK_3;                  //规则组盒子序号:3号
    sConfig1.SamplingTime = ADC_SAMPLETIME_41CYCLES_5;   //采样时间:41.5T
    HAL_ADC_ConfigChannel(&hadc1, &sConfig1);
    
    sConfig1.Channel = ADC_CHANNEL_3;                    //通道选择:通道3
    sConfig1.Rank = ADC_REGULAR_RANK_4;                  //规则组盒子序号:4号
    sConfig1.SamplingTime = ADC_SAMPLETIME_41CYCLES_5;   //采样时间:41.5T
    HAL_ADC_ConfigChannel(&hadc1, &sConfig1);
    
    /* 4、组入组通道配置 */
    sConfigInjected.InjectedChannel = ADC_CHANNEL_4;                    //通道选择:通道4
    sConfigInjected.InjectedRank = ADC_INJECTED_RANK_1;                 //注入组盒子序号:1号
    sConfigInjected.InjectedSamplingTime = ADC_SAMPLETIME_41CYCLES_5;   //采样时间:41.5T
    sConfigInjected.InjectedOffset = 0;                                 //偏移值:0
    sConfigInjected.InjectedNbrOfConversion = 4;                        //组入组通道数量:4个
    sConfigInjected.InjectedDiscontinuousConvMode = DISABLE;            //关闭间断模式
    sConfigInjected.AutoInjectedConv = ENABLE;                          //自动注入:开启
    sConfigInjected.ExternalTrigInjecConv = ADC_INJECTED_SOFTWARE_START;//触发:软件触发
    HAL_ADCEx_InjectedConfigChannel(&hadc1, &sConfigInjected);
    
    sConfigInjected.InjectedChannel = ADC_CHANNEL_5;                    //通道选择:通道5
    sConfigInjected.InjectedRank = ADC_INJECTED_RANK_2;                 //注入组盒子序号:2号
    sConfigInjected.InjectedSamplingTime = ADC_SAMPLETIME_41CYCLES_5;   //采样时间:41.5T
    sConfigInjected.InjectedOffset = 0;                                 //偏移值:0
    HAL_ADCEx_InjectedConfigChannel(&hadc1, &sConfigInjected);
    
    sConfigInjected.InjectedChannel = ADC_CHANNEL_6;                    //通道选择:通道6
    sConfigInjected.InjectedRank = ADC_INJECTED_RANK_3;                 //注入组盒子序号:3号
    sConfigInjected.InjectedSamplingTime = ADC_SAMPLETIME_41CYCLES_5;   //采样时间:41.5T
    sConfigInjected.InjectedOffset = 0;                                 //偏移值:0
    HAL_ADCEx_InjectedConfigChannel(&hadc1, &sConfigInjected);
    
    sConfigInjected.InjectedChannel = ADC_CHANNEL_7;                    //通道选择:通道7
    sConfigInjected.InjectedRank = ADC_INJECTED_RANK_4;                 //注入组盒子序号:4号
    sConfigInjected.InjectedSamplingTime = ADC_SAMPLETIME_41CYCLES_5;   //采样时间:41.5T
    sConfigInjected.InjectedOffset = 0;                                 //偏移值:0
    HAL_ADCEx_InjectedConfigChannel(&hadc1, &sConfigInjected);
    
    /* 5、模拟看门狗的配置 */
    AnalogWDGConfig.WatchdogMode = ADC_ANALOGWATCHDOG_SINGLE_REG;       //模拟看门狗模式:选择规则组的某个通道
    AnalogWDGConfig.Channel = ADC_CHANNEL_0;                            //单通道:选择通道0。
    AnalogWDGConfig.ITMode = ENABLE;                                    //开启模拟看门狗中断
    AnalogWDGConfig.HighThreshold = 0xAFF;                              //寄存器的上限值 
    AnalogWDGConfig.LowThreshold = 0X3FF;                               //寄存器的下限值
    HAL_ADC_AnalogWDGConfig(&hadc1, &AnalogWDGConfig);
    
    /* 5、ADC1校准 */
    HAL_ADCEx_Calibration_Start(&hadc1);                //ADC1自校准
    
    /* 6、开启ADC规则组转换 */
    HAL_ADC_Start_DMA(&hadc1,(uint32_t*)ADC1_Buffer,4); //开启转换:DMA方式,转换完成DMA执行搬运,
                                                        //开启了DMA中断,搬运4后执行DMA中断
    HAL_NVIC_SetPriority(DMA1_Channel1_IRQn,3,0);       //配置优先级
    HAL_NVIC_EnableIRQ(DMA1_Channel1_IRQn);             //使能中断源
    
    /* 7、开启ADC注入组转换 */
    HAL_ADCEx_InjectedStart_IT(&hadc1);                 //开启转换:设置通道全部转换完成中断
    HAL_NVIC_SetPriority(ADC1_2_IRQn,3,0);              //配置优先级
    HAL_NVIC_EnableIRQ(ADC1_2_IRQn);                    //使能中断源
}

/**
 * @brief:HAL_ADC_Init()调用函数
 */
DMA_HandleTypeDef hdma1_ADC1;               //ADC1的DMA1的通道配置结构体
void HAL_ADC_MspInit(ADC_HandleTypeDef* hadc)
{
    GPIO_InitTypeDef GPIO_Init;             //IO口配置的结构体
    if(hadc->Instance == ADC1)
    {
        /* 配置ADC1通道0:PA0,通道1:PA1,通道2:PA2,通道3:PA3 */
        __HAL_RCC_GPIOA_CLK_ENABLE();       //使能GPIOA时钟
        GPIO_Init.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3
                       |GPIO_PIN_4 | GPIO_PIN_5 | GPIO_PIN_6 | GPIO_PIN_7;
        GPIO_Init.Mode = GPIO_MODE_ANALOG;  //选择模拟输入模式
        HAL_GPIO_Init(GPIOA, &GPIO_Init);
        
        /* 1、初始化DMA1的通道1配置 */
        __HAL_RCC_DMA1_CLK_ENABLE();                                    //使能DMA1的时钟
        hdma1_ADC1.Instance = DMA1_Channel1;                            //选择DMA1的通道1
        hdma1_ADC1.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;  //外设站点数据宽度:16位
        hdma1_ADC1.Init.PeriphInc = DMA_PINC_DISABLE;                   //外设地址是否递增:选择不自增
        hdma1_ADC1.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;     //内存站点数据宽度:16位
        hdma1_ADC1.Init.MemInc = DMA_MINC_ENABLE;                       //内存地址是否递增:选择自增
        hdma1_ADC1.Init.Direction = DMA_PERIPH_TO_MEMORY;               //传输方向:这里选择外设---->内存
        hdma1_ADC1.Init.Mode = DMA_CIRCULAR;                            //计数器传输模式:自动重装
        hdma1_ADC1.Init.Priority = DMA_PRIORITY_MEDIUM;                 //通道1传输优先级:选择中等
        __HAL_LINKDMA(&hadc1,DMA_Handle,hdma1_ADC1);                    //ADC1和DMA1构建链接
        HAL_DMA_Init(&hdma1_ADC1);
        
    }
    else if(hadc->Instance == ADC2)
    {
        
    }    
}

②ADC.h文件的代码如下

#ifndef __ADC_H
#define __ADC_H

#include "stm32f1xx_hal.h"
extern uint16_t ADC1_Buffer[4];
extern ADC_HandleTypeDef hadc1;                //ADC1配置结构体
extern DMA_HandleTypeDef hdma1_ADC1;           //ADC1的DMA1的通道配置结构体
void ADC_Init(void);

#endif

③main.c文件的代码如下

#include "stm32f1xx_hal.h"
#include "STM32_RCC_Init.h"
#include "ADC.h"
#include "UART.h"
 
int main(void){
    
	HAL_Init();
	HSE_RCC_Init(); 
	UART1_Init(115200);
    ADC_Init();
	printf("启动判断!\r\n");
    
	while(1){
       
	}	
}

④stm32f1xx_it.c文件的代码如下

#include "stm32f1xx_hal.h"   
#include "stm32f1xx_it.h" 
#include "ADC.h" 
#include "UART.h"
/**
 * @brief:DMA通道1中断服务函数
 */
void DMA1_Channel1_IRQHandler(void)
{
    HAL_DMA_IRQHandler(&hdma1_ADC1);//DMA中断服务总函数
}

/**
 * @brief:ADC中断服务函数
 */
void ADC1_2_IRQHandler(void)
{
     HAL_ADC_IRQHandler(&hadc1);//ADC中断服务总函数
}
/******************* 下面的中断的回调函数 ***************************/
/**
 * @brief:规则组的DMA通道1传输完成的中断服务函数
 */
float ADC_Value = 0;
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)
{
    if(hadc->Instance == ADC1)
    {
        ADC_Value = ADC1_Buffer[0] * 3.3 / 4095;            //将二进制计数为电压电压值
        printf("通道0电压值 = %f\r\n",ADC_Value);            //输出电压值
        
        ADC_Value = ADC1_Buffer[1] * 3.3 / 4095;            //将二进制计数为电压电压值
        printf("通道1电压值 = %f\r\n",ADC_Value);           //输出电压值
        
        ADC_Value = ADC1_Buffer[2] * 3.3 / 4095;            //将二进制计数为电压电压值
        printf("通道2电压值 = %f\r\n",ADC_Value);            //输出电压值
        
        ADC_Value = ADC1_Buffer[3] * 3.3 / 4095;            //将二进制计数为电压电压值
        printf("通道3电压值 = %f\r\n",ADC_Value);           //输出电压值
    }else if(hadc->Instance == ADC2)
    {
    
    }
}

/**
 * @brief:ADC注入组中断服务函数
 */
void HAL_ADCEx_InjectedConvCpltCallback(ADC_HandleTypeDef* hadc)
{
    uint32_t Data = 0;
    if(hadc->Instance == ADC1)
    {
        Data = HAL_ADCEx_InjectedGetValue(hadc, ADC_INJECTED_RANK_1);   //获取注入组盒子序列1的数据寄存器的值
        ADC_Value = Data * 3.3 / 4095;                                  //将二进制计数为电压电压值
        printf("通道4电压值 = %f\r\n",ADC_Value);                        //输出电压值
        
        Data = HAL_ADCEx_InjectedGetValue(hadc, ADC_INJECTED_RANK_2);   //获取注入组盒子序列2的数据寄存器的值
        ADC_Value = Data * 3.3 / 4095;                                  //将二进制计数为电压电压值
        printf("通道5电压值 = %f\r\n",ADC_Value);                        //输出电压值
        
        Data = HAL_ADCEx_InjectedGetValue(hadc, ADC_INJECTED_RANK_3);   //获取注入组盒子序列3的数据寄存器的值
        ADC_Value = Data * 3.3 / 4095;                                  //将二进制计数为电压电压值
        printf("通道6电压值 = %f\r\n",ADC_Value);                        //输出电压值
        
        Data = HAL_ADCEx_InjectedGetValue(hadc, ADC_INJECTED_RANK_4);   //获取注入组盒子序列4的数据寄存器的值
        ADC_Value = Data * 3.3 / 4095;                                  //将二进制计数为电压电压值
        printf("通道7电压值 = %f\r\n",ADC_Value);                        //输出电压值
        __HAL_ADC_ENABLE_IT(hadc, ADC_IT_JEOC);
    }
}

/**
 * @brief:模拟看门狗的中断服务函数
 */
void HAL_ADC_LevelOutOfWindowCallback(ADC_HandleTypeDef* hadc)
{
    if(hadc->Instance == ADC1)
    {
       if(ADC1_Buffer[0] > 0xAFF)
       {
           printf("高于上限值了\r\n");
       }else if(ADC1_Buffer[0] < 0x3FF)
       {
           printf("低于下限值了\r\n");
       }
    }
}

http://www.kler.cn/a/456823.html

相关文章:

  • YK人工智能(三)——万字长文学会torch深度学习
  • uniapp——App下载文件,打开文档(一)
  • Linux-----进程处理(子进程创建)
  • STM32 高级 WIFi案例1:测试AT指令
  • 在基于Centos7的服务器上启用【Gateway】的【Clion Nova】(即 ReSharper C++ 引擎)
  • shell学习变量(二)
  • 科技创新 数智未来|清科·沙丘投研院走进竹云
  • 【zookeeper核心源码解析】第四课:客户端与服务端读写的io核心流程
  • 在STM32F103xx performance line block diagram找不到某一个外设所挂载在那条总线怎么办?
  • Docker 安装全攻略:从入门到上手
  • 快云服务器小助手getdetail存在任意文件文件读取漏洞
  • 普通部署redis伪集群模式
  • 阿里云-将旧服务器数据与配置完全迁移至新服务器
  • 25 - GRACE Mascon数据缺失月份数据插值
  • flask-admin 在modelview 视图中重写on_model_change 与after_model_change
  • Python定义类的属性
  • RTLinux和RTOS基本知识
  • 【Rust自学】7.3. use关键字 Pt.1:use的使用与as关键字
  • Kafka优势
  • yolov6算法及其改进
  • 【ETCD】【实操篇(十四)】etcd 集群备份与还原指南
  • Pandas07
  • 使用 VSCode 学习与实践 LaTeX:从插件安装到排版技巧
  • 基于三种机器学习方法的磁芯损耗预测模型
  • 使用内网穿透工具,为树莓派配置公网地址实现远程ssh
  • springboot maven 构建 建议使用 --release 21 而不是 -source 21 -target 21,因为它会自动设置系统模块的位置