目錄
1.基礎(chǔ)概念
2.原理:ADC采樣過程分為四步:采樣、保持、量化、編碼。
3.采樣定理
4.采樣保持放大器(SHA)
5.ADC電壓值轉(zhuǎn)換
6.ADC輪詢采樣
1.基礎(chǔ)概念
ADC 全稱:Analog-to-Digital Converter,指模擬/數(shù)字轉(zhuǎn)換器,就是將模擬信號轉(zhuǎn)換成數(shù)字信號
①模擬信號:是連續(xù)變化的,具有電路簡單,分辨率很高的特點,抗噪聲能力弱
②數(shù)字信號:是離散變化的,抗噪聲能力強,便于存儲和交換,可用于加密
2.原理:ADC采樣過程分為四步:采樣、保持、量化、編碼。
①采樣是指將模擬波形在時域上進行切分,每個切片大小大致等于原來的波形的值,這過程往往回丟失一些信息
②采樣保持:如果被采樣的模擬信號的變化頻率相對于A/D轉(zhuǎn)換器的速度來說比較高,為保證轉(zhuǎn)換精度,需要在A/D轉(zhuǎn)換之前加上采樣保持電路,使得在A/D轉(zhuǎn)換期間保持輸入模擬信號不變。
③量化:在采樣完后給每個時間片分配一個數(shù)字,這樣的過程稱為量化
④編碼:?量化后的數(shù)值還需通過編碼用一個二進制代碼表示出來,經(jīng)過編碼后得到的就是AD轉(zhuǎn)換結(jié)果的數(shù)字量,二進制編碼的位寬等于ADC的位寬。
3.采樣定理
?又稱奈奎斯特采樣定理,即當采樣頻率fs大于采樣信號最高頻率fmax的兩倍時,采樣后的數(shù)字信號完整地保留了原始信號中的信息。公式 :fs>2*fn
4.采樣保持放大器(SHA)
采樣保持過程將已采樣的模擬電壓在一段必要的時間內(nèi)保持恒定,以便讓ADC將模擬電壓轉(zhuǎn)換成數(shù)字形式。
一個基本的SHA如圖,開始的時候模擬開關(guān)閉合,通過輸入緩沖放大器對模擬電壓進行采樣,電容C存儲或保存采樣電壓一段時間,輸出緩沖放大器提供一個高輸入阻抗來防止電容快速掉電。ADI要求輸出緩沖器的輸入阻抗足夠高,以便電容可以保持時間內(nèi)放電少于1LSB
5.ADC電壓值轉(zhuǎn)換
1.首先確定ADC是幾位的,即確定最大數(shù)值是多少。比如一個8位的ADC,最大值是0xFF,就是255。
(一般芯片手冊會有說明)
2.然后確定最大值時對應的參考電壓值。一般而言最大值對應3.3V。這個你需要看這個芯片ADC模塊的說明。寄存器中有對于輸入信號參考電壓的設(shè)置。
3.計算電壓,讀取的ADC數(shù)值除以最大數(shù)值再乘以參考電壓值。比如你ADC值為0x55,那么實際值就是0x55/(0xFF+1)*3.3V = 1.65V
4.驗證計算值。你可以用電壓表量一下對應的引腳,看看計算值和實際值是否一樣。
/********************************************************/
/** AT89C52+ADC0832+LCD1602 **/
/** 用ADC0832采集電壓,并在1602上顯示電壓值 **/
/********************************************************/
#include <reg52.h>
#include <intrins.h>
typedef unsigned int u16;
typedef unsigned char u8;
bit RW=0;
sbit RS=P2^7;
sbit EN=P2^6;
sbit CLK=P1^0;
sbit DIO=P1^1;
sbit CS=P1^3;
u8 len;
u8 Display_Buffer[4];
void LcdInit();
void delay_us(u8 us);
void delay_ms(u8 ms);
void LcdDisplay(u8 x,u8 y, u8 *str);
void LcdSetCursor(u8 x,u8 y);
void LcdStar();
void write_con(u8 con);
void write_dat(u8 dat);
u8 Get_AD_Result()
{
u8 i;
u8 data1=0,data2=0;
CS=0;
//第一個下降沿到來前,DI需置1,起始控制位,開始轉(zhuǎn)換
CLK=0;DIO=1; _nop_();
CLK=1;_nop_();
//第二個下降沿到來前,設(shè)D=1/0,選擇單端/差分(SGL/DIF)模式中的單端輸入模式
CLK=0;DIO=1; _nop_();
CLK=1; _nop_();
//第三個下降沿到來前,設(shè)D=0/1,選擇CH0/CH1,這里選擇單通道ch0
CLK=0;DIO=1; _nop_();
CLK=1;DIO=0; _nop_();
//第四個下降沿到來前,DI =1
CLK=0;DIO=1; _nop_();
//4-11,共8個下降沿 DO輸出轉(zhuǎn)換信號,讀取數(shù)據(jù)(MSB-->LSB)
for(i=0;i<8;i++)
{
CLK=1;_nop_();
CLK=0;_nop_();
data1=(data1<<1)|(u8)DIO;
}
//11-18,共8個下降沿,讀取數(shù)據(jù)(LSB)-->MSB)
for(i=0;i<8;i++)
{
data2=data2|((u8)DIO<<i);
CLK=1;_nop_();
CLK=0;_nop_();
}
CS=1;
//如果MSB-->LSB和LSB)-->MSB讀取數(shù)據(jù)結(jié)果相同,返回讀取結(jié)果,否則0
return(data1==data2)?data1:0;
}
//-----------------------------------------
// 主函數(shù)
//-----------------------------------------
void main()
{
u8 Data;
LcdInit();
LcdStar();
while(1)
{
//獲取AD轉(zhuǎn)換值 最大值255對應最高電壓5.000v 顯示三個數(shù) 使用500
Data =Get_AD_Result()*500.0/255;
Display_Buffer[0]= Data/100+'0';
Display_Buffer[1]= '.';
Display_Buffer[2]=Data/10%10+'0';
Display_Buffer[3]=Data%10+'0';
LcdDisplay(9,1, Display_Buffer);
}
}
//-----------------------------------------
// 延時us和1ms函數(shù)
//-----------------------------------------
void delay_us(u8 us)
{
while(us--);
}
void delay_ms(u8 ms)
{
while(ms--)
{
delay_us(248);
delay_us(248);
}
}
//-----------------------------------------
// lcd1602顯示
//-----------------------------------------
//lcd初始化
void LcdInit()
{
write_con(0x01);//清屏
write_con(0x38);//設(shè)置16*2顯示,配置8位數(shù)據(jù)接口
write_con(0x38);//設(shè)置16*2顯示,配置8位數(shù)據(jù)接口
write_con(0x0C);//開顯示,光標關(guān),閃爍關(guān),去黑塊
write_con(0x06);//寫數(shù)據(jù)時光標右移,畫面不動
}
void LcdStar()
{
u8 code str[]="Voltage measure";
u8 tab[]="Voltage=";
LcdInit(); //初始化1602液晶
LcdDisplay(1,0,str);
LcdDisplay(1,1,tab);
LcdDisplay(9,1,"..."); //默認初始化溫度00
LcdDisplay(13,1,"V"); //添加V電壓
}
//設(shè)置顯示RAM 起始地址,亦即光標位置,(x,y)對應屏幕上的起始坐標
void LcdSetCursor(u8 x,u8 y)
{
u8 addr;
if(y==0) //由輸入的屏幕坐標計算顯示RAM的地址
addr=0x00+x; //第一行字符地址從0x00起始
else
addr=0x40+x; //第二行字符地址從0x40起始
write_con(addr|0x80); //設(shè)置RAM地址
}
//設(shè)置顯示RAM 起始地址,亦即光標位置,(x,y)對應屏幕上的起始坐標,str-字符串指針
void LcdDisplay(u8 x,u8 y,u8 *str)
{
LcdSetCursor(x,y); //設(shè)置起始地址
while(*str !='\0') //連續(xù)寫入字符串數(shù)據(jù),直到檢測到結(jié)束符
{
write_dat(*str++); //先取str指向的數(shù)據(jù),然后str自加1
delay_us(100);
}
}
//lcd1602寫指令
void write_con(u8 con)
{
P0=con;
RS=0;
RW=0;
EN=1;
delay_us(200);
EN=0;
}
//lcd1602寫數(shù)據(jù)
void write_dat(u8 dat)
{
P0=dat;
RS=1;
RW=0;
EN=1;
delay_us(200);
EN=0;
}
6.ADC輪詢采樣
在STM32 ADC輪詢轉(zhuǎn)換通道中,下一個通道開啟時前一個通道不需要手動關(guān)閉,ADC會自動切換到下一個通道進行采集。
ADC輪詢轉(zhuǎn)換通道的原理和過程:
ADC(Analog-to-Digital Converter)是模擬信號轉(zhuǎn)換為數(shù)字信號的電路。在STM32中,ADC是一個十分重要的外設(shè),它可以將模擬信號轉(zhuǎn)換為數(shù)字信號,供微處理器進行處理。
ADC的轉(zhuǎn)換方式有多種,其中輪詢轉(zhuǎn)換通道是最基本的一種,它的原理是:在一次轉(zhuǎn)換完成之后,自動切換到下一個通道進行采集,直到所有通道采集完成,然后產(chǎn)生一個轉(zhuǎn)換結(jié)束的中斷。
下面是一個簡單的ADC輪詢轉(zhuǎn)換通道的代碼示例:
初始化ADC模塊:設(shè)置ADC通道和轉(zhuǎn)換模式等參數(shù),以及開啟ADC時鐘。
獲取采樣數(shù)據(jù):通過設(shè)置ADC轉(zhuǎn)換模式為單次轉(zhuǎn)換或連續(xù)轉(zhuǎn)換,輪流對3個通道進行采樣,將采樣結(jié)果存儲到緩沖區(qū)中。
數(shù)據(jù)處理:將采樣結(jié)果進行處理,比如進行濾波、校準等操作,得到最終的采樣數(shù)據(jù)。
計算采樣時間和定采樣周期:采樣時間是指從開始采樣到采樣結(jié)束所需的時間,可以通過軟件延時或硬件定時器實現(xiàn)。采樣周期是指兩次采樣之間的時間間隔,可以根據(jù)需要進行設(shè)置。
以下是單次采樣的代碼實現(xiàn)和注釋,把三個通道的數(shù)據(jù)都放在一個緩沖區(qū):
#include "bf7006_adc.h"
#define ADC_BUFFER_SIZE 16 // 緩沖區(qū)大小
#define ADC_SAMPLE_TIME 10 // 采樣時間,單位為ms
#define ADC_SAMPLE_PERIOD 100 // 采樣周期,單位為ms
static uint16_t adc_buffer[ADC_BUFFER_SIZE]; // 采樣數(shù)據(jù)緩沖區(qū)
static uint8_t adc_buffer_index = 0; // 緩沖區(qū)索引
/**
* @brief 初始化ADC模塊
*/
void adc_init(void)
{
HAL_ADC_ConfigChannel(&hadc, ADC_CHANNEL_0, ADC_MODE_SINGLE); // 配置ADC通道0為單次轉(zhuǎn)換模式
HAL_ADC_ConfigChannel(&hadc, ADC_CHANNEL_1, ADC_MODE_SINGLE); // 配置ADC通道1為單次轉(zhuǎn)換模式
HAL_ADC_ConfigChannel(&hadc, ADC_CHANNEL_2, ADC_MODE_SINGLE); // 配置ADC通道2為單次轉(zhuǎn)換模式
HAL_ADC_Start(&hadc); // 開啟ADC轉(zhuǎn)換
}
/**
* @brief 獲取采樣數(shù)據(jù)
*/
void adc_sample(void)
{
HAL_ADC_Start(&hadc); // 開始轉(zhuǎn)換
HAL_ADC_PollForConversion(&hadc, ADC_SAMPLE_TIME); // 等待轉(zhuǎn)換完成
adc_buffer[adc_buffer_index++] = HAL_ADC_GetValue(&hadc); // 保存采樣結(jié)果
if (adc_buffer_index >= ADC_BUFFER_SIZE) { // 緩沖區(qū)已滿,重置索引
adc_buffer_index = 0;
}
}
/**
* @brief 數(shù)據(jù)處理
*/
uint16_t adc_process_data(void)
{
uint16_t result = 0;
for (uint8_t i = 0; i < ADC_BUFFER_SIZE; i++) { // 對所有采樣數(shù)據(jù)進行求和
result += adc_buffer[i];
}
result /= ADC_BUFFER_SIZE; // 求平均值
return result;
}
/**
* @brief 計算采樣周期
*/
uint32_t adc_calculate_period(void)
{
return ADC_SAMPLE_PERIOD - ADC_SAMPLE_TIME; // 采樣周期減去采樣時間即為等待時間
}
開發(fā)板的ADC模塊有三個通道,可以通過輪詢的方式進行連續(xù)轉(zhuǎn)換采樣。下面是采樣原理和過程:
采樣原理:
ADC模塊將模擬信號轉(zhuǎn)換為數(shù)字信號,采樣過程中需要注意采樣精度和采樣速率。采樣精度指的是數(shù)字信號的位數(shù),采樣速率指的是每秒鐘采樣的次數(shù)。
采樣過程:
1. 初始化ADC模塊,設(shè)置ADC通道和采樣精度;
2. 設(shè)置ADC轉(zhuǎn)換模式為連續(xù)轉(zhuǎn)換模式;
3. 啟動ADC轉(zhuǎn)換;
4. 輪詢ADC轉(zhuǎn)換完成標志位,讀取ADC轉(zhuǎn)換結(jié)果;
5. 對采樣數(shù)據(jù)進行處理和計算。下面是代碼注釋及解析:
#include "stm32f10x.h"
#define ADC1_DR_Address ((uint32_t)0x4001244C) // ADC1數(shù)據(jù)寄存器地址
uint16_t ADC_ConvertedValue[3]; // 存儲ADC采樣結(jié)果
void ADC_Configuration(void)
{
ADC_InitTypeDef ADC_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
// 使能ADC1和GPIOA時鐘
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1 | RCC_APB2Periph_GPIOA, ENABLE);
// 配置PA0、PA1、PA2為模擬輸入
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
GPIO_Init(GPIOA, &GPIO_InitStructure);
// ADC1配置
ADC_InitStructure.ADC_Mode = ADC_Mode_Independent; // 獨立模式
ADC_InitStructure.ADC_ScanConvMode = ENABLE; // 開啟掃描模式
ADC_InitStructure.ADC_ContinuousConvMode = ENABLE; // 開啟連續(xù)轉(zhuǎn)換模式
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; // 不使用外部觸發(fā)轉(zhuǎn)換
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; // 數(shù)據(jù)右對齊
ADC_InitStructure.ADC_NbrOfChannel = 3; // 采樣通道數(shù)為3
ADC_Init(ADC1, &ADC_InitStructure);
// 配置ADC1通道0、1、2為采樣通道
ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_55Cycles5);
ADC_RegularChannelConfig(ADC1, ADC_Channel_1, 2, ADC_SampleTime_55Cycles5);
ADC_RegularChannelConfig(ADC1, ADC_Channel_2, 3, ADC_SampleTime_55Cycles5);
// 使能ADC1
ADC_Cmd(ADC1, ENABLE);
// ADC1校準
ADC_ResetCalibration(ADC1);
while (ADC_GetResetCalibrationStatus(ADC1));
ADC_StartCalibration(ADC1);
while (ADC_GetCalibrationStatus(ADC1));
}
void ADC_Sampling(void)
{
uint8_t i;
// 開始轉(zhuǎn)換
ADC_SoftwareStartConvCmd(ADC1, ENABLE);
// 等待轉(zhuǎn)換完成
while (!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC));
// 讀取采樣結(jié)果
for (i = 0; i < 3; i++)
{
ADC_ConvertedValue[i] = ADC_GetConversionValue(ADC1);
}
// 清除轉(zhuǎn)換完成標志位
ADC_ClearFlag(ADC1, ADC_FLAG_EOC);
}
int main(void)
{
ADC_Configuration();
while (1)
{
ADC_Sampling();
}
}
在上面的代碼中,我們通過`ADC_Configuration()`函數(shù)初始化ADC模塊,設(shè)置ADC通道,ADC轉(zhuǎn)換模式。然后,在`adc_sampling()`函數(shù)中,啟動ADC轉(zhuǎn)換,我們通過輪詢ADC轉(zhuǎn)換完成標志位,讀取ADC轉(zhuǎn)換結(jié)果,并將采樣數(shù)據(jù)存儲到數(shù)組中。最后,在`adc_process()`函數(shù)中,我們對采樣數(shù)據(jù)進行處理和計算。
關(guān)于采樣時間和采樣周期的計算,可以根據(jù)采樣精度和采樣速率進行計算。采樣時間可以通過以下公式計算:
采樣時間 = 1 / 采樣速率
采樣周期可以通過以下公式計算:
采樣周期 = 采樣時間 x 采樣次數(shù)文章來源:http://www.zghlxwxcb.cn/news/detail-443804.html
在實際應用中,我們可以根據(jù)需要調(diào)整采樣精度和采樣速率,以滿足應用的要求。文章來源地址http://www.zghlxwxcb.cn/news/detail-443804.html
到了這里,關(guān)于STM32 ADC采樣的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!