找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 3471|回复: 14
收起左侧

利用单片机最小系统外接DS12C887在LCD1602上显示实时时钟

  [复制链接]
ID:897960 发表于 2021-6-15 14:44 | 显示全部楼层 |阅读模式
- 我在上一篇文章中焊接了单片机最小系统板,并且成功驱动了LCD1602,我没有在最后展示LCD显示部分,就放到这篇文章在外接DS12C887的情况下和大家分享一下。
- 需要准备的模块如下:
- 1.单片机的最小系统板(最好有复位电路)另外20引脚(地)和40引脚vcc要多引出来6个(后面接杜邦线很多地方要用)
- 2.DS12C887时钟芯片(24脚的)
- 3.LCD1602模块
这里的DS12C887买回不能直接用,得像51芯片一样焊接个底座出来,旁边两列焊接两列排针,作为芯片的引脚。焊接好的效果图如下


因为要驱动LCD1602,电位器也是必不可少的,我把电位器单独焊接在了另外一块板子上,这个焊接地方没有要求,合理安排空间即可,焊接电位器也要利用排针引出三个角,对于3296型电位器的各引脚说明如下1脚VCC,3脚GND,2脚接输出。电位器的大小选择位10k,如图

还需要准备4个轻触按键,因为设置时钟时,需要选择功能、增大键、减小键、闹钟查看键(我的板子上没有焊接蜂鸣器,所以闹钟到点后,不会响,蜂鸣器是一个比较简单的模块,代码里面都有定义,我在焊接的时候把他先忽视了,需要的话,外加上蜂鸣器模块,看一下程序里的引脚定义就可以)
4个轻触按键的接法从上到下排列,分别为功能选择、增大、减小、闹钟查看。此处的焊接为选择每个按键的两个对角引脚,每个按键选择的两个引脚要相同,从上到下在板子上安插好,
按键图.png 按键原理图.png

原理图和实物图引脚一一对应,我们可以选择1脚输出,4脚接地(对角接通)4个按键的4号脚连接在一起并且引出一个插针到时候直接接单片机的GND完成接地,再把每个按键的1号脚用插针引出来,接代码里定义的按键引脚。
在这里我给大家看一下DS12C887的芯片接法!
DS12C887实物图.png DS12C887引脚图.png
我从左边最上边开始逆时针转一圈来说明各引脚的接法
从第四引脚开始接4-11为数据传输,接单片机的P0口,12脚接单片机20脚的GND。
13脚cs接P1^4
14脚as接P1^5
15脚rw接P1^6
17脚ds接P1^7
18脚RESET接VCC
19脚IRQ接P3^3
24脚接VCC
现在DS12C887模块的准备工作都完成了。只剩下LCD1602的接线部分,原理图如下
1602接口.png
1602液晶上都有每个管脚的名称,可以对照着原理图来接线
1602实物图.JPG
从左向右,1脚接地,2脚接vcc,3脚接电位器的第二脚,rs接单片机的P3^5,rw接地,E接单片机的P3*4,D0-D7接单片机的P2口,A、K为背光电源,A接vcc,K接gnd。至此所有外接模块安装包括接口对应引脚都完成了。

```c
/*总体要求*/
/*在1602上显示年月日星期时分秒,并且按照秒来实时更新显示
  可以闹钟设定,到点报警功能,报警响起时,任意键可以取消报警
  四个按键,根据功能可以调节参数,分别为功能键,数值增大键,数值减少键,闹钟查看键,
  每次按键按下,蜂鸣器都会滴一声,
  利用DS12C887实现断电后,再次上电,时间仍可以准确显示 */
  /*另外这个程序中文部分是学习了一个半月C语言的人的理解,难免有错误的地方
  如果你想移植程序,除了开头的各种脚需要修改,程序里面1602和DS12C887的写指令写数据,读指令读数据的IO口也要修改
  应该是有4~6处,一定要注意,不然你的程序不会亮起来,然后初始化部分,记得初始化后去掉,但是仿真的时候不要去掉,去掉没法显示*/
  /*非常非常非常重要的一个细节,总线上要加    AD[0..7]         这个名字,如果没有永远也仿真不起来*/
#include<reg52.h>                         //52系列单片机机头文件
#define uchar unsigned char               //宏定义 定义一个无符号字符型数据
#define uint  unsigned int                       //宏定义 定义一个无符号整型数据
sbit lcdrs=P3^5;                          //自定义数据/命令选择端口
sbit lcden=P3^4;                          //自定义使能信号
//sbit dula=P2^6;
//sbit wela=P2^7;                                          /*P0口接液晶1602和时钟芯片DS12C887的AD0-AD7*/
sbit beep=P2^3;                           //蜂鸣器。有的按键接rd为低电平,就需要也定义一下rd,我这里面四个按键采用的是接地的结构!
sbit dscs=P1^4;                                                          //定义地址选通输入端 (读到那里去)
sbit dsas=P1^5;                                                          //定义芯片片选端           (读哪个芯片)
sbit dsrw=P1^6;                                                          //定义读数据允许输入脚,这里mot接地        (让不让读的开关)
sbit dsds=P1^7;                                                  //定义中断请求输出
sbit dsirq=P3^3;                                                           //定义读允许输入           (让读以后,我来输入数据)
sbit lcdrd=P3^7;                                                

sbit s1=P1^0;                                  //功能键        
sbit s2=P1^1;                                                          //数值增大键
sbit s3=P1^2;                                                          //数值减少键
sbit s4=P1^3;                                                          //闹钟查看键
                                                                                  //因为功能键要8次才能推出,这里可以加一个直接退出按键,可以放在外部中断上
bit    flag1, flag_ri;                                      //定义两个位变量
uchar  count,s1num,flag,t0_num;                             //定义几个无符号字符型数据,用到时再解释定义干啥用的
char   miao,shi,fen,year,month,day,week,amiao,afen,ashi;    //定义几个字符型数据,这个基本上都能理解。
uchar  code table[]=" 20  -  -      ";                          //让液晶固定显示的内容
uchar  code table1[]="      :  :  ";                                //让液晶固定显示的内容
void   write_ds(uchar, uchar);                                            //函数申明           寄存器初始化
void   set_alarm(uchar, uchar, uchar);                            //函数申明           设定闹钟
void   read_alarm();                                                                //函数申明           读报警器
void   set_time();                                                                    //函数申明       寄存器初始化
void   delay(uint z)                                                                //延时函数
{                                                                                 
  uint x,y;                                                                  //定义两个无符号整形数
  for(x=z;x>0;x--)                                                  //如果x>0,则y执行110次
     for(y=110;y>0;y--);                                  //本小段为单位是1ms的延时
}
void di()                                                                  //蜂鸣器报警
{
beep=0;                                                                  //低电平有效,蜂鸣器开始蜂鸣
delay(100);                                                          //延时100毫秒,响0.1秒
beep=1;                                                                  //蜂鸣器停止鸣叫
}
void write_com(uchar com)                                   //写液晶命令函数
{
  lcdrs=0;                                                                   //rs低电平,表示要写命令
  lcden=0;                                                                   //en低电平,表示为了下面送入数据,防止此时还是高电平,无法制造高脉冲
  P2=com;                                                                   //D0-D7我接的是P0上面,数据送给它
  delay(3);                                                                   //延时3ms
  lcden=1;                                                                   //en高电平,延时三秒        再变成低电平,完成一次高脉冲,使数据送入液晶显示屏
  delay(3);                                                                   //表示接下来,液晶显示屏可以过来读数据了
  lcden=0;
}
void write_date(uchar date)                                   //写液晶数据函数
{
lcdrs=1;                                                                   //高电平表示要写数据
lcden=0;                                                                   //en低电平,表示为了下面送入数据,防止此时还是高电平,无法制造高脉冲
P2=date;                                                                   //D0-D7我接的是P0上面,数据送给它
delay(3);                                                                   //延时3ms
lcden=1;                                                                   //en高电平,延时三秒        再变成低电平,完成一次高脉冲,使数据送入液晶显示屏
delay(3);                                                                   //表示接下来,液晶显示屏可以过来读数据了
lcden=0;
}
void init()                                //液晶初始化
{
  uchar  num;                                                           //定义一个字符
  EA=1;                                                                           //打开全局中断控制
  EX1=1;                                                                   //打开外部中断1中断
  IT1=1;                                                                   //设置负跳变沿触发中断
  flag=0;                                                                   // 自定义字符全部归零,为了方便实用
  flag1=0;
  s1num=0;                                                                        //键盘按下的次数
  week=1;                                                                   //星期显示最低也是周一的一
  lcden=0;                                                                   //使能信号定义为零,表示还没有数据
  lcdrd=0;
//  dula=0;//关闭数码管显示
//        wela=0;
  write_ds(0x0A,0x20);                                           //首次使用ds12c887时使用,以后不必在写。打开振荡器
  write_ds(0x0B,0x26);                                            // 设置24小时模式,数据二进制格式,开启闹钟中断。
                                            //0A,0B表示地址,20,26翻译成二进制是00100000,00100110对应着对着寄存器A和B从D7-D0
  set_time();                                                           //设置默认上电时间
  write_com(0x38);                                                   //设置16x2显示,5x7点阵,8位数据接口
  write_com(0x0c);                                                   //设置开显示,不显示光标
  write_com(0x06);                                                   //写一个字符后,地址指针自动加1
  write_com(0x01);                                                   //显示清0,数据指针清0

  write_com(0x80);                                                   //设置数据指针位置,此处时数据指针第一行,第一处
  for(num=0;num<15;num++)                                   //<15原因是第一行显示的数字或者空格一共14个
  {
    write_date(table[num]);                                   //把要显示的数据送入到液晶的第一行
        delay(1);                                                           //延迟一毫秒
  }

    write_com(0x80+0x40);                                   //设置数据指针位置,此处时数据指针第二行,第一处
    for(num=0;num<11;num++)                                   //<11原因是第二行显示的数字或者空格一共10个
  {
    write_date(table1[num]);                                   //把要显示的数据送入到液晶的第二行
        delay(1);                                                           //延迟一毫秒
  }
}
void write_sfm(uchar add,char date)                   //1602液晶刷新时分秒函数4为时,7为分,10为秒          ,4.7.10均是显示位置
{   
   char shi,ge;                                                           //定义两个数,来表示十位数和个位数
   shi=date/10;                                                           // 要送去显示的十位
   ge=date%10;                                                           //要送去显示的个位  
   write_com(0x80+0x40+add);                                   //时间是在第二行显示,所以是加0X40,在add处显示
   write_date(0x30+shi);                                   //shi和ge都是整形数值,但是液晶1602是内置ASCII表格,0在第048位
   write_date(0x30+ge);                                           //转成十六进制就是0x30,
}
/*这个地方可能会有人迷糊,设置时分秒,怎么只设置十位和个,好像给人的感觉就是只设置时位,和分位,秒位怎么不设置,
实际上是,这里写入并显示的是  把时的十位和个位,分的十位和个位,秒的十位和个位,分别送去进行运算 ,然后先写命令确定位置,
再写数据,用来显示,下面一个子函数也是同样的道理*/
void write_nyr(uchar add,char date)                   //1602液晶刷新年月日函数,3为年,6为月9为天         ,369也分别是位置
{   
   char shi,ge;                                                           //定义两个数,来表示十位数和个位数
   shi=date/10;                                                           // 要送去显示的十位
   ge=date%10;                                                           //要送去显示的个位  
   write_com(0x80+add);                                   //时间是在第二行显示,所以是加0X40,在add处显示
   write_date(0x30+shi);                                   //shi和ge都是整形数值,但是液晶1602是内置ASCII表格,0在第048位
   write_date(0x30+ge);                                           //转成十六进制就是0x30,
}   /*实际上到了主函数,时分秒,年月日会有六个子函数进行分别调用,这里用两个子函数来表示,不能用一个的原因是显示的内容不在一行,
主要是写入命令的位置不一样,大家可以观察一下*/
void write_week(char we)                                        //写液晶1602星期显示函数   
{
  write_com(0x80+12);                                                //让we在0x80+12这个位置显示
  switch(we)                                                                //多分支结构的条件选择语句,we等于几就去执行几号分支
  {
   case 1:write_date('M');                                   //写入M。整个的意思是如果we等于1,则显示MON,即星期一
          delay(5);                                                   //延时5毫秒后写入O
                  write_date('O');                                   //写入O
          delay(5);                                                   //延时5毫秒后写入N
                write_date('N');                                   //写入N
          break;                                                   //间断,为了和后面分开
   case 2:write_date('T');                                   //写入T。整个的意思是如果we等于2,则显示TUE,即星期二
          delay(5);                                                   //延时5毫秒后写入U
                  write_date('U');                                   //写入U
          delay(5);                                                   //延时5毫秒后写入E
                write_date('E');                                   //写入E
          break;                                                   // 间断,为了和后面分开
   case 3:write_date('W');                                   //写入W。整个的意思是如果we等于3,则显示WED,即星期三
          delay(5);                                                   //延时5毫秒后写入E
                  write_date('E');                                   //写入E
          delay(5);                                                   //延时5毫秒后写入D
                write_date('D');                                   //写入D
          break;                                                   //间断,为了和后面分开
   case 4:write_date('T');                                   //写入T。整个的意思是如果we等于4,则显示THU,即星期四
          delay(5);                                                   //延时5毫秒后写入H
                  write_date('H');                                   //写入H
          delay(5);                                                   //延时5毫秒后写入U
                write_date('U');                                   //写入U
          break;                                                   //间断,为了和后面分开
   case 5:write_date('F');                                   //写入F。整个的意思是如果we等于5,则显示FRI,即星期五
          delay(5);                                                   //延时5毫秒后写入R
                  write_date('R');                                   //写入R
          delay(5);                                                   //延时5毫秒后写入I
                write_date('I');                                   //写入I
          break;                                                   //间断,为了和后面分开
   case 6:write_date('S');                                   //写入S。整个的意思是如果we等于6,则显示SAT,即星期六
          delay(5);                                                   //延时5毫秒后写入A
                  write_date('A');                                   //写入A
          delay(5);                                                   //延时5毫秒后写入T
                write_date('T');                                   //写入T
          break;                                                   //间断,为了和后面分开
   case 7:write_date('S');                                   //写入S。整个的意思是如果we等于7,则显示SUN,即星期日
          delay(5);                                                   //延时5毫秒后写入U
                  write_date('U');                                   //写入U
          delay(5);                                                   //延时5毫秒后写入N
                write_date('N');                                   //写入N
          break;                                                   //间断,为了和后面分开
        
   }
}
void keyscan()                                                           //数字时钟按键扫描函数
{
   if(flag_ri==1)                                                   //如果标志位,闹钟等于1,则蜂鸣器会响 ,这一句和按键扫描没有关系,主要是为了任意键可以消除
                                           //闹钟的报警,可以理解为,为闹钟取消而增加的一个扫描小程序。
   {
        if((s1==0)||(s2==0)||(s3==0)||(s4==0))        //如果s1-s4有一个为零,低电平         ||这个符号是关系运算符, 或的意思,有一个是低电平,则进行下一步。
        {
         delay(5);                                                                //延时去抖动
         if((s1==0)||(s2==0)||(s3==0)||(s4==0))        //再次确认,如果s1-s4有一个为零,低电平
         {
           while(!(s1&&s2&&s3&&s4));                        /*/如果他们运算的结果为0         ,当闹钟响起,就会进入这个按键扫描程序,这没有按下键盘的时候,
           就会运行到这里,进行判断循环,一直等在,四个按键,有一个为0,这个语句就会判断为假,进行下一步运算,&&这个符号是关系运算的 与,
           一个值为零,则整体结果运算为0*/
           di();                                                            //则蜂鸣器会响,闹钟有自己的蜂鸣程序,这里有个DI主要原因是,每次按键 都会响,这是事先规定号的
           flag_ri=0;                                                        //清除报警标志
         }
        }
   }

  if(s1==0)                                                                          //检测按键s1
  {
   delay(5);                                                                  //延时5毫秒,也可叫延时去抖动。
   if(s1==0)                                                                  //再次检测按键s1
   {
    s1num++;                                                                  //定义为键盘按下的次数
        if(flag1 == 1)                                                          //这个是用来闹钟的,如果等予1,说明现在是在设置闹钟值,从下面来看这个只能调节每天的闹钟,不能调节年月
           if(s1num == 4)                                                 //因为只能调节时分秒,让他们在里面循环
              s1num=1;                                                          //这个地方我卡了几天,大家要综合前后文,明白flag1是闹钟被按下了,flag是为了跳出主程序循环,为了设置时间
        flag=1;                                                                      //按键计数以后,则这个位变量变成1,
        while(!s1);                                                                  /*!s1 的意思是取s1相反的数,是用来测试判断按键按下后有没有松开,松开则计数一次后,电平
                                                                       变成高电平,说明此时已经松开,也确定了s1num的具体数值,也就是按了几下*/
        di();                                                                          //每按下一次则响一声
        switch(s1num)                                                          //判断是按了几下,则选择什么位置光标点闪烁。
        {
                case 1:write_com(0x80+0x40+10);                  //很明显这是显示屏第二行的显示指令,10  说明光标调节的是秒
                       write_com(0x0f);                       /*/不管你按的再快,光标也会从第一步开始,所以把 开显示,显示光标,光标闪烁  这个lcd的这个
                                                                                             指令设置放在这里        */
                           break;                                                  //会不停的跳出,再去问现在是按了几下了,按了几下,就会进入对应的里面,下面都是一样的不解释了。
                case 2:write_com(0x80+0x40+7);               /*这个就是光标在分钟上闪烁,(不光时分秒都是在他们的十位闪烁,
                                                       如果送的是两位数,LCD的指针可以自动加一,把个位也给显示了)*/
                           break;
                case 3:write_com(0x80+0x40+4);               //这个是在小时的位置显示闪烁
                           break;
                case 4:write_com(0x80+12);                           //这就是进入显示屏第一行了,在显示星期的位置,第十位,最右边,是调节星期的位置。
                           break;
                case 5:write_com(0x80+9);                             //日
                           break;
                case 6:write_com(0x80+6);                             //月
                           break;
                case 7:write_com(0x80+3);                               //年
                           break;
                case 8:s1num=0;                                                          //把按键数置零,等这个小程序运行完,则光标不在闪缩,一切正常运行。相当于不选择任何位置。
                       write_com(0x0c);                                          //设置开显示,不显示光标
                           flag=0;                                                          //等于0就是回到主程序的正常运行(可以参看以下主程序,更能方便理解)
                                /*下面的几句基本一样,明白一个就全明白了,这个地方主要是查表,查寄存器A,功能列表有时分秒,闹钟的也有时分秒,年月日他们分别
                                对应的寄存器地址,比如秒对应的是00H,分钟对应的是02H,所以0,2,4,6,7,8,9都是地址,往这个里面写,就是写的时分秒,
                                可能有人问,既然是00H,02H,为什么写成0,2等等,其实是因为十六进制和十进制在0~9,书写虽然有区别,但是结果都一样*/
                           write_ds(0,miao);                                   
                           write_ds(2,fen);
                           write_ds(4,shi);
                           write_ds(6,week);
                           write_ds(7,day);
                           write_ds(8,month);
                           write_ds(9,year);
                           break;                                   //跳出
        }
   }
  }
  if(s1num!=0)                                            //测试不等于 0,也就是只有当s1按下时才能检测和用来启动s2和s3.
  {
   if(s2==0)                                               //问S2按键有没有按下
   {
        delay(1);                                                                                 //延时1毫秒
        if(s2==0)                                                                                 //再次来检测
        {
          while(!s2);                                                                          //给s2取反
          di();                                                                                         //滴一声
          switch(s1num)                                                                         //根据s1按下的次数,来确定调节哪个位置
          {                                                                                                    //下面给大家解释一组,应该可以全部明白
           case 1:miao++;                                                                 //按键s2按一下,这里就会加一          设置秒钟
                  if(miao==60)                                                          //如果加到了60 ,秒就会变成0
                             miao=0;
                     write_sfm(10,miao);                         //把秒的值经过运算,送到LCD相应的位置去显示
                         write_com(0x80+0x40+10);                /*这一句是调用写指令,因为指针把秒显示完毕后,光标就会在秒的个位,
                                                                 所以这一句是把光标在拉回来,因为不能正好一下子就把秒的值设置的正好*/
                         break;                                                         //然后跳出,等待按键再次按下
           case 2:fen++;                                                     //设置分钟
                  if(fen==60)                                             //分,秒都用到60,生活中并没有60,这里也不能设置成59,但是可以改程序为>59.道理是一样的
                             fen=0;
                         write_sfm(7,fen);
                         write_com(0x80+0x40+7);
                         break;
           case 3:shi++;                                                      //设置时钟
                  if(shi==24)                                               //和上面一样的道理
                             shi=0;
                          write_sfm(4,shi);
                          write_com(0x80+0x40+4);
                          break;
           case        4:week++;                                                  //设置星期
                  if(week ==8)                                              //当按下第八次的时候,则8就会变成1
                             week=1;
                          write_week(week);
                          write_com(0x80+12);
                          break;
          case 5:day++;                                                            //设置天数
                 if(day==32)                          
                            day=1;
                         write_nyr(9,day);
                         write_com(0x80+9);
                         break;
         case 6:month++;                                               //设置月数
                if(month==13)
                           month=1;
                        write_nyr(6,month);
                        write_com(0x80+6);
                        break;
        case 7:year++;                                                            //设置年
               if(year==100)
                      year=0;
                         write_nyr(3,year);
                         write_com(0x80+3);
                         break;         
          }
    }
   }
   if(s3==0)                                               //上面是增大键,下面就是减少键
   {
        delay(1);                                               //延迟1毫秒
        if(s3==0)                                              //再次判断有没有按下
        {
          while(!s3);                                     //取相反数,看看是不是为真
          di();
          switch(s1num)                                          //根据按键1,就可以确定光标在什么位置,下面介绍和上面基本上一样,
          {                                                                      //只不过没有60了,反而有59,可以好好理解一下,其实很简单这个地方,就不解释了
           case 1:miao--;                                                   //设置秒钟
                  if(miao==-1)
                             miao=59;
                     write_sfm(10,miao);
                         write_com(0x80+0x40+10);
                         break;
           case 2:fen--;                                                  //设置分钟
                  if(fen==-1)
                             fen=59;
                         write_sfm(7,fen);
                         write_com(0x80+0x40+7);
                         break;
           case 3:shi--;                                                      //设置小时
                  if(shi==-1)
                             shi=23;
                          write_sfm(4,shi);
                          write_com(0x80+0x40+4);
                          break;
           case        4:week--;                                                      //设置星期
                  if(week==-0)
                             week=7;
                          write_week(week);
                          write_com(0x80+12);
                          break;
           case 5:day--;                                                      //设置天数
                  if(day==0)
                             day=31;
                           write_nyr(9,day);
                          write_com(0x80+9);
                          break;
           case 6:month--;                                                       //设置月数
                 if(month==0)
                            month=12;
                         write_nyr(6,month);
                         write_com(0x80+6);
                         break;
            case 7:year--;                                                         //设置年
                 if(year==-1)
                      year=99;
                         write_nyr(3,year);
                         write_com(0x80+3);
                         break;         
          }
    }
   }
  }
  if(s4==0)                                                         //这个地方是闹钟设置键
  {
   delay(5);                                                     //延时5毫秒
   if(s4==0)                                                     //再次判断是否按下
   {
        flag1=~flag1;                                            //如果按下,则按键1程序,进入时分秒的循环,这里的讲解和前面相呼应。
        while(!s4);                                                     //取反是不是为真
        di();                                                             //为真说明,有按键按下,响一声,
        s1num=0;                                                                                                
        /*调试仿真时发现如果按下了按键一  在按闹钟,然后取消闹钟,在按按键一,会不出现光标,为了让闹钟和按键一不冲突,我添加这一句
        每当我按下按键一,不管按几次,只要按下按键4,都会让光标变成0位 */
        if(flag1==0)                                             //如果等于0,说明按得第二下,属于退出闹钟设置。
        {
         flag=0;                                                                                                 //程序运行到这一步,说明运行完这个程序,就要回到主程序了,
                                                                 //把按键1标志指令以后,本程序结束,可以进入主程序,否则还要在去按键1,按几下     
         write_com(0x80+0x40);                                                                         //把指针选择第二行,第一位,
         write_date(' ');                                                                                 //写入两个空的符号,主要是为了区别状态,是调整时间还是设置闹钟
         write_date(' ');
         write_com(0x0c);                                                                                  //关闭光标闪烁
         write_ds(1,miao);                                                                                  //把时分秒送到DS12C887,程序正常运行
         write_ds(3,fen);                                                                                  //这个时候的135要注意,可以看出是新设置闹钟值
         write_ds(5,shi);
        }
        else                                                                                                           //如果flag不等于0,则进入这个程序,实际上程序都是先运行这个
        {                                                                                                                   //进入闹钟设置
         read_alarm();                                                                                           //读闹钟原来的数据
         miao=amiao;                                                                                           //分别送入时分秒
         fen=afen;
         shi=ashi;
         write_com(0x80+0x40);                                                                           //写指令,把指针,也就是光标位置放在第二排第一位
         write_date('R');                                                                                   //分别送入R  I送去显示,可以区分现在是在调整时间,还是修改闹钟
         write_date('I');
         write_com(0x80+0x40+3);                                                                   /*这个地方还有一个指针,就会让很多人不理解,其实这个地方设计很巧妙
                                                                   3号位置,正好是时钟前面一位,然后再那边闪烁,接着等待按键1,来选择调整时分秒,
                                                                                                                           按一下变换一个位置,在3号位闪烁还不影响开始时的闹钟值*/
                                                                    
         write_sfm(4,ashi);                                                                                   //送到液晶去显示
         write_sfm(7,afen);
         write_sfm(10,amiao);
        }
   }
  }
}
void write_ds(uchar add,uchar date)                                   //写DS12C887函数
{
dscs=0;                                                                                                           //根据时序图,把相应的脚变化高低,片选端,低电平有效
dsas=1;                                                                                                           //地址选通输入端
dsds=1;                                                                                                           //读允许输入脚
dsrw=1;                                                                                                                //写输入脚
P0=add;                                                                                                                //写地址
dsas=0;
dsrw=0;
P0=date;                                                                                                            //写命令
dsrw=1;
dsas=1;
dscs=1;
}
uchar read_ds(uchar add)                                                                           //读DS12C887函数        ,这里没有用void要注意
{
uchar ds_date;                                                                                                   //定义一个无符号函数
dsas=1;                                                                                                           //根据时序图,进行高低电平设置
dsds=1;
dsrw=1;
dscs=0;
P0=add;                                                                                                           //写地址,确定要读什么位置的值
dsas=0;
dsds=0;
P0=0xff;                                                                                                           //先把P1进行置高,清理数据
ds_date=P0;                                                                                                        //把新的得到了  12c887里面的数值,赋值给ds_date
dsds=1;                                                                                                                //根据时序图继续设置电平
dsas=1;
dscs=1;
return ds_date;                                                                                           //谁调用它,什么位置调用的,就会把这个新得到的值在返回给他,
                                                                                                                           //看得出来只有读闹钟值是调用了。
}
void set_time()                                                                                           //首次操作12c887时给寄存器初始化,完成后,要把这一段用 给屏蔽起来
{
write_ds(0,0);                                                                                                  //根据寄存器A,相当于        所有的位置,全部显示00。
write_ds(1,0);
write_ds(2,0);
write_ds(3,0);
write_ds(4,0);
write_ds(5,0);
write_ds(6,0);
write_ds(7,0);
write_ds(8,0);
write_ds(9,0);
}         
void read_alarm()                                                                                          //读取闹钟值
{
amiao=read_ds(1);                                                                                           //根据寄存器A,分别把闹钟值读出来,并且赋值给时分秒
afen=read_ds(3);
ashi=read_ds(5);
}
void main()                                                                                                         //主程序
{
init();                                                                                                          //调用初始化函数
while(1)                                                                                                          //为真不断循环,等待闹钟中断
{
keyscan();                                                                                                           //按键子程序,不断地扫描
if(flag_ri==1)                                                                                                   //如果有闹钟,则进入这里
{
  di();
  delay(100);                                                                                                        //一直响 滴滴
  di();
  delay(500);
}
if((flag==0) && (flag1==0))                                                                   //如果按键标志位和闹钟标志位都为0,则继续
{
  keyscan();                                                                                                   //按键继续扫描
  year=read_ds(9);                                                                                           //把DS12C887里面的数值不断读取
  month=read_ds(8);
  day=read_ds(7);
  week=read_ds(6);
  shi=read_ds(4);
  fen=read_ds(2);
  miao=read_ds(0);
  write_sfm(10,miao);                                                                                   //这里把DS12c887的值不断地写入到lcd1602
  write_sfm(7,fen);
  write_sfm(4,shi);
  write_week(week);
  write_nyr(3,year);
  write_nyr(6,month);
  write_nyr(9,day);
}
}
}                                                                                                                        
void exter()interrupt 0                                                                            //中断1程序
{
uchar c;                                                                                                                //定义一个无符号数值
flag_ri=1;                                                                                                                //闹钟中断时间到了
c=read_ds(0x0c);                                                                                                //读取c寄存器的值,表示响应了中断
}
在这里插入代码片
电位器焊接背面图.JPG
电位器阻值大小图.JPG
电位器引脚图.JPG
电位器焊接正面图.JPG
DS12C887背面焊接图.JPG
DS12C887正面焊接图.JPG

评分

参与人数 1黑币 +50 收起 理由
admin + 50 共享资料的黑币奖励!

查看全部评分

回复

使用道具 举报

ID:897960 发表于 2021-6-17 16:39 | 显示全部楼层
有什么问题,大家可以在底下留言评论,我都会回复大家的
回复

使用道具 举报

ID:328014 发表于 2021-6-20 20:34 | 显示全部楼层
好资料,51黑有你更精彩!!!你的DS12C887时间准确度怎么样?一月大约有多少误差呢
回复

使用道具 举报

ID:940278 发表于 2021-6-20 20:49 来自手机 | 显示全部楼层
Lzxhmxy1839 发表于 2021-6-17 16:39
有什么问题,大家可以在底下留言评论,我都会回复大家的

谢谢楼主

回复

使用道具 举报

ID:940278 发表于 2021-6-20 21:28 | 显示全部楼层
好资料,51黑这网站太棒了
回复

使用道具 举报

ID:941161 发表于 2021-6-20 23:01 | 显示全部楼层
太酷炫了,牛 51黑有你更精彩!!!
回复

使用道具 举报

ID:897960 发表于 2021-6-22 15:11 | 显示全部楼层
51hei团团 发表于 2021-6-20 20:34
好资料,51黑有你更精彩!!!你的DS12C887时间准确度怎么样?一月大约有多少误差呢

ds12c887的误差的话,官方话我就不说了,我在实验的时候是是很准确的,肉眼几乎分辨不来
回复

使用道具 举报

ID:897960 发表于 2021-6-22 15:12 | 显示全部楼层

没事没事,大家也是互相学习
回复

使用道具 举报

ID:897960 发表于 2021-6-22 15:12 | 显示全部楼层
此用户不存在 发表于 2021-6-20 23:01
太酷炫了,牛 51黑有你更精彩!!!

加油,一起努力
回复

使用道具 举报

ID:58647 发表于 2021-7-6 18:20 | 显示全部楼层
这注释,详细,赞!
回复

使用道具 举报

ID:1011444 发表于 2022-5-23 13:42 | 显示全部楼层
程序注释详细,格式清晰,写得好!
回复

使用道具 举报

ID:977804 发表于 2022-5-23 18:59 来自手机 | 显示全部楼层
12887还是很准确的,实际使用一个问题是引脚多,一个是备用电池难更换
回复

使用道具 举报

ID:109865 发表于 2023-6-3 08:16 来自手机 | 显示全部楼层
1重新上电后为啥时间数据没有保存,问题出在哪,能不能给我指点一下
回复

使用道具 举报

ID:253767 发表于 2023-6-3 09:13 | 显示全部楼层
您太行了,厉害!
回复

使用道具 举报

ID:109865 发表于 2023-6-3 13:04 | 显示全部楼层
中断使用的外部中断1,但是代码是interrupt 0,应该是interrupt 2,否则闹钟不好使
回复

使用道具 举报

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

本版积分规则

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

Powered by 单片机教程网

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