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){}
}

在這里插入圖片描述

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/64235.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/64235.shtml
英文地址,請注明出處:http://en.pswp.cn/web/64235.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

磁盤分區格式

MBR和GPT ?磁盤分區形式主要有兩種&#xff1a;MBR和GPT。?? MBR&#xff08;Master Boot Record&#xff09; MBR是一種較舊的分區形式&#xff0c;首次引入于1983年的IBM PC DOS 2.0。它位于驅動器的第一個扇區&#xff0c;包含460字節的引導代碼、64字節的磁盤分區表和…

幾個支持用戶名密碼的代理鏈工具: glider, gost, proxychains+microsocks

幾個支持用戶名密碼的代理鏈工具: glider, gost, proxychainsmicrosocks gost -L:7777 -Fsocks5://192.168.2.20:7575 -Fsocks5://user:passwd1.1.1.1:10086 -Dgost&#xff1a;(https://github.com/ginuerzh/gost) 參考 https://www.quakemachinex.com/blog/279.html

量子退火與機器學習(1):少量數據求解未知QUBO矩陣,以少見多

文章目錄 前言ー、復習QUBO&#xff1a;中藥配伍的復雜性1.QUBO 的介入&#xff1a;尋找最佳藥材組合 二、難題&#xff1a;QUBO矩陣未知的問題1.為什么這么難&#xff1f; 三、稀疏建模(Sparse Modeling)1. 欠定系統中的稀疏解2. L1和L2的選擇&#xff1a; 三、壓縮感知算法(C…

【連續學習之SSL算法】2018年論文Selfless sequential learning

1 介紹 年份&#xff1a;2018 期刊&#xff1a; arXiv preprint Aljundi R, Rohrbach M, Tuytelaars T. Selfless sequential learning[J]. arXiv preprint arXiv:1806.05421, 2018. 本文提出了一種名為SLNID&#xff08;Sparse coding through Local Neural Inhibition and…

關于SNAT、DNAT及浮動地址

SNAT、DNAT SNAT、DNAT就是實現代理的功能。 SNAT 類似于客戶端代理&#xff1a;內網主機通過共享公網 IP 地址訪問外部服務。DNAT 類似于服務端代理&#xff1a;外部請求通過公網 IP 轉發到內網主機上的服務。 沒有大網地址的內部主機想要作為客戶端訪問外部網絡&#xff08;主…

結構方程模型【SEM】:嵌套分層數據及數據分組分析

結構方程模型&#xff08;System of Equations Model&#xff0c;簡稱SEM&#xff09;&#xff0c;在生態學和環境科學中通常指的是一組描述生態系統中能量、物質和信息流動的數學方程。這些方程可以是確定性的&#xff0c;也可以是隨機的&#xff0c;它們共同構成了一個模型&a…

hot100_56. 合并區間

以數組 intervals 表示若干個區間的集合&#xff0c;其中單個區間為 intervals[i] [starti, endi] 。 請你合并所有重疊的區間&#xff0c;并返回 一個不重疊的區間數組&#xff0c;該數組需恰好覆蓋輸入中的所有區間 。數據結構 二維鏈表存儲每個區間 方法 先對每個區間的…

Python大數據:基于Python的王者榮耀戰隊數據分析系統的設計與實現

系統展示 比賽信息管理 看板展示 系統管理 摘要 本文使用Python與MYSQL技術搭建了一個王者榮耀戰隊的數據分析系統。對用戶提出的功能進行合理分析&#xff0c;然后搭建開發平臺以及配置計算機軟硬件&#xff1b;通過對數據流圖以及系統結構的設計&#xff0c;創建相應的數據…

兩分鐘解決:vscode卡在設置SSH主機,VS Code-正在本地初始化VSCode服務器

問題原因 remote-ssh還是有一些bug的&#xff0c;在跟新之后可能會一直加載初始化SSH主機解決方案 1.打開終端2.登錄鏈接vscode的賬號&#xff0c;到家目錄下3.找到 .vscode-server文件,刪掉這個文件4.重啟 vscode 就沒問題了

深入理解與優化Java二維數組:從定義到性能提升的全面指南

1. 定義和初始化二維數組 在Java中&#xff0c;二維數組可以看作是數組的數組。你可以將它想象成一個矩陣或表格&#xff0c;每個元素是一個數組。 1.1 定義二維數組 二維數組的定義語法如下&#xff1a; datatype[][] arrayName;datatype 是數組元素的數據類型。arrayName…

day26 文件io

函數接口 1 .open和close 文件描述符&#xff1a;系統為用open打開的文件分配的標識符 非負的整形數據 0-1023 最小未被使用原則 使用完時及時釋放&#xff0c;避免文件描述符溢出 文件描述溢出就是文件使用完沒有及時關閉文件 int open(const char *pathname, int flags); /…

Java Stream流詳解——串行版

Stream流——串行版 ? Stream流是java8引入的特性&#xff0c;極大的方便了我們對于程序內數據的操作&#xff0c;提高了性能。通過函數式編程解決復雜問題。 1.BaseStream<T,S extense BaseStream<T,S>> ? 他是流處理的基石概念&#xff0c;重點不在于這個接…

el-backtop(返回頂部)

案例&#xff1a; <el-backtop target".app-main"><svg-icon icon-class"backtop" size"24px" /></el-backtop>

探秘“香水的 ChatGPT”:AI 開啟嗅覺奇幻之旅!

你沒有看錯&#xff0c;AI也能聞到味道了&#xff01;這是一家名為Osmo公司公布的信息&#xff0c;他們成功創造出了由AI生成的李子味道&#xff0c;快跟著小編一探究竟吧~ 【圖片來源于網絡&#xff0c;侵刪】 Osmo公司的這項技術&#xff0c;通過分析香味的化學成分和人類嗅…

Vue3入門(9)

1. 【 replace屬性】 作用&#xff1a;控制路由跳轉時操作瀏覽器歷史記錄的模式。 瀏覽器的歷史記錄有兩種寫入方式&#xff1a;分別為push和replace&#xff1a; - push是追加歷史記錄&#xff08;默認值&#xff09;。 - replace是替換當前記錄。 . 開啟replace模式&#xff…

第十九章 C++ 日期 時間

C 日期 & 時間 C 標準庫沒有提供所謂的日期類型。C 繼承了 C 語言用于日期和時間操作的結構和函數。為了使用日期和時間相關的函數和結構&#xff0c;需要在 C 程序中引用 <ctime> 頭文件。 有四個與時間相關的類型&#xff1a;clock_t、time_t、size_t 和 tm。類型…

電子配件行業的未來之路:產品說明書數字化轉型的力量

在科技飛速發展的今天&#xff0c;電子配件行業作為科技創新的前沿陣地&#xff0c;正經歷著前所未有的變革。從智能手機、平板電腦到智能穿戴設備&#xff0c;各種新型電子配件層出不窮&#xff0c;極大地豐富了人們的生活。然而&#xff0c;隨著產品種類的增多和功能的復雜化…

強化學習方法分類詳解

強化學習方法分類詳解 引言 強化學習&#xff08;Reinforcement Learning, RL&#xff09;是一種通過智能體與環境互動來學習如何做出最佳決策的方法。根據不同的優化中心、策略特性、環境模型、獎勵函數、動作空間類型以及行為策略和目標策略的一致性&#xff0c;RL可以分為…

RockyLinux介紹及初始化

文章目錄 一、背景二、下載 RockyLinux9 鏡像三、環境初始化四、安裝 Docker 環境 一、背景 這里講一個小故事&#xff1a; 我們都知道Linux 內核是由芬蘭計算機科學家林納斯托瓦茲 (Linus Torvalds) 于 1991 年首次開發的&#xff0c;隨后有一個非常重要的公司RetHat成立&am…

AWS、Google Cloud Platform (GCP)、Microsoft Azure、Linode和 桔子數據 的 價格對比

要對比 AWS、Google Cloud Platform (GCP)、Microsoft Azure、Linode 和 桔子數據 的 價格&#xff0c;我們需要先了解每個平臺的定價模型、服務類型以及不同服務之間的價格差異。以下是根據各個平臺常見服務&#xff08;如計算實例、存儲、數據傳輸等&#xff09;做的一個 簡化…