找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 3064|回复: 6
收起左侧

自己用洞洞板焊的单片机数码管时钟程序有问题

[复制链接]
ID:46220 发表于 2018-1-16 13:00 | 显示全部楼层 |阅读模式
在本论坛看到的一个数码管时钟程序,稍作修改后,自己用洞洞板焊了一块板子,用了两个四位共阳数码管做的,取消了锁存器,实现的功能完全正常,后来又加入了DS18B20测温程序,温度显示也正常,时间显示4秒多然后显示温度1秒的样子,交替显示,现在遇到的问题是,在没加温度程序的时候,调整时间的时候时分秒年月日都会闪烁,并且调整加减的时候都实时显示,现在加了温度程序以后,按下调整键的时候,时分秒不会闪烁,按加减的时候,数据也不能实时变化,但是数据的加减在调整退出后是有变化的,只是没能实时的显示,而年月日的调整是正常的,就是说调整的时候年月日会闪烁,且数据也是随加减键实时变化的,下面是我的程序,大神帮我看看程序哪里有问题?已经折腾好几天了,没能解决

  1. #include <reg52.h>                                //头文件
  2. #define uchar unsigned char                //宏定义
  3. #define uint unsigned  int                //宏定义

  4. sbit TRST = P1^0;        /* DS1302实时时钟的复位/片选线引脚(第5脚RST低电平复位高电平时芯片正常工作)*/
  5. sbit TIO  = P1^1;        /* DS1302实时时钟的数据输入/输出引脚(第6脚I/O)*/
  6. sbit SCLK = P1^2;        /* DS1302实时时钟的串行时钟引脚(第7脚SCLK)*/
  7. sbit S2 = P1^3;                //定义调整按键
  8. sbit S3 = P1^4;                //定义减数据按键,正常走时情况下按下显示年月日,延时6秒后转回时间显示
  9. sbit S4 = P1^5;                //定义加数据按键
  10. sbit  DQ = P1^6;         //定义DS18B20的数据输入/输出口

  11. unsigned char code duan[]=
  12. {0xc0,0xf9,0xa4,0xb0,
  13. 0x99,0x92,0x82,0xf8,
  14. 0x80,0x90,0xbf,0xff,0x9c,0xc6};           //共阳数码管段选码0-9     
  15. /*****************************************************/
  16. /***********ds18b20子程序模块*************************/
  17. /*****************************************************/                  
  18. unsigned char temp_value,temp1_value;      //temp_value温度值整数部分 temp1_value温度值小数部分
  19. bit  fg=1;        //温度正负标志  1为正0为负
  20. /***********ds18b20延迟子函数(晶振12MHz )*******/
  21. void delay_18B20(unsigned int i)
  22. {
  23.         while(i--);
  24. }
  25. /**********ds18b20初始化函数**********************/
  26. void Init_DS18B20(void)
  27. {
  28.          unsigned char x=0;
  29.          DQ = 1;          //DQ复位,不要也行
  30.          delay_18B20(8);  //稍做延时
  31.          DQ = 0;          //单片机将DQ拉低
  32.          delay_18B20(40); //精确延时维持至少480us当总线停留在低电平超过480us,总线上所以器件都将被复位
  33.          DQ = 1;          //释放总线即拉高总线,产生复位脉冲后,微处理器释放总线,让总线处于空闲状态
  34.          delay_18B20(7);        //稍作延时,释放总线后,以便从机18b20通过拉低总线来指示其是否在线
  35.          x=DQ;            //稍做延时后 如果x=0则初始化成功 x=1则初始化失败
  36.          delay_18B20(10);        //稍作延时
  37. }
  38. /***********ds18b20读一个字节**************/  
  39. unsigned char ReadOneChar(void)
  40. {
  41.         unsigned char i=0;
  42.         unsigned char dat = 0;        //一定别忘了给初值
  43.         for (i=8;i>0;i--)        //读取数据时,数据以字节的最低有效位先从总线移出
  44.          {
  45.                   DQ = 0; // 给脉冲信号,单片机(微处理器)将DS18B20总线拉低
  46.                   dat>>=1;
  47.                   DQ = 1; // 给脉冲信号,拉低总线后接着释放总线,让从机18b20能够接管总线,输出有效数据
  48.                   if(DQ)
  49.                   dat|=0x80;
  50.                   delay_18B20(4);        //所有读"时间隙"必须60~120us
  51.          }
  52.         return(dat);        //返回一个字节的数据
  53. }
  54. /*************ds18b20写一个字节****************/  
  55. void WriteOneChar(unsigned char dat)
  56. {
  57.         unsigned char i=0;
  58.         for (i=8; i>0; i--)
  59.         {
  60.                   DQ = 0;
  61.                 DQ = dat&0x01;
  62.             delay_18B20(5);
  63.                 DQ = 1;
  64.             dat>>=1;
  65.         }
  66. }
  67. /**************读取ds18b20当前温度************/
  68. void ReadTemp(void)
  69. {
  70.         unsigned char L=0;
  71.         unsigned char H=0;
  72.         unsigned char t=0;
  73.         Init_DS18B20();                        //ds18b20初始化
  74.         WriteOneChar(0xCC);            // 跳过读序号列号的操作
  75.         WriteOneChar(0x44);         // 启动温度转换
  76.         delay_18B20(100);       // this message is wery important
  77.         Init_DS18B20();                        //ds18b20初始化
  78.         WriteOneChar(0xCC);         //跳过读序号列号的操作
  79.         WriteOneChar(0xBE);         //读取温度寄存器等(共可读9个寄存器) 前两个就是温度
  80.         delay_18B20(50);                //延时
  81.         L=ReadOneChar();            //读取温度值低8位
  82.         H=ReadOneChar();                   //读取温度值高8位
  83.         t=H&0xf8;                //把读取到的温度值高8位跟11111000做与运算判断温度正负,若高5位全部为1即为负否则为正
  84.         if(t)
  85.         {
  86.           fg=0;                //给出温度为负的标志
  87.             temp_value=H<<4;
  88.           temp_value+=(L&0xf0)>>4;  
  89.           temp_value=~temp_value+1;        //负温度值整数部分-取反加1
  90.           temp1_value=~L&0x0f;                //负温度值小数部分
  91.         }
  92.         else
  93.         {  
  94.         temp_value=H<<4;
  95.         temp_value+=(L&0xf0)>>4; //正温度值整数部分
  96.                 temp1_value=L&0x0f;                //正温度值小数部分            
  97.     }
  98. }
  99. //*********************************************************************************************
  100. /*******************************时钟芯片DS1302的数据时序子程序********************************/
  101. //*********************************************************************************************
  102. #include <intrins.h>                        //包含_nop_函数的头文件
  103. #define sce   timedate[1]        //秒钟寄存器1读WRITE 0x80写READ 0x81(bit7CH是时钟停止标志位0是正常工作若为1说明芯片掉电没有备用电池未运行剩下7位高3位是秒的十位,低4位是秒的个位)
  104. #define min   timedate[2]        //分钟寄存器2读WRITE 0x82写READ 0x83(bit7没意义,剩下的7位高3位是分钟的十位,低4位是分钟的个位)
  105. #define hour  timedate[3]        //小时寄存器3读WRITE 0x84写READ 0x85(bit7是1代表12小时制,0代表24小时制bit6固定是0,bit5在12小时制下0代表上午1代表下午在24小时制下和bit4一起代表了小时的十位低4位代表的是小时的个位)
  106. #define date  timedate[4]        //日期寄存器4读WRITE 0x86写READ 0x87(高2位固定是0,bit5和bit4是日期的十位,低4位是日期的个位)
  107. #define month timedate[5]        //月份寄存器5读WRITE 0x88写READ 0x89(高3位固定是0 bit4是月的十位,低4位是月的个位)
  108. #define week  timedate[6]        //星期寄存器6读WRITE 0x8a写READ 0x8b(高5位固定是0,低3位代表了星期)
  109. #define year  timedate[7]        //年份寄存器7读WRITE 0x8c写READ 0x8d(高4位代表了年的十位,低4位代表了年的个位,这里特别注意,这里的00到99年指的是2000年到2099)
  110.                                                         //寄存器8读WRITE 0x8e写READ 0x8f(bit7是一个保护位,如果这一位是1,那么是禁止给任何其他的寄存器或者那31个字节的RAM写数据的,因此在写数据之前,这一位必须先写成0,剩下7位都是0)
  111. unsigned char displaychar1[8]={0,1,2,3,4,5,6,7},a,ya,ja ;                   //a结尾的字符都用来专门延时,a通用,ya日期延时程序用
  112. unsigned char commandchar[9]={0,0x80,0x82,0x84,0x86,0x88,0x8a,0x8c,0x8e};   //与timedate对应,分别控制每个寄存器的写,读时数组+1,第8个数是控制写保护位
  113. unsigned char timedate[8],sdat,seta,b,fen,tz;        //fen用来给分钟计数,tz用来计算分钟数自动补偿差错
  114. unsigned char LD = 1;      //************数码管,亮度调节,0最小,10最高,越亮越闪 因会影响开始信号查询时间,建议最高设置为3**************
  115. char m;
  116. bit s,s2,s3,s4,K,setbit,sk;
  117. /******************延时子程序***********************/
  118. void timeout(unsigned char a)      
  119.         {
  120.            unsigned char b;
  121.            for(;a>0;a--)
  122.               for(b=10;b>0;b--);//本来b=114会闪烁
  123.         }
  124.                   /*********延时5微秒子程序************/
  125. //        void timeout5us()      
  126. //                {
  127. //                    _nop_();
  128. //                }
  129. /**************写控制和一个字节***********************/
  130. void sendchar(unsigned char csdat,unsigned char sdat)
  131.         {
  132.                 SCLK = 0;                //串行时钟置低//拉低SCLK,为脉冲上升沿写入数据做好准备
  133.                 TRST = 1;                //启动数据传输 打开片选 DS1302实时时钟的复位/片选线引脚(第5脚RST低电平复位高电平时芯片正常工作)
  134.                 for(a=0;a<8;a++)        //连续写8个二进制位数据
  135.                 {                                   
  136.                         SCLK = 0;//确保写数据前SCLK被拉低
  137.                         TIO  = (csdat%2);
  138.                         SCLK = 1;//上升沿写入数据
  139.                         csdat >>=1; //将csdat的各数据位右移1位,准备写入下一个数据位
  140.                 }
  141.                 for(a=0;a<8;a++)        //连续写8个二进制位数据
  142.                 {                                   
  143.                         SCLK = 0;//确保写数据前SCLK被拉低
  144.                         TIO  = (sdat%2);
  145.                         SCLK = 1;//上升沿写入数据
  146.                         sdat >>=1;
  147.                 }
  148.                 SCLK = 0;        //重新拉低SCLK,形成脉冲
  149.                 TRST = 0;        //禁止数据传递 关闭片选 DS1302实时时钟的复位/片选线引脚(第5脚RST低电平复位高电平时芯片正常工作)      
  150.         }
  151. /**************************读一个字节**************************************************************/
  152. unsigned char receviechar(unsigned char crdat)
  153.         {                        
  154.                 unsigned char rdat;
  155.                 TRST = 1;       //打开片选 DS1302实时时钟的复位/片选线引脚(第5脚RST低电平复位高电平时芯片正常工作)
  156.                 //TRST = 1;
  157.                 for(a=0;a<8;a++)
  158.                 {                                   
  159.                         SCLK = 0;
  160.                         TIO  = (crdat%2);
  161.                         SCLK = 1;
  162.                         crdat >>=1;
  163.                 }
  164.                 for(a=0;a<8;a++)
  165.                 {
  166.                         SCLK =   1;
  167.                         rdat >>= 1;
  168.                         SCLK =   0;
  169.                
  170.                         if(TIO)
  171.                         rdat = rdat|0x80;
  172.                 }
  173.                 SCLK = 0;
  174.             TRST = 0;        
  175.                 return rdat ; //返回读出的rdat的值
  176.         }
  177. /*************************读取时分秒子程序**************************************/
  178. void readtime()
  179.         {                                   
  180.             sendchar(0x8e,0);                        //去DS1302写保护
  181.             hour = receviechar(0x85);         //读小时数据
  182.             min  = receviechar(0x83);         //读分钟数据
  183.             sce  = receviechar(0x81);        //读秒针数据
  184.             sendchar(0x8e,0x80);        //DS1302加写保护               
  185.         }
  186. /************************读取年月日子程序***************************************/
  187. void readyear()
  188.         {                                   
  189.             sendchar(0x8e,0);                        //去DS1302写保护
  190.             date = receviechar(0x87);         //读日期
  191.             month  = receviechar(0x89);        //读月份
  192.             year  = receviechar(0x8d);        //读年份
  193.             sendchar(0x8e,0x80);         //DS1302加写保护                        
  194.         }
  195. /**********************键盘扫描子程序,用定时器延时******************************/
  196. bit jianpan(K)
  197.         {
  198.             if((!K)&TF0)    //如果S2或S3或S4被按下且计时器0溢出
  199.             {
  200.                  TF0 = 0;        //定时器0溢出标志清0(溢出时TF0被硬件置1,并且申请中断,软件查询到该位置1后需用软件清零)
  201.                  ja++;         
  202.                  if(ja>=2)
  203.                  {
  204.                     TR0 = 0; //关闭定时器0,每次按下后都会关闭定时器,后面的程序会检测松手,松开按键后会重新打开定时器,可以保护每次按下只起作用一次
  205.                     ja = 0;                                
  206.                     s = 1;
  207.                  }
  208.                  return s;        //返回s的值给K
  209.             }
  210.              //return s;        //返回s的值给K
  211.         }
  212. //**********************************************设置时间日期子程序*******************************************/
  213. void settime()
  214. {        
  215.         setbit=1;                //设置控制标识,进本函数后先就让标识打开,在下面延时跳出前都会一直跳入设置功能函数
  216.         if(TF1&(s2==s3==s4==0))  //没有按键按下时用定时器1来延时跳出
  217.         {                  
  218.             TF1=0;      //定时器1溢出标志清0(溢出时TF1被硬件置1,并且申请中断,软件查询到该位置1后需用软件清零)   
  219.             seta ++;
  220.         }
  221.         if(!(s2==s3==s4==0))        //松手检测
  222.                 seta = 0;        //延时时间超过一定值,或者有按键被按下(注意!这个符号)时,时间会被延长
  223.         if(seta>=70)                //延时
  224.         {                  
  225.              setbit=0;        //关闭设置
  226.              sdat = 0;        
  227.         }
  228.         if(sk!=s2)            //sk用来做s2的中间暂存数据,用来用来识别S2是否变化过
  229.         {
  230.                 sk = s2;
  231.                 if(s2)
  232.                 sdat ++;      //每次进行一次S2动作时才自加一次sdat
  233.                 if(sdat ==6)sdat=7;   //跳过星期,本程序不显示星期                           
  234.         }
  235.         m = timedate[sdat]/16*10+timedate[sdat]%16;        //m用10进制存下以供写入DS1302
  236.         if(s3) m--;
  237.                 switch (sdat)           //每次进入设置的对应操作判断
  238.         {
  239.                 case 1:
  240.                         if(m==-1)                                        //调整秒钟
  241.                                                  m = 59;
  242.                                   break;
  243.       
  244.                 case 2:
  245.                         if(m==-1)                                        //调整分钟
  246.                                                  m = 59;
  247.                                   break;
  248.       
  249.                 case 3:
  250.                         if(m==-1)                                        //调整小时
  251.                                                  m =23;
  252.                                   break;
  253.       
  254.                 case 4:                                                //调整日期***因为月份不同所以每个月的天数是不同的
  255.                         if(timedate[5]==4|timedate[5]==6|timedate[5]==9|timedate[5]==11)  //小月,
  256.                         {
  257.                            if(m<=0)
  258.                                                  m = 30;
  259.                               break;        //4月6月9月和11月是小月份,只有30天,所以到了30后转到1日
  260.                         }
  261.                         if(timedate[5]==2&(timedate[7]%4==0))                            //闰年2月
  262.                         {
  263.                            if(m<=0)
  264.                                                  m=29;
  265.                                    break;     //闰年2月有29天
  266.                         }
  267.                         if(timedate[5]==2&(timedate[7]%4!=0))                          //平年2月
  268.                         {
  269.                            if(m<=0)
  270.                                                  m=28;
  271.                                 break;     //平年2月只有28天                                                      
  272.                         }
  273.                         if(m<=0)
  274.                                                  m =31;
  275.                                 break;         //其它月分情况
  276.         /********************************************************************************************************
  277.         怎么判断一个年份是不是闰年:1:普通情况求闰年只需除以4可除尽即可 年/4余数为0
  278.                                                                    2:如果是100的倍数但不是400的倍数,那就不是闰年了,即末两位都是零的整除400才行
  279.         判断闰年条件①:非整百年数除以4,无余为闰,有余为平;②整百年数除以400,无余为闰有余为平。
  280.         *********************************************************************************************************/
  281.                 case 5:                                        //调整月份
  282.                         if(m==0)
  283.                                                 m = 12;
  284.                                break;
  285.       
  286.                 case 6:
  287.                          sdat++;        //跳过星期本程序不显示星期
  288.                         if(m<=0)
  289.                                           m = 7;
  290.                               break;
  291.       
  292.                 case 7:                                        //调整年份17-99
  293.                         if(m<=16)
  294.                                                  m = 99;
  295.                               break;
  296.       
  297.                 default :         /****不在判断范围的进行初始化处理*/
  298.                         sdat = 0;        //S2按键计数清0
  299.                                     sk = 0;                //s2的中间暂存数据清0
  300.                         setbit = 0;        //设置控制标识清0
  301.                         s2 = 0;     //s2=0是优化点,在按下S2后按键标识不会清零,松手时程序已重复运行了很多遍,所以会重新跳回设置的第一位.加本命令可以让设置判断失效,不进设置页。                             
  302.                                          break;
  303.         }
  304.         if(s4) m++;
  305.         switch (sdat)           //每次进入设置的对应操作判断
  306.         {
  307.                 case 1:                                 //调整秒钟
  308.                         if(m>59)
  309.                                                  m = 0;
  310.                                   break;
  311.       
  312.                 case 2:                                        //调整分钟
  313.                         if(m>59)
  314.                                                  m = 0;
  315.                                   break;
  316.       
  317.                 case 3:                                        //调整小时
  318.                         if(m>23)
  319.                                                  m = 0;
  320.                                   break;
  321.       
  322.                 case 4:                                        //调整日期***因为月份不同所以每个月的天数是不同的
  323.                         if(timedate[5]==4|timedate[5]==6|timedate[5]==9|timedate[5]==11)  //小月,
  324.                         {
  325.                            if(m>=31)
  326.                                                          m = 1;
  327.                                        break;//4月6月9月和11月是小月份,只有30天,所以到了30后转到1日
  328.                         }
  329.                         if(timedate[5]==2&(timedate[7]%4==0))                            //闰年2月
  330.                         {
  331.                            if(m>=30)
  332.                                                         m = 1;
  333.                                            break;      //闰年2月有29天
  334.                         }
  335.                         if(timedate[5]==2&(timedate[7]%4!=0))                          //平年2月
  336.                         {
  337.                            if(m>=29)
  338.                                                         m = 1;
  339.                                         break;     //平年2月只有28天                                                      
  340.                         }
  341.                         if(m>=32)
  342.                                                         m = 1;
  343.                                     break;            //其它月分情况
  344.       
  345.                 case 5:                                                        //调整月份
  346.                         if(m>=13)
  347.                                                  m = 1;
  348.                                     break;
  349.       
  350.                 case 6:
  351.                         sdat++;              //跳过星期本程序不显示星期
  352.                         if(m>=8)
  353.                                                  m = 1;
  354.                                     break;
  355.       
  356.                 case 7:                                                //调整年份17-99
  357.                         if(m>=100)
  358.                                                  m = 17;
  359.                                     break;
  360.       
  361.                 default : /****不在判断范围的进行初始化处理*/
  362.                         sdat = 0;        //S2按键计数清0
  363.                                     sk = 0;                //s2的中间暂存数据清0
  364.                         setbit = 0;        //设置控制标识清0
  365.                         s2 = 0;     //s2=0是优化点,在按下S2后按键标识不会清零,松手时程序已重复运行了很多遍,所以会重新跳回设置的第一位.加本命令可以让设置判断失效,不进设置页。                                 
  366.                                         break;
  367.         }
  368.         if(setbit)        //如果设置控制标识setbit为1则说明以上有成立的条件,需要发送修改数据
  369.         {
  370.            sendchar(0x8e,0);                         //去DS1302写保护
  371.            sendchar(commandchar[sdat],m/10*16+m%10); //将改好的数据写入DS1302(sdat的值决定写时分秒或年月日星期,m的值转换成BCD写入)
  372.            sendchar(0x8e,0x80);                      //加写保护
  373.         
  374.            if(seta%5>2&seta<50)                 //设置延时操作期间控制闪烁时间
  375.               timedate[sdat] = 0xbb;  //显示空,对应段选的两位11;0xbb/16=11,0xbb%16=11,而上面段选数组中第12个数是显示空   
  376.         }                                 
  377. }
  378. /***************************************************************************************
  379.                  显示子程序 两个数,分别记录键值和重复码个数
  380. *****************************************************************************************/
  381.                 void display()  
  382.                         {   
  383.                                P2 = 0x7f;         //送位选数据0111 1111                                 
  384.                                    P0 = (displaychar1[0]);        //送段选数据
  385.                                       timeout(LD);        //延时
  386.                                        P0 =0xff;                        //消隐,很重要,不然会闪烁,共阴数码管用P0=0x00
  387.                                                                                                                                 
  388.                                 P2 = 0xbf;                //送位选数据1011 1111     
  389.                                    P0 = displaychar1[1];
  390.                                       timeout(LD);        //延时
  391.                                        P0 =0xff;
  392.                        
  393.                                 P2 = 0xdf;                //送位选数据1101 1111   
  394.                                    P0 = displaychar1[2];
  395.                                       timeout(LD);//延时      
  396.                                        P0 =0xff;
  397.                                     
  398.                                 P2 = 0xef;                //送位选数据1110 1111   
  399.                                    P0 = displaychar1[3];
  400.                                       timeout(LD);        //延时
  401.                                        P0 =0xff;      
  402.                                 
  403.                                 P2 = 0xf7;                //送位选数据1111 0111     
  404.                                    P0 = displaychar1[4];
  405.                                       timeout(LD);        //延时
  406.                                        P0 =0xff;
  407.                                 
  408.                                 P2 = 0xfb;                //送位选数据1111 1011      
  409.                                    P0 = displaychar1[5];
  410.                                       timeout(LD);          //延时                                                         
  411.                                        P0 =0xff;
  412.                        
  413.                                 P2 = 0xfd;                //送位选数据1111 1101            
  414.                                    P0 = displaychar1[6];   
  415.                                       timeout(LD);        //延时
  416.                                        P0 =0xff;
  417.                        
  418.                                 P2 = 0xfe;                //送位选数据1111 1110   
  419.                                     P0 = displaychar1[7];
  420.                                        timeout(LD);        //延时
  421.                                         P0 =0xff;      
  422.                         }
  423. /************************************温度显示子程序*****************************************/
  424. DS18b20display()
  425. {
  426.         if(fg==1)        //温度为正时显示的数据
  427.         {
  428.                 if((temp_value/100)>=1)        //若温度高于100度时--即温度百位数大于或等于1的时候
  429.                 {
  430.                         displaychar1[0] = duan[11];                //不显示
  431.                         displaychar1[1] = duan[temp_value/100];                //显示温度百位
  432.                         displaychar1[2] = duan[temp_value%100/10];        //显示温度十位
  433.                         displaychar1[3] = duan[temp_value%10]&0x7f;   //显示温度个位和小数点
  434.                         displaychar1[4] = duan[temp1_value*625/1000%10];//显示温度小数点后第一位
  435.                         displaychar1[5] = duan[11];                //不显示
  436.                         displaychar1[6] = duan[12];      //温度显示"0"        
  437.                         displaychar1[7] = duan[13];                //温度显示"C"
  438.                 }
  439.                         if((temp_value%100/10)>=1&(temp_value/100)<1)        //若温度高于10度与温度低于100度时--即温度十位数大于或等于1并且温度百位数小于1的时候
  440.                         {
  441.                                 displaychar1[0] = duan[11];                //不显示
  442.                                 displaychar1[1] = duan[11];                //不显示
  443.                                 displaychar1[2] = duan[temp_value%100/10];        //显示温度十位
  444.                                 displaychar1[3] = duan[temp_value%10]&0x7f;   //显示温度个位和小数点
  445.                                 displaychar1[4] = duan[temp1_value*625/1000%10];//显示温度小数点后第一位
  446.                                 displaychar1[5] = duan[11];                //不显示
  447.                                 displaychar1[6] = duan[12];     //温度显示"0"         
  448.                                 displaychar1[7] = duan[13];                //温度显示"C"
  449.                         }
  450.                                 if((temp_value%100/10)<1&(temp_value/100)<1)        //若温度低于10度时--即温度十位数小于1并且百位数小于1的时候
  451.                                 {
  452.                                         displaychar1[0] = duan[11];                //不显示
  453.                                         displaychar1[1] = duan[11];                //不显示
  454.                                         displaychar1[2] = duan[temp_value%10]&0x7f;   //显示温度个位和小数点
  455.                                         displaychar1[3] = duan[temp1_value*625/1000%10];//显示温度小数点后第一位
  456.                                         displaychar1[4] = duan[11];                //不显示
  457.                                         displaychar1[5] = duan[12];     //温度显示"0"
  458.                                         displaychar1[6] = duan[13];      //温度显示"C"      
  459.                                         displaychar1[7] = duan[11];                //不显示
  460.                                 }
  461.         }
  462.         if(fg==0)   //温度为负时显示的数据
  463.         {
  464.                 if(((temp_value-1)%100/10)>=1)        //如果为负10度以下时
  465.                 {
  466.                         displaychar1[0] = duan[11];                //不显示
  467.                         displaychar1[1] = duan[10];                //显示"-"
  468.                         displaychar1[2] = duan[(temp_value-1)%100/10];        //显示负温度十位
  469.                         displaychar1[3] = duan[(temp_value-1)%10]&0x7f;   //显示负温度个位和小数点
  470.                         displaychar1[4] = duan[temp1_value*625/1000%10];//显示负温度小数点后第一位
  471.                         displaychar1[5] = duan[11];                //不显示
  472.                         displaychar1[6] = duan[12];      //温度显示"0"        
  473.                         displaychar1[7] = duan[13];                //温度显示"C"
  474.                                        
  475.                         fg=1;                                                                //清负温度标志
  476.                 }
  477.                 else                                //负十度以上时
  478.                 {
  479.                         displaychar1[0] = duan[11];                //不显示
  480.                         displaychar1[1] = duan[11];                //不显示
  481.                         displaychar1[2] = duan[10];        //显示"-"
  482.                         displaychar1[3] = duan[(temp_value-1)%10]&0x7f;   //显示负温度个位和小数点
  483.                         displaychar1[4] = duan[temp1_value*625/1000%10];//显示负温度小数点后第一位
  484.                         displaychar1[5] = duan[11];                //不显示
  485.                         displaychar1[6] = duan[12];     //温度显示"0"//小数点后第二位temp1_value*625/100%10      
  486.                         displaychar1[7] = duan[13];                //温度显示"C"   //小数点后第三位temp1_value*625/10%10

  487.                         fg=1;                                                                //清负温度标志      
  488.                 }
  489.         }//温度为负时显示的数据包含的大括号      
  490. }//显示温度数据包含的大括号                              

  491. /***************************************主函数**************************************************/
  492. main()
  493. {                                    
  494.     SCLK = 0 ;                 /* DS1302实时时钟的串行时钟引脚(第7脚SCLK)*/
  495.     TRST = 0 ;                /* DS1302实时时钟的复位/片选线引脚(第5脚RST低电平复位高电平时芯片正常工作)*///复位DS1302实时时钟
  496.         readtime();             //先读一下时间然后再判断自动补偿程序
  497.         fen=min;                                //fen用来判断min是否到了1分钟
  498.         if(S2==0)        //上电检测 如果调整键S2被按下就初始化1302 给初值是17年12月26日,16:30:00星期二
  499.     {                                //这里是给系统送初始值的,使用的方法是断电之后,按住S2调整键,然后上电,S2键按住1~3s,松开即设置完成
  500.          sendchar(0x8e,0);                //去DS1302写保护
  501.          sendchar(0x80,0x00);        //写入秒数据00
  502.          sendchar(0x82,0x30);        //写入分数据30
  503.          sendchar(0x84,0x16);        //写入小时数据16
  504.          sendchar(0x8a,0x02);        //写入星期数据2
  505.          sendchar(0x86,0x26);        //写入日期数据26
  506.          sendchar(0x88,0x12);        //写入月份数据12
  507.          sendchar(0x8c,0x17);        //写入年份数据17
  508.          sendchar(0x8e,0x80);        //DS1302加写保护
  509.     }
  510.     TMOD = 0x12;    //设置定时器工作模式0001 0010(T1为方式1-16位定时器/计数器  T2为方式2-8位初值自动重装的8位定时器/计数器)
  511.     TR1 = 1;        //启动定时器/计数器1               
  512.     TR0 = 1;                //启动定时器/计数器0
  513.     while(1)                //大循环
  514.     {
  515.                 readtime();             //先读一下时间然后再判断自动补偿程序
  516.                 if(fen!=min)                        //如果fen不等于min证明过了1分钟了
  517.                 {
  518.                         fen=min;                //那么再让fen等于min
  519.                         tz++;                        //tz自加1
  520.                 }
  521.                 if((tz==38)&(sce>=01))        //如果计时到了38分钟和秒钟过了1秒的时候
  522.                 {
  523.                         tz=0;                                                                        //tz清零
  524.                         sendchar(0x8e,0);                         //去DS1302写保护
  525.                 sendchar(0x80,0x00);                                         //秒清0--即减去1秒或者加1秒再这里修改
  526.                 sendchar(0x8e,0x80);                      //加写保护
  527.                 }
  528.         if(!S2)                //检测设置按键S2是否按下
  529.                 s2 = jianpan(S2);        //若S2被按下则扫描键盘扫描程序S2
  530.                 if(!S3)                //检测减数据按键S3是否被按下
  531.                         s3 = jianpan(S3);        //若S3被按下则扫描键盘扫描程序S3
  532.                          if(!S4)                 //检测加数据按键S4是否被按下
  533.                                  s4 = jianpan(S4);        //若S4被按下则扫描键盘扫描程序S4
  534.                  TRST = 0;        /* DS1302实时时钟的复位/片选线引脚(第5脚RST低电平复位高电平时芯片正常工作)*/
  535.         /*以下是开始年月日自动归零的问题修改,问题产生原因是开始没有加!setbit这个条件,程序在运行到设置年月日时依然会进
  536.           入下面这个判断,然后再进入设置,但是年月日在这里还没有读数,所以这里的设置就会进入M=0然后加或减,从而让设置值
  537.           出现错误
  538.         */
  539.     if((!ya&(!setbit)&(!s3))|(setbit&(sdat<4)))//如果S2没有被按下且不在显示年月日的延时范围,而且设置标识为0时,或者在标识为1但是设置值在123中时,则正常显示时间格式                                                                                               
  540.         {
  541.         readtime();             //先读一下时间然后再判断设置程序,这样的主要目的是让初m的值由1302决定。
  542.                 ReadTemp();                                //读取DS18B20当前温度
  543.         if(s2|setbit)          //按下S2或设置标识打开时会进入本判断
  544.         {
  545.              ya = 0;                                //进设置后会关闭日期显示延时
  546.              settime();                  //设置时间日期子程序
  547.         }
  548.                 else        //正常显示时间和温度
  549.                 {
  550.                         if((sce%5)!=0)        //如果秒对5求余不等于0的时候显示时间--即温度和时间间歇显示,时间显示比温度显示长
  551.                         {
  552.                                 displaychar1[0] = duan[hour/16];                //正常显示小时十位
  553.                                 displaychar1[1] = duan[hour%16];                //正常显示小时个位
  554.                                 displaychar1[2] = duan[10];                                //正常显示"-"
  555.                                 displaychar1[3] = duan[min/16];                        //正常显示分钟十位
  556.                                 displaychar1[4] = duan[min%16];                        //正常显示分钟个位
  557.                                 displaychar1[5] = duan[10];                                //正常显示"-"
  558.                                 displaychar1[6] = duan[sce/16];             //正常显示秒钟十位         
  559.                                 displaychar1[7] = duan[sce%16];                        //正常显示秒钟个位
  560.                         }
  561.                         else        //否则显示温度
  562.                         {
  563.                                 DS18b20display();        //温度显示子程序
  564.                         }
  565.                 }//正常显示时间和温度数据包含的大括号                              
  566.         }//如果S2没有被按下且不在显示年月日的延时范围,而且设置标识为0时,或者在标识为1但是设置值在123中时,则正常显示时间格式包含的大括号                                       
  567.     if(((!setbit)&s3)|ya>0|(setbit&sdat>3))
  568.     {
  569.             if(TF1&!setbit)                 //如果定时器1计满溢出或设置标识打开时会进入本判断
  570.             {
  571.                ya++;              //非设置页面才进去日期延时
  572.                TF1 = 0;                        //定时器1溢出标志清0(溢出时TF1被硬件置1,并且申请中断,软件查询到该位置1后需用软件清零)
  573.             }                       
  574.             readyear();                                //读取年月日数据
  575.             if(s2|setbit)            //如果按下S2或设置标识打开时会进入本判断
  576.             {
  577.                ya = 0;                //进设置后会关闭日期显示延时
  578.                settime();                        //设置时间日期子程序
  579.             }
  580.                 displaychar1[0] = duan[2];                        //显示年月日 固定显示2
  581.                 displaychar1[1] = duan[0];                        //显示年月日 固定显示0
  582.                 displaychar1[2] = duan[year/16];                //显示年份十位
  583.                 displaychar1[3] = duan[year%16]&0x7f;        //显示年份个位****&0x7f是让这一位显示出小数点,共阴数码管就是或0x80或者是+0x80
  584.                 displaychar1[4] = duan[month/16];                //显示月份十位
  585.                 displaychar1[5] = duan[month%16]&0x7f;        //显示月份个位****&0x7f是让这一位显示出小数点,共阴数码管就是或0x80或者是+0x80
  586.                 displaychar1[6] = duan[date/16];                //显示日期十位
  587.                 displaychar1[7] = duan[date%16];                //显示日期个位
  588.                 if(ya>70) ya =0;       //日期延时约6秒,大约时间,与计时器和程序的运行有关
  589.      }
  590.      s3 = s4 =0;               
  591.      if(S2==S3==S4==1)                //松手检测  如果三个按键都没有被按下
  592.      {  
  593.          ja = 0;
  594.          TR0 = 1;                //启动定时器0
  595.          s2= s3= s4= 0; //松开按键后恢复计时器并清零按键值
  596.        //s=0;     //为快速跳时,s清零放在松手检测中,s3和s4在按下不放后会重复跳值,想要每次按下只起作用一次,请将s放在本循环外面这个循环后面
  597.      }                               //
  598.          s = 0;
  599.      for(a=0; a<50;a++)                 //一个循环显示50次数码管
  600.          display();
  601.   }//while包含的大括号
  602. }
复制代码


回复

使用道具 举报

ID:76227 发表于 2018-1-16 17:17 | 显示全部楼层
明显是刷新数码管频率的问题,做好的办法是使用数码管驱动IC。最方便,软件刷新数码管效率很低
回复

使用道具 举报

ID:46220 发表于 2018-1-16 20:51 | 显示全部楼层
905377346 发表于 2018-1-16 17:17
明显是刷新数码管频率的问题,做好的办法是使用数码管驱动IC。最方便,软件刷新数码管效率很低

谢谢指导,那我再从这方面想想
回复

使用道具 举报

ID:46220 发表于 2018-1-16 22:03 | 显示全部楼层
我把数码管的刷新时间加快也不行,还是老样子,数码管的显示亮度已经变得很暗了,时分秒还是不能闪烁
回复

使用道具 举报

ID:46220 发表于 2018-1-16 23:05 | 显示全部楼层

显示温度

显示温度

显示时间

显示时间

按下S3时显示年月日

按下S3时显示年月日

回复

使用道具 举报

ID:267736 发表于 2018-1-18 04:02 | 显示全部楼层
楼主搞定了吗?你是参考哪个帖子做的?
回复

使用道具 举报

ID:46220 发表于 2018-1-18 07:52 | 显示全部楼层
izhineng 发表于 2018-1-18 04:02
楼主搞定了吗?你是参考哪个帖子做的?

是这个
http://www.51hei.com/bbs/dpj-99616-1.html
回复

使用道具 举报

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

本版积分规则

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

Powered by 单片机教程网

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