打印
[疑难问答]

protues仿真实时时钟,时间不随秒增加

[复制链接]
1370|7
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
Listate|  楼主 | 2018-3-25 20:12 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式
#include<reg52.h>
#define uchar unsigned char
#define uint unsigned int
sbit lcden=P3^4; //液晶使能端
sbit rs=P3^5; //液晶数据命令选择端
sbit led=P2^5; //控制LED的锁存器
sbit dula=P2^6;  //控制LCD的段锁存器
sbit wela=P2^7;  //控制LCD的位锁存器
sbit dsirq=P3^2;  //DS12887的中断请求端
sbit dsds=P1^7;  //DS12887的读允许输入端
sbit dsrw=P1^6; //DS12887的写允许输入端
sbit dsas=P1^5;  //DS12887的地址选通端
sbit dscs=P1^4;  //DS12887的芯片片选端
sbit a=P3^0;  //设置键盘用的
sbit b=P3^1;  //设置键盘用的
sbit c=P3^6;  //设置键盘用的
sbit d=P3^7;  //设置键盘用的
sbit e=P3^3;  //设置键盘用的
uchar code table1[]=" 2000-00-00     ";
uchar code table2[]=" 00:00:00       ";
uchar flag1,flag2,temp,temp1;
/*
  falg1标志位是用来判断是否执行从DS12C887中读取数据并送去液晶显示;
  flag2标志位是用来判断LCD上显示的年数是否是闰年;
  temp与temp1都时当月的天数值,用来判断DS12C887中的天数值是否大
  于当月应有的天数,如大于则将天数值置1,如有需要请重新设置天数值。
*/  
char miao,fen,nian,yue,ri,xingqi;  
int shi;  //小时的数值大于128,所以不能选择char型数据
/*------------
  延时子程序
*/
void delayms(uchar a)
{
uchar x,y;
for(x=a;x>0;x--)
  for(y=110;y>0;y--);
}
/*----------------
  往液晶中写指令
----------------*/
void write_com(uchar com)
{
rs=0;      //选择写命令模式
lcden=0;  //将lcden置为零
P0=com;   //将要写的命令字送到数据总线上
delayms(5);  //稍做延时以待数据稳定
lcden=1;  //使能端给一个高脉冲
delayms(5);  //稍做延时
lcden=0;  //将使能端置0以完成高脉冲
}
/*----------------
  往液晶中写数据
----------------*/
void write_date(uchar date)
{
rs=1;   //选择写数据模式
lcden=0;  //将lcden置为零
P0=date;  //将要写的数据送到数据总线上
delayms(5);  //稍做延时以待数据稳定
lcden=1;  //使能端给一个高脉冲
delayms(5);  //稍做延时
lcden=0;  //将使能端置0以完成高脉冲
}
/*--------------------
  向DS12C887内写数据
--------------------*/
void write_ds(uchar add,uchar date)
{
dscs=0;
dsas=1;
dsds=1;
dsrw=1;
P0=add;   //先写地址
dsas=0;
dsrw=0;
P0=date;  //再写数据
dsrw=1;
dsas=1;
dscs=1;
}
/*--------------------
  从DS12C887中读数据
--------------------*/
uchar read_ds(uchar add)
{
uchar temp;
dscs=0;
dsas=1;
dsds=1;
dsrw=1;
P0=add;   //先写地址
dsas=0;
dsds=0;
P0=0xff;  //读数据之前先将P0口置一
temp=P0;  //再读数据
dsds=1;
dsas=1;
dscs=1;  
return temp;
}
/*----------------------------------------------------------------------
  24小时制在液晶的指定位置写入时分秒,12小时制在液晶的指定位置写入分秒
----------------------------------------------------------------------*/
void write_sfm(uchar add,uchar date)
{
uchar shi,ge;
shi=date/10;  //分解一个2位数的十位和个位
ge=date%10;
write_com(0x80+0x40+add);  //设置显示位置
write_date(shi+0x30);    //送去液晶显示十位
write_date(ge+0x30);    //送去液晶显示个位
}
/*----------------------------
  在液晶的指定位置写入年月日
----------------------------*/
void write_nyr(uchar add,uchar date)
{
uchar shi,ge;
shi=date/10;  //分解一个2位数的十位和个位
ge=date%10;
write_com(0x80+add);   //设置显示位置
write_date(shi+0x30);  //送去液晶显示十位
write_date(ge+0x30);   //送去液晶显示个位
}
/*----------------------------
  在液晶的指定位置写入星期
----------------------------*/
void write_xq(uchar date)
{
uchar i;
i=date;
write_com(0x80+12);
switch(i)    //switch-case语句判断i的值及执行相应的操作
{
  case 1:     //当i等于1时,送去液晶显示MON(星期一)
   write_date('M');
   write_date('O');
   write_date('N');
   break;
  case 2:     //当i等于2时,送去液晶显示TUE(星期二)
   write_date('T');
   write_date('U');
   write_date('E');
   break;
  case 3:     //当i等于3时,送去液晶显示WED(星期三)
   write_date('W');
   write_date('E');
   write_date('D');
   break;
  case 4:     //当i等于4时,送去液晶显示THU(星期四)
   write_date('T');
   write_date('H');
   write_date('U');
  break;
  case 5:       //当i等于5时,送去液晶显示FRI(星期五)
   write_date('F');
   write_date('R');
   write_date('I');
   break;
  case 6:     //当i等于6时,送去液晶显示SAT(星期六)
   write_date('S');
   write_date('A');
   write_date('T');
   break;
  case 7:     //当i等于7时,送去液晶显示SUN(星期日)
   write_date('S');
   write_date('U');
   write_date('N');
   break;
}
}
/*----------------
  判断天数的函数
----------------*/
char day_num(char nian,char yue)
{
char num;
if(((nian%4==0)&&(nian%100!=0))||((nian%100==0)&&(nian%400==0)))  //闰年判断
  flag2=1;
else
  flag2=0;
if(flag2==1)  //是闰年时,将第二月的天数设为29
{
  switch(yue)
  {
   case 1:
    num=31;  //1月的天数
    break;
   case 2:
    num=29;  //2月的天数
    break;
   case 3:
    num=31;  //3月的天数
    break;
   case 4:
    num=30;  //4月的天数
    break;
   case 5:
    num=31;  //5月的天数
    break;
   case 6:
    num=30;  //6月的天数
    break;
   case 7:
    num=31;  //7月的天数
    break;
   case 8:
    num=31;  //8月的天数
    break;
   case 9:
    num=30;  //9月的天数
    break;
   case 10:
    num=31;  //10月的天数
    break;
   case 11:  
    num=30;  //11月的天数
    break;
   case 12:
   num=31;  //12月的天数
    break;
  }
}
if(flag2==0)  //不是闰年时,将第二月的天数设为28
{
  switch(yue)
  {
   case 1:
    num=31;  //1月的天数
    break;
   case 2:
    num=28;  //2月的天数
    break;
   case 3:
    num=31;  //3月的天数
    break;
   case 4:
    num=30;  //4月的天数
    break;
   case 5:
    num=31;  //5月的天数
    break;
   case 6:
    num=30;  //6月的天数
    break;
   case 7:
    num=31;  //7月的天数
    break;
   case 8:
    num=31; //8月的天数
    break;
   case 9:
    num=30;  //9月的天数
    break;
   case 10:
    num=31;  //10月的天数
    break;
   case 11:
    num=30;  //11月的天数
    break;
   case 12:
    num=31;  //12月的天数
    break;
  }
}
return num;  //函数的返回值时当月的天数
}
/*--------------
  键盘扫描程序
--------------*/
void keyscan()
{
uchar num;
a=0;  //设置矩阵键盘S1低电平
b=1;  //设置矩阵键盘S2高电平
if(c==0)   //判断S3有没有被按下
{
  delayms(5);  //去抖延时
  if(c==0)  //判断S3有没有被按下
  {
   while(!c);  //判断按键S3有没有释放
   num++;     //按下键的次数
   flag1=1;    //标志位flag1置一
   if(num==1)  //当num等于1时,光标在秒钟处闪烁
   {
    write_com(0x80+0x40+8);
    write_com(0x0f);
   }
   if(num==2)  //当num等于2时,光标在分钟处闪烁
   {
    write_com(0x80+0x40+5);
    write_com(0x0f);
   }
   if(num==3) //当num等于3时,光标在时钟处闪烁
   {
    write_com(0x80+0x40+2);
    write_com(0x0f);
   }
   if(num==4) //当num等于4时,光标在年处闪烁
   {
   write_com(0x80+4);
    write_com(0x0f);
   }
   if(num==5)  //当num等于5时,光标在月处闪烁
   {
    write_com(0x80+7);
    write_com(0x0f);
   }
   if(num==6)  //当num等于6时,光标在日处闪烁
   {
    write_com(0x80+10);
    write_com(0x0f);
   }
   if(num==7)  //当num等于7时,光标在星期处闪烁
   {
    write_com(0x80+14);
    write_com(0x0f);
   }
   if(num==8)
   {
    num=0;  //num清0
    write_ds(0x00,miao);    //将秒写入DS12C887
    write_ds(0x02,fen);     //将分写入DS12C887
    write_ds(0x04,shi);     //将时写入DS12C887
    write_ds(0x06,xingqi);  //将星期写入DS12C887
    write_ds(0x07,ri);     //将日写入DS12C887
    write_ds(0x08,yue);     //将月写入DS12C887
    write_ds(0x09,nian);    //将年写入DS12C887
    flag1=0;  //标志位flag1清0
   }
  }
}
if(num!=0)  //当功能键S3按下后,数值增大键S4才有用
{
  a=0;  //设置矩阵键盘第一排位低电平
  b=1;  //设置矩阵键盘第二排位高电平
  if(d==0)  //判断S4有没有被按下
  {
   delayms(5);  //去抖延时
   if(d==0)  //判断S4有没有被按下
   {
    while(!d);  //判断按键S4有没有释放
    if(num==1)
    {
     miao++;  //当num=1时,秒值加一
     if(miao>59)  //当秒值大于59时,将秒值置0
      miao=0;
     write_sfm(7,miao);  //将秒值写入液晶显示
     write_com(0x80+0x40+8);  //光标在秒值的个位闪烁
     write_com(0x0f);
    }
    if(num==2)
    {
     fen++;  //当num=2时,分值加一??
     if(fen>59)  //当分值大于59时,将分值置0
      fen=0;
     write_sfm(4,fen);  //将分值写入液晶显示
     write_com(0x80+0x40+5);  //光标在分值的个位闪烁
     write_com(0x0f);
    }
    if(num==3)
    {
    shi++;  //当num=3时,时钟加一?
    if(shi>23)  //当时钟大于23时,将时钟置0
      shi=0;
     write_sfm(1,shi);  //将时钟写入液晶显示
     write_com(0x80+0x40+2);  //光标在时钟的个位闪烁
     write_com(0x0f);
    }
    if(num==4)
    {
     nian++;  //当num=4时,年加一
     if(nian>99)  //当年大于99时,将年置0
      nian=0;
     write_nyr(3,nian);  //将年写入液晶显示
     write_com(0x80+4);  //光标在年的个位闪烁
     write_com(0x0f);
    }
    if(num==5)
    {
     yue++;  //当num=5时,月加一
     if(yue>12)  //当月大于12时,将月置1
      yue=1;
     write_nyr(6,yue);   //将月写入液晶显示
     write_com(0x80+7);  //光标在月的个位闪烁
     write_com(0x0f);
    }
    if(num==6)
    {
     ri++;  //当num=6时,日加一
     temp=day_num(nian,yue);
     if(ri>temp)  //当日大于当月的天数时,将日置1
      ri=1;
    write_nyr(9,ri);  //将日写入液晶显示
    write_com(0x80+10);  //光标在月的个位闪烁
     write_com(0x0f);
    }
    if(num==7)
    {
     xingqi++;  //当num=7时,星期加一
     if(xingqi>7)  //当星期大于7时,将星期置1
      xingqi=1;
     write_xq(xingqi);  //将星期写入液晶显示
     write_com(0x80+14);  //光标在星期的个位闪烁
     write_com(0x0f);
    }
   }
  }
}
if(num!=0)  //当功能键S3按下后,数值减小键S5才有用
{
  a=1;  //设置矩阵键盘第一排位高电平
  b=0;  //设置矩阵键盘第二排位低电平
  if(e==0)  //判断S5有没有被按下
  {
   delayms(5);  //去抖延时
   if(e==0)  //判断S5有没有被按下
   {
    while(!e);  //判断按键S5有没有释放
    if(num==1)
    {
     miao--;  //当num=1时,秒值减一
     if(miao<0)  //当秒值小于0时,将秒值置59
      miao=59;
     write_sfm(7,miao);  //将秒值写入液晶显示
     write_com(0x80+0x40+8);  //光标在秒值的个位闪烁
     write_com(0x0f);
    }
    if(num==2)
    {
     fen--;  //当num=2时,分值减一
     if(fen<0)  //当分值小于0时,将分值置59
      fen=59;
     write_sfm(4,fen);  //将分值写入液晶显示
     write_com(0x80+0x40+5);  //光标在分值的个位闪烁
     write_com(0x0f);
    }
    if(num==3)
    {
     shi--;  //当num=3时,时钟减一
     if(shi<0) //当时钟小于0时,将时钟置23
      shi=23;
     write_sfm(1,shi);  //将时钟写入液晶显示
     write_com(0x80+0x40+2);  //光标在时钟的个位闪烁
     write_com(0x0f);
        }
    if(num==4)
    {
     nian--;  //当num=4时,年减一
     if(nian<0)  //当年小于0时,将年置99
      nian=99;
     write_nyr(3,nian);  //将年写入液晶显示
     write_com(0x80+4);  //光标在年的个位闪烁
     write_com(0x0f);
    }
    if(num==5)
    {
     yue--;  //当num=5时,月减一
     if(yue<1)  //当月小于1时,将月置12
      yue=12;
     write_nyr(6,yue);   //将月写入液晶显示
     write_com(0x80+7);  //光标在月的个位闪烁
     write_com(0x0f);
    }
    if(num==6)
    {
     ri--;  //当num=6时,日减一
     temp=day_num(nian,yue);
    if(ri>temp)
     ri=temp;
     if(ri<1)  //当日小于1时,将日置为当月的天数
      ri=temp;
     write_nyr(9,ri);  //将日写入液晶显示
     write_com(0x80+10);  //光标在月的个位闪烁
     write_com(0x0f);
    }
    if(num==7)
    {
     xingqi--;  //当num=7时,星期加一
     if(xingqi<1)  //当星期小于1时,将星期置7
      xingqi=7;
     write_xq(xingqi);  //将星期写入液晶显示
     write_com(0x80+14);  //光标在星期的个位闪烁
     write_com(0x0f);
    }
   }
  }
}
}
/*--------------
? 初始化时钟函数
--------------*/
void set_time()
{
write_ds(0,0);  //初始化时钟秒钟的数值为0
write_ds(2,0); //初始化时钟分钟的数值为0
write_ds(4,1); //初始化时钟小时的数值为1
write_ds(6,1); //初始化时钟星期的数值为1
write_ds(7,1); //初始化时钟日的数值为1
write_ds(8,1); //初始化时钟月的数值为1
write_ds(9,0); //初始化时钟年的数值为0
}
/*------------
? 初始化程序
------------*/
void init()
{
uchar i;
dula=0;         //关段锁存器(不让数码管显示)
wela=0;    //关位锁存器
lcden=0;
write_com(0x38); //设置16*2显示,5*7点阵,8位数据接口(LCD初始化设置)
write_com(0x0c);  //设置开显示,不显示光标(LCD初始化设置)
write_com(0x06);  //写一个字符后地址指针自动加一(LCD初始化设置)
write_com(0x01);  //显示清零,数据指针清零(LCD初始化设置)
write_com(0x80);  //将数据指针定位到第一行第一字处
for(i=0;i<16;i++)
{
  write_date(table1[i]);  //将字符串1写入液晶
}  
write_com(0x80+0x40);  //将数据指针定位到第2行第1字处
for(i=0;i<16;i++)
{
   write_date(table2[i]);  //将字符串2写入液晶
}
set_time();  //初始化时钟
}
void main()
{
init();  //调用初始化子程序
while(1)
{
  keyscan();
  if(flag1==0)  //当标志位flag1等于0时,才从DS12C887中读取数据并送去液晶显示
  {
   miao=read_ds(0);  //从DS12C887中读取秒的值
   write_sfm(7,miao);  //将秒值送去液晶显示
   fen=read_ds(0x02);  //从DS12C887中读取分的值
   write_sfm(4,fen);  //将分值送去液晶显示
   shi=read_ds(0x04);  //从DS12C887中读取小时的值
   write_sfm(1,shi);  //将小时送去液晶显示
   nian=read_ds(0x09);  //从DS12C887中读取年的值
   write_nyr(3,nian);  //将年值送去液晶显示
   yue=read_ds(0x08);  //从DS12C887中读取月份的值
   write_nyr(6,yue);  //将月份送去液晶显示
   ri=read_ds(0x07);  //从DS12C887中读取日的值
   temp1=day_num(nian,yue);  //读取当月的天数值
   if(ri>temp1)  //判断DS12C887中的天数值是否大于当月应有的天数,如大于则将天数值置1,如有需要请重新设置
    ri=1;
   write_nyr(9,ri);  //将日值送去液晶显示
   xingqi=read_ds(0x06);  //从DS12C887中读取星期的值
   write_xq(xingqi);  //将星期送去液晶显示
  }
}
}
沙发
feiqi1| | 2018-3-25 20:14 | 只看该作者
我下载过这个,没有C语言主程序,想在里面加点其他程序就没法加了

使用特权

评论回复
板凳
androidbus| | 2018-3-25 20:16 | 只看该作者
适当修改参数,可能是晶振的问题

使用特权

评论回复
地板
litengg| | 2018-3-25 20:18 | 只看该作者
仿真电路和Hex文件能在清华出版社网站免费下载,程序源代码只能到书上看了。

使用特权

评论回复
5
qiangweii| | 2018-3-25 20:19 | 只看该作者
到图书馆借,或到新华书店翻阅,或到网上书店打折购买。

使用特权

评论回复
6
shashaa| | 2018-3-25 20:21 | 只看该作者
不加网络标号就等于没和单片机连接,仿真肯定不行的

使用特权

评论回复
7
shashaa| | 2018-3-25 20:21 | 只看该作者
P0口加上上拉电阻试试

使用特权

评论回复
8
xia00| | 2018-3-25 20:24 | 只看该作者
Proteus仿真,确认有效

234617he7bwqbwwn57bceb.jpg (390.35 KB )

234617he7bwqbwwn57bceb.jpg

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

161

主题

1233

帖子

1

粉丝