ADC模數轉換器概念函數及應用
文章目錄
- ADC模數轉換器概念函數及應用
- 1.ADC簡介
- 2.逐次逼近型ADC
- 2.1逐次逼近型ADC
- 2.2stm32逐次逼近型
- 2.3ADC基本結構
- 2.4十六個通道
- 3.規則組的4種轉換模式
- 3.1單次轉換,非掃描模式
- 3.2連續轉換,非掃描模式
- 3.3單次轉換,掃描模式
- 3.4連續轉換,掃描模式
- 4.觸發控制
- 5.數據對齊
- 6.轉換時間
- 7.校準(了解)
- 8.硬件電路
- 9.相關函數說明
- RCC的函數
- ADC的函數
- 控制校準的函數
- 軟件觸發的函數
- 獲取標志位狀態
- 配置間斷模式
- ADC規則組通道配置
- ADC獲取轉換值
- ADC注入組的配置(了解)
- 模擬看門狗的配置
- ADC溫度傳感器,內部電壓控制
- 標志位相關
- 9.實操圖
- 10.AD單通道
- 10.1接線圖
- 10.2代碼編寫
- 10.2.1主程序main.c
- 10.2.2函數定義AD.c
- 10.2.3函數聲明AD.h
- 11.AD多通道
- 11.1接線圖
- 11.2代碼編寫
- 11.2.1主程序main.c
- 11.2.2函數定義AD.c
- 11.2.3函數聲明AD.h
- n.實現步驟
- n.1ADC配置的步驟
- n.2校準的4個步驟
- n.實現步驟
- n.1ADC配置的步驟
- n.2校準的4個步驟
1.ADC簡介
- ADC(Analog-Digital Converter)模擬-數字轉換器
- ADC可以將引腳上連續變化的模擬電壓轉換為內存中存儲的數字變量,建立模擬電路到數字電路的橋梁
- 12位逐次逼近型ADC,1us轉換時間
- 輸入電壓范圍:0~3.3V,轉換結果范圍:0~4095
- 18個輸入通道,可測量16個外部和2個內部信號源(16個外部就是16個GPIO口,2個內部信號源是內部溫度傳感器和內部參考電壓)
- 規則組(常規使用)和注入組(用于突發事件)兩個轉換單元
- 模擬看門狗自動監測輸入電壓范圍
- STM32F103C8T6 ADC資源:ADC1、ADC2,10個外部輸入通道
STM32主要是數字電路,數字電路只有高低電平,沒有幾v電壓的概念
2.逐次逼近型ADC
2.1逐次逼近型ADC
2.2stm32逐次逼近型
2.3ADC基本結構
2.4十六個通道
通道 | ADC1 | ADC2 | ADC3 |
---|---|---|---|
通道0 | PA0 | PA0 | PA0 |
通道1 | PA1 | PA1 | PA1 |
通道2 | PA2 | PA2 | PA2 |
通道3 | PA3 | PA3 | PA3 |
通道4 | PA4 | PA4 | PF6 |
通道5 | PA5 | PA5 | PF7 |
通道6 | PA6 | PA6 | PF8 |
通道7 | PA7 | PA7 | PF9 |
通道8 | PB0 | PB0 | PF10 |
通道9 | PB1 | PB1 | |
通道10 | PC0 | PC0 | PC0 |
通道11 | PC1 | PC1 | PC1 |
通道12 | PC2 | PC2 | PC2 |
通道13 | PC3 | PC3 | PC3 |
通道14 | PC4 | PC4 | |
通道15 | PC5 | PC5 | |
通道16 | 溫度傳感器 | ||
通道17 | 內部參考電壓 |
3.規則組的4種轉換模式
EOC在規則或注入通道組結束時設置,由軟件清除或由讀取ADC_DR時清除
3.1單次轉換,非掃描模式
3.2連續轉換,非掃描模式
3.3單次轉換,掃描模式
3.4連續轉換,掃描模式
4.觸發控制
5.數據對齊
- 數據右對齊
- 數據左對齊
左對齊的作用:如果不想要右對齊那么高的分辨率,0~4095數太大了,可以選擇左對齊將數據的高8位取出來,舍棄后面4位的精度,將12位的ADC退化為8位的ADC
6.轉換時間
AD轉換的步驟:采樣,保持,量化,編碼
STM32 ADC的總轉換時間為:
TCONV = 采樣時間 + 12.5個ADC周期
例如:當ADCCLK=14MHz,采樣時間為1.5個ADC周期
TCONV = 1.5 + 12.5 = 14個ADC周期 = 1μs
量化:ADC逐次比較的過程,位數越多時間越長,
采樣時間:采樣保持花費的時間,采樣時間越長,越能避免一些毛刺信號的干擾
12.5個ADC周期:量化編碼花費的時間,因為是12位的ADC,所以需要花費12個周期
ADC周期:就是從RCC分頻過來的ADCCLK
14MHz:最大,最快的轉換速度
7.校準(了解)
固定過程,了解即可
- ADC有一個內置自校準模式。校準可大幅減小因內部電容器組的變化而造成的準精度誤差。校準期間,在每個電容器上都會計算出一個誤差修正碼(數字值),這個碼用于消除在隨后的轉換中每個電容器上產生的誤差
- 建議在每次上電后執行一次校準
- 啟動校準前, ADC必須處于關電狀態超過至少兩個ADC時鐘周期
8.硬件電路
9.相關函數說明
RCC的函數
void RCC_ADCCLKConfig(uint32_t RCC_PCLK2);
- void RCC_ADCCLKConfig(uint32_t RCC_PCLK2);配置ADCCLK預分頻器,可以對APB2的72MHz時鐘選擇2、4、6、8分頻,輸入到ADCCLK
ADC的函數
void ADC_DeInit(ADC_TypeDef* ADCx);
void ADC_Init(ADC_TypeDef* ADCx, ADC_InitTypeDef* ADC_InitStruct);
void ADC_StructInit(ADC_InitTypeDef* ADC_InitStruct);
void ADC_Cmd(ADC_TypeDef* ADCx, FunctionalState NewState);
void ADC_DMACmd(ADC_TypeDef* ADCx, FunctionalState NewState);
void ADC_ITConfig(ADC_TypeDef* ADCx, uint16_t ADC_IT, FunctionalState NewState);
- void ADC_DeInit(ADC_TypeDef* ADCx);恢復缺省配置
- void **ADC_Init (ADC_TypeDef ADCx, ADC_InitTypeDef ADC_InitStruct);初始化
- void ADC_StructInit(ADC_InitTypeDef* ADC_InitStruct);結構體初始化
- void ADC_Cmd(ADC_TypeDef* ADCx, FunctionalState NewState);給ADC上電的,就是開關控制
- void ADC_DMACmd(ADC_TypeDef* ADCx, FunctionalState NewState);用于開啟DMA輸出信號,使用DMA轉運數據,就得調用這個函數
- void ADC_ITConfig(ADC_TypeDef* ADCx, uint16_t ADC_IT, FunctionalState NewState);中斷輸出控制,控制某個中斷是否能通往NVIC
控制校準的函數
void ADC_ResetCalibration(ADC_TypeDef* ADCx);
FlagStatus ADC_GetResetCalibrationStatus(ADC_TypeDef* ADCx);
void ADC_StartCalibration(ADC_TypeDef* ADCx);
FlagStatus ADC_GetCalibrationStatus(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);獲取開始校準狀態
在ADC初始化后依次調用即可
軟件觸發的函數
void ADC_SoftwareStartConvCmd(ADC_TypeDef* ADCx, FunctionalState NewState);
FlagStatus ADC_GetSoftwareStartConvStatus(ADC_TypeDef* ADCx);//一般不會用到
- void ADC_SoftwareStartConvCmd(ADC_TypeDef* ADCx, FunctionalState NewState);用于軟件觸發的函數,設置SWSTART為1
- FlagStatus ADC_GetSoftwareStartConvStatus(ADC_TypeDef* ADCx);返回SWSTART的狀態,與轉換是否結束無關
獲取標志位狀態
FlagStatus ADC_GetFlagStatus(ADC_TypeDef* ADCx, uint8_t ADC_FLAG);
- FlagStatus ADC_GetFlagStatus(ADC_TypeDef* ADCx, uint8_t ADC_FLAG);參數給EOC的標志位判斷EOC標志位是不是置1
如何判斷轉換是否結束:
調用ADC_GetFlagStatus函數獲取標志位狀態,判斷EOC標志位是不是置1了,如果轉換結束,EOC標志位置1,然后調用這個函數判斷標志位
配置間斷模式
void ADC_DiscModeChannelCountConfig(ADC_TypeDef* ADCx, uint8_t Number);
void ADC_DiscModeCmd(ADC_TypeDef* ADCx, FunctionalState NewState);
- void ADC_DiscModeChannelCountConfig(ADC_TypeDef* ADCx, uint8_t Number);每隔幾個通道間斷一次
- void ADC_DiscModeCmd(ADC_TypeDef* ADCx, FunctionalState NewState);是不是啟用間斷模式
ADC規則組通道配置
void ADC_RegularChannelConfig(ADC_TypeDef* ADCx, uint8_t ADC_Channel, uint8_t Rank, uint8_t ADC_SampleTime);
- void ADC_RegularChannelConfig(ADC_TypeDef* ADCx, uint8_t ADC_Channel, uint8_t Rank, uint8_t ADC_SampleTime);給序列的每個位置填寫指定通道,參數1ADCx,參數2ADC_Channel你想指定的通道,參數三Rank:序列幾的位置(規則器中的序列),參數四SampleTime:指定通道的采樣時間(數值小的轉換快,數值大的穩定)
void ADC_ExternalTrigConvCmd(ADC_TypeDef* ADCx, FunctionalState NewState);
- void ADC_ExternalTrigConvCmd(ADC_TypeDef* ADCx, FunctionalState NewState);ADC外部觸發轉換控制,就是是否允許外部觸發轉換,
ADC獲取轉換值
uint16_t ADC_GetConversionValue(ADC_TypeDef* ADCx);
uint32_t ADC_GetDualModeConversionValue(void);
- uint16_t ADC_GetConversionValue(ADC_TypeDef* ADCx);就是獲取AD轉換的數據寄存器,讀取轉換結果就使用該函數
- uint32_t ADC_GetDualModeConversionValue(void);ADC獲取雙模式轉換值,雙ADC模式讀取轉換結果的函數
以上所有函數都是對ADC基本功能和規則組的配置
ADC注入組的配置(了解)
void ADC_AutoInjectedConvCmd(ADC_TypeDef* ADCx, FunctionalState NewState);
void ADC_InjectedDiscModeCmd(ADC_TypeDef* ADCx, FunctionalState NewState);
void ADC_ExternalTrigInjectedConvConfig(ADC_TypeDef* ADCx, uint32_t ADC_ExternalTrigInjecConv);
void ADC_ExternalTrigInjectedConvCmd(ADC_TypeDef* ADCx, FunctionalState NewState);
void ADC_SoftwareStartInjectedConvCmd(ADC_TypeDef* ADCx, FunctionalState NewState);
FlagStatus ADC_GetSoftwareStartInjectedConvCmdStatus(ADC_TypeDef* ADCx);
void ADC_InjectedChannelConfig(ADC_TypeDef* ADCx, uint8_t ADC_Channel, uint8_t Rank, uint8_t ADC_SampleTime);
void ADC_InjectedSequencerLengthConfig(ADC_TypeDef* ADCx, uint8_t Length);
void ADC_SetInjectedOffset(ADC_TypeDef* ADCx, uint8_t ADC_InjectedChannel, uint16_t Offset);
uint16_t ADC_GetInjectedConversionValue(ADC_TypeDef* ADCx, uint8_t ADC_InjectedChannel);
模擬看門狗的配置
void ADC_AnalogWatchdogCmd(ADC_TypeDef* ADCx, uint32_t ADC_AnalogWatchdog);
void ADC_AnalogWatchdogThresholdsConfig(ADC_TypeDef* ADCx, uint16_t HighThreshold, uint16_t LowThreshold);
void ADC_AnalogWatchdogSingleChannelConfig(ADC_TypeDef* ADCx, uint8_t ADC_Channel);
- void ADC_AnalogWatchdogCmd(ADC_TypeDef* ADCx, uint32_t ADC_AnalogWatchdog);是否啟動模擬看門狗
- void ADC_AnalogWatchdogThresholdsConfig(ADC_TypeDef* ADCx, uint16_t HighThreshold, uint16_t LowThreshold);配置高低閾值
- voidADC_AnalogWatchdogSingleChannelConfig(ADC_TypeDef* ADCx, uint8_t ADC_Channel);配置看門的通道
ADC溫度傳感器,內部電壓控制
void ADC_TempSensorVrefintCmd(FunctionalState NewState);
- void ADC_TempSensorVrefintCmd(FunctionalState NewState);用于開啟內部的兩個通道的,不開啟將讀不到正確結果
標志位相關
FlagStatus ADC_GetFlagStatus(ADC_TypeDef* ADCx, uint8_t ADC_FLAG);
void ADC_ClearFlag(ADC_TypeDef* ADCx, uint8_t ADC_FLAG);
ITStatus ADC_GetITStatus(ADC_TypeDef* ADCx, uint16_t ADC_IT);
void ADC_ClearITPendingBit(ADC_TypeDef* ADCx, uint16_t ADC_IT);
- FlagStatus ADC_GetFlagStatus(ADC_TypeDef* ADCx, uint8_t ADC_FLAG);獲取標志位狀態
- void ADC_ClearFlag(ADC_TypeDef* ADCx, uint8_t ADC_FLAG);清楚標志位
- ITStatus ADC_GetITStatus(ADC_TypeDef* ADCx, uint16_t ADC_IT);獲取中斷狀態
- void ADC_ClearITPendingBit(ADC_TypeDef* ADCx, uint16_t ADC_IT);清除中斷掛起位
9.實操圖
10.AD單通道
10.1接線圖
根據引腳定義表,PA0到PB1這10個引腳是ADC的10個通道,其他的引腳不是ADC引腳,不能接模擬電壓
10.2代碼編寫
10.2.1主程序main.c
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "LED.h"
#include "KEY.h"
#include "OLED.h"
//#include "OLED_Font.h"
#include "AD.h"uint16_t AD_Value;
float Voltage;int main(void){OLED_Init();AD_Init();OLED_ShowString(1,1,"ADValue:");OLED_ShowString(2,1,"Voltage:0.00V");while(1){AD_Value = ADC_GetValue();Voltage = (float)AD_Value/4095*3.3;OLED_ShowNum(1,9,AD_Value,4);//ADC值為整數,直接除不準確,所以需要強制類型轉換,雖然還是有偏差OLED_ShowNum(2,9,Voltage,1);//顯示整數部分OLED_ShowNum(2,11,(uint16_t)(Voltage*100)%100,2);//顯示小數部分Delay_ms(100);}
}
10.2.2函數定義AD.c
#include "stm32f10x.h" // Device headervoid AD_Init(void){RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);//開啟ADC時鐘RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,ENABLE);//配置ADCCLKRCC_ADCCLKConfig(RCC_PCLK2_Div6);//ADCCLK=72MHz/6=12MHz//GPIO初始化GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;//防止干擾模擬電壓GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;GPIO_Init(GPIOA, &GPIO_InitStructure);//配置規則組輸入通道(ADC通道,通道,序列,采樣時間參數)ADC_RegularChannelConfig(ADC1,ADC_Channel_0,1,ADC_SampleTime_55Cycles5);//這里的ADCCLK的采樣時間就是55.5個ADCCLK周期//ADC初始化ADC_InitTypeDef ADC_InitStructure;ADC_InitStructure.ADC_ContinuousConvMode =ENABLE;//連續轉換模式,選擇連續或單次轉換ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;//數據對齊ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;//外部觸發轉換選擇,對應框圖的左下角,None不使用外部觸發,使用軟件觸發ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;//模式選擇:獨立模式ADC_InitStructure.ADC_NbrOfChannel = 1;//通道數目,一共掃描幾個通道ADC_InitStructure.ADC_ScanConvMode = DISABLE;//掃描轉換模式ADC_Init(ADC1,&ADC_InitStructure);ADC_Cmd(ADC1,ENABLE);//校準ADC_ResetCalibration(ADC1);//復位校準while(ADC_GetResetCalibrationStatus(ADC1) == SET);//復位完成后系統會自動置為0ADC_StartCalibration(ADC1);//開始校準while(ADC_GetCalibrationStatus(ADC1)==SET);}//獲取ADC值
uint16_t ADC_GetValue(void){ADC_SoftwareStartConvCmd(ADC1,ENABLE);//軟件觸發獲取ADC值的函數//獲取標志位狀態while(ADC_GetFlagStatus(ADC1,ADC_FLAG_EOC)==RESET);//等待時間:采樣周期55.5,轉換周期固定為12.5,55.5+12.5=68,76/6=12(6分頻),(1/12)*68=5.6usreturn ADC_GetConversionValue(ADC1);
}
PCLK2就是APB2時鐘的意思
AIN模式下,GPIO口是無效的,斷開GPIO,防止GPIO口的輸入輸出對模擬電壓造成干擾
10.2.3函數聲明AD.h
#ifndef __AD_H
#define __AD_Hvoid AD_Init(void);
uint16_t ADC_GetValue(void);#endif
11.AD多通道
11.1接線圖
11.2代碼編寫
11.2.1主程序main.c
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "LED.h"
#include "KEY.h"
#include "OLED.h"
//#include "OLED_Font.h"
#include "AD.h"uint8_t AD0;
uint8_t AD1;
uint8_t AD2;
uint8_t AD3;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){AD0 = ADC_GetValue(ADC_Channel_0);AD1 = ADC_GetValue(ADC_Channel_1);AD2 = ADC_GetValue(ADC_Channel_2);AD3 = ADC_GetValue(ADC_Channel_3);OLED_ShowNum(1,5,AD0,4);OLED_ShowNum(2,5,AD1,4);OLED_ShowNum(3,5,AD2,4);OLED_ShowNum(4,5,AD3,4);Delay_ms(100);}
}
11.2.2函數定義AD.c
主要是在獲取AD值時對通道進行修改,實現動態單通道獲取多個通道
#include "stm32f10x.h" // Device headervoid AD_Init(void){RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);//開啟ADC時鐘RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,ENABLE);//配置ADCCLKRCC_ADCCLKConfig(RCC_PCLK2_Div6);//ADCCLK=72MHz/6=12MHz//GPIO初始化GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 |GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3;GPIO_Init(GPIOA, &GPIO_InitStructure);//ADC初始化ADC_InitTypeDef ADC_InitStructure;ADC_InitStructure.ADC_ContinuousConvMode =ENABLE;ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;ADC_InitStructure.ADC_NbrOfChannel = 1;ADC_InitStructure.ADC_ScanConvMode = DISABLE; ADC_Init(ADC1,&ADC_InitStructure);ADC_Cmd(ADC1,ENABLE);//校準ADC_ResetCalibration(ADC1);while(ADC_GetResetCalibrationStatus(ADC1) == SET);ADC_StartCalibration(ADC1);while(ADC_GetCalibrationStatus(ADC1)==SET);}//獲取ADC值
uint16_t ADC_GetValue(uint8_t ADC_Channel){//每次都重新指定通道,來實現多通道ADC_RegularChannelConfig(ADC1,ADC_Channel,1,ADC_SampleTime_55Cycles5);//使用參數來修改通道ADC_SoftwareStartConvCmd(ADC1,ENABLE);//獲取標志位狀態while(ADC_GetFlagStatus(ADC1,ADC_FLAG_EOC)==RESET);return ADC_GetConversionValue(ADC1);
}
11.2.3函數聲明AD.h
#ifndef __AD_H
#define __AD_Hvoid AD_Init(void);
uint16_t ADC_GetValue(uint8_t ADC_Channel);#endif
n.實現步驟
n.1ADC配置的步驟
- 開啟RCC時鐘,包括ADC和GPIO的時鐘,另外。ADCCLK的分頻器時鐘
- 配置GPIO,把需要的GPIO配置成模擬輸入的模式
- 選擇規則組的輸入通道
- 配置多路開關,把左邊的通道接入右邊的規則組列表里
- 配置ADC轉換器
- 開關控制,調用ADC_Cmd函數,開啟ADC
n.2校準的4個步驟
調用4個函數即可
- 復位校準
- 等待校準完成
- 開始校準
- 等待校準完成
e(ADC_GetFlagStatus(ADC1,ADC_FLAG_EOC)==RESET);
return ADC_GetConversionValue(ADC1);
}
#### 11.2.3函數聲明AD.h```c
#ifndef __AD_H
#define __AD_Hvoid AD_Init(void);
uint16_t ADC_GetValue(uint8_t ADC_Channel);#endif
n.實現步驟
n.1ADC配置的步驟
- 開啟RCC時鐘,包括ADC和GPIO的時鐘,另外。ADCCLK的分頻器時鐘
- 配置GPIO,把需要的GPIO配置成模擬輸入的模式
- 選擇規則組的輸入通道
- 配置多路開關,把左邊的通道接入右邊的規則組列表里
- 配置ADC轉換器
- 開關控制,調用ADC_Cmd函數,開啟ADC
n.2校準的4個步驟
調用4個函數即可
- 復位校準
- 等待校準完成
- 開始校準
- 等待校準完