1、ADC簡介
? ? ? ? ADC,即Analog-Digital?Converter,模擬-數字轉換器。
????????ADC可以將引腳上連續變化的模擬電壓轉換為內存中存儲的數字變量,建立模擬電路到數字電路的橋梁。
????????12位逐次逼近型ADC,1us轉換時間。
????????輸入電壓范圍:0~3.3V,轉換結果范圍:0~4095(2的12次方)。
????????18個輸入通道,可測量16個外部和2個內部信號源。
????????規則組和注入組兩個轉換單元。
????????模擬看門狗自動監測輸入電壓范圍。
????????STM32F103C8T6 ADC資源:ADC1、ADC2,10個外部輸入通道。
2、ADC框圖
? ? ? ? 基于stm32f103x
? ? ? ? 逐次逼近型ADC
? ? ? ? EOC:End?of?Convert?轉換結束信號
? ? ? ? START:開始轉換,給一個輸入脈沖,開始轉換
? ? ? ? CLOCK:ADC時鐘,因為ADC內部是一步一步進行判斷的,需要時鐘來推動這個過程
? ? ? ? Vref+、Vref-:DAC的參考電壓,這個范圍也決定了ADC的輸入范圍,所以它也是ADC的參考電壓
? ? ? ? 簡化框圖
? ? ? ? ADC時序圖:
????????????????如下圖所示,ADC在開始精確轉換前需要一個穩定時間tSTAB。在開始ADC轉換和14個時鐘周期后,EOC標志被設置,16位ADC數據寄存器包含轉換的結果。
3、通道選擇
????????有16個多路通道。可以把轉換組織成兩組:規則組和注入組。在任意多個通道上以任意順序進行的一系列轉換構成成組轉換。例如,可以如下順序完成轉換:通道3、通道8、通道2、通道2、通道0、通道2、通道2、通道15。
3.1?規則組
????????規則組由多達16個轉換組成。規則通道和它們的轉換順序在ADC_SQRx寄存器中選擇。規則組中轉換的總數應寫入ADC_SQR1寄存器的L[3:0]位中。
? ? ? ? 規則組雖然有16個通道,但是只有1個數據寄存器,一次最多只能轉換1個通道,如果一次轉換16個通道,那么前15個會被覆蓋掉,只保留第16個。如果要使用規則組一次轉換多個通道,最好搭配DMA使用,轉換一個就轉移一個。
3.2?注入組
????????注入組由多達4個轉換組成。注入通道和它們的轉換順序在ADC_JSQR寄存器中選擇。注入組里的轉換總數目應寫入ADC_JSQR寄存器的L[1:0]位中。
? ? ? ? 注入組一次最多可以轉換4個通道,有4個數據寄存器。
4、轉換/掃描模式
4.1?單次轉換
????????單次轉換模式下,ADC只執行一次轉換。該模式既可通過設置ADC_CR2寄存器的ADON位(只適用于規則通道)啟動,也可通過外部觸發啟動(適用于規則通道或注入通道),這時CONT位為0。一旦選擇通道的轉換完成:
????????如果一個規則通道被轉換:
????????????????轉換數據被儲存在16位ADC_DR寄存器中
????????????????EOC(轉換結束)標志被設置
????????????????如果設置了EOCIE,則產生中斷。
????????如果一個注入通道被轉換:
????????????????轉換數據被儲存在16位的ADC_DRJ1寄存器中
????????????????JEOC(注入轉換結束)標志被設置
????????????????如果設置了JEOCIE位,則產生中斷。
? ? ? ? 然后ADC停止。
4.2?連續轉換
????????在連續轉換模式中,當前面ADC轉換一結束馬上就啟動另一次轉換。此模式可通過外部觸發啟動或通過設置ADC_CR2寄存器上的ADON位啟動,此時CONT位是1。每個轉換后:
????????如果一個規則通道被轉換:
????????????????轉換數據被儲存在16位的ADC_DR寄存器中
????????????????EOC(轉換結束)標志被設置
????????????????如果設置了EOCIE,則產生中斷。
????????如果一個注入通道被轉換:
????????????????轉換數據被儲存在16位的ADC_DRJ1寄存器中
????????????????JEOC(注入轉換結束)標志被設置
????????????????如果設置了JEOCIE位,則產生中斷。
4.3?掃描模式
????????此模式用來掃描一組模擬通道。
????????掃描模式可通過設置ADC_CR1寄存器的SCAN位來選擇。一旦這個位被設置,ADC掃描所有被ADC_SQRX寄存器(對規則通道)或ADC_JSQR(對注入通道)選中的所有通道。在每個組的每個通道上執行單次轉換。在每個轉換結束時,同一組的下一個通道被自動轉換。如果設置了CONT位,轉換不會在選擇組的最后一個通道上停止,而是再次從選擇組的第一個通道繼續轉換。如果設置了DMA位,在每次EOC后,DMA控制器把規則組通道的轉換數據傳輸到SRAM中。而注入通道轉換的數據總是存儲在ADC_JDRx寄存器中。
? ? ? ? 掃描模式一般與轉換模式結合使用。
5、觸發控制
????????轉換可以由外部事件觸發(例如定時器捕獲,EXTI線)。如果設置了EXTTRIG控制位,則外部事件就能夠觸發轉換。EXTSEL[2:0]和JEXTSEL2:0]控制位允許應用程序選擇8個可能的事件中的某一個,可以觸發規則和注入組的采樣。
????????注意:當外部觸發信號被選為ADC規則或注入轉換時,只有它的上升沿可以啟動轉換。
6、數據對齊
? ? ? ? ?本芯片的ADC是12位的,它的轉換結果就是一個12位的數據,但是這個數據寄存器是16位的,所以就存在一個數據對齊的問題。
????????ADC_CR2寄存器中的ALIGN位選擇轉換后數據儲存的對齊方式。數據可以左對齊或右對齊,如圖29和圖30所示。
????????注入組通道轉換的數據值已經減去了在ADC_JOFRx寄存器中定義的偏移量,因此結果可以是一個負值。SEXT位是擴展的符號值。
????????對于規則組通道,不需減去偏移值,因此只有12個位有效。
? ? ? ? 一般選擇使用的都是數據右對齊。
7、轉換時間
? ? ? ? AD轉換的步驟:采樣、保持、量化、編碼
????????ADC使用若干個ADC_CLK周期對輸入電壓采樣,采樣周期數目可以通過ADC_SMPR1和ADC_SMPR2寄存器中的SMP[2:0]位更改。每個通道可以分別用不同的時間采樣。
????????總轉換時間如下計算:
????????????????Tconv=采樣時間+12.5個周期
? ? ? ? 采樣時間是采樣保持花費的時間,采樣時間越大,越能避免一些毛刺信號的干擾,不過轉換時間也會相應延長;12.5個周期是量化編碼花費的時間,因為是12位的ADC,所以需要花費12個周期,多出來0.5個周期可能是要做一些其它東西花費的時間。ADC周期就是從RCC分頻過來的ADCCLK,這里這個ADCCLK最大為14KHz。
? ? ? ? 例如:當ADCCLK=14MHz,采樣時間為1.5個ADC周期
????????????????Tconv=1.5+12.5=14個ADC采樣周期=14*1/14MHz=1us
8、校準
????????ADC有一個內置自校準模式。校準可大幅減小因內部電容器組的變化而造成的準精度誤差。在校準期間,在每個電容器上都會計算出一個誤差修正碼(數字值),這個碼用于消除在隨后的轉換中每個電容器上產生的誤差。
????????通過設置ADC_CR2寄存器的CAL位啟動校準。一旦校準結束,CAL位被硬件復位,可以開始正常轉換。建議在上電時執行一次ADC校準。校準階段結束后,校準碼儲存在ADC_DR中。
? ? ? ? 注意:????????
? ? ? ? ? ? ? ? (1)建議在每次上電后執行一次校準。
? ? ? ? ? ? ? ? (2)啟動校準前,ADC必須處于關電狀態(ADON='O')超過至少兩個ADC時鐘周期。
????????校準時序圖:
9、ADC編程示例
//AD_Init.c
#include "stm32f10x.h" // Device headervoid AD_Init(void)
{//第一步,開啟RCC的時鐘,包括ADC和GPIO的時鐘,ADCCLK的分頻器也需要配置一下RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,ENABLE);RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);RCC_ADCCLKConfig(RCC_PCLK2_Div6); //ADCCLK = 72MHz / 6 = 12MHz//第二步,配置GPIO,將需要用的GPIO配制成模擬輸入的模式GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; //模擬輸入,在AIN模式下,gpio口是無效的,斷開gpio,防止gpio的輸入輸出對模擬電壓造成干擾GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA, &GPIO_InitStructure);//第三步,配置多路開關,把左邊的通道接入到右邊的規則組列表里ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_55Cycles5); //關于采樣時間的參數,需要更快的轉換就用小參數,需要穩定的轉換就用大參數,這里就是55.5個ADCCLK的周期//第四步,配置ADC轉換器ADC_InitTypeDef ADC_InitStructure;ADC_InitStructure.ADC_Mode = ADC_Mode_Independent; //ADC工作模式,獨立模式ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; //數據對齊方式,右對齊ADC_InitStructure.ADC_ContinuousConvMode = DISABLE; //連續轉換模式,可以選擇是連續轉換還是單次轉換ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; //外部觸發轉換選擇,就是觸發控制的觸發源,這里不使用外部觸發,用內部軟件觸發ADC_InitStructure.ADC_NbrOfChannel = 1; //通道數目,指定在掃描模式下總共會用到幾個通道ADC_InitStructure.ADC_ScanConvMode = DISABLE; //掃描轉換模式,可以選擇是掃描模式還是非掃描模式ADC_Init(ADC1, &ADC_InitStructure);//如果是連續轉換模式,僅需要在最開始觸發一次就行了,所以只要把下面軟件觸發轉換的函數放在初始化函數最后面就行,在初始化完成后觸發一次就行了//第五步,開關控制,開啟ADCADC_Cmd(ADC1, ENABLE);//對ADC進行校準,可以減少誤差ADC_ResetCalibration(ADC1); //復位校準while (ADC_GetResetCalibrationStatus(ADC1) == SET); //ADC_GetResetCalibrationStatus返回復位校準的狀態,如果狀態變為0了,說明復位校準完成,可以跳出等待了ADC_StartCalibration(ADC1); //開始校準,之后內部電路會自動開始校準while (ADC_GetCalibrationStatus(ADC1) == SET); //等待校準是否完成}uint16_t AD_GetValue(void)
{ADC_SoftwareStartConvCmd(ADC1, ENABLE); //使用ADC_SoftwareStartConvCmd軟件觸發轉換函數,觸發之后,adc就開始轉換了while (ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET); //獲取adc狀態標志位,ADC_FLAG_EOC規則組轉換完成標志位return ADC_GetConversionValue(ADC1); //獲取AD轉換的結果,獲取轉換值的函數是直接讀取ADC的DR數據寄存器,因為讀取DR寄存器會自動清楚EOC標志位,就不用手動再來清除標志位了
}
//main.c
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "OLED.h"
#include "AD.h"uint16_t ADValue;
float Voltage;int main(void)
{//初始化OLEDOLED_Init();AD_Init();// OLED_ShowChar(1, 1, 'A');OLED_ShowString(1, 1, "ADValue:");OLED_ShowString(2, 1, "Voltage:0.00V");
// OLED_ShowNum(2, 1, 12345, 5);
// OLED_ShowSignedNum(2, 7, -66, 2);
// OLED_ShowHexNum(3, 1, 0xAA55, 4);
// OLED_ShowBinNum(4, 1, 0xAA55, 16);// OLED_Clear();while (1){ADValue = AD_GetValue();Voltage = (float)ADValue / 4095 * 3.3;OLED_ShowNum(1, 9, ADValue, 4);OLED_ShowNum(2, 9, Voltage, 1);OLED_ShowNum(2, 11, (uint16_t)(Voltage * 100) % 100, 2);Delay_ms(100);}
}