找回密码
 立即注册

QQ登录

只需一步,快速开始

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

搭棚焊了一个高精度时钟送小姑娘(DS3231+89c52单片机)

  [复制链接]
跳转到指定楼层
楼主
前几天在网上闲逛发现有人搭棚焊了一个时钟,一时心动想自己也做一个送小姑娘。

说干咱就干,从万能的X宝上下单,几天货到!

先简单画了个草图
开焊,过程就不发图了,看成品。89c52+ds1302+18b20+共阳时钟数码管
串口线直接焊在1011脚上,写程序。成了!!!




拷了几天机,发现时间不准,平均每天慢十几分钟,查了一下说是晶振没选好,电容没匹配。哎!调了几次没搞好,也不想再调试了。



有人说DS3231好用,于是换方案。

同样草图



为了焊的好看一点,数码管自定义。
早晨上班,等红灯时发现一女司机抱着狗儿开车。

过程不多,看成品。还是串口线直接下载。底座是电池盒,用三节5号电池。不知能用多久,没测过电工作电流。没有万用表。你信吗,试验室里竟然没有万用表!
后来焊了一个USB接口可以手机充电器供电。




拷机一个月快了55秒!哎!勉强接授吧!



最后附上电路图和程序,这是我做完以后画的,各实际的不太一样,特别是单片机和数码管之间的连接不一样,所以才用了自定义的显示字库,其它的也不知有没有错误。
程序奉上一部分,其它的请下载吧!赚点积分!

单片机源码:
  1. #include <reg52.h>
  2. #include<intrins.h>[/color][/align][align=left][color=#000000]#define uchar unsigned char
  3. #define uint  unsigned int[/color][/align][align=left][color=#000000]
  4. sbit SDA=P2^7;     //数据传送位SDA        
  5. sbit SCL=P2^6;     //时钟控制位SCL
  6. sbit INT=P3^3;     //中断位
  7. sbit RESET=P3^2;   //复位
  8. sbit smg4=P1^1;    //位码1声明 分个位
  9. sbit smg3=P1^3;    //位码2声明 分十位
  10. sbit smg2=P1^5;    //位码3声明 时个位
  11. sbit smg1=P1^7;    //位码4声明 时十位
  12. sbit k1=P1^4;      //按键k1的声明
  13. sbit k2=P1^6;      //按键k2的声明
  14. sbit k3=P3^7;      //按键k3的声明
  15. sbit bell=P3^5;    //蜂鸣器声明
  16. sbit gm=P2^1;      //测光声明,黑暗时等于1[/color][/align]
  17. bit gm_en=0;       //光敏使能信号;
  18. bit  ack;          //应答标志位
  19. char code dis_code[]={0X28,0XEE,0X32,0XA2,0XE4,0XA1,0X21,0XEA,0X20,0XA0,0X60,0X25,0X37,0X26,0X31,0X71};//数码管没有按a-h的顺序连接,自定义的显示字库,0-9,A-F
  20. uchar bell_en=0,x=1;//闹钟使能信号,任意键关闭铃声标志位
  21. uchar tabtime[]={0x00,0x00,0x07,0x02,0x23,0x10,0x18};                //首次上电时默认的时间2018年 星期二 10月23日 07:00:00
  22. uchar year,month,day,week,hour,minute,second,temperature;             //从1302读出的实时时间数据
  23. uchar gm_time=60,temp_en=0,n=0,a=0,b=0;       //gm_time光敏控制亮度值,n是按键标志位,a产生一个1秒的计时,b控制字符闪烁,temp_en温度显示标志
  24. uint  t=0;      //用来产生30秒的计时
  25. uint  TtempH,TtempL;    //定义温度高位,低位
  26. char shi,fen,miao,b_shi=7,b_fen=0; //必须使用符号型:数据暂存单元shi/fen/miao,闹铃时间b_shi,b_fen,
  27. void baojing();               //报警函数
  28. void delay_50us(uint t);      //延时50*T微妙函数的声明
  29. void Start_I2C();             //I2C总线产生起始信号函数
  30. void Stop_I2C();              //I2C总线产生停止信号函数
  31. void Ack_I2C(bit a);          //接收应答信号函数;
  32. void SendByte(uchar c);       //向I2C总线写入一个字节的数据函数
  33. uchar RcvByte();              //字节数据接收函数
  34. uchar write_byte(uchar addr, uchar write_data);//将一个字节写入DS3231指定地址
  35. uchar read_byte(uchar addr);  //从DS3231指定地址读一个字节
  36. void Set_Time();              //设置时间
  37. void get_time(void);          //读取时间
  38. void get_Temperature();       //读取温度
  39. void show_Temperature();      //显示温度
  40. void init();                  //初始化函数
  41. void timer0();                //定时器0中断服务程序
  42. void display(uchar s,f);      //显示子程序
  43. void key();                   //按键控制函数

  44. void baojing()//报警函数
  45. {
  46.    uint j=10,i=10;
  47.    bell=0;
  48.    while(i--)display(shi,fen);
  49.    bell=1;
  50.    while(j--)display(shi,fen);
  51. }

  52. //函数名称:void delay_50US(unsigned int t)
  53. //功能: 延时50*t(us)
  54. void delay_50us(uint t)
  55. {
  56.   unsigned char j;
  57.   for(;t>0;t--)
  58.   {
  59.     for(j=19;j>0;j--);
  60.   }
  61. }

  62. void Start_I2C()            //I2C总线产生起始信号函数
  63. {
  64.     SDA=1;                  //拉高数据线,发送起始条件的数据信号
  65.     SCL=1;                  //拉高时钟线
  66.     SDA=0;                  //在时钟线为高电平时,拉低数据线,产生起始信号
  67.     SCL=0;                  //钳住I2C总线,准备发送或接收数据
  68. }

  69. void Stop_I2C()             //I2C总线产生停止信号函数
  70. {
  71.     SDA=0;                  //拉低数据线,发送结束条件的数据信号
  72.     SCL=1;                  //拉高时钟线,发送结束条件的时钟信号
  73.     SDA=1;                  //时钟时线为高电平时,拉高数据线,发送I2C总线结束信号
  74. }

  75. /********************************************************************
  76.                       应答子函数
  77. 函数原型:   void I2CACK(bit a);
  78. 功能:       主控器进行应答信号(可以是应答或非应答信号,由位参数a决定)
  79. ********************************************************************/
  80. void Ack_I2C(bit a)         //接收应答信号函数;a是定义的一个位变量,来暂存应答状态。
  81. {

  82.     if(a==0)
  83.         SDA=0;              //在此发出应答或非应答信号
  84.     else
  85.         SDA=1;
  86.     SCL=1;
  87.     SCL=0;                  //清时钟线,钳住I2C总线以便继续接收
  88. }


  89. /*******************************************************************
  90.                   字节数据发送函数               
  91. 函数原型:     void   SendByte(uchar c);
  92. 功能:      将数据c发送出去,可以是地址,也可以是数据,发完后等待应答,并对
  93.            此状态位进行操作.(不应答或非应答都使ack=0)
  94.            ack=1        发送数据正常,
  95.            ack=0        被控器无应答或损坏。
  96. ********************************************************************/
  97. void SendByte(uchar c)                      //向I2C总线写入一个字节的数据函数
  98. {
  99.     uchar BitCnt;
  100.    
  101.     for(BitCnt=0;BitCnt<8;BitCnt++)         //要传送的数据长度为8位
  102.     {
  103.         if((c<<BitCnt)&0x80)
  104.             SDA=1;                          //判断发送位
  105.         else
  106.             SDA=0;               
  107.           SCL=1;                            //置时钟线为高,通知被控器开始接收数据位
  108.           SCL=0;
  109.     }
  110.    
  111.     SDA=1;                                  //8位发送完后释放数据线,准备接收应答位
  112.     SCL=1;
  113.     if(SDA==1)
  114.         ack=0;   
  115.     else
  116.         ack=1;                              //判断是否接收到应答信号
  117.     SCL=0;
  118. }


  119. /*******************************************************************
  120.                   字节数据接收函数               
  121. 函数原型:     uchar   RcvByte();
  122. 功能:      用来接收从器件传来的数据,并判断总线错误(不发应答信号),
  123.            发完后请用应答函数应答从机。  
  124. ********************************************************************/
  125. uchar RcvByte()    //字节数据接收函数
  126. {
  127.    uchar retc;
  128.    uchar BitCnt;

  129.    retc=0;
  130.    SDA=1;                           //置数据线为输入方式
  131.    for(BitCnt=0;BitCnt<8;BitCnt++)
  132.    {
  133.         SCL=0;                      //置时钟线为低,准备接收数据位
  134.         SCL=1;                      //置时钟线为高使数据线上数据有效
  135.         retc=retc<<1;
  136.         if(SDA==1)
  137.             retc=retc+1;            //读数据位,接收的数据位放入retc中
  138.    }
  139.    SCL=0;
  140.    return(retc);
  141. }




  142. /***********将一个字节写入DS3231指定地址***********/
  143. uchar write_byte(uchar addr, uchar write_data)
  144. {
  145.     Start_I2C();
  146.     SendByte(0xD0);
  147.     if (ack == 0)
  148.         return 0;
  149.    
  150.     SendByte(addr);   
  151.     if (ack == 0)
  152.         return 0;
  153.    
  154.     SendByte(write_data);
  155.     if (ack == 0)
  156.         return 0;
  157.    
  158.     Stop_I2C();
  159.     return 1;
  160. }
  161. /************从DS3231指定地址读一个字节************/
  162. uchar read_byte(uchar addr)
  163. {
  164.     uchar read_data;
  165.     Start_I2C();
  166.     SendByte(0xD0);
  167.     if(ack==0)
  168.         return(0);
  169.    
  170.     SendByte(addr);
  171.     if(ack==0)
  172.         return(0);

  173.     Start_I2C();
  174.     SendByte(0xD1);
  175.     if(ack==0)
  176.         return(0);
  177.     read_data = RcvByte();
  178.     Ack_I2C(1);
  179.     Stop_I2C();
  180. return read_data;
  181. }


  182. /**************************设置时间******************************************/

  183. void Set_Time()
  184. {
  185.     uchar i;
  186.     uchar ucAddr=0x00;      //秒的地址
  187.     for(i=0;i<7;i++)
  188.     {
  189.        write_byte(ucAddr,tabtime[i]);//从秒开始连续写入秒分时星期日月年
  190.        ucAddr+=1;
  191. }
  192. }



  193. /*********************读取时间**********************/
  194. void get_time(void)
  195. {
  196.     hour=read_byte(0x02)/16*10+read_byte(0x02)%16;
  197. minute=read_byte(0x01)/16*10+read_byte(0x01)%16;    //因只显示时、分,故可只读取时、分
  198.     year=read_byte(0x06)/16*10+read_byte(0x06)%16;

  199. /*
  200.     uchar i;
  201. uchar ucCurtime[7];
  202. uchar ucAddr = 0x00;     //秒地址
  203. for(i=0;i<7;i++)
  204.         {ucCurtime[i]=0;}

  205. for(i=0; i<7; i++)
  206. {
  207.   ucCurtime[i] = read_byte(ucAddr);  //格式为: 从秒地址开始连续读取,秒分时星期日月年。  
  208.   ucAddr += 1;
  209. }
  210. year=ucCurtime[6]/16*10+ucCurtime[6]%16;
  211. month=ucCurtime[5]/16*10+ucCurtime[5]%16;
  212. day=ucCurtime[4]/16*10+ucCurtime[4]%16;
  213. week=ucCurtime[3]/16*10+ucCurtime[3]%16;
  214. hour=ucCurtime[2]/16*10+ucCurtime[2]%16;
  215. minute=ucCurtime[1]/16*10+ucCurtime[1]%16;
  216. second=ucCurtime[0]/16*10+ucCurtime[0]%16;
  217. */
  218. }


  219. /*********************读取温度**********************/
  220. void get_Temperature()
  221. {
  222.     TtempH=read_byte(0X11);   //读温度高字节
  223. //因数码管位数只有四位,故温度的小数部分不显示,可以不用读温度低字节
  224. //TtempL=read_byte(0x12);    //读温度低字节
  225. //TtempL=(TtempL>>6)*25;//将BIT7,BIT6的数据移入BIT1,BIT0位;分辨率数值扩大100倍便于整数运算
  226.    
  227. }
  228. ………………
复制代码

完整程序代码

原代码.rar (4.87 KB, 下载次数: 165)

评分

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

查看全部评分

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

使用道具 举报

沙发
ID:456690 发表于 2018-12-27 18:57 | 只看该作者
学习了好帖
回复

使用道具 举报

板凳
ID:456769 发表于 2018-12-27 20:19 | 只看该作者
学习学习
回复

使用道具 举报

地板
ID:449525 发表于 2018-12-28 09:19 | 只看该作者
做的精致啊,你连洞洞板都省了,厉害
回复

使用道具 举报

5#
ID:220779 发表于 2018-12-28 10:36 | 只看该作者
ds1302匹配电容搭配好了,再加上高精度晶振,可以做到3天误差1秒,做过好多这样的表了
回复

使用道具 举报

6#
ID:140489 发表于 2018-12-28 10:49 | 只看该作者
DS3231供电要3.3V,走时误差才小,5V供电误差较大
回复

使用道具 举报

7#
ID:456116 发表于 2019-1-4 17:03 | 只看该作者
lids 发表于 2018-12-28 10:49
DS3231供电要3.3V,走时误差才小,5V供电误差较大

谢谢了,等我试试
回复

使用道具 举报

8#
ID:229361 发表于 2019-1-21 13:36 | 只看该作者
谢谢楼主的分享
回复

使用道具 举报

9#
ID:282850 发表于 2019-1-21 14:32 | 只看该作者
动手能力可以,关键是“早晨上班,等红灯时发现一女司机抱着狗儿开车”...《交通法》抱着狗狗开车罚款1元,扣12分。    狗狗
回复

使用道具 举报

10#
ID:211167 发表于 2019-1-21 15:13 | 只看该作者
这个厉害了
回复

使用道具 举报

11#
ID:35873 发表于 2019-1-21 20:29 | 只看该作者
这个真不错  学习下
回复

使用道具 举报

12#
ID:116551 发表于 2019-3-1 22:37 | 只看该作者
楼主,想问一下,你的资料里是DS3231的程序还是DS1302的程序???还望麻烦回一下,谢谢!!!
回复

使用道具 举报

13#
ID:333807 发表于 2019-4-4 10:07 | 只看该作者
V这个真不错  学习下
回复

使用道具 举报

14#
ID:266095 发表于 2019-4-4 12:08 | 只看该作者
焊的用心
回复

使用道具 举报

15#
ID:608007 发表于 2020-3-28 12:24 | 只看该作者
感谢楼主的资料 已经做成啦,我用共阳数码管,程序稍微修改了一下,时间能正常显示。但温度只能显示正的温度是正常,到负温度是就显示不正常啦,望楼主指点迷津
回复

使用道具 举报

16#
ID:716703 发表于 2020-3-28 15:24 | 只看该作者
f556 发表于 2019-1-21 14:32
动手能力可以,关键是“早晨上班,等红灯时发现一女司机抱着狗儿开车”...《交通法》抱着狗狗开车罚 ...

罚款一元??
回复

使用道具 举报

17#
ID:685070 发表于 2020-3-29 09:08 | 只看该作者

ds1302做了个时钟一天快70s左右,目前很郁闷
回复

使用道具 举报

18#
ID:403593 发表于 2020-3-29 20:42 | 只看该作者
要是想省电的话,可以这样做:单片机外部中断接一个按键,单片机上电就进入掉电模式,然后按下按键唤醒,点亮LED轮流显示温度和时间,5秒到10秒以后,再自动进入掉电模式。这样下来估计三节5南孚用一个月应该问题不大。
回复

使用道具 举报

19#
ID:619259 发表于 2020-3-30 18:44 | 只看该作者
光敏作什么用途?
回复

使用道具 举报

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

本版积分规则

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

Powered by 单片机教程网

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