完整教程下載地址:http://www.armbbs.cn/forum.php?mod=viewthread&tid=86980
第44章 STM32H7的ADC基礎知識和HAL庫API
本章節為大家講解ADC(Analog-to-digital converters,模數轉換器),極具項目使用價值,因為STM32H7的ADC已經高達16位分辨率,支持3.6Msps采樣率。
44.1 初學者重要提示
44.2 ADC基礎知識
44.3 ADC的HAL庫用法
44.4 源文件stm32h7xx_hal_adc.c
44.5 總結
44.1 初學者重要提示
- STM32H7雖然支持差分,但不支持負壓測量。
- STM32H7的ADC采集通道體驗快速通道Fast Channels和低速通道Slow Channels的區別,詳情看本章2.12小節的電氣特性。
- STM32H7的ADC支持過采樣,通過過采樣技術可以做到26位分辨率。
- ADC的專業術語詮釋文檔,推薦大家看看:
http://www.armbbs.cn/forum.php?mod=viewthread&tid=89414 。
44.2 ADC基礎知識
ADC的幾個關鍵知識點放在開頭說:
- STM32H7支持三路ADC,分別是ADC1,ADC2和ADC3。其中ADC1和ADC2可以組成雙ADC模式,ADC3是獨立的。這個跟STM32F4有所不同,F4的ADC1,ADC2和ADC3可以組成三ADC模式。
- 可以配置為16bit,14bit,12bit,10bit或者8bit分辨率,分辨率越低可以做到的采樣率越高,因為轉換時間要短。
- 每個ADC都支持20路采樣通道。其中有6路快速通道和14路慢速通道,慢速和快速的區別主要是支持的最高采樣率不同,慢速通道要比快速通道低。
- 支持單獨輸入和差分輸入,其中差分輸入不支持負壓測量。
- 支持偏移校准和線性度校准,STM32F1的時候還帶校准功能,到了STM32F4取消掉了,H7又恢復了校准功能。
- 支持規則通道和注入通道兩種采樣方式。
- 支持低功耗特性,系統在低頻工作時保持最佳 ADC 性能(提供自動延遲插入)。
- 具有五條專用的內部通道,內部參考電壓 VrefInt,內部溫度傳感器和VBAT 監測通道 VBAT/4都是連接到 ADC3。另外內部 DAC 通道 1 和通道 2,連接到 ADC2。
- 支持過采樣,最高可以調整到26bit采樣率。
- ADC采樣的數據可接入DFSDM數字濾波器進行后期處理。
- 每個ADC支持三路模擬看門狗。
44.2.1 ADC硬件框圖
認識一個外設,最好的方式就是看他的框圖,方便我們快速的了解ADC的基本功能,然后再看手冊了解細節。框圖如下所示(ADC1和ADC2):
相比前面章節講解的外設,ADC的框圖相對較復雜,因為涉及到控制寄存器較多。通過這個框圖,我們可以得到如下信息:
- ADC_INP[0:19]和ADC_INN[0:19]
INP是差分正向輸入,INN是差分反向輸入。
ADC_INP[0:5]和ADC_INN[0:5]是快速通道。
ADC_INP[6:19]和ADC_INN[6:19]是慢速通道。
- adc_ext_trg[20:0]
共有21路觸發用於規則通道,ADC1和ADC2共用的,而ADC3是獨立的。
- adc_jext_trg[20:0]
共有21路觸發用於注入通道,ADC1和ADC2共用的,而ADC3是獨立的。
- adc_awd1,adc_awd2和adc_awd3
每個ADC都支持三個模擬看門狗。
- adc_it
ADC中斷。
- adc_hclk
ADC的AHB時鍾。
- adc_ker_ck
ADC的內核時鍾。
- adc_dma
用於ADC的DMA請求。
- dac_out1,dac_out2,Vsense,Vrefint和Vbat
五條專用的內部通道,內部參考電壓 VrefInt,內部溫度傳感器和VBAT 監測通道 VBAT/4都是連接到 ADC3。另外內部 DAC 通道 1 和通道 2,連接到 ADC2。
44.2.2 ADC時鍾源選擇
ADC有兩種時鍾源可供選擇,可以使用來自AHB總線的系統時鍾(屬於同步時鍾,對應下面框圖的adc_hclk),也可以使用PLL2,PLL3,HSE,HSI或者CSI時鍾(屬於異步時鍾,對應下面框圖的adc_ker_ck)。
結合上面的框圖,ADC的時鍾源要注意以下幾個問題:
- ADC1,ADC2和ADC3共用選擇的時鍾。
- ADC的時鍾源使用AHB時鍾,且使用注入模式,那么在16bit,14bit,12bit或者10bit分辨率時,ADC的時鍾不能超過AHB時鍾的四分之一。8bit模式時,不能超過AHB時鍾的三分之一。
- 選擇AHB時鍾的話,ADC的配置中提供了不分頻,二分頻和四分頻。如果選擇了不分頻,那么配置AHB的時鍾輸出時也不可以設置分頻,即RCC的CFGR寄存器配置不可分頻。
- 如果使用PLL時鍾,運行期間要一直開啟,不可關閉。
最后特別注意一點,如果STM32H7工作在400MHz,ADC使用AHB做時鍾源,超頻是不可避免的。ADC1和ADC2位於200MHz的AHB1總線時鍾,而ADC3位於200MHz的AHB4下。根據上面的框圖,ADCx_CCR寄存器的CKMODE最高可以選擇4分頻,那么就是50MHz,而ADC數據手冊限制最高是36MHz,也就是說已經超頻了。
使用AHB作為時鍾源的好處就是定時器等外部觸發方式的效果好。
44.2.3 ADC的采樣時間和轉換時間
STM32H7的ADC采樣速度,即轉換時間 = 采樣時間 + 逐次逼近時間。
采樣時間是可配置的,通過ADCx_SMPR1 和 ADCx_SMPR2 寄存器中的 SMP[2:0] 位就可以編程所有ADC通道,可選采樣時間值如下:
- SMP = 000: 1.5 個 ADC 時鍾周期
- SMP = 001: 2.5 個 ADC 時鍾周期
- SMP = 010: 8.5 個 ADC 時鍾周期
- SMP = 011: 16.5 個 ADC 時鍾周期
- SMP = 100: 32.5 個 ADC 時鍾周期
- SMP = 101: 64.5 個 ADC 時鍾周期
- SMP = 110: 387.5 個 ADC 時鍾周期
- SMP = 111: 810.5 個 ADC 時鍾周期
不同ADC分辨率對應的逐次逼近時間不同,具體數值如下:
比如配置SMP = 110,采用16位分辨率,那么:
ADC的轉換時間 =采樣時間 + 逐次逼近時間
= 387.5個ADC時鍾周期 + 8.5個ADC時鍾周期
= 396個ADC時鍾周期。
44.2.4 ADC單次轉換和連續轉換
STM32H7的ADC支持單次轉換和連續轉換。
- 單次轉換
在單次轉換模式下,ADC會將通道的所有轉換執行一次。
- 連續轉換
該模式僅適用於常規通道。
在連續轉換模式下,如果發生軟件或硬件觸發,ADC會執行所有常規通道的轉換,隨后會自動重啟並繼續執行每個通道的轉換。
44.2.5 ADC外部觸發采樣
STM32H7既可以選擇軟件觸發也可以選擇外部硬件觸發,並且可以設置觸發邊沿。
- 這里有一點要特別注意,對於ADC1和ADC2是共用相同的規則通道觸發和注入通道觸發:
- 外部觸發支持上升沿、下降沿和雙沿觸發。
- 規則通道支持的外部觸發源如下:
#define ADC_EXTERNALTRIG_T1_CC1 ((uint32_t)0x00000000) #define ADC_EXTERNALTRIG_T1_CC2 ((uint32_t)ADC_CFGR_EXTSEL_0) #define ADC_EXTERNALTRIG_T1_CC3 ((uint32_t)ADC_CFGR_EXTSEL_1) #define ADC_EXTERNALTRIG_T2_CC2 ((uint32_t)(ADC_CFGR_EXTSEL_1 | ADC_CFGR_EXTSEL_0)) #define ADC_EXTERNALTRIG_T3_TRGO ((uint32_t)ADC_CFGR_EXTSEL_2) #define ADC_EXTERNALTRIG_T4_CC4 ((uint32_t)(ADC_CFGR_EXTSEL_2 | ADC_CFGR_EXTSEL_0)) #define ADC_EXTERNALTRIG_EXT_IT11 ((uint32_t)(ADC_CFGR_EXTSEL_2 | ADC_CFGR_EXTSEL_1)) #define ADC_EXTERNALTRIG_T8_TRGO ((uint32_t)(ADC_CFGR_EXTSEL_2 | ADC_CFGR_EXTSEL_1 | ADC_CFGR_EXTSEL_0)) #define ADC_EXTERNALTRIG_T8_TRGO2 ((uint32_t) ADC_CFGR_EXTSEL_3) #define ADC_EXTERNALTRIG_T1_TRGO ((uint32_t)(ADC_CFGR_EXTSEL_3 | ADC_CFGR_EXTSEL_0)) #define ADC_EXTERNALTRIG_T1_TRGO2 ((uint32_t)(ADC_CFGR_EXTSEL_3 | ADC_CFGR_EXTSEL_1)) #define ADC_EXTERNALTRIG_T2_TRGO ((uint32_t)(ADC_CFGR_EXTSEL_3 | ADC_CFGR_EXTSEL_1 | ADC_CFGR_EXTSEL_0)) #define ADC_EXTERNALTRIG_T4_TRGO ((uint32_t)(ADC_CFGR_EXTSEL_3 | ADC_CFGR_EXTSEL_2)) #define ADC_EXTERNALTRIG_T6_TRGO ((uint32_t)(ADC_CFGR_EXTSEL_3 | ADC_CFGR_EXTSEL_2 | ADC_CFGR_EXTSEL_0)) #define ADC_EXTERNALTRIG_T15_TRGO ((uint32_t)(ADC_CFGR_EXTSEL_3 | ADC_CFGR_EXTSEL_2 | ADC_CFGR_EXTSEL_1)) #define ADC_EXTERNALTRIG_T3_CC4 ((uint32_t)(ADC_CFGR_EXTSEL_3 | ADC_CFGR_EXTSEL_2 | ADC_CFGR_EXTSEL_1 | ADC_CFGR_EXTSEL_0)) #define ADC_EXTERNALTRIG_HR1_ADCTRG1 ((uint32_t) ADC_CFGR_EXTSEL_4) #define ADC_EXTERNALTRIG_HR1_ADCTRG3 ((uint32_t) (ADC_CFGR_EXTSEL_4 | ADC_CFGR_EXTSEL_0)) #define ADC_EXTERNALTRIG_LPTIM1_OUT ((uint32_t) (ADC_CFGR_EXTSEL_4 | ADC_CFGR_EXTSEL_1)) #define ADC_EXTERNALTRIG_LPTIM2_OUT ((uint32_t) (ADC_CFGR_EXTSEL_4 | ADC_CFGR_EXTSEL_1| ADC_CFGR_EXTSEL_0)) #define ADC_EXTERNALTRIG_LPTIM3_OUT ((uint32_t) (ADC_CFGR_EXTSEL_4 | ADC_CFGR_EXTSEL_2))
- 注入通道支持的外部觸發源如下:
#define ADC_EXTERNALTRIGINJEC_T1_TRGO ((uint32_t)0x00000000) #define ADC_EXTERNALTRIGINJEC_T1_CC4 ((uint32_t)ADC_JSQR_JEXTSEL_0) #define ADC_EXTERNALTRIGINJEC_T2_TRGO ((uint32_t)ADC_JSQR_JEXTSEL_1) #define ADC_EXTERNALTRIGINJEC_T2_CC1 ((uint32_t)(ADC_JSQR_JEXTSEL_1 | ADC_JSQR_JEXTSEL_0)) #define ADC_EXTERNALTRIGINJEC_T3_CC4 ((uint32_t)ADC_JSQR_JEXTSEL_2) #define ADC_EXTERNALTRIGINJEC_T4_TRGO ((uint32_t)(ADC_JSQR_JEXTSEL_2 | ADC_JSQR_JEXTSEL_0)) #define ADC_EXTERNALTRIGINJEC_EXT_IT15 ((uint32_t)(ADC_JSQR_JEXTSEL_2 | ADC_JSQR_JEXTSEL_1)) #define ADC_EXTERNALTRIGINJEC_T8_CC4 ((uint32_t)(ADC_JSQR_JEXTSEL_2 | ADC_JSQR_JEXTSEL_1 | ADC_JSQR_JEXTSEL_0)) #define ADC_EXTERNALTRIGINJEC_T1_TRGO2 ((uint32_t)ADC_JSQR_JEXTSEL_3) #define ADC_EXTERNALTRIGINJEC_T8_TRGO ((uint32_t)(ADC_JSQR_JEXTSEL_3 | ADC_JSQR_JEXTSEL_0)) #define ADC_EXTERNALTRIGINJEC_T8_TRGO2 ((uint32_t)(ADC_JSQR_JEXTSEL_3 | ADC_JSQR_JEXTSEL_1)) #define ADC_EXTERNALTRIGINJEC_T3_CC3 ((uint32_t)(ADC_JSQR_JEXTSEL_3 | ADC_JSQR_JEXTSEL_1 | ADC_JSQR_JEXTSEL_0)) #define ADC_EXTERNALTRIGINJEC_T3_TRGO ((uint32_t)(ADC_JSQR_JEXTSEL_3 | ADC_JSQR_JEXTSEL_2)) #define ADC_EXTERNALTRIGINJEC_T3_CC1 ((uint32_t)(ADC_JSQR_JEXTSEL_3 | ADC_JSQR_JEXTSEL_2 | ADC_JSQR_JEXTSEL_0)) #define ADC_EXTERNALTRIGINJEC_T6_TRGO ((uint32_t)(ADC_JSQR_JEXTSEL_3 | ADC_JSQR_JEXTSEL_2 | ADC_JSQR_JEXTSEL_1)) #define ADC_EXTERNALTRIGINJEC_T15_TRGO ((uint32_t)(ADC_JSQR_JEXTSEL_3 | ADC_JSQR_JEXTSEL_2 | ADC_JSQR_JEXTSEL_1 | ADC_JSQR_JEXTSEL_0)) #define ADC_EXTERNALTRIGINJEC_HR1_ADCTRG2 ((uint32_t)ADC_JSQR_JEXTSEL_4) #define ADC_EXTERNALTRIGINJEC_HR1_ADCTRG4 ((uint32_t)(ADC_JSQR_JEXTSEL_4 | ADC_JSQR_JEXTSEL_0)) #define ADC_EXTERNALTRIGINJEC_LPTIM1_OUT ((uint32_t)(ADC_JSQR_JEXTSEL_4 | ADC_JSQR_JEXTSEL_1)) #define ADC_EXTERNALTRIGINJEC_LPTIM2_OUT ((uint32_t)(ADC_JSQR_JEXTSEL_4 | ADC_JSQR_JEXTSEL_1 | ADC_JSQR_JEXTSEL_0)) #define ADC_EXTERNALTRIGINJEC_LPTIM3_OUT ((uint32_t)(ADC_JSQR_JEXTSEL_4 | ADC_JSQR_JEXTSEL_2))
44.2.6 ADC多通道連接方式
ADC1,ADC2和ADC3均支持 20條通道掃描采樣(注意,部分引腳是多個ADC共用的):
- 6 路快速模擬輸入 (ADCx_INP[0]/INN[0] 到 ADCx_INP[5]/INN[5])
- 14 路慢速模擬輸入 (ADCx_INP[6]/INN[6] 到 ADCx_INP[19]/INN[19])
- ADC 連接至 5 路內部模擬輸入:
- 內部溫度傳感器 (VSENSE) 連接到 ADC3_INP18
- 內部參考電壓 (VREFINT) 連接到 ADC3_INP19
- VBAT 監測通道 (VBAT/4) 連接到 ADC3_INP17
- DAC內部通道 1連接到 ADC2_INP16
- DAC內部通道 2連接到 ADC2_INP17
反映到硬件上,這些通道的連接方式就是下面這樣(以ADC3為例):
44.2.7 ADC多通道掃描時序
ADC的多通道采樣過程是單個ADC通過多路選擇器不斷切換不同的通道進行采樣的,也就是說當前通道采集完成后才會進行下一個通道的采樣。
通過下面這四幅時序圖可以讓大家有個感性的認識:
單次轉換序列,軟件觸發:
ADSTART表示軟件啟動轉換。
EOC表示一個通道轉換結束。
EOS表示所有通道轉換結束。
關於這個時序圖的解讀:
- 配置為單次轉換的話,每次軟件啟動,所有通道僅進行一次轉換,如果需要再次轉換,需要再啟動一次。
- 每個通過轉換完畢有個EOC標志,所有通道轉換完畢有個EOS標志。
連續轉換序列,軟件觸發:
ADSTART表示軟件啟動轉換。
ADSTP表示停止轉換。
EOC表示一個通道轉換結束。
EOS表示所有通道轉換結束。
關於這個時序圖的解讀:
- 配置為連續轉換的話,軟件啟動ADSTART會開啟所有通道轉換,全部轉換完畢后,繼續進行下一輪轉換。調用了停止轉換ADSTP后,會停止轉換。
- 每個通過轉換完畢有個EOC標志,所有通道轉換完畢有個EOS標志。
單次轉換序列,硬件觸發:
ADSTART表示軟件啟動轉換。
EOC表示一個通道轉換結束。
EOS表示所有通道轉換結束。
TRGX表示硬件上升沿觸發。
關於這個時序圖的解讀:
- 軟件啟動ADSTART后還不會開啟轉換,TRGX硬件上升沿觸發才會啟動轉換,全部轉換完畢后,再來一個TRGX硬件上升沿觸發會繼續進行下一輪轉換。如果所有通道轉換期間有個TRGX硬件上升沿會被忽略。
- 每個通過轉換完畢有個EOC標志,所有通道轉換完畢有個EOS。
連續轉換序列,硬件觸發:
ADSTART表示軟件啟動轉換。
EOC表示一個通道轉換結束。
EOS表示所有通道轉換結束。
TRGX表示硬件上升沿觸發。
關於這個時序圖的解讀:
- 軟件啟動ADSTART后還不會開啟轉換,TRGX硬件下降沿觸發才會啟動轉換,一旦開啟轉換, 所有通道的轉換會一輪接一輪的進行下去,也就是說TRGX硬件下降沿會被忽略。調用了停止轉換ADSTP后,會停止轉換。停止后再有TRGX硬件下降沿觸發不會再轉換,必須再次啟動ADSTART才行。
- 每個通過轉換完畢有個EOC標志,所有通道轉換完畢有個EOS。
44.2.8 ADC單端和差分的支持
初學的話,容易有幾個概念搞不清楚,單極性,雙極性,真差分和偽差分。在此貼里面有一個專門的截圖:http://www.armbbs.cn/forum.php?mod=viewthread&tid=89397 (暫未找到這個圖片的原始出處,所以先不放在教程里面)。
單極性,雙極性比較好理解,就是單電源供電或者雙電源供電,這里的雙電源是指的正負電壓供電。
- 單端輸入是第1幅圖的效果,ADC讀取VIN和GND的差值。
- 偽差分AIP-AIN就是第5幅圖,內部ADC讀取AIP和AIN的差值,但允許AIN上有一個很小的共模電壓,比如正負0.3V。
- 真差分是AIP-AIN就是第2幅或者第5幅圖,其內部AIP和AIN分別有一個ADC,分別讀取轉換AIP-GND,和AIN-GND,再對這兩個數字值做差,所以AIN上也可以接收很大的共模值。
STM32H7的差分屬於單極性真差分,也就是不可以測量負壓。另外要注意下面內容:
- 單端輸入模式下,通道i轉換的模擬電壓是VINP[i]正向復用引腳與 VREF-之差。
- 差分輸入模式下,通道i轉換的模擬電壓是VINP[i]正向復用引腳與 VINN[i]反向復用引腳之差。
- 差分模式的輸出數據是無符號數據。當VINP[i]為VREF-、VINN[i]為VREF+時,輸出數據為0x0000(16 位分辨率模式);當VINP[i]為VREF+、VINN[i]為VREF-時,輸出數據為0xFFFF。對應的公式如下:
(1)當 ADC 配置為差分模式時,兩路輸入的偏置電壓均為 Vref+/2。
(2)輸入信號應為差分信號且共模電壓應固定。
44.2.9 ADC過采樣機制
過采樣的意思就是提高單位時間的采樣次數,比如原來每秒采集1次,那么16倍過采樣就是每秒要采集16次。
STM32H7最高支持1024倍過采樣,1024次采樣數據累加后存到ADC的數據寄存器里面。如果想求1024次采集的平均數,也不需要用戶參與計算,ADC的CFGR2寄存器OVSS[3:0]位支持右移操作(右移1位到11位均可配置),可以方便的求平均。
這個功能在實際項目還是非常實用的。比如下面的測試:
- 測試條件
做了一個ADC3+DMA的多通道采樣。
通道1:PC0采集2.5V的穩壓基准。
通道2:Vbat/4。
通道3:VrefInt。
通道4:溫度。
- 不做任何處理的效果
- 16倍過采樣求平均后的效果。
44.2.10 ADC的Vbat/4,VrefInt和溫度采樣
- Vbat/4電池監測電壓
Vbat/4連接至ADC3_INP17,所以可以使用ADC3的通道17進行測量。為什么不是直接測試Vbat,
因為Vbat電壓有可能高於Vdda,導致ADC3測量電壓超出范圍。Vbat的測量框圖如下:
注意:必須將 VBATEN 位置1才能使能內部通道 ADC3_INP17采集。
- VrefInt內部電源模塊參考電壓
VrefInt連接至ADC3_INP19,所以可以使用ADC3的通道19進行測量。可以通過監測內部電源模塊參考電壓VrefInt來評估ADC Vref+電壓的參考值。VrefInt的測量框圖如下:
注意:必須將 ADCx_CCR 寄存器中的 VREFEN 位置1才能使能內部通道 ADC3_INP19采集。
- 溫度測量
STM32H7帶有溫度傳感器,可以使用ADC3_INP18進行測量,不過讀取出來的還是個電壓值,需要將其轉換為溫度值,調用下面的轉換公式即可:
TS_CAL1 = *(__IO uint16_t *)(0x1FF1E820);
TS_CAL2 = *(__IO uint16_t *)(0x1FF1E840);
TS_CAL2表示溫度110℃時的ADC測量值,讀取地址0x1FF1E820可以獲得。
TS_CAL1表示溫度30℃時的ADC測量值,讀取地址0x1FF1E840可以獲得。
TS_DATA表示當前的測量值,獲得當前的測試值代入上面公式就可以獲取溫度。
溫度測量的框圖如下:
注意:必須將VSENSEEN位置1才能使能內部通道 ADC3_VINP18采集。
44.2.11 ADC校准問題
STM32H7的ADC支持偏移校准和線性度校准,兩種校准實現都比較方便,HAL庫已經為我們做好了,直接調用API即可,但是使用中務必注意此貼的問題:
http://www.armbbs.cn/forum.php?mod=viewthread&tid=91436 。
44.2.12 ADC電氣特性(重要)
如果使用ADC的話,部分電氣特性一定要了解:
通過上面的截圖,我們要了解到以下幾點:
- BOOST=1的時候,ADC的最高采樣率36MHz。(BOOST位可以通過寄存器配置)
- BOOST=0的時候,ADC的最高采樣率20MHz。
- 對於快速通道(Fast Channels),配置的分辨率越低,支持的最高采樣率越高。
- 對於慢速通道(Slow Channels),不同分辨率支持的最高采樣率一樣。
- 支持的測量范圍是0 – Vref+,不支持負壓測量。以我們V7開發板為例,穩壓基准Vref是通過跳線帽設置的,可以選擇2.5V,也可以選擇3.3V。
- 差分測量時,共模電壓的典型值是Vref / 2。
- ADC的輸入阻抗最大值是50KΩ。
44.3 ADC的HAL庫用法
ADC的HAL庫用法其實就是幾個結構體變量成員的配置和使用,然后配置時鍾,並根據需要配置NVIC、中斷和DMA。
只是ADC涉及到定義非常多,下面我們逐一展開為大家做個說明。
44.3.1 ADC寄存器結構體ADC_TypeDef
ADC相關的寄存器是通過HAL庫中的結構體ADC_TypeDef和ADC_Common_TypeDef定義的,在stm32h743xx.h中可以找到它們的具體定義如下:
/** * @brief Analog to Digital Converter */ typedef struct { __IO uint32_t ISR; /*!< ADC Interrupt and Status Register, Address offset: 0x00 */ __IO uint32_t IER; /*!< ADC Interrupt Enable Register, Address offset: 0x04 */ __IO uint32_t CR; /*!< ADC control register, Address offset: 0x08 */ __IO uint32_t CFGR; /*!< ADC Configuration register, Address offset: 0x0C */ __IO uint32_t CFGR2; /*!< ADC Configuration register 2, Address offset: 0x10 */ __IO uint32_t SMPR1; /*!< ADC sample time register 1, Address offset: 0x14 */ __IO uint32_t SMPR2; /*!< ADC sample time register 2, Address offset: 0x18 */ __IO uint32_t PCSEL; /*!< ADC pre-channel selection, Address offset: 0x1C */ __IO uint32_t LTR1; /*!< ADC watchdog Lower threshold register 1, Address offset: 0x20 */ __IO uint32_t HTR1; /*!< ADC watchdog higher threshold register 1, Address offset: 0x24 */ uint32_t RESERVED1; /*!< Reserved, 0x028 */ uint32_t RESERVED2; /*!< Reserved, 0x02C */ __IO uint32_t SQR1; /*!< ADC regular sequence register 1, Address offset: 0x30 */ __IO uint32_t SQR2; /*!< ADC regular sequence register 2, Address offset: 0x34 */ __IO uint32_t SQR3; /*!< ADC regular sequence register 3, Address offset: 0x38 */ __IO uint32_t SQR4; /*!< ADC regular sequence register 4, Address offset: 0x3C */ __IO uint32_t DR; /*!< ADC regular data register, Address offset: 0x40 */ uint32_t RESERVED3; /*!< Reserved, 0x044 */ uint32_t RESERVED4; /*!< Reserved, 0x048 */ __IO uint32_t JSQR; /*!< ADC injected sequence register, Address offset: 0x4C */ uint32_t RESERVED5[4]; /*!< Reserved, 0x050 - 0x05C */ __IO uint32_t OFR1; /*!< ADC offset register 1, Address offset: 0x60 */ __IO uint32_t OFR2; /*!< ADC offset register 2, Address offset: 0x64 */ __IO uint32_t OFR3; /*!< ADC offset register 3, Address offset: 0x68 */ __IO uint32_t OFR4; /*!< ADC offset register 4, Address offset: 0x6C */ uint32_t RESERVED6[4]; /*!< Reserved, 0x070 - 0x07C */ __IO uint32_t JDR1; /*!< ADC injected data register 1, Address offset: 0x80 */ __IO uint32_t JDR2; /*!< ADC injected data register 2, Address offset: 0x84 */ __IO uint32_t JDR3; /*!< ADC injected data register 3, Address offset: 0x88 */ __IO uint32_t JDR4; /*!< ADC injected data register 4, Address offset: 0x8C */ uint32_t RESERVED7[4]; /*!< Reserved, 0x090 - 0x09C */ __IO uint32_t AWD2CR; /*!< ADC Analog Watchdog 2 Configuration Register, Address offset: 0xA0 */ __IO uint32_t AWD3CR; /*!< ADC Analog Watchdog 3 Configuration Register, Address offset: 0xA4 */ uint32_t RESERVED8; /*!< Reserved, 0x0A8 */ uint32_t RESERVED9; /*!< Reserved, 0x0AC */ __IO uint32_t LTR2; /*!< ADC watchdog Lower threshold register 2, Address offset: 0xB0 */ __IO uint32_t HTR2; /*!< ADC watchdog Higher threshold register 2, Address offset: 0xB4 */ __IO uint32_t LTR3; /*!< ADC watchdog Lower threshold register 3, Address offset: 0xB8 */ __IO uint32_t HTR3; /*!< ADC watchdog Higher threshold register 3, Address offset: 0xBC */ __IO uint32_t DIFSEL; /*!< ADC Differential Mode Selection Register, Address offset: 0xC0 */ __IO uint32_t CALFACT; /*!< ADC Calibration Factors, Address offset: 0xC4 */ __IO uint32_t CALFACT2; /*!< ADC Linearity Calibration Factors, Address offset: 0xC8 */ } ADC_TypeDef; typedef struct { __IO uint32_t CSR; /*!< ADC Common status register, Address offset: ADC1/3 base address + 0x300 */ uint32_t RESERVED; /*!< Reserved, ADC1/3 base address + 0x304 */ __IO uint32_t CCR; /*!< ADC common control register, Address offset: ADC1/3 base address + 0x308 */ __IO uint32_t CDR; /*!< ADC common regular data register for dual Address offset: ADC1/3 base address+0x30C */ __IO uint32_t CDR2; /*!< ADC common regular data register for 32-bit dual mode Address offset: ADC1/3 base address + 0x310 */ } ADC_Common_TypeDef;
__IO表示volatile, 這是標准C語言中的一個修飾字,表示這個變量是非易失性的,編譯器不要將其優化掉。core_m7.h 文件定義了這個宏:
#define __O volatile /*!< Defines 'write only' permissions */ #define __IO volatile /*!< Defines 'read / write' permissions */
結構體變量ADC_TypeDef用於ADC1,ADC2和ADC3,每個ADC都有一組。結構體變量ADC_Common_TypeDef是公共寄存器,ADC1和ADC2共用一組,而ADC3單獨用一組。
下面我們再看ADC1,ADC2和ADC3以及公共寄存器的定義,在stm32h743xx.h文件。
#define PERIPH_BASE ((uint32_t)0x40000000) #define D2_AHB1PERIPH_BASE (PERIPH_BASE + 0x00020000) #define D3_AHB1PERIPH_BASE (PERIPH_BASE + 0x18020000) #define ADC1_BASE (D2_AHB1PERIPH_BASE + 0x2000) #define ADC2_BASE (D2_AHB1PERIPH_BASE + 0x2100) #define ADC12_COMMON_BASE (D2_AHB1PERIPH_BASE + 0x2300) #define ADC3_BASE (D3_AHB1PERIPH_BASE + 0x6000) #define ADC3_COMMON_BASE (D3_AHB1PERIPH_BASE + 0x6300) #define ADC1 ((ADC_TypeDef *) ADC1_BASE) <----- 展開這個宏,(ADC_TypeDef *) 0x40022000 #define ADC2 ((ADC_TypeDef *) ADC2_BASE) #define ADC3 ((ADC_TypeDef *) ADC3_BASE) #define ADC12_COMMON ((ADC_Common_TypeDef *) ADC12_COMMON_BASE) #define ADC3_COMMON ((ADC_Common_TypeDef *) ADC3_COMMON_BASE)
我們訪問ADC1的ISR寄存器可以采用這種形式:ADC1->ISR = 0;
44.3.2 ADC句柄結構體ADC_HandleTypeDef
HAL庫在ADC_TypeDef的基礎上封裝了一個結構體ADC_HandleTypeDef,定義如下:
typedef struct { ADC_TypeDef *Instance; ADC_InitTypeDef Init; DMA_HandleTypeDef *DMA_Handle; HAL_LockTypeDef Lock; __IO uint32_t State; __IO uint32_t ErrorCode; ADC_InjectionConfigTypeDef InjectionConfig ; }ADC_HandleTypeDef;
下面將這幾個參數逐一做個說明。
- ADC_TypeDef *Instance
這個參數是寄存器的例化,方便操作寄存器,比如使能ADC內部穩壓器。
SET_BIT(hadc->Instance->CR, ADC_CR_ADVREGEN);
- DMA_InitTypeDef Init;
這個參數是用戶接觸最多的,用於配置ADC的基本參數,像ADC時鍾、分辨率、掃描模式、過采樣等。ADC_InitTypeDef結構體的定義如下:
typedef struct { uint32_t ClockPrescaler; uint32_t Resolution; uint32_t ScanConvMode; uint32_t EOCSelection; FunctionalState LowPowerAutoWait; FunctionalState ContinuousConvMode; uint32_t NbrOfConversion; FunctionalState DiscontinuousConvMode; uint32_t NbrOfDiscConversion; uint32_t ExternalTrigConv; uint32_t ExternalTrigConvEdge; uint32_t ConversionDataManagement; uint32_t Overrun; uint32_t LeftBitShift; FunctionalState BoostMode; FunctionalState OversamplingMode; ADC_OversamplingTypeDef Oversampling; }ADC_InitTypeDef;
具體每個成員的含義在本章3.3小節有說明。
- DMA_HandleTypeDef *DMA_Handle;
如果ADC使用DMA模式的話,此參數用於關聯DMA的句柄,方便DMA的配置。
- HAL_LockTypeDef Lock
__IO uint32_t State;
__IO uint32_t ErrorCode
這三個變量主要供函數內部使用。Lock用於設置鎖狀態,State用於設置ADC通信狀態,而ErrorCode用於配置代碼錯誤。
- ADC_InjectionConfigTypeDef InjectionConfig
用於配置ADC注入模式。
44.3.3 ADC參數初始化結構體ADC_InitTypeDef
參數初始化結構體ADC _InitTypeDef要注意的事項比較多,所以專門開一個小節單獨說明。
跟寄存器結構體ADC_TypeDef一樣,參數初始化結構體ADC_InitTypeDef也是封裝在了ADC的句柄結構體ADC_HandleTypeDef里面,定義如下:
typedef struct { uint32_t ClockPrescaler; uint32_t Resolution; uint32_t ScanConvMode; uint32_t EOCSelection; FunctionalState LowPowerAutoWait; FunctionalState ContinuousConvMode; uint32_t NbrOfConversion; FunctionalState DiscontinuousConvMode; uint32_t NbrOfDiscConversion; uint32_t ExternalTrigConv; uint32_t ExternalTrigConvEdge; uint32_t ConversionDataManagement; uint32_t Overrun; uint32_t LeftBitShift; FunctionalState BoostMode; FunctionalState OversamplingMode; ADC_OversamplingTypeDef Oversampling; }ADC_InitTypeDef;
下面將這幾個參數逐一做說明:
ClockPrescaler
用於ADC的時鍾分頻設置,ADC有兩種時鍾源可供選擇,可以使用來自AHB總線的系統時鍾(屬於同步時鍾),也可以使用PLL2,PLL3,HSE,HSI或者CSI時鍾(屬於異步時鍾)。
- ADC1,ADC2和ADC3共用選擇的時鍾。
- ADC的時鍾源使用AHB時鍾,且使用注入模式,那么在16bit,14bit,12bit或者10bit分辨率時,ADC的時鍾不能超過AHB時鍾的四分之一。8bit模式時,不能超過AHB時鍾的三分之一。
- 選擇AHB時鍾的話,ADC的配置中提供了不分頻,二分頻和四分頻。如果選擇了不分頻,那么配置AHB的時鍾輸出時也不可以設置分頻,即RCC的CFGR寄存器配置不可分頻。
- 如果使用PLL時鍾,運行期間要一直開啟,不可關閉。
- 此參數僅可以在關閉ADC的時候配置。
有以下幾種參數可供選擇:
/** @defgroup ADC_ClockPrescaler ADC clock source and clock prescaler * @{ */ #define ADC_CLOCK_SYNC_PCLK_DIV1 ((uint32_t)ADC_CCR_CKMODE_0) #define ADC_CLOCK_SYNC_PCLK_DIV2 ((uint32_t)ADC_CCR_CKMODE_1) #define ADC_CLOCK_SYNC_PCLK_DIV4 ((uint32_t)ADC_CCR_CKMODE) #define ADC_CLOCKPRESCALER_PCLK_DIV1 ADC_CLOCK_SYNC_PCLK_DIV1 /* 這三個僅僅是為了兼容,已經不推薦使用 */ #define ADC_CLOCKPRESCALER_PCLK_DIV2 ADC_CLOCK_SYNC_PCLK_DIV2 #define ADC_CLOCKPRESCALER_PCLK_DIV4 ADC_CLOCK_SYNC_PCLK_DIV4 #define ADC_CLOCK_ASYNC_DIV1 ((uint32_t)0x00000000) #define ADC_CLOCK_ASYNC_DIV2 ((uint32_t)ADC_CCR_PRESC_0) #define ADC_CLOCK_ASYNC_DIV4 ((uint32_t)ADC_CCR_PRESC_1) #define ADC_CLOCK_ASYNC_DIV6 ((uint32_t)(ADC_CCR_PRESC_1|ADC_CCR_PRESC_0)) #define ADC_CLOCK_ASYNC_DIV8 ((uint32_t)(ADC_CCR_PRESC_2)) #define ADC_CLOCK_ASYNC_DIV10 ((uint32_t)(ADC_CCR_PRESC_2|ADC_CCR_PRESC_0)) #define ADC_CLOCK_ASYNC_DIV12 ((uint32_t)(ADC_CCR_PRESC_2|ADC_CCR_PRESC_1)) #define ADC_CLOCK_ASYNC_DIV16 ((uint32_t)(ADC_CCR_PRESC_2|ADC_CCR_PRESC_1|ADC_CCR_PRESC_0)) #define ADC_CLOCK_ASYNC_DIV32 ((uint32_t)(ADC_CCR_PRESC_3)) #define ADC_CLOCK_ASYNC_DIV64 ((uint32_t)(ADC_CCR_PRESC_3|ADC_CCR_PRESC_0)) #define ADC_CLOCK_ASYNC_DIV128 ((uint32_t)(ADC_CCR_PRESC_3|ADC_CCR_PRESC_1)) #define ADC_CLOCK_ASYNC_DIV256 ((uint32_t)(ADC_CCR_PRESC_3|ADC_CCR_PRESC_1|ADC_CCR_PRESC_0))
Resolution
用於ADC的分辨率配置,支持如下幾種:
/** @defgroup ADC_Resolution ADC Resolution * @{ */ #define ADC_RESOLUTION_16B ((uint32_t)0x00000000) #define ADC_RESOLUTION_14B ((uint32_t)ADC_CFGR_RES_0) #define ADC_RESOLUTION_12B ((uint32_t)ADC_CFGR_RES_1) #define ADC_RESOLUTION_10B ((uint32_t)(ADC_CFGR_RES_1 | ADC_CFGR_RES_0)) #define ADC_RESOLUTION_8B ((uint32_t)ADC_CFGR_RES_2)
ScanConvMode
用於使能或者禁止ADC的掃描模式,即多通道轉換。此參數配合成員DiscontinuousConvMode可以將主轉換序列分成多個子系列進行逐步轉換。
- 禁止掃描模式,表示單通道轉換,成員NbrOfConversion和InjectedNbrOfConversion不起作用,等效為1,即僅進行一個通道轉換。
- 使能掃描模式,表示支持多通道轉換,成員NbrOfConversion和InjectedNbrOfConversion分別用於規則通道和注入通道轉換序列數。
支持的參數如下:
#define ADC_SCAN_DISABLE ((uint32_t)0x00000000) #define ADC_SCAN_ENABLE ((uint32_t)0x00000001)
EOCSelection
用於中斷或者查詢模式時,轉換結束標志EOC (End Of Conversion)的選擇。參數可以單通道轉換結束或者序列轉換結束:
#define ADC_EOC_SINGLE_CONV ((uint32_t) ADC_ISR_EOC) /*!< End of unitary conversion flag */ #define ADC_EOC_SEQ_CONV ((uint32_t) ADC_ISR_EOS) /*!< End of sequence conversions flag */
LowPowerAutoWait
用於使能或者禁止低功耗自動延遲等待模式。僅當用戶調用函數HAL_ADC_GetValue()獲取規則通道數據或者調用函數HAL_ADCEx_InjectedGetValue()獲取注入通道數據后才會開啟下一次ADC轉換。
- 此功能可自動將ADC觸發頻率調整為讀取數據速度,即完全由用戶決定的自適應模式。這樣可以避免溢出,適用於低頻應用。
- 此模式僅可用於ADC的查詢模式,不可用於中斷或者DMA模式,即調用函數HAL_ADC_Start_IT()或者HAL_ADC_Start_DMA(),因為這種模式會立即清除EOC轉換結束標志,從而釋放中斷請求向量序列。
- 使用查詢模式的調用方法:
- 調用函數HAL_ADC_Start啟動轉換。
- 調用函數HAL_ADC_PollForConversion等待轉換結束,然后調用函數HAL_ADC_GetValue可以獲取當前的轉換值,並且會自動啟動下次轉換。
- 如果是注入通道,就是調用函數HAL_ADCExInjected_Start()啟動轉換,調用函數HAL_ADCEx_InjectedGetValue()獲取轉換數據。
參數可以是使能ENABLE或者禁能DISABLE。
ContinuousConvMode
用於配置使用單次轉換還是連續轉換,此參數僅對規則通道有效。觸發方式可以選擇軟件觸發或者外部觸發。
參數可以是使能ENABLE,表示連續轉換或者DISABLE禁能,表示單次轉換。
NbrOfConversion
用於配置規則通道要轉換的通道數。
- 如果要進行多個通道的轉換,參數成員ScanConvMode必須使能。
- 通道數范圍1到16。
- 僅當規則通道上沒有后續的轉換時才可以修改此參數(即ADC禁止的情況下或者ADC單次轉換模式,又或者無外部觸發)。
DiscontinuousConvMode
用於配置ADC規則組轉換序列的不連續方式。這里的不連續含義是指每次觸發進行一個子組的轉換。注意跟參數成員ContinuousConvMode的含義區分開。
- 使能此參數,要轉換的整個序列通道1,2,6,7,8,10,設置2個為一個子組,那么第1次觸發會進行通道1和通道2的轉換,下次觸發進行通道6和通道7的轉換,以此進行了。
- 禁止此參數,要轉換的整個序列通道1,2,6,7,8,10,那么第1次觸發會進行所有通道的轉換。
使用此參數要注意以下兩點:
- 只有參數成員ScanConvMode使能的情況下,此參數才有使用的意義,否則忽略此參數。
- 只有參數成員ContinuousConvMode禁止的情況下,此參數才有使用的意義,否則忽略此參數。也就是說這兩個參數不能同時使能。
參數可以是使能ENABLE或者禁止DISABLE。
NbrOfDiscConversion
使能了參數DiscontinuousConvMode的情況下,用於設置子組的大小。
- 僅用於規則通道。
- 如果參數DiscontinuousConvMode禁止的情況下,忽略此參數。
- 此參數范圍1到8。
ExternalTrigConv
用於規則通道外部觸發源的選擇。如果使能了軟件觸發,那么外部觸發將被關閉,使用軟件觸發。ADC1,ADC2和ADC3支持的觸發源是相同的。具體支持的觸發源參數如下:
/** @defgroup ADC_regular_external_trigger_source ADC group regular trigger source * @{ */ /* External triggers of regular group for ADC1, ADC2, ADC3 */ #define ADC_EXTERNALTRIG_T1_CC1 ((uint32_t)0x00000000) #define ADC_EXTERNALTRIG_T1_CC2 ((uint32_t)ADC_CFGR_EXTSEL_0) #define ADC_EXTERNALTRIG_T1_CC3 ((uint32_t)ADC_CFGR_EXTSEL_1) #define ADC_EXTERNALTRIG_T2_CC2 ((uint32_t)(ADC_CFGR_EXTSEL_1 | ADC_CFGR_EXTSEL_0)) #define ADC_EXTERNALTRIG_T3_TRGO ((uint32_t)ADC_CFGR_EXTSEL_2) #define ADC_EXTERNALTRIG_T4_CC4 ((uint32_t)(ADC_CFGR_EXTSEL_2 | ADC_CFGR_EXTSEL_0)) #define ADC_EXTERNALTRIG_EXT_IT11 ((uint32_t)(ADC_CFGR_EXTSEL_2 | ADC_CFGR_EXTSEL_1)) #define ADC_EXTERNALTRIG_T8_TRGO ((uint32_t)(ADC_CFGR_EXTSEL_2 | ADC_CFGR_EXTSEL_1 | ADC_CFGR_EXTSEL_0)) #define ADC_EXTERNALTRIG_T8_TRGO2 ((uint32_t) ADC_CFGR_EXTSEL_3) #define ADC_EXTERNALTRIG_T1_TRGO ((uint32_t)(ADC_CFGR_EXTSEL_3 | ADC_CFGR_EXTSEL_0)) #define ADC_EXTERNALTRIG_T1_TRGO2 ((uint32_t)(ADC_CFGR_EXTSEL_3 | ADC_CFGR_EXTSEL_1)) #define ADC_EXTERNALTRIG_T2_TRGO ((uint32_t)(ADC_CFGR_EXTSEL_3 | ADC_CFGR_EXTSEL_1 | ADC_CFGR_EXTSEL_0)) #define ADC_EXTERNALTRIG_T4_TRGO ((uint32_t)(ADC_CFGR_EXTSEL_3 | ADC_CFGR_EXTSEL_2)) #define ADC_EXTERNALTRIG_T6_TRGO ((uint32_t)(ADC_CFGR_EXTSEL_3 | ADC_CFGR_EXTSEL_2 | ADC_CFGR_EXTSEL_0)) #define ADC_EXTERNALTRIG_T15_TRGO ((uint32_t)(ADC_CFGR_EXTSEL_3 | ADC_CFGR_EXTSEL_2 | ADC_CFGR_EXTSEL_1)) #define ADC_EXTERNALTRIG_T3_CC4 ((uint32_t)(ADC_CFGR_EXTSEL_3 | ADC_CFGR_EXTSEL_2 | ADC_CFGR_EXTSEL_1 | ADC_CFGR_EXTSEL_0)) #define ADC_EXTERNALTRIG_HR1_ADCTRG1 ((uint32_t) ADC_CFGR_EXTSEL_4) #define ADC_EXTERNALTRIG_HR1_ADCTRG3 ((uint32_t) (ADC_CFGR_EXTSEL_4 | ADC_CFGR_EXTSEL_0)) #define ADC_EXTERNALTRIG_LPTIM1_OUT ((uint32_t) (ADC_CFGR_EXTSEL_4 | ADC_CFGR_EXTSEL_1)) #define ADC_EXTERNALTRIG_LPTIM2_OUT ((uint32_t) (ADC_CFGR_EXTSEL_4 | ADC_CFGR_EXTSEL_1| ADC_CFGR_EXTSEL_0)) #define ADC_EXTERNALTRIG_LPTIM3_OUT ((uint32_t) (ADC_CFGR_EXTSEL_4 | ADC_CFGR_EXTSEL_2))
ExternalTrigConvEdge
如果使用外部觸發的話,設置觸發沿類型,支持上升沿、下降沿或者雙沿觸發。
#define ADC_EXTERNALTRIGCONVEDGE_NONE ((uint32_t)0x00000000) #define ADC_EXTERNALTRIGCONVEDGE_RISING ((uint32_t)ADC_CFGR_EXTEN_0) #define ADC_EXTERNALTRIGCONVEDGE_FALLING ((uint32_t)ADC_CFGR_EXTEN_1) #define ADC_EXTERNALTRIGCONVEDGE_RISINGFALLING ((uint32_t)ADC_CFGR_EXTEN)
注意,如果使能了軟件觸發,那么外部觸發將被關閉,使用軟件觸發,此參數已經不起作用。
ConversionDataManagement
此參數成員用於ADC采集數據的管理,可以存到ADC的DR寄存器,傳輸給DFSDM,又或者通過DMA的單次或者循環模式傳輸數據到指定地址。
/** @defgroup ADC_ConversionDataManagement ADC Conversion Data Management * @{ */ #define ADC_CONVERSIONDATA_DR ((uint32_t)0x00000000) #define ADC_CONVERSIONDATA_DFSDM ((uint32_t)ADC_CFGR_DMNGT_1) #define ADC_CONVERSIONDATA_DMA_ONESHOT ((uint32_t)ADC_CFGR_DMNGT_0) #define ADC_CONVERSIONDATA_DMA_CIRCULAR ((uint32_t)(ADC_CFGR_DMNGT_0 | ADC_CFGR_DMNGT_1))
使用此參數成員注意以下問題:
- 如果參數成員ContinuousConvMode配置為連續轉換模式,那么DMA必須配置為循環模式,否則會造成DMA傳輸溢出。
- 僅當規則通道上沒有后續的轉換時才可以修改此參數(即ADC禁止的情況下或者ADC單次轉換模式,又或者無外部觸發)。
Overrun
用於配置ADC轉換數據未及時讀取,造成溢出時的處理,可以選擇繼續保留上次轉換的數據,也可以選擇新轉換的數據覆蓋,具體支持的參數如下:
#define ADC_OVR_DATA_PRESERVED ((uint32_t)0x00000000) #define ADC_OVR_DATA_OVERWRITTEN ((uint32_t)ADC_CFGR_OVRMOD)
使用此參數成員注意以下問題:
此參數僅可用於規則通道。
- 如果此參數設置為保留上次轉換的數據,且使用函數HAL_ADC_Start_IT的中斷服務程序里面去的清除轉換結束標志會導致保存的數據被釋放。針對這種情況,用戶可以在中斷服務程序的回調函數HAL_ADC_ConvCpltCallback里面保存轉換的數據(此回調函數是在清除轉換結束標志前調用)。
- 如果ADC轉換采用查詢或者中斷方式且此參數被設置為保留上次轉換的數據,會產生錯誤報告。此參數設置為覆蓋方式,那么用戶不讀取數據時,不會被視為溢出錯誤。
- 如果ADC轉換采用DMA方式,不管此參數配置為何種方式,都會報告溢出錯誤(因為DMA是需要處理所有轉換的數據)。
LeftBitShift
用於設置ADC轉換結果的左移位數,使用或者沒有使用過采樣的情況下,都可以使用此參數。
具體支持的參數如下:
#define ADC_LEFTBITSHIFT_NONE ((uint32_t)0x00000000) #define ADC_LEFTBITSHIFT_1 ((uint32_t)ADC_CFGR2_LSHIFT_0) #define ADC_LEFTBITSHIFT_2 ((uint32_t)ADC_CFGR2_LSHIFT_1) #define ADC_LEFTBITSHIFT_3 ((uint32_t)(ADC_CFGR2_LSHIFT_1 | ADC_CFGR2_LSHIFT_0)) #define ADC_LEFTBITSHIFT_4 ((uint32_t)ADC_CFGR2_LSHIFT_2) #define ADC_LEFTBITSHIFT_5 ((uint32_t)(ADC_CFGR2_LSHIFT_2 | ADC_CFGR2_LSHIFT_0)) #define ADC_LEFTBITSHIFT_6 ((uint32_t)(ADC_CFGR2_LSHIFT_2 | ADC_CFGR2_LSHIFT_1)) #define ADC_LEFTBITSHIFT_7 ((uint32_t)(ADC_CFGR2_LSHIFT_2 | ADC_CFGR2_LSHIFT_1 | ADC_CFGR2_LSHIFT_0)) #define ADC_LEFTBITSHIFT_8 ((uint32_t)ADC_CFGR2_LSHIFT_3) #define ADC_LEFTBITSHIFT_9 ((uint32_t)(ADC_CFGR2_LSHIFT_3 | ADC_CFGR2_LSHIFT_0)) #define ADC_LEFTBITSHIFT_10 ((uint32_t)(ADC_CFGR2_LSHIFT_3 | ADC_CFGR2_LSHIFT_1)) #define ADC_LEFTBITSHIFT_11 ((uint32_t)(ADC_CFGR2_LSHIFT_3 | ADC_CFGR2_LSHIFT_1 | ADC_CFGR2_LSHIFT_0)) #define ADC_LEFTBITSHIFT_12 ((uint32_t)(ADC_CFGR2_LSHIFT_3 | ADC_CFGR2_LSHIFT_2)) #define ADC_LEFTBITSHIFT_13 ((uint32_t)(ADC_CFGR2_LSHIFT_3 | ADC_CFGR2_LSHIFT_2 | ADC_CFGR2_LSHIFT_0)) #define ADC_LEFTBITSHIFT_14 ((uint32_t)(ADC_CFGR2_LSHIFT_3 | ADC_CFGR2_LSHIFT_2 | ADC_CFGR2_LSHIFT_1)) #define ADC_LEFTBITSHIFT_15 ((uint32_t)(ADC_CFGR2_LSHIFT_3 | ADC_CFGR2_LSHIFT_2 | ADC_CFGR2_LSHIFT_1 | ADC_CFGR2_LSHIFT_0))
BoostMode
用於設置ADC的BOOST模式,當ADC的時鍾高於20MHz時,必須使能此位。
參數可以是使能ENABLE或者禁止DISABLE。
OversamplingMode
此參數成員用於使能或者禁止過采樣模式。只有當ADC規則通道或者注入通道沒有數據轉換時才可以修改此參數。
參數可以是使能ENABLE或者禁止DISABLE。
Oversampling
此參數是ADC_OversamplingTypeDef類型結構體變量,用於設置過采樣的相關參數。
44.3.4 ADC通道配置結構體ADC_ChannelConfTypeDef
結構體變量ADC_ChannelConfTypeDef用於配置ADC規則通道的一些特性,定義如下:
typedef struct { uint32_t Channel; uint32_t Rank; uint32_t SamplingTime; uint32_t SingleDiff; uint32_t OffsetNumber; uint32_t Offset; FunctionalState OffsetRightShift; FunctionalState OffsetSignedSaturation; }ADC_ChannelConfTypeDef;
下面將這幾個參數逐一做說明:
Channel
具體支持的通道參數如下:
/** @defgroup ADC_channels ADC Channels * @{ */ #define ADC_CHANNEL_0 ((uint32_t)(0x00000000)) #define ADC_CHANNEL_1 ((uint32_t)(ADC_SQR3_SQ10_0)) #define ADC_CHANNEL_2 ((uint32_t)(ADC_SQR3_SQ10_1)) #define ADC_CHANNEL_3 ((uint32_t)(ADC_SQR3_SQ10_1 | ADC_SQR3_SQ10_0)) #define ADC_CHANNEL_4 ((uint32_t)(ADC_SQR3_SQ10_2)) #define ADC_CHANNEL_5 ((uint32_t)(ADC_SQR3_SQ10_2 | ADC_SQR3_SQ10_0)) #define ADC_CHANNEL_6 ((uint32_t)(ADC_SQR3_SQ10_2 | ADC_SQR3_SQ10_1)) #define ADC_CHANNEL_7 ((uint32_t)(ADC_SQR3_SQ10_2 | ADC_SQR3_SQ10_1 | ADC_SQR3_SQ10_0)) #define ADC_CHANNEL_8 ((uint32_t)(ADC_SQR3_SQ10_3)) #define ADC_CHANNEL_9 ((uint32_t)(ADC_SQR3_SQ10_3 | ADC_SQR3_SQ10_0)) #define ADC_CHANNEL_10 ((uint32_t)(ADC_SQR3_SQ10_3 | ADC_SQR3_SQ10_1)) #define ADC_CHANNEL_11 ((uint32_t)(ADC_SQR3_SQ10_3 | ADC_SQR3_SQ10_1 | ADC_SQR3_SQ10_0)) #define ADC_CHANNEL_12 ((uint32_t)(ADC_SQR3_SQ10_3 | ADC_SQR3_SQ10_2)) #define ADC_CHANNEL_13 ((uint32_t)(ADC_SQR3_SQ10_3 | ADC_SQR3_SQ10_2 | ADC_SQR3_SQ10_0)) #define ADC_CHANNEL_14 ((uint32_t)(ADC_SQR3_SQ10_3 | ADC_SQR3_SQ10_2 | ADC_SQR3_SQ10_1)) #define ADC_CHANNEL_15 ((uint32_t)(ADC_SQR3_SQ10_3 | ADC_SQR3_SQ10_2 | ADC_SQR3_SQ10_1 | ADC_SQR3_SQ10_0)) #define ADC_CHANNEL_16 ((uint32_t)(ADC_SQR3_SQ10_4)) #define ADC_CHANNEL_17 ((uint32_t)(ADC_SQR3_SQ10_4 | ADC_SQR3_SQ10_0)) #define ADC_CHANNEL_18 ((uint32_t)(ADC_SQR3_SQ10_4 | ADC_SQR3_SQ10_1)) #define ADC_CHANNEL_19 ((uint32_t)(ADC_SQR3_SQ10_4 | ADC_SQR3_SQ10_1| ADC_SQR3_SQ10_0)) /* Note: Vbat/4, TempSensor and VREFINT internal channels are available on ADC3 only */ #define ADC_CHANNEL_VBAT_DIV4 ADC_CHANNEL_17 #define ADC_CHANNEL_TEMPSENSOR ADC_CHANNEL_18 #define ADC_CHANNEL_VREFINT ADC_CHANNEL_19 /* Note: DAC1CH1 and DAC1CH2 internal channels is available on ADC2 only */ /*!< ADC internal channel connected to DAC1 channel 1, channel specific to ADC2 */ #define ADC_CHANNEL_DAC1CH1_ADC2 (ADC_CHANNEL_16) /*!< ADC internal channel connected to DAC1 channel 2, channel specific to ADC2 */ #define ADC_CHANNEL_DAC1CH2_ADC2 (ADC_CHANNEL_17)
這里要特別注意:
- VBAT、溫度傳感器和VREFINT僅ADC3可用。
- DAC1的兩個通道在內部連接至ADC2,也就是說僅ADC2可用。
Rank
用於配置規則通道的轉換順序,如果想禁止一個通道或者改變一個通道的順序,可以使用新配置覆蓋。
具體支持的參數如下:
/** @defgroup ADC_regular_rank ADC group regular sequencer rank * @{ */ #define ADC_REGULAR_RANK_1 ((uint32_t)0x00000001) /*!< ADC regular conversion rank 1 */ #define ADC_REGULAR_RANK_2 ((uint32_t)0x00000002) /*!< ADC regular conversion rank 2 */ #define ADC_REGULAR_RANK_3 ((uint32_t)0x00000003) /*!< ADC regular conversion rank 3 */ #define ADC_REGULAR_RANK_4 ((uint32_t)0x00000004) /*!< ADC regular conversion rank 4 */ #define ADC_REGULAR_RANK_5 ((uint32_t)0x00000005) /*!< ADC regular conversion rank 5 */ #define ADC_REGULAR_RANK_6 ((uint32_t)0x00000006) /*!< ADC regular conversion rank 6 */ #define ADC_REGULAR_RANK_7 ((uint32_t)0x00000007) /*!< ADC regular conversion rank 7 */ #define ADC_REGULAR_RANK_8 ((uint32_t)0x00000008) /*!< ADC regular conversion rank 8 */ #define ADC_REGULAR_RANK_9 ((uint32_t)0x00000009) /*!< ADC regular conversion rank 9 */ #define ADC_REGULAR_RANK_10 ((uint32_t)0x0000000A) /*!< ADC regular conversion rank 10 */ #define ADC_REGULAR_RANK_11 ((uint32_t)0x0000000B) /*!< ADC regular conversion rank 11 */ #define ADC_REGULAR_RANK_12 ((uint32_t)0x0000000C) /*!< ADC regular conversion rank 12 */ #define ADC_REGULAR_RANK_13 ((uint32_t)0x0000000D) /*!< ADC regular conversion rank 13 */ #define ADC_REGULAR_RANK_14 ((uint32_t)0x0000000E) /*!< ADC regular conversion rank 14 */ #define ADC_REGULAR_RANK_15 ((uint32_t)0x0000000F) /*!< ADC regular conversion rank 15 */ #define ADC_REGULAR_RANK_16 ((uint32_t)0x00000010) /*!< ADC regular conversion rank 16 */
SamplingTime
用於所選通道的采樣時間配置,ADC的采樣速度是由采樣時間和轉換時間同決定。用於內部通道測量時(VrefInt/Vbat/TempSensor),務必要遵循數據手冊要求的參數范圍。此參數成員具體支持的定義如下:
/** @defgroup ADC_sampling_times ADC Sampling Times * @{ */ #define ADC_SAMPLETIME_1CYCLE_5 ((uint32_t)0x00000000) #define ADC_SAMPLETIME_2CYCLES_5 ((uint32_t)ADC_SMPR2_SMP10_0) #define ADC_SAMPLETIME_8CYCLES_5 ((uint32_t)ADC_SMPR2_SMP10_1) #define ADC_SAMPLETIME_16CYCLES_5 ((uint32_t)(ADC_SMPR2_SMP10_1 | ADC_SMPR2_SMP10_0)) #define ADC_SAMPLETIME_32CYCLES_5 ((uint32_t)ADC_SMPR2_SMP10_2) #define ADC_SAMPLETIME_64CYCLES_5 ((uint32_t)(ADC_SMPR2_SMP10_2 | ADC_SMPR2_SMP10_0)) #define ADC_SAMPLETIME_387CYCLES_5 ((uint32_t)(ADC_SMPR2_SMP10_2 | ADC_SMPR2_SMP10_1)) #define ADC_SAMPLETIME_810CYCLES_5 ((uint32_t)ADC_SMPR2_SMP10)
SingleDiff
此參數成員用於選擇單端輸入還是差分輸入。差分輸入要用到輸入通道i(正向輸入)和i+1反向輸入,用戶僅需配置通道i即可,通道i+1會被自動配置。具體支持的定義如下:
/** @defgroup ADCEx_SingleDifferential ADC Extended Single-ended/Differential input mode * @{ */ #define ADC_SINGLE_ENDED ((uint32_t)0x00000000) #define ADC_DIFFERENTIAL_ENDED ((uint32_t)ADC_CR_ADCALDIF)
使用此參數要注意以下問題:
- 如果用於差分模式,要注意選擇的通道是正確的。
- 如果配置了通道i為差分模式,不可再配置通道i+1。
- ADC禁止期間才可以修改此參數,ADC使能后修改此參數會被忽略,也不會報錯。
OffsetNumber
此參數成員用於選擇偏移序號Offset Number,具體支持的參數定義如下:
/** @defgroup ADCEx_OffsetNumber ADC Extended Offset Number * @{ */ #define ADC_OFFSET_NONE ((uint32_t)0x00) /*!< No offset correction */ #define ADC_OFFSET_1 ((uint32_t)0x01) /*!< Offset correction to apply to a first channel */ #define ADC_OFFSET_2 ((uint32_t)0x02) /*!< Offset correction to apply to a second channel */ #define ADC_OFFSET_3 ((uint32_t)0x03) /*!< Offset correction to apply to a third channel */ #define ADC_OFFSET_4 ((uint32_t)0x04) /*!< Offset correction to apply to a fourth channel */
注意,每個通道僅支持一個偏移設置。
Offset
定義要從原始數據中減去的偏移量。
- 偏移量必須是正數。
- 根據用戶配置的ADC分辨率為16bit,14bit,12bit,10bit或者8bit,偏移量的最小值為0x0000,最大值分別為0xFFFF,0x3FFF, 0xFFF, 0x3FF 和 0xFF。
- 僅當規則通道或者注入通道上沒有后續的轉換時才可以修改此參數(即ADC禁止的情況下或者ADC單次轉換模式,又或者無外部觸發)。
OffsetRightShift
此參數成員用於選擇是否使能偏移校准后數據右移,僅適用於16bit或者8bit分辨率。
支持的參數可以是使能ENABLE或者禁止DISABLE。
OffsetSignedSaturation
此參數成員用於選擇是否使能有符號飽和特性,僅適用於16bit或者8bit分辨率。
支持的參數可以是使能ENABLE或者禁止DISABLE。
44.3.5 ADC過采樣結構體ADC_OversamplingTypeDef
結構體ADC_OversamplingTypeDef主要用於過采樣方面參數配置,定義如下:
typedef struct { uint32_t Ratio; uint32_t RightBitShift; uint32_t TriggeredMode; uint32_t OversamplingStopReset; }ADC_OversamplingTypeDef;
下面將這幾個參數逐一做說明:
Ratio
此參數成員用於配置過采樣率。
RightBitShift
此參數用於設置右移,即分頻因數。具體支持的參數如下:
/** @defgroup ADCEx_Right_Bit_Shift ADC Extended Oversampling Right Shift * @{ */ #define ADC_RIGHTBITSHIFT_NONE ((uint32_t)0x00000000) #define ADC_RIGHTBITSHIFT_1 ((uint32_t)ADC_CFGR2_OVSS_0) #define ADC_RIGHTBITSHIFT_2 ((uint32_t)ADC_CFGR2_OVSS_1) #define ADC_RIGHTBITSHIFT_3 ((uint32_t)(ADC_CFGR2_OVSS_1 | ADC_CFGR2_OVSS_0)) #define ADC_RIGHTBITSHIFT_4 ((uint32_t)ADC_CFGR2_OVSS_2) #define ADC_RIGHTBITSHIFT_5 ((uint32_t)(ADC_CFGR2_OVSS_2 | ADC_CFGR2_OVSS_0)) #define ADC_RIGHTBITSHIFT_6 ((uint32_t)(ADC_CFGR2_OVSS_2 | ADC_CFGR2_OVSS_1)) #define ADC_RIGHTBITSHIFT_7 ((uint32_t)(ADC_CFGR2_OVSS_2 | ADC_CFGR2_OVSS_1 | ADC_CFGR2_OVSS_0)) #define ADC_RIGHTBITSHIFT_8 ((uint32_t)ADC_CFGR2_OVSS_3) #define ADC_RIGHTBITSHIFT_9 ((uint32_t)(ADC_CFGR2_OVSS_3 | ADC_CFGR2_OVSS_0)) #define ADC_RIGHTBITSHIFT_10 ((uint32_t)(ADC_CFGR2_OVSS_3 | ADC_CFGR2_OVSS_1)) #define ADC_RIGHTBITSHIFT_11 ((uint32_t)(ADC_CFGR2_OVSS_3 | ADC_CFGR2_OVSS_1 | ADC_CFGR2_OVSS_0))
TriggeredMode
此參數成員用於過采樣的觸發模式配置,具體支持的定義如下:
/** @defgroup ADCEx_Triggered_Oversampling_Mode ADC Extended Triggered Regular Oversampling * @{ */ #define ADC_TRIGGEREDMODE_SINGLE_TRIGGER ((uint32_t)0x00000000) #define ADC_TRIGGEREDMODE_MULTI_TRIGGER ((uint32_t)ADC_CFGR2_TROVS)
OversamplingStopReset
此參數成員用於配置使用注入通道時,過采樣的處理。可以選擇保持原有過采樣緩沖數據,或者緩沖數據清零。具體支持的定義如下:
/** @defgroup ADCEx_Regular_Oversampling_Mode ADC Extended Regular Oversampling Continued or Resumed Mode * @{ */ /*!< Oversampling buffer maintained during injection sequence */ #define ADC_REGOVERSAMPLING_CONTINUED_MODE ((uint32_t)0x00000000) /*!< Oversampling buffer zeroed during injection sequence */ #define ADC_REGOVERSAMPLING_RESUMED_MODE ((uint32_t)ADC_CFGR2_ROVSM)
注意,如果規則通道和注入通道同時使用過采樣,此參數成員的配置將被忽略,強制設置為ADC_REGOVERSAMPLING_RESUMED_MODE。
44.3.6 ADC模擬看門狗結構體ADC_AnalogWDGConfTypeDef
結構體ADC_AnalogWDGConfTypeDef主要用於模擬看門狗參數配置,ADC1,ADC2和ADC3都有三個模擬看門狗,結構體定義如下:
typedef struct { uint32_t WatchdogNumber; uint32_t WatchdogMode; uint32_t Channel; FunctionalState ITMode; uint32_t HighThreshold; uint32_t LowThreshold; }ADC_AnalogWDGConfTypeDef;
下面將這幾個參數逐一做說明:
WatchdogNumber
此參數成員用於配置選擇那個看門狗監測通道。
- 模擬看門狗1僅可以監測1個通道,或者通過成員WatchdogMode配置選擇監測所有通道。
- 模擬看門狗2和3可以檢測任意指定的通道,調用函數HAL_ADC_AnalogWDGConfig配置即可,要監測那個通道,調用一次這個函數。
具體支持的定義如下:
/** @defgroup ADCEx_analog_watchdog_number ADC Extended Analog Watchdog Selection * @{ */ #define ADC_ANALOGWATCHDOG_1 ((uint32_t)0x00000001) #define ADC_ANALOGWATCHDOG_2 ((uint32_t)0x00000002) #define ADC_ANALOGWATCHDOG_3 ((uint32_t)0x00000003)
WatchdogMode
此參數用於設置模擬看門狗模式。
- 模擬看門狗1可以配置監測單個通道或者所有通道,適用於規則通道和注入通道。
- 模擬看門狗2和3不支持監測所有通道,但可以監測指定的多個通道,每調用一次函數HAL_ADC_AnalogWDGConfig可以指定一個通道,如果此參數配置為ADC_ANALOGWATCHDOG_NONE,那么參數Channel配置的通道將被復位。
此參數具體支持的定義如下:
/** @defgroup ADCEx_analog_watchdog_mode ADC Extended Analog Watchdog Mode * @{ */ #define ADC_ANALOGWATCHDOG_NONE ((uint32_t) 0x00000000) #define ADC_ANALOGWATCHDOG_SINGLE_REG ((uint32_t)(ADC_CFGR_AWD1SGL | ADC_CFGR_AWD1EN)) #define ADC_ANALOGWATCHDOG_SINGLE_INJEC ((uint32_t)(ADC_CFGR_AWD1SGL | ADC_CFGR_JAWD1EN)) #define ADC_ANALOGWATCHDOG_SINGLE_REGINJEC ((uint32_t)(ADC_CFGR_AWD1SGL | ADC_CFGR_AWD1EN | ADC_CFGR_JAWD1EN)) #define ADC_ANALOGWATCHDOG_ALL_REG ((uint32_t) ADC_CFGR_AWD1EN) #define ADC_ANALOGWATCHDOG_ALL_INJEC ((uint32_t) ADC_CFGR_JAWD1EN) #define ADC_ANALOGWATCHDOG_ALL_REGINJEC ((uint32_t)(ADC_CFGR_AWD1EN | ADC_CFGR_JAWD1EN))
Channel
用於配置要監測的通道。
- 對於模擬看門狗1,參數成員WatchdogMode配置為單個通道時,此參數才有意義。
- 對於模擬看門狗2和3,每調用一次函數HAL_ADC_AnalogWDGConfig可以指定一個通道,如果要復位那個通道,將參數WatchdogMode配置為ADC_ANALOGWATCHDOG_NONE即可。
ITMode
用於配置模擬看門狗為中斷方式或者查詢方式。
配置為ENABEL表示使用中斷方式,配置為DISABLE表示查詢方式。
HighThreshold
用於配置模擬看門狗高閥值。根據配置的ADC的分辨率16, 14, 12, 10或者8bit,高閥值最小都是0x0000,最大值分別是0xFFFF, 0x3FFF, 0xFFF, 0x3FF 和 0xFF。
LowThreshold
用於配置模擬看門狗低閥值。根據配置的ADC的分辨率16, 14, 12, 10或者8bit,高閥值最小都是0x0000,最大值分別是0xFFFF, 0x3FFF, 0xFFF, 0x3FF 和 0xFF。
44.3.7 ADC的狀態標志清除問題
下面我們介紹__HAL_ADC_GET_FLAG函數。這個函數用來檢查ADC標志位是否被設置。
/** * @brief Checks whether the specified ADC flag is set or not. * @param __HANDLE__: ADC handle * @param __FLAG__: ADC flag to check * This parameter can be one of the following values: * @arg ADC_FLAG_RDY ADC Ready (ADRDY) flag * @arg ADC_FLAG_EOSMP ADC End of Sampling flag * @arg ADC_FLAG_EOC ADC End of Regular Conversion flag * @arg ADC_FLAG_EOS ADC End of Regular sequence of Conversions flag * @arg ADC_FLAG_OVR ADC overrun flag * @arg ADC_FLAG_JEOC ADC End of Injected Conversion flag * @arg ADC_FLAG_JEOS ADC End of Injected sequence of Conversions flag * @arg ADC_FLAG_AWD1 ADC Analog watchdog 1 flag (main analog watchdog) * @arg ADC_FLAG_AWD2 ADC Analog watchdog 2 flag (additional analog watchdog) * @arg ADC_FLAG_AWD3 ADC Analog watchdog 3 flag (additional analog watchdog) * @arg ADC_FLAG_JQOVF ADC Injected Context Queue Overflow flag * @retval The new state of __FLAG__ (TRUE or FALSE). */ #define __HAL_ADC_GET_FLAG(__HANDLE__, __FLAG__) ((((__HANDLE__)->Instance->ISR) & (__FLAG__)) == (__FLAG__))
與標志獲取函數__HAL_ADC_GET_FLAG對應的清除函數是__HAL_ADC_CLEAR_FLAG:
/** * @brief Clear a specified ADC flag * @param __HANDLE__: ADC handle * @param __FLAG__: ADC flag to clear * This parameter can be one of the following values: * @arg ADC_FLAG_RDY ADC Ready (ADRDY) flag * @arg ADC_FLAG_EOSMP ADC End of Sampling flag * @arg ADC_FLAG_EOC ADC End of Regular Conversion flag * @arg ADC_FLAG_EOS ADC End of Regular sequence of Conversions flag * @arg ADC_FLAG_OVR ADC overrun flag * @arg ADC_FLAG_JEOC ADC End of Injected Conversion flag * @arg ADC_FLAG_JEOS ADC End of Injected sequence of Conversions flag * @arg ADC_FLAG_AWD1 ADC Analog watchdog 1 flag (main analog watchdog) * @arg ADC_FLAG_AWD2 ADC Analog watchdog 2 flag (additional analog watchdog) * @arg ADC_FLAG_AWD3 ADC Analog watchdog 3 flag (additional analog watchdog) * @arg ADC_FLAG_JQOVF ADC Injected Context Queue Overflow flag * @note: bit cleared bit by writing 1 (writing 0 has no effect on any bit of register ISR) * @retval None */ #define __HAL_ADC_CLEAR_FLAG(__HANDLE__, __FLAG__) (((__HANDLE__)->Instance->ISR) = (__FLAG__))
清除標志函數所支持的參數跟獲取函數是一 一對應的。除了這兩個函數,還有ADC的中斷開啟和中斷關閉函數,有時候也要用到。
/** * @brief Enable an ADC interrupt. * @param __HANDLE__: ADC handle * @param __INTERRUPT__: ADC Interrupt to enable * This parameter can be one of the following values: * @arg ADC_IT_RDY ADC Ready (ADRDY) interrupt source * @arg ADC_IT_EOSMP ADC End of Sampling interrupt source * @arg ADC_IT_EOC ADC End of Regular Conversion interrupt source * @arg ADC_IT_EOS ADC End of Regular sequence of Conversions interrupt source * @arg ADC_IT_OVR ADC overrun interrupt source * @arg ADC_IT_JEOC ADC End of Injected Conversion interrupt source * @arg ADC_IT_JEOS ADC End of Injected sequence of Conversions interrupt source * @arg ADC_IT_AWD1 ADC Analog watchdog 1 interrupt source (main analog watchdog) * @arg ADC_IT_AWD2 ADC Analog watchdog 2 interrupt source (additional analog watchdog) * @arg ADC_IT_AWD3 ADC Analog watchdog 3 interrupt source (additional analog watchdog) * @arg ADC_IT_JQOVF ADC Injected Context Queue Overflow interrupt source * @retval None */ #define __HAL_ADC_ENABLE_IT(__HANDLE__, __INTERRUPT__) (((__HANDLE__)->Instance->IER) |= (__INTERRUPT__)) /** * @brief Disable an ADC interrupt. * @param __HANDLE__: ADC handle * @param __INTERRUPT__: ADC Interrupt to disable * @arg ADC_IT_RDY ADC Ready (ADRDY) interrupt source * @arg ADC_IT_EOSMP ADC End of Sampling interrupt source * @arg ADC_IT_EOC ADC End of Regular Conversion interrupt source * @arg ADC_IT_EOS ADC End of Regular sequence of Conversions interrupt source * @arg ADC_IT_OVR ADC overrun interrupt source * @arg ADC_IT_JEOC ADC End of Injected Conversion interrupt source * @arg ADC_IT_JEOS ADC End of Injected sequence of Conversions interrupt source * @arg ADC_IT_AWD1 ADC Analog watchdog 1 interrupt source (main analog watchdog) * @arg ADC_IT_AWD2 ADC Analog watchdog 2 interrupt source (additional analog watchdog) * @arg ADC_IT_AWD3 ADC Analog watchdog 3 interrupt source (additional analog watchdog) * @arg ADC_IT_JQOVF ADC Injected Context Queue Overflow interrupt source * @retval None */ #define __HAL_ADC_DISABLE_IT(__HANDLE__, __INTERRUPT__) (((__HANDLE__)->Instance->IER) &= ~(__INTERRUPT__))
注意:操作ADC的寄存器不限制必須要用HAL庫提供的API,比如要操作ADC1的寄存器IER,直接調用DMA1->IER操作即可。
44.3.8 ADC初始化流程總結
使用方法由HAL庫提供:
第1步:ADC時鍾源選擇。
兩種時鍾源可供選擇,可以選擇同步時鍾,來自AHB;也可以選擇異步時鍾,來自系統時鍾,PLL2或者PLL3的時鍾。
比如使用PLL2:
RCC_PeriphClkInitTypeDef RCC_PeriphClkInit; PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_ADC; PeriphClkInit.AdcClockSelection = RCC_ADCCLKSOURCE_PLL2; HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit);
第2步:ADC輸入引腳配置。
- 調用函數__HAL_RCC_GPIOx_CLK_ENABLE使能時鍾。
- 調用函數HAL_GPIO_Init配置引腳工作在模擬模式。
第3步:ADC中斷配置(如果用到的話)。
- 調用函數HAL_NVIC_EnableIRQ(ADCx_IRQn)使能ADC中斷。
- 將ADC中斷處理函數HAL_ADC_IRQHandler()填到ADC中斷服務程序ADCx_IRQHandler()中。
第4步:ADC使用DMA方式配置(如果用到的話)
- 調用函數HAL_DMA_Init配置DMA的相關參數。
- 使用函數HAL_NVIC_SetPriority配置DMA優先級。
- 使用函數HAL_NVIC_EnableIRQ使能DMA中斷。
- 將函數HAL_DMA_IRQHandler()填到中斷服務程序HAL_DMA_IRQHandler()里面。
- 傳輸結束后會調用函數HAL_DMA_IRQHandler(),此函數里面會執行回調函數HAL_ADC_ConvCpltCallback,HAL_ADC_ConvHalfCpltCallback等。
第5步:配置ADC,ADC通道和模擬看門狗
- 調用函數HAL_ADC_Init初始化ADC。
- 調用函數HAL_ADC_ConfigChannel配置ADC通道各個參數。
- 調用函數HAL_ADC_AnalogWDGConfig配置模擬看門狗。
第6步:調用函數HAL_ADCEx_Calibration_Start做自動校准。
第7步:ADC數值獲取的三種方式。
- 查詢方式
HAL_ADC_Start()
HAL_ADC_PollForConversion()
HAL_ADC_GetValue()
HAL_ADC_Stop()
- 中斷方式
HAL_ADC_Start_IT()
HAL_ADC_ConvCpltCallback()
HAL_ADC_GetValue()
HAL_ADC_Stop_IT()
- DMA方式
HAL_ADC_Start_DMA()
HAL_ADC_ConvCpltCallback() 和 HAL_ADC_ConvHalfCpltCallback()
HAL_ADC_Stop_DMA()
44.4 源文件stm32h7xx_hal_adc.c
此文件涉及到的函數比較多,這里把我們幾個常用的函數做個說明:
- HAL_ADC_Init
- HAL_ADC_ConfigChannel
- HAL_ADC_Start
- HAL_ADC_Start_DMA
- HAL_ADCEx_Calibration_Start
44.4.1 函數HAL_ADC_Init
函數原型:
HAL_StatusTypeDef HAL_ADC_Init(ADC_HandleTypeDef* hadc) { HAL_StatusTypeDef tmp_hal_status = HAL_OK; ADC_Common_TypeDef *tmpADC_Common; uint32_t tmpCFGR = 0; __IO uint32_t wait_loop_index = 0; /* 程序中不重要的部分被清除掉,僅留下關鍵部分做注釋 */ /* 檢測ADC句柄 */ if(hadc == NULL) { return HAL_ERROR; } /* 復位狀態初始化 */ if (hadc->State == HAL_ADC_STATE_RESET) { HAL_ADC_MspInit(hadc); ADC_CLEAR_ERRORCODE(hadc); hadc->Lock = HAL_UNLOCKED; } /* ADC退出深度掉電模式 */ if (HAL_IS_BIT_SET(hadc->Instance->CR, ADC_CR_DEEPPWD)) { /* 退出深度掉電模式Exit deep power down mode */ CLEAR_BIT(hadc->Instance->CR, ADC_CR_DEEPPWD); /* 退出深度掉電模式,一旦ADC穩壓器使能,必須重新校准或者應用之前保存的校准值 */ } if (HAL_IS_BIT_CLR(hadc->Instance->CR, ADC_CR_ADVREGEN)) { /* 使能ADC內部穩壓器 */ SET_BIT(hadc->Instance->CR, ADC_CR_ADVREGEN); /* 等待ADC穩定 */ wait_loop_index = (ADC_STAB_DELAY_US * (SystemCoreClock / (1000000 * 2))); while(wait_loop_index != 0) { wait_loop_index--; } } /* 檢測ADC穩壓器是否使能,潛在的時鍾穩定會導致使失敗 */ if (HAL_IS_BIT_CLR(hadc->Instance->CR, ADC_CR_ADVREGEN)) { /* 更新ADC狀態 */ SET_BIT(hadc->State, HAL_ADC_STATE_ERROR_INTERNAL); /* 設置內部錯誤 */ SET_BIT(hadc->ErrorCode, HAL_ADC_ERROR_INTERNAL); tmp_hal_status = HAL_ERROR; } /* 如果ADC之前的配置成功且沒有繼續進行規則通道的 */ if (HAL_IS_BIT_CLR(hadc->State, HAL_ADC_STATE_ERROR_INTERNAL) && (ADC_IS_CONVERSION_ONGOING_REGULAR(hadc) == RESET) ) { /* Initialize the ADC state */ SET_BIT(hadc->State, HAL_ADC_STATE_BUSY_INTERNAL); /* 配置ADC的公共參數 */ if((hadc->Instance == ADC1) || (hadc->Instance == ADC2)) { tmpADC_Common = ADC12_COMMON_REGISTER(hadc); } else { tmpADC_Common = ADC3_COMMON_REGISTER(hadc); } if ((ADC_IS_ENABLE(hadc) == RESET) && (ADC_ANY_OTHER_ENABLED(hadc) == RESET) ) { /* 配置CCR寄存器 */ MODIFY_REG(tmpADC_Common->CCR, ADC_CCR_PRESC|ADC_CCR_CKMODE, hadc->Init.ClockPrescaler); } /* 配置ADC參數 */ tmpCFGR = ( ADC_CFGR_CONTINUOUS(hadc->Init.ContinuousConvMode) | hadc->Init.Overrun | hadc->Init.Resolution | ADC_CFGR_REG_DISCONTINUOUS(hadc->Init.DiscontinuousConvMode) ); if (hadc->Init.DiscontinuousConvMode == ENABLE) { tmpCFGR |= ADC_CFGR_DISCONTINUOUS_NUM(hadc->Init.NbrOfDiscConversion); } /* 注意,如果參數ExternalTrigConvEdge設置為trigger edge none等效於軟件啟動 */ if ((hadc->Init.ExternalTrigConv != ADC_SOFTWARE_START) && (hadc->Init.ExternalTrigConvEdge != ADC_EXTERNALTRIGCONVEDGE_NONE)) { tmpCFGR |= ( hadc->Init.ExternalTrigConv | hadc->Init.ExternalTrigConvEdge); } MODIFY_REG(hadc->Instance->CFGR, ADC_CFGR_FIELDS_1, tmpCFGR); /* 更新ADC參數 */ if (ADC_IS_CONVERSION_ONGOING_REGULAR_INJECTED(hadc) == RESET) { tmpCFGR = ( ADC_CFGR_AUTOWAIT(hadc->Init.LowPowerAutoWait) | ADC_CFGR_DMACONTREQ(hadc->Init.ConversionDataManagement) ); MODIFY_REG(hadc->Instance->CFGR, ADC_CFGR_FIELDS_2, tmpCFGR); if (hadc->Init.OversamplingMode == ENABLE) { if ((hadc->Init.ExternalTrigConv == ADC_SOFTWARE_START) || (hadc->Init.ExternalTrigConvEdge == ADC_EXTERNALTRIGCONVEDGE_NONE)) { /* 軟件啟動不能用於多觸發,只能單觸發 */ assert_param((hadc->Init.Oversampling.TriggeredMode == ADC_TRIGGEREDMODE_SINGLE_TRIGGER)); } /* 配置過采樣 */ MODIFY_REG(hadc->Instance->CFGR2, ADC_CFGR2_FIELDS, ADC_CFGR2_ROVSE | (hadc->Init.Oversampling.Ratio << 16) | hadc->Init.Oversampling.RightBitShift | hadc->Init.Oversampling.TriggeredMode | hadc->Init.Oversampling.OversamplingStopReset); } else { /* 禁止規則通道過采樣 */ CLEAR_BIT( hadc->Instance->CFGR2, ADC_CFGR2_ROVSE); } /* 設置左移參數 */ MODIFY_REG(hadc->Instance->CFGR2, ADC_CFGR2_LSHIFT, hadc->Init.LeftBitShift); /* 是否使能BOOST模式 */ if(hadc->Init.BoostMode == ENABLE) { SET_BIT(hadc->Instance->CR, ADC_CR_BOOST); } else { CLEAR_BIT(hadc->Instance->CR, ADC_CR_BOOST); } } /* 配置規則通道 */ if (hadc->Init.ScanConvMode == ADC_SCAN_ENABLE) { /* 配置規格通道轉換個數 */ MODIFY_REG(hadc->Instance->SQR1, ADC_SQR1_L, (hadc->Init.NbrOfConversion - (uint8_t)1)); } else { CLEAR_BIT(hadc->Instance->SQR1, ADC_SQR1_L); } /* 初始ADC就緒狀態 */ ADC_STATE_CLR_SET(hadc->State, HAL_ADC_STATE_BUSY_INTERNAL, HAL_ADC_STATE_READY); } else { /* 設置ADC狀態錯誤 */ SET_BIT(hadc->State, HAL_ADC_STATE_ERROR_INTERNAL); tmp_hal_status = HAL_ERROR; } /* 返回狀態 */ return tmp_hal_status; }
函數描述:
此函數用於初始化ADC1,ADC2或者ADC3。
函數參數:
- 第1個參數是ADC_HandleTypeDef類型結構體指針變量,用於配置要初始化的參數。結構體變量成員的詳細介紹看本章3.2小節。
- 返回值,返回HAL_ERROR表示配置失敗,HAL_OK表示配置成功,HAL_BUSY表示忙(操作中),HAL_TIMEOUT表示時間溢出。
注意事項:
- 函數HAL_ADC_MspInit用於初始化定時器的底層時鍾、引腳等功能。需要用戶自己在此函數里面實現具體的功能。由於這個函數是弱定義的,允許用戶在工程其它源文件里面重新實現此函數。當然,不限制一定要在此函數里面實現,也可以像早期的標准庫那樣,用戶自己初始化即可,更靈活些。
- 如果形參hadc的結構體成員State沒有做初始狀態,這個地方就是個坑。特別是用戶搞了一個局部變量ADC_HandleTypeDef AdcHandle。
對於局部變量來說,這個參數就是一個隨機值,如果是全局變量還好,一般MDK和IAR都會將全部變量初始化為0,而恰好這個HAL_ADC_STATE_RESET = 0x00U。
解決辦法有四
方法1:用戶自己初始定時器和涉及到的GPIO等。
方法2:定義ADC_HandleTypeDef AdcHandle為全局變量。
方法3:定義為局部變量要賦初始值ADC_HandleTypeDef AdcHandle = {0}。
方法4:下面的方法:
if(HAL_ADC_DeInit(&AdcHandle)!= HAL_OK) { Error_Handler(); } if(HAL_ADC_Init(&AdcHandle)!= HAL_OK) { Error_Handler(); }
- ADC有兩種時鍾源可供選擇,可以使用來自AHB總線的系統時鍾(屬於同步時鍾),也可以使用PLL2,PLL3,HSE,HSI或者CSI時鍾(屬於異步時鍾)。如果使用異步時鍾,調用函數HAL_ADC_Init前要單獨配置。而AHB是默認時鍾,所以不必單獨配置。
- 如果更新ADC的公共寄存器,需要關閉了所有ADC時才能更新。
使用舉例:
ADC_HandleTypeDef AdcHandle = {0}; __HAL_RCC_ADC12_CLK_ENABLE(); AdcHandle.Instance = ADC1; /* 采用AHB同步時鍾,4分頻,即200MHz/4 = 50MHz */ AdcHandle.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV4; AdcHandle.Init.Resolution = ADC_RESOLUTION_16B; /* 16位分辨率 */ AdcHandle.Init.ScanConvMode = ADC_SCAN_DISABLE; /* 禁止掃描,因為僅開了一個通道 */ AdcHandle.Init.EOCSelection = ADC_EOC_SINGLE_CONV; /* EOC轉換結束標志 */ AdcHandle.Init.LowPowerAutoWait = DISABLE; /* 禁止低功耗自動延遲特性 */ AdcHandle.Init.ContinuousConvMode = DISABLE; /* 禁止自動轉換,采用的定時器觸發轉換 */ AdcHandle.Init.NbrOfConversion = 1; /* 使用了1個轉換通道 */ AdcHandle.Init.DiscontinuousConvMode = DISABLE; /* 禁止不連續模式 */ /* 禁止不連續模式后,此參數忽略,此位是用來配置不連續子組中通道數 */ AdcHandle.Init.NbrOfDiscConversion = 1; AdcHandle.Init.ExternalTrigConv = ADC_EXTERNALTRIG_T1_CC1; /* 定時器1的CC1觸發 */ AdcHandle.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_RISING; /* 上升沿觸發 */ AdcHandle.Init.ConversionDataManagement = ADC_CONVERSIONDATA_DMA_CIRCULAR;/*DMA循環模式接收ADC轉換的數據*/ AdcHandle.Init.BoostMode = ENABLE; /* ADC時鍾超過20MHz的話,使能boost */ AdcHandle.Init.Overrun = ADC_OVR_DATA_OVERWRITTEN; /* ADC轉換溢出的話,覆蓋ADC的數據寄存器 */ AdcHandle.Init.OversamplingMode = DISABLE; /* 禁止過采樣 */ /* 初始化DMA */ if(HAL_DMA_Init(&DmaHandle) != HAL_OK) { Error_Handler(__FILE__, __LINE__); }
44.4.2 函數HAL_ADC_ConfigChannel
函數原型:
HAL_StatusTypeDef HAL_ADC_ConfigChannel(ADC_HandleTypeDef* hadc, ADC_ChannelConfTypeDef* sConfig) { HAL_StatusTypeDef tmp_hal_status = HAL_OK; ADC_Common_TypeDef *tmpADC_Common; uint32_t tmpOffsetShifted; __IO uint32_t wait_loop_index = 0; /* 程序中不重要的部分被清除掉,僅留下關鍵部分做注釋 */ /* 上鎖 */ __HAL_LOCK(hadc); /* 配置ADC參數 */ if (ADC_IS_CONVERSION_ONGOING_REGULAR(hadc) == RESET) { /* ADC通道選擇 */ hadc->Instance->PCSEL |= (1U << sConfig->Channel); /* Rank 1 to 4 */ if (sConfig->Rank < 5) { MODIFY_REG(hadc->Instance->SQR1, ADC_SQR1_RK(ADC_SQR2_SQ5, sConfig->Rank), ADC_SQR1_RK(sConfig->Channel, sConfig->Rank)); } /* For Rank 5 to 9 */ else if (sConfig->Rank < 10) { MODIFY_REG(hadc->Instance->SQR2, ADC_SQR2_RK(ADC_SQR2_SQ5, sConfig->Rank), ADC_SQR2_RK(sConfig->Channel, sConfig->Rank)); } /* For Rank 10 to 14 */ else if (sConfig->Rank < 15) { MODIFY_REG(hadc->Instance->SQR3, ADC_SQR3_RK(ADC_SQR3_SQ10, sConfig->Rank), ADC_SQR3_RK(sConfig->Channel, sConfig->Rank)); } /* For Rank 15 to 16 */ else { MODIFY_REG(hadc->Instance->SQR4, ADC_SQR4_RK(ADC_SQR4_SQ15, sConfig->Rank), ADC_SQR4_RK(sConfig->Channel, sConfig->Rank)); } /* 更新ADC參數 */ if (ADC_IS_CONVERSION_ONGOING_REGULAR_INJECTED(hadc) == RESET) { /* 通道采樣時間配置 */ /* For channels 10 to 19 */ if (sConfig->Channel >= ADC_CHANNEL_10) { MODIFY_REG(hadc->Instance->SMPR2, ADC_SMPR2(ADC_SMPR2_SMP10, sConfig->Channel), ADC_SMPR2(sConfig->SamplingTime, sConfig->Channel)); } else /* For channels 0 to 9 */ { MODIFY_REG(hadc->Instance->SMPR1, ADC_SMPR1(ADC_SMPR1_SMP0, sConfig->Channel), ADC_SMPR1(sConfig->SamplingTime, sConfig->Channel)); } /* 配置偏移 */ tmpOffsetShifted = ADC_OFFSET_SHIFT_RESOLUTION(hadc, sConfig->Offset); switch (sConfig->OffsetNumber) { case ADC_OFFSET_1: MODIFY_REG(hadc->Instance->OFR1, ADC_OFR_FIELDS, ADC_OFR_CHANNEL(sConfig->Channel) | tmpOffsetShifted); MODIFY_REG(hadc->Instance->CFGR2, ADC_CFGR2_RSHIFT1, sConfig->OffsetRightShift); if(sConfig->OffsetSignedSaturation != DISABLE) { SET_BIT(hadc->Instance->OFR1, ADC_OFR1_SSATE); } else { CLEAR_BIT(hadc->Instance->OFR1, ADC_OFR1_SSATE); } break; case ADC_OFFSET_2: break; case ADC_OFFSET_3: break; case ADC_OFFSET_4: break; default : break; } } /* ADC參數更新 */ /* 內部的 Vbat/VrefInt/TempSensor */ if (ADC_IS_ENABLE(hadc) == RESET) { /* 配置差分模式 */ if (sConfig->SingleDiff != ADC_DIFFERENTIAL_ENDED) { /* 禁止差分 */ CLEAR_BIT(hadc->Instance->DIFSEL, ADC_DIFSEL_CHANNEL(sConfig->Channel)); } else { /* 使能差分 */ SET_BIT(hadc->Instance->DIFSEL, ADC_DIFSEL_CHANNEL(sConfig->Channel)); /* 配置通道ADC_IN+1 (negative input)的采樣時間 */ /* 通道 9 to 15 (ADC1, ADC2) or to 11 (ADC3), SMPR2寄存器必須配置 */ if (sConfig->Channel >= ADC_CHANNEL_9) { MODIFY_REG(hadc->Instance->SMPR2, ADC_SMPR2(ADC_SMPR2_SMP10, sConfig->Channel +1), ADC_SMPR2(sConfig->SamplingTime, sConfig->Channel +1)); } else /* 對於通道0 to 8, SMPR1必須配置 */ { MODIFY_REG(hadc->Instance->SMPR1, ADC_SMPR1(ADC_SMPR1_SMP0, sConfig->Channel +1), ADC_SMPR1(sConfig->SamplingTime, sConfig->Channel +1)); } } /* 內部測量通道配置: Vbat/VrefInt/TempSensor */ /* 公用寄存器配置 */ if((hadc->Instance == ADC1) || (hadc->Instance == ADC2)) { tmpADC_Common = ADC12_COMMON_REGISTER(hadc); } else { tmpADC_Common = ADC3_COMMON_REGISTER(hadc); } /* 具體內部通道的配置,省略未寫 */ } } else { SET_BIT(hadc->State, HAL_ADC_STATE_ERROR_CONFIG); tmp_hal_status = HAL_ERROR; } /* 解鎖 */ __HAL_UNLOCK(hadc); /* 返回函數狀態 */ return tmp_hal_status; }
函數描述:
調用函數HAL_ADC_Init配置了基礎功能后,就可以調用此函數配置ADC的具體通道了。
函數參數:
- 第1個參數是ADC_HandleTypeDef類型結構體指針變量。
- 第2個參數是ADC_ChannelConfTypeDef類型結構體指針變量,用於配置ADC的采樣時間,使用的通道號,單端或者差分方式的配置等。
- 返回值,返回HAL_ERROR表示配置失敗,HAL_OK表示配置成功,HAL_BUSY表示忙(操作中),HAL_TIMEOUT表示時間溢出。
注意事項:
- 第1個參數的結構體成員介紹在本章的3.2小節進行了詳細說明。
- 第2個參數的結構體成員介紹在本章的3.4小節進行了詳細說明。
使用舉例:
ADC_ChannelConfTypeDef sConfig = {0}; /* 配置ADC通道 */ sConfig.Channel = ADC_CHANNEL_10; /* 配置使用的ADC通道 */ sConfig.Rank = ADC_REGULAR_RANK_1; /* 采樣序列里的第1個 */ sConfig.SamplingTime = ADC_SAMPLETIME_1CYCLE_5; /* 采樣周期 */ sConfig.SingleDiff = ADC_SINGLE_ENDED; /* 單端輸入 */ sConfig.OffsetNumber = ADC_OFFSET_NONE; /* 無偏移 */ sConfig.Offset = 0; /* 無偏移的情況下,此參數忽略 */ if (HAL_ADC_ConfigChannel(&AdcHandle, &sConfig) != HAL_OK) { Error_Handler(__FILE__, __LINE__); }
44.4.3 函數HAL_ADC_Start
函數原型:
HAL_StatusTypeDef HAL_ADC_Start(ADC_HandleTypeDef* hadc)
函數描述:
調用函數HAL_ADC_Init配置了基礎功能后,就可以調用此函數啟動ADC了。
函數參數:
- 第1個參數是ADC_HandleTypeDef類型結構體指針變量。
- 返回值,返回HAL_ERROR表示配置失敗,HAL_OK表示配置成功,HAL_BUSY表示忙(操作中),HAL_TIMEOUT表示時間溢出。
注意事項:
- 第1個參數的結構體成員介紹在本章的3.2小節進行了詳細說明。
使用舉例:
if (HAL_ADC_ConfigChannel(&AdcHandl) != HAL_OK) { Error_Handler(__FILE__, __LINE__); }
44.4.4 函數HAL_ADC_Start_DMA
函數原型:
HAL_StatusTypeDef HAL_ADC_Start_DMA(ADC_HandleTypeDef* hadc, uint32_t* pData, uint32_t Length)
函數描述:
調用函數HAL_ADC_Init配置了基礎功能后,就可以調用此函數啟動ADC的DMA方式了。
函數參數:
- 第1個參數是ADC_HandleTypeDef類型結構體指針變量。
- 第2個參數是ADC采樣數據傳輸的目的地址。
- 第3個參數是傳輸的數據長度。
- 返回值,返回HAL_ERROR表示配置失敗,HAL_OK表示配置成功,HAL_BUSY表示忙(操作中),HAL_TIMEOUT表示時間溢出。
注意事項:
- 第1個參數的結構體成員介紹在本章的3.2小節進行了詳細說明。
- 這個函數會開啟DMA的HT,TC,TE和MDE中斷。
- 此函數用於單ADC模式,多ADC模式是調用的函數HAL_ADCEx_MultiModeStart_DMA。
使用舉例:
uint16_t ADCxValues[4]; ADC_HandleTypeDef AdcHandle = {0}; /* ADC和DMA的配置部分未貼,函數較多 */ if (HAL_ADC_Start_DMA(&AdcHandle, (uint32_t *)ADCxValues, 4) != HAL_OK) { Error_Handler(__FILE__, __LINE__); }
44.4.5 函數HAL_ADCEx_Calibration_Start
函數原型:
HAL_StatusTypeDef HAL_ADCEx_Calibration_Start(ADC_HandleTypeDef* hadc, uint32_t CalibrationMode, uint32_t SingleDiff)
函數描述:
調用函數HAL_ADC_Init配置了基礎功能后,就可以調用此函數啟動ADC的自校准功能了,支持偏移校准和線性度校准。
函數參數:
- 第1個參數是ADC_HandleTypeDef類型結構體指針變量。
- 第2個參數是校准模式選擇:
- ADC_CALIB_OFFSET表示只運行偏移校准而不運行線性度校准。
- ADC_CALIB_OFFSET_LINEARITY表示同時運行偏移校准和線性度校准。
- 第3個參數是單端或差分模式選擇:
- ADC_SINGLE_ENDED表示單端模式。
- ADC_DIFFERENTIAL_ENDED表示差分模式。
- 返回值,返回HAL_ERROR表示配置失敗,HAL_OK表示配置成功,HAL_BUSY表示忙(操作中),HAL_TIMEOUT表示時間溢出。
注意事項:
- 第1個參數的結構體成員介紹在本章的3.2小節進行了詳細說明。
- 必須在函數HAL_ADC_Start(或者中斷和MDA方式的啟動函數)執行前或者HAL_ADC_Stop(或者中斷和MDA方式的停止函數)執行后才可以調用此校准函數。
使用舉例:
/* 校准ADC,采用偏移校准 */ if (HAL_ADCEx_Calibration_Start(&AdcHandle, ADC_CALIB_OFFSET, ADC_SINGLE_ENDED) != HAL_OK) { Error_Handler(__FILE__, __LINE__); }
44.5 總結
本章節就為大家講解這么多,由於ADC用到的場合比較多,建議將常用的知識點熟練掌握。