stm32cubemx adc_STM32CubeMX__Exp5_ADC1_2CH_DMA_TIM3_Trig__简明指导文件__jyb
用定時器TIM3觸發DMA方式的雙通道ADC定時采樣:
拷貝STM32CubeMX工程文件LED_Flash_PC12.ioc,修改為:Exp5_ADC1_2CH_DMA_TIM3_Trig.ioc
(1)配置ADC1的通道和參數
配置ADC通道參數
(2)配置ADC1的DMA
①通過點"Add"按鈕,添加ADC1---DMA1 Channel 1。選擇后ADC1后自動添加其DMA通道。
② DMA Request Settings:配置結果如下圖所示。
Mode:Circular;設置DMA的傳輸模式為連續不斷的循環模式。若只想訪問一次后就不要訪問了(或按指令操作來反問,也就是想要它訪問的時候就訪問,不要它訪問的時候就停止),可以設置成通用模式:DMA_Mode_Normal。
Peripheral:Increment Address:不勾選。如果DMA通道有外設,可以通過DMA通道將數據輸出。
Memory:勾選。DMA通過地址遞增方式將數據存儲到內部數據存儲器中。
Data Width:Word。Word是32bits,Half Word是16bits。選擇要與ADC轉換結果的數據寬度相同。
配置ADC的DMA
(3)配置ADC1的NVIC:不做任何選擇,按默認即可,如下圖所示。DMA1中斷已經默認強制選擇了。我們在這里是采用TIM3的定時溢出事件觸發ADC轉換的,在DMA中斷服務程序中讀取數據,所以不需要使能ADC的中斷。
配置ADC的NVIC
(4)"User Constants"和"GPIO Settings"按默認即可。
(5)配置TIM3。配置結果如下圖所示。
配置TIM3
用其更新事件作為TRGO觸發ADC。用鼠標點"Pinout & Configuration"點"Timers"點"TIM3""Mode"選項卡中,"Clock Source"選"Internal Clock""TIM3 Mode and Configuration"的"Configuration"菜單欄中,點"Parameter Settings""Trigger Output(TRGO)Parameters"下拉選項中,"Trigger Event Selection"選擇"Update Event"。這樣就為ADC的啟動提供觸發信號。72MHz的時鐘信號經過(7199+1)和(39999+1)分頻后,頻率為0.25Hz,其周期為4秒,也就是說每4秒觸發一次ADC轉換。
(6) 為了觀察程序運行,添加PC12接LED。
(7) ADC的時鐘為12MHz
配置ADC的時鐘
(8)配置完成,保存STM32CubeMX工程文件,點擊"GENERATE CODE",生成代碼工程框架并打開。
添加代碼
(1) 在main.c里面添加ADC轉換的相關變量
/* USER CODE BEGIN PV */
uint32_t ADC_Value[10]; //通道IN6、IN7采樣5次的值
uint8_t i,j,ADC_DMA_ConvCpltFlag=0; //ADC1_DMA方式轉換結束標志
uint32_t IN6_Value[5],IN7_Value[5]; //從DMA轉換值中分離IN6和IN7的值
uint32_t IN6_AverageValue,IN7_AverageValue; //IN6和IN7的平均值
/* USER CODE END PV */
(2)開啟定時器TIM3,通過TIM3啟動ADC。開啟DMA方式的ADC1
/* USER CODE BEGIN 2 */
HAL_TIM_Base_Start(&htim3); //啟動TIM3基本定時功能,定時到觸發ADC啟動
HAL_ADC_Start_DMA(&hadc1, (uint32_t*)&ADC_Value, 10); //啟動DMA方式的ADC轉換,采樣到10個之后觸發DMA方式的ADC中斷
/* USER CODE END 2 */
(3)在中斷回調函數中做簡單的數據處理
/* USER CODE BEGIN 4 */
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* AdcHandle) //DMA方式的ADC中斷回調函數
{
// HAL_TIM_Base_Stop(&htim3);
// HAL_ADC_Stop_DMA(&hadc1);
j=0; //將采樣到的10個ADC轉換值分離給IN6和IN7
for(i = 0; i < 10;i++)
{
IN6_Value[j]=ADC_Value[i];
i++;
IN7_Value[j]=ADC_Value[i];
j++;
}
ADC_DMA_ConvCpltFlag=1; //置DMA方式的ADC轉換結束標志
}
/* USER CODE END 4 */
(4)在主程序中做復雜些的數據處理
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
HAL_GPIO_TogglePin(GPIOB,LED1_Pin); //用LED1指示主程序運行
HAL_Delay(200); //每200msLED1閃爍一次
if(ADC_DMA_ConvCpltFlag==1) //判斷DMA方式的ADC轉換結束了沒有
{
IN6_AverageValue=0; //一次DMA方式的ADC轉換結束,計算兩個通道的平均值
IN7_AverageValue=0;
for(i =0;i <5;i++)
{
IN6_AverageValue+=IN6_Value[i];
IN7_AverageValue+=IN7_Value[i];
}
IN6_AverageValue=IN6_AverageValue/5;
IN7_AverageValue=IN7_AverageValue/5;
// HAL_TIM_Base_Start(&htim3);
// HAL_ADC_Start_DMA(&hadc1, (uint32_t*)&ADC_Value, 10);
ADC_DMA_ConvCpltFlag=0; //清除轉換結束標志,以便判斷下次中斷
}
}
/* USER CODE END 3 */
在啟動了TIM3定時器后,TIM3計數溢出事件將觸發ADC啟動轉換,ADC轉換按照規定的DMA方式進行,先轉換IN6通道,再轉換IN7通道,這就是掃描轉換各個通道一次,等到下一次TIM3溢出事件再次啟動ADC轉換,這樣反復5次,轉換得到10個ADC轉換值,將觸發DMA中斷,在DMA中斷回調函數中做簡單的數據處理,置DMA中斷標志。在主程序中,通過LED1指示主程序的運行情況,檢測到DMA中斷后對采樣到的數據做處理,并復位DMA中斷標志。
這里你也許會問,DMA中斷為什么是void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* AdcHandle)這個函數呀?這個函數不是當開啟AD的中斷的時候才調用的嗎? 對,是這樣的。我們仔細分析一下開啟AD的DMA中斷函數,在里面就會發現這個函數也在啊。在main.c中找到HAL_ADC_Start_DMA(&hadc1, (uint32_t*)&ADC_Value, 10);,在HAL_ADC_Start_DMA上點鼠標右鍵,跟蹤其定義可以找到函數:HAL_StatusTypeDef HAL_ADC_Start_DMA(ADC_HandleTypeDef* hadc, uint32_t* pData, uint32_t Length),該函數中有一句:
/* Set the DMA transfer complete callback */
hadc->DMA_Handle->XferCpltCallback = ADC_DMAConvCplt;
DMA傳輸完成,自動調用名字為ADC_DMAConvCplt函數,在ADC_DMAConvCplt上點鼠標右鍵,跟蹤其定義,進入到void ADC_DMAConvCplt(DMA_HandleTypeDef *hdma)函數里面可以找到
/* Conversion complete callback */
#if (USE_HAL_ADC_REGISTER_CALLBACKS == 1)
hadc->ConvCpltCallback(hadc);
#else
HAL_ADC_ConvCpltCallback(hadc);
#endif /* USE_HAL_ADC_REGISTER_CALLBACKS */
發現DMA方式的ADC轉換,按照開辟的數據區大小,轉換結果將數據區填滿后,轉換完成,還是調用HAL_ADC_ConvCpltCallback(hadc); 這個回調函數,在回調函數中對數據做初步處理。今后用到AD,不論是中斷方式還是DMA方式,都可以直接調用這個回調函數了,不用再糾結了。需要注意的是,中斷方式的ADC在回調函數中需要通過uhADCxConvertedValue = HAL_ADC_GetValue(AdcHandle); 獲得ADC的轉換值,而DMA方式的ADC,則通過DMA直接將轉換值存放在用數組名開辟的片內RAM中,當數組存滿數據后會觸發DMA中斷,在回調函數中直接從數組中取轉換結果即可。
以上程序是連續啟動ADC轉換的,如果要想控制這個轉換過程,可以通過以下語句實現:
HAL_TIM_Base_Stop(&htim3); //關閉定時器,停止溢出事件觸發ADC
HAL_ADC_Stop_DMA(&hadc1); //停止DMA方式的ADC轉換
HAL_TIM_Base_Start(&htim3); //啟動定時器,定時溢出事件觸發ADC
HAL_ADC_Start_DMA(&hadc1, (uint32_t*)&ADC_Value, 10); //啟動DMA方式的ADC轉換,得到10個轉換值后中斷
第三步:編譯、下載、運行
為觀察到變化效果,可以先將PA6(IN6)和PA7(IN7)懸空,此時測量到是干擾。程序運行后,可以看到LED持續閃爍,表明主程序一直在運行,不用設置斷點,全速運行程序,在觀察窗口中添加變量ADC_Value、IN6_Value、IN7_Value、IN6_AverageValue、IN7_AverageValue、i、j,可以看到,每隔4秒鐘ADC_Value的值以組(IN6和IN7)為單位變化一次,因為TIM3定時4秒,所以每隔4秒觸發一次ADC轉換,轉換結果通過DMA送給ADC_Value數組。需要20秒后,ADC_Value填滿,觸發DMA中斷,IN6_Value和IN7_Value在中斷回調函數中得到各自的轉換結果,如下圖所示。也可以將PA6和PA7接GND、3.3V,做進一步觀察。
觀察運行結果
總結
以上是生活随笔為你收集整理的stm32cubemx adc_STM32CubeMX__Exp5_ADC1_2CH_DMA_TIM3_Trig__简明指导文件__jyb的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: java servlet 3_java
- 下一篇: java的reentrantlock_J