目錄
1:簡歷
2:逐次逼近型ADC
3:ADC基本結(jié)構(gòu)
?4:輸入通道
5:規(guī)則組的4種轉(zhuǎn)換模式?
1:單次轉(zhuǎn)化,非掃描模式
2:連續(xù)轉(zhuǎn)化,非掃描模式
3:單次轉(zhuǎn)化,掃描模式
4:單次轉(zhuǎn)化,掃描模式
6:觸發(fā)控制
7:數(shù)據(jù)對齊
?8:轉(zhuǎn)化時間
9:校準
10:ADC的硬件電路
A: AD單通道
1:連接圖?
2:函數(shù)介紹
3:步驟
4:代碼
?B:AD多通道
?1:連接圖??
2:代碼
1:簡歷
????????ADC(Analog-Digital Converter)模擬-數(shù)字轉(zhuǎn)換器
????????ADC可以將引腳上連續(xù)變化的模擬電壓轉(zhuǎn)換為內(nèi)存中存儲的數(shù)字變量,建立模擬電路到數(shù)字電路的橋梁
????????12位逐次逼近型ADC,1us轉(zhuǎn)換時間
????????輸入電壓范圍:0~3.3V,轉(zhuǎn)換結(jié)果范圍:0~4095
????????18個輸入通道,可測量16個外部(GPIO)和2個內(nèi)部信號源(內(nèi)部溫度傳感器和內(nèi)部參考電壓)
????????規(guī)則組和注入組兩個轉(zhuǎn)換單元
????????模擬看門狗自動監(jiān)測
????????輸入電壓范圍 STM32F103C8T6 ADC資源:ADC1、ADC2,10個外部輸入通道
????????12位逐次逼近型ADC,1us轉(zhuǎn)換時間 :?
????????分辨率 :?一般用多少位來表示,12位AD值,它的表示范圍就是0~2^12-1,量化結(jié)果的范圍是0~4095 ,?位數(shù)越高,量化結(jié)果就越精細,對應(yīng)分辨率就越高
????????轉(zhuǎn)換時間: 就是轉(zhuǎn)化頻率AD轉(zhuǎn)換是需要花一小段時間的,這里1us就表示從AD轉(zhuǎn)換開始到產(chǎn)生結(jié)果,需要花1us的時間。對應(yīng)AD轉(zhuǎn)換的頻率就是1MHZ ,??這個就是STM32 ADC的最快轉(zhuǎn)換頻率
?規(guī)則組和注入組兩個轉(zhuǎn)換單元:
????????普通的AD轉(zhuǎn)換流程是,啟動一次轉(zhuǎn)換、讀一次值 ,?然后再啟動、再讀值,這樣的流程 ;?
STM32的ADC就比較高級:?可以列一個組,一次性啟動一個組,連續(xù)轉(zhuǎn)換多個值 ,?并且有兩個組,一個是用于常規(guī)使用的規(guī)則組 ,一個是用于突發(fā)事件的注入組
2:逐次逼近型ADC
?????????ADC0809 :?獨立的8位逐次逼近型ADC芯片
????????EOC是End of Convert : 轉(zhuǎn)換結(jié)束信號
????????START : 是開始轉(zhuǎn)換,給一個輸入脈沖,開始轉(zhuǎn)換
????????CLOCK : 是ADC時鐘,因為ADC內(nèi)部是一步一步進行判斷的
????????REF+和VREF- : DAC的參考電壓
3:ADC基本結(jié)構(gòu)
?4:輸入通道
5:規(guī)則組的4種轉(zhuǎn)換模式?
在初始化ADC時配置的參數(shù)
單次轉(zhuǎn)化 :?ADC 執(zhí)行一次轉(zhuǎn)換,然后,ADC 停止
連續(xù)轉(zhuǎn)化:?與單次轉(zhuǎn)換不同的是,它在一次轉(zhuǎn)換結(jié)束后不會停止 ,??而是立刻開始下一輪的轉(zhuǎn)換,然后一直持續(xù)下去? ,??這樣就只需要最開始觸發(fā)一次,之后就可以一直轉(zhuǎn)換了
掃描模式 : 在組中填幾個通道幾個通道就有效 , 填入多個的時候應(yīng)避免覆蓋的問題,? 使用使用DMA
非掃描模式 : 這個組就只有第一個序列1的位置有效 , 這時選中一組的方式就退化為簡單地選中一個的方式了
?X.ADC_ContinuousConvMode=DISABLE;//選擇是連續(xù)轉(zhuǎn)換還是單次轉(zhuǎn)換---單X.ADC_ScanConvMode=DISABLE;//可以選擇是掃描模式還是非掃描模式---非掃描模式
1:單次轉(zhuǎn)化,非掃描模式
?
????????在非掃描的模式下,這個組就只有第一個序列1的位置有效 , 這時選中一組的方式就退化為簡單地選中一個的方式了
????????我們可以在序列1的位置指定我們想轉(zhuǎn)換的通道 ,?比如通道2 ,?然后,我們就可以觸發(fā)轉(zhuǎn)換,ADC就會對這個通道2進行模數(shù)轉(zhuǎn)換 , 過一段時間轉(zhuǎn)化完成? , 轉(zhuǎn)換結(jié)果放在數(shù)據(jù)寄存器里,同時給EOC標志位置1----轉(zhuǎn)換過程就結(jié)束了 .? ?我們判斷這個EOC標志位,如果轉(zhuǎn)換完了 ,??可以在數(shù)據(jù)寄存器里讀取結(jié)果了 ,??如果我們想再啟動一次轉(zhuǎn)換,那就需要再觸發(fā)一次 ,??轉(zhuǎn)換結(jié)束,置EOC標志位,讀結(jié)果
2:連續(xù)轉(zhuǎn)化,非掃描模式
?
????????首先,它還是非掃描模式,所以組列表就只用第一個? ,? 與單次轉(zhuǎn)換不同的是,它在一次轉(zhuǎn)換結(jié)束后不會停止 ,??而是立刻開始下一輪的轉(zhuǎn)換,然后一直持續(xù)下去? ,??這樣就只需要最開始觸發(fā)一次,之后就可以一直轉(zhuǎn)換了
? ? ? ? 優(yōu)點? :? 開始轉(zhuǎn)換之后不需要等待一段時間的 ,??它一直都在轉(zhuǎn)換,所以你就不需要手動開始轉(zhuǎn)換了 ,?也不用判斷是否結(jié)束的 ,??想要讀AD值的時候,直接從數(shù)據(jù)寄存器取就是了
3:單次轉(zhuǎn)化,掃描模式
?
????????這個模式也是單次轉(zhuǎn)換,所以每觸發(fā)一次 ,?轉(zhuǎn)換結(jié)束后,就會停下來? ,??下次轉(zhuǎn)換就得再觸發(fā)能開始
????????掃描模式 : 會用到這個組了 , 在序列中填入通道 ,?這里每個位置是通道幾可以任意指定,并且也是可以重復(fù)的 ,??初始化結(jié)構(gòu)體里還會有個參數(shù),就是通道數(shù)目 (x.ADC_NbrOfChannel=)??比如這里指定通道數(shù)目為7,那它就只看前7個位置,那么x.ADC_NbrOfChannel=7, 它就會只對前7個AD通道進行轉(zhuǎn)化,? ?轉(zhuǎn)換結(jié)果都放在數(shù)據(jù)寄存器里? ,? ?這里為了防止數(shù)據(jù)被覆蓋,就需要用DMA及時將數(shù)據(jù)挪走? ,??那7個通道轉(zhuǎn)換完成之后,產(chǎn)生EOC信號(EOC置1),轉(zhuǎn)換結(jié)束 ,??然后再觸發(fā)下一次,就又開始新一輪的轉(zhuǎn)換
使用DMA---避免通道數(shù)據(jù)覆蓋
????????因為這里只有一個規(guī)則組的數(shù)據(jù)寄存器 , 如果使用了?掃描模式在一個組中開啟了7個通道,? 只會有最后一個通道被保留下來,? 前面的6個通道會被覆蓋掉. 最后只會得到一個通道.
? ? ? ? 使用這里使用MDA在下一個通道來之前,? 把現(xiàn)在的數(shù)據(jù)放到了MDA中, 避免出現(xiàn)通道的覆蓋問題
4:單次轉(zhuǎn)化,掃描模式
?????????次轉(zhuǎn)換完成后,立刻開始下一次的轉(zhuǎn)換 , 也開啟組
6:觸發(fā)控制
配置ADC時使用的參數(shù)-----X.ADC_ExternalTrigConv
7:數(shù)據(jù)對齊
ADC初始化中的配置---X.ADC_DataAlign
?
????????我們這個ADC是12位的,它的轉(zhuǎn)換結(jié)果就是一個12位的數(shù)據(jù) ,??但是這個數(shù)據(jù)寄存器是16位的,所以就存在一個數(shù)據(jù)對齊的問題
右對齊 :?就是12位的數(shù)據(jù)向右靠 ,?就是12位的數(shù)據(jù)向有靠 ,?高位多出來的幾位就補0 ,一般
使用右對齊,??這樣讀取這個16位寄存器,直接就是轉(zhuǎn)換結(jié)果
左對齊 :?是12位的數(shù)據(jù)向左靠 ,??低位多出來的幾位補0 ,? 得到的數(shù)據(jù)會比實際的大 ,??數(shù)據(jù)左對齊實際上就是把數(shù)據(jù)左移了4次? ,數(shù)據(jù)左移一次,就等效于把這個數(shù)據(jù)乘2 , 直接讀取的話相當于把數(shù)據(jù)擴大了16倍 .?
?8:轉(zhuǎn)化時間
?
?
9:校準
????????ADC有一個內(nèi)置自校準模式。校準可大幅減小因內(nèi)部電容器組的變化而造成的準精度誤差。校準期間,在每個電容器上都會計算出一個誤差修正碼(數(shù)字值),這個碼用于消除在隨后的轉(zhuǎn)換中每個電容器上產(chǎn)生的誤差
????????建議在每次上電后執(zhí)行一次校準
????????啟動校準前, ADC必須處于關(guān)電狀態(tài)超過至少兩個ADC時鐘周期
10:ADC的硬件電路
?
A: AD單通道
1:連接圖
?
2:函數(shù)介紹
在stm32f10x rcc.h文件中-----配置ADCCLK
void RCC_ADCCLKConfig(uint32_t RCC_PCLK2)
RCC_ADCCLKConfig :??APB2時鐘72MHz時鐘信號然后通過ADC預(yù)分頻器進行分頻,得到ADCCLK鐘信號 ;?ADCCLK最大是14MHz , 所以這里只能是6分頻或者是8分頻
? ? ? ? 6分頻:72Mhz/6=12Mhz,? ? ? ? ? ? ?8分頻:72Mhz/8=9Mhz
在stm32f10x adc.h文件中----選擇組----我們選擇規(guī)則組的輸入通道
void ADC_RegularChannelConfig(ADC_TypeDef* ADCx, uint8_t ADC_Channel, uint8_t Rank, uint8_t ADC_SampleTime);
?ADC_RegularChannelConfig : 參數(shù)2--選擇通道 , 參數(shù)3--選擇序列范圍1~16? ? ? ?參數(shù)3: 指定通道的采樣時間
在stm32f10x adc.h文件中----初始化ADC
void ADC_Init(ADC_TypeDef* ADCx, ADC_InitTypeDef* ADC_InitStruct);
ADC_InitTypeDef ADC_initstruct;
?? ?ADC_initstruct.ADC_ContinuousConvMode=DISABLE;//選擇是連續(xù)轉(zhuǎn)換還是單次轉(zhuǎn)換---單次
?? ?ADC_initstruct.ADC_DataAlign=ADC_DataAlign_Right; //數(shù)據(jù)對齊---右對齊
?? ?ADC_initstruct.ADC_ExternalTrigConv=ADC_ExternalTrigConv_None;//觸發(fā)控制的觸發(fā)源---不使用外部觸發(fā),使用內(nèi)部軟件觸發(fā)
?? ?ADC_initstruct.ADC_Mode=ADC_Mode_Independent;//ADC的工作模式---獨立模式
?? ?ADC_initstruct.ADC_NbrOfChannel=1; ?//通道數(shù)目--指定在掃描模式下,總共會用到幾個通道
?? ?ADC_initstruct.ADC_ScanConvMode=DISABLE;//可以選擇是掃描模式還是非掃描模式---非掃描模式
?? ?ADC_Init(ADC1,&ADC_initstruct);
在stm32f10x adc.h文件中----開啟ADC
void ADC_Cmd(ADC_TypeDef* ADCx, FunctionalState NewState)
在stm32f10x adc.h文件中----校準ADC
第一步,調(diào)用第一個函數(shù),復(fù)位校準
第二步,調(diào)用第二個函數(shù),等待復(fù)位校準完成
第三步,調(diào)用第三個函數(shù),開始校準
第四步,調(diào)用第四個函數(shù),等待校準完成
1 : void ADC_ResetCalibration(ADC_TypeDef* ADCx);
2 : FlagStatus ADC_GetResetCalibrationStatus(ADC_TypeDef* ADCx);
3 : void ADC_StartCalibration(ADC_TypeDef* ADCx);
4 : FlagStatus ADC_GetCalibrationStatus(ADC_TypeDef* ADCx);
ADC_ResetCalibration :?復(fù)位校準
ADC_GetResetCalibrationStatus :?等待復(fù)位校準完成
ADC_StartCalibration :?開始校準
ADC_GetCalibrationStatus :?獲取校準狀態(tài)
在stm32f10x adc.h文件中----啟動轉(zhuǎn)換,獲取結(jié)果
void ADC_SoftwareStartConvCmd(ADC_TypeDef* ADCx, FunctionalState NewState);
FlagStatus ADC_GetFlagStatus(ADC_TypeDef* ADCx, uint8_t ADC_FLAG);
uint16_t ADC_GetConversionValue(ADC_TypeDef* ADCx)
ADC_SoftwareStartConvCmd :?軟件觸發(fā)轉(zhuǎn)換
ADC_GetFlagStatus :?獲取標志位狀態(tài)的函數(shù)
ADC_GetConversionValue :?ADC 獲取轉(zhuǎn)換值
3:步驟
1:RCC開啟時鐘-----ADC和GPIO的時鐘
2:?配置ADCCLK----RCC_ADCCLKConfig
3: 配置GPIO-----GPIO_Init
4:選擇組----我們選擇規(guī)則組的輸入通道--------ADC_RegularChannelConfig
5:?初始化ADC-----ADC_Init
6:開啟ADC----ADC_Cmd
7:校準ADC:
A:?復(fù)位校準-----ADC_ResetCalibration
B:等待復(fù)位校準完成----ADC_GetResetCalibrationStatus
C:?開始校準-----ADC_StartCalibration
D:獲取校準狀態(tài)-----ADC_GetCalibrationStatus?
4:代碼
????????使用的是單次轉(zhuǎn)化,非掃描模式
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "OLED.h"
#include "AD.h"
void AD_init(void){
//RCC開啟時鐘
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
//配置ADCCLK
//APB2時鐘72MHz時鐘信號然后通過ADC預(yù)分頻器進行分頻,得到ADCCLK鐘信號
RCC_ADCCLKConfig(RCC_PCLK2_Div6);//72Mhz/6=12Mhz
//配置GPIO
GPIO_InitTypeDef GPIO_initstruct;
GPIO_initstruct.GPIO_Mode=GPIO_Mode_AIN; //模擬輸入,可以理解為ADC的專屬模式
GPIO_initstruct.GPIO_Pin=GPIO_Pin_0;
GPIO_initstruct.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&GPIO_initstruct);
//選擇AD轉(zhuǎn)化器----我們選擇規(guī)則組的輸入通道
ADC_RegularChannelConfig(ADC1,ADC_Channel_0,1,ADC_SampleTime_55Cycles5);
/*ADC_Channel_0--通道o
1----1~16的范圍規(guī)則組第幾個序列
ADC_SampleTime_55Cycles5-----指定通道的采樣時間
*/
//初始化ADC
ADC_InitTypeDef ADC_initstruct;
ADC_initstruct.ADC_ContinuousConvMode=DISABLE;//選擇是連續(xù)轉(zhuǎn)換還是單次轉(zhuǎn)換---單次
ADC_initstruct.ADC_DataAlign=ADC_DataAlign_Right; //數(shù)據(jù)對齊---右對齊
ADC_initstruct.ADC_ExternalTrigConv=ADC_ExternalTrigConv_None;//觸發(fā)控制的觸發(fā)源---不使用外部觸發(fā),使用內(nèi)部軟件觸發(fā)
ADC_initstruct.ADC_Mode=ADC_Mode_Independent;//ADC的工作模式---獨立模式
ADC_initstruct.ADC_NbrOfChannel=1; //通道數(shù)目--指定在掃描模式下,總共會用到幾個通道
ADC_initstruct.ADC_ScanConvMode=DISABLE;//可以選擇是掃描模式還是非掃描模式---非掃描模式
ADC_Init(ADC1,&ADC_initstruct);
//開啟ADC
ADC_Cmd(ADC1,ENABLE);
//校準ADC
//復(fù)位校準
ADC_ResetCalibration(ADC1);//---把CR2_RSTCAL_Set這一位置一
//等待復(fù)位校準完成--ADC_GetResetCalibrationStatus作用:返回復(fù)位校準的狀態(tài)
while (ADC_GetResetCalibrationStatus(ADC1)==SET); //SET=1
/*獲取的是這個CR2_RSTCAL_Set的標志位 ,該位由軟件設(shè)置并由硬件清除
在校準寄存器被初始化后該位將被清除,所以該位的用法就是:
你軟件置該位為1,那硬件就會開始復(fù)位校準 , 當復(fù)位校準完成后,該位就會由硬件自動清0
*/
//開始校準
ADC_StartCalibration(ADC1);
//獲取校準狀態(tài)
while(ADC_GetCalibrationStatus(ADC1)==SET);
}
uint16_t ad_getvalue(){
//啟動轉(zhuǎn)換,獲取結(jié)果
//軟件觸發(fā)轉(zhuǎn)換
ADC_SoftwareStartConvCmd(ADC1,ENABLE);
//獲取標志位狀態(tài)的函數(shù)
while(ADC_GetFlagStatus(ADC1,ADC_FLAG_EOC)==RESET);
/*
EOC是規(guī)則組或注入組完成時都會置1 , 0(RESET):轉(zhuǎn)換未完成:
1(SET):轉(zhuǎn)換完成
*/
//ADC 獲取轉(zhuǎn)換值
return ADC_GetConversionValue(ADC1);
/*ADC_GetConversionValue---那這里,因為讀取DR寄存器會自動清除EOC標志位
所以這之后我們就不需要再手動清除標志位了
*/
}
uint16_t advalue;
float volatge;
int main(void)
{
OLED_Init();
AD_init();
OLED_ShowString(1, 1, "ADValue:");
OLED_ShowString(2, 1, "volatge:0.00V");
while (1)
{
advalue=ad_getvalue();
volatge=(float)advalue /4095 *3.3;
OLED_ShowNum(1, 9, advalue, 4);
OLED_ShowNum(2, 9, volatge, 1);
//浮點數(shù)不能取余
OLED_ShowNum(2, 11, (uint16_t)(volatge * 100) % 100, 2);
Delay_ms(100);
//OLED_ShowNum函數(shù)是寫整數(shù)的,所以使用這中方法表示小數(shù)
}
}
校準ADC? ? ?SET=1? ?RESET=0
? ? ? ?//復(fù)位校準
?? ?ADC_ResetCalibration(ADC1);
? ?//等待復(fù)位校準完成
?? ?while (ADC_GetResetCalibrationStatus(ADC1)==SET);? ?
?? ?//開始校準
?? ?ADC_StartCalibration(ADC1);
?? ?//獲取校準狀態(tài)
?? ?while(ADC_GetCalibrationStatus(ADC1)==SET);????????復(fù)位校準(ADC_ResetCalibration)函數(shù)的作用是把CR2_RSTCAL_Set這一位置一 ;?
?????????等待復(fù)位校準完成(while (ADC_GetResetCalibrationStatus(ADC1)==SET) :??獲取的是這個CR2_RSTCAL_Set的標志位 ,該位由軟件設(shè)置并由硬件清除在校準寄存器被初始化后該位將被清除,所以該位的用法就是:你軟件置該位為1,那硬件就會開始復(fù)位校準 , 當復(fù)位校準完成后,該位就會由硬件自動清0
????????開始校準(ADC_StartCalibration) : 這樣子就可以啟動校準
????????獲取校準狀態(tài)(while(ADC_GetCalibrationStatus(ADC1)==SET);) : 看校準是否完成
啟動轉(zhuǎn)換,獲取結(jié)果? ??SET=1? ?RESET=0
?????????????//軟件觸發(fā)轉(zhuǎn)換
?? ?ADC_SoftwareStartConvCmd(ADC1,ENABLE);
?? ?//獲取標志位狀態(tài)的函數(shù)
?? ?while(ADC_GetFlagStatus(ADC1,ADC_FLAG_EOC)==RESET);
?? ? //ADC 獲取轉(zhuǎn)換值
?? ?return ADC_GetConversionValue(ADC1);
??????????軟件觸發(fā)轉(zhuǎn)換(ADC_SoftwareStartConvCmd) : ADC開始轉(zhuǎn)化????????獲取標志位狀態(tài)的函(while(ADC_GetFlagStatus(ADC1,ADC_FLAG_EOC)==RESET);)
:?EOC是規(guī)則組或注入組完成時都會置1 , 0(RESET):轉(zhuǎn)換未完成:1(SET):轉(zhuǎn)換完成
????????ADC 獲取轉(zhuǎn)換值(ADC_GetConversionValue(ADC1);) :?ADC_GetConversionValue---那這里,因為讀取DR寄存器會自動清除EOC標志位?所以這之后我們就不需要再手動清除標志位了
?? ?按照上面的流程來執(zhí)行就ok了 :?首先,軟件觸發(fā)轉(zhuǎn)換 , 然后等待轉(zhuǎn)換完成,也就是等待EOC標志位置1?,?最后,讀取ADC數(shù)據(jù)寄存器
配置GPIO---模式選擇模擬輸入?
GPIO_initstruct.GPIO_Mode=GPIO_Mode_AIN;
????????在AIN模式下,GPIO口是無效的 ,? 斷開GPIO”防止你GPIO口的輸入輸出對我模擬電壓造成干擾 ,??所以AIN模式就是ADC的專屬模式
引腳分布
? ? ? ?
使用連續(xù)轉(zhuǎn)化,非掃描模式
????????優(yōu)點:?不需要不斷地觸發(fā),也不需要等待轉(zhuǎn)換完成的
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "OLED.h"
#include "AD.h"
void AD_init(void){
//RCC開啟時鐘
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
//配置ADCCLK
//APB2時鐘72MHz時鐘信號然后通過ADC預(yù)分頻器進行分頻,得到ADCCLK鐘信號
RCC_ADCCLKConfig(RCC_PCLK2_Div6);//72Mhz/6=12Mhz
//配置GPIO
GPIO_InitTypeDef GPIO_initstruct;
GPIO_initstruct.GPIO_Mode=GPIO_Mode_AIN; //模擬輸入,可以理解為ADC的專屬模式
GPIO_initstruct.GPIO_Pin=GPIO_Pin_0;
GPIO_initstruct.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&GPIO_initstruct);
//選擇AD轉(zhuǎn)化器----我們選擇規(guī)則組的輸入通道
ADC_RegularChannelConfig(ADC1,ADC_Channel_0,1,ADC_SampleTime_55Cycles5);
/*ADC_Channel_0 --通道o
1----1~16的范圍規(guī)則組第幾個序列
ADC_SampleTime_55Cycles5-----指定通道的采樣時間
*/
//初始化ADC
ADC_InitTypeDef ADC_initstruct;
ADC_initstruct.ADC_ContinuousConvMode=ENABLE;//選擇是連續(xù)轉(zhuǎn)換還是單次轉(zhuǎn)換---單次
ADC_initstruct.ADC_DataAlign=ADC_DataAlign_Right; //數(shù)據(jù)對齊---右對齊
ADC_initstruct.ADC_ExternalTrigConv=ADC_ExternalTrigConv_None;//觸發(fā)控制的觸發(fā)源---不使用外部觸發(fā),使用內(nèi)部軟件觸發(fā)
ADC_initstruct.ADC_Mode=ADC_Mode_Independent;//ADC的工作模式---獨立模式
ADC_initstruct.ADC_NbrOfChannel=1; //通道數(shù)目--指定在掃描模式下,總共會用到幾個通道
ADC_initstruct.ADC_ScanConvMode=DISABLE;//可以選擇是掃描模式還是非掃描模式---非掃描模式
ADC_Init(ADC1,&ADC_initstruct);
//開啟ADC
ADC_Cmd(ADC1,ENABLE);
//校準ADC
//復(fù)位校準
ADC_ResetCalibration(ADC1);//---把CR2_RSTCAL_Set這一位置一
//等待復(fù)位校準完成--ADC_GetResetCalibrationStatus作用:返回復(fù)位校準的狀態(tài)
while (ADC_GetResetCalibrationStatus(ADC1)==SET); //SET=1
/*獲取的是這個CR2_RSTCAL_Set的標志位 ,該位由軟件設(shè)置并由硬件清除
在校準寄存器被初始化后該位將被清除,所以該位的用法就是:
你軟件置該位為1,那硬件就會開始復(fù)位校準 , 當復(fù)位校準完成后,該位就會由硬件自動清0
*/
//開始校準
ADC_StartCalibration(ADC1);
//獲取校準狀態(tài)
while(ADC_GetCalibrationStatus(ADC1)==SET);
//軟件觸發(fā)轉(zhuǎn)換
ADC_SoftwareStartConvCmd(ADC1,ENABLE);//連續(xù)模式下只需要觸發(fā)一次
}
uint16_t ad_getvalue(){
//啟動轉(zhuǎn)換,獲取結(jié)果
return ADC_GetConversionValue(ADC1);
/*ADC_GetConversionValue---那這里,因為讀取DR寄存器會自動清除EOC標志位
所以這之后我們就不需要再手動清除標志位了
*/
}
uint16_t advalue;
float volatge;
int main(void)
{
OLED_Init();
AD_init();
OLED_ShowString(1, 1, "ADValue:");
OLED_ShowString(2, 1, "volatge:0.00V");
while (1)
{
advalue=ad_getvalue();
volatge=(float)advalue /4095 *3.3;
OLED_ShowNum(1, 9, advalue, 4);
OLED_ShowNum(2, 9, volatge, 1);
OLED_ShowNum(2, 11, (uint16_t)(volatge * 100) % 100, 2);
Delay_ms(100);
}
}
????????因為使用了連續(xù)模式 , 使用只有需要觸發(fā)一次即可,? 把//軟件觸發(fā)轉(zhuǎn)換?ADC_SoftwareStartConvCmd(ADC1,ENABLE);移到 void AD_init函數(shù)下即可
????????//獲取標志位狀態(tài)的while(ADC_GetFlagStatus(ADC1,ADC_FLAG_EOC)==RESET);
在初始化完成之后,觸發(fā)一次就行了 ,?內(nèi)部的ADC就會一次接著一次地、連續(xù)不斷地 ,??對我們指定的通道0進行轉(zhuǎn)換,轉(zhuǎn)換結(jié)果放在數(shù)據(jù)寄存器里? ,??此時數(shù)據(jù)寄存器會不斷地刷新最新的轉(zhuǎn)換結(jié)果 ,使用在uint16_t ad_getvalue() 這里就不需要獲取標志位狀態(tài)的函數(shù)了
?B:AD多通道
?1:連接圖??
?AO----模擬量的輸出引腳
3個模塊的AO,分別接在PA1、PA2和PA3口
DO-----數(shù)字輸出
????????AO是指傳感器輸出的模擬電信號:????????可以是電壓、電流等連續(xù)變化的信號,其數(shù)值與光照強度(或其他被測量的參數(shù))相關(guān)。AO信號可以通過模數(shù)轉(zhuǎn)換器(ADC)轉(zhuǎn)換為數(shù)字信號,以供后續(xù)處理或控制使用。
????????DO是指傳感器輸出的數(shù)字信號:????????通常以邏輯電平(例如高電平或低電平)表示,表示光照強度(或其他被測量的參數(shù))是否達到或超過設(shè)定的閾值。DO信號可以直接用于觸發(fā)開關(guān)、報警或其他數(shù)字控制應(yīng)用。
通過同時使用AO和DO,光敏傳感器可以提供更豐富的信息輸出,并滿足不同應(yīng)用場景的需求。
以前我們使用的都是DO,? 這里我們使用的為A0
2:代碼
使用: 單次非掃描的模式
????????多通道? :? 首先我們應(yīng)該想到掃描的模式 , 啟動一個組在組中填入我們要使用的通道,? 但是由于覆蓋的問題,要使用DMA(見下一節(jié)) ,所以沒有使用掃描模式
????????//選擇AD轉(zhuǎn)化器----我們選擇規(guī)則組的輸入通道
?? ?ADC_RegularChannelConfig(ADC1,ADC_Channel,1,ADC_SampleTime_55Cycles5); 第二個參數(shù)就是我們的通道,? 我們把通道作為參數(shù), 放在組中的第一給序列中, 只需要在主函數(shù)中不斷調(diào)用ad_getvalue函數(shù)即可文章來源:http://www.zghlxwxcb.cn/news/detail-681794.html
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "OLED.h"
#include "AD.h"
void AD_init(void){
//RCC開啟時鐘
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
//配置ADCCLK
//APB2時鐘72MHz時鐘信號然后通過ADC預(yù)分頻器進行分頻,得到ADCCLK鐘信號
RCC_ADCCLKConfig(RCC_PCLK2_Div6);//72Mhz/6=12Mhz
//配置GPIO
GPIO_InitTypeDef GPIO_initstruct;
GPIO_initstruct.GPIO_Mode=GPIO_Mode_AIN; //模擬輸入,可以理解為ADC的專屬模式
GPIO_initstruct.GPIO_Pin=GPIO_Pin_0 |GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3;
GPIO_initstruct.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&GPIO_initstruct);
/*ADC_Channel_0 --通道o
1----1~16的范圍規(guī)則組第幾個序列
ADC_SampleTime_55Cycles5-----指定通道的采樣時間
*/
//初始化ADC
ADC_InitTypeDef ADC_initstruct;
ADC_initstruct.ADC_ContinuousConvMode=DISABLE;//選擇是連續(xù)轉(zhuǎn)換還是單次轉(zhuǎn)換---單次
ADC_initstruct.ADC_DataAlign=ADC_DataAlign_Right; //數(shù)據(jù)對齊---右對齊
ADC_initstruct.ADC_ExternalTrigConv=ADC_ExternalTrigConv_None;//觸發(fā)控制的觸發(fā)源---不使用外部觸發(fā),使用內(nèi)部軟件觸發(fā)
ADC_initstruct.ADC_Mode=ADC_Mode_Independent;//ADC的工作模式---獨立模式
ADC_initstruct.ADC_NbrOfChannel=1; //通道數(shù)目--指定在掃描模式下,總共會用到幾個通道
ADC_initstruct.ADC_ScanConvMode=DISABLE;//可以選擇是掃描模式還是非掃描模式---非掃描模式
ADC_Init(ADC1,&ADC_initstruct);
//開啟ADC
ADC_Cmd(ADC1,ENABLE);
//校準ADC
//復(fù)位校準
ADC_ResetCalibration(ADC1);//---把CR2_RSTCAL_Set這一位置一
//等待復(fù)位校準完成--ADC_GetResetCalibrationStatus作用:返回復(fù)位校準的狀態(tài)
while (ADC_GetResetCalibrationStatus(ADC1)==SET); //SET=1
/*獲取的是這個CR2_RSTCAL_Set的標志位 ,該位由軟件設(shè)置并由硬件清除
在校準寄存器被初始化后該位將被清除,所以該位的用法就是:
你軟件置該位為1,那硬件就會開始復(fù)位校準 , 當復(fù)位校準完成后,該位就會由硬件自動清0
*/
//開始校準
ADC_StartCalibration(ADC1);
//獲取校準狀態(tài)
while(ADC_GetCalibrationStatus(ADC1)==SET);
}
uint16_t ad_getvalue(uint8_t ADC_Channel){
//啟動轉(zhuǎn)換,獲取結(jié)果
//選擇AD轉(zhuǎn)化器----我們選擇規(guī)則組的輸入通道
ADC_RegularChannelConfig(ADC1,ADC_Channel,1,ADC_SampleTime_55Cycles5);
//軟件觸發(fā)轉(zhuǎn)換
ADC_SoftwareStartConvCmd(ADC1,ENABLE);
//獲取標志位狀態(tài)的函數(shù)
while(ADC_GetFlagStatus(ADC1,ADC_FLAG_EOC)==RESET);
/*
EOC是規(guī)則組或注入組完成時都會置1 , 0(RESET):轉(zhuǎn)換未完成:
1(SET):轉(zhuǎn)換完成
*/
//ADC 獲取轉(zhuǎn)換值
return ADC_GetConversionValue(ADC1);
/*ADC_GetConversionValue---那這里,因為讀取DR寄存器會自動清除EOC標志位
所以這之后我們就不需要再手動清除標志位了
*/
}
uint16_t AD1,AD2,AD3,AD4;
float volatge;
int main(void)
{
OLED_Init();
AD_init();
OLED_ShowString(1, 1, "AD0:");
OLED_ShowString(2, 1, "AD1:");
OLED_ShowString(3, 1, "AD2:");
OLED_ShowString(4, 1, "AD3:");
while (1)
{
AD1=ad_getvalue(ADC_Channel_0);
AD2=ad_getvalue(ADC_Channel_1);
AD3=ad_getvalue(ADC_Channel_2);
AD4=ad_getvalue(ADC_Channel_3);
OLED_ShowNum(1, 5, AD1, 4);
OLED_ShowNum(2, 5, AD2, 4);
OLED_ShowNum(3, 5, AD3, 4);
OLED_ShowNum(4, 5, AD4, 4);
Delay_ms(100);
}
}
?文章來源地址http://www.zghlxwxcb.cn/news/detail-681794.html
到了這里,關(guān)于07:STM32----ADC模數(shù)轉(zhuǎn)化器的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!