找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 10973|回复: 12
收起左侧

DS1302实时时钟的问题,如何用4个按键调时呢?

[复制链接]
ID:309880 发表于 2018-5-29 11:27 | 显示全部楼层 |阅读模式
不好意思,我又来了,我用4个按键调节时钟(考虑手上没有与门器件没用中断,时间不够了),代码如下,可是LCD不显示,请各位帮俺看看如何修改,问题应该出在主函数和主函数上面的子函数上了,请各位帮帮忙
#include <reg52.h>
#include <string.h>
#include<intrins.h>
#define uchar unsigned char
#define uint unsigned int
sbit SDA=P1^0;        // DS1302数据线
sbit CLK=P1^1;        //DS1302时钟线
sbit RST=P1^2;  //DS1302复位线
sbit RS=P2^0;
sbit RW=P2^1;
sbit EN=P2^2;
sbit K1=P3^4; // 选择
sbit K2=P3^5; // 加
sbit K3=P3^6; // 减
sbit K4=P3^7; // 确定

uchar tCount=0;
//一年中每个月的天数,2月的天数由年份决定
uchar MonthsDays[]={31,31,30,31,30,31,31,30,31,30,31};
uchar *WEEK[]={"SAT","SUN","MON","TUS","WEN","THU","FRI"};
uchar LCD_DSY_BUFFER1[]={"Date 00-00-00   "}; //LCD显示缓冲
uchar LCD_DSY_BUFFER2[]={"Time 00:00:00   "};
uchar DateTime[7]; //所读取的日期时间
char Adjust_Index=-1;
uchar Change_Flag[]="-MHDM-Y"; //当前调节的标志:分钟,小时,天,月,年

void DelayMS(uint x)
{
  uchar i;
  while(x--) for(i=0;i<120;i++);
}

void DS1302_Write_Byte(uchar x)         //发送一个字节到DS1302通信线上
{
          uchar i;
          
          for(i=0;i<8;i++) //低位在前,移位输出
          {
                  SDA=x&1;  //输出该位数据
                CLK=1;          //拉高时钟
                CLK=0;          //拉低时钟,完成一个位的操作
                x>>=1;
          }
}

uchar DS1302_Read_Byte()
{
uchar i,b,t;
for(i=0;i<8;i++)
{
        b>>=1;
        t=SDA;
        b|=t<<7;
        CLK=1;
        CLK=0;
}
return b/16*10+b%16;
}

uchar Read_Data(uchar addr)
{
        uchar dat;
        RST=0;
        CLK=0;
        RST=1;
        DS1302_Write_Byte(addr);
        dat=DS1302_Read_Byte();
        CLK=1;
        RST=0;
        _nop_();    //以下为DS1302复位的稳定时间,必须的。
    CLK = 1;
    _nop_();
    SDA = 0;
    _nop_();
    SDA = 1;
    _nop_();
        return dat;       
}

void Write_DS1302(uchar addr,uchar dat)
{
        CLK=0;
        RST=1;
        DS1302_Write_Byte(addr);
        DS1302_Write_Byte(dat);
        CLK=0;
        RST=0;       
}

void SET_DS1302()
{
uchar i;
Write_DS1302(0x8e,0x00);
for(i=0;i<7;i++)
{
        Write_DS1302(0x80+2*i,(DateTime[i]/10<<4|(DateTime[i]%10)));
}
Write_DS1302(0x8e,0x80);
}

void GetTime()
{       
        uchar i;
        for(i=0;i<7;i++)
        {
                DateTime[i]=Read_Data(0x81+2*i);
        }
}


uchar Read_LCD_State()
{
        uchar state;
        RS=0;                   //命令
        RW=1;                   //读
        EN=1;                   //读为高电平
        DelayMS(1);
        state=P0;
        EN=0;
        DelayMS(1);
        return state;  //要输出
}

void LCD_Busy_Wait()   //LCD1602响应速度相对于单片机来说是偏慢的
{
        while((Read_LCD_State()&0x08)==0x80);
        DelayMS(5);
}

void Write_LCD_Data(uchar dat) //写数据
{
        LCD_Busy_Wait();   //忙检测
        RS=1;                           //数据
        RW=0;                           //写为低电平
        EN=0;                           //写操作时为低电平
        P0=dat;
        EN=1;
        DelayMS(1);
        EN=0;
}

void Write_LCD_Command(uchar cmd)//写命令
{
        LCD_Busy_Wait();
        RS=0;           //命令
        RW=0;           //写为低电平
        EN=0;           //写操作时为低电平
        P0=cmd;
        EN=1;
        DelayMS(1);
        EN=0;
}

void Init_LCD()        //LCD初始化
{
        Write_LCD_Command(0x38); DelayMS(1);
        Write_LCD_Command(0x01); DelayMS(1);
        Write_LCD_Command(0x06); DelayMS(1);
        Write_LCD_Command(0x0C); DelayMS(1);       
}

void Set_LCD_POS(uchar p)
{
        Write_LCD_Command(p+0x80);
}

void Display_LCD_String(uchar p,uchar *s)
{
        uchar i;
        Set_LCD_POS(p);
        for(i=0;i<16;i++)
        {
                Write_LCD_Data(s[i]);
                DelayMS(1);
        }
}

void Format_DateTime(uchar d,uchar *a)
{
        a[0]=d/10+'0';a[1]=d%10+'0';
}

uchar isLeapYear(uint y)
{
return (y%4==0&&y%100!=0)||(y%400==0);
}

void DateTime_Adjust(char x)
{
switch (Adjust_Index)
{
        case 6:          //年
                if(x== 1&&DateTime[6]<99) DateTime[6]++;
                if(x==-1&&DateTime[6]>0)  DateTime[6]--;
                MonthsDays[2]=isLeapYear(2000+DateTime[6])? 29:28;
                if(DateTime[3]>MonthsDays[DateTime[4]])
                   DateTime[3]=MonthsDays[DateTime[4]];
                //RefreshWeekDay();
                break;

        case 4:         //月
                if(x== 1&&DateTime[4]<12) DateTime[4]++;
                if(x==-1&&DateTime[4]>1)  DateTime[4]--;
                MonthsDays[2]=isLeapYear(2000+DateTime[6])? 29:28;
                if(DateTime[3]>MonthsDays[DateTime[4]])
                DateTime[3]=MonthsDays[DateTime[4]];
                //RefreshWeekDay();
                break;
   case 3:                //日
                MonthsDays[2]=isLeapYear(2000+DateTime[6])? 29:28;
                if(x== 1&&DateTime[3]<MonthsDays[DateTime[4]]) DateTime[3]++;
                if(x==-1&&DateTime[3]>0) DateTime[3]--;
                //RefreshWeekDay();
                break;
   case 2:          //时
                if(x== 1&&DateTime[2]<23) DateTime[2]++;
                if(x==-1&&DateTime[2]>0)  DateTime[2]--;
                break;

   case 1:           //秒
                if(x== 1&&DateTime[1]<59) DateTime[1]++;
                if(x==-1&&DateTime[1]>0)  DateTime[1]--;
                break;         
}
}

void main()
{
  Init_LCD();
  while(1)
  {         
        GetTime();
        if(K1==0)
        {  
           DelayMS(10);        //按键消抖
           while(K1==0);
           if(Adjust_Index==-1||Adjust_Index==1) {Adjust_Index=7;}//uchar Change_Flag[]="-MHDM-Y";
           Adjust_Index--;
           if(Adjust_Index==5) Adjust_Index=4;
           LCD_DSY_BUFFER2[13]='[';
           LCD_DSY_BUFFER2[14]=Change_Flag[Adjust_Index];
           LCD_DSY_BUFFER2[15]=']';
          if(K2==0)   //  加
          {
                 DelayMS(10);        //按键消抖
             while (K2==0); DateTime_Adjust(1);
          }
        else if(K3==0)  //  减
          {
                DelayMS(10);        //按键消抖
                while (K3==0); DateTime_Adjust(-1);
      }
        else if(K4==0)  // 确定
          {
                DelayMS(10);        //按键消抖
                while(K4==0);
                SET_DS1302();        //调整后的时间写入DS1302
                LCD_DSY_BUFFER2[13]=' ';
                LCD_DSY_BUFFER2[14]=' ';
                LCD_DSY_BUFFER2[15]=' ';
                Adjust_Index=-1;
          }
    }
  }
    Format_DateTime(DateTime[6],LCD_DSY_BUFFER1+5);           //年
        Format_DateTime(DateTime[4],LCD_DSY_BUFFER1+8);           //月
        Format_DateTime(DateTime[3],LCD_DSY_BUFFER1+11);   //日
        strcpy(LCD_DSY_BUFFER1+13,WEEK[DateTime[5]]);           //week

        Format_DateTime(DateTime[2],LCD_DSY_BUFFER2+5);           //时
        Format_DateTime(DateTime[1],LCD_DSY_BUFFER2+8);           //分
        Format_DateTime(DateTime[0],LCD_DSY_BUFFER2+11);   //秒

        Display_LCD_String(0x00,LCD_DSY_BUFFER1);
        Display_LCD_String(0x40,LCD_DSY_BUFFER2);
}

回复

使用道具 举报

ID:111634 发表于 2018-5-29 22:31 | 显示全部楼层
本帖最后由 zl2168 于 2018-5-29 22:33 编辑

下功夫阅读别人成功有效的程序,认真体会理解,仔细对照查错。而不是发出大段无里头程序,让别人帮你查错。

评分

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

查看全部评分

回复

使用道具 举报

ID:340985 发表于 2018-5-29 22:37 | 显示全部楼层
仔细看,可以的
回复

使用道具 举报

ID:118735 发表于 2018-5-29 22:46 | 显示全部楼层
肯定是需要中断的,毕竟单片机是怎么都跑步过来
回复

使用道具 举报

ID:118735 发表于 2018-5-29 22:49 | 显示全部楼层
你这样处理,按键调节分开。按键处理的时候。停止时间显示,然后按键处理完了再回去处理显示
回复

使用道具 举报

ID:340390 发表于 2018-5-29 22:57 | 显示全部楼层
你把LCD的函数写在死循环外面当然LCD不显示啦,在编写程序时要有个程序流程的概念,楼上说得对,要自己仔细查,不然永远都是发帖问
回复

使用道具 举报

ID:309880 发表于 2018-5-29 23:39 | 显示全部楼层
zl2168 发表于 2018-5-29 22:31
下功夫阅读别人成功有效的程序,认真体会理解,仔细对照查错。而不是发出大段无里头程序,让别人帮你查错。

苦口良药,感谢指点
回复

使用道具 举报

ID:309880 发表于 2018-5-29 23:40 | 显示全部楼层
王企鹅 发表于 2018-5-29 22:46
肯定是需要中断的,毕竟单片机是怎么都跑步过来

明白,已经解决
回复

使用道具 举报

ID:309880 发表于 2018-5-29 23:41 | 显示全部楼层
benng1996 发表于 2018-5-29 22:57
你把LCD的函数写在死循环外面当然LCD不显示啦,在编写程序时要有个程序流程的概念,楼上说得对,要自己仔细 ...

以后会注意,感谢提醒
回复

使用道具 举报

ID:111634 发表于 2018-5-30 06:20 | 显示全部楼层
本帖最后由 zl2168 于 2018-5-30 06:22 编辑

我这里有3个不同方式的按键调时案例,你可参考一下。
实例91  具有校正功能的时钟1302LCD1602显示)

先Proteus仿真,确认有效。 实例91 带校正时钟1302(LCD1602显示).rar (52.68 KB, 下载次数: 79)
回复

使用道具 举报

ID:111634 发表于 2018-5-30 06:23 | 显示全部楼层
实例93  具有校正功能的时钟1302(LED数码管显示)
Proteus仿真一下,确认有效。
实例93 带校正时分秒的时钟1302(6位LED数码管显示).rar (732.75 KB, 下载次数: 55)
回复

使用道具 举报

ID:111634 发表于 2018-5-30 06:25 | 显示全部楼层
本帖最后由 zl2168 于 2018-5-30 06:27 编辑

实例94  模拟电子钟(由80C51定时器产生秒时基)
Proteus仿真一下,确认有效。
实例94 模拟电子钟(由80C51定时器产生秒时基).rar (43.05 KB, 下载次数: 15)
回复

使用道具 举报

ID:503107 发表于 2019-4-21 20:05 来自手机 | 显示全部楼层
迈特拉布 发表于 2018-5-29 23:41
以后会注意,感谢提醒

楼主可以发个联系方式吗,想搬运一下程序,谢谢
回复

使用道具 举报

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

本版积分规则

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

Powered by 单片机教程网

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