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

ADC(二):外部触发

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

ADC(二):外部触发

  • 1、TIM1的CC1事件触发ADC1+DMA重装载
  • 2、TIM3的TRGO事件(的更新事件)触发ADC1+DMA重装载
  • 3、TIM3的TRGO事件(的捕获事件)触发ADC1+DMA重装载
  • 4、优化TIM3的TRGO事件(的捕获事件)触发ADC1+DMA重装载
  • 5、外部中断EXTI11触发ADC1+DMA重装载
  • 6、外部中断EXTI11触发ADC1+DMA重装载+间断模式

在这里插入图片描述【注意】触发ADC的CC事件只包括OC(输出比较),不包括IC(输入捕获),需要输入捕获触发ADC,则使用TRGO事件。
【注意】使用外部触发时,一般关闭ADC的连续转换模式,使用单次转换

1、TIM1的CC1事件触发ADC1+DMA重装载

将TIM1的CC1事件配置为PWM模式1,且PWM周期为1s。则ADC1每1s触发一次。ADC1触发10次后,计数平均值,输出打印电压值。
①ADC.c文件的代码如下

#include "ADC.h"uint16_t ADC1_Buffer[10] = {0};             //数据缓冲区
/*** @brief:ADC1初始化函数*/
RCC_PeriphCLKInitTypeDef PeriphClkInit; //ADC时钟配置结构体
ADC_HandleTypeDef hadc1;                //ADC1配置结构体
ADC_ChannelConfTypeDef sConfig1;         //规则组通道配置结构体
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();/* 3、ADC1的初始化 */hadc1.Instance = ADC1;                              //选择ADC1hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;         //数据对齐方式:右对齐hadc1.Init.ScanConvMode = ADC_SCAN_DISABLE;         //扫描模式:关闭扫描(仅一个通道)hadc1.Init.ContinuousConvMode = DISABLE;            //转换模式:单次转换//hadc1.Init.NbrOfConversion =                        //扫描模式下规则组的数量//hadc1.Init.DiscontinuousConvMode =                  //扫描模式规则组间断模式//hadc1.Init.NbrOfDiscConversion =                    //规则组间断模式下每次间断的通道数hadc1.Init.ExternalTrigConv = ADC_EXTERNALTRIGCONV_T1_CC1;   //ADC触发:TIM1的CC1事件触发HAL_ADC_Init(&hadc1);/* 4、规则组通道配置 */sConfig1.Channel = ADC_CHANNEL_0;                    //通道选择:通道0sConfig1.Rank = ADC_REGULAR_RANK_1;                  //规则组盒子序号:1号sConfig1.SamplingTime = ADC_SAMPLETIME_41CYCLES_5;   //采样时间:41.5THAL_ADC_ConfigChannel(&hadc1, &sConfig1);/* 5、ADC1校准 */HAL_ADCEx_Calibration_Start(&hadc1);                //ADC1自校准/* 6、开启ADC规则组转换 */HAL_ADC_Start_DMA(&hadc1,(uint32_t*)ADC1_Buffer,10);//开启转换:DMA方式,转换完成DMA执行搬运,//开启了DMA中断,搬运10后执行DMA中断HAL_NVIC_SetPriority(DMA1_Channel1_IRQn,3,0);       //配置优先级HAL_NVIC_EnableIRQ(DMA1_Channel1_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 */__HAL_RCC_GPIOA_CLK_ENABLE();       //使能GPIOA时钟GPIO_Init.Pin = GPIO_PIN_0;         //选择PA0GPIO_Init.Mode = GPIO_MODE_ANALOG;  //选择模拟输入模式HAL_GPIO_Init(GPIOA, &GPIO_Init);/* 1、使能DMA1的时钟 */__HAL_RCC_DMA1_CLK_ENABLE();                                    //使能DMA1的时钟/* 2、初始化DMA1的通道1配置 */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[10];
extern ADC_HandleTypeDef hadc1;                //ADC1配置结构体
extern DMA_HandleTypeDef hdma1_ADC1;           //ADC1的DMA1的通道配置结构体
void ADC_Init(void);#endif

③Time.c文件的代码如下

#include "Time.h"/*** 定时器TIM1的配置* psc: 时钟预分频数(1~65536)* arr: 自动重装值(1~65536)* rep: 重复次数(0为不重复,1为重复一次,用于高级定时器)*/
TIM_HandleTypeDef htim1_OC1;                                //TIM1输出比较的时基单元配置结构体
TIM_OC_InitTypeDef sConfig;                                 //TIM1输出比较的通道配置结构体
void TIM1_Init(uint16_t psc, uint16_t arr, uint8_t rep)
{/* 1、使能TIM1的时钟 */__HAL_RCC_TIM1_CLK_ENABLE();/* 2、配置TIM1的时基单元 */htim1_OC1.Instance = TIM1;                              //选择定时器TIM1htim1_OC1.Init.Prescaler = psc - 1;                     //预分频器htim1_OC1.Init.CounterMode = TIM_COUNTERMODE_UP;        //向上计数htim1_OC1.Init.Period = arr - 1;                        //自动重装载值htim1_OC1.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;  //时钟分频因子,用于防干扰,与定时无关htim1_OC1.Init.RepetitionCounter = rep;                 //重复计数器htim1_OC1.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE; //禁止预加载HAL_TIM_OC_Init(&htim1_OC1);__HAL_TIM_CLEAR_FLAG(&htim1_OC1,TIM_FLAG_UPDATE);       //清除更新标志位/* 3、TIM1的OC1配置 */sConfig.OCMode = TIM_OCMODE_PWM1;                       //规则模式:PWM1模式(小于比较值输出有效电平)sConfig.Pulse = 1000;                                   //比较值:1000sConfig.OCPolarity = TIM_OCPOLARITY_LOW;                //有效电平极性:低电平HAL_TIM_OC_ConfigChannel(&htim1_OC1, &sConfig, TIM_CHANNEL_1);/* 4、启动TIM1 */HAL_TIM_OC_Start_IT(&htim1_OC1, TIM_CHANNEL_1);             //启动TIM1,开启匹配中断HAL_NVIC_SetPriority(TIM1_CC_IRQn,3,0);HAL_NVIC_EnableIRQ(TIM1_CC_IRQn);
}/*** @brief:HAL_TIM_OC_Init()调用函数*/
void HAL_TIM_OC_MspInit(TIM_HandleTypeDef *htim)
{GPIO_InitTypeDef GPIO_Init;                     //IO口配置的结构体if (htim->Instance == TIM1)                   {     /* TIM1的CH1的引脚的PA8:输入 */__HAL_RCC_GPIOA_CLK_ENABLE();               //使能GPIOA时钟GPIO_Init.Pin = GPIO_PIN_8;                 //选择PA8GPIO_Init.Mode = GPIO_MODE_AF_PP;           //输出模式:复用推挽GPIO_Init.Speed = GPIO_SPEED_FREQ_MEDIUM;   //最大输出速度:中等HAL_GPIO_Init(GPIOA,&GPIO_Init);}else if(htim->Instance == TIM2){}
}

④Time.h文件的代码如下

#ifndef __Time_H
#define __Time_H#include "stm32f1xx_hal.h"
extern TIM_HandleTypeDef htim1_OC1;//TIM1输出比较的时基单元配置结构体
void TIM1_Init(uint16_t psc, uint16_t arr, uint8_t rep);#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);TIM1_Init(7200, 10000, 0);//0.1ms计数一次,周期为1s,即:PWM1s产生一次上升沿ADC_Init();printf("启动判断!\r\n");while(1){}	
}

⑥stm32f1xx_it.c文件的代码如下

#include "stm32f1xx_hal.h"   
#include "stm32f1xx_it.h" 
#include "ADC.h" 
#include "Time.h" 
#include "UART.h"/*** @brief:TIM1的CC的中断服务函数*/
void TIM1_CC_IRQHandler(void)
{HAL_TIM_IRQHandler(&htim1_OC1);//定时器中断服务总函数
}
/*** @brief:DMA通道1中断服务函数*/
void DMA1_Channel1_IRQHandler(void)
{HAL_DMA_IRQHandler(&hdma1_ADC1);//DMA中断服务总函数
}/******************* 下面的中断的回调函数 ***************************/
/*** @brief:TIM1输出比较匹配中断服务函数*/
void HAL_TIM_PWM_PulseFinishedCallback(TIM_HandleTypeDef *htim)
{if(htim->Instance == TIM1){if(htim->Channel == HAL_TIM_ACTIVE_CHANNEL_1){printf("匹配成功,产生上升沿!\r\n");}else if(htim->Channel == HAL_TIM_ACTIVE_CHANNEL_2){}}else if(htim->Instance == TIM2){}
}/*** @brief:DMA通道1传输完成的中断服务函数*/
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)
{float ADC_Value = 0;uint16_t sum = 0;if(hadc->Instance == ADC1){for(uint8_t i = 0; i<10; i++){sum += ADC1_Buffer[i];}printf("结果寄存器数值为:%d\r\n",sum/10);ADC_Value = (sum/10) * 3.3 / 4095;            //将二进制计数为电压电压值printf("电压值 = %f\r\n",ADC_Value);          //输出电压值}else if(hadc->Instance == ADC2){}
}

在这里插入图片描述

2、TIM3的TRGO事件(的更新事件)触发ADC1+DMA重装载

将定时器TIM3配置为主模式,且能够使TRGO产生信号的情况如下:
一般触发ADC:选择更新事件和比较脉冲的输出捕获事件
在这里插入图片描述实验要求:选择TIM3主模式的更新事件产生TRGO信号来触发ADC1的转换
①ADC.c文件的代码如下

#include "ADC.h"uint16_t ADC1_Buffer[10] = {0};             //数据缓冲区
/*** @brief:ADC1初始化函数*/
RCC_PeriphCLKInitTypeDef PeriphClkInit; //ADC时钟配置结构体
ADC_HandleTypeDef hadc1;                //ADC1配置结构体
ADC_ChannelConfTypeDef sConfig1;         //规则组通道配置结构体
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();/* 3、ADC1的初始化 */hadc1.Instance = ADC1;                              //选择ADC1hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;         //数据对齐方式:右对齐hadc1.Init.ScanConvMode = ADC_SCAN_DISABLE;         //扫描模式:关闭扫描(仅一个通道)hadc1.Init.ContinuousConvMode = DISABLE;            //转换模式:单次转换//hadc1.Init.NbrOfConversion =                        //扫描模式下规则组的数量//hadc1.Init.DiscontinuousConvMode =                  //扫描模式规则组间断模式//hadc1.Init.NbrOfDiscConversion =                    //规则组间断模式下每次间断的通道数hadc1.Init.ExternalTrigConv = ADC_EXTERNALTRIGCONV_T3_TRGO;   //ADC触发:TIM3的TRGO事件触发HAL_ADC_Init(&hadc1);/* 4、规则组通道配置 */sConfig1.Channel = ADC_CHANNEL_0;                    //通道选择:通道0sConfig1.Rank = ADC_REGULAR_RANK_1;                  //规则组盒子序号:1号sConfig1.SamplingTime = ADC_SAMPLETIME_41CYCLES_5;   //采样时间:41.5THAL_ADC_ConfigChannel(&hadc1, &sConfig1);/* 5、ADC1校准 */HAL_ADCEx_Calibration_Start(&hadc1);                //ADC1自校准/* 6、开启ADC规则组转换 */HAL_ADC_Start_DMA(&hadc1,(uint32_t*)ADC1_Buffer,10);//开启转换:DMA方式,转换完成DMA执行搬运,//开启了DMA中断,搬运10后执行DMA中断HAL_NVIC_SetPriority(DMA1_Channel1_IRQn,3,0);       //配置优先级HAL_NVIC_EnableIRQ(DMA1_Channel1_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 */__HAL_RCC_GPIOA_CLK_ENABLE();       //使能GPIOA时钟GPIO_Init.Pin = GPIO_PIN_0;         //选择PA0GPIO_Init.Mode = GPIO_MODE_ANALOG;  //选择模拟输入模式HAL_GPIO_Init(GPIOA, &GPIO_Init);/* 1、使能DMA1的时钟 */__HAL_RCC_DMA1_CLK_ENABLE();                                    //使能DMA1的时钟/* 2、初始化DMA1的通道1配置 */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[10];
extern ADC_HandleTypeDef hadc1;                //ADC1配置结构体
extern DMA_HandleTypeDef hdma1_ADC1;           //ADC1的DMA1的通道配置结构体
void ADC_Init(void);#endif

③Time.c文件的代码如下

#include "Time.h"/*** 定时器TIM3的配置* psc: 时钟预分频数(1~65536)* arr: 自动重装值(1~65536)*/
TIM_HandleTypeDef htim3;                                //TIM3时基单元配置结构体
TIM_MasterConfigTypeDef sMasterConfig;                  //主模式配置结构体
void TIM3_Init(uint16_t psc, uint16_t arr)
{/* 1、使能TIM3的时钟 */__HAL_RCC_TIM3_CLK_ENABLE();/* 2、配置TIM3的时基单元 */htim3.Instance = TIM3;                              //选择定时器TIM3htim3.Init.Prescaler = psc - 1;                     //预分频器htim3.Init.CounterMode = TIM_COUNTERMODE_UP;        //向上计数htim3.Init.Period = arr - 1;                        //自动重装载值htim3.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;  //时钟分频因子,用于防干扰,与定时无关htim3.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE; //禁止预加载HAL_TIM_Base_Init(&htim3);__HAL_TIM_CLEAR_FLAG(&htim3,TIM_FLAG_UPDATE);       //清除更新标志位/* 3、TIM3的主模式的配置 */sMasterConfig.MasterOutputTrigger = TIM_TRGO_UPDATE;//触发TRGO信号事件:更新事件HAL_TIMEx_MasterConfigSynchronization(&htim3,&sMasterConfig);/* 4、启动TIM3 */HAL_TIM_Base_Start_IT(&htim3);                      //启动TIM3,开启更新中断HAL_NVIC_SetPriority(TIM3_IRQn,3,0);HAL_NVIC_EnableIRQ(TIM3_IRQn);
}/*** @brief:HAL_TIM_Base_Init()调用函数*/
void HAL_TIM_Base_MspInit(TIM_HandleTypeDef *htim)
{if (htim->Instance == TIM1)                   {     }else if(htim->Instance == TIM2){}else if(htim->Instance == TIM3){}
}

④Time.h文件的代码如下

#ifndef __Time_H
#define __Time_H#include "stm32f1xx_hal.h"
extern TIM_HandleTypeDef htim3;                         //TIM3输出比较的时基单元配置结构体
void TIM3_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);TIM3_Init(7200, 10000);//0.1ms计数一次,周期为1s,即:1s产生一次更新ADC_Init();printf("启动判断!\r\n");while(1){}	
}

⑥stm32f1xx_it.c文件的代码如下

#include "stm32f1xx_hal.h"   
#include "stm32f1xx_it.h" 
#include "ADC.h" 
#include "Time.h" 
#include "UART.h"/*** @brief:TIM3中断服务函数*/
void TIM3_IRQHandler(void)
{HAL_TIM_IRQHandler(&htim3);//中断服务总函数
}
/*** @brief:DMA通道1中断服务函数*/
void DMA1_Channel1_IRQHandler(void)
{HAL_DMA_IRQHandler(&hdma1_ADC1);//DMA中断服务总函数
}/******************* 下面的中断的回调函数 ***************************/
/*** @brief:TIM3更新事件中断服务函数*/
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{if(htim->Instance == TIM3){printf("TIM3更新了,产生TRGO信号了!\r\n");}
}
/*** @brief:DMA通道1传输完成的中断服务函数*/
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)
{float ADC_Value = 0;uint16_t sum = 0;if(hadc->Instance == ADC1){for(uint8_t i = 0; i<10; i++){sum += ADC1_Buffer[i];}printf("结果寄存器数值为:%d\r\n",sum/10);ADC_Value = (sum/10) * 3.3 / 4095;            //将二进制计数为电压电压值printf("电压值 = %f\r\n",ADC_Value);          //输出电压值}else if(hadc->Instance == ADC2){}
}

在这里插入图片描述

3、TIM3的TRGO事件(的捕获事件)触发ADC1+DMA重装载

【注意】只有定时器的CC1捕获才能触发TRGO信号,所以TIM3的CC1通道引脚是PA6,而ADC1/ADC2的采样通道6的引脚也是PA6。即若只用ADC的通道6进行采样,且由TIM3的输入捕获进行触发转换,则将TIM3的输入捕获引脚进行重映射到PB4即可。
【注意】在使用PB4是需要释放JTAG
①ADC.c文件的代码如下

#include "ADC.h"uint16_t ADC1_Buffer[10] = {0};             //数据缓冲区
/*** @brief:ADC1初始化函数*/
RCC_PeriphCLKInitTypeDef PeriphClkInit; //ADC时钟配置结构体
ADC_HandleTypeDef hadc1;                //ADC1配置结构体
ADC_ChannelConfTypeDef sConfig1;         //规则组通道配置结构体
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();/* 3、ADC1的初始化 */hadc1.Instance = ADC1;                              //选择ADC1hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;         //数据对齐方式:右对齐hadc1.Init.ScanConvMode = ADC_SCAN_DISABLE;         //扫描模式:关闭扫描(仅一个通道)hadc1.Init.ContinuousConvMode = DISABLE;            //转换模式:单次转换//hadc1.Init.NbrOfConversion =                        //扫描模式下规则组的数量//hadc1.Init.DiscontinuousConvMode =                  //扫描模式规则组间断模式//hadc1.Init.NbrOfDiscConversion =                    //规则组间断模式下每次间断的通道数hadc1.Init.ExternalTrigConv = ADC_EXTERNALTRIGCONV_T3_TRGO;   //ADC触发:TIM3的TRGO事件触发HAL_ADC_Init(&hadc1);/* 4、规则组通道配置 */sConfig1.Channel = ADC_CHANNEL_0;                    //通道选择:通道0sConfig1.Rank = ADC_REGULAR_RANK_1;                  //规则组盒子序号:1号sConfig1.SamplingTime = ADC_SAMPLETIME_41CYCLES_5;   //采样时间:41.5THAL_ADC_ConfigChannel(&hadc1, &sConfig1);/* 5、ADC1校准 */HAL_ADCEx_Calibration_Start(&hadc1);                //ADC1自校准/* 6、开启ADC规则组转换 */HAL_ADC_Start_DMA(&hadc1,(uint32_t*)ADC1_Buffer,10);//开启转换:DMA方式,转换完成DMA执行搬运,//开启了DMA中断,搬运10后执行DMA中断HAL_NVIC_SetPriority(DMA1_Channel1_IRQn,3,0);       //配置优先级HAL_NVIC_EnableIRQ(DMA1_Channel1_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 */__HAL_RCC_GPIOA_CLK_ENABLE();       //使能GPIOA时钟GPIO_Init.Pin = GPIO_PIN_0;         //选择PA0GPIO_Init.Mode = GPIO_MODE_ANALOG;  //选择模拟输入模式HAL_GPIO_Init(GPIOA, &GPIO_Init);/* 1、使能DMA1的时钟 */__HAL_RCC_DMA1_CLK_ENABLE();                                    //使能DMA1的时钟/* 2、初始化DMA1的通道1配置 */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[10];
extern ADC_HandleTypeDef hadc1;                //ADC1配置结构体
extern DMA_HandleTypeDef hdma1_ADC1;           //ADC1的DMA1的通道配置结构体
void ADC_Init(void);#endif

③Time.c文件的代码如下

#include "Time.h"/*** 定时器TIM3的配置* psc: 时钟预分频数(1~65536)* arr: 自动重装值(1~65536)*/
TIM_HandleTypeDef htim3_IC;                             //TIM3输入捕获时基单元配置结构体
TIM_MasterConfigTypeDef sMasterConfig;                  //主模式配置结构体
TIM_IC_InitTypeDef sConfig_IC;                          //捕获通道配置结构体
void TIM3_Init(uint16_t psc, uint16_t arr)
{/* 1、使能TIM3的时钟 */__HAL_RCC_TIM3_CLK_ENABLE();/* 2、配置TIM3的时基单元 */htim3_IC.Instance = TIM3;                              //选择定时器TIM3htim3_IC.Init.Prescaler = psc - 1;                     //预分频器htim3_IC.Init.CounterMode = TIM_COUNTERMODE_UP;        //向上计数htim3_IC.Init.Period = arr - 1;                        //自动重装载值htim3_IC.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;  //时钟分频因子,用于防干扰,与定时无关htim3_IC.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE; //禁止预加载HAL_TIM_IC_Init(&htim3_IC);__HAL_TIM_CLEAR_FLAG(&htim3_IC,TIM_FLAG_UPDATE);       //清除更新标志位/* 3、TIM3输出捕获通道1的配置 */sConfig_IC.ICPolarity = TIM_ICPOLARITY_RISING;      //捕获边沿:上升沿sConfig_IC.ICSelection = TIM_ICSELECTION_DIRECTTI;  //输入对应方式:直接连接sConfig_IC.ICPrescaler = TIM_ICPSC_DIV1;            //捕获分频:1分频sConfig_IC.ICFilter = 0x8;                          //滤波HAL_TIM_IC_ConfigChannel(&htim3_IC, &sConfig_IC, TIM_CHANNEL_1);/* 4、TIM3的主模式的配置 */sMasterConfig.MasterOutputTrigger = TIM_TRGO_OC1;   //触发TRGO信号事件:捕获事件HAL_TIMEx_MasterConfigSynchronization(&htim3_IC,&sMasterConfig);/* 4、启动TIM1 */HAL_TIM_IC_Start_IT(&htim3_IC,TIM_CHANNEL_1);       //启动TIM3,开启捕获中断HAL_NVIC_SetPriority(TIM3_IRQn,3,0);HAL_NVIC_EnableIRQ(TIM3_IRQn);
}/*** @brief:HAL_TIM_IC_Init()调用函数*/
void HAL_TIM_IC_MspInit(TIM_HandleTypeDef *htim)
{GPIO_InitTypeDef GPIO_Init;             //IO口配置结构体if (htim->Instance == TIM1)                   {     }else if(htim->Instance == TIM2){}else if(htim->Instance == TIM3){/* TIM3的CC1的引脚为PA6,将引脚重映射到PB4 */__HAL_RCC_AFIO_CLK_ENABLE();        //使能AFIO的时钟__HAL_AFIO_REMAP_TIM3_PARTIAL();    //TIM3引脚部分重映射__HAL_RCC_GPIOB_CLK_ENABLE();       //开启GPIOB时钟__HAL_AFIO_REMAP_SWJ_NOJTAG();      //关闭JTAG,释放PB4/* 配置PB4 */GPIO_Init.Mode = GPIO_MODE_INPUT;   //模式:输入模式GPIO_Init.Pin = GPIO_PIN_4;         //选择PB4GPIO_Init.Pull = GPIO_PULLDOWN;     //下拉输入HAL_GPIO_Init(GPIOB, &GPIO_Init);}
}

④Time.h文件的代码如下

#ifndef __Time_H
#define __Time_H#include "stm32f1xx_hal.h"
extern TIM_HandleTypeDef htim3_IC;                         //TIM3输出比较的时基单元配置结构体
void TIM3_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);TIM3_Init(7200, 10000);//0.1ms计数一次,周期为1s,即:1s产生一次更新ADC_Init();printf("启动判断!\r\n");while(1){}	
}

⑥stm32f1xx_it.c文件的代码如下

#include "stm32f1xx_hal.h"   
#include "stm32f1xx_it.h" 
#include "ADC.h" 
#include "Time.h" 
#include "UART.h"/*** @brief:TIM3中断服务函数*/
void TIM3_IRQHandler(void)
{HAL_TIM_IRQHandler(&htim3_IC);//中断服务总函数
}
/*** @brief:DMA通道1中断服务函数*/
void DMA1_Channel1_IRQHandler(void)
{HAL_DMA_IRQHandler(&hdma1_ADC1);//DMA中断服务总函数
}/******************* 下面的中断的回调函数 ***************************/
/*** @brief:TIM3捕获事件中断服务函数*/
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{if(htim->Instance == TIM3){printf("TIM3捕获了,产生TRGO信号了!\r\n");}
}/*** @brief:DMA通道1传输完成的中断服务函数*/
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)
{float ADC_Value = 0;uint16_t sum = 0;if(hadc->Instance == ADC1){for(uint8_t i = 0; i<10; i++){sum += ADC1_Buffer[i];}printf("结果寄存器数值为:%d\r\n",sum/10);ADC_Value = (sum/10) * 3.3 / 4095;            //将二进制计数为电压电压值printf("电压值 = %f\r\n",ADC_Value);          //输出电压值}else if(hadc->Instance == ADC2){}
}

在这里插入图片描述

4、优化TIM3的TRGO事件(的捕获事件)触发ADC1+DMA重装载

案列3需要按下按键10次,才会输出测量到的结果。下面进行优化,只需按键按下1次,就会输出测量结果,但是输出的结果依然是10次平均滤波得到的。
修改的代码如下:
①ADC.c文件需要修改的代码如下
开启ADC连续转换模式

hadc1.Init.ContinuousConvMode = ENABLE;             //转换模式:连续转换

②stm32f1xx_it.c文件需要修改的代码如下
在触发中断服务函数中关闭连续转换,ADC采集速度>代码执行到关闭连续转换的速度
在DMA完成中断服务函数中开启连续转换

/*** @brief:TIM3捕获事件中断服务函数*/
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{if(htim->Instance == TIM3){printf("TIM3捕获了,产生TRGO信号了!\r\n");ADC1->CR2 &= ~ADC_CR2_CONT; //关闭连续转换}
}/*** @brief:DMA通道1传输完成的中断服务函数*/
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)
{float ADC_Value = 0;uint16_t sum = 0;if(hadc->Instance == ADC1){for(uint8_t i = 0; i<10; i++){sum += ADC1_Buffer[i];}printf("结果寄存器数值为:%d\r\n",sum/10);ADC_Value = (sum/10) * 3.3 / 4095;            //将二进制计数为电压电压值printf("电压值 = %f\r\n",ADC_Value);          //输出电压值ADC1->CR2 |= ADC_CR2_CONT;                    //开启连续转换}else if(hadc->Instance == ADC2){}
}

在这里插入图片描述

5、外部中断EXTI11触发ADC1+DMA重装载

①ADC.c文件的代码如下

#include "ADC.h"uint16_t ADC1_Buffer[10] = {0};             //数据缓冲区
/*** @brief:ADC1初始化函数*/
RCC_PeriphCLKInitTypeDef PeriphClkInit; //ADC时钟配置结构体
ADC_HandleTypeDef hadc1;                //ADC1配置结构体
ADC_ChannelConfTypeDef sConfig1;         //规则组通道配置结构体
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();/* 3、ADC1的初始化 */hadc1.Instance = ADC1;                              //选择ADC1hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;         //数据对齐方式:右对齐hadc1.Init.ScanConvMode = ADC_SCAN_DISABLE;         //扫描模式:关闭扫描(仅一个通道)hadc1.Init.ContinuousConvMode = ENABLE;             //转换模式:连续转换//hadc1.Init.NbrOfConversion =                        //扫描模式下规则组的数量//hadc1.Init.DiscontinuousConvMode =                  //扫描模式规则组间断模式//hadc1.Init.NbrOfDiscConversion =                    //规则组间断模式下每次间断的通道数hadc1.Init.ExternalTrigConv = ADC_EXTERNALTRIGCONV_EXT_IT11;   //ADC触发:EXTI11事件触发HAL_ADC_Init(&hadc1);/* 4、规则组通道配置 */sConfig1.Channel = ADC_CHANNEL_0;                    //通道选择:通道0sConfig1.Rank = ADC_REGULAR_RANK_1;                  //规则组盒子序号:1号sConfig1.SamplingTime = ADC_SAMPLETIME_41CYCLES_5;   //采样时间:41.5THAL_ADC_ConfigChannel(&hadc1, &sConfig1);/* 5、ADC1校准 */HAL_ADCEx_Calibration_Start(&hadc1);                //ADC1自校准/* 6、开启ADC规则组转换 */HAL_ADC_Start_DMA(&hadc1,(uint32_t*)ADC1_Buffer,10);//开启转换:DMA方式,转换完成DMA执行搬运,//开启了DMA中断,搬运10后执行DMA中断HAL_NVIC_SetPriority(DMA1_Channel1_IRQn,3,0);       //配置优先级HAL_NVIC_EnableIRQ(DMA1_Channel1_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 */__HAL_RCC_GPIOA_CLK_ENABLE();       //使能GPIOA时钟GPIO_Init.Pin = GPIO_PIN_0;         //选择PA0GPIO_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){}    
}

②ADC.h文件的代码如下

#ifndef __ADC_H
#define __ADC_H#include "stm32f1xx_hal.h"
extern uint16_t ADC1_Buffer[10];
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 "Time.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:EXTI11中断服务函数*/
void EXTI15_10_IRQHandler(void)
{HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_11);//外部中断服务总函数
}
/*** @brief:DMA通道1中断服务函数*/
void DMA1_Channel1_IRQHandler(void)
{HAL_DMA_IRQHandler(&hdma1_ADC1);//DMA中断服务总函数
}/******************* 下面的中断的回调函数 ***************************/
/*** @brief:外部中断服务函数*/
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{if(GPIO_Pin == GPIO_PIN_11){printf("按键11按下了!\r\n");ADC1->CR2 &= ~ADC_CR2_CONT; //关闭连续转换}
}/*** @brief:DMA通道1传输完成的中断服务函数*/
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)
{float ADC_Value = 0;uint16_t sum = 0;if(hadc->Instance == ADC1){for(uint8_t i = 0; i<10; i++){sum += ADC1_Buffer[i];}printf("结果寄存器数值为:%d\r\n",sum/10);ADC_Value = (sum/10) * 3.3 / 4095;            //将二进制计数为电压电压值printf("电压值 = %f\r\n",ADC_Value);          //输出电压值ADC1->CR2 |= ADC_CR2_CONT;                    //开启连续转换}else if(hadc->Instance == ADC2){}
}

在这里插入图片描述

6、外部中断EXTI11触发ADC1+DMA重装载+间断模式

间断模式:就是将ADC规则组中的多个通道分成小组,小组转换完成后则需要重新触发,继续转换下一个小组。所以一般为单次扫描模式+DMA重装载
①ADC.c文件的代码如下

#include "ADC.h"uint16_t ADC1_Buffer[2] = {0};             //数据缓冲区
/*** @brief:ADC1初始化函数*/
RCC_PeriphCLKInitTypeDef PeriphClkInit; //ADC时钟配置结构体
ADC_HandleTypeDef hadc1;                //ADC1配置结构体
ADC_ChannelConfTypeDef sConfig1;        //规则组通道配置结构体
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();/* 3、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);/* 4、规则组通道配置 */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);/* 5、ADC1校准 */HAL_ADCEx_Calibration_Start(&hadc1);                //ADC1自校准/* 6、开启ADC规则组转换 */HAL_ADC_Start_DMA(&hadc1,(uint32_t*)ADC1_Buffer,2); //开启转换:DMA方式,转换完成DMA执行搬运,//开启了DMA中断,搬运2后执行DMA中断HAL_NVIC_SetPriority(DMA1_Channel1_IRQn,3,0);       //配置优先级HAL_NVIC_EnableIRQ(DMA1_Channel1_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_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){}    
}

②ADC.h文件的代码如下

#ifndef __ADC_H
#define __ADC_H#include "stm32f1xx_hal.h"
extern uint16_t ADC1_Buffer[10];
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 "Time.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:EXTI11中断服务函数*/
void EXTI15_10_IRQHandler(void)
{HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_11);//外部中断服务总函数
}
/*** @brief:DMA通道1中断服务函数*/
void DMA1_Channel1_IRQHandler(void)
{HAL_DMA_IRQHandler(&hdma1_ADC1);//DMA中断服务总函数
}/******************* 下面的中断的回调函数 ***************************/
/*** @brief:外部中断服务函数*/
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{if(GPIO_Pin == GPIO_PIN_11){printf("按键11按下了!\r\n");}
}/*** @brief:DMA通道1传输完成的中断服务函数*/
uint8_t Num = 0;
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)
{float ADC_Value = 0;if(hadc->Instance == ADC1){ADC_Value = ADC1_Buffer[0] * 3.3 / 4095;            //将二进制计数为电压电压值printf("通道%d电压值 = %f\r\n",(Num%2)*2 ,ADC_Value);          //输出电压值ADC_Value = ADC1_Buffer[1] * 3.3 / 4095;            //将二进制计数为电压电压值printf("通道%d电压值 = %f\r\n",(Num%2)*2 + 1,ADC_Value);          //输出电压值Num++;}else if(hadc->Instance == ADC2){}
}

在这里插入图片描述

相关文章:

ADC(二):外部触发

有关ADC的基础知识请参考标准库入门教程 ADC&#xff08;二&#xff09;&#xff1a;外部触发 1、TIM1的CC1事件触发ADC1DMA重装载2、TIM3的TRGO事件(的更新事件)触发ADC1DMA重装载3、TIM3的TRGO事件(的捕获事件)触发ADC1DMA重装载4、优化TIM3的TRGO事件(的捕获事件)触发ADC1D…...

数仓开发那些事(8)

程序员圣经 为什么刚刚能运行&#xff0c;现在就不行 为什么刚刚不运行&#xff0c;现在就可以 为什么他的可以跑&#xff0c;我的不能跑 为什么我的可以跑&#xff0c;他的就不行 为什么这台电脑能&#xff0c;那台就不行 为什么这台电脑不行&#xff0c;那台就行 神州员工&a…...

【CSS in Depth 2 精译_096】16.4:CSS 中的三维变换 + 16.5:本章小结

当前内容所在位置&#xff08;可进入专栏查看其他译好的章节内容&#xff09; 第五部分 添加动效 ✔️【第 16 章 变换】 ✔️ 16.1 旋转、平移、缩放与倾斜 16.1.1 变换原点的更改16.1.2 多重变换的设置16.1.3 单个变换属性的设置 16.2 变换在动效中的应用 16.2.1 放大图标&am…...

【连续学习之ResCL算法】2020年AAAI会议论文:Residual continual learning

1 介绍 年份&#xff1a;2020 会议&#xff1a; AAAI Lee J, Joo D, Hong H G, et al. Residual continual learning[C]//Proceedings of the AAAI Conference on Artificial Intelligence. 2020, 34(04): 4553-4560. 本文提出的算法是Residual Continual Learning (ResC…...

【zookeeper核心源码解析】第二课:俯瞰QuorumPeer启动核心流程,实现选举关键流程

系列文章目录 【zookeeper核心源码解析】第一课&#xff1a;zk启动类核心流程序列图 【zookeeper核心源码解析】第二课&#xff1a;俯瞰QuorumPeer启动核心流程&#xff0c;实现选举关键流程 【zookeeper核心源码解析】第三课&#xff1a;leader与follower何时开始同步&#…...

数据流图和流程图的区别

在结构化建模中&#xff0c;数据流图和流程图都是非常重要的工具&#xff0c;它们为开发人员提供了强大的手段来分析和设计系统。尽管两者在表面上看起来有些相似&#xff0c;但它们在功能、用途和表达方式上存在显著的区别。本文将详细探讨数据流图和流程图的区别&#xff0c;…...

关于内网服务器依托可上网电脑实现访问互联网

关于内网服务器依托可上网电脑实现访问互联网 背景&#xff1a;在实验室内网的一个服务器&#xff0c;没有配置 NAT &#xff0c;无法使用外网&#xff0c;只能在局域网内进行访问&#xff0c;但是呢&#xff0c;我们自己的电脑是可以访问互联网的&#xff0c;那么怎么通过让自…...

期权懂|期权入门知识:如何选择期权合约?

锦鲤三三每日分享期权知识&#xff0c;帮助期权新手及时有效地掌握即市趋势与新资讯&#xff01; 期权入门知识&#xff1a;如何选择期权合约&#xff1f; 一、选择月份&#xff1a; 通常情况下&#xff0c;月份的选择与期货合约的选择类似&#xff0c;主要关注主力合约。主力…...

如何用gpt来分析链接里面的内容(比如分析论文链接)和分析包含多个文件中的一块代码

如何用gpt来分析链接里面的内容&#xff0c;方法如下 这里使用gpt4里面有一个网路的功能 点击搜索框下面这个地球的形状即可启动搜索网页模式 然后即可提出问题在搜索框里&#xff1a;发现正确识别和分析了链接里面的内容 链接如下&#xff1a;https://arxiv.org/pdf/2009.1…...

Bash 脚本教程

注&#xff1a;本文为 “Bash 脚本编写” 相关文章合辑。 BASH 脚本编写教程 as good as well于 2017-08-04 22:04:28 发布 这里有个老 American 写的 BASH 脚本编写教程&#xff0c;非常不错&#xff0c;至少没接触过 BASH 的也能看懂&#xff01; 建立一个脚本 Linux 中有…...

Pinia最简单使用(vite+vue3)

文章目录 创建项目安装Pinia包main.js注册Pinia在src下创建store/store.js文件,放入以下内容在app.vue中的使用(在其他组件也一样的) 创建项目 npm create vitelatest my-vue-app选vue 选JavaScript cd my-vue-app npm install npm run dev安装Pinia包 npm install piniamain…...

计算机网络——期末复习(4)协议或技术汇总、思维导图

思维导图 协议与技术 物理层通信协议&#xff1a;曼彻斯特编码链路层通信协议&#xff1a;CSMA/CD &#xff08;1&#xff09;停止-等待协议&#xff08;属于自动请求重传ARQ协议&#xff09;&#xff1a;确认、否认、重传、超时重传、 &#xff08;2&#xff09;回退N帧协…...

Microsoft word@【标题样式】应用不生效(主要表现为在导航窗格不显示)

背景 随笔。Microsoft word 2013基础使用&#xff0c;仅做参考和积累。 问题 Microsoft word 2013&#xff0c;对段落标题文字应用【标题样式】不生效&#xff08;主要表现为在导航窗格不显示&#xff09;。 图1 图2 观察图1和图2&#xff0c;发现图1的文字在应用【标题一】样…...

轮播图带详情插件、uniApp插件

超级好用的轮播图 介绍访问地址参数介绍使用方法&#xff08;简单使用&#xff0c;参数结构点击链接查看详情&#xff09;图片展示 介绍 带有底部物品介绍以及价格的轮播图组件&#xff0c;持续维护&#xff0c;uniApp插件&#xff0c;直接下载填充数据就可以在项目里面使用 …...

云计算时代携程的网络架构变迁

大家觉得有意义和帮助记得及时关注和点赞!!! 前言0 携程云平台简介 网络演进时间线1 基于 VLAN 的二层网络 1.1 需求1.2 解决方案&#xff1a;OpenStack Provider Network 模型1.3 硬件网络拓扑1.4 宿主机内部网络拓扑1.5 小结 优点缺点2 基于 SDN 的大二层网络 2.1 面临的新问…...

USB 状态机及状态转换

文章目录 USB 状态机及状态转换连接状态供电状态默认状态地址状态配置状态挂起状态USB 状态机及状态转换 枚举完成之前,USB 设备要经过一系列的状态变化,才能最终完成枚举。这些状态是 连接状态 - attached供电状态 - powered默认状态 - default地址状态 - address配置状态 -…...

Go C编程 第6课 无人机 --- 计算旋转角

旋转的秘密---认识角度 rt、lt命令学习 goc电子课程 一、编程步骤 第一步 第二步 第三步 第四步 二、画“四轴无人机” &#xff08;一&#xff09;、画第一根机轴 &#xff08;二&#xff09;、画第二根机轴 &#xff08;三&#xff09;、画完整的无人机 三、画“多轴无人…...

C++-----图

一、图的结构 在 C 中&#xff0c;图可以用多种结构表示&#xff0c;常见的有邻接矩阵和邻接表。 邻接矩阵 使用二维数组 adjMatrix 来表示图中顶点之间的连接关系。对于无向图&#xff0c;如果 adjMatrix[i][j] 不为零&#xff0c;则表示顶点 i 和顶点 j 之间存在边&#x…...

mysql 数据库迁移到达梦数据库

1.windows安装达梦数据库&#xff0c;去官网下载 dm8 进行安装&#xff0c;安装后&#xff0c;可以使用管理工具管理数据 使用迁移工具对数据进行迁移&#xff1b; 2.使用php 或者 thinkphp连接达梦数据库 2.1、先PHP开启DM扩展 从达梦数据库安装目录下drivers/php_pdo 复制对…...

【记录】使用R2 CDN替换本地项目图片以加速图片加载

将图片存储到 Cloudflare 的存储桶中&#xff0c;并通过其提供的公共 URL 来替换代码中的本地路径&#xff0c;可以减小项目中打包的图片文件体积 实现方法的详细步骤&#xff1a; 1. 上传图片到 Cloudflare 的存储桶 &#xff08;1&#xff09;登录 Cloudflare Dashboard&am…...

云原生核心技术 (7/12): K8s 核心概念白话解读(上):Pod 和 Deployment 究竟是什么?

大家好&#xff0c;欢迎来到《云原生核心技术》系列的第七篇&#xff01; 在上一篇&#xff0c;我们成功地使用 Minikube 或 kind 在自己的电脑上搭建起了一个迷你但功能完备的 Kubernetes 集群。现在&#xff0c;我们就像一个拥有了一块崭新数字土地的农场主&#xff0c;是时…...

java_网络服务相关_gateway_nacos_feign区别联系

1. spring-cloud-starter-gateway 作用&#xff1a;作为微服务架构的网关&#xff0c;统一入口&#xff0c;处理所有外部请求。 核心能力&#xff1a; 路由转发&#xff08;基于路径、服务名等&#xff09;过滤器&#xff08;鉴权、限流、日志、Header 处理&#xff09;支持负…...

(十)学生端搭建

本次旨在将之前的已完成的部分功能进行拼装到学生端&#xff0c;同时完善学生端的构建。本次工作主要包括&#xff1a; 1.学生端整体界面布局 2.模拟考场与部分个人画像流程的串联 3.整体学生端逻辑 一、学生端 在主界面可以选择自己的用户角色 选择学生则进入学生登录界面…...

【快手拥抱开源】通过快手团队开源的 KwaiCoder-AutoThink-preview 解锁大语言模型的潜力

引言&#xff1a; 在人工智能快速发展的浪潮中&#xff0c;快手Kwaipilot团队推出的 KwaiCoder-AutoThink-preview 具有里程碑意义——这是首个公开的AutoThink大语言模型&#xff08;LLM&#xff09;。该模型代表着该领域的重大突破&#xff0c;通过独特方式融合思考与非思考…...

新能源汽车智慧充电桩管理方案:新能源充电桩散热问题及消防安全监管方案

随着新能源汽车的快速普及&#xff0c;充电桩作为核心配套设施&#xff0c;其安全性与可靠性备受关注。然而&#xff0c;在高温、高负荷运行环境下&#xff0c;充电桩的散热问题与消防安全隐患日益凸显&#xff0c;成为制约行业发展的关键瓶颈。 如何通过智慧化管理手段优化散…...

从零实现STL哈希容器:unordered_map/unordered_set封装详解

本篇文章是对C学习的STL哈希容器自主实现部分的学习分享 希望也能为你带来些帮助~ 那咱们废话不多说&#xff0c;直接开始吧&#xff01; 一、源码结构分析 1. SGISTL30实现剖析 // hash_set核心结构 template <class Value, class HashFcn, ...> class hash_set {ty…...

手机平板能效生态设计指令EU 2023/1670标准解读

手机平板能效生态设计指令EU 2023/1670标准解读 以下是针对欧盟《手机和平板电脑生态设计法规》(EU) 2023/1670 的核心解读&#xff0c;综合法规核心要求、最新修正及企业合规要点&#xff1a; 一、法规背景与目标 生效与强制时间 发布于2023年8月31日&#xff08;OJ公报&…...

适应性Java用于现代 API:REST、GraphQL 和事件驱动

在快速发展的软件开发领域&#xff0c;REST、GraphQL 和事件驱动架构等新的 API 标准对于构建可扩展、高效的系统至关重要。Java 在现代 API 方面以其在企业应用中的稳定性而闻名&#xff0c;不断适应这些现代范式的需求。随着不断发展的生态系统&#xff0c;Java 在现代 API 方…...

【Linux】自动化构建-Make/Makefile

前言 上文我们讲到了Linux中的编译器gcc/g 【Linux】编译器gcc/g及其库的详细介绍-CSDN博客 本来我们将一个对于编译来说很重要的工具&#xff1a;make/makfile 1.背景 在一个工程中源文件不计其数&#xff0c;其按类型、功能、模块分别放在若干个目录中&#xff0c;mak…...

通过 Ansible 在 Windows 2022 上安装 IIS Web 服务器

拓扑结构 这是一个用于通过 Ansible 部署 IIS Web 服务器的实验室拓扑。 前提条件&#xff1a; 在被管理的节点上安装WinRm 准备一张自签名的证书 开放防火墙入站tcp 5985 5986端口 准备自签名证书 PS C:\Users\azureuser> $cert New-SelfSignedCertificate -DnsName &…...