[TOC] # STM ADC 簡介 - 見野火- HAL庫開發指南30章 - rm0090 13章 - [其他網站1](https://zhuanlan.zhihu.com/p/599754496) - [其他網站2](https://blog.csdn.net/qq_36347513/article/details/112850329) - 以下只提及一般使用的部分,其他更多功能見手冊 - STM32F407有3個ADC電路轉換功能,每個ADC有多個輸入通道可選擇,不同的ADC可以獨立運作或互相協同工作,解析度等ADC基本參數亦可自由設定 # ADC的組成 ## 電壓 - ADC 輸入範圍為 V~REF-~ ≤ V~IN~ ≤ V~REF+~,查閱 rm0090 的 Table 65.與 UM1472的電路圖可知 - <font color="red">V~REF-~ = V~SSA~ = 0 (GND)</font> - <font color="red">V~REF+~ = VDD = 3V</font> - <font color="red">GPIO腳位使用ADC模式時絕對不能輸入超過此電壓的訊號否則可能燒毀晶片</font> - 大部分(請查手冊)GPIO腳位作為數位輸入時確實可以容忍到5V,但那是因為該模式下有二極體保護 ## 通道 (Channel) - ![image](https://hackmd.io/_uploads/S1u1qsPp0.png =80%x) - 每個ADC有10種以上的外部通道,而且可以注意到腳位基本上是共用的,使用多個ADC時要特別注意 - 針對每個ADCx來說,每次轉換一定只針對一個通道,所以如果要使用多個通道,就會有通道轉換的優先順序區別,見轉換順序 - 有兩種通道 1. **Regular Channel** : - 由 ADC regular sequence register 控管,此類通道轉換時依照設定的優先順序一個一個進行轉換 2. **Injected Channel** : - 由 ADC injected sequence register 控管,類似中斷的概念,只有Regular Channel啟用時才有injected conversion。 - 當Regular Channel正在轉換時,Injected Channel的觸發源被觸發(軟體內或外部源),那麼Regular Channel的轉換會被reset,轉而先執行Injected Channel的轉換 ## 轉換順序 - 不論是Regular Channel或是Injected Channel被觸發要轉換時都可能要決定輪到哪個Channel做轉換 - 主要分類見[其他網站1](https://zhuanlan.zhihu.com/p/599754496) - ![image](https://hackmd.io/_uploads/rknAenv6A.png) - 如果使用單次轉換,就是得等到下個觸發發生(軟體手動或是外部),才會做下一輪轉換。連續轉換則一開始啟動後就一直轉換 - 掃描就是每輪轉換時,全部有啟用的通道都轉換。不掃描就是只轉換一個,下一輪就依照順序換下一個 - 無特別要求時,<font color="red">多通道使用連續掃描轉換,單通道使用連續轉換(掃不掃描沒差)</font> ## 時間 - **時鐘源** - ADC clock 由 PCLK2決定,可再經過分頻 - ADC clock決定ADC轉換的基礎週期 - **採樣時間** - ADC的採樣時間可以被設定(n個週期),如果很在意ADC總轉換時間,要考慮ADC本身工作花的週期 : <p class="text-center"> 總轉換週期數 = 採樣週期數+12 </p> ## 其他 - ADC轉換完成後會有End of Conversion(EOC) 旗標立起,該旗標可以用來觸發中斷 - EOC旗標也可產生DMA request,DMA主要用於數據傳輸,可減少CPU負擔 - STM的ADC有<font color="red">Overrun Detection</font>,用於偵測資料的丟失,如果有資料丟失, ADC_SR的OVR bit會立起,需要手動清除才會繼續AD轉換,使用cubeMX設置時要注意。詳見rm0090 13.8節 # ADC模式 - 使用單個ADC時只有independent mode可以使用 - 使用多個ADC時,如果選用independent,則表示每個ADC之間獨立運作,使用多個協作可見rm0090 13.9章 # CubeMX - Mode 勾選需要的Channel - Parameter配置(單個ADC、單個Channel、連續自動轉換) - ![image](https://hackmd.io/_uploads/SyquHtppR.png) - ADC Mode : independent表示每個ADC之間獨立運作 - 時鐘可分頻、解析度可以選擇,解析度後的週期數表示要花的時間 - 數據可選擇對齊方式,right alignment 可直接食用,較方便 - 依據需要選擇是否要Scan和Continous - 是需要可產生DMA request - EOC flag立起來的時機點可選擇,注意這會影響Overrun Detection的啟用,polling 方式見 rm009013.8.3 - 選擇Regular通道數,下面Rank可以選擇每個通道的順序 - External Trigger可以選擇是軟體觸發或是利用timer 觸發 - 剩下的要用自己查 - 使用timer作為觸發源 - [timer trigger ADC1](https://community.st.com/t5/stm32-mcus/using-timers-to-trigger-adc-conversions-periodically/ta-p/49889) - [timer trigger ADC2](https://www.wpgdadatong.com/blog/detail/41128) - 使用timer作為觸發源可以固定頻率的觸發ADC轉換,記得timer那邊也要開啟並做設定,trigger output 通常選update event(見基礎 timer 筆記) - ADC轉換完成後啟用中斷,方便程式使用 - ![image](https://hackmd.io/_uploads/SyoUGaDTC.png) # 程式編寫 - 在 stm32f4xx_hal_adc.c 中的" Execution of ADC conversions "有講述ADC轉換使用方法,基本上分成輪詢和中斷兩種,因應控制需求,使用中斷方法 - ![image](https://hackmd.io/_uploads/B18V4TvTA.png) - 在user begin 2 區段加入以下,以啟用ADC與其中斷 ``` c++= // adc_interrupt enable HAL_ADC_Start_IT(&hadc1); ``` - 依據設定,ADC轉換會再觸發後進行轉換,上面做的是連續轉換,所以會不斷自動觸發 - 轉換完成後會觸發中斷,可以像timer中斷一樣調用get函式獲取ADC值 ``` c++= void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef *hadc) { if (HAL_IS_BIT_SET(HAL_ADC_GetState(&hadc1), HAL_ADC_STATE_REG_EOC)) { adc_val = HAL_ADC_GetValue(&hadc1); } } ```