用ADC0809实现八通道采集

不要白嫖,不要瞎抄程序,因为我在试图教会你
如果没有用过proteus 没关系,看这个教程新手快速上手proteus实现仿真画pcb

1.ADC0809的概述

ADC0809是美国国家半导体公司生产的CMOS工艺8通道,8位逐次逼近式A/D模数转换器。其内部有一个8通道多路开关,它可以根据地址码锁存译码后的信号,只选通8路模拟输入信号中的一个进行A/D转换。仅在单片机初学应用设计中较为常见。

1.1芯片特点
  1. 8路输入通道,8位A/D转换器,即分辨率为8位。
  2. 具有转换起停控制端。
  3. 转换时间为100μs(时钟为640KHz时),130μs(时钟为500KHz时)。
  4. 单个+5V电源供电。
  5. 模拟输入电压范围0~+5V,不需零点和满刻度校准。
  6. 工作温度范围为-40~+85摄氏度。
  7. 低功耗,约15mW。
1.2引脚介绍

ADC0809是CMOS单片型逐次逼近式A/D转换器,它由8路模拟开关、地址锁存与译码器、比较器、8位开关树型A/D转换器、逐次逼近寄存器、逻辑控制和定时电路组成。

  1. IN0~IN7:8路模拟量输入端。
  2. 2-1~2-8:8位数字量输出端。
  3. ADDA、ADDB、ADDC:3位地址输入线,用于选通8路模拟输入中的一路。
  4. ALE:地址锁存允许信号,输入端,产生一个正脉冲以锁存地址。
  5. START: A/D转换启动脉冲输入端,输入一个正脉冲(至少100ns宽)使其启动(脉冲上升沿使0809复位,下降沿启动A/D转换)。
  6. EOC: A/D转换结束信号,输出端,当A/D转换结束时,此端输出一个高电平(转换期间一直为低电平)。
  7. OE:数据输出允许信号,输入端,高电平有效。当A/D转换结束时,此端输入一个高电平,才能打开输出三态门,输出数字量。
  8. CLK:时钟脉冲输入端。时钟频率范围为10KHz-1280KHz。
  9. REF(+)、REF(-):基准电压。
  10. Vcc:电源,单一+5V。
  11. GND:地。
1.3工作过程

首先输入3位地址,并使ALE=1,将地址存入地址锁存器中。此地址经译码选通8路模拟输入之一到比较器。START上升沿将逐次逼近寄存器复位。下降沿启动 A/D转换,之后EOC输出信号变低,指示转换正在进行。直到A/D转换完成,EOC变为高电平,指示A/D转换结束,结果数据已存入锁存器,这个信号可用作中断申请。当OE输入高电平 时,输出三态门打开,转换结果的数字量输出到数据总线上。
转换数据的传送 A/D转换后得到的数据应及时传送给单片机进行处理。数据传送的关键问题是如何确认A/D转换的完成,因为只有确认完成后,才能进行传送。为此可采用下述三种方式。

(1)定时传送方式
对于一种A/D转换器来说,转换时间作为一项技术指标是已知的和固定的。例如ADC0809转换时间为128μs,相当于6MHz的MCS-51单片机共64个机器周期。可据此设计一个延时子程序,A/D转换启动后即调用此子程序,延迟时间一到,转换肯定已经完成了,接着就可进行数据传送。
(2)查询方式
A/D转换芯片有表明转换完成的状态信号,例如ADC0809的EOC端。因此可以用查询方式,测试EOC的状态,即可确认转换是否完成,并接着进行数据传送。
(3)中断方式
把表明转换完成的状态信号(EOC)作为中断请求信号,以中断方式进行数据传送。
不管使用上述哪种方式,只要一旦确定转换完成,即可通过指令进行数据传送。首先送出口地址并以信号有效时,OE信号即有效,把转换数据送上数据总线,供单片机接受。

2.使用原理图仿真

2.1实验仿真概述

我们要实现多通道采集,所以外部模拟量就通一些可变变阻或者电压源来代替模拟输入,我们显示数值使用lcd显示,再采用按键来切换通道,达到我们的目的。

2.2原理图

实验原理图

3.解析原理图

3.1晶振和复位模块

这边是可以保证单片机芯片运行的部分,有晶振机器保证以一定的Hz数正常运行。复位也是很重要的一环
晶振和复位

3.2模拟电压源部分

我们这块采用了可调的滑动变阻器来模拟电压源,为清楚的看到电压值的差别,我们特意加了电压表来显示数值和lcd显示的数值来对比,比较显示误差

电压源
电压表

3.3lcd显示部分

我们lcd显示就是可以显示的东西能多一点比如可以显示一些字母注释,可以更清楚的看到数值。但是需要注意的是连接P0口的时候一定要加上拉电阻。加一个排阻也是一个不错的选择

lcd模块

首先要有定义的引脚和一些定义的字符串数组

sbit RS=P1^3;         
sbit RW=P1^4;         
sbit E=P1^5;
sbit BF =P0^7;

sbit key1= P1^6;
sbit key2= P1^7;

unsigned char code Str[]={"Vorlt="}; 
unsigned char code digit[10]={"0123456789"};   //定义字符数组显示数字

其次就是lcd的显示函数,对其进行了封装,只需要一开始进行初始化就行,然后调用display(x)函数就可以在指定要位置写上数字,也有一些写字符串符号小数点的函数,调用即可。

bit BusyTest(void)
  {
    bit result;
    RS=0;       //根据规定,RS为低电平,RW为高电平时,可以读状态
    RW=1;
    E=1;        //E=1,才允许读写
    _nop_();     
    _nop_();   //空操作两个机器周期,给硬件反应时间 
    result=BF;  //将忙碌标志电平赋给result
    E=0;         //将E恢复低电平
   return result;
  }
//函数功能:将模式设置指令或显示地址写入液晶模块   入口参数:dictate
void WriteInstruction (unsigned char dictate)
{   
    while(BusyTest()==1);   //如果忙就等待
  RS=0;                  //根据规定,RS和R/W同时为低电平时,可以写入指令
  RW=0;   
  E=0;                   //E置低电平(根据表8-6,写指令时,E为高脉冲,                          // 就是让E从0到1发生正跳变,所以应先置"0"
  _nop_();
  _nop_();               //空操作两个机器周期,给硬件反应时间
  P0=dictate;            //将数据送入P0口,即写入指令或地址
  _nop_();
  _nop_();               //空操作两个机器周期,给硬件反应时间
  E=1;                   //E置高电平
  _nop_();
  _nop_();               //空操作两个机器周期,给硬件反应时间
   E=0;                  //当E由高电平跳变成低电平时,液晶模块开始执行命令
 }
//函数功能:指定字符显示的实际地址   入口参数:x
 void WriteAddress(unsigned char x)
 {
     WriteInstruction(x|0x80); //显示位置的确定方法规定为"80H+地址码x"
 }
//函数功能:将数据(字符的标准ASCII码)写入液晶模块   入口参数:y(为字符常量)
 void WriteData(unsigned char y)
 {
    while(BusyTest()==1);  
   RS=1;           //RS为高电平,RW为低电平时,可以写入数据
   RW=0;
   E=0;            //E置低电平(根据表8-6,写指令时,E为高脉冲,
                     // 就是让E从0到1发生正跳变,所以应先置"0"
   P0=y;           //将数据送入P0口,即将数据写入液晶模块
   _nop_();
     _nop_();       //空操作四个机器周期,给硬件反应时间
   E=1;           //E置高电平
   _nop_(); 
  _nop_();        //空操作四个机器周期,给硬件反应时间
  E=0;            //当E由高电平跳变成低电平时,液晶模块开始执行命令
 }
//函数功能:对LCD的显示模式进行初始化设置
void LcdInitiate(void)
{
   	 delaynms(15);               //延时15ms,首次写指令时应给LCD一段较长的反应时间
   	 WriteInstruction(0x38);     //显示模式设置:16×2显示,5×7点阵,8位数据接口
	 delaynms(5);                //延时5ms ,给硬件一点反应时间
  	  WriteInstruction(0x38);
	 delaynms(5);               //延时5ms ,给硬件一点反应时间
	 WriteInstruction(0x38);     //连续三次,确保初始化成功
	 delaynms(5);               //延时5ms ,给硬件一点反应时间
	 WriteInstruction(0x0c);     //显示模式设置:显示开,无光标,光标不闪烁
	 delaynms(5);               //延时5ms ,给硬件一点反应时间
	 WriteInstruction(0x06);     //显示模式设置:光标右移,字符不移
	 delaynms(5);                //延时5ms ,给硬件一点反应时间
	 WriteInstruction(0x01);     //清屏幕指令,将以前的显示内容清除
	 delaynms(5);             //延时5ms ,给硬件一点反应时间
 }

//函数功能:显示电压符号 
void display_volt(void)
 {
    unsigned char i;
  WriteAddress(0x00);    //写显示地址,将在第2行第1列开始显示
  i = 0;                //从第一个字符开始显示
  while(Str[i] != '\0')  //只要没有写到结束标志,就继续写
   {      
   WriteData(Str[i]);   //将字符常量写入LCD
   i++;                 //指向下一个字符    
  } 
}
//函数功能:显示电压的小数点 
void  display_dot(void)
{         
  WriteAddress(0x08);   //写显示地址,将在第1行第10列开始显示     
  WriteData('.');       //将小数点的字符常量写入LCD  
}
//函数功能:显示电压的单位(V) 
void  display_V(void)
{
    WriteAddress(0x0b); //写显示地址,将在第2行第13列开始显示 
    WriteData('v');   
}
//函数功能:显示电压的整数部分    入口参数:x
void display1(unsigned char x)
{
 WriteAddress(0x07);    //写显示地址,将在第2行第7列开始显示
 WriteData(digit[x]);    //将百位数字的字符常量写入LCD
 }
//函数功能:显示电压的小数数部分    入口参数:x
 void display2(unsigned char x)
{
  unsigned char i,j;
 i=x/10;            //取十位(小数点后第一位)
 j=x%10;            //取个位(小数点后第二位)
   WriteAddress(0x09);      //写显示地址,将在第1行第11列开始显示
 WriteData(digit[i]);     //将小数部分的第一位数字字符常量写入LCD
     WriteAddress(0x0a);
 WriteData(digit[j]);     //将小数部分的第一位数字字符常量写入LCD
}

3.4ADC0809模块

这就是本次采集的核心部分,利用多通道的输入去实现多通道的采集,因为采集是要把模拟量转换为数字量的过程。所以需要对out口的传输到单片机芯片的数字量进行处理显示。但是这里有一个要注意的点就是out1是高位,而out7是地位,也就是说在连接口引脚的时候iuot7对应的是p2.0低位口。在仿真的时候由于proteus中没有ADC0809的moudle ,在运行时报错,我们就用一个功能几乎一样的ADC0808来代替仿真。

ADC0809

这块也是要先定义它的引脚和变量,进行全局定义

unsigned char dat,results,n;
sbit CLK=P3^3;
sbit A_C=P1^2;
sbit A_B=P1^1;
sbit A_A=P1^0;
sbit EOC = P3^1;
sbit OE = P3^0;
sbit START = P3^2 ;
//初始化ad
void InitUart(void)
{
   SCON=0x50;  //设置中断模式
   TMOD=0x22;
   PCON=0x00;
   TL1=0xfd;
   TH1=0xfd;
   TI=1;
   TR1 =1;
   n=0;
}
//定时器中断
void Timer0_INT() interrupt 1
{
   CLK =!CLK;
}
3.5按键模块

按键的主要作用就是切换通道进行通道选择。

按键

首先就得定义按键。然后将按键选择的函数进行封装,减少主函数中的代码量就可以更加清楚的观察到主函数的功能。

sbit key1= P1^6;
sbit key2= P1^7;
void Choose(unsigned char x)
{
   switch(x){
    case 0:   A_A=0; A_B=0; A_C=0;      break  ;
    case 1:   A_A=1; A_B=0; A_C=0;      break  ;
    case 2:   A_A=0; A_B=1; A_C=0;      break  ;
    case 3:   A_A=1; A_B=1; A_C=0;      break  ;
    case 4:   A_A=0; A_B=0; A_C=1;      break  ;
    case 5:   A_A=1; A_B=0; A_C=1;      break  ;
    case 6:   A_A=0; A_B=1; A_C=1;      break  ;
    case 7:   A_A=1; A_B=1; A_C=1;      break  ;
   }
} 

4.实验程序

前面是每部分的概述和程序的实现,主程序才是对这些模块封装的函数的调用和使用。去实现我们想要的功能。

void main(void)
 { 
  	unsigned char Int,Dec; 
     LcdInitiate();         //将液晶初始化
    InitUart();
    TH0 = 0x14;
    TL0 = 0x00;
    ET0 =1;TR0 =1 ; EA =1 ;
    while(1)
    {
       delaynms(5);
		Choose(n); //选择通道     
      START=0;     
      START=1;
      START=0;//当低电平来时开始读取数据
      while(EOC==0);
      	OE=1;
     	dat=P2; //将数据赋给P2
     	 OE=0;       
	 display_volt();  //显示电压字符串
	 Int = dat/51;
	 Dec = (dat-Int*51)*100 /51 ;    //处理数据
	 display1(Int);  
	 display_dot();//分别显示个位和小数位和小数点
	 display2(Dec);
	 display_V();  //显示电压值符号         
       if(key1==0)
       {
	 	 delay1ms(); //消抖
	 	 if(key1==0)
	 	 {
	     	n++;   //通道++
	 	 }
	  	while(!key1);
	}
      if(key2==0)
       {
	  		delay1ms();//消抖
	  		if(key2==0)
	 		 {
	    		 n--;  //通道--
	 		 }
	  while(!key2);
	}
 }            
}

5仿真结果

基本完成所需要的功能,成功实现模拟信号的多路采集
实验结果

6PCB的绘制

说实话没有专业的训练,只能凑活画出来,虽然很丑但是没有错误就很不错
PCB

7实验总结

本次实验使用ADC0809模拟了八通道模拟量的采集的过程,我们使用了电压源来模拟通道输入,利用AD转换成数字量,再到lcd上进行显示的一个过程,我们实现了按键切换通道的功能,了解熟悉了ADC0809芯片的使用,如何去完成的数据的转换和采集。更多的让我们可以在软件上实现对硬件的编程的使用。让书上的原理得到实践和验证。

  • 67
    点赞
  • 332
    收藏
    觉得还不错? 一键收藏
  • 25
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 25
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值