打印

基于51的数字电压表

[复制链接]
2361|5
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
mjg89|  楼主 | 2009-12-22 09:45 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式
按着电路搭的仿真能作用,可实际搭的时候却不能体现其功能,请给位帮帮忙(附有仿真图和原理图)
#include <reg51.h>
#include <intrins.h>
/*********************************端口定义**********************************/
sbit CS = P1^0;
sbit Clk = P1^1;
sbit DATI=P1^3;
sbit DATO = P1^2;
#define vref 2.35
/*******************************定义全局变量********************************/
unsigned char dat = 0x00;      //AD值
unsigned char count = 0x00;      //定时器计数
unsigned char CH;       //通道变量
unsigned char dis[] = {0x00, 0x00, 0x00};       //显示数值
/*******************************共阴LED段码表*******************************/
unsigned char code tab[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};
  //unsigned char code tab[]={0xc0,0xf9,0xa4,0Xb0,0x99,0x92,0x82,0xf8,0x80,0x90};
/****************************************************************************
函数功能:AD转换子程序
入口参数:CH (模拟输入通道)
出口参数:dat
****************************************************************************/
unsigned char adc0832(unsigned char CH)
{
      unsigned char i,test,adval;
  
  adval = 0x00;
  test = 0x00;
  
  Clk = 0;       //初始化
  DATI = 1;
  CS = 0;
  _nop_();
  Clk = 1;
  _nop_();
  Clk = 0;
   if ( CH == 0x00 )      //通道选择 (若自己的板子调试不出来,可能是这里的问题,即选择的模拟通道错了)
   {
  DATI = 1;      //通道0的第一位
  _nop_();
  Clk = 1;
  _nop_();
  Clk = 0;
  DATI = 0;      //通道0的第二位
  _nop_();
  Clk = 1;
  _nop_();
  Clk = 0;
    }
    else
    {
      DATI = 1;      //通道1的第一位
       _nop_();
       Clk = 1;
       _nop_();
      Clk = 0;
      DATI = 1;      //通道1的第二位
    _nop_();
     Clk = 1;
     _nop_();
  Clk = 0;
    }
    DATI = 1;

    for( i = 0;i < 8;i++ )      //读取前8位的值
    {
       _nop_();
       adval <<= 1;
       Clk = 1;
       _nop_();
       Clk = 0;  //CIK输入4个高电平了
       if (DATO)  //DATO数据输入;若DATO=1(高电位),则执行,反之,else
          {adval |= 0x01;}  //简写 本身其为:adval=adval 1 0xo1
      else
          {adval |= 0x00; }
    }

      for (i = 0; i < 8; i++)      //读取后8位的值
      {
           test >>= 1;  //右循环,反序输出。特点
           if (DATO)
              test |= 0x80;
           else
              test |= 0x00;
          _nop_();
          Clk = 1;   //停止使用芯片。
          _nop_();
          Clk = 0;
      }
      if (adval == test)      //比较前8位与后8位的值,如果不相同舍去。若一直出现显示为零,请将该行去掉
          {
     dat = test;
    }
      _nop_();
       CS = 1;        //释放ADC0832
       DATO = 1;
       Clk = 1;
      return dat;
}
/****************************************************************************
函数功能:延时子程序
入口参数:
出口参数:
****************************************************************************/
void delay(void)
{
    int k;
    for(k=0;k<500;k++);
}
/****************************************************************************
函数功能:将0-255级换算成0.00-5.00的电压数值
入口参数:i
出口参数:
****************************************************************************/
void convdata(unsigned char i)
{
//将2精制转化成数值
int j = (i*vref/255.0)*100; //放大100倍
    dis[0] = j/100;       //个位
    dis[1] = (j%100)/10;      //小数点后第一位
    dis[2] = (j%100)%10;     //小数点后第二位
}
/****************************************************************************
函数功能:数码管显示子程序
入口参数:
出口参数:
****************************************************************************/
void display(void) //(开发板上的位选是连接错的。不看.实际是0位是P2.4;1位是P2.5;2位是P2.6;3位是P2.7)
{
  P2=0xff;
   P0=tab[dis[0]] | 0x80;// P0=tab[dis[0]] & 0x7f;      //显示个位和小数点
  P2=0xef;
    delay();
P2=0xff;
    P0=tab[dis[1]];//P0=tab[dis[1]];       //显示小数点后第一位
   P2=0xdf;
    delay();
  P2=0xff;
    P0=tab[dis[2]];//P0=tab[dis[2]];       //显示小数点后第二位
    P2=0xbf;
    delay();
}
/****************************************************************************
函数功能:定时器中断延时程序 这一段的作用时隔一段时间抽样一次 否侧显示的最后一位会不稳定
入口参数:
出口参数:
****************************************************************************/
void timer0(void) interrupt 1
{
    TMOD = 0x01;   //工作方式,为16位的计数器
    TH0 = 0x00;  //作高位
    TL0 = 0x00;  //作低位
    IE = 0x82; //中断允许寄存器,用来选择允许或禁止那些中断(然后可以通过中断优先级寄存器IP,第一被允许中断的优先级)
      //IE=10000010 ,表示允许中断;允许T0中断。(具体IE结构看书)
    TR0 = 01; //应该默默地含有GATE=0,即允许T0计数。
    count++;
    if (count == 0x0A)
    {
       count = 0x00;
       dat = adc0832(CH);
    }
}

/****************************************************************************
函数功能:主程序
入口参数:
出口参数:
****************************************************************************/
void main(void)
{
  //while(1)
  //{
    P2=0x00;       //端口初始化
    P0=0xff;
P1=0X00;      
    CH = 0x00;       //在这里选择通道 0x00或0x01
           
     TMOD = 0x01;       //设置中断
    TH0 = 0x00;
    TL0 = 0x00;
     IE = 0x82;
    TR0 = 01;
    while(1)       //主循环
    {   
      convdata(dat);      //数据转换
       display();      //显示数值
    }
}

相关帖子

沙发
mjg89|  楼主 | 2009-12-22 09:53 | 只看该作者
所有线路连接时正确的,本人认为是AD转换程序出了问题。。但仿真又是正确的。让我疑惑不得解。

QQ截图.png (11.39 KB )

QQ截图.png

QQ截图未命.png (14.76 KB )

QQ截图未命.png

使用特权

评论回复
板凳
xushouxue999| | 2009-12-22 10:38 | 只看该作者
AD程序错了吧!好像你读了16位啊?按照时序图好像是:7,6,5,4,3,2,1,0,1,2,3,4,5,6,7吧!所以你前八位读到的是7—0,后八位读到的是1-6再加一个非数据位!
所以你前后两次的读数也即是adval , test如果能相等应该是偶然的吧!

使用特权

评论回复
地板
xushouxue999| | 2009-12-22 10:39 | 只看该作者
1-7

使用特权

评论回复
5
mjg89|  楼主 | 2009-12-22 12:23 | 只看该作者
怎样改过来呢?

使用特权

评论回复
6
xushouxue999| | 2009-12-22 15:15 | 只看该作者
呵呵,这应该不是个难事了吧!我都说的很清楚了!

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

5

主题

13

帖子

1

粉丝