电子技术论坛

 找回密码
 快速注册

QQ登录

只需一步,快速开始

搜索
下载方法|用单线程|避免多扣帖子规范|求助必读|发帖建议积分策略|勋章介绍|新人必读获取金币|推广论坛|出售帖子基本礼节|致会员信|版规总则
禁涉政治|反对低俗|举报专帖征集相片|留下足迹|推荐精华上传附件|制作分卷|使用网盘禁发qq群|恶意灌水|纯表情帖加入团队|监督机制|安全上网
查看: 2625|回复: 4

分享一个51单片机24C02和数码管动态扫描实验程序

[复制链接]
发表于 2019-5-17 15:22:15 | 显示全部楼层 |阅读模式

注册家电维修技术论坛,与同行畅聊维修技术,享更多技术论坛功能。

您需要 登录 才可以下载或查看,没有帐号?快速注册

x

/*开机倒计时读秒到0后数码管加1,倒计时可设置并保存,倒计时设置限定5~100,
数码管实时保存,下一次开机读秒后从上一次的数码管数字继续加1,9999后清零*/
#include <STC89C5xRC.H>
#include <intrins.h>
#define uint unsigned int
#define uchar unsigned char
sbit SDA=P2^7;
sbit SCL=P2^6;        //24C02数据线和时钟线
sbit w1=P3^4;
sbit w2=P3^5;
sbit w3=P3^7;
sbit w4=P3^6;   //数码管4个位选
sbit she=P1^0;
sbit jia=P1^1;
sbit jian=P1^2;
sbit ok=P1^3;         //设置,加,减,确定(取消)
uchar cc,ge,shi,bai,qian,time,a22,a33,a44,dc;
bit fa,ya,key,s0;
uchar code table[ ]={0xc0,0xf9,0xa4,0xb0,0x99,
                     0x92,0x82,0xf8,0x80,0x90 };  //共阳0~9段码
void delay(uint z)         //1ms延时
    {
         uint x,y;
         for(x=z;x>0;x--)
             for(y=114;y>0;y--);
        }
void start( )          //启动IIC总线
        {
          SDA=1;       //发送起始条件的数据信号
          _nop_( );
          SCL=1;
          _nop_( );    //起始条件建立时间大于4.7us,延时
          _nop_( );
          _nop_( );
          _nop_( );
          _nop_( );   
          SDA=0;       //发送起始信号
          _nop_( );    //起始条件锁定时间大于4μ
          _nop_( );
          _nop_( );
          _nop_( );
          _nop_( );      
          SCL=0;    //钳住I2C总线,准备发送或接收数据
          _nop_( );
          _nop_( );                        //SCL置低,准备接收或发送数据
        }
void stop( )                   //停止IIC总线
        {
          SDA=0;           //发送结束条件的数据信号
          _nop_( );        //发送结束条件的时钟信号
          SCL=1;           //结束条件建立时间大于4μ
          _nop_( );
          _nop_( );
          _nop_( );
          _nop_( );
          _nop_( );
          SDA=1;            //发送I2C总线结束信号
          _nop_( );
          _nop_( );
          _nop_( );
          _nop_( );        //延时保持4.7US以上
        }
void write(uchar a)                         //传送一个字节8位数据
        {
         uchar b,shu;
         for(b=0;b<8;b++)           //要传送的数据长度为8位
            {
              shu=a<<b;             //把即将发送的数据的为移到最高位
              if((shu&0x80)!=0)                //判断最高位是否为0
                        SDA=1;                        //不等于0说明最明当前要发送的数据为1
              else  SDA=0;          //否则数据为0     
             SCL=1;                 //置时钟线为高,通知被控器开始接收数据位
              _nop_( );
              _nop_( );             //保证时钟高电平周期大于4μ
              _nop_( );
              _nop_( );
              _nop_( );         
              SCL=0;
            }
        _nop_( );
            SDA=1;               //8位发送完后释放数据线,准备接收应答位
            _nop_( );   
            SCL=1;
            _nop_( );
        }
bit ack( )                                         //等待应答函数
        {
         bit h;
         SDA=1;
         _nop_( );
         SCL=1;                                        //SDA和SCL全部置高
         _nop_( );
         _nop_( );
         _nop_( );
         _nop_( );
         SCL=0;                                  //等待4.7US以上,把SCL置低
         _nop_( );
         _nop_( );
         _nop_( );
         _nop_( );
         h=SDA;                                 //等待4.7SU以上读取SDA应答信号
         return        h;                         //应答成功则是0,没有应答则是1
        }
uchar reade( )                          //接收一个字节8位数据
        {
         uchar d,g;
         SDA=1;                                  //数据线置高电平
         for(d=0;d<8;d++)
                 {
                  _nop_( );
                  _nop_( );
                  SCL=0;
                  _nop_( );
                  _nop_( );
                  _nop_( );
                  _nop_( );                 //SCL低电平,数据变化
                  SCL=1;                 
                  _nop_( );
                  _nop_( );                 //SCL高电平,数据稳定
                  if(SDA==1)
                    g=(g<<1)|0x01; //如果读到的数据是1就是最低位置1
                  else
                    g=g<<1;                //否则读到是0,直接左移1位(左移后右补0)
                }
          return g;                 //经过8次读取移位,把g返回
        }
void fasong(uchar add , uchar tab)          //指定地址发送一个字节
        {
          start( );                  //启动总线
          write(0xa0);          //器件地址(发送)
      ack( );              //等待应答
          write(add);     //发送器件内部地址
      ack( );                  //等待应答
          write(tab);          //发送数据
          ack( );                  //等待应答
          stop( );
        }
uchar jieshou(uchar add)        //指定地址接收一个字节
        {
          uchar shu;
          start( );                //读取(开始-器件地址(发)- 器件内部地址 - 开始 - 器件地址(收)- 接收数据 -发应答或停止接收
          write(0xa0);
          ack( );
          write(add);
          ack( );
          start( );
          write(0xa1);
          ack( );
          shu=reade( );
          stop( );
          return shu;
        }
void display(uchar a , uchar b , uchar c , uchar d)           //数码管显示函数
        {
         if(a!=0)                   //最高位不为0则显示千位
                 {
                 w1=0;
                 P0=table[a];
                 delay(5);
                 P0=0XFF;
                 w1=1;
                }
         if(a!=0||b!=0)                //千位或者百位不为0则显示百位(如1024这种百位是0)
                 {
                 w2=0;
                 P0=table[b];
                 delay(5);
                 P0=0XFF;
                 w2=1;
                }
         if(a!=0||b!=0||c!=0)        //千位或者百位或者十位不为0则显示十位
                 {
                 w3=0;
                 P0=table[c];
                 delay(5);
                 P0=0XFF;
                 w3=1;
                }
         w4=0;                                 //个位始终显示
     P0=table[d];
         delay(5);
         P0=0XFF;
         w4=1;
        }
void main( )
        {
          w1=w2=w3=w4=1;          //初始化位选
          ge=jieshou(0x03);           //接收个位
          shi=jieshou(0x04);   //接收十位
          bai=jieshou(0x05);   //接收百位
          qian=jieshou(0x06);  //接收千位
          time=jieshou(0x07);  //接收读秒时间
          fasong(0x07,time);   //把时间再存回去
          a22=time%1000/100;                                                 
          a33=time%100/10;
          a44=time%10;                   //分离出读秒的个十百(读秒最大100,没有千位)
          EA=1;
          ET0=1;
          ET1=1;
          TMOD=0X11;
          TH0=0X3C;
          TL0=0XB0;
          TH1=0X3C;
          TL1=0XB0;
          TR1=1;                         //配置定时器0和1,启动定时器1
          while(1)
          {
                   display(0,a22,a33,a44);        //读秒显示
                while(ya==1)         //ya默认是0,读秒结束后定时器1把ya置1,进入数字++显示
                        {
                  display(qian,bai,shi,ge);         //显示数字
                         if(fa==1)         //定时器0标记数字有变化,需要进行保存
                         {
                                           fa=0;
                                           fasong(0x03,ge);         //存个位
                                           display(qian,bai,shi,ge);
                                           fasong(0x04,shi);
                                           display(qian,bai,shi,ge);
                                           fasong(0x05,bai);
                                           display(qian,bai,shi,ge); //由于存4次时间较长,数码管会闪烁,插入数码管显示函数
                                           fasong(0x06,qian);
                                   }
                          if(she==0&&key==0)         //数字++时,按下设置键,暂停加,再按一次恢复加
                                  {
                                 delay(5);
                                 if(she==0)
                                         {
                                         s0=~s0;
                                         key=1;
                                          TR0=~TR0;
                                    }
                                }
                           if(ok==0&&key==0&&s0==1)         //设置有效时,ok键把数字清零
                              {
                                   delay(5);
                                   if(ok==0)
                                             {
                                           key=1;
                                           s0=0;
                                           time=0;
                                           qian=bai=shi=ge=0;  //更新个十百千
                                           fasong(0x03,0);
                                           fasong(0x04,0);
                                           fasong(0x05,0);
                                           fasong(0x06,0);          //更新EEPROM,直接给实参就行
                                           display(0,0,0,0);  // 显示出来,并启动定时器0
                                           TR0=1;
                                          }
                                  }
                           if(key==1)                                 //松手检测
                              {
                                   if(she==1&&ok==1)
                                      {
                                           delay(5);
                                           if(she==1&&ok==1)
                                                     key=0;
                                          }
                                  }       
                         }
                if(she==0&&key==0)                          //读秒设置,暂停读秒,再按一次恢复读秒
                        {
                         delay(5);
                         if(she==0)
                                 {
                                 TR1=~TR1;
                                 s0=~s0;
                                 key=1;
                                 time=jieshou(0x07);
                                 fasong(0x07,time);
                                 a22=time%1000/100;
                               a33=time%100/10;
                                   a44=time%10;
                                }
                        }
                if(jia==0&&key==0&&s0==1)                //读秒设置++
                        {
                        delay(5);
                        if(jia==0)
                                {
                                 uchar sa;
                                 key=1;
                                 sa=time;
                                 sa++;
                                 if(sa>100)                  //限定读秒上限100
                                         sa=5;
                                 time=sa;
                                 fasong(0x07,sa);        //加一次保存一次
                                 a22=time%1000/100;
                               a33=time%100/10;
                                   a44=time%10;
                                }
                        }
                 if(jian==0&&key==0&&s0==1)                 //读秒设置--
                         {
                         delay(5);
                         if(jian==0)
                                 {
                                 uchar sb;
                                 key=1;
                                 sb=time;
                                 sb--;
                                 if(sb<5)                        //限定读秒下限5
                                         sb=100;
                                 time=sb;
                                 fasong(0x07,sb);        //减一次保存一次
                                 a22=time%1000/100;
                               a33=time%100/10;
                                   a44=time%10;
                                }
                        }
                if(key==1)                                //松手检测
                        {
                        if(she==1&&jia==1&&jian==1)
                                {
                                 delay(5);
                                 if(she==1&&jia==1&&jian==1)
                                          key=0;
                                }
                     }
          }
        }
void aa( ) interrupt 1                  //定时器0负责数字++
        {
         TH0=0X3c;
         TL0=0Xb0;
         cc++;
         if(cc==10)
                 {
                 fa=1;
                 cc=0;
                 ge++;
                 if(ge==10)
                         {
                           ge=0;
                          shi++;
                          if(shi==10)
                                  {
                                 shi=0;
                                 bai++;
                                 if(bai==10)
                                         {
                                         bai=0;
                                         qian++;
                                         if(qian==10)
                                                 {
                                                 qian=0;
                                                }
                                        }
                                }
                        }
                }
        }
void bb( ) interrupt 3                //定时器1负责读秒--
        {
         TH1=0X3c;
         TL1=0Xb0;
         dc++;
         if(dc==20)
                 {
                 dc=0;
                 time--;
                 if(time<=0)
                    {
                    ya=1;
                        TR1=0;
                        TR0=1;
                        }
                  a22=time%1000/100;
              a33=time%100/10;
                  a44=time%10;
                }
        }

评分

参与人数 1威望 +8 收起 理由
wangji + 8 谢谢分享,家电维修论坛有您更精彩!.

查看全部评分

 楼主| 发表于 2019-5-17 15:31:47 | 显示全部楼层
程序是我自己写的,实验一切正常,但是也有两个地方不明白,一个是24C02如果同一个地址保存的数据只进行读操作,多读几次就会出错了,比如开机延时读秒的数据,假定是50,第一次开机读出来是50,第二次开机再读还是50,第三次也许还是50,第四次开机读出来的就不一定是50了,有可能是其它数了,为了保证数据不会出错,程序上不得以读出来以后又把数立马存回去以保证下一次读取正确。
再一个是中断服务函数里如果调用display()函数会有警告,不知道为什么
希望有知道的师傅能解答一下
发表于 2019-5-17 16:03:10 | 显示全部楼层
希望有知道的师傅能解答一下,

去加入 51黑电子论坛, 专研究单片。
发表于 2019-5-17 18:13:36 | 显示全部楼层
本帖最后由 wangji 于 2019-5-17 18:15 编辑
欧阳云天 发表于 2019-5-17 15:31
程序是我自己写的,实验一切正常,但是也有两个地方不明白,一个是24C02如果同一个地址保存的数据只进行读 ...


建议用示波器抓读写时序,COLCK DATA 上拉电阻用1.5K的。
您需要登录后才可以回帖 登录 | 快速注册

本版积分规则

手机版|家电维修技术论坛 ( 鄂ICP备09003585号-2 )

GMT+8, 2024-11-22 04:52 , Processed in 0.071604 second(s), 4 queries , Gzip On, MemCache On.

Powered by Discuz! X3.4

Copyright © 2001-2020, Tencent Cloud.

CopyRight © 电子技术论坛
电子邮箱:8794149@qq.com | 联系 QQ:3081868839 | 官方网址:www.dzdu.com

Qiji. All Rights Reserved


服务条款 | 站长声明

Wuhan Qiji Technology Co., Ltd.武汉奇迹科技有限公司版权所有


鄂ICP备09003585号-2鄂公网安备42010602000420号

快速回复 返回顶部 返回列表