STM32CubeMX教程14 ADC - 多通道DMA转换
1、準備材料
開發板(正點原子stm32f407探索者開發板V2.4)
ST-LINK/V2驅動
STM32CubeMX軟件(Version 6.10.0)
keil μVision5 IDE(MDK-Arm)
CH340G Windows系統驅動程序(CH341SER.EXE)
XCOM V2.6串口助手
3個滑動變阻器
2、實驗目標
使用STM32CubeMX軟件配置STM32F407開發板的ADC實現ADC多通道DMA采集,具體為使用ADC_IN5/6/7三個通道進行DMA連續ADC轉換
3、實驗流程
3.0、前提知識
“STM32CubeMX教程13 ADC - 單通道轉換”實驗中提到過,規則通道只有一個16位的數據寄存器,因此規則通道同時只能轉換一個ADC通道,而且每次轉化完一個ADC通道就需要及時從數據寄存器中取出轉化的數據,否則會被后面轉化完畢的通道數據覆蓋
這個時間非常短,一般不采用像單通道轉化中使用中斷提取處理每個單通道數據的方法,而是采用DMA連續轉化的方法,將多通道轉化完畢之后,在DMA的數據存儲中將采集到的所有通道的數據一起處理
ADC是利用片上的模數轉換器將外部的模擬量轉化為數字量存儲到內存中,數據傳輸方向應該只有從外設到內存這一種方向,因此可知ADC的DMA方向也只有外設到內存一種
從“STM32CubeMX DMA 直接內存讀取”實驗中可知ADC1的DMA通道有DMA2_Stream0 CH0 和 DMA2_Stream4 CH0 兩個通道
ADC的DMA請求模式一般選擇循環模式,在多通道ADC采集時,配合使能掃描轉化模式,這樣就可以連續轉化多通道而不停止
由于ADC采集后的數據一般需要存儲在內存中,因此在選擇地址遞增時,ADC外設地址不增加,內存地址選擇遞增
使用HAL_ADC_Start_DMA()以DMA方式啟動ADC采集時需要指定存儲的內存首地址,從函數的定義可知其為uint32_t*類型,因此在DMA配置時我們需要選擇的數據寬度為字Word
3.1、CubeMX相關配置
3.1.0、工程基本配置
打開STM32CubeMX軟件,單擊ACCESS TO MCU SELECTOR選擇開發板MCU(選擇你使用開發板的主控MCU型號),選中MCU型號后單擊頁面右上角Start Project開始工程,具體如下圖所示
開始工程之后在配置主頁面System Core/RCC中配置HSE/LSE晶振,在System Core/SYS中配置Debug模式,具體如下圖所示詳細工程建立內容讀者可以閱讀STM32CubeMX教程1 工程建立
3.1.1、時鐘樹配置
系統時鐘使用8MHz外部高速時鐘HSE,HCLK、PCLK1和PCLK2均設置為STM32F407能達到的最高時鐘頻率,具體如下圖所示
3.1.2、外設參數配置
本實驗需要需要初始化USART1作為輸出信息渠道,具體配置步驟請閱讀“STM32CubeMX教程9 USART/UART 異步通信”
設置TIM3通用定時器溢出時間100ms,外部觸發事件選擇更新事件,參數詳解請閱讀“STM32CubeMX教程6 TIM 通用定時器 - 生成PWM波”實驗,具體配置如下圖所示
在Pinout & Configuration頁面左邊功能分類欄目Analog中單擊其中ADC1,勾選IN5/6/7三個通道,在下方的參數設置中以ADC - 單通道轉換實驗為模板修改部分參數
Scan Conversion Mode :使能掃描轉換模式,因此現在需要轉換5/6/7三個通道,因此使能該模式之后,在規則通道轉換為其中一個通道后就會接收轉換下一個通道
DMA Continuous Requests :使能DMA連續轉換請求,該參數的使能需要在配置完DMA請求之后才可選,配合參數 Scan Conversion Mode 可以實現連續不間斷的對三個通道數據進行采集
End Of Conversion Selection :選擇EOC flag at the end of all conversions,該參數表示當轉換完畢一組ADC中的所有通道之后再產生EOC標志,進入中斷
Number Of Conversion :規則通道轉換數量現在為3,對應三個不同的通道,通道轉換順序及每個通道的采樣時間由Rank及其下參數決定
具體參數配置如下圖所示
單擊Configuration中的DMA Settings選項卡對ADC1的DMA請求進行設置,單擊ADD按鍵增加DMA請求,這里可選的只有一個ADC1
選擇想要使用的DMA Stream,并設置優先級,將DMA請求模式設置為循環模式,外設地址不增加,內存地址遞增,數據寬度選擇字Word
為何如此配置?
請閱讀本實驗“3.0、前提知識”
如下圖所示為ADC1的DMA請求具體設置
3.1.3、外設中斷配置
在Pinout & Configuration頁面左邊System Core/NVIC中勾選DMA2 Stream0 全局中斷,然后選擇合適的中斷優先級即可
注意這里沒有勾選ADC1/2/3的全局中斷,因為外設DMA中斷使用的回調函數和外設本身中斷的回調函數一般是同一個回調函數(為什么?請閱讀本實驗3.2.2小節),如果同時開始兩者中斷可能會導致重復進入中斷函數
但是有些外設使用DMA時必須開啟自身的中斷,不同外設情況不一樣
建議在外設使用DMA時,盡量不開啟外設全局中斷,必須開啟的可以禁用外設主要事件源產生的硬件中斷 (注釋1)
上述步驟如下圖所示
3.2、生成代碼
3.2.0、配置Project Manager頁面
單擊進入Project Manager頁面,在左邊Project分欄中修改工程名稱、工程目錄和工具鏈,然后在Code Generator中勾選“Gnerate peripheral initialization as a pair of 'c/h' files per peripheral”,最后單擊頁面右上角GENERATE CODE生成工程,具體如下圖所示
詳細Project Manager配置內容讀者可以閱讀“STM32CubeMX教程1 工程建立”實驗3.4.3小節
3.2.1、外設初始化調用流程
首先在生成的工程主函數main()中調用MX_DMA_Init()函數對ADC1用到的DMA時鐘及其流的中斷進行了配置
然后調用MX_ADC1_Init()函數對ADC1的基本參數、通道和通道參數進行了配置,并調用了HAL_ADC_Init()使用配置的參數初始化了ADC1
在初始化函數HAL_ADC_Init()中又調用了HAL_ADC_MspInit()函數,在該函數中使能了ADC1/GPIOA的時鐘,對ADC1_IN5/6/7的輸入引腳做了復用設置,然后對ADC1的DMA參數配置并進行了初始化,最后調用了__HAL_LINKDMA(adcHandle,DMA_Handle,hdma_adc1)將adc1外設與DMA流對象關聯
具體的ADC DMA初始化調用流程如下圖所示
3.2.2、外設中斷調用流程
CubeMX中勾選DMA2_Stream0的全局中斷后,會在stm32f4xx_it.c中增加DMA的中斷服務函數DMA2_Stream0_IRQHandler()
在中斷服務函數DMA2_Stream0_IRQHandler()中調用了HAL庫的DMA全局中斷處理函數,該函數中根據各種標志判斷DMA傳輸完成/失敗/一半完成等事件,然后根據不同的事件調用不同的回調函數,這里DMA傳輸完成之后調用了hdma->->XferCpltCal1back()
上述過程如下圖所示
這個函數指針在以DMA方式啟動ADC采集時被指向DMA傳輸完成回調ADC_DMAConvCplt()函數在該DMA傳輸完成回調ADC_DMAConvCplt()函數中最終調用了ADC采集完成回調HAL_ADC_ConvCpltCallback()函數,該函數上一個實驗我們重新實現過
上述過程如下圖所示
之前所有的外設回調函數都是直接調用了HAL庫提前準備好的虛函數,比如ADC的采集完成回調函數HAL_ADC_ConvCpltCallback(),用戶直接實現該虛函數即可但是DMA不是一個外設,而是數據傳輸手段,大多數外設都可以使用,因此DMA的各種事件回調函數不是一個真正的函數,而是一個函數指針
當我們以DMA傳輸的方式啟動某個外設的時候,就會將該外設對應事件的中斷服務函數地址賦值給對應事件DMA中斷回調函數指針
3.2.3、添加其他必要代碼
在主函數中以DMA的方式啟動ADC采集傳輸,然后啟動ADC1的觸發源TIM3定時器,具體代碼如下圖所示
在adc.c中重新實現DMA傳輸完成回調函數,在該函數中取出ADC轉換完成的三通道采集值,然后處理并通過串口輸出,具體代碼如下圖所示
一些定義及函數源代碼如下
/*main.c中的全局變量定義*/
uint32_t DataBuffer[BATCH_DATA_LEN];
/*main.h中的變量外擴及宏定義*/
#define BATCH_DATA_LEN 3
extern uint32_t DataBuffer[BATCH_DATA_LEN];
/*DMA轉換完成中斷回調*/
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef *hadc)
{
/*定時器DMA啟動多通道轉換*/
uint32_t val=0,Volt=0;
for(uint8_t i=0;i<BATCH_DATA_LEN;i++)
{
val=DataBuffer[i];
Volt=(3300*val)>>12;
printf("ADC_IN%d, val:%d, Volt:%d\r\n",i+5,val,Volt);
}
printf("\r\n");
}
4、常用函數
/*以DMA方式啟動ADC采集*/
HAL_StatusTypeDef HAL_ADC_Start_DMA(ADC_HandleTypeDef *hadc, uint32_t *pData, uint32_t Length)
/*結束以DMA方式啟動的ADC采集*/
HAL_StatusTypeDef HAL_ADC_Stop_DMA(ADC_HandleTypeDef *hadc)
5、燒錄驗證
燒錄程序,單片機上電之后,串口不斷的輸出三個通道的ADC采集值,筆者將三個滑動變阻器按照通道5、通道6和通道7的順序,分別從一端緩慢擰到另一端,可以從串口輸出的數據看到,通道5/6/7三個通道采集到的ADC數據從最大4095慢慢變到最小值0
6、注釋詳解
注釋1:詳細內容請閱讀STM32Cube高效開發教程(基礎篇)14.5.1小節內容
更多內容請瀏覽 STM32CubeMX+STM32F4系列教程文章匯總貼
總結
以上是生活随笔為你收集整理的STM32CubeMX教程14 ADC - 多通道DMA转换的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 如何快速部署本地训练的 Bert-VIT
- 下一篇: AI 图像自动补全 Uncrop 工具