1.基础概念

ADC 全称:Analog-to-Digital Converter,指模拟/数字转换器,就是将模拟信号转换成数字信号

 

edd5ca53e555432db7899086862e41f1.png

 

①模拟信号:是连续变化的,具有电路简单,分辨率很高的特点,抗噪声能力弱

②数字信号:是离散变化的,抗噪声能力强,便于存储和交换,可用于加密

 

c59ef09329c84c43add56ac04f8c0be0.png

2.原理:ADC采样过程分为四步:采样、保持、量化、编码。

①采样是指将模拟波形在时域上进行切分,每个切片大小大致等于原来的波形的值,这过程往往回丢失一些信息

②采样保持:如果被采样的模拟信号的变化频率相对于A/D转换器的速度来说比较高,为保证转换精度,需要在A/D转换之前加上采样保持电路,使得在A/D转换期间保持输入模拟信号不变。

③量化:在采样完后给每个时间片分配一个数字,这样的过程称为量化

④编码: 量化后的数值还需通过编码用一个二进制代码表示出来,经过编码后得到的就是AD转换结果的数字量,二进制编码的位宽等于ADC的位宽。

 

d3229d9aa80c4d8581c63724d9b39b9d.png

 

3.采样定理

 又称奈奎斯特采样定理,即当采样频率fs大于采样信号最高频率fmax的两倍时,采样后的数字信号完整地保留了原始信号中的信息。公式 :fs>2*fn

 

4.采样保持放大器(SHA)

采样保持过程将已采样的模拟电压在一段必要的时间内保持恒定,以便让ADC将模拟电压转换成数字形式。

一个基本的SHA如图,开始的时候模拟开关闭合,通过输入缓冲放大器对模拟电压进行采样,电容C存储或保存采样电压一段时间,输出缓冲放大器提供一个高输入阻抗来防止电容快速掉电。ADI要求输出缓冲器的输入阻抗足够高,以便电容可以保持时间内放电少于1LSB

 

d053f3dd8e0d410aa335052e50bffa58.png

 

 

 

ADC电压值转换

1.首先确定ADC是几位的,即确定最大数值是多少。比如一个8位的ADC,最大值是0xFF,就是255。
(一般芯片手册会有说明)

2.然后确定最大值时对应的参考电压值。一般而言最大值对应3.3V。这个你需要看这个芯片ADC模块的说明。寄存器中有对于输入信号参考电压的设置。

3.计算电压,读取的ADC数值除以最大数值再乘以参考电压值。比如你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,起始控制位,开始转换

    CLK=0;DIO=1; _nop_();   

    CLK=1;_nop_();

    

 //第二个下降沿到来前,设D=1/0,选择单端/差分(SGL/DIF)模式中的单端输入模式

    CLK=0;DIO=1; _nop_();  

    CLK=1;       _nop_();     

 

 //第三个下降沿到来前,设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输出转换信号,读取数据(MSB-->LSB) 

    for(i=0;i<8;i++)

    {

        CLK=1;_nop_();

        CLK=0;_nop_();

       data1=(data1<<1)|(u8)DIO;

    }

//11-18,共8个下降沿,读取数据(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读取数据结果相同,返回读取结果,否则0

    return(data1==data2)?data1:0;

}

 

//-----------------------------------------

//    主函数

//-----------------------------------------

void main()

{

    u8 Data;

	LcdInit();

    LcdStar();

	while(1)

	{

        //获取AD转换值 最大值255对应最高电压5.000v 显示三个数 使用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函数

//-----------------------------------------

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);//设置16*2显示,配置8位数据接口

    write_con(0x38);//设置16*2显示,配置8位数据接口

	write_con(0x0C);//开显示,光标关,闪烁关,去黑块

	write_con(0x06);//写数据时光标右移,画面不动

	

}

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电压

}

//设置显示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);   //设置RAM地址

        

}

//设置显示RAM 起始地址,亦即光标位置,(x,y)对应屏幕上的起始坐标,str-字符串指针

void LcdDisplay(u8 x,u8 y,u8 *str)

{

    LcdSetCursor(x,y); //设置起始地址  

	while(*str !='\0')  //连续写入字符串数据,直到检测到结束符

	{

		write_dat(*str++);  //先取str指向的数据,然后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写数据

void write_dat(u8 dat)

{

	P0=dat;

	RS=1;

	RW=0;

	EN=1;

	delay_us(200);

	EN=0;

}

 

 

 

 

物联沃分享整理
物联沃-IOTWORD物联网 » STM32 ADC采样

发表回复