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");
}
}
}