ADC簡介? Analog-Digital Converter 模擬-數字轉換器
ADC可以將引腳上連續變化的模擬電壓轉換為內存中存儲的數字變量,建立模擬電路到數字電路的橋梁。
12位逐次逼近型ADC,1us轉換時間;輸入電壓范圍:0-3.3V,轉換結果范圍0-4095;18個輸入通道,可測量16個外部和2個內部信號源;規則組和注入組兩個轉換單元;模擬看門狗自動檢測輸入電壓范圍。
????????數字到模擬的橋梁:PWM或DAC。目前DAC的主要應用是在波形生成這些領域,比如信號發生器、音頻解碼芯片等。
ADC參數:分辨率、轉換速度。輸入電壓范圍。
? ? ? ? 16個外部信號就是GPIO口,可在引腳上直接測模擬信號即可。2個內部信號時內部溫度傳感器和內部參考電壓,溫度傳感器可以測量CPU的溫度,內部參考電壓是一個1.2V左右的基準電壓,基準電壓是不隨外部供電電壓變化而變化的。
????????規則組和注入組兩個轉換單元,是STM32ADC的增強功能。普通的AD轉換流程是,啟動一次轉換,讀一次值,然后再啟動,再讀值。STM32的ADC可以列一個組,一次性啟動一個組,連續轉換多個值,并且有兩個組,一個是用于常規使用的規則組,一個是用于突發事件的注入組。
????????ADC可以用模擬看門狗來自動執行,模擬看門狗可以檢測指定的某些通道,當AD值高于它設定的上閾值或者低于下閾值時,就會申請中斷可以在中斷函數里執行相應的操作。就不用不斷地手動讀值,再進行判斷了。
逐次逼近型ADC0809
????????逐次逼近型ADC0809的內部結構,了解這個結構對學習STM32的ADC幫助很大。在以前芯片集成功能不強的時候,需要外掛一個ADC芯片進行AD轉換。
????????左邊IN0-IN7,是8路輸入通道,通過通道選擇開關,選中一路,輸入到一點進行轉換。地址鎖存和譯碼是一個多路選擇開關的作用。輸入信號進入到比較器后,通過逐次逼近的方法來獲取電壓對應的編碼數據。
????????DAC內部使用加權電阻網絡來實現的轉換。如果DAC輸出的電壓比較大,就調小DAC數據,如果比較小,就增大DAC數據,直到DAC輸出的電壓和外部通道輸入的電壓近似相等。這樣DAC輸入的數據就是外部電壓的編碼數據。
????????電壓調節的過程是逐次逼近SAR來完成的,為了最快找到未知電壓的編碼,通常我們會使用二分法進行尋找,會發現128,64,32這些數據,正好是二進制每一位的位權,判斷過程就是二進制從高位到低位依次判斷是1還是0的過程。這就是逐次逼近型名字的由來。
EOC End Of Convert 轉換結束信號;
START 開始轉換,給一個輸入脈沖,開始轉換;
CLOCK 是ADC的時鐘,因為ADC內部是一步一步進行判斷的。 需要時鐘來推動這個過程;
VREF+和VREF-是DAC的參考電壓,參考電壓決定ADC的輸入范圍。通常低要求時,參考電壓的正極和VCC接到一起、參考電壓的負極和GND接在一起。
STM32的ADC
一般手冊里,每個外設的最前面都有一個整體的結構圖,這個結構圖是非常重要的,需要多花時間看看。
????????左邊IN0-IN15是ADC的16個GPIO外部輸入通道;VREFINT (V Reference Internal),內部參考電壓;溫度傳感器。總共18個通道,到一個模擬多路開關,指定我們想要選擇的通道。進入模數轉換器,執行逐次比較,將轉換結果放在數據寄存器里,用戶讀取寄存器獲取ADC轉換數值。
????????普通的ADC,多路開關一般只選中一個的。但是此ADC可以同時選中多個,而且在轉換時還分成了兩個組,規則通道組和注入通道組,其中規則組一次性最多選中16個通道,注入組最多可以選中4個通道。
舉個例子:就像是去餐廳點菜,普通的ADC是指定一個菜,老板給你做,然后做好了送給你,這里就是指定一個菜單,這個菜單最多可以填16個菜,直接把菜單寄給老板,老板就按照菜單的順序依次做好,一次性給你端上菜,這樣的話可以大大提高效率,這樣這個菜單就簡化成普通的模式了。那對于這個菜單也有兩種,一種規則組菜單,可以同時上16個菜,有個尷尬的地方,就是這個規則組只有一個數據寄存器,就是這個桌子比較小,最多只能放一個菜,如果要上16個菜,那不好意思,前15個菜都會被擠掉,只能得到第16個菜,所以對于規則組轉換來說,如果使用這個菜單的話,最好配合DMA來實現,DMA是一個數據轉運小幫手,它可以在每上一個菜之后,把這個菜挪到其他地方去,防止被覆蓋。
規則組雖然可以同時轉換16個通道,但是數據寄存器只能存一個結果,如果不想之前的結果被覆蓋,那在轉換之后,就要盡快把結果拿走。
注入組就比較高級了,相當于餐廳的VIP座,在這個座位上,一次性最多可以點4個菜,并且這里數據寄存器有4個,是可以同時上4個菜的,對于注入組而言,就不用擔心數據覆蓋的問題了,一般情況下,使用規則組就完全足夠了。如果要使用規則組的菜單,那就再配合DMA轉運數據,就不用擔心數據覆蓋的問題。
注入組的操作:涉及的不多,可以看手冊自行了解。
規則組的操作:先看模數轉換器外圍的一些線路,首先左下角是觸發轉換的部分,也就是ADC0809的START信號,開始轉換。
對于STM32的ADC,觸發ADC開始轉換的信號有兩種,一種是軟件觸發,就是在程序中手動調用一條代碼,就可以啟動轉換了;另一種是硬件觸發,就是這里的這些觸發源。上面是注入組的觸發源,下面是規則組的觸發源。這些觸發源主要是來自于定時器,,有定時器的各個通道,還有TRGO定時器主模式的輸出,定時器可以通向ADC、DAC這些外設,用于觸發轉換,因為ADC經常需要過一個固定時間段轉換一次,比如每隔1ms轉換一次。正常的思路就是用定時器,每隔1ms申請一次中斷,在中斷里手動開始一次轉換,這樣也是可以的。但是頻繁進中斷對我們的程序是由一定影響的。
比如有很多中斷都需要頻繁進入,那肯定會影響主程序的執行,并且不同中斷之間,由于優先級的不同,也會導致某些中斷不能及時得到響應。那我們ADC的轉換頻率就肯定會產生影響了,所以對于這種需要頻繁進中斷,并且在中斷里只完成了簡單工作的情況,一般都會有硬件的支持。
比如這里給TIM3定1ms的時間,并且把TIM3的更新事件選擇為TRGO輸出,然后在ADC這里,選擇開始觸發信號為TIM3的TRGO,這樣TIM3的更新事件就能通過硬件自動觸發ADC轉換了,整個過程不需要進中斷,節省了中斷資源。這就是這里定時器的觸發作用。
當然這里還可以選擇外部中斷引腳來觸發轉換,都可以在程序中配置。
ADCCLK是ADC的時鐘,相當于0809的CLOCK,用于驅動內部逐次比較的時鐘。ADC預分頻器來源于RCC。
DMA的請求:是用于觸發DMA進行數據轉運的,DMA章節再講。
兩個數據寄存器,是用于存放轉換結果的。
????????模擬看門狗,里面可以存一個閾值高限和閾值低限,如果啟動了模擬看門狗,并指定了看門的通道,那這個看門狗就會關注它看門的通道,一旦超過這個閾值范圍了,它就會亂叫,就會在上面,申請一個模擬看門狗的中斷,最后通向NVIC。
????????然后對于規則組和注入組而言,它們轉換完成之后,也會有一個EOC規則組轉換完成的信號,JEOC是注入組完成的信號,這兩個信號會在狀態寄存器里置一個標志位,我們讀取這個標志位,就能知道是不是轉換結束了,同時這兩個標志位也可以去NVIC,申請中斷,如果開啟了NVIC對應的通道,它們就會觸發中斷,。
ADC基本結構圖
左邊是輸出通道,16個GPIO口,外加兩個內部的通道,然后進入AD轉換器(有兩個組,一個規則組,一個注入組),規則組最多可以選中16個通道,注入組最多可以選擇4個通道,然后轉換的結果可以存放在AD數據寄存器里,其中規則組只有1個數據寄存器,注入組有4個,觸發控制提供了開始轉換這個START信號,觸發控制可以選擇軟件觸發和硬件觸發。硬件觸發主要是來自于定時器,當然也可以選擇外部中斷的引腳,右邊這里是來自于RCC的ADC時鐘CLOCK,ADC的逐次比較的過程就是由這個時鐘推動的。然后上面可以布置一個模擬看門狗用于監測轉換結果的范圍。
最后右下角還有一個開關控制,在庫函數中,就是ADC_Cmd函數,用于給ADC上電的,這些就是STM32 ADC的內部結構了。
接下來是一些細節問題:
ADC12_IN0的意思是這個引腳是ADC1和ADC2的IN0都是在PA0上的。
ADC的一個高級功能:雙ADC模式,這個模式比較復雜,暫時簡單了解,不需要掌握。
雙ADC模式就是ADC1和ADC2一起工作,它倆可以配合組成同步模式、交叉模式等等模式,比如交叉模式:ADC1和ADC2交叉地對一個通道進行采樣,就可以進一步提高采樣率。當然ADC1和ADC2可以分開使用。可以分別對不同的引腳進行采樣。
規則組的4種轉換模式:
在ADC初始化的結構體里,會有兩個參數:一個是選擇單次轉換還是連續轉換的,另一個是選擇非掃描模式還是掃描模式,這兩個參數組合起來,就有4種轉換方式。
單次轉換,每觸發一次,轉換結束后,就會停下來,下次轉換得再觸發才能開始。
連續轉換:一次轉換完成后,立刻開始下一次的轉換。
非掃描模式:所以菜單列表就只用第一個。
掃描模式:一次可以轉換多個序列,但需要使用DMA進行數據轉運。
單次轉換-非掃描模式:
? ? ? ? 最簡單的一種模式。序列是規則組里的菜單,有16個空位,分別是序列1到序列16。可以寫入要轉換的通道,在非掃描的模式下,只有序列1的位置有效。在序列1的位置指定我們想轉換的通道,比如通道2,寫到這個位置,然后以觸發轉換,ADC就會對這個通道2進行模數轉換。轉換結果放在數據寄存器里,同時給EOC標志位置1。我們判斷這個EOC標志位,如果轉換完了,如果想再啟動一次轉換,那就需要再觸發一次,轉換結束,置EOC標志位,讀結果。
????????如果想換一個通道轉換,那在轉換之前,把第一個位置的通道2改成其他通道,然后再啟動轉換,這樣就行了。
連續轉換-非掃描模式
???????與單次轉換不同的是,它在一次轉換結束后不會停止,而是立刻開始下一輪的轉換。好處:開始轉換之后不需要等待一段時間的,因為它一直在轉換,所以就不需要手動,也不用判斷是否結束,想要讀AD值的時候,直接從數據寄存器取就可以了。
單次轉換-掃描模式
????????
????????掃描模式就用到這個菜單列表了,可以在這個菜單里點菜,比如第一個菜是通道2,第二個菜是通道5,等等,這里每個位置是通道幾可以任意指定,并且也是可以重復的。然后初始化結構體有個參數,就是通道數目,因為這16個通道可以不用完,只用前幾個,那就需要再給他一個通道數目的參數。告訴它,我有幾個通道,比如這里指定通道數目為7,那它就只看前7個位置,然后每次觸發之后,它就一次對這前7個位置進行AD轉換,轉換結構都放在數據寄存器里,這里為了防止數據被覆蓋,就需要用DMA及時將數據挪走,那7個通道轉換完成之后,產生EOC信號,轉換結束,然后再觸發下一次,就開始新一輪的轉換。
連續轉換-掃描模式
????????當然在掃描模式的情況下,還可以有一種模式,叫間斷模式,它的作用是,在掃描的過程中,每隔幾個轉換,就暫停一次。需要再次觸發,才能繼續,這個模式沒有列出來,不然要列出來的太多了。
觸發控制
????????這個表是規則組的觸發源:有來自引腳或定時器的信號,具體是引腳還是定時器,需要用AFIO重映射來確定。軟件控制位也就是我們之前說的軟件觸發。這些觸發信號怎么選擇,可以通過設置右邊的寄存器來完成,當然使用庫函數的話,直接給一個參數就行了。這就是觸發控制。
數據對齊
????????ADC是12位的,它的轉換結果是一個12位的數據,但寄存器是16位的,所以就存在一個數據對齊的問題。12位的數據向右靠,高位多出來幾位補0;12位的數據向左靠,低位多出來的幾位補0。
????????一般使用右對齊:在讀取16位寄存器直接就是轉換結果。
? ? ? ? 左對齊用途:如果你不需要高分辨率,覺得0-4095太大了,就做個簡單的判斷,可以選擇左對齊,把數據的高8位取出來,舍棄后4位的精度。當然也可以把12位都取出來。
轉換時間
AD轉換的步驟:采樣、保持、量化、編碼
STM32ADC的總采樣時間:Tconv=采樣時間+12.5個ADC周期
例如:當ADCCLK=14MHz,采樣時間位1.5個ADC周期,Tconv=1.5+12.5=14個ADC周期=1us
一般不敏感,因為一般AD轉換都很快,如果不需要非常高速的轉換頻率,那轉換時間就可以忽略了,AD轉換需要一小段時間,就像廚子做菜一樣,也需要等待一會才能上菜的。
采樣保持可以放在一起,量化編碼可以放在一起,總共是這兩大步。量化編碼就是之前講的ADC逐次比較的過程。這個需要花一段時間,一般位數越多,花的時間就越長。
采樣保持是因為 AD轉換后面的量化編碼,是需要一小段時間的,如果在這一小段時間里,輸入電壓還在不斷變化,那就沒法定位輸入電壓到底在哪里了,所以在量化編碼之前,需要設置一個采樣開關,比如可以用一個小容量的電容存儲一下這個電壓,存儲好了之后,斷開采樣開關,在進行后面的AD轉換。這樣在量化編碼的過程中,電壓始終保持不變,這就是采樣保持電路。
那采樣保持的過程,需要閉合采樣開關,過一段時間再斷開,這里就會產生一個采樣時間,那回到這里這里,我們就得到了第二條。
采樣時間就是采樣保持花費的時間,這個可以在程序中進行配置,采樣時間越大,越能避免一些毛刺信號的干擾,不過轉換時間也會相應延長,12.5個ADC周期是量化編碼花費的時間,因為是12位的ADC,所以需要花費12個周期,這里多了半個周期,可能是做其他一些東西畫的時間。ADC周期就是從RCC分頻過來的ADCCLK,這個ADCCLK最大是14MHz,所以下面有個例子,這里就是最快的轉換時間。
如果采樣周期再長些,它就達不到1us了,另外也可以把ADCCLK的時鐘設置超過14MHz,這樣就是在超頻了,那轉換時間可以比1us還短,不過這樣穩定性就沒辦法保證了
聽起來很復雜,但是這個校準我們暫時不需要理解,因為校準過程是固定的,我們只需要在ADC初始化最后,加幾條代碼就行了,至于怎么計算,怎么校準的,我們不需要管,所以了解一下就行了
ADC的外圍電路
第一個是電位器產生一個可調的電壓,電阻阻值不能給的太小,
第二個是傳感器輸出電壓的電路,一般來說,像光敏電阻,熱敏電阻,紅外接收管,麥克風等等,都可以等效為一個可變電阻,所以這里就可以通過和一個固定電阻串聯分壓,這個福鼎電阻一般可以選擇和傳感器阻值相近的電阻。這樣可以得到一個位于中間電壓區域比較好的輸出。
第三個是電壓轉換電路,使用電阻進行分壓,但是如果是高電壓采集最好使用一些專用的采集芯片,比如隔離放大器等等,做好高低電壓的隔離,保證電路的安全
手冊介紹:
見參考手冊。
代碼步驟:
1.開啟RCC時鐘,包括ADC和GPIO的時鐘,另外ADCCLK的分頻器,也需要配置一下
2.配置GPIO,把需要用到的GPIO配置成模擬輸入的模式
3.配置多路開關,把左邊的通道接入到右邊的規則組列表里,這個過程就是我們之前說的點菜,把各個通道的菜,列在菜單里
4.配置ADC轉換器,在庫函數里,是用結構體來配置的,可以配置這一大塊電路的參數。包括ADC是單次轉換還是連續轉換、掃描還是非掃描、有幾個通道、觸發源是什么、數據對齊是左對齊還是右對齊,這一大批參數,用一個結構體配置就可以了,如果需要模擬看門狗,那會有幾個函數用來配置閾值和監測通道的,那就在中斷輸出控制里ITConfig函數開啟對應的中斷輸出,然后再在NVIC里,配置一下優先級,這樣就能觸發中斷了。不過這一塊模擬看門狗和中斷,本節暫時不用。
開關控制,調用一下ADC_Cmd函數,開啟ADC,這樣ADC就配置完成了,就能正常工作了,當然在開啟ADC之后,根據手冊里的建議,還可以對ADC進行一下校準,這樣可以減小誤差,那在ADC工作的時候,如果想要軟件觸發轉換,那會有函數可以觸發,如果想讀取轉換結果,那也會有函數可以讀取結果
配置程序的大致思路。
void RCC_ADCCLKConfig(uint32_t RCC_PCLK2);
配置ADCCLK分頻器的,它可以對應APB2的72MHz時鐘選擇2、4、6、8分頻,輸入到ADCCLK
DeInit恢復缺省設置、Init初始化、StructInit結構體初始化
ADC_Cmd是用于給ADC上電的,
DMACmd是用于開啟DMA輸出信號的
ITConfig中斷輸出控制,用于控制某個中斷,能不能通往NVIC
ADC_ResetCalibration 復位校準
ADC_GetResetCalibrationStatus 獲取復位狀態
ADC_StartCalibration 開始校準
ADC_GetCalibrationStatus 獲取開始校準狀態
在ADC初始化完成之后,依次調用就行了。
然后繼續,ADC軟件開始控制轉換,就是這個用于軟件觸發的函數了 ADC_SoftwareStartConvCmd
ADC獲取軟件開始轉換狀態 ADC_GetSoftwareStartConvStatus
從名字上來看,這個函數好像是判斷是不是正在進行的,那我們可不可以調用這個函數,來判斷轉換是否已經結束呢,這個可以分析一下源碼,源碼分析可得這個函數的返回值跟轉換是否結束,毫無關系
ADC_GetFlagStatus 獲取標志位狀態,知道轉換是否結束,然后參數給EOC的標志位,判斷EOC標志位是不是置1了,如果轉換結束,EOC標志位置1,然后調用這個函數,判斷這個標志位,這樣才是正確的判斷轉換是否結束的方法。
所以簡單倆說, ADC_GetSoftwareStartConvStatus這個函數其實沒啥用,我們一般不用,不要被他誤導了
下面兩個函數是用來配置間斷模式的
ADC_DiscModeChannelCountConfig 是每隔幾個通道間斷一次,
ADC_DiscModeCmd 是不是啟用間斷模式,需要間斷模式的話可以理解一下,
void ADC_RegularChannelConfig(ADC_TypeDef* ADCx, uint8_t ADC_Channel, uint8_t Rank, uint8_t ADC_SampleTime); ADC_規則組通道配置,這個函數比較重要,它的作用是給序列的每個位置填寫指定的通道,就是填寫點菜菜單的過程,第一個參數ADCx,第二個ADC_Channel,就是想要指定的通道,第三個Rank,就是序列幾的位置,第四個SampleTime指定通道的采樣時間
ADC_ExternalTrigConvCmd 外部觸發控制轉換,就是是否允許外部觸發轉換,
ADC_GetConversionValue 是ADC獲取轉換值,這個函數也比較重要,獲取AD轉換的數據寄存器,讀取轉換結果就要使用這個函數
ADC_GetDualModeConversionValue ADC獲取雙模式轉換值,這個是雙ADC模式讀取轉換結果的函數
以上函數就是對ADC的一些基本功能和規則組的配置,
接下來的一大批函數里面都帶了一個Injected,就是注入組的意思,所以一大批函數都是對ADC注入組進行配置的,注入組暫時不多講,
這三個函數就是對模擬看門狗進行配置的,第二個是配置高低閾值、第三個是配置看門的通道、之后ADC溫度傳感器、內部參考電壓控制、如果要用到這兩個通道,那得調用這個函數,開啟一下,要不然是讀不到正確的結果,這個要注意一下。
最后四個,獲取標志位狀態,清除標志位,獲取終端狀態,清除終端掛起位。常用函數,不多說。
EOC看手冊得知,是規則或注入。這一點需要看參考手冊進行筆記的修改。
如果想要用掃描模式實現多通道,最好要配合DMA來實現,
可能會問:一個通道轉換完成之后,手動把數據轉運出來,不就行了,為啥非要用DMA來轉運呢,這個方案看似簡單,實際操作起來會有一些問題,第一個就是在掃描模式下,你啟動列表之后,它里面每一個單獨的通道轉換完成之后,不會產生任何的標志位,也不會觸發中斷,你不知道某一個通道是不是轉換完了,它只有在整個列表都轉換完成之后,才會產生一次EOC標志位,才能觸發中斷,而這時,前面的數據就已經覆蓋丟失了。
第二個問題:AD轉換是非常快的,通過計算轉換一個通道大概只有幾us,也就是說,如果你不能在幾us的時間內把數據轉運走,那數據就會丟失,這對于我們程序手動轉運數據,要求就比較高,所以在掃描模式下,手動轉運數據是比較困難的。
不過比較困難也不是說手動轉運不可行,在掃描的時候,每轉換一個通道就暫停一次,等我們手動把數據轉運走之后,再繼續觸發,繼續下一次轉換,這樣可以實現手動轉運數據的功能,但是由于單個通道轉換完成之后,沒有標志位,所以啟動轉換之后,只能通過Delay延時的方法,才能保證轉換完成,這種方式既不能讓我們省心,也不能提高效率。所以暫不推薦使用
實現多通道一個簡單的方法:可以使用單次轉換、非掃描的模式。只需要在每次觸發轉換之前,手動更改一下列表第一個位置的通道就行了,比如第一次轉換,先寫入通道0,之后觸發、等待、讀值;第二次轉換,再先把通道0改成通道1,之后觸發、等待、讀值。第三次轉換,再先改成通道2,等等,在轉換前,先指定一下通道,再啟動轉換。就可以輕松地實現多通道轉換的功能了。