找回密码
 立即注册

QQ登录

只需一步,快速开始

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

基于单片机的计算器与万年历仿真,PCB电路图与源程序分享

[复制链接]
跳转到指定楼层
楼主
Proteus仿真和电路图还有源程序在本帖附件中下载.
制作出来的实物图:


Altium Designer画的计算器与万年历原理图和PCB图如下:(51hei附件中可下载工程文件)


计算器与万年历仿真原理图如下(proteus仿真工程文件可到本帖附件中下载)


单片机计算器与万年历源程序如下:
  1. #include <reg52.h>
  2. #include <intrins.h>  //包含_nop_()函数定义的头文件
  3. #define uchar unsigned char
  4. #define uint  unsigned int
  5. //以下是对1302的定义
  6. sbit  clk= P2^3;              //实时时钟时钟线引脚
  7. sbit  IO= P2^2;              //实时时钟数据线引脚
  8. sbit  rst =P2^1;              //实时时钟复位线引脚
  9. uchar second,minute,hour,week,day,month,year;       //8421码表示的时间  高四位用于表示十位,低四位用于表示个位
  10. char second1,minute1,hour1,week1,day1,month1,year1;//十进制表示的时间  也即普通意义下的时间
  11. uchar read_byte(uchar com);
  12. uchar readyear_byte(uchar com);
  13. void write_byte(uchar com,uchar date);
  14. void init_1302();
  15. void readtime();
  16. //以下是对lcd1602的定义
  17. sbit wela=P2^6;
  18. sbit dula=P2^7;
  19. uchar table[]="0123456789";
  20. sbit LCM_RS=P2^6;    //寄存器选择位,将RS位定义为P2.6引脚
  21. sbit LCM_EN=P2^5;     //使能信号位,将E位定义为P2.5引脚
  22. bit lcd_bz(void);
  23. void write_com(unsigned char CMD);
  24. void write_date(unsigned char dataW);
  25. void init_1602();
  26. void displaytime();
  27. void delaynms(unsigned char n);
  28. //以下是对按键调时程序的定义
  29. sbit mode=P1^0;         //调整闹钟或者时间时的选择按键
  30. sbit plus=P1^1;         //加1键
  31. sbit minus=P1^2; //减1键
  32. sbit s1=P1^3;         //计算器和万年历切换键
  33. void key();
  34. void delay20ms();
  35. //以下是对温度采集部分的定义
  36. sbit DS=P2^0;                          //DS18B20数据端口
  37. uchar code wendu[]="0123456789";        //利用一个温度表解决温度显示乱码
  38. void write_byte(uchar com,uchar date);         //写一个字节
  39. void tmpDelay(int num);                                        // 延时
  40. void Init_DS18B20();                                        //初始化DS18B20
  41. unsigned char ReadOneChar();                    //读一个字节
  42. void WriteOneChar(unsigned char dat);        //写数据
  43. unsigned int Readtemp();                                //读温度
  44. void display();                                                        //显示温度

  45. uchar num;         
  46. sbit lcden=P2^5; //定义引脚
  47. sbit rs=P2^6;

  48. sbit busy=P0^7;         //LCD1602忙
  49. //计算器有关变量定义
  50. char i,j,temp,num_1,num1_2=0;
  51. long a,b,c;     //a,第一个数 b,第二个数 c,得数
  52. float a_c,b_c;
  53. uchar flag,fuhao;//flag表示是否有符号键按下,fuhao表征按下的是哪个符号

  54. uchar code table1[]={
  55. 7,8,9,0,
  56. 4,5,6,0,
  57. 1,2,3,0,
  58. 0,0,0,0};
  59. uchar code table2[]={
  60. 7,8,9,0x2f-0x30,
  61. 4,5,6,0x2a-0x30,
  62. 1,2,3,0x2d-0x30,
  63. 0x01-0x30,0,0x3d-0x30,0x2b-0x30};

  64. void delay2(uchar z) // 延迟函数
  65. {
  66. uchar y;
  67. for(z;z>0;z--)
  68.    for(y=0;y<110;y++);
  69. }

  70. void check() // 判断忙或空闲
  71. {
  72. do{
  73.     P0=0xFF;    rs=0;     //指令
  74.     lcden=0;     //禁止读写
  75.     delay2(1); //等待,液晶显示器处理数据
  76.     lcden=1;     //允许读写
  77.         delay2(1);        busy=0;
  78.     }while(busy==1); //判断是否为空闲,1为忙,0为空闲
  79. }
  80. void write_com1(uchar com) // 写指令函数
  81. {
  82. P0=com;    //com指令付给P0口
  83. rs=0;lcden=0;
  84. check();lcden=1;
  85. }

  86. void write_date1(uchar date) // 写数据函数
  87. {
  88.         P0=date;
  89.         rs=1;
  90.         lcden=0;
  91.         check();
  92.         lcden=1;
  93. }

  94. void init1() //初始化
  95. {
  96.         num=-1;
  97.         lcden=1; //使能信号为高电平
  98.         write_com1(0x38); //8位,2行
  99.         delay2(5);
  100.         write_com1(0x38); //8位,2行
  101.         delay2(5);
  102.         write_com1(0x0c); //显示开,光标关,不闪烁*/
  103.         delay2(1);
  104.         write_com1(0x06); //增量方式不移位
  105.         delay2(1);
  106.         write_com1(0x80); //检测忙信号
  107.         delay2(1);
  108.         write_com1(0x01); //显示开,光标关,不闪烁
  109.         num_1=0;
  110.         i=0;
  111.         j=0;
  112.         a=0;     //第一个参与运算的数
  113.         b=0;     //第二个参与运算的数
  114.         c=0;
  115.         flag=0; //flag表示是否有符号键按下,
  116.         fuhao=0; // fuhao表征按下的是哪个符号
  117. }
  118. void keyscan1() // 键盘扫描程序
  119. {
  120.         P3=0xfe;
  121.         if(P3!=0xfe)
  122.         {   delay2(20);// 延迟20ms
  123.            if(P3!=0xfe) { temp=P3&0xf0;
  124.                                     switch(temp)
  125.                                     {
  126.                                      case 0xe0:num=0;      break;
  127.                                      case 0xd0:num=1;      break;
  128.                                      case 0xb0:num=2;      break;
  129.                                      case 0x70:num=3;      break;
  130.                                     }
  131.            } while(P3!=0xfe);
  132.            if(num==0||num==1||num==2)//如果按下的是'7','8'或'9
  133.            {
  134.                if(j!=0){ write_com1(0x01);  j=0;  }
  135.                if(flag==0){  a=a*10+table1[num];  }//没有按过符号键            
  136.                else{ b=b*10+table1[num];  }//如果按过符号键            
  137.            }
  138.            else//如果按下的是'/'
  139.            {  flag=1; fuhao=4;}//4表示除号已按   
  140.            i=table2[num];   write_date1(0x30+i);
  141.         }

  142.         P3=0xfd;
  143.         if(P3!=0xfd)
  144.         {  delay2(20);
  145.            if(P3!=0xfd){ temp=P3&0xf0;
  146.                                     switch(temp)
  147.                                     {
  148.                                      case 0xe0:num=4;  break;
  149.                                      case 0xd0:num=5;  break;
  150.                                      case 0xb0:num=6;  break;
  151.                                      case 0x70:num=7; break;
  152.                                     }
  153.            } while(P3!=0xfd);
  154.            if(num==4||num==5||num==6&&num!=7)//如果按下的是'4','5'或'6'
  155.            {
  156.                     if(j!=0){write_com1(0x01); j=0;}
  157.                     if(flag==0){  a=a*10+table1[num];   }//没有按过符号键              
  158.                     else{  b=b*10+table1[num];   }//如果按过符号键            
  159.            }
  160.            else//如果按下的是'/'
  161.            { flag=1;   fuhao=3;}//3表示乘号已按           
  162.            i=table2[num];            write_date1(0x30+i);
  163.         }

  164.         P3=0xfb;
  165.         if(P3!=0xfb)
  166.         {   delay2(20);
  167.            if(P3!=0xfb) { temp=P3&0xf0;
  168.                                     switch(temp)
  169.                                     {
  170.                                      case 0xe0:num=8;   break;
  171.                                      case 0xd0:num=9;   break;
  172.                                      case 0xb0:num=10;  break;
  173.                                      case 0x70:num=11;  break;
  174.                                     }
  175.            }  while(P3!=0xfb);
  176.            if(num==8||num==9||num==10)//如果按下的是'1','2'或'3'
  177.            {
  178.                     if(j!=0){ write_com1(0x01); j=0;  }
  179.                     if(flag==0){ a=a*10+table1[num];  }//没有按过符号键                    
  180.                     else//如果按过符号键
  181.                     {   b=b*10+table1[num];    }
  182.            }
  183.            else if(num==11)//如果按下的是'-'
  184.            {  flag=1;   fuhao=2;}//2表示减号已按           
  185.            i=table2[num];           write_date1(0x30+i);
  186.         }

  187.         P3=0xf7;
  188.         if(P3!=0xf7)
  189.         {  delay2(20);
  190.            if(P3!=0xf7) {temp=P3&0xf0;
  191.                     switch(temp)
  192.                     {
  193.                      case 0xe0:num=12; break;
  194.                      case 0xd0:num=13; break;
  195.                      case 0xb0:num=14; break;
  196.                      case 0x70:num=15; break;
  197.                     }
  198.            } while(P3!=0xf7);
  199.            switch(num)
  200.            {
  201.             case 12:{write_com1(0x01);a=0;b=0;flag=0;fuhao=0;}  break;//按下的是"清零"            
  202.             case 13:{                //按下的是"0"
  203.                                if(flag==0)//没有按过符号键
  204.                                {   a=a*10;  write_date1(0x30);        P2=0;         }
  205.                                else if(flag>=1)//如果按过符号键
  206.                                {    b=b*10;       write_date1(0x30);   }
  207.                       }             break;
  208.             case 14:{j=1;
  209.                    if(fuhao==1)
  210.                            {
  211.                                            write_com1(0x80+0x4f);//按下等于键,光标前进至第二行最后一个显示处
  212.                                    write_com1(0x04);     //设置从后住前写数据,每写完一个数据,光标后退一格        
  213.                                    c=a+b;
  214.                                    while(c!=0){write_date1(0x30+c%10);c=c/10;  }
  215.                                    write_date1(0x3d);     //再写"="
  216.                                    a=0;b=0;flag=0;fuhao=0;
  217.                    }
  218.                       else if(fuhao==2)
  219.                              {
  220.                                         write_com1(0x80+0x4f);//光标前进至第二行最后一个显示处
  221.                             write_com1(0x04);     //设置从后住前写数据,每写完一个数据,光标后退一格(这个照理说顺序不对,可显示和上段一样)
  222.                                    if(a-b>0)         c=a-b;
  223.                                    else                    c=b-a;
  224.                                    while(c!=0) {write_date1(0x30+c%10);c=c/10; }
  225.                                    if(a-b<0)              write_date1(0x2d);
  226.                                   write_date1(0x3d);     //再写"="           
  227.                                   a=0;b=0;flag=0;fuhao=0;
  228.                    }
  229.                        else if(fuhao==3)
  230.                                  {write_com1(0x80+0x4f); write_com1(0x04);
  231.                              c=a*b;
  232.                              while(c!=0){ write_date1(0x30+c%10);c=c/10;}
  233.                              write_date1(0x3d);  a=0;b=0;flag=0;fuhao=0;
  234.                      }
  235.                         else if(fuhao==4)
  236.                           {        write_com1(0x80+0x4f);         write_com1(0x04);
  237.                     i=0;
  238.                                         if(b!=0){
  239.                                             c=(long)(((float)a/b)*1000);
  240.                                             while(c!=0)        { write_date1(0x30+c%10); c=c/10;
  241.                                                            i++;
  242.                                                            if(i==3)write_date1(0x2e); }
  243.                                                     if(a/b<=0)         {
  244.                                                                  if(i<=2) {if(i==1) write_date1(0x30);
  245.                                                                         write_date1(0x2e);           //  .
  246.                                                                         write_date1(0x30);}                                                                  
  247.                                                       write_date1(0x30);           //
  248.                                                         }
  249.                                             write_date1(0x3d);  a=0;b=0;flag=0;fuhao=0;
  250.                                                 }
  251.                                                 else
  252.                                                 {
  253.                                                         write_date1('!');         write_date1('R');
  254.                                                         write_date1('O');        write_date1('R');
  255.                                                         write_date1('R');         write_date1('E');
  256.                                                 }
  257.                    }
  258.               }  break;
  259.              case 15:{write_date1(0x30+table2[num]);flag=1;fuhao=1;}     break;
  260.            }
  261.         }
  262. }
  263. /**************************************************************
  264. 时钟、计算器切换程序
  265. *************************************************************/
  266. void switchfunction()
  267. {unsigned char ID;
  268.   if(!s1)        //切换键按下
  269. {  delay2(20);         //延时
  270.          if(!s1)                 //再判
  271.         { init1();        //计算器初始化
  272.           ID=1;            //设置计算器工作模式标志
  273.           while(!s1) ;//等待切换键释放
  274.                 while(ID)
  275.                         {   
  276.                            keyscan1();        //调矩阵键盘扫描 ,进入计算器工作模式
  277.                            if(!s1)                //切换键按下
  278.                                  {  delay2(20);        if(!s1)
  279.                                         { ID=0;         //退出计算器工作模式,进入万年历工作模式
  280.                                            init_1602();//万年历工作模式LCD1602初始化
  281.                                         }
  282.                                         while(!s1) ; //等待切换键按下
  283.                                  }
  284.                         }                                          
  285.         }
  286. }                                
  287. }  
  288. /**************************************************************
  289. 主程序
  290. *************************************************************/
  291. main()
  292. {        init_1602();   //LCD1602初始化
  293.         while(1)
  294.         {readtime();        //读时间         
  295.          displaytime();        //显示时间
  296.          key();                        //调整时间键盘
  297.          display();           //读温度并显示
  298.          switchfunction();//调功能切换程序,若功能切换键按下,进入计算器显示模式
  299.          }         
  300. }                                 

  301. /*****************************************************
  302. 函数功能:延时若干毫秒
  303. 入口参数:n
  304. ***************************************************/
  305. void delaynms(unsigned char n) {    unsigned char t,i,j;
  306.         for(t=0;t<n;t++)  for(i=0;i<10;i++)            for(j=0;j<33;j++); }
  307. /*********************************************************************
  308. ds1302写一个字节的数据
  309. 参数:com 选择要写数据的寄存器地址
  310.       date 向寄存器写入的数据
  311. **********************************************************************/
  312. void write_byte(uchar com,uchar date)
  313. {
  314.     uchar i;
  315.     rst=0;  //没有先前的低电平不能工作,所以先将RST置成的低电平         
  316.     clk=0;        //在写命令前clk也是低电平
  317.     rst=1;        //开始写命令
  318.         for(i=0;i<8;i++)
  319.         {
  320.          if(com&0x01) IO=1;//获取com的最低位
  321.                  else IO=0;
  322.          com=com>>1;            //移位,为下一位的发送做好准备
  323.          clk=1;         _nop_();                   //clk的高电平至少为250ns
  324.          clk=0;                           
  325.         }                  //到此,命令传输完毕        
  326.         for(i=0;i<8;i++)   //紧接着传输数据
  327.         {
  328.                  if(date&0x01) IO=1;
  329.                           else IO=0;
  330.                  date=date>>1;         clk=1;         _nop_(); clk=0;                           
  331.          }
  332.    rst=0;              //结束传输
  333. }
  334. /*********************************************************************
  335. ds1302读一个字节的数据
  336. 参数:com 选择要读数据的寄存器地址
  337.       date 从寄存器读出的数据  
  338. 由于读出数据的最高位丢失(为0),这对于除了年变量以外的都没有关系。但对于年,
  339. 当年份超过2080年,将不能正常显示,为此我为读年专一再写一个读函数。
  340. **********************************************************************/
  341. uchar read_byte(uchar com)
  342. {
  343.     uchar i;
  344.         uchar date; //用来存储读到的数据
  345.     rst=0;            //没有先前的低电平不能工作,所以先将RST置成的低电平
  346.     clk=0;            //在写命令前clk也是低电平
  347.     rst=1;                //开始写命令
  348.         for(i=0;i<8;i++)
  349.         {
  350.          if(com&0x01) IO=1;//获取com的最低位
  351.                  else IO=0;
  352.          com=com>>1;            //移位,为下一位的发送做好准备
  353.          clk=0;         _nop_();                   //clk的低电平至少为250ns
  354.          clk=1;                           
  355.         }                  //到此,命令传输完毕
  356.         /*********************************************************************
  357.          接收数据,接收的是1302发送的低7位,而dete的最高位为0,这样做的目的是避免了后边对
  358.          接收到数据的处理(因为日历的七个变量的最高位在计算时必须处理成0)。
  359.          这里通过少接收一次数据实现除去最高位。
  360.          *********************************************************************/
  361.     for(i=0;i<8;i++)  
  362.         {
  363.              if(IO==1) date|=0x80;//虽然也接收了八次,但第一次接收的数据不对(接收的肯定是1),且后来移位除掉了。实际上是接收了七位        
  364.                  date=date>>1;                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     
  365.                  clk=1;         _nop_();         clk=0;             //时钟的下降沿,ds1302开始向主机发送数据
  366.          }
  367.     rst=0;                           //结束传输
  368.     return date;
  369. }
  370. /*********************************************************************
  371. 这个函数能完整的读取1302所传的一个字节(八位数据),它的高位没有丢失
  372. 当年份超过2080年,也能正常显示,这是我为读年专一写的一个函数。
  373. ************************************************************************/
  374. uchar readyear_byte(uchar com)
  375. {
  376.     uchar i;
  377.         uchar date; //用来存储读到的数据
  378.     rst=0;            //没有先前的低电平不能工作,所以先将RST置成的低电平
  379.     clk=0;            //在写命令前clk也是低电平
  380.     rst=1;                //开始写命令
  381.         for(i=0;i<8;i++)
  382.         {
  383.          if(com&0x01) IO=1;//获取com的最低位
  384.                  else IO=0;
  385.          com=com>>1;            //移位,为下一位的发送做好准备
  386.          clk=0;
  387.          _nop_();                   //clk的低电平至少为250ns
  388.          clk=1;                           
  389.         }                  //到此,命令传输完毕
  390.     for(i=0;i<8;i++)  
  391.         {
  392.          date=date>>1;  //由于空移了一次,所以没有浪费数据                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      
  393.          clk=0;                                   //时钟的下降沿,ds1302开始向主机发送数据
  394.          if(IO==1) date|=0x80;//这一次就能接收八次数据,没有无用的,也没有浪费
  395.          clk=1;            
  396.          }
  397.     rst=0;                           //结束传输
  398.         clk=0;
  399.     return date;
  400. }

  401. void readtime()//读出时间  时间的每一部分的最高位都已经置零
  402. {
  403. year=readyear_byte(0x8d);
  404. month=read_byte(0x89);
  405. day=read_byte(0x87);
  406. hour=read_byte(0x85);  
  407. minute=read_byte(0x83);
  408. second=read_byte(0x81);
  409. week=read_byte(0x8b);
  410. }
  411. /*********************************************************************************
  412. 一下是对lcd1602的操作
  413. ***********************************************************************************/                  
  414. /*******************************/         //lcd1602写命令                  
  415. void write_com(unsigned char CMD)
  416. {                                       
  417.         delaynms(10);        LCM_RS=0;        LCM_EN=0;        _nop_();        _nop_();
  418.         P0=CMD;                _nop_();        _nop_();        _nop_();         _nop_();        
  419.         LCM_EN=1;_nop_();_nop_();_nop_(); _nop_();LCM_EN=0;
  420. }                                       
  421. /*******************************/        //lcd1602写数据                        
  422. void write_date(unsigned char dataW)
  423. {                                       
  424.         delaynms(10);        LCM_RS=1;         LCM_EN=0;        _nop_();
  425.         P0=dataW;          _nop_();        _nop_();         _nop_();         _nop_();
  426.         LCM_EN=1;        _nop_();          _nop_();         _nop_();          _nop_();
  427.         LCM_EN=0;
  428. }
  429. void init_1602()//初始化液晶
  430. {
  431.         wela=0;dula=0;
  432.         write_com(0x38);delay20ms();
  433.         write_com(0x38); delay20ms();
  434.         write_com(0x38);delay20ms();         //初始化三次确保功能设定成功
  435.         write_com(0x0c);  write_com(0x06);        write_com(0x01);
  436.         
  437.         write_com(0x85);//以下将液晶上不变的字符先显示出来
  438.         write_date('/');
  439.         write_com(0x88);write_date('/');
  440.         write_com(0xc2);write_date(':');
  441.         write_com(0xc5);write_date(':');
  442.         write_com(0xc0+13);write_date(0xdf);  write_date('C');        
  443. }
  444. /***************************************************************************
  445. 显示时间  在计算时间(年 、月、日等等)的十位和个位时需要注意
  446. 这需要将8421码表示的两位十进制数的十位和个位分别求出来 十位=时间(比方说天)/16;个位=时间%16
  447. *****************************************************************************/
  448. void displaytime()
  449. {
  450.         write_com(0x81); write_date(table[2]);write_date(table[0]);
  451.         write_date(table[year/16]);        write_date(table[year%16]);//显示出年
  452.         
  453.         write_com(0x86);write_date(table[month/16]);write_date(table[month%16]);//显示出月
  454.         
  455.         write_com(0x89);write_date(table[day/16]); //显示出日
  456.         write_date(table[day%16]);
  457.         
  458.         write_com(0x80+12);                   //显示出星期
  459.         switch(week) {
  460.           case 1:write_date('M'); write_date('O');  write_date('N'); break;
  461.           case 2:write_date('T'); write_date('U');  write_date('E'); break;
  462.           case 3:write_date('W'); write_date('E');  write_date('D'); break;
  463.           case 4:write_date('T'); write_date('H');         write_date('U'); break;
  464.           case 5:write_date('F'); write_date('R');  write_date('T'); break;
  465.           case 6:write_date('S'); write_date('A');  write_date('T'); break;
  466.           case 7:write_date('S'); write_date('U');  write_date('N'); break;
  467.         }
  468.         write_com(0xc0);write_date(table[hour/16]);        write_date(table[hour%16]);//显示出小时
  469.         write_com(0xc3);write_date(table[minute/16]); write_date(table[minute%16]);//显示出分钟
  470.         write_com(0xc6);write_date(table[second/16]);write_date(table[second%16]);//显示出秒
  471. }                                          
  472. /****************************************************************************
  473. 以下是有关键盘调时内容的程序
  474. ******************************************************************************/
  475. /**************************************************************
  476. 函数功能:延时20ms的子程序
  477. **************************************************************/
  478. void delay20ms(){  unsigned char i,j;
  479.   for(i=0;i<100;i++)   for(j=0;j<60;j++)  ;}

  480. void delay1(uchar z){ uchar x,y;
  481.         for(x=1000;x>1;x--)        for(y=z;y>1;y--);  }
  482. /**************************************************************
  483. 函数功能:扫描键盘调时程序
  484. **************************************************************/         
  485. void key()
  486. {        uchar timenum;                //调整时的标志符。当num=0时,正常工作状态。当num!=0时,就是调时状态。
  487.         if(mode==0)                                         //当按下模式选择键就开始进入调时模式,直到num=0为止
  488.         {delay20ms();  if(mode==0) { timenum++;}
  489.                 while(!mode==1);        }         
  490.         if(timenum) //当num不为零时,就处于调时状态,就让1302停止计时。调时完成后,就重新打开计时                                               
  491.         {write_byte(0x8e,0);                 //调时过程中允许写入
  492.         second=read_byte(0x81);                //先求出秒的数值
  493.         write_byte(0x80,second|0x80);//再让1302停止         
  494.         while(timenum)                                           //进入循环的调时状态,直到num=0,跳出调时模块
  495.         {switch(timenum)
  496.                  { case 1:write_com(0x84);   write_com(0x0f); //年
  497.                                delaynms(200);                           //让年的个位闪烁需要足够的时间
  498.                                  year1=(year/16)*10+year%16;  //把当前从1302中读出的8424码表示的数,转化成十进制计算           
  499.                          if(plus==0)                                  //扫描按键
  500.                                         { delay20ms();                          //延迟后再检测去除抖动
  501.                                           if(plus==0){        year1++;   //确认按下后就加1
  502.                                             if(year1==100) year1=0;        write_byte(0x8c,((year1/10)*16+year1%10));}//将更改后的十进制年转换成8421码存入1302的年寄存器中
  503.                                          }         while(!plus)  ;                                                                 //等待按键释放
  504.                                         if(minus==0){delay20ms();
  505.                                                 if(minus==0){         year1--;           if(year1==-1) year1=99;
  506.                                                 write_byte(0x8c,((year1/10)*16+year1%10));        }
  507.                                         }while(!minus) ;
  508.                                         year=readyear_byte(0x8d);                                    //将年读出来
  509.                                         write_com(0x83);                                                   //将年显示出来,以使调整后能看到变化
  510.                                         write_date(table[year/16]);   write_date(table[year%16]);   break;
  511.                          case 2: write_com(0x87);                                   //选择光标闪烁的位置,月的个位
  512.                                  delaynms(200);                                          //让月的个位闪烁需要足够的时间
  513.                                          month1=(month/16)*10+month%16;         //把当前从1302中读出的8424码表示的数,转化成十进制计算
  514.                                          if(plus==0) { delay20ms();
  515.                                           if(plus==0) {month1++; if(month1==13) month1=1;write_byte(0x88,((month1/10)*16+month1%10));}                                
  516.                                           }        while(!plus) ;
  517.                                         if(minus==0){  delay20ms();
  518.                                                 if(minus==0){  month1--; if(month1==0) month1=12;
  519.                                                 write_byte(0x88,((month1/10)*16+month1%10)); }                                       
  520.                                         }  while(!minus) ;
  521.                                          month=read_byte(0x89);
  522.                                          write_com(0x86); write_date(table[month/16]);
  523.                         write_date(table[month%16]);//显示出月
  524.                                         break;
  525.                           case 3:write_com(0x80+10);         
  526.                                         delaynms(200);
  527.                                         day1=(day/16)*10+day%16;                 //把当前从1302中读出的8424码表示的数,转化成十进制计算
  528.                                            if(plus==0){ delay20ms();
  529.                                           if(plus==0){                        day1++;
  530.                                                         switch(month1)//对于日的调整比较麻烦1,3,5,7,8,10,12月有31天;而4,6,9,11有30天;闰年的2月29天,平年则有28天
  531.                                                    {case 1:case 3:case 5:case 7:case 8:case 10:case 12: if(day1==32)   day1=1;break;  
  532.                                                     case 4:case 6:case 9:case 11: if(day1==31) day1=1;break;
  533.                                                         case 2:if(year1%4==0) {if(day1==30)  day1=1;}
  534.                                                                else {if(day1=29)  day1=1;} break;
  535.                                                     }  
  536.                                            write_byte(0x86,((day1/10)*16+day1%10));
  537.                             }                             
  538.                                 }while(!plus)  ;
  539.                                         if(minus==0){ delay20ms();
  540.                                                 if(minus==0){ day1--;
  541.                                             switch(month1)
  542.                                            {case 1:case 3:case 5:case 7:case 8:case 10:case 12: if(day1==0)   day1=31;break;  
  543.                                             case 4:case 6:case 9:case 11: if(day1==0) day1=30;break;
  544.                                                 case 2:if(year1%4==0) {if(day1==0)  day1=29;}
  545.                                                          else {if(day1=0)  day1=28;} break;
  546.                                             }   
  547.                                                 write_byte(0x86,((day1/10)*16+day1%10));
  548.                           }                             
  549.                                 }while(!minus) ;
  550.                                          day=read_byte(0x87);write_com(0x89);
  551.                         write_date(table[day/16]);   write_date(table[day%16]);
  552.                                         break;
  553.                  case 4:write_com(0x80+14);  //星期
  554.                                         delaynms(200);
  555.                                         week1=(week/16)*10+week%16;                 //把当前从1302中读出的8424码表示的数,转化成十进制计算
  556.                                       if(plus==0){ delay20ms();
  557.                                           if(plus==0) {        week1++;
  558.                                                 if(week1==8) week1=1;
  559.                                                 write_byte(0x8a,((week1/10)*16+week1%10));        }
  560.                                         }        while(!plus)  ;
  561.                                         if(minus==0){ delay20ms();
  562.                                                 if(minus==0) { week1--;
  563.                                                 if(week1==0) week1=7;
  564.                                                 write_byte(0x8a,((week1/10)*16+week1%10)); }
  565.                                         }while(!minus) ;
  566.                                          week=read_byte(0x8b);//显示出星期
  567.                                         write_com(0x80+12);                  
  568.                                         switch(week)
  569.                                          {
  570.                                                   case 1:        write_date('M');write_date('O'); write_date('N');break;
  571.                                                   case 2:write_date('T');write_date('U');write_date('E'); break;
  572.                                                   case 3:write_date('W');write_date('E');write_date('D'); break;
  573.                                                   case 4:write_date('T');write_date('H'); write_date('U');break;
  574.                                                   case 5:write_date('F');write_date('R');write_date('T');break;
  575.                                                   case 6:write_date('S');write_date('A'); write_date('T');break;
  576.                                                   case 7:write_date('S');write_date('U');write_date('N');break;
  577.                                         }        break;                                                
  578.                  case 5:     write_com(0xc1);  //时
  579.                                         delaynms(200);
  580.                                         hour1=(hour/16)*10+hour%16;     //把当前从1302中读出的8424码表示的数,转化成十进制计算
  581.                                      if(plus==0){ delay20ms();
  582.                                           if(plus==0){ hour1++;        if(hour1==24) hour1=0;
  583.                                                 write_byte(0x84,((hour1/10)*16+hour1%10));        }
  584.                                         }while(!plus)  ;
  585.                                         if(minus==0)        {delay20ms();
  586.                                                 if(minus==0){ hour1--;        if(hour1==-1) hour1=23;
  587.                                                 write_byte(0x84,((hour1/10)*16+hour1%10));        }
  588.                                         }        while(!minus) ;
  589.                                          hour=read_byte(0x85);write_com(0xc0);
  590.                                         write_date(table[hour/16]);        write_date(table[hour%16]);//显示出小时
  591.         
  592.                                         break;                                                   
  593.                          case 6: write_com(0xc4);         //分
  594.                                         delaynms(200);
  595.                                         minute1=(minute/16)*10+minute%16;         //把当前从1302中读出的8424码表示的数,转化成十进制计算
  596.                                         if(plus==0){ delay20ms();
  597.                                           if(plus==0){minute1++;        if(minute1==60) minute1=0;
  598.                                                 write_byte(0x82,((minute1/10)*16+minute1%10));                }                                       
  599.                                         }while(!plus)  ;
  600.                                         if(minus==0){delay20ms();
  601.                                                 if(minus==0){         minute1--;         if(minute1==-1) minute1=59;        }
  602.                                                 write_byte(0x82,((minute1/10)*16+minute1%10));
  603.                                         }   while(!minus) ;
  604.                                          minute=read_byte(0x83);        write_com(0xc3);
  605.                                         write_date(table[minute/16]);write_date(table[minute%16]);//显示出分钟
  606.                                         break;
  607.                           case 7: write_com(0xc7);         //秒
  608.                                          delaynms(200);
  609.                                          second1=(second/16)*10+second%16;         //把当前从1302中读出的8424码表示的数,转化成十进制计算
  610.                                            if(plus==0)        { delay20ms();
  611.                                           if(plus==0){ second1++;if(second1==60) second1=0;
  612.                                                 write_byte(0x80,((second1/10)*16+second1%10)|0x80);//将更改后的十进制秒转换成8421码存入1302的年寄存器中
  613.                                              //由于read_byte()函数的最高位没读(为0)。虽然秒的最高位在停止时已经置成1,但是由于最高位的丢失,所以按前边的写进去必定又将计时启动了。
  614.                                                  //这里在char型变量秒的最高位添了1以保证调秒时也停止计时
  615.                                                 }           
  616.                          }        while(!plus) ;
  617.                                         if(minus==0){delay20ms();
  618.                                                 if(minus==0){second1--;        if(second1==-1) second1=59;
  619.                                                 write_byte(0x80,((second1/10)*16+second1%10)|0x80);        }
  620.                                         } while(!minus) ;
  621.                                          second=read_byte(0x81);        write_com(0xc6);
  622.                                         write_date(table[second/16]);write_date(table[second%16]);//显示出秒  
  623.                                         break;                                 
  624.                         }
  625.                           if(mode==0)                                          //当按下模式选择键选择要调整的量,当num=0时跳出调时状态
  626.                            {        delay20ms();   
  627.                             if(mode==0)          { timenum++;                 }
  628.                                 while(!mode==1);
  629.                         }         
  630.                       if(timenum==8){ timenum=0;         } //当调整完时,num=0,就可以脱离调时状态
  631.                                           
  632.           }  
  633.           second=read_byte(0x81);                //先求出秒的数值
  634.           write_byte(0x80,second&0x7f);        //再让1302启动
  635.           write_byte(0x8e,0x80);                //禁止写入
  636.           write_com(0x0c);                             //光标在调整年(num=1)时开始闪烁,在调整其他位(num=2,3,4,5,6,7)时也在闪烁,。调整完(num=0)时,停止闪烁
  637.           }                                                                                                                                                                 
  638. }

  639. /*************DS18B20温度读取模块*************/
  640. void tmpDelay(int num)//延时函数
  641. {
  642. ……………………

  643. …………限于本文篇幅 余下代码请从51黑下载附件…………
复制代码


所有资料51hei提供下载:
计算器与万年历.zip (796.33 KB, 下载次数: 79)


评分

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

查看全部评分

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

使用道具 举报

沙发
ID:370415 发表于 2018-7-16 10:10 | 只看该作者
1602背光用IO口控制就更好了
回复

使用道具 举报

板凳
ID:380705 发表于 2018-10-12 14:32 | 只看该作者
你们的LCD有字符或其它什么东西显示吗?我的为什么是一片亮

2018-10-12_14-31.jpg (775.57 KB, 下载次数: 27)

2018-10-12_14-31.jpg
回复

使用道具 举报

地板
ID:1012708 发表于 2022-3-24 12:52 | 只看该作者
linyin 发表于 2018-7-16 10:10
1602背光用IO口控制就更好了

你好,这个博主的程序有点问题,显示屏不能显示,请问您解决这个问题了吗
回复

使用道具 举报

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

本版积分规则

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

Powered by 单片机教程网

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