Stm32 ADC學習


stm32 ADC 簡介

stm32的ADC是 12位逐次逼近型 模擬數字轉換器;它包括18個通道,可以用來測量16個外部通道2個內部通道.ADC轉換的結果存放在16位數據寄存器(ADC規則數據寄存器,ADC_DR 和 ADC注入數據寄存器,ADC_JDCx)中,這個數據寄存器可以設置對齊方式為左對齊或右對齊.

ADC通道與GPIO對應表(圖片來自整點原子STM32F1開發指南庫函數版本)


規則通道組注入通道組

注入通道可打斷規則通道的轉換

所謂規則通道組和注入通道組其實應該就是通道的分組吧,按照OOP的思想來理解,通道組是一個基類,注入通道組和規則通道組派生自通道組這個基類,通道組這個基類中包含了一個保存各個通道的數組.

為什么要對通道進行分組呢,這個有待深究,以后再說.


ADC相關的寄存器

ADC_CR1

各個位描述如下圖:

  • scan位:
    設置掃描模式,1為使用掃描模式,0則關閉.掃描模式下,有ADC_SQRx或ADC_JSQRx寄存器選中的通道被轉換,此時如果設置了EOCIE或JEOCIE,則只有在最后一個通道轉換完畢后才會產生EOC或JEOC中斷
  • DUALMOD位:
    設置ADC的操作模式,詳細的看下面的來自<<stm32中文參考手冊>>截圖

ADC_CR2

各個位描述如下圖:

  • ADON位:用於開關AD轉換器
  • CONT位:用於設置是否進行連續轉換,使用單次轉換CONT位必須設置為0.
  • EXTSEL[2:0]:用於選擇啟動規則轉換組轉換的外部事件

    如果需要使用軟件觸發,就將這三個位設置為 111

ADC采樣事件寄存器(ADC_SMPR1和ADC_SMPR2)

各個位描述如下圖:

這兩個寄存器用來設置通道0~17的采樣時間,每個通道要占3位.

對於每個要轉換的通道,采樣時間盡量長一點,以獲得較高的准確度,但是會降低ADC的轉換速率.ADC的轉換時間可以由以下公式計算:

Tconv = 采樣時間 + 12.5周期

ADC規則序列寄存器(ADC_SQR1~3)

這幾個寄存器功能都差不多,不一一詳細說明了.

  • L[3:0]:用於存儲規則序列的長度

ADC數據寄存器(ADC_DR)

這個沒什么好說的,用來存放AD轉換后的結果

要注意可以通過ADC_CR2的ALIGN位設置這個寄存器是左對齊還是右對齊

ADC狀態寄存器(ADC_SR)

沒啥好說的,保存了各種狀態,看圖吧.


通過庫函數配置ADC1通道1進行AD轉換

查看手冊可以知道ADC1通道1對應着PA1,如下圖



1.外設使能

  • STM32F103ZET6的ADC通道1在PA1上所以我們先要使能 PORTA的時鍾 和 ADC1時鍾,然后設置 PA1為模擬輸入.

2.復位ADC1,同時設置ADC1的分頻因子

  • 開啟了ADC1的時鍾后,要復位ADC1,將ADC1的全部寄存器重設位缺省值,然后通過RCC_CFGR設置ADC1的分頻因子,並且分頻因子要確保ADC1的時鍾不超過14MHz!
    //ADC復位 ADC_DeInit();
    RCC_ADCCLKConfig(RCC_PCLK2_DIV6); //設置分配因子的庫函數

3.初始化ADC1參數,設置ADC1的工作模式以及規則序列的相關信息.
void ADC_Init(ADC_TypeDef* ADCx, ADC_InitTypeDef* ADC_InitStruct);// ADC初始化

4.使能ADC並校准
void ADC_Cmd(ADC_TypeDef* ADCx, FunctionalState NewState); //使能指定的ADC
void ADC_ResetCalibration(ADC_TypeDef* ADCx);//復位校准
while(ADC_GetResetCalibrationStatus(ADCx));//等待復位校准結束
void ADC_StartCalibration(ADC_TypeDef* ADCx);//執行ADC校准
while(ADC_GetCalibrationStatus(ADCx));//等待AD校准結束

5.設置規則序列1里面的通道,讀取ADC的值
void ADC_RegularChannelConfig(ADC_TypeDef* ADCx, uint8_t ADC_Channel, uint8_t Rank, uint8_t ADC_SampleTime); //設置規則序列通道以及采樣周期
void ADC_SoftwareStartConvCmd(ADC_TypeDef* ADCx, FunctionalState NewState);//允許軟件開啟ADC轉換
while(!ADC_GetFlagStatus(ADCx,ADC_FLAG_EOC));//等待轉換結束
uint16_t ADC_GetConversionValue(ADC_TypeDef* ADCx);//獲取轉 換結果數據

MDK5中實現代碼

  • 配置stm32f103庫函數編程環境,我用的是正點原子的那一套,不多記錄了;

  • ADC1_Init() 函數

    void ADC1_Init(void)
    /* ---------------------------------------------
        ADC1_IN1 -> PA.1
    --------------------------------------------- */
    void ADC1_Init(void)
    {
        GPIO_InitTypeDef gpioInitStruct;
        ADC_InitTypeDef adcInitStruct;
        //Enable periph clock
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_ADC1,ENABLE);
        //配置ADC的時鍾,不要超過14MHz;
        RCC_ADCCLKConfig(RCC_PCLK2_Div6);	
        //Congfig PA.1
        gpioInitStruct.GPIO_Mode = GPIO_Mode_AIN;	//設置PA.1的輸入模式為模擬輸入
        gpioInitStruct.GPIO_Pin = GPIO_Pin_1;
        gpioInitStruct.GPIO_Speed = GPIO_Speed_50MHz;
        GPIO_Init(GPIOA,&gpioInitStruct);
        //ADC1 復位
        ADC_DeInit(ADC1);
        //initialize adc1
        adcInitStruct.ADC_Mode = ADC_Mode_Independent;	//ADC模式:ADC獨立模式
        adcInitStruct.ADC_DataAlign = ADC_DataAlign_Right;	//ADC_DR寄存器的數據對齊方式:右對齊
        adcInitStruct.ADC_ScanConvMode = DISABLE;	//是否允許連續掃描模式:不允許,使用單通道模式
        adcInitStruct.ADC_ContinuousConvMode = DISABLE;	//單次轉換模式
        adcInitStruct.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;	//ADC觸發方式:不需要外部觸發源,由軟件觸發
        adcInitStruct.ADC_NbrOfChannel = 1;	//進行轉換的ACD通道數目
        ADC_Init(ADC1,&adcInitStruct);
        //Enable ADC1
        ADC_Cmd(ADC1,ENABLE);
        //ADC1校准
        ADC_ResetCalibration(ADC1);	//復位校准
        while(ADC_GetResetCalibrationStatus(ADC1));//等待復位校准完成
        ADC_StartCalibration(ADC1); //ACD校准
        while(ADC_GetCalibrationStatus(ADC1));	//等待ADC校准完成
    }
    
  • ADC_GetConvValue()

    u16 ADC_GetConvValue(u8 channel)
    /**
    * 獲取指定的通道adc的轉換結果
    * @param channel: 指定adc的通道,必須在1~3之間
    */
    u16 ADC_GetConvValue(u8 channel)
    {
        //Config sample channel
        //采樣周期盡量設置長一些,以確保精度
        ADC_RegularChannelConfig(ADC1,channel,1,ADC_SampleTime_239Cycles5);
        //使能軟件轉換
        ADC_SoftwareStartConvCmd(ADC1,ENABLE);
        while(!ADC_GetFlagStatus(ADC1,ADC_FLAG_EOC));
        return ADC_GetConversionValue(ADC1);
    }
    
  • ADC_GetAverageConvValue()

    u16 ADC_GetAverageConvValue(u8 channel,u8 times)
    u16 ADC_GetAverageConvValue(u8 channel,u8 times)
    {
        u8 i = 0;
        u32 temp = 0;
        for(;i < times;i++)
        {
            temp += ADC_GetConvValue(channel);
        }
        return (u16)(temp/times);
    }
    
  • ADC_SampleValue2ReadableValue()

    double ADC_SampleValue2ReadableValue(u16 sampleValue)
    /**
        * 描述:將AD轉換后存放在ADC_DR寄存器中的值轉換為有意義的值,
        * 		 可以通過宏定義 REF 來設置參考電壓
        * @param sampleValue : 要轉換的值
        * @retval 轉換的結果,是一個double類型的浮點數
        */
    double ADC_SampleValue2ReadableValue(u16 sampleValue)
    {
        return (double)sampleValue*((double)REF/4096.0);
    }
    
  • main.c文件代碼

    main.c
    #include"ADC.h"
    #include"delay.h"
    #include"usart.h"
    

    void Init(void);
    void Loop(void);

    int main(void)
    {
    Init();
    while(1)
    Loop();
    }

    void Init(void)
    {
    delay_init();
    USART_Debug_Init();
    ADC1_Init();
    USART_WriteLine("系統初始化完成!將開始AD采集.");
    }

    void Loop(void)
    {
    u16 sampledValue;
    sampledValue = ADC_GetAverageConvValue(1,5);
    USART_WriteLine("采樣值: %d ; 計算所得電壓值: %.2f ",sampledValue,ADC_SampleValue2ReadableValue(sampledValue));
    delay_ms(250);
    }

  • 在main.c中使用的 USART_WriteLine(const char*str,...)函數 是我自己封裝的串口函數,也可以使用正點原子 System文件夾 下提供的printf()函數;

總結庫函數配置ADC的步驟

1.使能需要用到的GPIO 和 ADC的時鍾;
2.配置ADC的時鍾分頻:
void RCC_ADCCLKConfig(uint32_t RCC_PCLK2);
2.配置IO口,輸入模式為 GPIO_Mode_AIN,模擬輸入模式;
3.調用 ADC_DeInit(); 對ADC進行復位;
4.調用 ADC_Init();初始化ADC
5.調用 ADC_Cmd(ADCx,ENABLE);,使能ADC
6.校准ADC:
ADC_ResetCalibration(ADC1); //復位校准 while(ADC_GetResetCalibrationStatus(ADC1));//等待復位校准完成 ADC_StartCalibration(ADC1); //ACD校准 while(ADC_GetCalibrationStatus(ADC1)); //等待ADC校准完成
7.獲取AD轉換的結果

  </div>


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM