有关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; //需要配置的外设:ADCPeriphClkInit.AdcClockSelection = RCC_ADCPCLK2_DIV6; //设置ADC分频值:6分频 = 12MHzHAL_RCCEx_PeriphCLKConfig(&PeriphClkInit);/* 2、ADC1的初始化 */__HAL_RCC_ADC1_CLK_ENABLE(); //使能ADC1时钟hadc1.Instance = ADC1; //选择ADC1hadc1.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; //通道选择:通道0sConfig1.Rank = ADC_REGULAR_RANK_1; //规则组盒子序号:1号sConfig1.SamplingTime = ADC_SAMPLETIME_41CYCLES_5; //采样时间:41.5THAL_ADC_ConfigChannel(&hadc1, &sConfig1);sConfig1.Channel = ADC_CHANNEL_1; //通道选择:通道1sConfig1.Rank = ADC_REGULAR_RANK_2; //规则组盒子序号:2号sConfig1.SamplingTime = ADC_SAMPLETIME_41CYCLES_5; //采样时间:41.5THAL_ADC_ConfigChannel(&hadc1, &sConfig1);sConfig1.Channel = ADC_CHANNEL_2; //通道选择:通道2sConfig1.Rank = ADC_REGULAR_RANK_3; //规则组盒子序号:3号sConfig1.SamplingTime = ADC_SAMPLETIME_41CYCLES_5; //采样时间:41.5THAL_ADC_ConfigChannel(&hadc1, &sConfig1);sConfig1.Channel = ADC_CHANNEL_3; //通道选择:通道3sConfig1.Rank = ADC_REGULAR_RANK_4; //规则组盒子序号:4号sConfig1.SamplingTime = ADC_SAMPLETIME_41CYCLES_5; //采样时间:41.5THAL_ADC_ConfigChannel(&hadc1, &sConfig1);/* 4、组入组通道配置 */sConfigInjected.InjectedChannel = ADC_CHANNEL_4; //通道选择:通道4sConfigInjected.InjectedRank = ADC_INJECTED_RANK_1; //注入组盒子序号:1号sConfigInjected.InjectedSamplingTime = ADC_SAMPLETIME_41CYCLES_5; //采样时间:41.5TsConfigInjected.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; //通道选择:通道5sConfigInjected.InjectedRank = ADC_INJECTED_RANK_2; //注入组盒子序号:2号sConfigInjected.InjectedSamplingTime = ADC_SAMPLETIME_41CYCLES_5; //采样时间:41.5TsConfigInjected.InjectedOffset = 0; //偏移值:0HAL_ADCEx_InjectedConfigChannel(&hadc1, &sConfigInjected);sConfigInjected.InjectedChannel = ADC_CHANNEL_6; //通道选择:通道6sConfigInjected.InjectedRank = ADC_INJECTED_RANK_3; //注入组盒子序号:3号sConfigInjected.InjectedSamplingTime = ADC_SAMPLETIME_41CYCLES_5; //采样时间:41.5TsConfigInjected.InjectedOffset = 0; //偏移值:0HAL_ADCEx_InjectedConfigChannel(&hadc1, &sConfigInjected);sConfigInjected.InjectedChannel = ADC_CHANNEL_7; //通道选择:通道7sConfigInjected.InjectedRank = ADC_INJECTED_RANK_4; //注入组盒子序号:4号sConfigInjected.InjectedSamplingTime = ADC_SAMPLETIME_41CYCLES_5; //采样时间:41.5TsConfigInjected.InjectedOffset = 0; //偏移值:0HAL_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的通道1hdma1_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; //需要配置的外设:ADCPeriphClkInit.AdcClockSelection = RCC_ADCPCLK2_DIV6; //设置ADC分频值:6分频 = 12MHzHAL_RCCEx_PeriphCLKConfig(&PeriphClkInit);/* 2、ADC1的初始化 */__HAL_RCC_ADC1_CLK_ENABLE(); //使能ADC1时钟hadc1.Instance = ADC1; //选择ADC1hadc1.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; //通道选择:通道0sConfig1.Rank = ADC_REGULAR_RANK_1; //规则组盒子序号:1号sConfig1.SamplingTime = ADC_SAMPLETIME_41CYCLES_5; //采样时间:41.5THAL_ADC_ConfigChannel(&hadc1, &sConfig1);sConfig1.Channel = ADC_CHANNEL_1; //通道选择:通道1sConfig1.Rank = ADC_REGULAR_RANK_2; //规则组盒子序号:2号sConfig1.SamplingTime = ADC_SAMPLETIME_41CYCLES_5; //采样时间:41.5THAL_ADC_ConfigChannel(&hadc1, &sConfig1);sConfig1.Channel = ADC_CHANNEL_2; //通道选择:通道2sConfig1.Rank = ADC_REGULAR_RANK_3; //规则组盒子序号:3号sConfig1.SamplingTime = ADC_SAMPLETIME_41CYCLES_5; //采样时间:41.5THAL_ADC_ConfigChannel(&hadc1, &sConfig1);sConfig1.Channel = ADC_CHANNEL_3; //通道选择:通道3sConfig1.Rank = ADC_REGULAR_RANK_4; //规则组盒子序号:4号sConfig1.SamplingTime = ADC_SAMPLETIME_41CYCLES_5; //采样时间:41.5THAL_ADC_ConfigChannel(&hadc1, &sConfig1);/* 4、组入组通道配置 */sConfigInjected.InjectedChannel = ADC_CHANNEL_4; //通道选择:通道4sConfigInjected.InjectedRank = ADC_INJECTED_RANK_1; //注入组盒子序号:1号sConfigInjected.InjectedSamplingTime = ADC_SAMPLETIME_41CYCLES_5; //采样时间:41.5TsConfigInjected.InjectedOffset = 0; //偏移值:0sConfigInjected.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; //通道选择:通道5sConfigInjected.InjectedRank = ADC_INJECTED_RANK_2; //注入组盒子序号:2号sConfigInjected.InjectedSamplingTime = ADC_SAMPLETIME_41CYCLES_5; //采样时间:41.5TsConfigInjected.InjectedOffset = 0; //偏移值:0HAL_ADCEx_InjectedConfigChannel(&hadc1, &sConfigInjected);sConfigInjected.InjectedChannel = ADC_CHANNEL_6; //通道选择:通道6sConfigInjected.InjectedRank = ADC_INJECTED_RANK_3; //注入组盒子序号:3号sConfigInjected.InjectedSamplingTime = ADC_SAMPLETIME_41CYCLES_5; //采样时间:41.5TsConfigInjected.InjectedOffset = 0; //偏移值:0HAL_ADCEx_InjectedConfigChannel(&hadc1, &sConfigInjected);sConfigInjected.InjectedChannel = ADC_CHANNEL_7; //通道选择:通道7sConfigInjected.InjectedRank = ADC_INJECTED_RANK_4; //注入组盒子序号:4号sConfigInjected.InjectedSamplingTime = ADC_SAMPLETIME_41CYCLES_5; //采样时间:41.5TsConfigInjected.InjectedOffset = 0; //偏移值:0HAL_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的通道1hdma1_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; //选择PA11GPIO_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; //需要配置的外设:ADCPeriphClkInit.AdcClockSelection = RCC_ADCPCLK2_DIV6; //设置ADC分频值:6分频 = 12MHzHAL_RCCEx_PeriphCLKConfig(&PeriphClkInit);/* 2、ADC1的初始化 */__HAL_RCC_ADC1_CLK_ENABLE(); //使能ADC1时钟hadc1.Instance = ADC1; //选择ADC1hadc1.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; //通道选择:通道0sConfig1.Rank = ADC_REGULAR_RANK_1; //规则组盒子序号:1号sConfig1.SamplingTime = ADC_SAMPLETIME_41CYCLES_5; //采样时间:41.5THAL_ADC_ConfigChannel(&hadc1, &sConfig1);sConfig1.Channel = ADC_CHANNEL_1; //通道选择:通道1sConfig1.Rank = ADC_REGULAR_RANK_2; //规则组盒子序号:2号sConfig1.SamplingTime = ADC_SAMPLETIME_41CYCLES_5; //采样时间:41.5THAL_ADC_ConfigChannel(&hadc1, &sConfig1);sConfig1.Channel = ADC_CHANNEL_2; //通道选择:通道2sConfig1.Rank = ADC_REGULAR_RANK_3; //规则组盒子序号:3号sConfig1.SamplingTime = ADC_SAMPLETIME_41CYCLES_5; //采样时间:41.5THAL_ADC_ConfigChannel(&hadc1, &sConfig1);sConfig1.Channel = ADC_CHANNEL_3; //通道选择:通道3sConfig1.Rank = ADC_REGULAR_RANK_4; //规则组盒子序号:4号sConfig1.SamplingTime = ADC_SAMPLETIME_41CYCLES_5; //采样时间:41.5THAL_ADC_ConfigChannel(&hadc1, &sConfig1);/* 4、组入组通道配置 */sConfigInjected.InjectedChannel = ADC_CHANNEL_4; //通道选择:通道4sConfigInjected.InjectedRank = ADC_INJECTED_RANK_1; //注入组盒子序号:1号sConfigInjected.InjectedSamplingTime = ADC_SAMPLETIME_41CYCLES_5; //采样时间:41.5TsConfigInjected.InjectedOffset = 0; //偏移值:0sConfigInjected.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; //通道选择:通道5sConfigInjected.InjectedRank = ADC_INJECTED_RANK_2; //注入组盒子序号:2号sConfigInjected.InjectedSamplingTime = ADC_SAMPLETIME_41CYCLES_5; //采样时间:41.5TsConfigInjected.InjectedOffset = 0; //偏移值:0HAL_ADCEx_InjectedConfigChannel(&hadc1, &sConfigInjected);sConfigInjected.InjectedChannel = ADC_CHANNEL_6; //通道选择:通道6sConfigInjected.InjectedRank = ADC_INJECTED_RANK_3; //注入组盒子序号:3号sConfigInjected.InjectedSamplingTime = ADC_SAMPLETIME_41CYCLES_5; //采样时间:41.5TsConfigInjected.InjectedOffset = 0; //偏移值:0HAL_ADCEx_InjectedConfigChannel(&hadc1, &sConfigInjected);sConfigInjected.InjectedChannel = ADC_CHANNEL_7; //通道选择:通道7sConfigInjected.InjectedRank = ADC_INJECTED_RANK_4; //注入组盒子序号:4号sConfigInjected.InjectedSamplingTime = ADC_SAMPLETIME_41CYCLES_5; //采样时间:41.5TsConfigInjected.InjectedOffset = 0; //偏移值:0HAL_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的通道1hdma1_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; //选择定时器TIM2htim2_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; //比较值:1000sConfig_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; //选择PA0GPIO_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; //需要配置的外设:ADCPeriphClkInit.AdcClockSelection = RCC_ADCPCLK2_DIV6; //设置ADC分频值:6分频 = 12MHzHAL_RCCEx_PeriphCLKConfig(&PeriphClkInit);/* 2、ADC1的初始化 */__HAL_RCC_ADC1_CLK_ENABLE(); //使能ADC1时钟hadc1.Instance = ADC1; //选择ADC1hadc1.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; //通道选择:通道0sConfig1.Rank = ADC_REGULAR_RANK_1; //规则组盒子序号:1号sConfig1.SamplingTime = ADC_SAMPLETIME_41CYCLES_5; //采样时间:41.5THAL_ADC_ConfigChannel(&hadc1, &sConfig1);sConfig1.Channel = ADC_CHANNEL_1; //通道选择:通道1sConfig1.Rank = ADC_REGULAR_RANK_2; //规则组盒子序号:2号sConfig1.SamplingTime = ADC_SAMPLETIME_41CYCLES_5; //采样时间:41.5THAL_ADC_ConfigChannel(&hadc1, &sConfig1);sConfig1.Channel = ADC_CHANNEL_2; //通道选择:通道2sConfig1.Rank = ADC_REGULAR_RANK_3; //规则组盒子序号:3号sConfig1.SamplingTime = ADC_SAMPLETIME_41CYCLES_5; //采样时间:41.5THAL_ADC_ConfigChannel(&hadc1, &sConfig1);sConfig1.Channel = ADC_CHANNEL_3; //通道选择:通道3sConfig1.Rank = ADC_REGULAR_RANK_4; //规则组盒子序号:4号sConfig1.SamplingTime = ADC_SAMPLETIME_41CYCLES_5; //采样时间:41.5THAL_ADC_ConfigChannel(&hadc1, &sConfig1);/* 4、组入组通道配置 */sConfigInjected.InjectedChannel = ADC_CHANNEL_4; //通道选择:通道4sConfigInjected.InjectedRank = ADC_INJECTED_RANK_1; //注入组盒子序号:1号sConfigInjected.InjectedSamplingTime = ADC_SAMPLETIME_41CYCLES_5; //采样时间:41.5TsConfigInjected.InjectedOffset = 0; //偏移值:0sConfigInjected.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; //通道选择:通道5sConfigInjected.InjectedRank = ADC_INJECTED_RANK_2; //注入组盒子序号:2号sConfigInjected.InjectedSamplingTime = ADC_SAMPLETIME_41CYCLES_5; //采样时间:41.5TsConfigInjected.InjectedOffset = 0; //偏移值:0HAL_ADCEx_InjectedConfigChannel(&hadc1, &sConfigInjected);sConfigInjected.InjectedChannel = ADC_CHANNEL_6; //通道选择:通道6sConfigInjected.InjectedRank = ADC_INJECTED_RANK_3; //注入组盒子序号:3号sConfigInjected.InjectedSamplingTime = ADC_SAMPLETIME_41CYCLES_5; //采样时间:41.5TsConfigInjected.InjectedOffset = 0; //偏移值:0HAL_ADCEx_InjectedConfigChannel(&hadc1, &sConfigInjected);sConfigInjected.InjectedChannel = ADC_CHANNEL_7; //通道选择:通道7sConfigInjected.InjectedRank = ADC_INJECTED_RANK_4; //注入组盒子序号:4号sConfigInjected.InjectedSamplingTime = ADC_SAMPLETIME_41CYCLES_5; //采样时间:41.5TsConfigInjected.InjectedOffset = 0; //偏移值:0HAL_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的通道1hdma1_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; //选择PB15GPIO_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; //需要配置的外设:ADCPeriphClkInit.AdcClockSelection = RCC_ADCPCLK2_DIV6; //设置ADC分频值:6分频 = 12MHzHAL_RCCEx_PeriphCLKConfig(&PeriphClkInit);/* 2、ADC1的初始化 */__HAL_RCC_ADC1_CLK_ENABLE(); //使能ADC1时钟hadc1.Instance = ADC1; //选择ADC1hadc1.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; //通道选择:通道0sConfig1.Rank = ADC_REGULAR_RANK_1; //规则组盒子序号:1号sConfig1.SamplingTime = ADC_SAMPLETIME_41CYCLES_5; //采样时间:41.5THAL_ADC_ConfigChannel(&hadc1, &sConfig1);sConfig1.Channel = ADC_CHANNEL_1; //通道选择:通道1sConfig1.Rank = ADC_REGULAR_RANK_2; //规则组盒子序号:2号sConfig1.SamplingTime = ADC_SAMPLETIME_41CYCLES_5; //采样时间:41.5THAL_ADC_ConfigChannel(&hadc1, &sConfig1);sConfig1.Channel = ADC_CHANNEL_2; //通道选择:通道2sConfig1.Rank = ADC_REGULAR_RANK_3; //规则组盒子序号:3号sConfig1.SamplingTime = ADC_SAMPLETIME_41CYCLES_5; //采样时间:41.5THAL_ADC_ConfigChannel(&hadc1, &sConfig1);sConfig1.Channel = ADC_CHANNEL_3; //通道选择:通道3sConfig1.Rank = ADC_REGULAR_RANK_4; //规则组盒子序号:4号sConfig1.SamplingTime = ADC_SAMPLETIME_41CYCLES_5; //采样时间:41.5THAL_ADC_ConfigChannel(&hadc1, &sConfig1);/* 4、组入组通道配置 */sConfigInjected.InjectedChannel = ADC_CHANNEL_4; //通道选择:通道4sConfigInjected.InjectedRank = ADC_INJECTED_RANK_1; //注入组盒子序号:1号sConfigInjected.InjectedSamplingTime = ADC_SAMPLETIME_41CYCLES_5; //采样时间:41.5TsConfigInjected.InjectedOffset = 0; //偏移值:0sConfigInjected.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; //通道选择:通道5sConfigInjected.InjectedRank = ADC_INJECTED_RANK_2; //注入组盒子序号:2号sConfigInjected.InjectedSamplingTime = ADC_SAMPLETIME_41CYCLES_5; //采样时间:41.5TsConfigInjected.InjectedOffset = 0; //偏移值:0HAL_ADCEx_InjectedConfigChannel(&hadc1, &sConfigInjected);sConfigInjected.InjectedChannel = ADC_CHANNEL_6; //通道选择:通道6sConfigInjected.InjectedRank = ADC_INJECTED_RANK_3; //注入组盒子序号:3号sConfigInjected.InjectedSamplingTime = ADC_SAMPLETIME_41CYCLES_5; //采样时间:41.5TsConfigInjected.InjectedOffset = 0; //偏移值:0HAL_ADCEx_InjectedConfigChannel(&hadc1, &sConfigInjected);sConfigInjected.InjectedChannel = ADC_CHANNEL_7; //通道选择:通道7sConfigInjected.InjectedRank = ADC_INJECTED_RANK_4; //注入组盒子序号:4号sConfigInjected.InjectedSamplingTime = ADC_SAMPLETIME_41CYCLES_5; //采样时间:41.5TsConfigInjected.InjectedOffset = 0; //偏移值:0HAL_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的通道1hdma1_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");}}
}