STM32學習筆記之ADC轉換
1. ADC簡介
stm32f103最少有2個AD模數轉換器,每個ADC都有18個通道,可以測量16個外部和2個內部模擬量。最大轉換頻率為1Mhz,也就是轉換時間為1us(在 ADCCLK = 14Mhz,取樣週期為1.5個時鐘週期時)。最大時鐘超過14Mhz,將導致ADC轉換準確度降低。stm32的ADC是12位精度的。
stm32的ADC轉換有兩種通道,規則通道和注入通道,注入通道可以搶佔式地打斷規則通道的取樣,執行注入通道取樣後,再執行之前的規則通道取樣,和中斷類似。本例只使用規則通道實現獨立模式的中斷取樣,這裡不再贅述兩種通道區別。
stm32的ADC可以由外部事件觸發(例如定時器捕獲,EXTI線)和軟體觸發(即在配置相關暫存器時,直接開啟取樣)。
STM32的ADC在單次轉換模式下,只執行一次轉換,該模式可以通過ADC_CR2 暫存器的ADON 位(只適用於規則通道)啟動,也可以通過外部觸發啟動(適用於規則通道和注入通道),這是CONT 位為0 。 以規則通道為例,一旦所選擇的通道轉換完成,轉換結果將被存在ADC_DR 暫存器,EOC (轉換結束)標誌將被置位,如果設定了EOCIE ,則會產生中斷。然後ADC將停止,直到下次啟動。
2. 暫存器簡介
2.1. ADC控制暫存器(ADC_CR1和ADC_CR2)
ADC_CR1的SCAN 位,該位用於設定掃描模式,由軟體設定和清除,如果設定為1 ,則使用掃描模式,如果為 0,則關閉掃描模式。在掃描模式下,由 ADC_SQRx或ADC_JSQRx暫存器選中的通道被轉換。如果設定了 EOCIE 或JEOCIE,只在最後一個通道轉換完畢後才會產生EOC 或JEOC 中斷。
ADC_CR1[19:16]用於設定 ADC的操作模式
ADC_CR2
ADCON 位用於開關AD轉換器。而CONT 位用於設定是否進行連續轉換,我們使用單次轉換,所以CONT 位必須為0。CAL 和RSTCAL 用於AD校準。ALIGN用於設定資料對齊,我們使用右對齊,該位設定為0 。
EXTSEL[2:0]用於選擇啟動規則轉換組轉換的外部事件,詳細的設定關係如下:
這裡使用的是軟體觸發(SWSTART ),所以設定這3 個位為111 。ADC_CR2 的SWSTART 位用於開始規則通道的轉換,我們每次轉換(單次轉換模式下)都需要向該位寫 1 。AWDEN 為用於使能溫度感測器和Vrefint 。
2.2. ADC取樣事件暫存器(ADC_SMPR1 和ADC_SMPR2 )
這兩個暫存器用於設定通道0~17的取樣時間,每個通道佔用 3 個位。
ADC_SMPR2 的各位描述如下
對於每個要轉換的通道,取樣時間建議儘量長一點,以獲得較高的準確度,但是這樣會降低ADC的轉換速率。ADC的轉換時間可以由下式計算:
Tcovn= 取樣時間+12.5 個週期
其中:Tcovn 為總轉換時間,取樣時間是根據每個通道的SMP位的設定來決定的。例如,當ADCCLK=14Mhz 的時候,並設定 1.5個週期的取樣時間,則得到:Tcovn=1.5+12.5=14 個週期=1us 。
2.3. ADC規則序列暫存器(ADC_SQR1~3)
L[3:0] 用於儲存規則序列的長度,我們這裡只用了 1 個,所以設定這幾個位的值為 0 。其他的SQ13~16 則儲存了規則序列中第13~16 個通道的編號(0~17)。另外兩個規則序列暫存器同ADC_SQR1大同小異,我們這裡就不再介紹了,要說明一點的是:我們選擇的是單次轉換,所以只有一個通道在規則序列裡面,這個序列就是SQ0 ,通過ADC_SQR3的最低5 位設定。
2.4. ADC規則資料暫存器(ADC_DR)
這裡要提醒一點的是,該暫存器的資料可以通過ADC_CR2 的ALIGN位設定左對齊還是右對齊。在讀取資料的時候要注意。
2.5. ADC狀態暫存器(ADC_SR )
這裡我們要用到的是EOC 位,我們通過判斷該位來決定是否此次規則通道的AD轉換已經完成,如果完成我們就從ADC_DR 中讀取轉換結果,否則等待轉換完成。
3. 暫存器操作步驟
1 、開啟PA口時鐘,設定PA0 為模擬輸入。
STM32F103RBT6的ADC通道0 在PA 0 上,所以,我們先要使能 PORTA的時鐘,然後設定PA 0 為模擬輸入。
2 、使能ADC1 時鐘,並設定分頻因子。
要使用ADC1,第一步就是要使能 ADC1 的時鐘,在使能完時鐘之後,進行一次 ADC1 的復位。接著我們就可以通過RCC_CFGR設定ADC1 的分頻因子。分頻因子要確保 ADC1 的時鐘(ADCCLK)不要超過14Mhz 。
3 、設定ADC1 的工作模式。
在設定完分頻因子之後,我們就可以開始 ADC1 的模式配置了,設定單次轉換模式、觸發方式選擇、資料對齊方式等都在這一步實現。
4 、設定ADC1 規則序列的相關資訊。
接下來我們要設定規則序列的相關資訊,我們這裡只有一個通道,並且是單次轉換的,所以設定規則序列中通道數為1 ,然後設定通道 0 的取樣週期。
5 、開啟AD轉換器,並校準。
在設定完了以上資訊後,我們就開啟AD轉換器,執行復位校準和AD校準,注意這兩步是必須的!不校準將導致結果很不準確。
6 )讀取ADC值。
在上面的校準完成之後,ADC就算準備好了。接下來我們要做的就是設定規則序列 0 裡面的通道,然後啟動ADC轉換。在轉換結束後,讀取ADC1_DR 裡面的值就是了。
硬體設定:我們通過ADC1 的通道0 (PA 0 )來讀取外部電壓值。
注意:這裡不能接到板上5V電源上去測試,這可能會燒壞 ADC!
ADC.C
#include <stm32f10x_lib.h> #include "adc.h" //ADC 驅動程式碼 //初始化ADC //這裡我們僅以規則通道為例 //我們預設將開啟通道0~3 void Adc_Init(void) { //先初始化IO口 RCC->APB2ENR|=1<<2; //使能PORTA口時鐘 GPIOA->CRL&=0XFFFF0000;//PA0 1 2 3 anolog輸入 //通道10/11設定 RCC->APB2ENR|=1<<9; //ADC1時鐘使能 RCC->APB2RSTR|=1<<9; //ADC1復位 RCC->APB2RSTR&=~(1<<9);//復位結束 RCC->CFGR&=~(3<<14); //分頻因子清零 //SYSCLK/DIV2=12M ADC時鐘設定為12M,ADC最大時鐘不能超過14M! //否則將導致ADC準確度下降! RCC->CFGR|=2<<14; ADC1->CR1&=0XF0FFFF; //工作模式清零 ADC1->CR1|=0<<16; //獨立工作模式 ADC1->CR1&=~(1<<8); //非掃描模式 ADC1->CR2&=~(1<<1); //單次轉換模式 ADC1->CR2&=~(7<<17); ADC1->CR2|=7<<17; //軟體控制轉換 ADC1->CR2|=1<<20; //使用用外部觸發(SWSTART)!!! 必須使用一個事件來觸發 ADC1->CR2&=~(1<<11); //右對齊 ADC1->SQR1&=~(0XF<<20); ADC1->SQR1&=0<<20; //1個轉換在規則序列中 也就是隻轉換規則序列1 //設定通道0~3的取樣時間 ADC1->SMPR2&=0XFFFFF000;//通道0,1,2,3取樣時間清空 ADC1->SMPR2|=7<<9; //通道3 239.5週期,提高取樣時間可以提高精確度 ADC1->SMPR2|=7<<6; //通道2 239.5週期,提高取樣時間可以提高精確度 ADC1->SMPR2|=7<<3; //通道1 239.5週期,提高取樣時間可以提高精確度 ADC1->SMPR2|=7<<0; //通道0 239.5週期,提高取樣時間可以提高精確度 ADC1->CR2|=1<<0; //開啟AD轉換器 ADC1->CR2|=1<<3; //使能復位校準 while(ADC1->CR2&1<<3); //等待校準結束 //該位由軟體設定並由硬體清除。在校準暫存器被初始化後該位將被清除。 ADC1->CR2|=1<<2; //開啟AD校準 while(ADC1->CR2&1<<2); //等待校準結束 //該位由軟體設定以開始校準,並在校準結束時由硬體清除 } //獲得ADC值 //ch:通道值 0~3 u16 Get_Adc(u8 ch) { //設定轉換序列 ADC1->SQR3&=0XFFFFFFE0;//規則序列1 通道ch ADC1->SQR3|=ch; ADC1->CR2|=1<<22; //啟動規則轉換通道 while(!(ADC1->SR&1<<1));//等待轉換結束 return ADC1->DR; //返回adc值 }
- #ifndef __ADC_H
- #define __ADC_H
- #define ADC_CH0 0//通道0
- #define ADC_CH1 1//通道1
- #define ADC_CH2 2//通道2
- #define ADC_CH3 3//通道3
- voidAdc_Init(void);
- u16 Get_Adc(u8 ch);
- #endif