STM32學習心得二十三:ADC轉換原理及模數轉換實驗

記錄一下,方便以後翻閱~
主要內容:
1) STM32 ADC相關知識;
2) 相關寄存器和庫函數配置;
3) 相關實驗代碼解讀。
實驗功能:針對GPIOA, 引腳1,實時採集開發版上3.3v的電壓信號(用杜邦線連接),在串口調試助手上實時觀察該電壓值。
官方資料:《STM32中文參考手冊V10》第11章——模擬/數字轉換(ADC)
1. ADC (Analog-to-Digital Converter)模/數轉換器
ADC是指將連續變量的模擬信號轉換爲離散的數字信號的器件。典型的模擬/數字轉換器將模擬信號轉換爲表示一定比例電壓值的數字信號。
2. STM32 ADC特點
2.1 12位逐次逼近型的模擬數字轉換器;
2.2 最多帶3個ADC控制器(如下圖所示,其中144腳芯片因爲帶PF腳,所以多5個通道,爲21個外部通道。小於144腳芯片只有16個外部通道);
在這裏插入圖片描述
2.3 最多支持18個通道,可最多測量16個外部和2個內部信號源;
2.4 支持單次和連續轉換模式;
2.5 轉換結束,注入轉換結束,和發生模擬看門狗事件時產生中斷;
2.6 通道0到通道n的自動掃描模式;
2.7 自動校準;
2.8 採樣間隔可以按通道編程;
2.9 規則通道和注入通道均有外部觸發選項;
2.10 轉換結果支持左對齊或右對齊方式存儲在16位數據寄存器;
2.11 ADC轉換時間:最大轉換速率1us(最大轉換速度爲1MHz,在ADCCLK=14M,採樣週期爲1.5個ADC時鐘下得到);
2.12 ADC供電要求:2.4V-3.6V(ADC引腳輸入不要超過3.3v,否則會燒壞!);
2.13 ADC輸入範圍:VREF-≤ VIN ≤ VREF+。
3. STM32F10x系列芯片ADC通道和引腳對應關係
在這裏插入圖片描述
4. ADC引腳
在這裏插入圖片描述
5. ADC框圖
在這裏插入圖片描述
6. STM32通道組
6.1 規則通道組:相當正常運行的程序。最多16個通道。規則通道和它的轉換順序在ADC_SQRx寄存器中選擇,規則組轉換的總數應寫入ADC_SQR1寄存器的L[3:0]中;
6.2 注入通道組:相當於中斷。最多4個通道。注入組和它的轉換順序在ADC_JSQR寄存器中選擇。注入組裏轉化的總數應寫入ADC_JSQR寄存器的L[1:0]中。
在這裏插入圖片描述
STM32F1的ADC的各通道可以單次,連續,掃描或者間斷模式執行。
7. 相關寄存器
7.1 單次轉化 VS 連續轉換
在這裏插入圖片描述
在這裏插入圖片描述
7.2 掃描模式
在這裏插入圖片描述
在這裏插入圖片描述
7.3 ADC中斷
在這裏插入圖片描述
7.4 ADC時鐘配置
在這裏插入圖片描述
備註:不要讓ADC時鐘超過14MHz,否則可能不準。
推薦函數配置:

RCC_ADCCLKConfig(RCC_PCLK2_Div6); 

7.5 ADC_CR1寄存器
在這裏插入圖片描述
在這裏插入圖片描述
在掃描模式下,由ADC_SQRx或者ADC_JSQRx寄存器選中的通道被轉換。如果設置了EOCIE或者JEOCIE,在最後一個通道轉換完畢後纔會產生EOC或者JEOC中斷。
在這裏插入圖片描述
7.6 ADC_CR2寄存器
在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述
7.7 數據對齊方式
在這裏插入圖片描述
7.8 ADC_SMPR1寄存器
在這裏插入圖片描述
7.9 ADC_SMPR2寄存器
在這裏插入圖片描述
7.10 ACD採樣時間
在這裏插入圖片描述
最小轉換時間1us(ADC時鐘=14MHz,採樣週期爲1.5週期下得到)
7.11 ADC_SQR1/SQR2/SQR3規則序列寄存器
在這裏插入圖片描述
7.12 ADC_JSQR注入系列寄存器
在這裏插入圖片描述
7.13 ADC_DR規則通道數據寄存器
在這裏插入圖片描述
7.14 ADC_JDR注入通道數據寄存器
在這裏插入圖片描述
7.15 ADC_SR狀態寄存器
在這裏插入圖片描述
8. 常用庫函數
8.1 常用庫函數一覽

void ADC_Init(ADC_TypeDef* ADCx, ADC_InitTypeDef* ADC_InitStruct);
void ADC_DeInit(ADC_TypeDef* ADCx)void ADC_Cmd(ADC_TypeDef* ADCx, FunctionalState NewState);
void ADC_ITConfig(ADC_TypeDef* ADCx, uint16_t ADC_IT, FunctionalState NewState);
void ADC_SoftwareStartConvCmd(ADC_TypeDef* ADCx, FunctionalState NewState);
voidADC_RegularChannelConfig(ADC_TypeDef* ADCx, uint8_t ADC_Channel, uint8_t Rank, uint8_t ADC_SampleTime);
uint16_t ADC_GetConversionValue(ADC_TypeDef* ADCx);
void ADC_ResetCalibration(ADC_TypeDef* ADCx);
FlagStatus ADC_GetResetCalibrationStatus(ADC_TypeDef* ADCx);
void ADC_StartCalibration(ADC_TypeDef* ADCx);
FlagStatus ADC_GetCalibrationStatus(ADC_TypeDef* ADCx);

8.2 ADC初始化函數

void ADC_Init(ADC_TypeDef* ADCx, ADC_InitTypeDef* ADC_InitStruct);
typedef struct
{
  uint32_t ADC_Mode;                      //ADC模式:配置ADC_CR1寄存器的位[19:16]:DUALMODE[3:0]位//
  FunctionalState ADC_ScanConvMode;       //是否使用掃描模式。ADC_CR1位8:SCAN位// 
  FunctionalState ADC_ContinuousConvMode; //單次轉換OR連續轉換:ADC_CR2的位1:CONT//
  uint32_t ADC_ExternalTrigConv;          //觸發方式:ADC_CR2的位[19:17]:EXTSEL[2:0]//                
  uint32_t ADC_DataAlign;                 //對齊方式:左對齊還是右對齊:ADC_CR2的位11:ALIGN// 
  uint8_t ADC_NbrOfChannel;               //規則通道序列長度:ADC_SQR1的位[23:20]:L[3:0]//       
}
ADC_InitTypeDef;

例:

ADC_InitStruct.ADC_Mode = ADC_Mode_Independent;                   //獨立模式
ADC_InitStruct.ADC_ScanConvMode = DISABLE;                        //不開啓掃描 
ADC_InitStruct.ADC_ContinuousConvMode = DISABLE;                  //單次轉換模式
ADC_InitStruct.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;  //觸發軟件 
ADC_InitStruct.ADC_DataAlign = ADC_DataAlign_Right;               //ADC數據右對齊
ADC_InitStruct.ADC_NbrOfChannel = 1;                              //順序進行規則轉換的ADC通道的數目
ADC_Init(ADC1, &ADC_InitStructure);      

8.3 ADC使能函數 ADC_Cmd();

void ADC_Cmd(ADC_TypeDef* ADCx, FunctionalState NewState);

例:

ADC_Cmd(ADC1, ENABLE);                      //使能指定的ADC1//

8.4
ADC使能軟件轉換函數

void ADC_SoftwareStartConvCmd(ADC_TypeDef*  ADCx,  FunctionalState NewState);

例:

ADC_SoftwareStartConvCmd(ADC1, ENABLE);    //使能ADC1的軟件轉換啓動//

8.5 ADC 規則通道配置函數

void ADC_RegularChannelConfig(ADC_TypeDef* ADCx, uint8_t ADC_Channel, uint8_t Rank, uint8_t ADC_SampleTime);

例:

ADC_RegularChannelConfig(ADC1, ADC_Channel_1, 1, ADC_SampleTime_239Cycles5 );

8.6 ADC 獲取轉換結果函數

uint16_t ADC_GetConversionValue(ADC_TypeDef* ADCx);

例:

ADC_GetConversionValue(ADC1);               //獲取ADC1轉換結果//

9. 一般配置步驟
9.1 開啓PA口時鐘和ADC1時鐘,設置PA1爲模擬輸入;

GPIO_Init(); 
APB2PeriphClockCmd();

9.2 復位ADC1,同時設置ADC1分頻因子;

RCC_ADCCLKConfig(RCC_PCLK2_Div6);
ADC_DeInit(ADC1);

9.3 初始化ADC1參數,設置ADC1的工作模式以及規則序列的相關信息;

void ADC_Init(ADC_TypeDef* ADCx, ADC_InitTypeDef* ADC_InitStruct)

9.4 使能ADC並校準;

ADC_Cmd(ADC1, ENABLE);
ADC_ResetCalibration(ADC1);                 //使能復位校準//   
while(ADC_GetResetCalibrationStatus(ADC1)); //等待復位校準結束// 
ADC_StartCalibration(ADC1);                 //開啓AD校準//
while(ADC_GetCalibrationStatus(ADC1));      //等待校準結束//

9.5 配置規則通道參數;

ADC_RegularChannelConfig();

9.6 開啓軟件轉換:

ADC_SoftwareStartConvCmd(ADC1);

9.7 等待轉換完成,讀取ADC值。

while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC ));   //等待轉換結束,EOC=1時,轉換完成,則While停止//
ADC_GetConversionValue(ADC1);
  1. 相關代碼解讀
    10.1 adc.h頭文件代碼解讀
#ifndef __ADC_H
#define __ADC_H 
#include "sys.h"
//申明瞭三個函數//
void Adc_Init(void);  
u16  Get_Adc(u8 ch); 
u16 Get_Adc_Average(u8 ch,u8 times); 
#endif 

10.2 adc.c文件代碼解讀

#include "adc.h"
#include "delay.h"
//編寫void Adc_Init(void)函數//                   
void  Adc_Init(void)
{  
 ADC_InitTypeDef  ADC_InitStructure;              //ADC_Init初始化結構體//
 GPIO_InitTypeDef GPIO_InitStructure;             //GPIO_Init初始化結構體//
 //使能GPIOA和ADC1通道時鐘//
 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA |RCC_APB2Periph_ADC1 , ENABLE );  
 //配置GPIOA,引腳1,模擬輸入//                        
 GPIO_InitStructure.GPIO_Pin  = GPIO_Pin_1;       //引腳1//
 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;    //模擬輸入//
 GPIO_Init(GPIOA, &GPIO_InitStructure); 
 //設置ADC分頻因子6,72M/6=12M,ADC最大時間不能超過14M//
 RCC_ADCCLKConfig(RCC_PCLK2_Div6);   
 ADC_DeInit(ADC1);                                //復位ADC1,可寫可不寫// 
 //配置ADC_Init結構體參數//
 //ADC_CR1寄存器,位[19:16]:DUALMODE雙模式選擇,ADC_Mode_Independent=0x00000000,獨立模式//
 ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;                   
 //ADC_CR1寄存器,位8:SCAN掃描模式,0關閉掃描模式//
 ADC_InitStructure.ADC_ScanConvMode = DISABLE;   
 //ADC_CR2寄存器,位1:CONT連續轉換,0單次轉換模式// 
 ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;
 //ADC_CR2寄存器,位[19:17]:EXTSEL選擇啓動規則通道組轉換的外部事件,ADC_ExternalTrigConv_None=0x000E0000,SWSTART軟件控制// 
 ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; 
 //ADC_CR2寄存器,位11:ALIGN數據對齊,ADC_DataAlign_Right=0x00000000,右對齊//
 ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; 
 //ADC_SQR1寄存器,位[23:20]:L規則通道序列長度,1指1個轉換,即位[23:20]設爲0000//
 ADC_InitStructure.ADC_NbrOfChannel = 1; 
 ADC_Init(ADC1, &ADC_InitStructure);    
 //使能指定的ADC1//
 ADC_Cmd(ADC1, ENABLE); 
 //下面四個函數用於校準//
 ADC_ResetCalibration(ADC1);                     //使能復位校準//   
 while(ADC_GetResetCalibrationStatus(ADC1));     //等待復位校準結束// 
 ADC_StartCalibration(ADC1);                     //開啓AD校準//
 while(ADC_GetCalibrationStatus(ADC1));          //等待校準結束//
}      
//編寫u16 Get_Adc函數(u8 ch)//
u16 Get_Adc(u8 ch)   
{
 //設置指定ADC的規則組通道,四個入口參數//
 ADC_RegularChannelConfig(ADC1, ch, 1, ADC_SampleTime_239Cycles5 );           
 ADC_SoftwareStartConvCmd(ADC1, ENABLE);          //使能指定的ADC1的軟件轉換啓動功能// 
 while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC ));  //等待轉換結束,EOC=1時,轉換完成,則While停止//
 return ADC_GetConversionValue(ADC1);             //返回最近一次ADC1規則組的轉換結果//
}
//編寫u16 Get_Adc_Average(u8 ch,u8 times)//
u16 Get_Adc_Average(u8 ch,u8 times)
{
 u32 temp_val=0;
 u8 t;
 for(t=0;t<times;t++)
 {
  temp_val+=Get_Adc(ch);
  delay_ms(5);
 }
 return temp_val/times;
}   

10.3 main.c代碼解讀

#include "led.h"
#include "delay.h"
#include "sys.h"
#include "usart.h"  
#include "adc.h"
int main(void)
 {  
  u16 adcx;
  float temp;
  delay_init();        //延時函數初始化   
  uart_init(115200);   //串口初始化爲115200
  LED_Init();          //LED端口初始化
  Adc_Init();          //ADC初始化    
 while(1)
 {
  adcx=Get_Adc_Average(ADC_Channel_1,10);
  temp=(float)adcx*(3.3/4096);
  printf("電壓大小(從二進制寄存器讀取後轉換爲十進制):%d\n",adcx); 
  printf("電壓大小(換算成電壓單位後):%f\n",temp);
  LED0=!LED0;
  delay_ms(250); 
 }
 }

舊知識點
1)複習如何新建工程模板,可參考STM32學習心得二:新建工程模板
2)複習基於庫函數的初始化函數的一般格式,可參考STM32學習心得三:GPIO實驗-基於庫函數
3)複習寄存器地址,可參考STM32學習心得四:GPIO實驗-基於寄存器
4)複習位操作,可參考STM32學習心得五:GPIO實驗-基於位操作
5)複習寄存器地址名稱映射,可參考STM32學習心得六:相關C語言學習及寄存器地址名稱映射解讀
6)複習時鐘系統框圖,可參考STM32學習心得七:STM32時鐘系統框圖解讀及相關函數
7)複習延遲函數,可參考STM32學習心得九:Systick滴答定時器和延時函數解讀
8)複習ST-LINK仿真器的參數配置,可參考STM32學習心得十:在Keil MDK軟件中配置ST-LINK仿真器
9)複習ST-LINK調試方法,可參考STM32學習心得十一:ST-LINK調試原理+軟硬件仿真調試方法
10)複習如何對GPIO進行復用,可參考STM32學習心得十二:端口複用和重映射
11)複習串口通信相關知識,可參考STM32學習心得十四:串口通信相關知識及配置方法
12)複習通用定時器基本原理,可參考STM32學習心得十八:通用定時器基本原理及相關實驗代碼解讀

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章