找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 2275|回复: 5
收起左侧

关于DS1302时钟问题?

[复制链接]
ID:687423 发表于 2020-2-15 15:15 | 显示全部楼层 |阅读模式
这个程序是我在网上找到,自己又改了一下只是有几个地方不是很明白,请求大家支援。
DS1302芯片是自动将我定义的time数组里的数据转化成BCD码吗?
这两天看了很多进制,有点蒙了,time数组里定义的数据的类型是16进制的吗?
关于key2的程序中,为什么需要手动转化BCD码吗,不应该是1302自动转化吗?
关于lcd1602中周的显示,为什么星期是&0x07,这个进制转换的怎么转换啊?
星期的显示地址我设置为0x80+0x40+0x0f,开始好使,按下k3后1602的第一行最后也有一个4(假设星期为4)。地址为0x80+0x0f的话4就出现在第1行第一个位置了,按下k3后第一行最后一个位置才出现4。这是为什么啊,是程序问题吗?

#include <reg52.h>
#include <intrins.h>
#define lcd1602data P0
typedef unsigned char u8;
typedef unsigned int u16;
sbit E=P2^7;  
sbit RW=P2^5;   
sbit RS=P2^6;   
sbit  key1=P3^1;
sbit  key2=P3^0;
sbit  key3=P3^2;

sbit SCLK=P3^6;
sbit IO=P3^4;
sbit RST=P3^5;  
u16 read[]={0x81,0x83,0x85,0x87,0x89,0x8b,0x8d};  
u16 write[]={0x80,0x82,0x84,0x86,0x88,0x8a,0x8c};  
u8 time[]={0x15,0x27,0x09,0x15,0x02,0x06,0x20};  
u16 setmark,setplace;     
void delay_ms(u16 n);
void initConfiguration();
void lcdDisplay();
void lcdwrite_com(u8 datas);
void lcdwrite_datas(u8 datas);
void lcdinit();
void writebyte(u8 address,u8 datas);
u8 readbyte(u8 address);
void ds1302init();
void read_time();
void main()
{
  u16 i;
  initConfiguration();
  lcdinit();
  ds1302init();
  while(1)
  {
   if(setmark==0)   
   {
    read_time();
   }
   else      
   {
     if(key1==0)
    {
     delay_ms(1);
    if(key1==0)
    {
       setplace++;   
      setplace%=7;
    }
    while(i<50&&key1==0)   
     {
     i++;
     delay_ms(10);
     }
     i=0;
    }

    if(key2==0)
    {
      delay_ms(1);
     if(key2==0)      
     {
     time[setplace]++;
     if((time[setplace]&0x0f)>9)   
     {
      time[setplace]=time[setplace]+6;
     }
     if((time[setplace]>=0x60)&&(setplace<2))  
     {
      time[setplace]=0;
     }
     if((time[setplace]>=0x24)&&(setplace==2))
     {
      time[setplace]=0;
     }
     if((time[setplace]>=0x32)&&(setplace==3))
     {
      time[setplace]=0;
     }
     if((time[setplace]>=0x13)&&(setplace==4))  
      time[setplace]=0;
     }
     if((time[setplace]>=0x7)&&(setplace==5))
     {
      time[setplace]=1;
     }
                  
     }
     while((i<50)&&(0==key2))
     {
      i++;
     delay_ms(10);
     }
     i=0;
    }
   }
   lcdDisplay();
  }
}
void delay_ms(u16 n)   
{
u16 a,b;
for(;n>0;n--)
{
  for(a=199;a>0;a--)
  {
   for(b=1;b>0;b--)
   {
     ;
   }
  }
}
}

void initConfiguration()
{
EA=1;
IT0=1;
EX0=1;
}
void init0() interrupt 0
{
  delay_ms(10);
  if(key3==0)
  {
   setmark=~setmark;
  setplace=0;
  ds1302init();
  }
}
void lcdDisplay()   
{

lcdwrite_com(0x80+0x01);   
lcdwrite_datas('d');
lcdwrite_datas('a');
lcdwrite_datas('t');
lcdwrite_datas('e');
lcdwrite_datas(':');
lcdwrite_datas('2');
lcdwrite_datas('0');
lcdwrite_datas('0'+time[6]/16);  
lcdwrite_datas('0'+(time[6]&0x0f));
lcdwrite_datas('-');
lcdwrite_datas('0'+time[4]/16);
lcdwrite_datas('0'+(time[4]&0x0f));
lcdwrite_datas('-');  
lcdwrite_datas('0'+time[3]/16);
lcdwrite_datas('0'+(time[3]&0x0f));
lcdwrite_com(0x80+0x0f);
lcdwrite_datas('0'+(time[5]&0x07));
lcdwrite_com(0x80+0x40);        
lcdwrite_datas('t');
lcdwrite_datas('i');
lcdwrite_datas('m');
lcdwrite_datas('e');
lcdwrite_datas(':');
lcdwrite_datas('0'+time[2]/16);
lcdwrite_datas('0'+(time[2]&0x0f));
lcdwrite_datas('-');
lcdwrite_datas('0'+time[1]/16);
lcdwrite_datas('0'+(time[1]&0x0f));
lcdwrite_datas('-');
lcdwrite_datas('0'+time[0]/16);   
lcdwrite_datas('0'+(time[0]&0x0f));
}
void lcdwrite_com(u8 datas)   
{
E=0;
RW=0;
RS=0;
lcd1602data=datas;
delay_ms(1);
E=1;
delay_ms(1);
E=0;

}
void lcdwrite_datas(u8 datas)  
{
E=0;
RW=0;
RS=1;
lcd1602data=datas;
delay_ms(1);     
E=1;
delay_ms(1);
E=0;

}
void lcdinit()     
{
lcdwrite_com(0x38);  
lcdwrite_com(0x0c);   
lcdwrite_com(0x06);   
lcdwrite_com(0x01);   
lcdwrite_com(0x80);  
}


void writebyte(u8 address,u8 datas)   
{
u8 i;
RST=0;
_nop_();
SCLK=0;
_nop_();
RST=1;
_nop_();
for(i=0;i<8;i++)
{
  IO=address&0x01;
  address>>=1;
  SCLK=1;
  _nop_();
  SCLK=0;
  _nop_();
}
for(i=0;i<8;i++)
{
  IO=datas&0x01;
  datas>>=1;
  SCLK=1;
  _nop_();
  SCLK=0;
  _nop_();
}
RST=0;
}
u8 readbyte(u8 address)   
{
u8 i,datas,dat;
RST=0;
_nop_();
SCLK=0;
_nop_();
RST=1;
_nop_();
for(i=0;i<8;i++)
{
  IO=address&0x01;
  address>>=1;
  SCLK=1;
  _nop_();
  SCLK=0;
  _nop_();
}
_nop_();
for(i=0;i<8;i++)
{
  dat=IO;
  datas=(datas>>1)|(dat<<7);
  SCLK=1;
  _nop_();
  SCLK=0;
  _nop_();
}
RST=0;
_nop_();
SCLK=1;
_nop_();
IO=0;
_nop_();
IO=1;
_nop_();
return datas;
}
void ds1302init()     
{
u8 i;
writebyte(0x8e,0x00);   
for(i=0;i<7;i++)
{
  writebyte(write[i],time[i]);
}
writebyte(0x8e,0x80);   
}
void read_time()     
{
u8 i;
for(i=0;i<7;i++)
{
  time[i]=readbyte(read[i]);
}
}
回复

使用道具 举报

ID:235200 发表于 2020-2-15 16:11 | 显示全部楼层
你的问题加了注释如下:
#include <reg52.h>
#include <intrins.h>
#define lcd1602data P0
typedef unsigned char u8;
typedef unsigned int u16;
sbit E=P2^7;  
sbit RW=P2^5;   
sbit RS=P2^6;   
sbit  key1=P3^1;
sbit  key2=P3^0;
sbit  key3=P3^2;

sbit SCLK=P3^6;
sbit IO=P3^4;
sbit RST=P3^5;  
u16 read[]={0x81,0x83,0x85,0x87,0x89,0x8b,0x8d};      //这是读DS1302时钟数据的地址"秒 分 小时 日 月 星期 年"
u16 write[]={0x80,0x82,0x84,0x86,0x88,0x8a,0x8c};     //这是写DS1302时钟数据的地址"秒 分 小时 日 月 星期 年"  
u8 time[]={0x15,0x27,0x09,0x15,0x02,0x06,0x20};       //这是设置DS1302时钟数据"秒 分 小时 日 月 星期 年"
//以上数据不需要转换,可以认为是十六制数,可以认为BCD码,16进制数只是BCD码的一种表现形式,即BCD数据中不可能出现A-F数码
u16 setmark,setplace;     
void delay_ms(u16 n);
void initConfiguration();
void lcdDisplay();
void lcdwrite_com(u8 datas);
void lcdwrite_datas(u8 datas);
void lcdinit();
void writebyte(u8 address,u8 datas);
u8 readbyte(u8 address);
void ds1302init();
void read_time();
void main()
{
  u16 i;
  initConfiguration();
  lcdinit();
  ds1302init();
  while(1)
  {
   if(setmark==0)   
   {
    read_time();
   }
   else      
   {
     if(key1==0)      //按键1操作
    {
     delay_ms(1);
    if(key1==0)
    {
       setplace++;   
      setplace%=7;
    }
    while(i<50&&key1==0)   
     {
     i++;
     delay_ms(10);
     }
     i=0;
    }

    if(key2==0)    //按鍵2操作
    {
      delay_ms(1);
     if(key2==0)      
     {
     time[setplace]++;             //按键设置的时钟数据处理
     if((time[setplace]&0x0f)>9)   //每次加1后出现A-F数据不符合BCD,所以要保证数据只有0-9
     {
      time[setplace]=time[setplace]+6;
     }
     if((time[setplace]>=0x60)&&(setplace<2))    //保证分钟在十进制00-59间变化
     {
      time[setplace]=0;
     }
     if((time[setplace]>=0x24)&&(setplace==2))   //保证小时在十进制00-23之间变化
     {
      time[setplace]=0;
     }
     if((time[setplace]>=0x32)&&(setplace==3))   //保证日期在十进制1-31之间变化
     {
      time[setplace]=0;
     }
     if((time[setplace]>=0x13)&&(setplace==4))   //保证月份在十进制1-12之间变化
      time[setplace]=0;
     }
     if((time[setplace]>=0x7)&&(setplace==5))    //保证星期在十进制0-6之间变化 0表示星期天 1-6表示星期一至六
     {
      time[setplace]=1;
     }
                  
     }
     while((i<50)&&(0==key2))
     {
      i++;
     delay_ms(10);
     }
     i=0;
    }
   }
   lcdDisplay();
  }
}
void delay_ms(u16 n)   
{
u16 a,b;
for(;n>0;n--)
{
  for(a=199;a>0;a--)
  {
   for(b=1;b>0;b--)
   {
     ;
   }
  }
}
}

void initConfiguration()
{
EA=1;
IT0=1;
EX0=1;
}
void init0() interrupt 0
{
  delay_ms(10);
  if(key3==0)          //按键3在中断里判断是不行的  这个中断程序是有问题的
  {
   setmark=~setmark;
  setplace=0;
  ds1302init();
  }
}
void lcdDisplay()        //LCD显示程序
{

lcdwrite_com(0x80+0x01);   
lcdwrite_datas('d');
lcdwrite_datas('a');
lcdwrite_datas('t');
lcdwrite_datas('e');
lcdwrite_datas(':');
lcdwrite_datas('2');
lcdwrite_datas('0');
lcdwrite_datas('0'+time[6]/16);      //显示年份十位
lcdwrite_datas('0'+(time[6]&0x0f));  //显示年份个位
lcdwrite_datas('-');
lcdwrite_datas('0'+time[4]/16);      //显示月份十位
lcdwrite_datas('0'+(time[4]&0x0f));  //显示月份个位
lcdwrite_datas('-');  
lcdwrite_datas('0'+time[3]/16);      //显示日期十位
lcdwrite_datas('0'+(time[3]&0x0f));  //显示日期个位
lcdwrite_com(0x80+0x0f);
lcdwrite_datas('0'+(time[5]&0x07));  //显示星期 读出的星期数据只有最低3位是表示星期,其它位可能表示12时制或24时制
//&07的目的去掉不需的内容
lcdwrite_com(0x80+0x40);        
lcdwrite_datas('t');
lcdwrite_datas('i');
lcdwrite_datas('m');
lcdwrite_datas('e');
lcdwrite_datas(':');
lcdwrite_datas('0'+time[2]/16);
lcdwrite_datas('0'+(time[2]&0x0f));
lcdwrite_datas('-');
lcdwrite_datas('0'+time[1]/16);
lcdwrite_datas('0'+(time[1]&0x0f));
lcdwrite_datas('-');
lcdwrite_datas('0'+time[0]/16);   
lcdwrite_datas('0'+(time[0]&0x0f));
}
void lcdwrite_com(u8 datas)   
{
E=0;
RW=0;
RS=0;
lcd1602data=datas;
delay_ms(1);
E=1;
delay_ms(1);
E=0;

}
void lcdwrite_datas(u8 datas)  
{
E=0;
RW=0;
RS=1;
lcd1602data=datas;
delay_ms(1);     
E=1;
delay_ms(1);
E=0;

}
void lcdinit()     
{
lcdwrite_com(0x38);  
lcdwrite_com(0x0c);   
lcdwrite_com(0x06);   
lcdwrite_com(0x01);   
lcdwrite_com(0x80);  
}


void writebyte(u8 address,u8 datas)   
{
u8 i;
RST=0;
_nop_();
SCLK=0;
_nop_();
RST=1;
_nop_();
for(i=0;i<8;i++)
{
  IO=address&0x01;
  address>>=1;
  SCLK=1;
  _nop_();
  SCLK=0;
  _nop_();
}
for(i=0;i<8;i++)
{
  IO=datas&0x01;
  datas>>=1;
  SCLK=1;
  _nop_();
  SCLK=0;
  _nop_();
}
RST=0;
}
u8 readbyte(u8 address)   
{
u8 i,datas,dat;
RST=0;
_nop_();
SCLK=0;
_nop_();
RST=1;
_nop_();
for(i=0;i<8;i++)
{
  IO=address&0x01;
  address>>=1;
  SCLK=1;
  _nop_();
  SCLK=0;
  _nop_();
}
_nop_();
for(i=0;i<8;i++)
{
  dat=IO;
  datas=(datas>>1)|(dat<<7);
  SCLK=1;
  _nop_();
  SCLK=0;
  _nop_();
}
RST=0;
_nop_();
SCLK=1;
_nop_();
IO=0;
_nop_();
IO=1;
_nop_();
return datas;
}
void ds1302init()     
{
u8 i;
writebyte(0x8e,0x00);   
for(i=0;i<7;i++)
{
  writebyte(write[i],time[i]);
}
writebyte(0x8e,0x80);   
}
void read_time()     
{
u8 i;
for(i=0;i<7;i++)
{
  time[i]=readbyte(read[i]);
}
}
回复

使用道具 举报

ID:687423 发表于 2020-2-15 18:37 | 显示全部楼层
csmyldl 发表于 2020-2-15 16:11
你的问题加了注释如下:
#include
#include

感谢啊,讲的很详细。我想了解一下为什么不能再中断里判断按键
回复

使用道具 举报

ID:235200 发表于 2020-2-15 19:47 | 显示全部楼层
。。jj 发表于 2020-2-15 18:37
感谢啊,讲的很详细。我想了解一下为什么不能再中断里判断按键

按键消抖方式改一下,不要在中断程序里加入延时,进入中断后如果要判断,再好把中断屏敞掉(EX0=0),处理完后再开启(EX0=1)
回复

使用道具 举报

ID:687423 发表于 2020-2-16 19:13 | 显示全部楼层
csmyldl 发表于 2020-2-15 19:47
按键消抖方式改一下,不要在中断程序里加入延时,进入中断后如果要判断,再好把中断屏敞掉(EX0=0),处理完后 ...

对于按键消抖来说,不是应该按键按下去之后才能消抖吗,可是按键一按下去不就中断了吗,按照你说的是按键按下去,进入中断,在中断的程序时先关闭中断在延时在看起中断吗,你看我按照你的话这么写程序对吗。这样写和中断写延时里有什么区别,还有就是如果在中断的程序关闭中断的话中断内部的程序还会进行吗?
//k3按键按下后进入中断
void init0() interrupt 1
{
      EX0=0;
      delay(100);
      if(k3==0)
      {
                EX1=0;
               其他程序
      }
}
回复

使用道具 举报

ID:235200 发表于 2020-2-17 20:18 | 显示全部楼层
从你的程序看,K3键主要是进入设置状态,K1是选择调整的内容,K2是进行选择的内容进行加1运算,如果是这样,可以设置按下K3键标记一下
void init0() interrupt 1
{
      EX0=0;               //屏幕中断
            
    FLAG=~FLAG;       //用一个标记来表示是设置状态还是非设置状态
    TH0=1;                //开启定时计数器,时间到才允许再次开启外部中断
}
在主程序中加上判断
  if (FLAG==1)
   {
       //判断K1  K2并执行相应的动作
}
何时开启外部中断呢?可以用一个定时计数器
Time0() interrupt 1
{
    EX1=1;         //开启外部中断
    TH0=0;        //12M晶振约65ms
    TL0=0;
    ET0=0;        //关闭  下次按键时才开启
}
这样就达到所需功能,K3键按一次进入设置 再按一次退出设置
回复

使用道具 举报

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

本版积分规则

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

Powered by 单片机教程网

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