【stm32f407】ADC實驗

1.      ADC簡介

STM32F4xx系列一般都有3個ADC,這些ADC可以獨立使用,也可以使用雙重/三重模式(提高採樣率)。STM32F4的ADC是12位逐次逼近型的模擬數字轉換器。它有19個通道,可測量16個外部源、2個內部源和Vbat通道的信號。這些通道的A/D轉換可以單次、連續、掃描或間斷模式執行。ADC的結果可以左對齊或右對齊方式存儲在16位數據寄存器中。 模擬看門狗特性允許應用程序檢測輸入電壓是否超出用戶定義的高/低閥值。

STM32F407VGT6包含有3個ADC。STM32F4的ADC最大的轉換速率爲2.4Mhz,也 就 是轉換時間爲0.41us(在ADCCLK=36M,採樣週期爲3個ADC時鐘下得到),不要讓ADC的時鐘超過36M,否則將導致結果準確度下降

STM32F4將ADC的轉換分爲2個通道組:規則通道組和注入通道組。規則通道相當於你正常運行的程序,而注入通道呢,就相當於中斷。在你程序正常執行的時候,中斷是可以打斷你的執行的。同這個類似,注入通道的轉換可以打斷規則通道的轉換, 在注入通道被轉換完成之後,規則通道才得以繼續轉換。

通過一個形象的例子可以說明:假如你在家裏的院子內放了5個溫度探頭,室內放了3個溫度探頭;你需要時刻監視室外溫度即可,但偶爾你想看看室內的溫度;因此你可以使用規則通道組循環掃描室外的5個探頭並顯示AD轉換結果,當你想看室內溫度時,通過一個按鈕啓動注入轉換組(3個室內探頭)並暫時顯示室內溫度,當你放開這個按鈕後,系統又會回到規則通道組繼續檢測室外溫度。從系統設計上,測量並顯示室內溫度的過程中斷了測量並顯示室外溫度的過程,但程序設計上可以在初始化階段分別設置好不同的轉換組,系統運行中不必再變更循環轉換的配置,從而達到兩個任務互不干擾和快速切換的結果。可以設想一下,如果沒有規則組和注入組的劃分,當你按下按鈕後,需要從新配置AD循環掃描的通道,然後在釋放按鈕後需再次配置AD循環掃描的通道。上面的例子因爲速度較慢,不能完全體現這樣區分(規則通道組和注入通道組)的好處,但在工業應用領域中有很多檢測和監視探頭需要較快地處理,這樣對AD轉換的分組將簡化事件處理的程序並提高事件處理的速度。

STM32F4其ADC的規則通道組最多包含16個轉換,而注入通道組最多包含4個通道。

STM32F4的ADC在單次轉換模式下,只執行一次轉換,該模式可以通過ADC_CR2寄存器的ADON位(只適用於規則通道)啓動,也可以通過外部觸發啓動(適用於規則通道和注入通道),這時CONT位爲0。

以規則通道爲例,一旦所選擇的通道轉換完成,轉換結果將被存在ADC_DR寄存器中,EOC(轉換結束)標誌將被置位,如果設置了EOCIE,則會產生中斷。然後ADC將停止,直到下次啓動

接下來,我們介紹一下我們執行規則通道的單次轉換,需要用到的ADC寄存器。第一個要介紹的是ADC控制寄存器(ADC_CR1和ADC_CR2)。ADC_CR1的各位描述如圖所示:


ADC_CR1的SCAN位,該位用於設置掃描模式,由軟件設置和清除,如果設置爲1,則使用掃描模式,如果爲0,則關閉掃描模式。在掃描模式下,由ADC_SQRx或ADC_JSQRx寄存器選中的通道被轉換。如果設置了EOCIE或JEOCIE,只在最後一個通道轉換完畢後纔會產生EOC或JEOC中斷。

ADC_CR1[25:24]用於設置ADC的分辨率,詳細的對應關係如圖所示


本章我們使用12位分辨率,所以設置這兩個位爲0就可以了。接着我們介紹ADC_CR2,該寄存器的各位描述如圖所示:


該寄存器我們也只針對性的介紹一些位:ADON位用於開關AD轉換器。而CONT位用於設置是否進行連續轉換,我們使用單次轉換,所以CONT位必須爲0。ALIGN用於設置數據對齊,我們使用右對齊,該位設置爲0。

EXTEN[1:0]用於規則通道的外部觸發使能設置,詳細的設置關係如圖所示


我們這裏使用的是軟件觸發,即不使用外部觸發,所以設置這2個位爲0即可。ADC_CR2的SWSTART位用於開始規則通道的轉換,我們每次轉換(單次轉換模式下)都需要向該位寫1。

第二個要介紹的是ADC通用控制寄存器(ADC_CCR),該寄存器各位描述如圖所示:


該寄存器我們也只針對性的介紹一些位:TSVREFE位是內部溫度傳感器和Vrefint通道使能位,內部溫度傳感器我們將在下一章介紹,這裏我們直接設置爲0。ADCPRE[1:0]用於設置ADC輸入時鐘分頻,00~11分別對應2/4/6/8分頻,STM32F4的ADC最大工作頻率是36Mhz,而ADC時 鍾(ADCCLK)來 自APB2,APB2頻率一般是84Mhz,所以我們一般設置ADCPRE=01,即4分頻,這樣得到ADCCLK頻率爲21Mhz。MULTI[4:0]用於多重ADC模式選擇,詳細的設置關係如圖所示:


本章我們僅用了ADC1(獨立模式),並沒用到多重ADC模式,所以設置這5個位爲0即可

第三個要介紹的是ADC採樣時間寄存器(ADC_SMPR1和ADC_SMPR2),這兩個寄存器用於設置通道0~18的採樣時間,每個通道佔用3個位。ADC_SMPR1的各位描述如圖所示:


對於每個要轉換的通道,採樣時間建議儘量長一點,以獲得較高的準確度,但是這樣會降低ADC的轉換速率。ADC的轉換時間可以由以下公式計算:

Tcovn=採樣時間+12個週期

其中:Tcovn爲總轉換時間,採樣時間是根據每個通道的SMP位的設置來決定的。例如,當ADCCLK=21Mhz的時候,並設置3個週期的採樣時間,則得到:Tcovn=3+12=15個週期=0.71us。

第四個要介紹的是ADC規則序列寄存器(ADC_SQR1~3),該寄存器總共有3個,這幾個寄存器的功能都差不多,這裏我們僅介紹一下ADC_SQR1,該寄存器的各位描述如圖所示:


L[3:0]用於存儲規則序列的長度,我們這裏只用了1個,所以設置這幾個位的值爲0。其他的SQ13~16則存儲了規則序列中第13~16個通道的編號(0~18)。另外兩個規則序列寄存器同ADC_SQR1大同小異,我們這裏就不再介紹了,要說明一點的是:我們選擇的是單次轉換,所以只有一個通道在規則序列裏面,這個序列就是SQ1,至於SQ1裏面哪個通道,完全由用戶自己設置,通過ADC_SQR3的最低5位(也就是SQ1)設置。

第五個要介紹的是ADC規則數據寄存器(ADC_DR)。規則序列中的AD轉化結果都將被存在這個寄存器裏面,而注入通道的轉換結果被保存在ADC_JDRx裏面。ADC_DR的各位描述如圖:


這裏要提醒一點的是,該寄存器的數據可以通過ADC_CR2的ALIGN位設置左對齊還是右對齊。在讀取數據的時候要注意。

最後一個要介紹的ADC寄存器爲ADC狀態寄存器(ADC_SR),該寄存器保存了ADC轉換時的各種狀態。該寄存器的各位描述如圖所示:


這裏我們僅介紹將要用到的是EOC位,我們通過判斷該位來決定是否此次規則通道的AD轉換已經完成,如果該位位1,則表示轉換完成了,就可以從ADC_DR中讀取轉換結果,否則等待轉換完成。

2.      ADC庫函數應用步驟

使用到的庫函數分佈在stm32f4xx_adc.c文件和stm32f4xx_adc.h文

件中。下面講解其詳細設置步驟

STM32F407ZGT6的ADC1通道5在PA5上,所以,我們先要使能GPIOA的時鐘,然後設置PA5爲模擬輸入。同時我們要把PA5複用爲ADC,所以我們要使能ADC1時鐘。這裏特別要提醒,對於IO口複用爲ADC我們要設置模式爲模擬輸入,而不是複用功能,也不需要調用GPIO_PinAFConfig函數來設置引腳映射關係。

使能GPIOA時鐘和ADC1時鐘都很簡單,具體方法爲:

RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA,ENABLE);//使能GPIOA時鐘

RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,ENABLE); //使能ADC1時鐘

初始化GPIOA5爲模擬輸入,方法也多次講解,關鍵代碼爲:

GPIO_InitStructure.GPIO_Mode =GPIO_Mode_AN;//模擬輸入

這裏需要說明一下,ADC的通道與引腳的對應關係在STM32F4的數據手冊可以查到,我們這裏使用ADC1的通道5,在數據手冊中的表格爲:


這裏我們把ADC1~ADC3的引腳與通道對應關係列出來, 16個外部源的對應關係如下表:


2)設置ADC的通用控制寄存器CCR,配置ADC輸入時鐘分頻,模式爲獨立模式等。

在庫函數中,初始化CCR寄存器是通過調用ADC_CommonInit來實現的:

void ADC_CommonInit(ADC_CommonInitTypeDef*ADC_CommonInitStruct)

這裏我們不再李處初始化結構體成員變量,而是直接看實例。初始化實例爲:

ADC_CommonInitStructure.ADC_Mode =ADC_Mode_Independent;//獨立模式

ADC_CommonInitStructure.ADC_TwoSamplingDelay= ADC_TwoSamplingDelay_5Cycles;

ADC_CommonInitStructure.ADC_DMAAccessMode =ADC_DMAAccessMode_Disabled;

ADC_CommonInitStructure.ADC_Prescaler =ADC_Prescaler_Div4;

ADC_CommonInit(&ADC_CommonInitStructure);//初始化

第一個參數ADC_Mode用來設置是獨立模式還是多重模式,這裏我們選擇獨立模式。

第二個參數ADC_TwoSamplingDelay用來設置兩個採樣階段之間的延遲週期數。這個比較好理解。取值範圍爲:ADC_TwoSamplingDelay_5Cycles~ADC_TwoSamplingDelay_20Cycles。

第三個參數ADC_DMAAccessMode是DMA模式禁止或者使能相應DMA模式。

第四個參數ADC_Prescaler用來設置ADC預分頻器。這個參數非常重要,這裏我們設置分頻係數爲4分頻ADC_Prescaler_Div4,保證ADC1的時鐘頻率不超過36MHz。

3)初始化ADC1參數,設置ADC1的轉換分辨率,轉換方式,對齊方式,以及規則序列等相關信息。

在設置完分通用控制參數之後,我們就可以開始ADC1的相關參數配置了,設置單次轉換模式、觸發方式選擇、數據對齊方式等都在這一步實現。具體的使用函數爲:

void ADC_Init(ADC_TypeDef* ADCx,ADC_InitTypeDef* ADC_InitStruct)

初始化實例爲:

ADC_InitStructure.ADC_Resolution =ADC_Resolution_12b;//12位模式

ADC_InitStructure.ADC_ScanConvMode =DISABLE;//非掃描模式

ADC_InitStructure.ADC_ContinuousConvMode =DISABLE;//關閉連續轉換

ADC_InitStructure.ADC_ExternalTrigConvEdge= ADC_ExternalTrigConvEdge_None;

//禁止觸發檢測,使用軟件觸發

ADC_InitStructure.ADC_DataAlign =ADC_DataAlign_Right;//右對齊

ADC_InitStructure.ADC_NbrOfConversion =1;//1個轉換在規則序列中

ADC_Init(ADC1,&ADC_InitStructure);//ADC初始化

第一個參數ADC_Resolution用來設置ADC轉換分辨率。取值範圍爲:ADC_Resolution_6b,

ADC_Resolution_8b,ADC_Resolution_10b和ADC_Resolution_12b。

第二個參數ADC_ScanConvMode用來設置是否打開掃描模式。這裏我們設置單次轉換所以不打開掃描模式,值爲DISABLE。

第三個參數ADC_ContinuousConvMode用來設置是單次轉換模式還是連續轉換模式,這裏我們是單次,所以關閉連續轉換模式,值爲DISABLE。

第三個參數ADC_ExternalTrigConvEdge用來設置外部通道的觸發使能和檢測方式。這裏我們直接禁止觸發檢測,使用軟件觸發。還可以設置爲上升沿觸發檢測,下降沿觸發檢測以及上升沿和下降沿都觸發檢測。

第四個參數ADC_DataAlign 用來設置數據對齊方式。取值範圍爲右對齊

ADC_DataAlign_Right和左對齊ADC_DataAlign_Left。

第五個參數ADC_NbrOfConversion用來設置規則序列的長度,這裏我們是單次轉換,所以值爲1即可。

實際上還有個參數ADC_ExternalTrigConv是用來爲規則組選擇外部事件。因爲我們前面配置的是軟件觸發,所以這裏我們可以不用配置。如果選擇其他觸發方式方式,這裏需要配置。

4)開啓AD轉換器。

在設置完了以上信息後,我們就開啓AD轉換器了(通過ADC_CR2寄存器控制)。

ADC_Cmd(ADC1, ENABLE);//開啓AD轉換器

5)讀取ADC值。

在上面的步驟完成後,ADC就算準備好了。接下來我們要做的就是設置規則序列1裏面的通道,然後啓動ADC轉換。在轉換結束後,讀取轉換結果值值就是了。

這裏設置規則序列通道以及採樣週期的函數是:

void ADC_RegularChannelConfig(ADC_TypeDef*ADCx, uint8_t ADC_Channel,

uint8_t Rank, uint8_t ADC_SampleTime);

我們這裏是規則序列中的第1個轉換,同時採樣週期爲480,所以設置爲:

ADC_RegularChannelConfig(ADC1,ADC_Channel_5, 1, ADC_SampleTime_480Cycles );

軟件開啓ADC轉換的方法是:

ADC_SoftwareStartConvCmd(ADC1);//使能指定的ADC1的軟件轉換啓動功能

開啓轉換之後,就可以獲取轉換ADC轉換結果數據,方法是:

ADC_GetConversionValue(ADC1);

同時在AD轉換中,我們還要根據狀態寄存器的標誌位來獲取AD轉換的各個狀態信息。庫函數獲取AD轉換的狀態信息的函數是:

FlagStatus ADC_GetFlagStatus(ADC_TypeDef*ADCx, uint8_t ADC_FLAG)

比如我們要判斷ADC1的轉換是否結束,方法是:

while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC));//等待轉換結束

這裏還需要說明一下ADC的參考電壓,探索者STM32F4開發板使用的是STM32F407ZGT6,該芯片只有Vref+參考電壓引腳,Vref+的輸入範圍爲:1.8~VDDA。探索者STM32F4開發板通過P7端口,來設置Vref+的參考電壓,默認的我們是通過跳線帽將ref+接到VDDA,參考電壓就是3.3V。如果大家想自己設置其他參考電壓,將你的參考電壓接在Vref+上就OK了(注意要共地)。另外,對於還有Vref-引腳的STM32F4芯片,直接就近將Vref-接VSSA就可以了。

本章我們的參考電壓設置的是3.3V。

通過以上幾個步驟的設置,我們就能正常的使用STM32F4的ADC1來執行AD轉換操作了。

3.      ADC實例

實現採集3.3V電壓和GND電壓,用串口打印出來

Adc.h

#ifndef _ADC_H_H_H
#define _ADC_H_H_H
#include "stm32f4xx_gpio.h"
#include "stm32f4xx_rcc.h"
#include "stm32f4xx_adc.h"
 
void Adc_Init(void);                                                        //ADC通道初始化
u16 Get_Adc(u8 ch);                                                     //獲得某個通道值
u16 Get_Adc_Average(u8 ch,u8 times);//得到某個通道給定次數採樣的平均值 
#endif

Adc.c

#include "adc.h"
#include "delay.h"
//初始化ADC                                                                                                                                                                                                                                     
void Adc_Init(void)
{
 GPIO_InitTypeDef GPIO_InitStructure;
 ADC_CommonInitTypeDef ADC_CommonInitStructure;
 ADC_InitTypeDef      ADC_InitStructure;
               
 RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);//使能GPIOA時鐘
 RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE); //使能ADC1時鐘
 
  //先初始化ADC1通道5 IO口
 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;//PA5 通道5
 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;//模擬輸入
 GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ;//不帶上下拉
 GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化 
 
 RCC_APB2PeriphResetCmd(RCC_APB2Periph_ADC1,ENABLE);                 //ADC1復位
 RCC_APB2PeriphResetCmd(RCC_APB2Periph_ADC1,DISABLE);               //復位結束
 
 ADC_CommonInitStructure.ADC_Mode = ADC_Mode_Independent;//獨立模式
 ADC_CommonInitStructure.ADC_TwoSamplingDelay =ADC_TwoSamplingDelay_5Cycles;//兩個採樣階段之間的延遲5個時鐘
 ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled;//DMA失能
 ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div4;//預分頻4分頻。ADCCLK=PCLK2/4=84/4=21Mhz,ADC時鐘最好不要超過36Mhz
 ADC_CommonInit(&ADC_CommonInitStructure);//初始化
 
 ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;//12位模式
 ADC_InitStructure.ADC_ScanConvMode = DISABLE;//非掃描模式        
 ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;//關閉連續轉換
 ADC_InitStructure.ADC_ExternalTrigConvEdge =ADC_ExternalTrigConvEdge_None;//禁止觸發檢測,使用軟件觸發
  ADC_InitStructure.ADC_DataAlign= ADC_DataAlign_Right;//右對齊   
 ADC_InitStructure.ADC_NbrOfConversion = 1;//1個轉換在規則序列中 也就是隻轉換規則序列1
 ADC_Init(ADC1, &ADC_InitStructure);//ADC初始化
 
 ADC_Cmd(ADC1, ENABLE);//開啓AD轉換器 
}
 
//獲得ADC值
//ch: @ref ADC_channels
//通道值 0~16取值範圍爲:ADC_Channel_0~ADC_Channel_16
//返回值:轉換結果
u16 Get_Adc(u8 ch)  
{
 ADC_RegularChannelConfig(ADC1, ch, 1, ADC_SampleTime_480Cycles );            //ADC1,ADC通道,480個週期,提高採樣時間可以提高精確度                                            
 
 ADC_SoftwareStartConv(ADC1);                            //使能指定的ADC1的軟件轉換啓動功能        
                 
 while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC ));//等待轉換結束
 
 return ADC_GetConversionValue(ADC1);           //返回最近一次ADC1規則組的轉換結果
}
 
u16 Get_Adc_Average(u8 ch,u8 times)
{
  u32temp_val=0;
  u8t;
 for(t=0;t<times;t++)
  {
   temp_val+=Get_Adc(ch);
   delay_ms(5);
  }
  returntemp_val/times;
}

Main.c

#include "led.h"
#include "key.h"
#include "delay.h"
#include "uart.h"
#include "exit.h"
#include "iwdog.h"
#include "pwm.h"
void User_Delay(__IO uint32_t nCount)
{
 while(nCount--)
  {
  }
}
static int count = 0;
int main(void)
{
 
  u16adcx;
 float temp;
 NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
  My_USART2_Init();
  delay_init(168);
  printf("main test start\n");
  Adc_Init();
  
  while(1)
   {
    adcx=Get_Adc_Average(ADC_Channel_5,20);
    temp=(float)adcx*(3.3/4096);
    printf("adc value:(%d) \n",adcx);
    delay_ms(250);
    
   }
}


 

發佈了207 篇原創文章 · 獲贊 561 · 訪問量 79萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章