找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 1891|回复: 2
打印 上一主题 下一主题
收起左侧

Protues 仿真51单片机 用AT24C2数据不保存

[复制链接]
跳转到指定楼层
楼主
本帖最后由 pull1121 于 2020-2-22 11:00 编辑

Protues 仿真51单片机 用AT24C2数据不保存,重启后,数据归零。
假如 数码管上显示 XX,(XX为任意数)重新上电后数码管变成 00效果图:如下

#include <reg51.h>
#include <intrins.h>
#define uint unsigned int
#define uchar unsigned char
uchar code table[]={         //数码管显示0到F
0x3f,0x06,0x5b,0x4f,
0x66,0x6d,0x7d,0x07,
0x7f,0x6f,0x77,0x7c,
0x39,0x5e,0x79,0x71};
sbit dula=P2^6;
sbit wela=P2^7;
sbit SDA=P2^0;
sbit SCL=P2^1;
bit write=0;

uchar sec,num1;

void delay(uint cc) //ms级别的延时
        {
                uint aa,bb;
                for(aa=cc;aa>0;aa--)
                        for(bb=110;bb>0;bb--);
        }
void delay_ws()          //ns级别的延时
        {
                _nop_();
                _nop_();
                _nop_();
                _nop_();
                _nop_();
        }

void display(uchar bai_c,uchar sh_c)
        {
        
                //shi=flag/10;
                //ge=flag%10;

                P0=0x00;
                dula=1;
                P0=table[bai_c];
                dula=0;
                P0=0xff;
                wela=1;
                P0=0x7e;
                wela=0;
                delay(5);

                P0=0x00;
                dula=1;
                P0=table[sh_c];
                dula=0;
                P0=0xff;
                wela=1;
                P0=0x7d;
                wela=0;
                delay(5);
        }
void init ()
        {
        /*        TMOD=0x11;                //T0定时器初始化
                TH0=(65536-45872)/256;
                TL0=(65536-45872)%256;
                TR0=1;
                ET0=1;
                EA=1;
   */
                SCL=1;                  //I2C的2条总线初始化
                delay_ws();
                SDA=1;
                delay_ws();
        }
void start()   //单片机开始写信号
        {                   //严格按照时序图来写,SCK=1时候,SDA从1到0,一个下降沿表示开始
                SDA=1;
                delay_ws();
                SCL=1;
                delay_ws();
                SDA=0;
                delay_ws();
                SCL=0;           //等待下一步开始 写数据 或者 读数据
                delay_ws();
        }
void respons()           //从机应答信号
        {                           //严格按照时序图来写
                uchar i=0;
                SCL=1;
                delay_ws();
                while((SDA==1)&&(i<255))  // SDA=0时候表示应答,或者等待一下无应答
                        i++;                                  // 都表示结束
                SCL=0;
                delay_ws();
        }
void stop()                   //单片机结束写信号
        {                           //严格按照时序图来写,SCK=1时候,SDA从0到1,一个上升沿表示结束
                SDA=0;
                delay_ws();
                SCL=1;
                delay_ws();
                SDA=1;
                delay_ws();
        }
void write_byte(uchar date)//单片机写一个字节信号,从1个字节的最高位到最低位依次写入
        {                                           //和读数据一样 最高到最低
                uchar i,temp;
                temp=date;
                for(i=0;i<8;i++)                   //将date的最高位到最低位依次赋给SDA
                        {
                                temp=temp<<1;          //将数据 date 最高位右移一位赋给变量 temp
                                SCL=0;
                                delay_ws();
                                SDA=CY;                          //变量 temp移出来的一位通过PSW寄存器的CY位赋给SDA
                                delay(5);
                                SCL=1;                          //SDA数据的变化 需要SCK从0到1变化
                                delay_ws();
                        }
                        SCL=0;        //等待下次sda上数据变化,个人理解是等待从机相应
                        delay_ws();
                        SDA=1;         //释放数据总线
                        delay_ws();               
        }
uchar read_byte()//单片机读一个字节信号,从1个字节的最高位到最低位依次读出
        {                         //此子函数带返回值 return k
                uchar i,k;
                SCL=0;          //置0,等待SDA上的数据被读取
                delay_ws();
                SDA=1;          //置1,释放SDA,等待SDA上的数据被读取
                delay_ws();
                for(i=0;i<8;i++)
                        {
                                SCL=1;                 //SCL从0到1,SDA上的一个字节数据被依次放入返回值 k
                                delay_ws();
                                k=(k<<1)|SDA; //将第一位SDA数据置于最高位,k0 | X(0或者1)
                                                          // 0|X都为X,所以将第一位SDA的数据置于K的最高位
                                                          //然后依次循环8次,将SDA从最高位放到最低位
                                SCL=0;                                                
                                delay_ws();         
                        }
               
                        return k; //SDA上的数据从第一位到第八位依次放入K的最高位到最低位
        }
void write_add(uchar address,uchar date) //从E2Prom任意地址写任意数据
        {
                start();                        //开始信号
                write_byte(0xa0);        // 1010 0000 单片机发地址,在I2C上面找
                                                        // 设备(低4位前3位代表设备地址000,后1位的0代表方向主机到从机)
                respons();                        // E2Prom设备应答
                write_byte(address); //        从E2Prom设备的address地址开始写数据
                respons();                        // E2Prom设备应答
                write_byte(date);        //给E2Prom设备开始写数据 date
                respons();                        // E2Prom设备应答
                stop();                                //停止
        }                        //从E2Prom任意地址写任意数据的流程是:1.开始 2.设备地址
                                //3.被寻址的设备应答 4.给被寻址的设备要写数据的位置
                                //5.被寻址的设备应答 6.给被寻址的设备写数据
                                //7.应答 8.停止
uchar read_add(uchar address)         //从E2Prom任意地址读任意数据
        {
                uchar date;
                start();                   //开始信号
                write_byte(0xa0);  // 1010 0000 单片机发地址,在I2C上面找
                                   //设备(低4位前3位代表设备地址000,后1位的0代表方向主机到从机)
                respons();
                write_byte(address);//从E2Prom设备的address地址开始读数据
                respons();                        // E2Prom设备应答

                start();                   //开始信号
                write_byte(0xa1);  // 1010 0001 单片机发地址,在I2C上面找
                                                   // 设备(低4位前3位代表设备地址000,后1位的1代表方向从机到主机)
                respons();                   // E2Prom设备应答
                date=read_byte();  //把读到的数据赋给date
                stop();                           //停止
                return date;           //返回读到的数据 date
        }
                                
                                 //从E2Prom任意地址读数据的流程是:1.开始 2.设备地址(主机到从机)
                                //3.被寻址的设备应答 4.给被寻址的设备要读数据的位置
                                //5.开始 6. 设备地址(从机到主机)7.被寻址的设备应答
                                //8.从被寻址的设备读数据赋给date  9.停止 10.将date返回
                        



void Time0 ()         interrupt 1         //T0中断子函数
        {
                TH0=(65536-45872)/256; //频率为11.0592MHZ下的 高8位 初值
                TL0=(65536-45872)%256; //频率为11.0592MHZ下的 低8位 初值
                num1++;        //每50ms加一次
                if(num1==20) //T0计满20次(1秒)时
                        {
                                num1=0;         //清零,继续计数
                                sec++;         //数码管上的数1s加一次
                                write=1; //一秒写一次AT24C02(E2PROM)
                                if(sec==100)//如果计时到了100S就重新计时
                                        sec=0;         //清零

                        }
        }

void main()
        {
                   init(); //初始化        ,其实就是SDA和SCL释放
                   sec=read_add(2);//读出保存的数据赋给sec
                   if(sec>99)//读出的E2PROM如果大于99,只有2位数码管显示最多显示2位数
                           sec=0;         //清零
                        TMOD=0x01;//设置T0定时器工作方式为1
                        TH0=(65536-45872)/256; //频率为11.0592MHZ下的 高8位 初值
                        TL0=(65536-45872)%256; //频率为11.0592MHZ下的 低8位 初值
                        TR0=1; //T0的运行位打开,开始计时
                        ET0=1; //T0中断打开
                        EA=1;  //总中断打开
                   while(1)
                           {
                                display(sec/10,sec%10);        //将数sec显示在数码管上
                                if(write==1) //判断计时器是否计时1S
                                {
                                        write=0; //清零
                                        write_add(2,sec);//在E2PROM的列地址2中写入数据sec
                                        delay(5);
                                }
                        }

        }


video_20200222105900[00_00_08--00_00_22].gif (156.85 KB, 下载次数: 53)

效果图

效果图
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享淘帖 顶 踩
回复

使用道具 举报

沙发
ID:535242 发表于 2020-2-22 12:13 | 只看该作者
问题已经找到,Protues里面的AT24C02的SDA和SCL连到P2口连反了,更改过来就可以了
回复

使用道具 举报

板凳
ID:679425 发表于 2020-2-22 13:04 | 只看该作者
Protues里面的AT24C02接线需要注意,管脚太多不好整
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

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