找回密码
 立即注册

QQ登录

只需一步,快速开始

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

DS1302电波钟制作 附单片机源程序

  [复制链接]
跳转到指定楼层
楼主
1、本人对单片机编程不在行,也是在不断学习中,我是搞硬件工作的,对一般的硬件电路倒是很熟悉,也用单片机做个一些非常简单的项目,比如一些试验设备也是用单片机来控制,事半功倍啊。但那些程序相对IIC,红外通信,1302来说都简单得不得了。本着利用业余时间不断学习精进的理想,一直在努力向前辈们学习中。平日里自己的作品都不能留在自己的手上,就像看着自己的儿子被人抱走一样,也许没什么技术含量,但自娱自乐一下,还是能提升不少荷尔蒙,为了弥补心中之遗憾,特别做一件留给自己的作品。
我不喜欢在开发板上作东西,那是开发前期试验程序用的,不能算是一件作品。一件作品必须是独立的实现预设的功能指标,所有的相关设计都是围绕这个功能为中心,并且作品具有一定的实用性和便利性。

该作品硬件比较简单,但程序部分花了我不少时间(因为是新手),电波钟解码部分找了些网上的相关解决方案和电波钟的信号编码规则,结合到手上1的程序,试验调试,解决各种BUG,最后完成。

2、材料清单:
1、STC12CXXXX单片机一片
2、1英寸白色数码管和红色小数码管共6只
3、74HC245一块
4、DS1302模块(用的现成的)一块
5、报时语音模块一块
6、电波钟模块一块
7、运放一块
8、光敏,发光二极管,PNP和NPN数只,按键4只,
9、连接线若干
10、透明防水外壳一个
11、杜帮线若干
12、9V线性变压电源一只
13、7805一块,SM1117一块
14、电解电容,钽电容,电阻,贴片电阻容若干
15、洞洞板一块,铜柱4根
16、防浪涌保护TVS管一只

3、开始工作
准备构思如何用好这些材料做出一个像样的作品,前壳为什么要全透明呢,这是为了增加电子作品的艺术性,观赏性(手工板也可以欣赏)能看清内部构造,即增加了作品的透明感,又增加了电子技术的神秘感。

理想中,成品应该可能也许大概是这样的

焊接几个,试试效果,不断构思,不断改进中。先用的绿色LED作为时分的分隔,后来发现绿光不纯,偏黄,后换成红色。

经过一天的焊接(业余时间),初步成型,先试试能不能动起来。嗯,不完美的地方来了,LED看起来亮与不亮的字段区分不明显,对于我这个强迫症来说,一定要加滤光片。不然难受,吃不下饭。

不管了,先把电波钟模块加上,淘宝15元。用热熔胶粘上去。语音模块也装上,喇叭也在侧面开了孔。电波模块用LED试验了一下,晚上能收到信号,白天基本不可能,电磁污染太严重(我就是搞EMC的),经我试验,坐标广州,收到商丘的电波钟信号,要在晚上00点以后,才能在窗户口收到正常的信号。


取个名《大笨钟》,LED已经加了滤光片,现在已经完美了。按键加上了,电波的电源控制等部分也完成了。写入程序,增加自己功能,并调试。白LED太亮,晚上就是小夜灯,所以在夜间要降低亮度,用光敏加运放自动控制。



红色LED在电波对时成功后会关闭,绿色LED是电波钟信号指示,会随信号有无闪动。夜间2-3点自动开启授时,授时失败红色LED亮起提示,直到第二次授时成功后,才会关闭。第4个按键改为强制手动授时。本来第4个键是手动关闭整点报时的。现在程序改为夜间自动关闭报时



最终完成,放在古董收音机上,不错。为什么我的按键要放在里面呢,调时要开盖,不方便??NONO,我的是电波授时,理论上,永远不用调时。所以不需要开盖调整。我也不需要年月日周,所以只要时间就OK。


以下是程序部分,发程序出来,不注释,别人很难看懂,隔几个月,自己可能都看不懂了。哈哈哈。

严正声明:本程序部分纯属个人技术性开发娱乐,无任何商业用途,如认为有侵权行为,速与我联系或与论坛管理员联系并删除。否则本人不承担任何法律责任。

/**************************************************
程序名:《大笨钟》
晶  振:24MHZ
功  能:LED数码管显示,按键可调,电波自动校时,整点报时功能,夜间光感自动亮度
全局变量已达到90个,有点多,后续要完善一下,只用一个程序文件写完。
******************************************************/
  1. /**************************************************
  2. 程序名:《大笨钟》
  3. 晶  振:24MHZ
  4. 功  能:LED数码管显示,按键可调,电波自动校时,整点报时功能,夜间光感自动亮度

  5. 全局变量已达到93个

  6. ******************************************************/
  7. #include<stc12c5a60s2.h>
  8. #include<intrins.h>

  9. #define uchar unsigned char
  10. #define uint unsigned int

  11. uchar Dat_su,Dat_num,min,hour,keysetnum;
  12. uchar s1,m1,h1;
  13. uchar hourshi,hourge,minshi,minge,secshi,secge;

  14. sbit DSIO = P2^2;          //1302信号脚
  15. sbit RST  = P2^1;          //1302复位信号脚
  16. sbit SCLK = P2^0;          //1302时钟信号脚

  17. sbit keyset = P3^7;           //进入设置
  18. sbit keyshi = P3^6;           //时加按键设置
  19. sbit keyfen = P3^5;           //分加按键设置
  20. sbit keyBPC = P3^4;           //电波强制对时按键
  21. sbit Ring   = P2^4;           //整点报时输出

  22. bit flag200ms;         //200MS读DS1302标志位
  23. bit keysetflag;         //进入按键设置标志位
  24. bit alarmflag;         //报时标志位

  25. /******BPC***********/
  26. sbit BPC    = P3^3;         //BPC输入,外部输入
  27. sbit BPC_EN = P2^3;          //BPC 使能
  28. sbit BPC_FailLED = P2^5;         //BPC校时失败指示灯
  29. bit keyBPCflag;                         //强制对时标志位
  30. bit BPC_add;                         //BPC中断标志位
  31. bit BPC_ok = 1;            //对时成功标志位,默认为开启才能开启BPC
  32. bit Get_time,As_time;          //授时标志位
  33. uchar Dat_su,Dat_num,keyBPCnum;
  34. uchar data BPC_dat[3][19];         //BPC3列个19组数组
  35. uint BPC_temp,Dat_add;                  //BPC脉宽时间记录变量
  36. uchar data Times[3];  //BPC "分,时,上/下午“数组


  37. uchar DisplayData[6];        //LED显示缓存数组
  38. uchar code smgduan[10] = {0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0x78,0x80,0x90};        //LED 0-9

  39. //DS1302写入和读取时分秒的地址命令
  40. //秒分时日月周年最低位读写位
  41. uchar code READ_RTC_ADDR[7] = {0x81, 0x83, 0x85, 0x87, 0x89, 0x8b, 0x8d};
  42. uchar code WRITE_RTC_ADDR[7] = {0x80, 0x82, 0x84, 0x86, 0x88, 0x8a, 0x8c};

  43. //存储顺序秒分时日月周年,存储格式是用BCD码//
  44. uchar TIME[7];


  45. /*************************************
  46. * 函数名: delay()
  47. * 按键延时函数,按键使用
  48. ************************************/
  49. void delay()           //100ms
  50. {                                 
  51.     unsigned char a,b,c;
  52.     for(c=4;c>0;c--)
  53.         for(b=212;b>0;b--)
  54.             for(a=140;a>0;a--);
  55. }

  56. /*******************************************************************************
  57. * 函 数 名         : Ds1302Write
  58. * 函数功能                   : 向DS1302命令(地址+数据)
  59. * 输    入         : addr,dat
  60. *******************************************************************************/

  61. void Ds1302Write(uchar addr, uchar dat)
  62. {
  63.         uchar n;
  64.         RST = 0;
  65.         _nop_();

  66.         SCLK = 0;               //先将SCLK置低电平。
  67.         _nop_();
  68.         RST = 1;                //然后将RST(CE)置高电平。
  69.         _nop_();

  70.         for (n=0; n<8; n++)     //开始传送八位地址命令
  71.         {
  72.                 DSIO = addr & 0x01;//数据从低位开始传送
  73.                 addr >>= 1;
  74.                 SCLK = 1;          //数据在上升沿时,DS1302读取数据
  75.                 _nop_();
  76.                 SCLK = 0;
  77.                 _nop_();
  78.         }
  79.         for (n=0; n<8; n++)   //写入8位数据
  80.         {
  81.                 DSIO = dat & 0x01;
  82.                 dat >>= 1;
  83.                 SCLK = 1;         //数据在上升沿时,DS1302读取数据
  84.                 _nop_();
  85.                 SCLK = 0;
  86.                 _nop_();        
  87.         }        
  88.                  
  89.         RST = 0;              //传送数据结束
  90.         _nop_();
  91. }

  92. /*******************************************************************************
  93. * 函 数 名         : Ds1302Read
  94. * 函数功能                   : 读取一个地址的数据
  95. * 输    入         : addr
  96. * 输    出         : dat
  97. *******************************************************************************/

  98. uchar Ds1302Read(uchar addr)
  99. {
  100.         uchar n,dat,dat1;
  101.         RST = 0;
  102.         _nop_();

  103.         SCLK = 0;              //先将SCLK置低电平。
  104.         _nop_();
  105.         RST = 1;               //然后将RST(CE)置高电平。
  106.         _nop_();

  107.         for(n=0; n<8; n++)     //开始传送八位地址命令
  108.         {
  109.                 DSIO = addr & 0x01;//数据从低位开始传送
  110.                 addr >>= 1;
  111.                 SCLK = 1;          //数据在上升沿时,DS1302读取数据
  112.                 _nop_();
  113.                 SCLK = 0;          //DS1302下降沿时,放置数据
  114.                 _nop_();
  115.         }
  116.         _nop_();
  117.         for(n=0; n<8; n++)    //读取8位数据
  118.         {
  119.                 dat1 = DSIO;      //从最低位开始接收
  120.                 dat = (dat>>1) | (dat1<<7);
  121.                 SCLK = 1;
  122.                 _nop_();
  123.                 SCLK = 0;        //DS1302下降沿时,放置数据
  124.                 _nop_();
  125.         }

  126.         RST = 0;
  127.         _nop_();               //DS1302复位的稳定时间,必须的。
  128.         SCLK = 1;
  129.         _nop_();
  130.         DSIO = 0;
  131.         _nop_();
  132.         DSIO = 1;
  133.         _nop_();
  134.         return dat;        
  135. }

  136. /*******************************************************************************
  137. * 函 数 名         : Ds1302Init
  138. * 函数功能                   : 初始化DS1302  

  139. *******************************************************************************/

  140. void Ds1302Init()
  141. {
  142.         uchar dat;
  143.         RST = 0;
  144.     SCLK = 0;
  145.         dat = Ds1302Read(0x81);                 //读1302最高位判断掉电时间是否正常
  146.         if((dat&0x80)!=0)                           //为0,正常运行
  147.          {
  148.                  Ds1302Write(0x8E,0X00);                 //禁止写保护,就是关闭写保护功能
  149.                 Ds1302Write(0x84,0x00);                  //写入时钟最高位为0,定义为24小时制
  150.                
  151.                 /******
  152.                 本程序不需要写入年月日和初始时间
  153.                 for (n=0; n<7; n++)          //写入7个字节的时钟信号:分秒时日月周年
  154.             {
  155.                         Ds1302Write(WRITE_RTC_ADDR[n],TIME[n]);        
  156.                 }
  157.                 *******/
  158.                 Ds1302Write(0x8E,0x80);                 //打开写保护功能
  159.         }         
  160. }

  161. /*******************************************************************************
  162. * 函 数 名         : Ds1302ReadTime
  163. * 函数功能                   : 读取时钟信息

  164. *******************************************************************************/

  165. void Ds1302ReadTime()
  166. {
  167.         uchar n;
  168.         for (n=0; n<7; n++)    //读取7个字节的时钟信号:分秒时日月周年
  169.         {
  170.                 TIME[n] = Ds1302Read(READ_RTC_ADDR[n]);
  171.         }
  172.                
  173. }


  174. /*******************************************************************************
  175. * 函 数 名         : datapros()
  176. * 函数功能                   : 时间读取处理转换函数

  177. *******************************************************************************/

  178. void datapros()         
  179. {
  180.            Ds1302ReadTime();  //先读取1302的时分秒
  181.         DisplayData[0] = smgduan[TIME[2]>>4];       //时十位                                    
  182.         DisplayData[1] = smgduan[TIME[2]&0x0f];                                 
  183.         DisplayData[2] = smgduan[TIME[1]/16];                //分十位
  184.         DisplayData[3] = smgduan[TIME[1]&0x0f];        
  185.         DisplayData[4] = smgduan[TIME[0]/16];                 //秒十位
  186.         DisplayData[5] = smgduan[TIME[0]&0x0f];
  187. }


  188. /*******************************************************************************
  189. * 函 数 名         :keyscan()
  190. * 函数功能                   :按键设置时间和BPC对时

  191. *******************************************************************************/
  192. void keyscan()
  193. {
  194.         if(keyset == 0)
  195.         {
  196.                 delay();
  197.                 if(keyset == 1)
  198.                   {                          
  199.                           keysetnum++;         //按键记录值
  200.                         h1 = (TIME[2]>>4)*10+(TIME[2]&0x0f)%10;//先将1302暂停时的小时值转换成十进制赋予变量H1时,以便在此基础上累加调整改然后写入1302
  201.                         m1 = (TIME[1]>>4)*10+(TIME[1]&0x0f)%10;//先将1302暂停的的分钟值转换成十进制赋予变量M1时,以便在此基础上累加调整改然后写入1302                    
  202.                   }
  203.                   if(keysetnum == 1)         //按一次
  204.                   {
  205.                           keysetflag = 1;           //按下KEYSET标志位,用以暂停读1302
  206.                   }
  207.                   if(keysetnum >= 2)   //按二次,恢复读1302,不能==2,可能因按键因素大于2
  208.                   {
  209.                           keysetnum = 0;                //清零
  210.                         keysetflag = 0;                //标志位清零,恢复读1302        
  211.                         Ds1302Write(0x8E,0X00);         //关闭1302写保护
  212.                         Ds1302Write(0x80,0);     //向秒寄存器写入0
  213.                         Ds1302Write(0x8E,0x80);         //打开1302写保护
  214.                   }
  215.      }
  216.          if(keyshi == 0)                                //“时”增加按键
  217.          {
  218.                  delay();
  219.                 if((keyshi==1)&&(keysetflag==1)) //判断KEYSET标志位,只有KEYSET按下后才运行
  220.                 {                        
  221.                         h1++;                                                 //小时加1,24小时制
  222.                         if(h1>23)
  223.                         {
  224.                                 h1 = 0;
  225.                         }
  226.                         DisplayData[0] = smgduan[h1/10];  //十进制转换送LED十位显示
  227.                         DisplayData[1] = smgduan[h1%10];  //十进制转换送LED个位显示
  228.                         hour = (h1/10*16)+(h1%10);         //将H1的值转换成BCD码赋给HOUR
  229.                         Ds1302Write(0x8E,0X00);                //关闭1302写保护
  230.                         Ds1302Write(0x84,hour);          //向1302“时”寄存器写入小时值
  231.                         Ds1302Write(0x8E,0x80);         //打开1302写保护
  232.                 }
  233.          }
  234.          if(keyfen == 0)                          //“分”增加键
  235.          {
  236.                  delay();
  237.                 if((keyfen==1)&&(keysetflag==1))   //判断KEYSET标志位,只有KEYSET按下后才运行
  238.                 {        
  239.                         m1++;
  240.                         if(m1>59)                                   //分,十进制
  241.                         {
  242.                                 m1 = 0;
  243.                         }
  244.                         DisplayData[2] = smgduan[m1/10];         //十进制转换送LED十位显示
  245.                         DisplayData[3] = smgduan[m1%10];        //十进制转换送LED个位显示
  246.                         min = (m1/10*16)+(m1%10);                //将m1的值转换成BCD码赋给min
  247.                         Ds1302Write(0x8E,0X00);                    //关闭写保护
  248.                         Ds1302Write(0x82,min);              //向"分"寄存器写入分钟值
  249.                         Ds1302Write(0x8E,0x80);                    //打开写保护
  250.                 }
  251.          }
  252.          if(keyBPC == 0)          //按键强制开启BPC
  253.          {
  254.                  delay();
  255.                 if(keyBPC == 1)
  256.                 {
  257.                         keyBPCnum++;
  258.                         if(keyBPCnum == 1)         //按下一次,开启BPC
  259.                         {
  260.                           BPC_EN = 0;
  261.                           BPC_FailLED = 1;
  262.                           keyBPCflag = 1;
  263.                     }
  264.                         if(keyBPCnum >= 2)          //按下第二次,关闭BPC
  265.                         {
  266.                           keyBPCnum = 0;
  267.                           BPC_EN = 1;
  268.                           BPC_FailLED = 0;
  269.                           keyBPCflag = 0;        
  270.                         }
  271.                 }               
  272.          }
  273. }

  274. /*********************************************
  275. * 整点报时函数     :AlarmRing()
  276. * 函数功能         : 整点报时

  277. **********************************************/
  278. void AlarmRing()
  279. {
  280.         uchar p,q;
  281.         p = (TIME[1]>>4)*10+(TIME[1]&0x0f)%10;        //读取1302 变为十进制,分钟为00
  282.         q = (TIME[0]>>4)*10+(TIME[0]&0x0f)%10;        //秒钟为00
  283.         if((p|q) == 0) //分与秒相或为0时
  284.         {        
  285.                 if(alarmflag == 1)         //先判断报时标志打开,禁止报时段标志为0
  286.                 {
  287.                   Ring = 1;                          //触发报时
  288.                   delay();
  289.                   delay();
  290.                   Ring = 0;                          //关闭触发
  291.             }        
  292.     }        
  293. }
  294. /************************************************************
  295. * 整点报时设定函数 : Closealarm()
  296. **函数功能         : 设置整点报时时段

  297. ***********************************************************/
  298. void Closealarm()
  299. {
  300.         uchar k;
  301.         k = (TIME[2]>>4)*10+(TIME[2]&0x0f)%10;         //读1302小时值,转成十进制,设定关闭闹钟时间段
  302.         if((0<=k)&&(k<=5))         //小5点,大于0点时段,关闭整点报时
  303.         {
  304.                 alarmflag = 0;        //关闭报时标志 0-6点
  305.                 //alarmLED = 0;        //关闭报时指示灯
  306.         }
  307.         else                                //打开报时
  308.         {
  309.                 alarmflag = 1;          //否则打启报时标志位
  310.                 //alarmLED = 1;
  311.         }
  312. }
  313. /******************************************************
  314. * BPC接收函数    : recieveBPCtime()
  315. * 函数功能       : 接收BPC授时和写入DS1302时间

  316. *******************************************************/
  317. void recieveBPCtime()
  318. {   
  319.     if(As_time)         //正确接收19位数据标志位
  320.      {
  321.            As_time=0;        //清零标志,并判断一分钟内3列19组相同的数据,“分时周月年”
  322.            if(
  323.                      (BPC_dat[0][1]==BPC_dat[1][1])&&(BPC_dat[0][1]==BPC_dat[2][1])
  324.                    &&(BPC_dat[0][2]==BPC_dat[1][2])&&(BPC_dat[0][2]==BPC_dat[2][2])
  325.                    &&(BPC_dat[0][3]==BPC_dat[1][3])&&(BPC_dat[0][3]==BPC_dat[2][3])
  326.                    &&(BPC_dat[0][4]==BPC_dat[1][4])&&(BPC_dat[0][4]==BPC_dat[2][4])
  327.                    &&(BPC_dat[0][5]==BPC_dat[1][5])&&(BPC_dat[0][5]==BPC_dat[2][5])
  328.                    &&(BPC_dat[0][6]==BPC_dat[1][6])&&(BPC_dat[0][6]==BPC_dat[2][6])
  329.                    &&(BPC_dat[0][7]==BPC_dat[1][7])&&(BPC_dat[0][7]==BPC_dat[2][7])
  330.                    &&(BPC_dat[0][8]==BPC_dat[1][8])&&(BPC_dat[0][8]==BPC_dat[2][8])
  331.                    &&(BPC_dat[0][10]==BPC_dat[1][10])&&(BPC_dat[0][10]==BPC_dat[2][10])
  332.                    &&(BPC_dat[0][11]==BPC_dat[1][11])&&(BPC_dat[0][11]==BPC_dat[2][11])
  333.                    &&(BPC_dat[0][12]==BPC_dat[1][12])&&(BPC_dat[0][12]==BPC_dat[2][12])
  334.                    &&(BPC_dat[0][13]==BPC_dat[1][13])&&(BPC_dat[0][13]==BPC_dat[2][13])
  335.                    &&(BPC_dat[0][14]==BPC_dat[1][14])&&(BPC_dat[0][14]==BPC_dat[2][14])
  336.                    &&(BPC_dat[0][15]==BPC_dat[1][15])&&(BPC_dat[0][15]==BPC_dat[2][15])
  337.                    &&(BPC_dat[0][16]==BPC_dat[1][16])&&(BPC_dat[0][16]==BPC_dat[2][16])
  338.                    &&(BPC_dat[0][17]==BPC_dat[1][17])&&(BPC_dat[0][17]==BPC_dat[2][17])
  339.              )
  340.                          Get_time=1;
  341.              }
  342.            if(Get_time)         //收到3帧相同的数据后,对Times[]数据赋值授时
  343.              {
  344.                    Get_time=0;                                   //标志位清零
  345.                                    keysetflag = 1;                            //利用该标志位来暂停读DS1302
  346.                                    Times[0]=((BPC_dat[0][2]*4)+(BPC_dat[0][3]));  //BPC”时“,4进制,第2、3位
  347.                    Times[1]=((BPC_dat[0][4]*16)+(BPC_dat[0][5]*4)+(BPC_dat[0][6])+1); //BPC”分“,4进制,第4,5,6位,3帧数据相同后,分的起始点为第2分钟00秒,要加1补偿                                                   
  348.                                    Times[2]=(BPC_dat[0][9]);   //判断BPC第10位识别上/下午,0,1为上午,2,3为下午
  349.                                    if(Times[2]<2)                   //上下午判断,如果小于2,为上午
  350.                                      {
  351.                                                  hour = (Times[0]/10*16)+(Times[0]%10);          //时转换成BCD
  352.                                                 min = (Times[1]/10*16)+(Times[1]%10);          //分转换成BCD
  353.                                          }
  354.                                         else                         //上下午判断,如果大于1,为下午
  355.                                          {
  356.                                                  hour = ((Times[0]+12)/10*16)+((Times[0]+12)%10);  //BPC下午,Times[3]要加12变为24小时制并转换为BCD
  357.                                                 min = (Times[1]/10*16)+(Times[1]%10);                  //分转成BCD
  358.                                          }                                   
  359.                                            Ds1302Write(0x8E,0X00);          //关闭写保护
  360.                                         Ds1302Write(0x84,hour);          //向时寄存器写入小时值
  361.                                         Ds1302Write(0x82,min);    //向分寄存器写入
  362.                                         Ds1302Write(0x80,0);      //向秒寄存器写入0,一分钟3帧相同信号,分加1后,秒归0.无需判断
  363.                                         Ds1302Write(0x8E,0x80);          //打开写保护
  364.                                         keysetflag = 0;                          //恢复读1302
  365.                                         BPC_ok = 0;                          //授时成功标志清零
  366.                                         BPC_EN = 1;               //接收成功后,关闭BPC
  367.                                         BPC_FailLED = 0;          //关闭授时失败指示灯
  368.                                         keyBPCflag = 0;                          //取消强制对时标志位
  369.               }
  370. }
  371. /**************************************************
  372. * BPC自动接收函数  : BPC_openset()
  373. * 函数功能         : 设置BPC开启授时时间

  374. *************************************************/
  375. void BPC_openset()
  376. {
  377.         uchar t;
  378.         t = (TIME[2]>>4)*10+(TIME[2]&0x0f)%10; //先读出1302的小时值,转换成十进制
  379.         if(t == 2)                                  //夜间2点,持续接收BPC。
  380.         {
  381.                 if(BPC_ok)                        //先判断BPC授时成功标志位,授时成功一次,不再执行该程序
  382.                 {
  383.                         BPC_EN = 0;                       //打开BPC授时模块
  384.                         BPC_FailLED = 1;           //打开授时失败指示灯
  385.                  }
  386.         }
  387.         if(t == 3)                              //夜时3点,如未成功授时自动关闭BPC
  388.         {
  389.                 if(keyBPCflag == 0)                  //判断按键强制对时按键标志位,如果有按键强制对时,不执行
  390.             {
  391.                    BPC_EN = 1;                  //1小时内授时不成功,关闭BPC模块,不关指示灯用于提示授时失败
  392.                    BPC_ok = 1;            // 开授时成功标志位,以便下一个2点能开启BPC模块
  393.              }
  394.         }        
  395. }

  396. /*******************************************************************************
  397. * 函 数 名       : main
  398. * 函数功能                 : 主函数

  399. *******************************************************************************/
  400. void main()
  401. {        
  402.         Ring = 0;                         // 整点报时初始值
  403.         BPC_EN = 1;                          //BPC使能初始
  404.         BPC_FailLED = 0;          //授时失败指示灯初始

  405.         EA = 1;
  406.         TMOD = 0x01;                //T0
  407.         TH0 = (65536-2000)/256;           //LED刷新和定时读DS1302
  408.         TL0 = (65536-2000)%256;
  409.         TR0 = 1;
  410.         ET0 = 1;

  411.         IT1=1;        //P33下降沿触发
  412.     EX1=1;                  //开启外部中断
  413.     PX1=1;                  //外部中断优先

  414.     //Ds1302Init(); //本程序无需初始化DS1302

  415.         while(1)
  416.         {
  417.                 Closealarm();       //整点报时关闭时段
  418.                 keyscan();                //按键
  419.                 AlarmRing();        //整点报时
  420.                 BPC_openset();            // BPC开启函数
  421.                 recieveBPCtime();   //BPC接收转换函数
  422.                
  423.                 if(flag200ms)                  //读1302时间标志
  424.                 {
  425.                         flag200ms = 0;
  426.                         if(keysetflag == 0)         //有按键调整时,标志位置1,暂停读1302
  427.                         {
  428.                           datapros();             //数据处理函数        
  429.                     }        
  430.         }
  431.         }        
  432. }               

  433. /*******************************************************************************
  434. * 函 数 名       : interruptimer()
  435. * 函数功能                 : 中断,刷新数码管,BPC时间记时判断脉宽值

  436. *******************************************************************************/
  437. void interrutptimer() interrupt 1
  438. {
  439.         uchar i,ms;
  440.         TH0 = (65536-2000)/256;           //1ms
  441.         TL0 = (65536-2000)%256;
  442.         ms++;
  443.         if(ms>=200)
  444.         {
  445.                 ms = 0;
  446.                 flag200ms = 1;                 //读1302间隔时间段
  447.         }
  448.         switch(i)
  449.         {
  450.                 case 0:        P1=0x3e;i++;P0=0x00;P0=DisplayData[5];break;         // 秒
  451.                 case 1:        P1=0x3d;i++;P0=0x00;P0=DisplayData[4];break;
  452.                 case 2:        P1=0x3b;i++;P0=0x00;P0=DisplayData[3];break;         //分
  453.                 case 3:        P1=0x37;i++;P0=0x00;P0=DisplayData[2];break;
  454.                 case 4:        P1=0x2f;i++;P0=0x00;P0=DisplayData[1];break;         //时
  455.                 case 5:        P1=0x1f;i=0;P0=0x00;P0=DisplayData[0];break;        
  456.                 default: break;
  457.         }
  458.         
  459.   Dat_add++;                     //外部中断内对ADD清零,1500次内,有外部中断,重新清零
  460.   if(Dat_add>1500)     //BPC启始信号,每1MS对DAT_add加1,如在1500个周期内没有进入外部中断被清零,1.5S后标志找到超始信号,重新对Dat_num清零,以便重新对19个位赋值
  461.           Dat_num=0;               //对数组清零,说明已授收到超始脉冲

  462.   if(BPC_add)          //外部中断标志为真
  463.     {
  464.       if(!BPC)                // 第1个脉冲负边到来时
  465.                   BPC_temp++;           //用BPC_temp累加值来判断脉宽
  466.      else
  467.         {
  468.           BPC_add=0;   //当第1个脉冲跳变为正边时,对BPC_add标志位清零,等待下个脉冲的中断
  469.           if((BPC_temp>50)&&(BPC_temp<150)) BPC_dat[Dat_su][Dat_num]=0;        //判断脉宽值,赋值给二维数组的第[0][0]
  470.      else if((BPC_temp>150)&&(BPC_temp<250))BPC_dat[Dat_su][Dat_num]=1;
  471.      else if((BPC_temp>250)&&(BPC_temp<350))BPC_dat[Dat_su][Dat_num]=2;
  472.      else if((BPC_temp>350)&&(BPC_temp<450))BPC_dat[Dat_su][Dat_num]=3;
  473.      else Dat_num=0;    //如果以上有不正确的值,对Dat_num清零重来
  474.          
  475.           Dat_num++;      //对第二维的数据的值清零
  476.           if(Dat_num>18)
  477.             {
  478.               Dat_num=0;
  479.               As_time=1;    //正确接收19位数据标志位
  480.               Dat_su++;                //对第一维的数据增加,最终共3*19组数据
  481.                           if(Dat_su>2)
  482.                           Dat_su=0;
  483.             }
  484.            BPC_temp=0;            //脉冲累加值清零
  485.         }
  486.      }        
  487. }

  488. /***********************************************************************
  489. * 电波钟中断检测函数    :Time_EX1()
  490. * 函数功能              : BPC当外部下降沿时产生中断,标志置位,清零时间累加值

  491. ***************************************************************************/
  492. void Time_EX1(void)interrupt 2          //外部中断,优先级为最高,防止漏检
  493. {
  494.   BPC_add=1;                                          //外部中断标志
  495.   Dat_add=0;                                          //1ms定时中断内对变量加1,用来判断1.5S的超始脉冲
  496. }

复制代码
发贴不易,敬请评论指点,特别是在程序上,希望能学习时步。
全部资料51hei下载地址:
大笨钟.zip (53.95 KB, 下载次数: 160)

评分

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

查看全部评分

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

使用道具 举报

沙发
ID:744744 发表于 2020-6-20 17:03 | 只看该作者
安装时需要注意,电波钟模块要离单片机远些,天线也要远离数码管,之所以选这么大的盒子,就是为了解决空间物理距离问题。
回复

使用道具 举报

板凳
ID:744744 发表于 2020-6-20 18:00 | 只看该作者
通过得这么快,管理员辛苦了
回复

使用道具 举报

地板
ID:392521 发表于 2020-6-22 08:54 | 只看该作者
感谢分享,我也打算做一个玩,请问楼主有没有原理图?

回复

使用道具 举报

5#
ID:744744 发表于 2020-6-22 20:17 | 只看该作者
sdqzlihui 发表于 2020-6-22 08:54
感谢分享,我也打算做一个玩,请问楼主有没有原理图?

原理图没画,硬件都是现成的,对应连好就行,更改端口定义就行。需要注意的是BPC电波钟信号要加一个NPN倒相输入,它的供电要加一个3.3V的LDO, 单片机的BPC_EN控制脚,采用电阻为压将这个IO口变为3V,其它的就是照常规连接就好。
在这几天的不断试验中发现,采用STC1T的单片机,加上又采用了24MHZ的晶振,重复开关机,会使时间读出错误码,1302反应不过来,单片机太快,自己读到自己的IO口电平了,读出92点35分,所以建议采用8MHZ晶振,给1302足够的反应时间。通过更改后就正常了。
回复

使用道具 举报

6#
ID:143244 发表于 2020-6-23 21:07 | 只看该作者
动手做,记得住,不过用便宜点的开发板更好!
回复

使用道具 举报

7#
ID:744744 发表于 2020-11-13 14:09 来自手机 | 只看该作者
近几天又重新做了个2.0版本来除了但留之前的功能外,还增加了夜间关闭led的功能,然后通过声控唤醒10秒,一来省电,二来放卧室不会影响到睡觉,完全是个小夜灯。
回复

使用道具 举报

8#
ID:744744 发表于 2020-11-13 14:10 来自手机 | 只看该作者
增加了日期和星期,温湿度等功能。

IMG_20201113_140607.jpg (1.63 MB, 下载次数: 152)

IMG_20201113_140607.jpg
回复

使用道具 举报

9#
ID:846386 发表于 2020-12-2 23:51 | 只看该作者
楼主把最新的电路图和代码发上来学习,谢谢
回复

使用道具 举报

10#
ID:383885 发表于 2020-12-3 10:33 | 只看该作者
太棒了,牛!
回复

使用道具 举报

11#
ID:744744 发表于 2020-12-9 11:58 来自手机 | 只看该作者
kiccleaf 发表于 2020-12-2 23:51
楼主把最新的电路图和代码发上来学习,谢谢

哪天有空用电脑上传上来
回复

使用道具 举报

12#
ID:744744 发表于 2022-4-17 07:31 来自手机 | 只看该作者
利用一个烂石英钟外壳,打印一张梅花图装饰,又做了个办工桌小闹钟。十分具有年代感。

IMG_20220417_072832.jpg (349.12 KB, 下载次数: 117)

IMG_20220417_072832.jpg
回复

使用道具 举报

13#
ID:430492 发表于 2022-4-17 13:30 | 只看该作者
楼上这张图,想法不错,很好看!!
回复

使用道具 举报

14#
ID:744744 发表于 2022-4-17 14:07 来自手机 | 只看该作者
cooleaf 发表于 2022-4-17 13:30
楼上这张图,想法不错,很好看!!

谢谢,业余时间,迷上了各种diy。做的东西挺多。纯属娱乐。
回复

使用道具 举报

15#
ID:478849 发表于 2022-4-29 09:08 | 只看该作者
谢谢分享,学习了,原理图是怎么接线的
回复

使用道具 举报

16#
ID:146324 发表于 2022-5-5 11:11 | 只看该作者
楼主,能简单的画个电路图吗?不知道怎么接线。谢谢了
回复

使用道具 举报

17#
ID:744744 发表于 2022-5-5 11:27 来自手机 | 只看该作者
突然想学习 发表于 2022-5-5 11:11
楼主,能简单的画个电路图吗?不知道怎么接线。谢谢了

其它的按键,显示等,根据自己的喜好使用,都是通用的。我画了电波模块的接线方法,可参考。

IMG_20220505_112454.jpg (552.53 KB, 下载次数: 137)

IMG_20220505_112454.jpg
回复

使用道具 举报

18#
ID:1011444 发表于 2022-5-8 18:23 | 只看该作者
请教:程序编译未通过,提示未发现设备,需要更新设备,这是什么原因?另外换用其他单片机(比如stc89c52rc)行吗、
回复

使用道具 举报

19#
ID:744744 发表于 2022-5-8 22:22 来自手机 | 只看该作者
kz0018 发表于 2022-5-8 18:23
请教:程序编译未通过,提示未发现设备,需要更新设备,这是什么原因?另外换用其他单片机(比如stc89c ...

至于是什么问题导致编辑不通过,从描述是很难找出原因的。单片机可以换,不影响。
回复

使用道具 举报

20#
ID:383222 发表于 2022-5-18 12:33 | 只看该作者
可以通过编译,谢谢,分享,
回复

使用道具 举报

21#
ID:272411 发表于 2023-4-19 21:28 | 只看该作者
下载收藏,谢谢分享。可以通过编译
回复

使用道具 举报

22#
ID:138707 发表于 2023-8-6 17:01 | 只看该作者
楼上这张图,想法不错,很好看!!
回复

使用道具 举报

23#
ID:1085441 发表于 2023-8-7 02:06 | 只看该作者
可以问一下电波钟模块的型号,价格多少?
回复

使用道具 举报

24#
ID:88256 发表于 2023-8-7 09:59 | 只看该作者
电波钟在很多地方的室内都不太好接收吧?楼主做的是实用性的东西,我觉得可以换个方案,现在的家里WIFI都是一直开着的,可以使用ESP-12F模块作为主控以及网络连接,用网络对时,走时靠模块,有纠结的话上RTC(不断电不断网其实真没必要);显示用TM1650系列,可以7级调节亮度(配合光敏电阻自动调节也行),电源、阻容不算,也就使用ESP-12F+TM1650+数码管,极度简洁。
回复

使用道具 举报

25#
ID:195496 发表于 2023-8-11 08:56 | 只看该作者
kz0018 发表于 2022-5-8 18:23
请教:程序编译未通过,提示未发现设备,需要更新设备,这是什么原因?另外换用其他单片机(比如stc89c ...

要更改头文件
回复

使用道具 举报

26#
ID:929517 发表于 2023-9-11 18:17 来自手机 | 只看该作者
不是低电平才能点亮LED吗,你这个怎么是高电平?另外,按键怎么没有消抖?
回复

使用道具 举报

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

本版积分规则

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

Powered by 单片机教程网

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