找回密码
 立即注册

QQ登录

只需一步,快速开始

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

一个掉电保护的问题。

[复制链接]
跳转到指定楼层
楼主
ID:86324 发表于 2015-7-21 09:36 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
这个题目是:用定时器以0.01秒间隔计数,数码管显示从0~9999。与此同时独立键盘,按下k1后开始计数,按下k2停止计数并保持原数,按下k3数字+1,按下k4数字-1.且掉电后数据写入24c02,上电后读出原来的数字。现在的问题是,掉电后再上电就不是原来的数字,总是有偏差,求哪位大神帮我看看,万分感谢!!
我的单片机有8个数码管,且独立键盘是P3.0~P3.3,你们看的时候注意一下,谢谢。
下面是程序

............................................................................................................................................................................................................................................

.#include<reg52.h>
#include<intrins.h>
#define uint unsigned int
#define uchar unsigned char
uchar code table[]={
0x3f,0x06,0x5b,0x4f,
0x66,0x6d,0x7d,0x07,
0x7f,0x6f,0x77,0x7c,
0x39,0x5e,0x79,0x71};
sbit k1=P3^0;
sbit k2=P3^1;
sbit k3=P3^2;
sbit k4=P3^3;
sbit dula=P2^6;
sbit wela=P2^7;
sbit bee=P2^3;
sbit sda=P2^0;
sbit scl=P2^1;
uint a=0,num,count;
void delay(uint z) //延时函数
{
        uint i,j;
        for(i=z;i>0;i--)
                for(j=110;j>0;j--);
}

void di()//蜂鸣器
{
        bee=0;
        delay(25);
        bee=1;
}
void init()       
{
        sda=1;        //I2C初始化
        _nop_();
        scl=1;
        _nop_();
        dula=0;        //定时器1初始化
        wela=0;
        TMOD=0x01;//选择方式1中断
        TH0=(65536-10000)/256;
        TL0=(65536-10000)%256;
        EA=1;
        ET0=1;
}

void start()//I2C起始信号
{
        sda=1;
        _nop_();
        scl=1;
        _nop_();
        sda=0;
        _nop_();
}

void stop()//I2C终止信号
{
        sda=0;
        _nop_();
        scl=1;
        _nop_();
        sda=1;
        _nop_();
}

void respons()//I2C应答
{
        uchar i;
        scl=1;
        _nop_();
        while(sda==1&&i<250)//应答或非应答均可
                i++;
        scl=0;
        _nop_();       
}

void write_byte(uchar date)//I2C写入一个字节
{
        uchar i,temp;
        temp=date;
        for(i=0;i<8;i++)
        {
                temp=temp<<1;
                scl=0;
                _nop_();
                sda=CY;
                _nop_();
                scl=1;
                _nop_();
        }
        scl=0;
        _nop_();
        sda=1;
        _nop_();
}

uchar read_byte()//I2C读出一个字节
{
        uchar i,k;
        scl=0;
        _nop_();
        sda=1;
        _nop_();
        for(i=0;i<8;i++)
        {
                scl=1;
                _nop_();
                k=(k<<1)|sda;
                scl=0;
                _nop_();
        }
        return k;
}

void write_add(uchar ad,uchar date)//指定地址写一个字节
{
        start();
        write_byte(0xa0);
        respons();
        write_byte(ad);
        respons();
        write_byte(date);
        respons();
        stop();
}

uchar read_add(uchar ad)//指定地址读出一个字节
{
        uchar date;
        start();
        write_byte(0xa0);
        respons();
        write_byte(ad);
        respons();
        start();
        write_byte(0xa1);
        respons();
        date=read_byte();
        stop();
        return date;
}

void display(uint num)//数码管显示0~9999
{
       
        uint qian,bai,shi,ge;
        write_add(1,num/256);//高8位写入地址1;
        write_add(2,num%256);//低8位写入地址2;
        qian=num/1000;
        bai=num%1000/100;
        shi=num%100/10;
        ge=num%10;
       
        dula=1;
        P0=table[qian];
        dula=0;
        P0=0xff;
        wela=1;
        P0=0xef;
        wela=0;
        delay(2);
       
        dula=1;
        P0=table[bai];
        dula=0;
        P0=0xff;
        wela=1;
        P0=0xdf;
        wela=0;
        delay(2);        
       
        dula=1;
        P0=table[shi];
        dula=0;
        P0=0xff;
        wela=1;
        P0=0xbf;
        wela=0;
        delay(2);        
       
        dula=1;
        P0=table[ge];
        dula=0;
        P0=0xff;
        wela=1;
        P0=0x7f;
        wela=0;
        delay(2);                
}


void main()
        {
       
                num=(256*read_add(1)+read_add(2));//num=256*高8位读出地址1;+低8位读出地址2
                        if(num>9999)
                                num=0;       
                while(k1)//按k1后开始启动
                        display(num);
                init();
                while(1)
                        {
                                if(a==1)
                                {
                                        a=0;
                                        num++;
                                                if(num==10000)
                                                        num=0;
                                        //write_add(2,num);
                                }
                                if(k1==0)
                                {
                                        delay(5);
                                        if(k1==0)
                                        {
                                                di();
                                                count=0;
                                                while(!k1)
                                                        P1=0x3f;
                                                P1=0xff;
                                                TR0=1;
                                        }
                                }
                                if(k2==0)
                                {
                                        delay(5);
                                        if(k2==0)
                                        {       
                                                di();
                                                count=1;
                                                while(!k2)
                                                P1=0xcf;
                                                P1=0xff;
                                                TR0=0;
                                        }
                                }
                                if(count==1)
                                {
                                       
                                        if(k3==0)
                                        {
                                                delay(5);
                                                if(k3==0)
                                                {       
                                                        di();
                                                        while(!k3)
                                                                P1=0xf3;
                                                        P1=0xff;
                                                        num++;
                                                        if(num==10000)
                                                                num=0;
                                                //        write_add(2,num);

                                                }
                                        }

                                        if(k4==0)
                                        {
                                                delay(5);
                                                if(k4==0)
                                                {       
                                                        di();
                                                        while(!k4)
                                                                P1=0xfc;
                                                        P1=0xff;
                                                        num--;
                                                        if(num==-1)
                                                         num=9999;
                                                 //        write_add(2,num);
                                                }
                                        }
                                }
                               
                                display(num);       
                        }
        }

void time() interrupt 1         //定时器1中断
{
    TH0=(65536-1000)/256;
        TL0=(65536-1000)%256;
        a=1; //0.01秒中断一次
}

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

使用道具 举报

沙发
ID:86324 发表于 2015-7-21 15:19 | 只看该作者
跪求哪位大神。!!
回复

使用道具 举报

板凳
ID:86324 发表于 2015-7-21 15:23 | 只看该作者
你们看的时候注意一下引脚和我的是否一样,独立键盘有些是P3.4~P3.7的
回复

使用道具 举报

地板
ID:84652 发表于 2015-7-21 16:48 | 只看该作者
为什么把写数据的部分注释了?
回复

使用道具 举报

5#
ID:86324 发表于 2015-7-21 17:05 | 只看该作者
王朗的诱惑 发表于 2015-7-21 16:48
为什么把写数据的部分注释了?

哦哦,那个可以忽略,我把写数据的放在dispaly里了。
void display(uint num)//数码管显示0~9999
{
        
        uint qian,bai,shi,ge;
       write_add(1,num/256);//高8位写入地址1;
        write_add(2,num%256);//低8位写入地址2;
回复

使用道具 举报

6#
ID:84652 发表于 2015-7-21 17:32 | 只看该作者
本帖最后由 王朗的诱惑 于 2015-7-21 17:40 编辑

存一个固定的数然后重新上电,还是原来的数么?
回复

使用道具 举报

7#
ID:86324 发表于 2015-7-21 18:00 | 只看该作者
王朗的诱惑 发表于 2015-7-21 17:32
存一个固定的数然后重新上电,还是原来的数么?

不是了,比如写入固定的500,第一次掉电后又上电就变成396,之后的掉电和上电都显示396.
回复

使用道具 举报

8#
ID:86324 发表于 2015-7-21 18:11 | 只看该作者
王朗的诱惑 发表于 2015-7-21 17:32
存一个固定的数然后重新上电,还是原来的数么?

2种单片机都是这样的现象,应该不是硬件问题。。是不是程序哪里不对?
我总觉得 write_add(1,num/256);//高8位写入地址1;write_add(2,num%256);//低8位写入地址2;有问题。。因为每次只能写入一个字节,所以我成2个字节读取。
     
回复

使用道具 举报

9#
ID:84652 发表于 2015-7-21 18:27 | 只看该作者
学51的小盆友 发表于 2015-7-21 18:11
2种单片机都是这样的现象,应该不是硬件问题。。是不是程序哪里不对?
我总觉得 write_add(1,num/256);/ ...

重写一下起始和停止。按这个顺序:起始SDA=1;SCL=1;  SDA=0;  SCL=0;停止SCL=0;  SDA=0;  SCL=1;  SDA=1;中间用nop隔开,看看行不行……不行了再调……

评分

参与人数 1黑币 +35 收起 理由
admin + 35 回帖助人的奖励!

查看全部评分

回复

使用道具 举报

10#
ID:86324 发表于 2015-7-21 18:35 | 只看该作者
王朗的诱惑 发表于 2015-7-21 18:27
重写一下起始和停止。按这个顺序:起始SDA=1;SCL=1;  SDA=0;  SCL=0;停止SCL=0;  SDA=0;  SCL=1;  SDA=1; ...

还是一样==。
我读数据和写数据的算法有没有错?
回复

使用道具 举报

11#
ID:84652 发表于 2015-7-21 18:50 | 只看该作者
看不出来……继续吧……把写字节里顺序换一下,先SDA = CY;再SCL = 1;再SCL = 0;再把for外面的SCL = 0;去掉。试试……

评分

参与人数 1黑币 +35 收起 理由
admin + 35 回帖助人的奖励!

查看全部评分

回复

使用道具 举报

12#
ID:84652 发表于 2015-7-21 19:02 | 只看该作者
本帖最后由 王朗的诱惑 于 2015-7-21 19:33 编辑

void write_byte(uchar date)//I2C写入一个字节
{
        uchar i,temp;
        temp=date;                        SCL = 0;
        _nop_();
        for(i=0;i<8;i++)
        {
                temp=temp<<1;
                sda=CY;
                _nop_();
                scl=0;
                _nop_();
                scl=1;
                _nop_();
        }
        sda=1;
        _nop_();
}试试看……



评分

参与人数 1黑币 +50 收起 理由
admin + 50 回帖助人的奖励!

查看全部评分

回复

使用道具 举报

13#
ID:86324 发表于 2015-7-21 20:23 | 只看该作者
王朗的诱惑 发表于 2015-7-21 19:02
void write_byte(uchar date)//I2C写入一个字节
{
        uchar i,temp;

这样不行的,因为一个for循环的话,每写一位都要拉低SCL才能写数据。。心塞。

评分

参与人数 1黑币 +50 收起 理由
admin + 50 回帖助人的奖励!

查看全部评分

回复

使用道具 举报

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

本版积分规则

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

Powered by 单片机教程网

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