单片机ad转换_单片机ad转换代码 - CSDN
精华内容
参与话题
  • 熟悉AD转换单片机的使用的编程。 二、设计环境 Keil开发环境 Proteus软件。 三、设计及调试 (1) 设计内容 将电阻的电压模拟信号通过AD转换芯片转换成数字量; 将转换后的数字量通过LED数码管显示。 (2) 设计...

    一、设计目的

    1. 掌握AD转换芯片的基本工作原理;
    2. 掌握一个完整的C语言程序结构;
    3. 熟悉AD转换与单片机的使用的编程。

    二、设计环境

    1. Keil开发环境
    2. Proteus软件。

    三、设计及调试
    (1) 设计内容

    1. 将电阻的电压模拟信号通过AD转换芯片转换成数字量;
    2. 将转换后的数字量通过LED数码管显示。

    (2) 设计硬件电路
    在这里插入图片描述
    AT89C51单片机,四位共阳数码管,滑动变阻器,ADC0809

    (3) 设计过程及调试关键步骤
    首先按要求连接电路,之后将各个引脚在keil中进行命名,在滑动变阻器旁边加个电压表进行对数码管数据的检验。因为使用的外部中断,在中断函数中进行AD转换操作。程序编写完成后运行仿真,发现数据改变过大且不准,经过检查是AD转换器的输出端高低位接反,改正后能正常显示,仿真完成。

    四、实验结果与分析
    (1)程序

    #include<reg51.h> 
    #define uchar unsigned char
    #define uint unsigned int 
    sbit OE=P3^0; //AD转换结果输出允许端
    sbit START=P3^1;//AD启动信号输入端与接受C、B、A编码时的锁存控制信号
    sbit EOC=P3^2;//转换结束输出信号,AD转换开始时为低电平,转换结束时为高电平
    sbit A_data=P3^3;
    sbit B_data=P3^4;
    sbit C_data=P3^5; 
    uint information=0; //转换出的数据
    uchar b[4];         //用于存放数码管的数据
    uchar a[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90};  
    //共阳数码管1-9数字代码
    uchar wei[]={0x01,0x02,0x04,0x08};   //共阳数码管位选代码 
    void delay1ms(uint digit){	
    uint i,j;	
    for(i=0;i<digit;i++)		
    for(j=0;j<120;j++);}
    void show(){	
    P2=wei[0];	
    P0=b[3];	
    delay1ms(1);	
    P2=0x00;	
    P2=wei[1];	
    P0=b[2]+128;	
    delay1ms(1);	
    P2=0x00;	
    P2=wei[2];	
    P0=b[1];	
    delay1ms(1);	
    P2=0x00;	
    P2=wei[3];	
    P0=b[0];	
    delay1ms(1);	
    P2=0x00;}
    void main(){	
    EA=1;            //开总中断	
    IT0=1;           //跳变沿方式感知外部中断(触发方式)	
    EX0=1;           //开外部中断0	
    while(1){	
    START=0;	
    A_data=0;	
    B_data=0;	
    C_data=0;	
    START=1; 	
    START=0;	
    delay1ms(5);}}
    void InT0(void) interrupt 0{	
    uchar i;	
    OE=1;	
    information=P1;	
    information=information*1.96; //将数据转换为十进制(5V/256约等于1.96)	
    OE=0;	
    b[0]=a[information%10];	
    b[1]=a[information/10%10];	
    b[2]=a[information/100%10];	
    b[3]=a[information/1000];	
    for(i=0;i<100;i++){		
    show();}	 //显示到数码管上
    }

    (2)设计结果及现象
    将电阻的电压模拟信号通过AD转换芯片转换成数字量,然后将转换后的数字量通过LED数码管显示
    在这里插入图片描述
    滑动变阻器拉到最上端时显示4.99
    在这里插入图片描述
    滑动变阻器拉到中端时显示2.48
    在这里插入图片描述
    滑动变阻器拉到低端时显示0.00

    (3)设计结果的分析与总结,有无改进方案?

    1. 设计结果的分析和总结:进行新芯片使用时应该先仔细观察各个引脚的作用与高低位,之后进行编程仿真时能够少出很多错,减少调试的时间。
    2. 改进方案:在编程时有多出重复可以使用for循环或者do while语句进行程序的简洁化和可观化。
    展开全文
  • 单片机AD转换

    千次阅读 2017-05-12 23:06:53
     声明 转换结果寄存器 转换出来的分数保存在这个寄存器里,范围0~255。 假如写程序 a=ADC_RES; a就获得转换结果了。 sfr P1ASF=0x9D 声明 P1口模拟功能寄存器   设置P1.7引脚对应的程序是: P1ASF=0x80; ...
     sfr ADC_RES=0xBD;  声明 转换结果寄存器
    转换出来的分数保存在这个寄存器里,范围0~255。
    假如写程序 a=ADC_RES; a就获得转换结果了。

    sfr P1ASF=0x9D 声明 P1口模拟功能寄存器
     
    设置P1.7引脚对应的程序是: P1ASF=0x80;

     sfr ADC_CONTR=0xBC  声明 模数转换寄存器
     .
    这个寄存器里面参数较多,不过我们只需要用该用到的就行了,别的暂时不用理会。
    寄存器的后三位是引脚选择,000~111,0到7代表P1.0~P1.7引脚。
    开始P1.7引脚AD转换,你可以直接设置为 1000 1111,也可以分开再相加 1000 1000+111
    对应程序,可以写作 ADC_CONTR=0x8F; 也可以写作 ADC_CONTR=0x88+7;

     AD转换例程
    P1ASF=0x80;  //设置P1.7引脚
    ADC_CONTR=0x88+7;  //开始P1.7引脚转换
    Delay50us();   //等待AD转换完成
    a=ADC_RES;  //读取转换结果

    单片机时钟为12M时,一次AD转换最慢也是45us,所以等待50us即可保证转换完成。

    、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、


    展开全文
  • 51单片机AD/DA转换

    万次阅读 2017-02-09 17:31:42
    一、A/D(模数)、D/A(数模)转换 (一)、引脚 AOUT:模拟输出 Vref:参考电压 AGND:模拟地 EXT:接地 OSC:悬空 SCL,SDA:IIC AIN0、AIN1、AIN2:模拟输入口 (二)、电路图 从电路图...
    一、A/D(模数)、D/A(数模)转换
    (一)、引脚

    AOUT:模拟输出
    Vref:参考电压
    AGND:模拟地
    EXT:接地
    OSC:悬空
    SCL,SDA:IIC
    AIN0、AIN1、AIN2:模拟输入口

    (二)、电路图

    从电路图可以看出,A0,A1,A2接地,所以当写入的时候地址应该是0X90,读取的时候应该是0X91

    (三)、AGND和DGND

    模拟地和数字地隔离开,消除干扰

    (四)、控制字节

    (五)、AD读数据函数
    #include <reg52.h>
    #include "delay.h"
    #include "iic.h"

    #define SUCC 1
    #define FAIL 0

    unsigned char ad_read_byte(unsigned char device_addr,unsigned char channel)
    {
        unsigned char result;
          unsigned char temp;

          iic_start();
          result = iic_send_byte(device_addr);
          if(result == FAIL)
            {
                  return FAIL;
            }

          result = iic_send_byte(0x44 + channel);
          if(result == FAIL)
            {
                  return FAIL;
            }

            iic_start();

            result = iic_send_byte(device_addr + 1);
          if(result == FAIL)
            {
                  return FAIL;
            }

        temp = iic_rcv_byte();

        iic_noack();
            iic_stop();
        return temp;        
    }

    (六)、AD写数据函数
    unsigned char ad_write_byte(unsigned char deviceaddr, unsigned char num)
    {
          unsigned char result;
          iic_start();

          result = iic_send_byte(deviceaddr);
          if(result == FAIL) return FAIL;

          result = iic_send_byte(0x40);
          if(result == FAIL) return FAIL;

          result = iic_send_byte(num);
          if(result == FAIL) return FAIL;

          iic_stop();

          return SUCC;
    }









    展开全文
  • 第五讲 单片机C语言之AD转换

    千次阅读 2017-07-18 12:58:23
    介绍了ADC转换的基本原理,分别利用实验讲述了ADC芯片TLC0831和片内ADC的使用方法。

    前面我在另一篇博客<<初学电子ADC模块应用的一些问题>>里面详细介绍过ADC的基本原理,那这讲便直接来看如何应用ADC。首先单片机可以使用专门的外设AD转换芯片来读取模拟数据,其次也可以通过片内ADC来实现读取。因此我们分两部分来进行。

    基础概念

    还是回顾一下基础概念,之前的单片机学习都是关于某个IO口输出或接收到低电平或者高电平,在51里是0或5V,但是如果想接收一些模拟信号呢?什么是模拟信号,两个特点,一是随时间连续变化,譬如温度,每时每刻都在变化,而是可以有无数个取值,就是说你在任何一个时间点都能找到一个温度值。现在如果我们要测量这个模拟信号,比如温度信号,可以怎么做呢?一种方法是使用特定的芯片如TLC0831或者TLC0832等等,这些芯片有输入引脚可以直接连接温度传感器,然后当温度变化的时候,传感器电路会发出电压值,通过该引脚捕获这个电压值,芯片便会输出一个数字量。通常温度与传感器的电压会成一定比例关系,因此我们也可以构建数字量与传感器电压之间的关系,进而得出了数字量与温度之间的关系。另一种方法则是使用片内的ADC了,一般51单片机的P1口(具体哪些口要看芯片数据手册)都具有ADC功能。不管哪种方法,AD转换器的技术指标都是一样的。一般我们只关注3个指标。

    (1)ADC的位数:ADC转换芯片输出的数字信号线的根数。(用N表示)常见的有8 bit, 10bit, 12bit, 24bit...
    (2)ADC的分辨率:能够引起AD转换输出端数字量发生一个台阶变化所对应的输入模拟量。(Vmin)
    (3)参考电压(VREF):所有的ADC芯片必须满足关系式,Vmin=VREF/2的n次方。

    一般来说我们在实际项目中,如果要求提高分辨率的话,可以考虑减小参考电压或者增加位数。但是建小了参考电压的话,量程又减小了。你比如一个传感器输出的电压是5V,但是你的AD转换器参考电压3.3V,那么就无法捕捉到其余部分了。所以这种情况下还是考虑选用高位数的AD转换器。另外如果有负压出现,比如有的温度传感器输出负电压时候对应的是负温度值,则要考虑引入负参考电压。

    既然现在有了数字量了,只需要将其标定为电压模拟信号,然后再由模拟信号计算出对应的实际模拟量的值。

    AD转换芯片

    好了,现在我们就来尝试用TLC0381芯片读取0-5V的电压。

    先看我们的硬件电路部分。


    MCU的三个引脚如高亮部分接到TLC0831芯片:


    再给TLC0831的模拟口输入一个由电位器调节的电压,另外P19处,VREF应当接到5v的参考电压,这里不再附图了:


    TLC0831是一款8位的AD转换器,即如果我们读到的数字量应该是一个介于0-255之间的数,当电位器电阻0时,对应数字量0,电压为0V,同理电位器电阻调到最大,应该对应255,电压为5V。好了我们直接上程序吧。

    main.c

    #include "reg51.h"
    #include "12864.h"
    #include "tlc0831.h"
    
    u8 ad;
    void main()
    {
    	 float v;
    	 LCD_Init();
    	 Show_String(0x80,"TLC0831");
    	while(1)
    	{
    		ad=Read_tcl0831();	   //读取数字量
    		v=0.0195*ad;			 //将数字量标定为电压值 5.00V/256=0.0195
    		Show_Number(0x90,ad);
    		Show_Float(0x88,v);	
    	}
    }

    tlc0831.c

    #include "tlc0831.h"
    sbit tlc0831_ck=P3^3;
    sbit tlc0831_do=P1^5;
    sbit tlc0831_cs=P2^3;
    
    u8 Read_tcl0831()
    {
    	u8 ad,i;
    	tlc0831_ck=0;
    	tlc0831_cs=0;
    	delay(1);
    
    	tlc0831_ck=1;
    	tlc0831_ck=0;
    	delay(1);
    
    	for(i=0;i<8;i++)
    	{
    		ad<<=1;
    		tlc0831_ck=1;
    		delay(1);
    		tlc0831_ck=0;
    		delay(1);
    		if(tlc0831_do)
    		{
    			ad|=0x01;
    		}
    	}
    
    	tlc0831_ck=0;
        tlc0831_cs=1;
    
    	return ad;
    }

    tlc0831.h

    #ifndef _tlc0831_
    #define _tlc0831_
    #include "reg51.h"
    #define u8 unsigned char
    #define u16 unsigned int
    
    u8 Read_tcl0831();
    extern void delay(u16 x);
    #endif

    12864.c

    #include "12864.h"
    #include "stdio.h"
    sbit LCDRS_CS=P3^5;   //-->4
    sbit LCDWR_SID=P3^6;   //5
    sbit LCDE_CLK=P3^7;	   //6PIN
     /*
     0XF8  µØÖ·£¬ÃüÁî
     0XFA  Êý¾Ý
     */
    
    code u8 Addmap[]={0X80,0X90,0X88,0X98};
    void delay(u16 x)
    {
      while(x--);
    }
    void LCD_SendByte(u8 d)  //ÏòLCD·¢ËÍÒ»¸ö×Ö½Ú
    {
      u8 i;
      for(i=0;i<8;i++)
      {
        LCDE_CLK=0;
    	if(d&0x80)
    	{
    	 LCDWR_SID=1;
    	}
    	else
    	{
    	 LCDWR_SID=0;
    	}
    	LCDE_CLK=1;
    	d<<=1;
      }
    }
    
    void Set_Text()  //ʹLCD½øÈëÎı¾Ä£Ê½
    {
      Write_cmd(0x30); 
    }
    void Set_DrawON()  //ʹLCD½øÈë»æͼģʽ
    {
      Write_cmd(0x36);
    }
    void Set_DrawOFF()  //ʹLCD½øÈë»æͼģʽ
    {
      Write_cmd(0x34);
    }
    void Set_TextAdd(u8 add) //ÉèÖÃÎı¾Ä£Ê½µØÖ·
    {
     	LCDE_CLK=0;
        LCDRS_CS=1;
    	LCD_SendByte(0XF8);
    	LCD_SendByte(add&0xf0);  //7654 0000
        LCD_SendByte(add<<4);	 //3210 0000
    	LCDE_CLK=0;
        LCDRS_CS=0;
    }
    
    void Write_data(u8 dat)  //ÏòLCDдÈëÏÔʾÊý¾Ý
    {
     	LCDE_CLK=0;
        LCDRS_CS=1;
    	LCD_SendByte(0XFa);
    	LCD_SendByte(dat&0xf0);  //7654 0000
        LCD_SendByte(dat<<4);	 //3210 0000
    	LCDE_CLK=0;
        LCDRS_CS=0;
    }
    void Write_cmd(u8 cmd)   //ÏòLCDдÈëÒ»ÌõÃüÁî
    {
     	LCDE_CLK=0;
        LCDRS_CS=1;
    	LCD_SendByte(0XF8);
    	LCD_SendByte(cmd&0xf0);  //7654 0000
        LCD_SendByte(cmd<<4);	 //3210 0000
    	LCDE_CLK=0;
        LCDRS_CS=0;
    }
    void LCD_Init()
    {
      Set_Text();  //ʹLCD½øÈëÎı¾Ä£Ê½
      Write_cmd(0x01);//Çå³ýÎı¾Ä£Ê½
      delay(5000);
      Write_cmd(0x0c); //
      delay(100);
      Draw_Clean();
    }
    void Show_chinese(u8 add,u8 qh,u8 ql)	   //ÔÚLCDÉÏÏÔʾһ¸öÖÐÎÄ
    {
      Set_Text();  
      Set_TextAdd(add);
      Write_data(qh);
      Write_data(ql); 
    }
    void Show_String(u8 add,u8 *str)   //ÔÚLCDÉÏÏÔʾ×Ö·û´®
    {
      Set_Text();  
      Set_TextAdd(add);
      while(*str)
      {
         Write_data(*str++);
      }   
    }
    
    void Show_Number(u8 add,u16 n)
    {
      char s[6]; 
      sprintf(s,"%05d",n);
      Show_String(add,s);
    }
    void Show_Float(u8 add,float n)	 //ÏÔʾ¸¡µãÊý
    {
      char s[6]; 
      sprintf(s,"%03.2f",n);
      Show_String(add,s);
    }
    
    void Set_GDRAMAdd(u8 add)  //ÉèÖÃGDRAMµÄµØÖ·
    {
        add|=0x80;
     	LCDE_CLK=0;
        LCDRS_CS=1;
    	LCD_SendByte(0XF8);
    	LCD_SendByte(add&0xf0);  //7654 0000
        LCD_SendByte(add<<4);	 //3210 0000
    	LCDE_CLK=0;
        LCDRS_CS=0;
    }
    
    void Show_Group(u8 x,u8 y,u16 dat)    //ÏÔʾ»æͼģʽµÄÒ»×é
    {			// x=0-7 y=0-63
     u8  x0, y0;   //LCDµÄÕæʵ×é×ø±ê
     if(y>31)	  //ÒªÏÔʾµÄ×éÔÚÏ°ëÆÁ
     {
        y0=y-32;
    	x0=x+8;
     }
     else	     //ÒªÏÔʾµÄ×éÔÚÉÏ°ëÆÁ
     {
        y0=y;
    	x0=x;
     }
    
      Set_DrawOFF() ;
      Set_GDRAMAdd(y0);
      Set_GDRAMAdd(x0);
      Write_data(dat>>8);
      Write_data(dat&0xff);
      Set_DrawON();
    }
     void Show_GroupX(u8 x,u8 y,u16 dat)    //ÏÔʾ»æͼģʽµÄÒ»×é
    {			// x=0-7 y=0-63
     u8  x0, y0;   //LCDµÄÕæʵ×é×ø±ê
     if(y>31)	  //ÒªÏÔʾµÄ×éÔÚÏ°ëÆÁ
     {
        y0=y-32;
    	x0=x+8;
     }
     else	     //ÒªÏÔʾµÄ×éÔÚÉÏ°ëÆÁ
     {
        y0=y;
    	x0=x;
     }
    
     // Set_DrawOFF() ;
      Set_GDRAMAdd(y0);
      Set_GDRAMAdd(x0);
      Write_data(dat>>8);
      Write_data(dat&0xff);
     // Set_DrawON();
    }
    
    void Draw_Clean()  //½«»æͼģʽµÄ×éÈ«²¿Çå0 
    {
     u8 x,y;
     Set_DrawOFF() ;
     for(y=0;y<64;y++)
     {
     	for(x=0;x<8;x++)
    	{  
    	  Show_GroupX(x,y,0x0000); 	
    	}
     }
     Set_DrawON() ;
    }
    
    void Showpic_128x64(u16 *tp) //ÏÔʾһ·ù128x64µÄͼƬ
    {
     u8 x,y;
     Set_DrawOFF() ;
     for(y=0;y<64;y++)
     {
     	for(x=0;x<8;x++)
    	{  
    	  Show_GroupX(x,y,*tp++); 	
    	}
     }
     Set_DrawON() ;
    }
    
    void Highlinght_line(u8 h,u8 w)   //½«Ä³Ò»ÐÐÎı¾Ëù¶ÔÓ¦µÄ»æͼÇø¸ßÁÁ»òÈ¡Ïû¸ßÁÁ
    {
      u16 dat;
      u8 sy,y,x;
      if(w==1)
      {
        dat=0xffff;
      }
      else
      {
        dat=0x0000;
      }
      sy=h*16;
    
      for(x=0;x<8;x++)
      {
      	for(y=sy;y<sy+16;y++)
    	{
    	  Show_Group(x,y,dat);
    	}
      }
    
    }
    
    void Dis_string(u8 h,u8 *str,u8 w)   //ÏÔʾһ¸ö×Ö·û´®£¬´ø¸ßÁÁ¿ØÖÆ
    {								     //w=1 ¸ßÁÁÏÔʾ£¬w=0Õý³£ÏÔʾ
      									 //h=0-3
      Show_String(Addmap[h],str);  
      Highlinght_line(h,w); 
    }
    void Highlinght_TextArea(u8 x,u8 y,u8 w)	//¸ßÁÁÏÔʾһ¸öÎı¾Çø
    {
     u8 sy,i;
     sy=y*16;
     for(i=0;i<16;i++)
     {
       if(w==1)
       {
       	   Show_Group(x,sy+i,0xffff);
       }
       else
       {
       	   Show_Group(x,sy+i,0x0000);   
       }
     }
    }
    
    
    12864.h

    #ifndef _12864_
    #define _12864_
    #include "reg51.h"
    #define u8 unsigned char
    #define u16 unsigned int
    void delay(u16 x);
    void SLCD_Init();et_Text();  //ʹLCD½øÈëÎı¾Ä£Ê½
    void Set_DrawON();  //ʹLCD½øÈë»æͼģʽ
    void Set_DrawOFF();  //ʹLCD½øÈë»æͼģʽ
    void Set_TextAdd(u8 add); //ÉèÖÃÎı¾Ä£Ê½µØÖ·
    void Write_data(u8 dat);  //ÏòLCDдÈëÏÔʾÊý¾Ý
    void Write_cmd(u8 cmd);   //ÏòLCDдÈëÒ»ÌõÃüÁî
    void LCD_Init(); 
    void Show_chinese(u8 add,u8 qh,u8 ql);
    void Show_String(u8 add,u8 *str);   //ÔÚLCDÉÏÏÔʾ×Ö·û´®
    void Show_Number(u8 add,u16 n);
    void Show_Float(u8 add,float n);	 //ÏÔʾ¸¡µãÊý
    void Show_Group(u8 x,u8 y,u16 dat);    //ÏÔʾ»æͼģʽµÄÒ»×é
    void Draw_Clean();  //½«»æͼģʽµÄ×éÈ«²¿Çå0 
    void Dis_string(u8 h,u8 *str,u8 w);   //ÏÔʾһ¸ö×Ö·û´®£¬´ø¸ßÁÁ¿ØÖÆ
    void Highlinght_line(u8 h,u8 w);   //½«Ä³Ò»ÐÐÎı¾Ëù¶ÔÓ¦µÄ»æͼÇø¸ßÁÁ»òÈ¡Ïû¸ßÁÁ
    void Highlinght_TextArea(u8 x,u8 y,u8 w);
    #endif
    实验部分12864液晶的程序还是跟原先的一样,有兴趣可以去阅读之前的文章,这里就不再赘述。我们重点看tlc0831.c驱动文件。程序是根据读取时序来的。

    首先在clk为0时,拉低cs。延时tsu,之后clk先拉高,再拉低。准备工作就做好了,现在开始读取8个位,从高到低。首先拉高clk,再拉低clk,读取第7位,并重复7次(总共8次)。最后便是在clk为0的时候,拉高cs便结束了。

    STC片内AD转换


    关于stc的片内ADC,主要有以下4点:

    (1)有8路10位的ADC。如上图P1口的8个引脚分别作为8路adc使用。10位也就是读取的数字量最大1023。

    (2)参考电压等于芯片的供电电压。

    (3)分辨率 5V/1023=0.00488V

    (4)使用过程:选择模拟输入通道,启动ADC转换,等待ADC转换完成,读取ADC结果。

    好了,现在我们要进行一个实验,实验是用温度传感器LM35来读取室内温度。我们选用P1.5作为温度传感器的输入,直接连接P1.5口到端子排P17的1脚即可。

    直接上程序吧(12864.c,12864.h同上,这里不再给出)。

    main.c

    #include "12864.h"
    #include "stc_adc.h"
    #include "filter.h"
    u16 ad5;
    float v5;
    float t;
    
    void main()
    {
    	LCD_Init();
    	Show_String(0x80,"stc_adc");
    	Stcadc_Init();
    	while(1)
    	{
    		ad5=Get_Adc();
    		v5=ad5*0.00488; //v
    		t=(v5*1000)/10;
    		Show_Number(0x90,ad5);
    		Show_Float(0x88,v5);
    		Show_Float(0x98,t);		
    	}
    }
    stc-adc.c

    #include "stc_adc.h"
    
    /*将P1.5 1.6 1.7配置成ADC的模拟信号输入口*/
    sfr P1M1=0x91;
    sfr P1M0=0x92;
    sfr P1ASF=0x9D;
    sfr ADC_CONTR=0XBC;
    sfr ADC_RES=0XBD;
    sfr ADC_RESL=0XBE;
    sfr AUXR1=0XA2;
    
    void Stcadc_Init()
    {
    	P1M1|=((1<<5)|(1<<6)|(1<<7));
    	P1M0&=~((1<<5)|(1<<6)|(1<<7)); //P1.5-P1.7输入模式
    	P1ASF=(1<<5)|(1<<6)|(1<<7);
    	ADC_CONTR=0XA0;	// 1010 0000
    	AUXR1|=(1<<2);	 //ADRJ=1
    }
    
    u16 Read_Stcadc(u8 ch) //读取STC单片机某一通道ADC的数字量
    {
    	u16 ad,temp;
    	ADC_CONTR=0xA0|ch;	 //ch~0-7|1010ccc 选择输入通道
    	delay(1);
    	ADC_CONTR|=(1<<3); // 启动ADC
    	while((ADC_CONTR&(1<<4))==0); //等待ADC转换完成
    	ADC_CONTR&=~(1<<4);//完成后置1
    
    	temp=ADC_RES;	 //读取ADC结果
    	temp<<=8;
    	ad=temp|ADC_RESL;
    
    	return ad;
    }
    
    
    stc-adc.h

    #ifndef _stc_adc_
    #define _stc_adc_
    
    #include "reg51.h"
    #define u8 unsigned char
    #define u16 unsigned int
    void delay(u16 x);
    void Stcadc_Init();
    u16 Read_Stcadc(u8 ch);
    
    #endif

    filter.c

    #include "filter.h"
    #include "stc_adc.h"
    
    void BubbleSort(u16 *arr, int n)
    {
         int i = 0, j =0;     
         for(i = 0; i < n; i++)
           for(j = 0; j < n - 1 - i; j++)
           {
                 if(arr[j] > arr[j + 1])
                 {
                           arr[j] = arr[j] ^ arr[j+1];
                           arr[j+1] = arr[j] ^ arr[j+1];
                           arr[j] = arr[j] ^ arr[j+1];
                 }             
           }     
    }
    
    
    u16 Get_Adc()  //获取当前真实的ADC值,具备抗干扰的能力
    {
    	#define count 10
    	xdata u16 Sam[count];
    	u16 ad;	
    	u8 i;
    	for(i=0;i<count;i++)
    	{
    		Sam[i]=Read_Stcadc(5);
    	}
    	BubbleSort(Sam, count);
    	
    	ad=0;
    	for(i=1;i<(count-1);i++)
    	{
    		ad+=Sam[i];
    	}
            ad=ad>>3;//右移动3位相当于 ad/8
    
    
    	return ad;
    
    }
    filter.h

    #ifndef _filter_
    #define _filter_
    
    #include "reg51.h"
    #define u8 unsigned char
    #define u16 unsigned int
    void delay(u16 x);
    
    u16 Get_Adc();
    void BubbleSort(int *arr, int n);
    
    #endif
    这里我们重点看看stc-adc.c驱动和filter.c滤波文件。驱动文件里,我们首先要声明各个寄存器的地址,因为A51启动文件没有这些寄存器的声明。初始化函数中,首先通过P1M1和P1M0设置P1.7,P1.6,P1.5位高阻输入口,其次再将P1ASF寄存器中对应p1.7-1.5置1,表示该3个通道最为AD使用。再将ADC-CONTR寄存器上电并选定中速360时钟周期转换一次,最后将AUXR1的第二位置1,表示转换结果低八位装在ADC-RESL中,剩余2位装在ADC-RES中,按低位开始右边对齐。读取函数中要先设置ADC-CONTR寄存器,选定输入通道5,延时,开启ADC转换。(具体请参考STC12C5A60S2数据手册)

    另外在filter.c中我们使用了平均值滤波法。滤波的好处是使读取的数值显示更加稳定,因为AD转换的分辨率为0.00488V,约为5mv,也就是只要有5mv的增加或减少,数字量便会加1或减1,我们知道传感器本身就是有很多干扰另外加上空气中电磁波干扰,数据会不停的跳动,这些都可以称为噪声。因此要滤波,即滤出噪声。我们这里的思路是每次取十个数字量,然后对其进行排序(排序的方法值得看看,采用异或操作),去除最小的和最大的,再求出剩余8个数的平均值,并将其作为最终的真实值。

    好了本文到此为止,多谢查看。资料上传有些不便,如果你需要,可以给我留言,留下你的邮箱,我会发给你需要的资料。有问题请及时联系。







    展开全文
  • 51单片机 AD转换

    万次阅读 多人点赞 2016-08-06 17:15:52
    在数逻的课程中,已经学习过AD转换的概念:将模拟信号采样、量化、编码后转换为数字信号。但是未学习过通过单片机编程,显示结果。 编码分有舍有入、只舍不入两种,量化误差前者更小。=2Vm/(2^n+1 - 1 ) 注意...
  • 关于单片机AD转换

    2020-07-19 09:18:44
    本文主要讲了一下关于单片机AD转换,希望对你的学习有所帮助。
  • 51单片机AD转换

    2020-07-30 23:31:53
    利用51单片机ad0809进行模数转换,其中比较电压利用单片机本身电源,而采样电压用滑动电阻输入。
  • 51单片机第六讲(AD/DA转换

    千次阅读 2018-02-06 14:14:50
    为使计算机系统能够了解外部世界,对外部事物进行处理,就必须有一个将模拟量转换为数字量,将数字量转换为模拟量的接口,这就是常说的 A/D和 D/A。 2.PCF8591t芯片 PCF8591 特性 • 单独供电 • PCF8591 的操作...
  • 51单片机AD转换的程序

    万次阅读 2017-12-26 13:39:29
    void Read_init ... unsigned char AD_FIN=0; //存储A/D转换标志   CHA &= 0x07; //选择ADC的8个接口中的一个(0000 0111 清0高5位)   ADC_CONTR = 0x40; //ADC转换的速度(0XX0 0000 
  • 单片机A/D采样的原理

    万次阅读 多人点赞 2017-09-11 20:55:41
    在A/D转换器中,因为输入的模拟信号在时间上式连续的,而输出的数字信号代码是离散的。所以A/D转换器在进行转换时,必须在一系列选定的瞬间(时间轴上的一些规定点上)对输入的模拟信号采样保持,然后再把这些采样值...
  • AD转换中参考电压的作用 .

    万次阅读 2012-08-25 11:33:26
    参考电压是这个样子的,假如你选择的参考电压是5v,你的ad是12位的,那么当你的输入电压是5v的时候你的单片机的显示应该是4095 ,如果是0v的输入那单片机里面的值就是0 ,中间点的值成线性关系,就是说假如你的输入...
  • 51单片机AD转换之PCF8591

    万次阅读 多人点赞 2015-12-15 09:55:16
    PCF8591是一个单片集成、单独供电、低功耗、8-bit CMOS数据获取器件。 1.引脚分析 PCF8591具有4个模拟输入(AIN0~AIN3)、1个模拟输出(AOUT)和1个串行I²C总线接口(SDA、SCL)。 PCF8591的3个地址引脚A0, A1...
  • stc单片机ad转换程序心得

    千次阅读 2013-05-18 23:18:58
    话说stc内部自带ad,但是功能多了!必然控制起来就啰嗦了!不像外部ad。stc如果不用中断ad方式需要注意一下几个问题: 1、在初始化ad的时候,一定要第一个给ad提供电源,即adc_power一定要第一个置1; 2、在每次对...
  • 用stc单片机内部ad采集多路交流信号,有两种办法: 一、用两个AD转换芯片,两路模拟量分别接一个。用单片机控制两个AD芯片同时启动转换,这样基本可以实现采集到同一时刻的两路模拟量值。 二、用两个采样保持器...
  • PIC单片机AD转换

    万次阅读 热门讨论 2015-07-23 16:34:14
    AD转换  我们先看看R1和R2,R2是个可调电阻 如果我们将R2变大 RA1这个管脚上的电压就越大。R2变小 RA1这个管脚上的电压就越小。那单片机是怎么知道电压变化的。这就需要AD转换。就是将模拟量转换成数字量。    ...
  • AD转换的理解

    千次阅读 2016-05-29 18:42:12
    自己学习的单片机也有一段时间了,刚开始接触单片机的时候,就总是强调AD单片机自带AD不,等一些说法,但是自己从来没有仔细想过AD的过程,只是知道是将模拟量转化为数字量,但是不知道这个采集过来的电压是2.5V,...
  • STC12C5A60S2 AD 转换详解

    万次阅读 2016-12-14 09:33:00
    STC系列单片机中的STC89LE516AD/X2提供了8路8位精度的高速A/D转换器,位于P1口上,从而省去了片外ADC的麻烦。这8路ADC为电压输入型,可做按键扫描,电池电压检测,频谱检测等。ADC转换过程需要17个机器周期。通过对...
  • AD和DA转换-第1季第16部分

    千人学习 2018-10-22 21:38:06
    本课程是《朱有鹏老师单片机完全学习系列课程》第1季第16个课程,主要讲解AD转换和DA转换。目标是理解模拟量和数字量的概念,并且学会使用AD转换来采集现实世界的模拟量。
  • 欢迎加入QQ电子交流群:658384577 项目下载 点击下载 1.电路图 2.程序 只在这里贴出主函数,其余的请点击上面(点击下载)进行下载,实在太麻烦。 主函数 #include<reg51.h>...code...
  • 单片机ad采样转换

    千次阅读 2013-02-01 15:52:50
     一个设计,要求显示电池电量,电源是充电电池,工作电压在4.4~5.4V中间,想做出和手机那样的效果,有4格的电量显示,用AD实现,AD转换的参考电压是随着电源电压的变化而变化的(Vref=VDD),如何检测成本最低?...
1 2 3 4 5 ... 20
收藏数 4,648
精华内容 1,859
关键字:

单片机ad转换