找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 9448|回复: 21
收起左侧

1寸数码管时钟+12C5A60S2单片机+自动亮度+时间温度轮流显示(实物+代码)

  [复制链接]
ID:140489 发表于 2018-12-18 19:26 | 显示全部楼层 |阅读模式
本帖最后由 lids 于 2018-12-21 08:41 编辑

描述: 4位共阳1寸数码管时钟,显示88:88样式,正常走时的时候,“:”1秒亮灭1次;调时间的的时候冒号熄灭
       调时:按KEY1按键第1次分钟位闪烁,再按KEY2一次分钟加1,按KEY3一次分钟减1,长按连加连减;
       按KEY1按键第2次小时位闪烁,再按KEY2一次小时加1,按KEY3一次小时减1,长按连加连减;
       按KEY1按键第3次,秒从零开始累加,时钟回到正常走时;
       校时的时候先调好时、分,分钟要比参考时间的分钟加1分,
       再看参考时间的秒数到了59再按KEY1按键的第3次,这样对时就比较准了,因为KEY1按键按第3次后秒会清零。
       加备用电池,掉电走时
                        
       KEY2键第2功能:非调时状态,为光控开关;
       KEY3键第2功能:非调时状态,为显示切换开关;
       DS18B20做温度检测,       可显示3个界面:1.实时时钟与温度轮流显示、2.只显示温度、3.只显示时间;
       温度显示范围: -9.9℃~99.9℃;
       增加数码管调亮度功能,自动10级亮度,P1.0接5.1K电阻上拉、光敏电阻下拉分压;
       环境光线越亮,数码管越亮,反之数码管越暗,晚上看不刺眼。
实物通过.  
                         12MHz晶振,STC12C5A60S2+DS1302时钟芯片+DS18B20,
                         P0口接段位,P2^4~P2^7接pnp三极管控制4个共阳极。

制作出来的实物图如下:
1.jpg 2.jpg

附件里有完整C文件,PCB文件,原理图
  1. /*********************************************************************************
  2. 描述: 4位共阳数码管时钟,显示88:88样式,正常走时的时候,“:”1秒闪烁2次;调时间的的时候冒号熄灭
  3.        调时:按KEY1按键第1次分钟位闪烁,再按KEY2一次分钟加1,按KEY3一次分钟减1,长按连加连减;
  4.                          按KEY1按键第2次小时位闪烁,再按KEY2一次小时加1,按KEY3一次小时减1,长按连加连减;
  5.                          按KEY1按键第3次,秒从零开始累加,时钟回到正常走时;
  6.                          校时的时候先调好时、分,分钟要比参考时间的分钟加1分,
  7.                          再看参考时间的秒数到了59再按KEY1按键的第3次,这样对时就比较准了。
  8.                          加备用电池,掉电走时
  9.                         
  10.                          KEY2键第2功能:非调时状态,为光控开关;
  11.                          KEY3键第2功能:非调时状态,为显示切换开关;
  12.                          DS18B20做温度检测,实时时钟与温度轮流显示;
  13.                          温度显示范围: -9.9℃~99.9℃;
  14.                          增加数码管调亮度功能,按键10级亮度P1.0接5.1K电阻上拉、光敏电阻下拉分压;
  15.                          环境光线越亮,数码管越亮,反之数码管越暗。
  16. 实物通过.  
  17.                          12MHz晶振,STC12C5A60S2+DS1302时钟芯片+DS18B20,
  18.                          P0口接段位,P2^4~P2^7接pnp三极管控制4个共阳极。
  19. **********************************************************************************/
  20. #include <STC12C5A60S2.h>
  21. #include <intrins.h>
  22. #define uchar unsigned char
  23. #define uint unsigned int


  24. sbit TSCLK = P2^0;//时钟线
  25. sbit TIO   = P2^1;//数据线
  26. sbit TRST  = P2^2;//使能端

  27. sbit key1 = P3^0;   //设置键
  28. sbit key2 = P3^1;   //加 /光控开关键(校时的时候做加键,反之为光控开关)
  29. sbit key3 = P3^2;   // 减/显示切换键
  30. sbit DQ = P2^3;                //DS18B20数据口

  31. sbit w1 = P2^4;          //设置位驱动口
  32. sbit w2 = P2^5;
  33. sbit w3 = P2^6;
  34. sbit w4 = P2^7;
  35. sbit w5 = P3^7;         //此位不显示
  36. sbit dd = P1^4;         //蜂鸣器控制端

  37. uchar xs=0; //显示切换计数变量
  38. uchar knum,shan_cont;
  39. char shi,fen,miao;
  40. uchar ba=40;
  41. uint mh,mh_count,count;
  42. bit shan;           //校时闪烁标志位
  43. uchar s=0;                   //显示负号
  44. uint temp;        //温度值
  45. bit flag;                  //轮流显示标志位
  46. bit flag_gk;          //光控标志位
  47. bit flag_js=0;          //自动校时标志
  48. bit flag_fm;          //蜂鸣器启动标志
  49. uchar fm;                //蜂鸣器计时变量
  50. /***************************************定义转换控制寄存器控制位*****************************************/
  51. #define ADC_POWER                   0X80            //电源控制位
  52. #define ADC_FLAG                    0X10            //转换结束标志位
  53. #define ADC_START                   0X08            //转换开始位
  54. /*********************************************定义AD转换速度*********************************************/
  55. #define ADC_SPEEDLL_540         0X00           
  56. #define ADC_SPEEDLL_360                0X20
  57. #define ADC_SPEEDLL_180                0X40
  58. #define ADC_SPEEDLL_90                0X60


  59. /***********写时分秒地址************/
  60. #define write_shi  0x84
  61. #define write_fen  0x82
  62. #define write_miao 0x80
  63. #define write_ram  0xc0
  64. /***********读时分秒地址************/
  65. #define read_shi  0x85
  66. #define read_fen  0x83
  67. #define read_miao 0x81
  68. #define read_ram  0xc1

  69. uchar code table[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0xff,0x46,0xbf};//共阳段码 (0--9、黑屏、C、-)

  70. /*********************************************************************************************************
  71. ** 函数功能 :延时函数
  72. ** 函数说明 :利用软件延时,占用CPU
  73. ** 入口参数 :time:需要延时的时间,
  74. ** 出口参数 :无
  75. *********************************************************************************************************/
  76. void Delay_ms(uint time)
  77. {
  78.         uint i,j;
  79.         for(i = 0;i < time;i ++)
  80.                 for(j = 0;j < 45;j ++);
  81. }
  82. /******************************/

  83. //void Delay_1(uint time)
  84. //{
  85. //        uint i,j;
  86. //        for(i = 0;i < time;i ++)
  87. //                for(j = 0;j < 600;j ++);
  88. //}



  89. /*********************************************************************************************************
  90. ** 函数功能 :延时函数
  91. ** 函数说明 :利用软件延时,占用CPU,经调试最小单位大约为1us
  92. ** 入口参数 :time:需要延时的时间,单位us
  93. ** 出口参数 :无
  94. *********************************************************************************************************/
  95. void delay(uchar n)
  96. {
  97.     while (n--)
  98.     {
  99.         _nop_();
  100.         _nop_();
  101.     }
  102. }

  103. /*************蜂鸣器*****************/
  104. //void didi(uchar i)
  105. //{
  106. //        uchar x;
  107. //        for(x = i; x >0; x--)
  108. //        {
  109. //                dd = 0;
  110. //                Delay_1(200);
  111. //                dd = 1;
  112. //                Delay_1(200);
  113. //        }
  114. //}

  115. /*****************DS18B20******************/

  116. void Init_Ds18b20(void)     //DS18B20初始化send reset and initialization command
  117. {
  118.         DQ = 1;                     //DQ复位,不要也可行。
  119.         delay(1);                  //稍做延时
  120.         DQ = 0;                    //单片机拉低总线
  121.         //delay(250);                //精确延时,维持至少480us
  122.         delay(240);
  123.         delay(240);
  124.         DQ = 1;                    //释放总线,即拉高了总线
  125.         delay(240);                //此处延时有足够,确保能让DS18B20发出存在脉冲。
  126. }

  127. uchar Read_One_Byte()       //读取一个字节的数据read a byte date
  128.                             //读数据时,数据以字节的最低有效位先从总线移出
  129. {
  130.         uchar i   = 0;
  131.         uchar dat = 0;
  132.         for(i=8;i>0;i--)
  133.         {
  134.            DQ = 0;                  //将总线拉低,要在1us之后释放总线
  135.                                    //单片机要在此下降沿后的15us内读数据才会有效。
  136.            delay(1);                //至少维持了1us,表示读时序开始
  137.            dat >>= 1;               //让从总线上读到的位数据,依次从高位移动到低位。
  138.            DQ = 1;                  //释放总线,此后DS18B20会控制总线,把数据传输到总线上
  139.            delay(7);                 //延时7us,此处参照推荐的读时序图,尽量把控制器采样时间放到读时序后的15us内的最后部分
  140.            if(DQ)                   //控制器进行采样
  141.            {
  142.             dat |= 0x80;            //若总线为1,即DQ为1,那就把dat的最高位置1;若为0,则不进行处理,保持为0
  143.            }        
  144.            delay(60);               //此延时不能少,确保读时序的长度60us。
  145.         }
  146.         return (dat);
  147. }

  148. void Write_One_Byte(uchar dat)
  149. {
  150.         uchar i = 0;
  151.         for(i=8;i>0;i--)
  152.         {
  153.            DQ = 0;                        //拉低总线
  154.            delay(1);                       //至少维持了1us,表示写时序(包括写0时序或写1时序)开始
  155.            DQ = dat&0x01;                 //从字节的最低位开始传输
  156.                                          //指令dat的最低位赋予给总线,必须在拉低总线后的15us内,
  157.                                          //因为15us后DS18B20会对总线采样。
  158.            delay(60);                     //必须让写时序持续至少60us
  159.            DQ = 1;                        //写完后,必须释放总线,
  160.            dat >>= 1;
  161.            delay(1);
  162.         }
  163. }


  164. uint Get_Tmp()                   //获取温度get the temperature
  165. {
  166.         float tt;
  167.         uchar L,M;
  168.         Init_Ds18b20();                //初始化
  169.         Write_One_Byte(0xcc);          //忽略ROM指令
  170.         Write_One_Byte(0x44);          //温度转换指令
  171.         Init_Ds18b20();                 //初始化
  172.         Write_One_Byte(0xcc);          //忽略ROM指令
  173.         Write_One_Byte(0xbe);          //读暂存器指令
  174.         L = Read_One_Byte();           //读取到的第一个字节为温度LSB
  175.         M = Read_One_Byte();           //读取到的第一个字节为温度MSB
  176.         //模拟显示-0.5度,实际测温需注解掉下面这两句
  177. //        L = 0xf8;
  178. //        M = 0xff;
  179.         
  180.         //模拟显示+0.5度,实际测温需注解掉下面这两句
  181. //        L = 0x08;
  182. //        M = 0x00;

  183.         temp = M;                      //先把高八位有效数据赋于temp
  184.         temp <<= 8;                    //把以上8位数据从temp低八位移到高八位
  185.         temp = temp|L;                //两字节合成一个整型变量

  186.         if(M >= 0x08)        //判断是否为负数
  187.         {
  188.                 temp = ~temp + 1;//负数是以补码的形式存放的需要取反加1
  189.                 s = 0xbf;  //显示负数符号
  190.         }
  191.         else s = 0;           //为正数则不显示负数符号


  192.         tt = temp*0.0625;              //得到真实十进制温度值
  193.                                         //因为DS18B20可以精确到0.0625度
  194.                                         //所以读回数据的最低位代表的是0.0625度
  195.         temp = tt*10+0.5;               //放大十倍
  196.                                         //这样做的目的将小数点后第一位也转换为可显示数字
  197.                                         //同时进行一个四舍五入操作。
  198.         return temp;
  199. }


  200. /****************温度显示函数**************/

  201. void Display_tem(uint temp)   //显示程序
  202. {
  203.         uchar A1,A2,A3;
  204.         A1 = temp/100;    //百位
  205.         A2 = temp%100/10;   //十位
  206.         A3 = temp%10;    //个位
  207.         
  208.         if(A1 > 0 && s == 0 )
  209.         {
  210.                 P0 = 0xff;
  211.                 w2 = 1; w3 = 1; w4 = 1;
  212.                 Delay_ms(50-ba);
  213.                 P0 = table[A1];    //显示百位
  214.                 w1 = 0;
  215.                 Delay_ms(ba);
  216.         }
  217.         else
  218.         {
  219.                 if(A1 == 0 && s == 0)
  220.                 {
  221.                         P0 = 0xff;
  222.                         w2 = 1; w3 = 1; w4 = 1;
  223.                         Delay_ms(50-ba);
  224.                         P0 = table[10];    //百位为0不显
  225.                         w1 = 0;
  226.                         Delay_ms(ba);
  227.                 }
  228.                 else
  229.                 if(s != 0)
  230.                 {
  231.                         P0 = 0xff;
  232.                         w2 = 1; w3 = 1; w4 = 1;
  233.                         Delay_ms(50-ba);
  234.                         P0 = s;    //百位为负数显示-
  235.                         w1 = 0;
  236.                         Delay_ms(ba);
  237.                 }
  238.                  
  239.         
  240.         }
  241.         
  242.         
  243.         P0 = 0xff;
  244.         w1 = 1; w3 = 1; w4 = 1;
  245.         Delay_ms(50-ba);
  246.         P0 = table[A2]&0X7F;   //显示十位,使用的是有小数点的数组(因为temp值扩大了10倍,虽然是十位,实际为个位)
  247.         w2 = 0;
  248.         Delay_ms(ba);
  249.         
  250.         P0 = 0xff;
  251.         w1 = 1; w2 = 1;  w4 = 1;
  252.         Delay_ms(50-ba);
  253.         P0 = table[A3];
  254.         w3 = 0;   
  255.         Delay_ms(ba);        
  256.          
  257.         P0 = 0xff;
  258.         w1 = 1; w2 = 1; w3 = 1;
  259.         Delay_ms(50-ba);
  260.         P0 = 0x46;   //显示C字样
  261.         w4 = 0;
  262.         Delay_ms(ba);
  263.         
  264.         P0 = 0xff;
  265.         w1 = 1; w2 = 1; w3 = 1;
  266.         Delay_ms(50-ba);
  267.         P0 = 0xff;   
  268.         w5 = 0;
  269.         P0 = 0xff;
  270.         Delay_ms(ba);        
  271. }



  272. void display( uchar shi,uchar fen)           //时间显示函数
  273. {

  274. /*****正常显示******/
  275.         if(knum == 0)
  276.         {
  277.                 if(shi/10 > 0)
  278.                 {
  279.                         w2 = 1; w3 = 1; w4 = 1;
  280.                         Delay_ms(50-ba);
  281.                         P0 = table[shi/10];    //显示小时十位
  282.                         w1 = 0;
  283.                         Delay_ms(ba);
  284.                 }
  285.                 else
  286.                 {
  287.                         w2 = 1; w3 = 1; w4 = 1;
  288.                         Delay_ms(50-ba);
  289.                         P0 = table[10];    //小时十位为0不显示
  290.                         w1 = 0;
  291.                         Delay_ms(ba);
  292.                
  293.                 }
  294.         
  295.                 P0 = 0xff;
  296.                 w1 = 1; w3 = 1; w4 = 1;
  297.                 Delay_ms(50-ba);
  298.                 if(mh_count>=50)
  299.                 P0 = table[shi%10]&0x7f;    //显示小时个位
  300.                 else
  301.                 P0 = table[shi%10];
  302.                 w2 = 0;
  303.                 Delay_ms(ba);
  304.                  
  305.                 P0 = 0xff;
  306.                 w1 = 1; w2 = 1; w4 = 1;
  307.                 Delay_ms(50-ba);
  308.                 if(mh_count>=50)
  309.                 P0 = table[fen/10]&0x7f;    //显示分钟十位
  310.                 else
  311.                 P0 = table[fen/10];
  312.                 w3 = 0;
  313.                 Delay_ms(ba);
  314.         
  315.                 P0 = 0xff;
  316.                 w2 = 1; w3 = 1; w1 = 1;
  317.                 Delay_ms(50-ba);
  318.                 P0 = table[fen%10];    //显示分钟个位
  319.                 w4 = 0;
  320.                 Delay_ms(ba);
  321.         
  322.                 P0 = 0xff;
  323.                 w1 = 1; w2 = 1; w3 = 1;
  324.                 Delay_ms(50-ba);
  325.                 P0 = 0xff;   
  326.                 w5 = 0;                  //这里扫描一个空位,数码管前4位亮度就均匀了,第4位与前3位亮度一致,不然第4位要比前3位亮
  327.                 P0 = 0xff;
  328.                 Delay_ms(ba);        
  329.         }

  330. /********校时小时位闪烁************/

  331. //        P0 = 0xff;
  332.         if(knum==1)
  333.         {
  334.                  if( shan==0 )
  335.                 {
  336.                 w2 = 1; w3 = 1; w4 = 1;
  337.                 Delay_ms(50-ba);
  338.                 P0 = 0xff;    //显示小时十位
  339.                 w1 = 0;
  340.                 Delay_ms(ba);

  341.                 P0 = 0xff;
  342.                 w1 = 1; w3 = 1; w4 = 1;
  343.                 Delay_ms(50-ba);
  344.                 P0 = 0xff;;
  345.                 w2 = 0;
  346.                 Delay_ms(ba);
  347.                 }
  348.         

  349.                 else
  350.                 {
  351.                         w2 = 1; w3 = 1; w4 = 1;
  352.                         Delay_ms(50-ba);
  353.                         P0 = table[shi/10];    //显示小时十位
  354.                         w1 = 0;
  355.                         Delay_ms(ba);
  356.                  
  357.                         P0 = 0xff;
  358.                         w1 = 1; w3 = 1; w4 = 1;
  359.                         Delay_ms(50-ba);
  360.                         P0 = table[shi%10];
  361.                         w2 = 0;
  362.                         Delay_ms(ba);
  363.                 }         
  364.                 P0 = 0xff;
  365.                 w1 = 1; w2 = 1; w4 = 1;
  366.                 Delay_ms(50-ba);
  367.                 P0 = table[fen/10];
  368.                 w3 = 0;
  369.                 Delay_ms(ba);
  370.         
  371.                 P0 = 0xff;
  372.                 w2 = 1; w3 = 1; w1 = 1;
  373.                 Delay_ms(50-ba);
  374.                 P0 = table[fen%10];    //显示分钟个位
  375.                 w4 = 0;
  376.                 Delay_ms(ba);
  377.         
  378.                 P0 = 0xff;
  379.                 w1 = 1; w2 = 1; w3 = 1;
  380.                 Delay_ms(50-ba);
  381.                 P0 = 0xff;   
  382.                 w5 = 0;                  //这里扫描一个空位,数码管前4位亮度就均匀了,第4位与前3位亮度一致,不然第4位要比前3位亮
  383.                 P0 = 0xff;
  384.                 Delay_ms(ba);
  385.         }        
  386. /*******校时分钟位闪烁*******/

  387.         if(knum==2 )
  388.         {
  389.                 if(shan==0)
  390.                 {
  391.                 w2 = 1; w1 = 1; w4 = 1;
  392.                 Delay_ms(50-ba);
  393.                 P0 = 0xff;    //显示小时十位
  394.                 w3 = 0;
  395.                 Delay_ms(ba);

  396.                 P0 = 0xff;
  397.                 w1 = 1; w3 = 1; w2 = 1;
  398.                 Delay_ms(50-ba);
  399.                 P0 = 0xff;;
  400.                 w4 = 0;
  401.                 Delay_ms(ba);
  402.                 }
  403.                 else
  404.                 {
  405.                         w2 = 1; w1 = 1; w4 = 1;
  406.                         Delay_ms(50-ba);
  407.                         P0 = table[fen/10];    //显示小时十位
  408.                         w3 = 0;
  409.                         Delay_ms(ba);
  410.                  
  411.                         P0 = 0xff;
  412.                         w1 = 1; w3 = 1; w3 = 1;
  413.                         Delay_ms(50-ba);
  414.                         P0 = table[fen%10];
  415.                         w4 = 0;
  416.                         Delay_ms(ba);
  417.                 }         

  418.                 P0 = 0xff;
  419.                 w3 = 1; w2 = 1; w4 = 1;
  420.                 Delay_ms(50-ba);
  421.                 P0 = table[shi/10];
  422.                 w1 = 0;
  423.                 Delay_ms(ba);
  424.         
  425.                 P0 = 0xff;
  426.                 w4 = 1; w3 = 1; w1 = 1;
  427.                 Delay_ms(50-ba);
  428.                 P0 = table[shi%10];    //显示分钟个位
  429.                 w2 = 0;
  430.                 Delay_ms(ba);


  431.         
  432.                 P0 = 0xff;
  433.                 w1 = 1; w2 = 1; w3 = 1;
  434.                 Delay_ms(50-ba);
  435.                 P0 = 0xff;   
  436.                 w5 = 0;                  //这里扫描一个空位,数码管前4位亮度就均匀了,第4位与前3位亮度一致,不然第4位要比前3位亮
  437.                 P0 = 0xff;
  438.                 Delay_ms(ba);
  439.         }               
  440.         
  441. }


  442. void t0_init()
  443. {
  444. //        TMOD |= 0x02;  //定时器0,8位自动重装模式
  445. //        TH0=TL0= 0X9c;  //100微秒初值 @12MHz
  446. //        TH0=TL0= 0Xce;  //50微秒初值 @12MHz
  447.         TMOD |= 0x01;  //定时器0,16位模式
  448.         TL0 = 0xF0;                //设置定时初值 10毫秒初值 @12MHz
  449.         TH0 = 0xD8;                //设置定时初值
  450.         EA=1;
  451.         ET0=1;
  452.         TR0 = 1;
  453. //        EADC=1;        
  454. }

  455. //void InitADC()
  456. //{
  457. //        P1ASF =        0x01;//使能P1.0口ADC功能
  458. //        ADC_RES = 0;   //初始AD转换结果为零
  459. //        ADC_CONTR = 0xc8; //1100 1000  ,打开AD转换电源,转换速度180个时钟周期,ADC_FLAG清零,ADC_START置1启动AD,选择P1.0为AD输入通道
  460. //        Delay_ms(1);
  461. //}            



  462. /*********************************************************************************************************
  463. ** 函数功能 :内置ADC的初始化配置
  464. ** 函数说明 :使用内置ADC时需要先配置对应的P1口的管脚为模拟输入
  465. ** 入口参数 :port:需要配置为模拟输入的通道,使用或运算可以同时配置多个管脚
  466. **                          如:ADC_Init(ADC_PORT0 | ADC_PORT1 | ADC_PORT2)调用此函数后可以同时配置P1^0,P1^1,P1^2为模拟输入
  467. ** 出口参数 :无
  468. *********************************************************************************************************/
  469. void ADC_Init()
  470. {
  471.         P1ASF=0x01;//设置AD转换通道 P1.0
  472.         ADC_RES=0;//清空转换结果
  473.         ADC_CONTR=ADC_POWER | ADC_SPEEDLL_540;//打开AD转化器电源
  474. //        IE=0XA0;//开启总中断,ADC中断
  475.         _nop_();
  476.         _nop_();
  477.         _nop_();
  478.         _nop_();
  479. }
  480. /*********************************************************************************************************
  481. ** 函数功能 :获取ADC对应通道的值,查询法
  482. ** 函数说明 :每次只能获取一个通道的值,不同通道需要分别调用该函数获取
  483. ** 入口参数 :
  484. ** 出口参数 :
  485. *********************************************************************************************************/
  486. uchar GetADCResult()//读取通道ch的电压值
  487. {
  488. //        unsigned int ADC_RESULT = 0;//用来存放结果
  489. //        float result;
  490.         ADC_CONTR = ADC_POWER | ADC_SPEEDLL_540 | ADC_START;//开始转换,并设置测量通道为P1^0
  491.         _nop_();//需经过四个CPU时钟延时,上述值才能保证被设进ADC_CONTR控制寄存器
  492.         _nop_();
  493.         _nop_();
  494.         _nop_();
  495.         while(!(ADC_CONTR & ADC_FLAG));//等待转换结束
  496.         ADC_CONTR &= ~ADC_FLAG;//软件清除中断控制位
  497. //        ADC_RESULT = ADC_RES;
  498. //        ADC_RESULT = (ADC_RESULT << 2) | (0x02 & ADC_RESL);        //默认数据存储方式:高八位在ADC_RES,低二位在ADC_RESL低二位
  499. //        result = ADC_RESULT * 5.0 / 1024.0 ;  //基准电压为电源电压5V,10的分辨率,即1024
  500. //        return result;
  501.         return         ADC_RES;
  502. }




  503. void timer0() interrupt 1

  504. {

  505.         TL0 = 0xF0;                //重装定时初值 10毫秒初值 @12MHz
  506.         TH0 = 0xD8;                //重装定时初值

  507.         
  508.         mh_count++;                  //冒号闪烁变量
  509.         if(mh_count==100) //1秒时间到
  510.         {
  511.                 mh_count=0;
  512.                 count++;
  513.                 if(count==5)
  514.                 {
  515.                         count=0;
  516.                         flag = !flag;
  517.                 }
  518.         }


  519.         if(knum != 0)  //调时间的时候,闪烁的位表示为调节的位
  520.     {
  521.                 shan_cont++;
  522.         if(shan_cont==30)  //设置时,300ms闪烁时间,可根据实际效果调整
  523.         {
  524.                 shan_cont=0;
  525.                 shan = !shan;
  526.         }
  527.     }

  528.         if(flag_fm)         //如果蜂鸣器启动标志为1
  529.         {
  530.                 dd = 0;           //蜂鸣器响
  531.                 fm++;           //计时变量自加
  532.                 if(fm == 30) //到300ms,蜂鸣器停
  533.                 {
  534.                         fm = 0;         //计时变量清零
  535.                         dd = 1;        // 蜂鸣器停
  536.                         flag_fm = 0;//启动标志清零
  537.                 }

  538.         }
  539. }  


  540. //写DS1302数据
  541. void Write_DS1302_DAT(uchar cmd, uchar dat)
  542. {
  543.         uchar i;
  544.         TRST = 0; //拉低使能端
  545.         TSCLK = 0;//拉低数据总线
  546.         TRST = 1; //拉高使能端,产生上升沿开始写数据
  547.         for(i = 0; i < 8; i++)//每次写1位,写8次
  548.         {
  549.                 TSCLK = 0;                  //拉低时钟总线
  550.                 TIO = cmd & 0x01; //写1位数据,从最低位开始写
  551.                 TSCLK = 1;                  //拉高时钟总线,产生上升沿数据被DS1302读走
  552.                 cmd >>=1;                  //右移一位
  553.         }
  554.         for(i = 0; i < 8; i++)//每次写1位,写8次
  555.         {
  556.                 TSCLK = 0;                  //拉低时钟总线
  557.                 TIO = dat & 0x01; //写1位数据,从最低位开始写
  558.                 TSCLK = 1;                  //拉高时钟总线,产生上升沿数据被DS1302读走
  559.                 dat >>= 1;                  //右移一位
  560.         }
  561. }
  562. //读DS1302数据
  563. uchar Read_DS1302_DAT(uchar cmd)
  564. {
  565.         uchar i, dat;
  566.         TRST = 0;  //拉低使能端
  567.         TSCLK = 0; //拉低数据总线
  568.         TRST = 1;  //拉高使能端,产生上升沿开始写数据
  569.         for(i = 0; i < 8; i++)//每次写1位,写8次
  570.         {
  571.                 TSCLK = 0;                 //拉低时钟总线
  572.                 TIO = cmd & 0x01;//写1位数据,从最低位开始写
  573.                 TSCLK = 1;                 //拉高时钟总线,产生上升沿数据被DS1302读走
  574.                 cmd >>=1;                 //右移一位
  575.         }
  576.         for(i = 0; i < 8; i++)//每次读1位,读8次
  577.         {
  578.                 TSCLK = 0;                  //拉低时钟总线,产生下降沿,DS1302把数据放到TIO上
  579.                 dat >>= 1;                  //右移一位
  580.                 if(TIO)        dat |= 0x80;//读取数据,从最低位开始
  581.                 TSCLK = 1;                        //拉高时钟总线,以备下一次产生下降沿
  582.         }
  583.         return dat;        //返回读出数据
  584. }


  585. //数据转BCD码
  586. uchar Dat_Chg_BCD(uchar dat)
  587. {
  588.         uchar dat1, dat2;
  589.         dat1 = dat / 10;
  590.         dat2 = dat % 10;
  591.         dat2 = dat2 + dat1 * 16;
  592.         return dat2;
  593. }        


  594. //BCD码转换为数据
  595. uchar BCD_Chg_Dat(uchar dat)
  596. {
  597.         uchar dat1, dat2;
  598.         dat1 = dat / 16;
  599.         dat2 = dat % 16;
  600.         dat2 = dat2 + dat1 * 10;
  601.         return dat2;
  602. }



  603. void init_1302()                //初始化函数 设置时间
  604. {                                                //加备用电池,掉电走时

  605. //        if((Read_DS1302_DAT(0x81)& 0x80) != 0)        //读出秒数据,再跟80h(0x80)与运算看结果,结果是0则不需要初始化1302;是80h就要初始化!
  606.         
  607.         if(Read_DS1302_DAT(read_ram) != 0xaa) //如果第00个RAM位置不等于0xaa,就初始化1302
  608.         {
  609.                 Write_DS1302_DAT(0x8e, 0);//清除写保护
  610.                 Write_DS1302_DAT(write_miao, Dat_Chg_BCD(58));//58秒(并且进行BCD码转换)
  611.                 Write_DS1302_DAT(write_fen, Dat_Chg_BCD(10));//10分
  612.                 Write_DS1302_DAT(write_shi, Dat_Chg_BCD(9));//9时
  613.                 Write_DS1302_DAT(write_ram,0xaa);//写入初始化标志RAM(第00个RAM位置)
  614.                 Write_DS1302_DAT(0x8e, 0x80);//开写保护
  615.         }

  616. }         


  617. void read_sf()
  618. {

  619.         miao = BCD_Chg_Dat(Read_DS1302_DAT(0x81));//读秒寄存器(并且进行BCD码转换)
  620.         fen        = BCD_Chg_Dat(Read_DS1302_DAT(0x83));//读分寄存器
  621.         shi = BCD_Chg_Dat(Read_DS1302_DAT(0x85));//读时寄存器

  622. //        display(shi,fen);

  623. }


  624. void zdjs()                                                          //自动校时,这方法测试可行,每天减去快出的秒数
  625. {
  626.          if((shi==7)&&(fen==30)&&(miao==6))        //   时钟每天快6秒
  627.            {
  628.                            if(flag_js==0)
  629.                         {
  630.                                 Write_DS1302_DAT(0x8e,0x00);           //写保护取消
  631.                                 Write_DS1302_DAT(write_miao,0x00); //写秒0,这里是假如每天快6秒,每到这个时候就减去6秒
  632.                             Write_DS1302_DAT(0x8e,0x80);           //启动写保护
  633.                                 flag_js=1;                                                           //标志位置1,不然这里会成一个死循环
  634.                         }
  635.             }

  636.           if((shi==7)&&(fen==35)&&(miao==0))
  637.                           flag_js=0;                                   //标志位清零,准备第二天校时
  638. }



  639. void keysan()
  640. {
  641.     static bit kf1=0, kf3=0,kf2=0;  //自锁标志,这里一定要加static(或者用全局变量),否则按键不灵
  642.     static uint i=0,j=0,k=0,m=0,n=0;        //消抖延时变量
  643.                
  644.         if(key1==1)                //设置         //IO是高电平,说明按键没有被按下,这时要及时清零一些标志位
  645.         {        
  646.         i=0;           //按键消抖计时变量清零
  647.         kf1=0;           //按键自锁标志清零
  648.         }
  649.         else if(kf1 == 0)        //有按键按下,且是第一次被按下
  650.         {        
  651.         flag_fm = 1;         //启动蜂鸣器
  652.                 ++i;
  653.         if(i>10)                   //i>10  ADC查询方式用
  654.         {
  655.             i=0;
  656.             kf1=1;         //自锁按键置位,避免一直触发
  657.             knum++;
  658.                         if(knum==1)
  659.                         {
  660.                                 Write_DS1302_DAT(0x8e,0x00);                //写保护取消
  661.                                 Write_DS1302_DAT(write_miao,0x80); //  写秒80,时钟停止走时;
  662.                         
  663.                         }
  664.             if(knum==3)
  665.                         {
  666.                                  knum = 0;

  667.                                 Write_DS1302_DAT(write_miao,0x00);
  668.                                 Write_DS1302_DAT(0x8e,0x80);                //保护启动

  669.                         }
  670.         }        
  671.         }
  672. /************显示和光控切换****************/
  673.         if(knum == 0)
  674.         {
  675.                 if(key3==1)                //设置         //IO是高电平,说明按键没有被按下,这时要及时清零一些标志位
  676.                 {        
  677.                 m=0;           //按键消抖计时变量清零
  678.                 kf3=0;           //按键自锁标志清零
  679.                 }
  680.                 else if(kf3 == 0)        //有按键按下,且是第一次被按下
  681.                 {        flag_fm = 1;         //启动蜂鸣器
  682.                 ++m;
  683.                 if(m>10)                   //i>10  ADC查询方式用
  684.                 {
  685.                     m=0;
  686.                     kf3=1;         //自锁按键置位,避免一直触发
  687.                     xs++;
  688.                    if(xs==3)
  689.                                 {
  690.                                          xs = 0;
  691.         
  692.                                 }
  693.                 }        
  694.                 }

  695.                 if(key2==1)                //设置         //IO是高电平,说明按键没有被按下,这时要及时清零一些标志位
  696.                 {
  697.                 n=0;           //按键消抖计时变量清零
  698.                 kf2=0;           //按键自锁标志清零
  699.                 }
  700.                 else if(kf2 == 0)        //有按键按下,且是第一次被按下
  701.                 {        flag_fm = 1;         //启动蜂鸣器
  702.                 ++n;
  703.                 if(n>10)                   //i>10  ADC查询方式用
  704.                 {
  705.                     n=0;
  706.                     kf2=1;         //自锁按键置位,避免一直触发
  707.                                 flag_gk = !flag_gk;
  708.                 }        
  709.                 }


  710.         }



  711. ///-------加--------///
  712.         if(knum != 0)
  713.         {
  714.                 if(key2==0)                //加
  715.             {  
  716.                         
  717.                 j++;
  718.         //        if(j >= 5000)           //长按连加 ADC中断方式用
  719.                 if(j >= 100)           //长按连加 ADC查询方式用
  720.         
  721.                 {   //flag_fm = 0;                                    
  722.                     if(knum==2)
  723.                     {
  724.                                 fen++;
  725.                                 fen=fen/10*16+fen%10;                //转为16进制
  726.                                 if(fen==0x60)
  727.                                             fen=0x00;
  728.                                         Write_DS1302_DAT(write_fen,fen);
  729.                                 read_sf();                                        //读出时间,然后显示
  730.                     }
  731.         
  732.                     if(knum==1)
  733.                     {
  734.                                         shi++;
  735.                                         shi=shi/10*16+shi%10;                //转为16进制
  736.                                         if(shi==0x24)
  737.                                                 shi=0x00;
  738.                                         Write_DS1302_DAT(write_shi,shi);
  739.                                         read_sf();
  740.                     }
  741.         
  742.                     j=90;           //这里j的值可以设置连加的快慢,j的值越大就越快
  743.                                                         //因为初值越大,加到100的时间就越短
  744.                                 flag_fm = 1;  //启动蜂鸣器
  745.                         }                           
  746.             }        
  747.         
  748.             else
  749.             {
  750.                 if(j>10 && j<100) //短按
  751.                 {
  752.                     flag_fm = 1;         //启动蜂鸣器   
  753.                     if(knum==2)
  754.                     {
  755.                                 fen++;
  756.                                 fen=fen/10*16+fen%10;                //转为16进制
  757.                                 if(fen==0x60)
  758.                                     fen=0x00;
  759.                                         Write_DS1302_DAT(write_fen,fen);
  760.                                 read_sf();                                        //读出时间,然后显示
  761.                     }
  762.         
  763.                     if(knum==1)
  764.                     {
  765.                                         shi++;
  766.                                         shi=shi/10*16+shi%10;                //转为16进制
  767.                                         if(shi==0x24)
  768.                                                 shi=0x00;
  769.                                        
  770.                                         Write_DS1302_DAT(write_shi,shi);
  771.                                         read_sf();
  772.                     }
  773.         
  774.                         j=0;
  775.                     }
  776.                 }        
  777.    
  778. //----------减-----------//   
  779.         if(key3==0)                //减
  780.     {           flag_fm = 1;         //启动蜂鸣器
  781.             k++;
  782.             if(k >= 100)           //长按
  783.             {
  784.                     if(knum==2)
  785.                     {
  786.                                                 fen--;
  787.                                                 fen=fen/10*16+fen%10;                //转为16进制
  788.                                                 if(fen==-1)
  789.                                                 fen=0x59;
  790.                                                 Write_DS1302_DAT(write_fen,fen);
  791.                                                 read_sf();
  792.                     }

  793.                     if(knum==1)
  794.                     {
  795.                                                 shi--;
  796.                                                 shi=shi/10*16+shi%10;                //转为16进制
  797.                                                 if(shi==-1)
  798.                                                 shi=0x23;
  799.                                                 Write_DS1302_DAT(write_shi,shi);
  800.                                                 read_sf();
  801.                     }

  802.                     k=90;
  803.             }
  804.     }        

  805.     else
  806.     {
  807.             if(k>10 && k<100) //短按
  808.             {
  809.                     flag_fm = 1;         //启动蜂鸣器        
  810.                     if(knum==2)
  811.                     {
  812.                                                 fen--;
  813.                                                 fen=fen/10*16+fen%10;                //转为16进制
  814.                                                 if(fen==-1)
  815.                                                 fen=0x59;
  816.                                                 Write_DS1302_DAT(write_fen,fen);
  817.                                                 read_sf();
  818.                     }

  819.                     if(knum==1)
  820.                     {
  821.                                                 shi--;
  822.                                                 shi=shi/10*16+shi%10;                //转为16进制
  823.                                                 if(shi==-1)
  824.                                                 shi=0x23;
  825.                                                 Write_DS1302_DAT(write_shi,shi);
  826.                                                 read_sf();
  827.                     }

  828.             }
  829.             k=0;        //消抖变量清零,为下次按键做准备        
  830.         }
  831.         }                 
  832. }


  833. void main()
  834. {        
  835. //        uchar i;
  836.         t0_init();
  837.         init_1302();
  838. //        InitADC();
  839.         ADC_Init();
  840.         flag_fm = 1;         //启动蜂鸣器
  841.         while(1)
  842.         {
  843.            read_sf();
  844.            switch(xs)
  845.            {
  846.                         case 0:if(flag==0 && knum == 0)         //时间、温度轮流显示,5秒切换一次
  847.                                            {Display_tem(Get_Tmp());}
  848.                                            else        
  849.                                            display( shi,fen);        break;
  850.                         case 1: display( shi,fen);  break;         //显示时间
  851.                         case 2: Display_tem(Get_Tmp()); break;//显示温度
  852.                         default: break;
  853.            }
  854.            keysan();
  855.            zdjs();//自动校时

  856. //                if(shi>=5 && shi<=21) //5~21 亮度最大
  857. //                ba=20;
  858. //                else ba=1;                          //22~4 亮度最小
  859. //                if(ADC_RES>5 && ADC_RES<25) ba=40;
  860. //                if(ADC_RES>25 && ADC_RES<50) ba=39; //10级亮度,ba值越大,LED越亮
  861. //                if(ADC_RES>50 && ADC_RES<80) ba=35;
  862. //                if(ADC_RES>80 && ADC_RES<100) ba=30;
  863. //                if(ADC_RES>100 && ADC_RES<130) ba=25;
  864. //                if(ADC_RES>130 && ADC_RES<150) ba=20;
  865. //                if(ADC_RES>150 && ADC_RES<180) ba=15;
  866. //                if(ADC_RES>180 && ADC_RES<200) ba=10;
  867. //                if(ADC_RES>200 && ADC_RES<230) ba=5;
  868. //                if(ADC_RES>230 && ADC_RES<250) ba=1;

  869. /**************************/
  870.                 if(!flag_gk)                //如果光控标志为0,就为自动亮度        ;默认为自动亮度
  871.                 {
  872.                         if(GetADCResult()>5 && GetADCResult()<25) ba=40;
  873.                         if(GetADCResult()>25 && GetADCResult()<50) ba=39; //10级亮度,ba值越大,LED越亮
  874.                         if(GetADCResult()>50 && GetADCResult()<80) ba=35;
  875.                         if(GetADCResult()>80 && GetADCResult()<100) ba=30;
  876.                         if(GetADCResult()>100 && GetADCResult()<130) ba=25;
  877.                         if(GetADCResult()>130 && GetADCResult()<150) ba=20;
  878.                         if(GetADCResult()>150 && GetADCResult()<180) ba=15;
  879.                         if(GetADCResult()>180 && GetADCResult()<200) ba=10;
  880.                         if(GetADCResult()>200 && GetADCResult()<230) ba=5;
  881.                         if(GetADCResult()>230 && GetADCResult()<250) ba=1;
  882.                 }
  883.                 else ba = 40; // 否则为最大亮度
  884. /*********************/
  885.                 if((shi>=5 && shi<=21) && fen ==0 && miao == 0) //整点报时
  886.                 {
  887.                         flag_fm = 1;
  888.                 }

  889.         }
  890. }

  891. /*------------------------------------------------
  892.                 ADC中断处理函数
  893. ------------------------------------------------*/
  894. //void adc_isr() interrupt 5 using 1
  895. //{
  896. ////        unsigned int temp;
  897. ////        temp=ADC_RES;                         //AD取8位结果
  898. ////        result=temp*0.01953125*1000;   //ad结果换算成电压值, 将5V分成256份,每份5v/256=0.01953125v        ,再扩大1000倍
  899. ////        ge=result/1000;
  900. ////        shifen=result%1000/100;
  901. ////        baifen=result%100/10;
  902. //         
  903. //        ADC_CONTR = 0xc8;//开启转换
  904. //}


复制代码
全部资料51hei下载地址:
1寸数码管时钟资料.rar (283.97 KB, 下载次数: 256)

评分

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

查看全部评分

回复

使用道具 举报

ID:1 发表于 2018-12-18 22:02 | 显示全部楼层
好东东 原理图是怎么连接的?
回复

使用道具 举报

ID:140489 发表于 2018-12-19 08:46 | 显示全部楼层
附件里面有原理图的,PDF格式的,原理图连接多数用的网络标号,这样看起来简洁
回复

使用道具 举报

ID:140489 发表于 2018-12-19 08:58 | 显示全部楼层
原理图里面,供电有两种方式可选,一种是用三端稳压器,一种是USB供电,安卓手机线就可以
回复

使用道具 举报

ID:140489 发表于 2018-12-19 09:11 | 显示全部楼层
PCB板上留有热敏电阻的位置,也可以热敏电阻测温
回复

使用道具 举报

ID:140489 发表于 2018-12-19 09:39 | 显示全部楼层
数码管连接图
微信图片编辑_20181219093629.jpg

评分

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

查看全部评分

回复

使用道具 举报

ID:328014 发表于 2018-12-21 14:53 | 显示全部楼层
自动亮度这个功能很有创意,有时间我在楼主的基础再改造一下接入天猫精灵做语言控制亮度的功能.
回复

使用道具 举报

ID:70614 发表于 2018-12-23 09:00 | 显示全部楼层
有闹钟功能吗加个闹钟功能更完美
回复

使用道具 举报

ID:171111 发表于 2018-12-23 20:16 | 显示全部楼层
谢谢分享 这个 很不错
回复

使用道具 举报

ID:60026 发表于 2018-12-24 16:19 | 显示全部楼层

谢谢分享!不错!
回复

使用道具 举报

ID:326489 发表于 2018-12-26 07:42 | 显示全部楼层
谢谢楼主分享!很好的程序!
回复

使用道具 举报

ID:315554 发表于 2018-12-26 17:06 | 显示全部楼层
调光功能很好,学习了,谢谢!
回复

使用道具 举报

ID:229361 发表于 2019-1-21 13:29 | 显示全部楼层
谢谢楼主的分享
回复

使用道具 举报

ID:343102 发表于 2019-1-21 21:11 | 显示全部楼层
调光功能我认为用途不大,一定要用的话,使用模拟电路更简单。这样可以用没有A/D转换的更廉价的芯片,节省的内存可以增加红外遥控,还可以增加自动闰秒功能以大幅提高走时精度,这样实用性会更强。
个人观点。
回复

使用道具 举报

ID:140489 发表于 2019-1-22 09:26 | 显示全部楼层
风158 发表于 2019-1-21 21:11
调光功能我认为用途不大,一定要用的话,使用模拟电路更简单。这样可以用没有A/D转换的更廉价的芯片,节省 ...

这些功能看个人喜好增减,我做自动亮度是为了晚上看不刺眼
回复

使用道具 举报

ID:84492 发表于 2019-3-14 15:45 | 显示全部楼层
51hei团团 发表于 2018-12-21 14:53
自动亮度这个功能很有创意,有时间我在楼主的基础再改造一下接入天猫精灵做语言控制亮度的功能.

你好,天猫精灵控制很新颖,能简单回复下怎么实现吗?或者什么模块可以?
回复

使用道具 举报

ID:84492 发表于 2019-3-14 15:47 | 显示全部楼层
lids 发表于 2019-1-22 09:26
这些功能看个人喜好增减,我做自动亮度是为了晚上看不刺眼

自动亮度很实用,对于产品本身来说也是对人比较友好的。
回复

使用道具 举报

ID:345426 发表于 2019-3-23 22:45 | 显示全部楼层
自动校时这个好办法
回复

使用道具 举报

ID:476064 发表于 2019-5-13 00:43 来自手机 | 显示全部楼层
那位大神修改下给stc89c52用,手里没有这个。
回复

使用道具 举报

ID:64253 发表于 2020-8-12 10:48 | 显示全部楼层
这位大师,牛逼啊,无私代码都快贴完了,赞一个
回复

使用道具 举报

ID:53978 发表于 2021-10-7 17:58 | 显示全部楼层
感谢无私分享 下载学习学习
回复

使用道具 举报

ID:53978 发表于 2021-10-18 14:56 | 显示全部楼层
这个用共阴数码管需要改什么代码呢
回复

使用道具 举报

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

本版积分规则

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

Powered by 单片机教程网

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