一、ADC簡介:
1.名稱:
ADC,Analog-Digital Converter,模擬數字轉換器
2.用途:
相當于電壓表,原本引腳只有兩種狀態,高電平和低電平,使用ADC后,可以將0-3.3V間的任一引腳電壓(模擬電壓)測量出來,放到一個變量里(數字變量),實現模擬電路到數字電路的橋梁。
電壓范圍:0-3.3V,轉換范圍:0-4095(12位,后面要考),為線性關系
18個輸入通道,16個外部通道,接在GPIO口上,2個內部信號源。
規則組和注入組兩個轉換單元(后面介紹)。
模擬看門狗自動檢測輸入電壓范圍(后面介紹)。
3.框圖:
如圖,GPIO端口與下面兩個內部通道,構成了ADC的18個輸入通道,再根據輸入的模擬電壓,轉化成數字值存放在兩個數據寄存器中。
注入通道和規則通道,作用是,原本只能測量一個端口的模擬電壓,現在可以將多個端口同時傳給ADC,ADC也同時將多個端口的電壓值存放在寄存器中。
其中,規則通道,可以同時傳入16個輸入通道,但只有一個寄存器,所以需要配合DMA使用,即每次轉換完一個電壓值,就將這個值運走,好給接下來的值騰位置。?
主要學習規則通道。
4.功能圖:
看門狗:可以設置電壓的上限和下限,當電壓超過或低于上下限,看門狗將申請中斷。
觸發控制,觸發進行一次AD轉換,可由軟件或硬件(其他外設)控制。
5.引腳定義表:
本芯片沒有通道10-15。
6.轉換模式:
有四種,單次非掃描,連續非掃描,單次掃描,連續掃描。
單次轉換,非掃描模式:一次只能轉換一個通道,觸發轉換,一段時間后,轉換完成,EOC標志位置1,我們就可以在數據寄存器中讀取結果,要想進行下一次轉換,需要再次觸發。
若為連續轉換,無需再次觸發,將一直轉換下去。
若為掃描模式,可以同時轉換多個通道,就是上文提到的注入通道與規則通道的功能。
二、實戰:ADC單通道
1.接線圖:
電位器就是滑動變阻器,用于向PA0輸出可調電壓。
2.代碼:
AD.c
#include "stm32f10x.h" // Device header/*** 函 數:AD初始化* 參 數:無* 返 回 值:無*/
void AD_Init(void)
{/*開啟時鐘*/RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE); //開啟ADC1的時鐘RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //開啟GPIOA的時鐘/*設置ADC時鐘*/RCC_ADCCLKConfig(RCC_PCLK2_Div6); //選擇時鐘6分頻,ADCCLK = 72MHz / 6 = 12MHz/*GPIO初始化*/GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; //此處的AIN模式,是ADC專屬模式,端口變為模擬端口GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA, &GPIO_InitStructure); //將PA0引腳初始化為模擬輸入/*規則組通道配置*/ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_55Cycles5); //規則組序列1(單通道只有序列1,多通道時,序列順序決定寄存器存放順序)的位置,配置為通道0(對應PA0引腳)//參數3為序列值,參數4為采樣時間,越小越快,越大越穩/*ADC初始化*/ADC_InitTypeDef ADC_InitStructure; //定義結構體變量ADC_InitStructure.ADC_Mode = ADC_Mode_Independent; //模式,選擇獨立模式,即單獨使用ADC1ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; //數據對齊,選擇右對齊ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; //外部觸發,使用軟件觸發,不需要外部觸發ADC_InitStructure.ADC_ContinuousConvMode = DISABLE; //連續轉換,失能,每轉換一次規則組序列后停止ADC_InitStructure.ADC_ScanConvMode = DISABLE; //掃描模式,失能,只轉換規則組的序列1這一個位置ADC_InitStructure.ADC_NbrOfChannel = 1; //通道數,為1,僅在掃描模式下,才需要指定大于1的數,在非掃描模式下,只能是1ADC_Init(ADC1, &ADC_InitStructure); //將結構體變量交給ADC_Init,配置ADC1/*ADC使能*/ADC_Cmd(ADC1, ENABLE); //使能ADC1,ADC開始運行/*ADC校準*/ADC_ResetCalibration(ADC1); //固定流程,內部有電路會自動執行校準while (ADC_GetResetCalibrationStatus(ADC1) == SET);ADC_StartCalibration(ADC1);while (ADC_GetCalibrationStatus(ADC1) == SET);
}/*** 函 數:獲取AD轉換的值* 參 數:無* 返 回 值:AD轉換的值,范圍:0~4095*/
uint16_t AD_GetValue(void)
{ADC_SoftwareStartConvCmd(ADC1, ENABLE); //軟件觸發AD轉換一次while (ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET); //等待EOC標志位,即等待AD轉換結束return ADC_GetConversionValue(ADC1); //讀數據寄存器,得到AD轉換的結果
}
main.c
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "OLED.h"
#include "AD.h"uint16_t ADValue; //定義AD值變量
float Voltage; //定義電壓變量int main(void)
{/*模塊初始化*/OLED_Init(); //OLED初始化AD_Init(); //AD初始化/*顯示靜態字符串*/OLED_ShowString(1, 1, "ADValue:");OLED_ShowString(2, 1, "Voltage:0.00V");while (1){ADValue = AD_GetValue(); //獲取AD轉換的值Voltage = (float)ADValue / 4095 * 3.3; //將AD值線性變換到0~3.3的范圍,表示電壓OLED_ShowNum(1, 9, ADValue, 4); //顯示AD值OLED_ShowNum(2, 9, Voltage, 1); //顯示電壓值的整數部分OLED_ShowNum(2, 11, (uint16_t)(Voltage * 100) % 100, 2); //顯示電壓值的小數部分Delay_ms(100); //延時100ms,手動增加一些轉換的間隔時間}
}
3.連續轉換:
若使用連續轉換的模式:
將ADC初始化結構體,連續轉化置ENABLE。
由于只需要觸發一次,可以將觸發轉換函數ADC_SoftwareStartConvCmd放在初始化函數的最后。
同時AD_GetValue中,也不需要判斷標志位EOC。
三、實戰:ADC多通道
由于沒有學習DMA,因此此處不使用掃描模式,一次獲取多個通道的值,而是采用在多次更改通道,再獲取轉換值。
在AD.c中,將初始化函數中的ADC_RegularChannelConfig函數去掉,放在獲取轉換值的函數中。
如下:
/*** 函 數:獲取AD轉換的值* 參 數:ADC_Channel 指定AD轉換的通道,范圍:ADC_Channel_x,其中x可以是0/1/2/3* 返 回 值:AD轉換的值,范圍:0~4095*/
uint16_t AD_GetValue(uint8_t ADC_Channel)
{ADC_RegularChannelConfig(ADC1, ADC_Channel, 1, ADC_SampleTime_55Cycles5); //在每次轉換前,根據函數形參靈活更改規則組的通道ADC_SoftwareStartConvCmd(ADC1, ENABLE); //軟件觸發AD轉換一次while (ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET); //等待EOC標志位,即等待AD轉換結束return ADC_GetConversionValue(ADC1); //讀數據寄存器,得到AD轉換的結果
}
同時記得多打開使用的GPIO口。
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3;