找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 9323|回复: 30
收起左侧

学习单片机,制作了一台LED电子钟

  [复制链接]
ID:97023 发表于 2020-3-31 00:39 | 显示全部楼层 |阅读模式
  学习单片机一段时间了,一直想做一个东西来验证一下自己的学习效果,“流水灯”之类觉得太简单;“示波器”、“扫频仪”、“LCR”、“晶体管特性曲线仪”等仪器又觉得太难,自己觉得还是制作一个电子钟难度比较适中。
  只所以选择制作LED显示的电子钟,是因为去年在网上30元买得有96只1寸的LED数码管,总得把它们消化点才是。当然成功后我还会再制作LCD显示的电子钟,那是后话。
  原本想用14个LED数码管来制作这个电子钟,让它直接显示:年、月、日、时、分、秒,其中“年”用4位,免得再出现当年“千年虫”的问题,其它通通用两位,当然还可以多加一位用来显示“星期”。但这样一来,这个电子钟就显得太宽了,做出来有点庞大。
  最后还是决定按照传统方法,用6位LED数码管就行了,用一个按键来切换日期与时间的显示。
  根据以上想法设计的电路原理图:
00 电路原理图.png


  要让钟走起来不难,网上有很多现成的代码,关键的难点是时钟的设置(调整)。
  我希望在进入设置状态时,对应的LED应该能够闪烁,以提醒我当前设置的是年、月、日、时、分、秒的哪一位(其实都是两位)?
  由于每位LED数码管都采用动态显示,在动态显示时又如何使某两位闪烁,一下子没想通怎么做。
  参考了很多网上的资料以及翻了很多书籍,都没发现哪一款LED数码管的电子钟在设置时间或日期时,对应的LED数码管能够闪烁,也许是我没有看懂别人的代码。
  想了几天后终于想到了一个办法:我们知道,LED数码管的动态显示,无非就是在某一个时刻只让一只LED数码管亮,其余的LED数码管是不亮的,下一个时刻才让下一位LED数码管亮,循环往复,只要时间足够快,由于人眼的“视觉暂留”作用,我们看到所有的LED数码管都是亮着的。
  我的办法就是:需要闪烁的这两位LED数码管,当轮到它们亮时暂时不亮,将亮的机会让给其它的数码管,这就使得它们“灭”的时间长一点,能让眼睛感觉到;轮到它们亮时,就让它们循环多亮一段时间,它们循环结束以后才将亮的机会交给其它的数码管。这样的效果,通过眼睛看到,这两位数码管一灭一亮地闪烁起来了。实际情况下,其它数码管也有轻微的闪烁,但没有这两位明显,眼睛不容易观察到。
  我就通过这个伎俩用来欺骗眼睛。
  由于机器配置有点低,所以这个效果用Proteus仿真不出来,只有用面包板实际搭电路才行。
  我通过测试,闪烁的数码管“亮”时,循环4次就够了,次数多了,其它数码管就会跟着闪烁起来;次数少了闪烁又不明显。
  说这么多,只是思路,具体实现看源代码。
  结构上,采用了4个按纽开关进行控制:
  1、【设置/移动/退出】;
  2、【加】;
  3、【减】;
  4、【确定/翻页】。
  各按纽功能解说:
  【设置/移动/退出】按纽的功能:
  单击第①次,进入(设置),第一位(其实是两个数码管,下同)闪烁;
  单击第②次,第二位闪烁;
  单击第③次,第三位闪烁;
  单击第④次,下一页第一位闪烁;
  单击第⑤次,下一页第二位闪烁;
  单击第⑥次,下一页第三位闪烁;
  单击第⑦次,退出(设置),进入走时状态。
  【加】、【减】:只在设置状态有效;
  【确定/翻页】:在设置状态下,保存并退出设置;在走时状态下,切换日期和时间。
  用面包板搭建的功能验证电路证实了上述想法。
01 面包板验证电路.jpg


  在面包板上成功以后,开始成品制作。
  电子钟由三个模块组成:显示板、控制板和电源板。
  显示板由6个LED数码管组成,用一块9×15CM的洞洞板裁成两块拼接而成,为了使两块洞洞板保持在一个平面,在它们的后面又加了一块装修吊顶用的“轻钢龙骨”作为支撑:
IMG_20190618_095136.jpg

IMG_20190618_095153.jpg

  为了避免焊接错误,数码管相同的段用相同颜色的导线连接。
IMG_20190621_230816.jpg


IMG_20190622_004009.jpg


  七个段由这七个插针输出
IMG_20190622_004128.jpg


  每一位数码管的控制由一块单独的控制板完成,这块控制板固定在数码管背面的“轻钢龙骨”上,它们构成了完整的显示模块,通过插针与单片机主控板连接。
IMG_20190622_095018.jpg


IMG_20190622_103105.jpg

  单片机模块:
IMG_20190623_213313.jpg


IMG_20190623_213417.jpg

  因为电源是12V的,所以用7805将电压控制在5V:
IMG_20190623_213911.jpg


  电源模块采用成品12V/1A开关电源,这种电源在网上1.50元一只(输出线被剪掉的),我买得有几十只,另外家人多年来丢弃的各种电源,都被我收集了起来,也有几十只,不管做什么电子装置,我都能找到合适的电源。
IMG_20200331_001052.jpg


  各个模块连接起来工作正常了:
IMG_20190624_170212.jpg


  日期显示:
IMG_20190626_001444.jpg


  时间显示:
IMG_20190626_001501.jpg


  用捡来的层板制作外壳:
IMG_20190702_113343.jpg


IMG_20190704_082007.jpg

  外壳全部用白乳胶粘接,没用一颗钉子。
IMG_20190705_084345.jpg


IMG_20190706_162320.jpg

IMG_20190707_133204.jpg


IMG_20190708_233139.jpg

  贴上黑胡桃木的贴皮美化一下:
IMG_20190720_142536.jpg

  内部布局:
IMG_20190720_142543.jpg

  开关电源的PCB板很小,不好单独固定,我是将电源外壳锯掉一部分,利用它内部的卡槽来固定电源。
IMG_20190720_142618.jpg

  右下角那片软包装锂电池是3.7V/180mAh的,在不使用电子钟时给DS1302供电,以免丢失设置好的时间。
IMG_20190720_142626.jpg


IMG_20190720_142738.jpg
  后盖板的螺丝孔与里面的螺帽对得很正,我是怎么做到的?给大家分享一点经验:先在后盖板适当位置钻孔,这时只需注意孔的中心与左右边缘的距离等于螺帽的半径,也就是说,螺帽应该紧贴着侧面板外沿,这个可以用尺子测量画线再钻孔;然后将4颗螺丝与螺帽固定在后盖板上,在前面板还空着的情况下,将后盖板小心地在后边推到位,用一根长一点的竹签粘少许兑好的AB胶,从前面窗口伸进去,将它们涂到螺帽与侧面板之间,这时不需要涂多少,只要能将它们粘住就行,等几个小时AB胶固化后,再将后盖板及螺丝一同拆下来,这时螺帽就已经粘在侧面板上了。再次兑一些AB胶,将螺帽与侧面板胶水不足的地方补足即可。
  如果你有更好的方法,就当我没说。
  薄膜开关的功能定义:
薄膜开关.png


IMG_20200328_221527.jpg

原理图及代码:
LED数码管电子钟.rar (60.08 KB, 下载次数: 141)

评分

参与人数 2黑币 +60 收起 理由
王朗的诱惑 + 10 优雅
admin + 50 共享资料的黑币奖励!

查看全部评分

回复

使用道具 举报

ID:328014 发表于 2020-3-31 01:06 | 显示全部楼层
好东东啊 下面是楼主的主程序:
  1. /*******************************************************
  2. 功能:LED数码管电子钟
  3. *******************************************************/
  4. #include <reg52.h>
  5. #include <intrins.h>

  6. #define uchar unsigned char
  7. #define uint unsigned int

  8. //函数定义
  9. void DelayMS(uint x);                                                //延时 xms(晶振:11.0592MHz,)
  10. uchar Get_A_Byte_FROM_DS1302();                                //从DS1302读取一个字节
  11. uchar Read_Data( uchar addr );                                //从DS1302指定位置读数据
  12. void Write_A_Byte_TO_DS1302( uchar x );                //向DS1302写入一个字节
  13. void Write_DS1302( uchar addr, uchar dat );        //向DS1302某地址写数据
  14. void SET_DS1302();                                                        //设置日期时间
  15. void GetTime();                                                                //读取当前时间日期
  16. void LedDisplay();                                                        //显示数据
  17. void Scan_Key();                                                        //扫描键盘
  18. void Init();                                                                //系统初始化
  19. void Play();                                                                //蜂鸣器发音
  20. void Format_DS1302();                                                //日期格式化

  21. sbit RST = P3^5;                        //DS1302复位线
  22. sbit SDA = P3^6;                        //DS1302数据线
  23. sbit CLK = P3^7;                        //DS1302时钟线

  24. sbit NOT = P3^4;                        //日期分隔小数点和时间分隔冒号(1-冒号亮、0-小数点亮)

  25. sbit BEEP = P1^7;                        //蜂鸣器输出端口

  26. uchar Current_Time[7];                //保存所读取的日期时间(秒分时日月周年)
  27. uchar Display_Buffer[12];   //处理过的日期时间,用于数码管显示

  28. uchar DelayTwinkle = 5;                //闪烁延时长度,原200
  29. uchar TimeTwinkle = 4;                //闪烁显示时间,原30
  30. uchar WeiTwinkle = 0;                //闪烁的位
  31. uchar TimeShake = 100;                //去抖动延时时间长度

  32. uint BeepTime = 0;                //蜂鸣器响一次的间隔时间

  33. uint Set_State = 0;                        //0:走时状态、1:设置状态。
  34. bit DateTime_State = 0;                //0:显示时间、1:显示日期。
  35. uint Count = 0;                                //记录“K_Setup”的状态

  36. //按键定义
  37. sbit K_Setup        = P1^2;                //设置/移动/退出
  38. sbit K_Add                = P1^3;                //加1
  39. sbit K_Sub                = P1^0;                //减1
  40. sbit K_OK                = P1^1;                //保存并退出/翻页
  41. sbit K_GND                = P1^4;                //由于薄膜开关的原因,此脚定义为地。

  42. sbit K_FORMAT        = P1^5;                //格式化(使日期时间内容为:2019-06-17 12:00:00)

  43. //共阳LED数码管位码(从左到右:1、2、3、4、5、6)
  44. //用PNP管驱动
  45. code uchar WEI_CODE [] =
  46. {
  47.         0xFE,                //1          11111110
  48.         0xFD,                //2          11111101
  49.         0xFB,                //3          11111011
  50.         0xF7,                //4          11110111
  51.         0xEF,                //5          11101111
  52.         0xDF                //6          11011111
  53. };

  54. //共阳LED数码管段码
  55. code uchar DSY_CODE [] =
  56. {
  57.         0x40,                //0
  58.         0x79,                //1
  59.         0x24,                //2
  60.         0x30,                //3
  61.         0x19,                //4
  62.         0x12,                //5
  63.         0x02,                //6
  64.         0x78,                //7
  65.         0x00,                //8
  66.         0x10                //9
  67. };

  68. // 延时 xms(晶振:11.0592MHz,)
  69. void DelayMS(uint x)
  70. {
  71.         uchar i;
  72.         while( x-- )
  73.         {
  74.                 for( i=0; i<111; i++ );
  75.         }
  76. }

  77. //蜂鸣器发音
  78. void Play()
  79. {
  80.         uchar i, j;
  81.         for( i = 0; i < 250; i++ )
  82.         {
  83.                 BEEP = ~BEEP;
  84.                 for (j = 0; j < 30; j++ )
  85.                 {
  86.                         _nop_();                //延时时间长短决定发音频率
  87.                 }
  88.         }
  89.         BEEP = 0;
  90. }                                                                                                           

  91. //从DS1302读取一个字节
  92. uchar Get_A_Byte_FROM_DS1302()
  93. {
  94.         uchar i,b,t;
  95.         for ( i = 0; i < 8; i++ )
  96.         {
  97.                 b >>= 1;
  98.                 t = SDA;
  99.                 b |= t << 7;
  100.                 CLK = 1;
  101.                 CLK = 0;
  102.         }
  103.         //BCD码转换
  104.         return b / 16 * 10 + b % 16;
  105. }

  106. //从DS1302指定位置读数据
  107. uchar Read_Data( uchar addr )
  108. {
  109.         uchar dat;
  110.         RST = 0;
  111.         CLK = 0;
  112.         RST = 1;
  113.         Write_A_Byte_TO_DS1302( addr );
  114.         dat = Get_A_Byte_FROM_DS1302();
  115.         CLK = 1;
  116.         RST = 0;
  117.         return dat;
  118. }

  119. //向DS1302写入一个字节
  120. void Write_A_Byte_TO_DS1302( uchar x )
  121. {
  122.         uchar i;
  123.         for ( i = 0; i < 8; i++ )
  124.         {
  125.                 SDA = x & 1;
  126.                 CLK = 1;
  127.                 CLK = 0;
  128.                 x >>= 1;
  129.         }
  130. }

  131. //向DS1302某地址写数据
  132. void Write_DS1302( uchar addr, uchar dat )
  133. {
  134.         CLK = 0;
  135.         RST = 1;
  136.         Write_A_Byte_TO_DS1302( addr );
  137.         Write_A_Byte_TO_DS1302( dat );
  138.         CLK = 0;
  139.         RST = 0;
  140. }

  141. //设置日期时间,括号里面是地址
  142. //秒(0x80)分(0x82)时(0x84)日(0x86)月(0x88)周(0x8a)年(0x8c)
  143. void SET_DS1302()
  144. {
  145.         uchar i;
  146.         Write_DS1302( 0x8E, 0x00 );        //写控制字,取消写保护
  147.         for ( i = 0; i < 7; i++ )
  148.         {
  149.                 Write_DS1302( 0x80 + 2 * i, ( Current_Time[i] / 10 << 4 ) | ( Current_Time[i] % 10 ) );
  150.         }
  151.         Write_DS1302( 0x8E, 0x80 );        //加保护
  152. }

  153. //日期格式化,使日期时间值为合法数据(使日期时间内容为:2019-06-20 12:00:00)
  154. void Format_DS1302()
  155. {
  156.         Current_Time[0] = 0x00;                //秒
  157.         Current_Time[1] = 0x00;                //分
  158.         Current_Time[2] = 0x0C;                //12小时
  159.         Current_Time[3] = 0x14;                //20日
  160.         Current_Time[4] = 0x06;                //06月
  161.         Current_Time[5] = 0x05;                //周5(星期日是一周的开始)
  162.         Current_Time[6] = 0x13;                //19年
  163.         
  164.         SET_DS1302();
  165. }

  166. //读取当前时间日期(秒、分、时、日、月、周、年)
  167. //将读取到的日期时间保存到显示缓冲区中。
  168. //运行时间约 2.4ms
  169. void GetTime()
  170. {
  171.         uchar i;
  172.         for ( i = 0; i < 7; i++ )
  173.         {
  174.                 Current_Time[i] = Read_Data( 0x81 + 2 * i );
  175.         }
  176.         Display_Buffer[0] = DSY_CODE[ Current_Time[2] / 10 ];           //小时的十位
  177.         Display_Buffer[1] = DSY_CODE[ Current_Time[2] % 10 ];           //小时的个位
  178.         Display_Buffer[2] = DSY_CODE[ Current_Time[1] / 10 ];           //分的十位
  179.         Display_Buffer[3] = DSY_CODE[ Current_Time[1] % 10 ];           //分的个位
  180.         Display_Buffer[4] = DSY_CODE[ Current_Time[0] / 10 ];           //秒的十位
  181.         Display_Buffer[5] = DSY_CODE[ Current_Time[0] % 10 ];           //秒的个位

  182.         Display_Buffer[6] = DSY_CODE[ Current_Time[6] / 10 ];           //年的十位
  183.         Display_Buffer[7] = DSY_CODE[ Current_Time[6] % 10 ];           //年的个位
  184.         Display_Buffer[8] = DSY_CODE[ Current_Time[4] / 10 ];           //月的十位
  185.         Display_Buffer[9] = DSY_CODE[ Current_Time[4] % 10 ];           //月的个位
  186.         Display_Buffer[10] = DSY_CODE[ Current_Time[3] / 10 ];           //日的十位
  187.         Display_Buffer[11] = DSY_CODE[ Current_Time[3] % 10 ];           //日的个位
  188.         Display_Buffer[12] = DSY_CODE[ Current_Time[5] - 1 ];           //周的个位(星期日是一周的开始)
  189. }

  190. //显示数据(运行时间约 12ms)
  191. void LedDisplay()
  192. {
  193.         uchar i;
  194.         if ( Set_State == 0 )                //走时状态
  195.         {
  196.                 WeiTwinkle = 0;
  197.                 if ( DateTime_State == 0 )                        //显示时间
  198.                 {
  199.                         NOT = 1;
  200.                         for ( i = 0; i < 6; i++ )
  201.                         {
  202.                                 P2 = WEI_CODE[ i ];
  203.                                 P0 = Display_Buffer[ i ];
  204.                                 DelayMS(1);
  205.                                 P2 = 0xFF;
  206.                                 P0 = 0xFF;
  207.                                 DelayMS(1);
  208.                         }
  209.                 }
  210.                 else                        //显示日期
  211.                 {
  212.                         NOT = 0;
  213.                         for ( i = 0; i < 6; i++ )
  214.                         {
  215.                                 P2 = WEI_CODE[ i ];
  216.                                 P0 = Display_Buffer[ i + 6 ];
  217.                                 DelayMS(1);
  218.                                 P2 = 0xFF;
  219.                                 P0 = 0xFF;
  220.                                 DelayMS(1);
  221.                         }
  222.                 }
  223.         }
  224.         else                //设置状态
  225.         {
  226.                 uchar j,k;
  227.                 if ( DateTime_State == 0 )                        //显示时间
  228.                 {
  229.                         NOT = 1;
  230.                         for ( i = 0; i < 6; i++ )
  231.                         {
  232.                                 if ( i != WeiTwinkle &&  i != WeiTwinkle + 1 )         //不闪烁的位
  233.                                 {
  234.                                         P2 = WEI_CODE[ i ];
  235.                                         P0 = Display_Buffer[ i ];
  236.                                         DelayMS(1);
  237.                                 }
  238.                                 else if ( j > DelayTwinkle )   //闪烁的位(2位)
  239.                                 {
  240.                                         for ( k = 0; k < TimeTwinkle; k++ )
  241.                                         {
  242.                                                 P2 = WEI_CODE[ i ];
  243.                                                 P0 = Display_Buffer[ i ];
  244.                                                 DelayMS( 1 );
  245.                                                 P2 = WEI_CODE[ i + 1 ];
  246.                                                 P0 = Display_Buffer[ i + 1 ];
  247.                                                 DelayMS( 1 );
  248.                                         }
  249.                                         j = 0;
  250.                                 }
  251.                                 P2 = 0xFF;
  252.                                 P0 = 0xFF;
  253.                                 DelayMS(1);
  254.                                 j++;
  255.                         }
  256.                 }
  257.                 else                        //显示日期
  258.                 {
  259.                         NOT = 0;
  260.                         for ( i = 0; i < 6; i++ )
  261.                         {
  262.                                 if ( i != WeiTwinkle &&  i != WeiTwinkle + 1 )         //不闪烁的位
  263.                                 {
  264.                                         P2 = WEI_CODE[ i ];
  265.                                         P0 = Display_Buffer[ i + 6 ];
  266.                                         DelayMS(2);
  267.                                 }
  268.                                 else if ( j > DelayTwinkle )   //闪烁的位(2位)
  269.                                 {
  270.                                         for ( k = 0; k < TimeTwinkle; k++ )
  271.                                         {
  272.                                                 P2 = WEI_CODE[ i ];
  273.                                                 P0 = Display_Buffer[ i + 6 ];
  274.                                                 DelayMS( 1 );
  275.                                                 P2 = WEI_CODE[ i+1 ];
  276.                                                 P0 = Display_Buffer[ i + 7 ];
  277.                                                 DelayMS( 1 );
  278.                                         }
  279.                                         j = 0;
  280.                                 }
  281.                                 P2 = 0xFF;
  282.                                 P0 = 0xFF;
  283.                                 DelayMS(1);
  284.                                 j++;
  285.                         }
  286.                 }
  287.         }
  288. }

  289. //扫描键盘
  290. void Scan_Key()
  291. {
  292.         //设置
  293.         if ( K_Setup == 0 )        
  294.         {
  295.                 DelayMS( TimeShake );                   //去抖动
  296.                 if ( K_Setup == 0 )
  297.                 {
  298.                         Set_State ++;

  299.                         if ( Set_State > 6 )
  300.                         {
  301.                                 Set_State = 0;
  302.                                 DateTime_State = 0;
  303.                                 WeiTwinkle = 0;
  304.                         }
  305.                         else
  306.                         {
  307.                                 switch ( Set_State )
  308.                                 {
  309.                                         case 0:
  310.                                                 WeiTwinkle = 0;
  311.                                                 break;
  312.                                         case 1:
  313.                                                 WeiTwinkle = 0;
  314.                                                 break;
  315.                                         case 2:
  316.                                                 WeiTwinkle = 2;
  317.                                                 break;
  318.                                         case 3:
  319.                                                 WeiTwinkle = 4;
  320.                                                 break;
  321.                                         case 4:
  322.                                                 WeiTwinkle = 0;
  323.                                                 break;
  324.                                         case 5:
  325.                                                 WeiTwinkle = 2;
  326.                                                 break;
  327.                                         case 6:
  328.                                                 WeiTwinkle = 4;
  329.                                                 break;
  330.                                 }

  331.                                 if ( Set_State < 4 )
  332.                                 {
  333.                                         DateTime_State = 0;                //第一页,显示时间
  334.                                 }
  335.                                 else
  336.                                 {
  337.                                         DateTime_State = 1;                //第二页,显示日期
  338.                                 }
  339.                         }
  340.                         DelayMS(1);
  341.                         Play();
  342.                 }
  343.         }
  344.         
  345.         //在设置时才能操作的按键
  346.         if ( Set_State != 0 )
  347.         {
  348.                 //调时:增加(设置状态有效)
  349.                 if ( K_Add == 0 )        
  350.                 {
  351.                         DelayMS( TimeShake );                   //去抖动
  352.                         if ( K_Add == 0 )
  353.                         {
  354.                                 switch( WeiTwinkle )
  355.                                 {
  356.                                         case 0:                //时/年
  357.                                                 if ( DateTime_State == 0 )
  358.                                                 {                        //小时
  359.                                                         Current_Time[2]++;
  360.                                                         if ( Current_Time[2] > 23 )
  361.                                                         {
  362.                                                                 Current_Time[2] = 0;
  363.                                                         }
  364.                                                         Display_Buffer[0] = DSY_CODE[ Current_Time[2] / 10 ];
  365.                                                         Display_Buffer[1] = DSY_CODE[ Current_Time[2] % 10 ];
  366.                                                 }
  367.                                                 else
  368.                                                 {                        //年
  369.                                                         Current_Time[6]++;
  370.                                                         Display_Buffer[6] = DSY_CODE[ Current_Time[6] / 10 ];
  371.                                                         Display_Buffer[7] = DSY_CODE[ Current_Time[6] % 10 ];
  372.                                                 }
  373.                                                 break;
  374.                                         case 2:                //分/月
  375.                                                 if ( DateTime_State == 0 )
  376.                                                 {                //分
  377.                                                         Current_Time[1]++;
  378.                                                         if ( Current_Time[1] > 59 )
  379.                                                         {
  380.                                                                 Current_Time[1] = 0;
  381.                                                         }
  382.                                                         Display_Buffer[2] = DSY_CODE[ Current_Time[1] / 10 ];
  383.                                                         Display_Buffer[3] = DSY_CODE[ Current_Time[1] % 10 ];
  384.                                                 }
  385.                                                 else
  386.                                                 {                //月
  387.                                                         Current_Time[4]++;
  388.                                                         if ( Current_Time[4] > 12 )
  389.                                                         {
  390.                                                                 Current_Time[4] = 1;
  391.                                                         }
  392.                                                         Display_Buffer[8] = DSY_CODE[ Current_Time[4] / 10 ];
  393.                                                         Display_Buffer[9] = DSY_CODE[ Current_Time[4] % 10 ];
  394.                                                 }
  395.                                                 break;
  396.                                         case 4:                //秒/日
  397.                                                 if ( DateTime_State == 0 )
  398.                                                 {                //秒
  399.                                                         Current_Time[0]++;
  400.                                                         if ( Current_Time[0] > 59 )
  401.                                                         {
  402.                                                                 Current_Time[0] = 0;
  403.                                                         }
  404.                                                         Display_Buffer[4] = DSY_CODE[ Current_Time[0] / 10 ];
  405.                                                         Display_Buffer[5] = DSY_CODE[ Current_Time[0] % 10 ];
  406.                                                 }
  407.                                                 else
  408.                                                 {                //日
  409.                                                         Current_Time[3]++;
  410.                                                         if ( Current_Time[3] > 31 )
  411.                                                         {
  412.                                                                 Current_Time[3] = 1;
  413.                                                         }
  414.                                                         Display_Buffer[10] = DSY_CODE[ Current_Time[3] / 10 ];
  415.                                                         Display_Buffer[11] = DSY_CODE[ Current_Time[3] % 10 ];
  416.                                                 }
  417.                                                 break;
  418.                                 }
  419.                                 Play();
  420.                         }
  421.                 }

  422.                 //调时:减小(设置状态有效)
  423.                 if ( K_Sub == 0 )        
  424.                 {
  425.                         DelayMS( TimeShake );                   //去抖动
  426.                         if ( K_Sub == 0 )
  427.                         {
  428.                                 switch( WeiTwinkle )
  429.                                 {
  430.                                         case 0:                //时/年
  431.                                                 if ( DateTime_State == 0 )
  432.                                                 {                        //小时
  433.                                                         Current_Time[2]--;
  434.                                                         if ( Current_Time[2] < 0 )
  435.                                                         {
  436.                                                                 Current_Time[2] = 23;
  437.                                                         }
  438.                                                         Display_Buffer[0] = DSY_CODE[ Current_Time[2] / 10 ];
  439.                                                         Display_Buffer[1] = DSY_CODE[ Current_Time[2] % 10 ];
  440.                                                 }
  441.                                                 else
  442.                                                 {                        //年
  443.                                                         Current_Time[6]--;
  444.                                                         if ( Current_Time[6] < 0 )
  445.                                                         {
  446.                                                                 Current_Time[6] = 0;
  447.                                                         }
  448.                                                         Display_Buffer[6] = DSY_CODE[ Current_Time[6] / 10 ];
  449.                                                         Display_Buffer[7] = DSY_CODE[ Current_Time[6] % 10 ];
  450.                                                 }
  451.                                                 break;
  452.                                         case 2:                //分/月
  453.                                                 if ( DateTime_State == 0 )
  454.                                                 {                //分
  455.                                                         Current_Time[1]--;
  456.                                                         if ( Current_Time[1] < 0 )
  457.                                                         {
  458.                                                                 Current_Time[1] = 59;
  459.                                                         }
  460.                                                         Display_Buffer[2] = DSY_CODE[ Current_Time[1] / 10 ];
  461.                                                         Display_Buffer[3] = DSY_CODE[ Current_Time[1] % 10 ];
  462.                                                 }
  463.                                                 else
  464.                                                 {                //月
  465.                                                         Current_Time[4]--;
  466.                                                         if ( Current_Time[4] <= 0 )
  467.                                                         {
  468.                                                                 Current_Time[4] = 12;
  469.                                                         }
  470.                                                         Display_Buffer[8] = DSY_CODE[ Current_Time[4] / 10 ];
  471.                                                         Display_Buffer[9] = DSY_CODE[ Current_Time[4] % 10 ];
  472.                                                 }
  473.                                                 break;
  474.                                         case 4:                //秒/日
  475.                                                 if ( DateTime_State == 0 )
  476.                                                 {                //秒
  477.                                                         Current_Time[0]--;
  478.                                                         if ( Current_Time[0] < 0 )
  479.                                                         {
  480.                                                                 Current_Time[0] = 59;
  481.                                                         }
  482.                                                         Display_Buffer[4] = DSY_CODE[ Current_Time[0] / 10 ];
  483.                                                         Display_Buffer[5] = DSY_CODE[ Current_Time[0] % 10 ];
  484.                                                 }
  485.                                                 else
  486.                                                 {                //日
  487.                                                         Current_Time[3]--;
  488.                                                         if ( Current_Time[3] <= 0 )
  489.                                                         {
  490.                                                                 Current_Time[3] = 31;
  491.                                                         }
  492.                                                         Display_Buffer[10] = DSY_CODE[ Current_Time[3] / 10 ];
  493.                                                         Display_Buffer[11] = DSY_CODE[ Current_Time[3] % 10 ];
  494.                                                 }
  495.                                                 break;
  496.                                 }
  497.                                 Play();
  498.                         }
  499.                 }
  500.         
  501.                 //保存数据并退回到走时状态(设置状态有效)
  502.                 if ( K_OK == 0 )         
  503.                 {
  504.                         DelayMS( TimeShake );                   //去抖动
  505.                         if ( K_OK == 0 )
  506.                         {
  507.                                 SET_DS1302();
  508.                                 Set_State = 0;
  509.                                 Play();
  510.                         }
  511.                 }

  512.                 //日期格式化,使日期时间值为合法数据(这个按键不安装在机壳上,如要操作,直接用杜邦线短接既可。)
  513.                 if ( K_FORMAT == 0 )
  514.                 {
  515.                         DelayMS( TimeShake );
  516.                         if ( K_FORMAT == 0 )
  517.                         {
  518.                                 Format_DS1302();
  519.                                 Set_State = 0;
  520.                         }
  521.                 }
  522.         }
  523.         else
  524.         {
  525.                 //走时状态(切换日期与时间)
  526.                 if ( K_OK == 0 )         
  527.                 {
  528.                         DelayMS( TimeShake );                   //去抖动
  529.                         if ( K_OK == 0 )
  530.                         {
  531.                                 DateTime_State = ~DateTime_State;
  532.                                 DelayMS(1);
  533.                                 Play();
  534.                         }
  535.                 }
  536.         }
  537. }

  538. //判断是否是闰年
  539. //uchar isLeapYear(uint y)
  540. //{
  541. //        return ( y % 4 == 0 && y % 100 != 0 ) || ( y % 400 == 0 );
  542. //}

  543. //系统初始化
  544. //T0 用于键盘扫描,每50ms一次。
  545. void Init()
  546. {
  547.         K_GND = 0;                //薄膜开关的地。
  548.         TMOD = 0x01;        //设置定时器0、1为工作方式1
  549.         TH0 = 0;                //65.536ms
  550.         TL0 = 0;
  551.         ET0 = 1;        //允许定时器0
  552.         TR0 = 1;        //启动定时器0
  553.         EA = 1;                //全局中断开
  554. }

  555. //主函数
  556. void main()
  557. {
  558.         Init();
  559.         while(1)
  560.         {
  561.                 if ( Set_State == 0 )        //走时状态
  562.                 {
  563.                         GetTime();                        //读取时间数据(运行时间约 2.4ms)
  564.                 }
  565.                 LedDisplay();
  566.         }
  567. }

  568. //定时器0中断
  569. void Time0() interrupt 1
  570. {
  571.         TR0 = 0;        //关闭定时器0
  572.         Scan_Key();                  //扫描键盘
  573.         TH0 = 0;                //65.536ms产生一次中断
  574.         TL0 = 0;
  575.         TR0 = 1;        //启动定时器0
  576. }

  577. //定时器1中断
  578. //控制蜂鸣器2秒响一声
  579. //void Time1() interrupt 3
  580. //{
  581. //        TR1 = 0;
  582. //        if ( BeepTime >= 40 )
  583. //        {
  584. ////                Play();
  585. //                BeepTime = 0;
  586. //        }
  587. //        BeepTime++;
  588. //        TH1 = ( 65536 - 50000 ) / 256;
  589. //        TL1 = ( 65536 - 50000 ) % 256;
  590. //        TR1 = 1;
  591. //}
复制代码
回复

使用道具 举报

ID:141556 发表于 2020-3-31 08:29 | 显示全部楼层
手工真好。
回复

使用道具 举报

ID:691573 发表于 2020-3-31 09:08 | 显示全部楼层
不错不错,赞一个!!!!好资料,51黑有你更精彩!!!
回复

使用道具 举报

ID:284488 发表于 2020-3-31 09:09 | 显示全部楼层
好东东啊!谢谢楼主的分享。
回复

使用道具 举报

ID:388929 发表于 2020-3-31 10:28 | 显示全部楼层
动手能力强,不错,而已很漂亮
回复

使用道具 举报

ID:342822 发表于 2020-3-31 13:00 | 显示全部楼层
数码管前贴黑膜~~~
回复

使用道具 举报

ID:143767 发表于 2020-3-31 17:30 | 显示全部楼层
有定闹功能吗?
回复

使用道具 举报

ID:97023 发表于 2020-3-31 21:56 | 显示全部楼层

暂时没有,包括日期、时间设置都还没有进行限制。
回复

使用道具 举报

ID:97023 发表于 2020-3-31 21:57 | 显示全部楼层
taotie 发表于 2020-3-31 13:00
数码管前贴黑膜~~~

谢谢,还没想到这一点。
回复

使用道具 举报

ID:584814 发表于 2020-4-2 10:36 | 显示全部楼层
手工能力超赞
回复

使用道具 举报

ID:116662 发表于 2020-4-4 20:17 | 显示全部楼层
这需要时间呀,多谢楼主分享
回复

使用道具 举报

ID:282850 发表于 2020-4-8 17:14 | 显示全部楼层
装1个DS18B20测温,如果用2个,一个测室外温度,一个测室内。我经常出门才知道衣服不够。
DS18b20精度、可靠性极高。程序想必你有了,如需要,我发给你。当然如果用无线把室外温度传来更好,推荐nrf24L01,不过MCU要低功耗的。
回复

使用道具 举报

ID:34298 发表于 2020-4-8 20:32 | 显示全部楼层
费劲做的最后时间误差太大 还是扔了 换成ds3231吧
回复

使用道具 举报

ID:690448 发表于 2020-4-8 21:54 | 显示全部楼层
楼主手艺好,壳子漂亮,但是瓤子太单调,建议换我这个方案。

20200323_135350.jpg



20200323_150835.jpg




101.jpg

评分

参与人数 1黑币 +10 收起 理由
王朗的诱惑 + 10 优雅

查看全部评分

回复

使用道具 举报

ID:630491 发表于 2020-4-13 18:58 | 显示全部楼层
推荐楼主学习ad,这样的话设计出pcb直接交付制作,这样只需要焊接元件,不需要焊接线路了
回复

使用道具 举报

ID:704585 发表于 2020-4-16 10:05 | 显示全部楼层
多谢楼主分享。
回复

使用道具 举报

ID:66679 发表于 2020-4-18 21:55 | 显示全部楼层

不错不错,赞一个!!!!好资料,51黑有你更精彩!!!
回复

使用道具 举报

ID:97023 发表于 2020-4-27 00:42 | 显示全部楼层
1679079206 发表于 2020-4-13 18:58
推荐楼主学习ad,这样的话设计出pcb直接交付制作,这样只需要焊接元件,不需要焊接线路了

谢谢推荐,其实AD我会的,只是平时制作一些小东西,专门去打板有点不划算。
年青时候不喜欢洞洞板,觉得一边焊接,一边思考,太痛苦了,特别是焊接好了以后要拆下来,更难。
最近几年接触到了洞洞板布线软件:LochMaster 4.0,先规划再焊接,这样轻松多了,目前对我来说用洞洞板制作是一种享受。至于打板,等今后制作更复杂的东西再说吧。
对你的《USB转TTL模块制作》文章很感兴趣,期待着更新。
回复

使用道具 举报

ID:128463 发表于 2020-5-25 16:45 | 显示全部楼层
多谢楼主分享!!!
回复

使用道具 举报

ID:430492 发表于 2020-5-25 19:15 | 显示全部楼层
做得不错,动手能力很棒啊!
回复

使用道具 举报

ID:743028 发表于 2020-5-26 10:35 来自手机 | 显示全部楼层
收藏一下
回复

使用道具 举报

ID:56960 发表于 2020-8-3 14:22 | 显示全部楼层
楼主强大,木制机箱是亮点,榫铆结构!
回复

使用道具 举报

ID:23303 发表于 2021-9-21 15:50 | 显示全部楼层
下载学习一下,谢谢楼主分享!
回复

使用道具 举报

ID:908826 发表于 2021-9-21 16:58 | 显示全部楼层
博主可以试试ds3231,这玩意还有温度采集功能。我觉得挺好用的
回复

使用道具 举报

ID:1011444 发表于 2022-6-30 20:43 | 显示全部楼层
楼主的动手能力,一个字“棒”,三个字“非常棒”,做出的产品几乎达到适用的机制水平,这对手工制作电子产品的电子业余爱好者来说,要做到是非常不容易。我也是diy爱好者,业余时间学点儿单片机知识,楼主应为我的学习的榜样。多谢了
回复

使用道具 举报

ID:832201 发表于 2022-7-3 23:35 | 显示全部楼层
佩服,
回复

使用道具 举报

ID:870445 发表于 2022-7-31 12:46 | 显示全部楼层
看到这个 真不错,正想做一个,谢谢了
回复

使用道具 举报

ID:1064667 发表于 2023-7-25 17:19 | 显示全部楼层
真不错,花了不少时间吧
回复

使用道具 举报

ID:397054 发表于 2023-7-29 17:49 | 显示全部楼层
同好啊,前两年我也做了个,形式跟你这个差不多,呵呵:

开工

开工


焊接中

焊接中



基本焊好

基本焊好



去年电路板上断了根线,缺比划,一直没功夫弄它,放在书架上吃了不少灰,前几天把它翻出来打算弄好那根线并修改一下程序:

51hei图片_20230729173223.jpg

回复

使用道具 举报

ID:1089276 发表于 2023-7-30 06:48 | 显示全部楼层
相当的牛叉
回复

使用道具 举报

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

本版积分规则

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

Powered by 单片机教程网

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