找回密码
 立即注册

QQ登录

只需一步,快速开始

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

51单片机+DS1302+DS18B20制作(程序开源)

  [复制链接]
跳转到指定楼层
楼主
由于本程序使用了STC12C5A60S2单片机,最好不要使用太高的晶振,不然DS18B20延时部分太难调试(搞不好会显示00.0度),一般12M以下相对好些.

制作出来的实物图如下:


单片机源程序如下:
  1. //******************************************************************************
  2. //LCD12864行地址地址定义                                          *
  3. //第一行地址:80H 81H 82H 83H 84H 85H 86H 87H          *
  4. //第二行地址:90H 91H 92H 93H 94H 95H 96H 97H          *
  5. //第三行地址:88H 89H 8AH 8BH 8CH 8DH 8EH 8FH          *
  6. //第四行地址:98H 99H 9AH 9BH 9CH 9DH 9EH 9FH          *
  7. //程序说明:本程序为带有字库汉字显示的12864液晶显示器源程序
  8. //****************************************************************
  9. //#include<stc12c5a60s2.h>表示头文件在keil5软件安装目录(根目录)下,编译时软件到安装目录找头文件。
  10. //#include"stc12c5a60s2.h"表示头文件在当前的工程目录下,如果找不到头文件再到安装目录的根目录找。
  11. //****************************************************************
  12. #include<stc12c5a60s2.h>           //载入STC12C5A60S2头文件
  13. #include<intrins.h>                               //用到这个头文件表示你可以在程序中调用单片机中库文件中的函数
  14. #define uchar unsigned char            //用Uchar代替unsigned char
  15. #define uint  unsigned int         //用uint代替unsigned int  
  16. //****************************************************************
  17. //定义LCD12864的数据线和相关函数
  18. //****************************************************************  
  19. sbit   LCD_RS=P2^7;                  //模式位,低电平输入指令,高电平输入数据
  20. sbit   LCD_RW=P2^6;                  //读写位,低电平读,高电平写
  21. sbit   LCD_E =P2^5;                  //LCD12864使能位,低电平无效,高电平使能
  22. #define Busy 0x80
  23. #define LCD_Data P0                //LCD12864的8位数据总线,单片机的P0端口
  24. void   WriteDataLCD(unsigned char WDLCD);          //给LCD12864写数据
  25. void   WriteCommandLCD(unsigned char WCLCD);       //给LCD12864写指令
  26. void   LCDInit(void);                              //LCD12864初始化
  27. void   LCDClear(void);                             //LCD12864清屏
  28. void   CheckBusy(void);                            //忙检测
  29. void   LCDSendWord(unsigned char *p);              //向LCD发送一个字符串
  30. void   LCDTestWord(bit i,unsigned char word);
  31. //****************************************************************
  32. //定义时间芯片DS1302的数据线及相关函数
  33. //****************************************************************
  34. void   DisplaySec(void);                           //在LCD上显示秒钟
  35. void   DisplayMin(void);                           //在LCD上显示分钟
  36. void   DisplayHour(void);                          //在LCD上显示小时
  37. unsigned char sec,min,hour;                      //秒,分,小时
  38. sbit   DS1302_CLK=P2^0;                            //DS1302的时钟信号线   
  39. sbit   DS1302_IO =P2^1;                            //DS1302的数据端口线
  40. sbit   DS1302_RST=P2^2;                            //DS1302的片选信号线
  41. void   WriteDs1302byte(unsigned char temp);                    //给DS1302写一个字节
  42. void   WriteDs1302(unsigned char address,unsigned char dat);  //给DS1302写入时间,先确定地址,再确定要写入的数据
  43. unsigned char ReadDs1302(unsigned char address);           //读取DS1302的数据
  44. void   InitDS1302();
  45. //****************************************************************
  46. //定义温度传感器DS18B20的数据线和相关函数
  47. //****************************************************************
  48. sbit   DS18B20=P1^2;                        //DS18B20的数据线
  49. int    temp;
  50. void   DS18B20Init(void);                   //DS18B20初始化函数
  51. int    GetTemp(void);
  52. void   TempWriteByte(unsigned char dat);
  53. unsigned char TempRead(void);
  54. bit    TempReadBit(void);   
  55. void   TempChange(void);
  56. //****************************************************************
  57. //定义延时部分相关函数
  58. //****************************************************************
  59. void   delayb(unsigned int count);
  60. void   DelayMs(unsigned int a);
  61. void   Delay(unsigned char num);
  62. //****************************************************************
  63. //定义开关按键的端口
  64. //****************************************************************
  65. sbit   Key1    =P1^4;       //按键功能:设置(本程序未使用按键)
  66. sbit   Key2    =P1^5;       //按键功能:确认(本程序未使用按键)
  67. sbit   Key3    =P1^6;       //按键功能:加        (本程序未使用按键)
  68. sbit   Key4    =P1^7;       //按键功能:左移(本程序未使用按键)
  69. void   Key(void);
  70. //****************************************************************
  71. //定义提示音乐部分相关函数
  72. //****************************************************************
  73. #define Fosc 6000000      //定义晶振频率24000000HZ
  74. sbit    Speaker=P3^7;         //定义输出管脚

  75. void SpeakerDiDi(void)
  76. {
  77. unsigned char i;  //整点报时延时
  78. for(i=0;i<3;i++)
  79. {
  80.   Speaker=0;
  81.   DelayMs(800);
  82.   Speaker=1;
  83.   DelayMs(800);
  84. }
  85. DelayMs(4000);
  86. for(i=0;i<3;i++)
  87. {
  88.   Speaker=0;
  89.   DelayMs(800);
  90.   Speaker=1;
  91.   DelayMs(800);
  92. }
  93. DelayMs(4000);
  94. for(i=0;i<2;i++)
  95. {
  96.   Speaker=0;
  97.   DelayMs(4000);
  98.   Speaker=1;
  99.   DelayMs(1000);
  100. }
  101. }


  102. /******************忙检测函数***************/
  103. void CheckBusy(void)
  104. {
  105. LCD_RS=0;
  106. LCD_RW=1;
  107. LCD_E=1;
  108. LCD_Data=0xff;
  109. while((LCD_Data&0x80)==0x80);
  110. LCD_E=0;
  111. }

  112. /**********************给LCD写入数据*****************/
  113. void WriteDataLCD(unsigned char WDLCD)
  114. {
  115.   CheckBusy();               //检测忙
  116.   LCD_RS = 1;                //RS为高电平,DB7----DB0为数据      
  117.   LCD_RW = 0;                //RW为低电平,E从高电平到低电平,则是把DB7----DB0的数据写到DR或者IR
  118.   LCD_E = 1;
  119.   LCD_Data = WDLCD;          //传送数据WDLCD
  120.   Delay(40);
  121.   LCD_E = 0;                 //E从 高电平 到 低电平
  122.   Delay(40);
  123. }

  124. /******************给LCD写入指令**********************/
  125. void WriteCommandLCD(unsigned char WCLCD) //BuysC为0时忽略忙检测
  126. {
  127.   CheckBusy();                //检测忙
  128.   LCD_RS = 0;                 //RS为低,DB7----DB0为指令
  129.   LCD_RW = 0;                 //RW为低,E从高电平到低电平,则是把DB7----DB0的数据写到DR或者IR
  130.   LCD_E = 1;
  131.   LCD_Data = WCLCD;           //传送数据
  132.   Delay(40);
  133.   LCD_E = 0;                  //E从 高电平到低电平
  134.   Delay(40);
  135. }

  136. /***************LCD初始化******************/

  137. void LCDInit(void)
  138. {
  139.   WriteCommandLCD(0x30);     //显示模式设置,开始要求每次检测忙信号
  140.   WriteCommandLCD(0x01);     //显示清屏
  141.   WriteCommandLCD(0x06);     // 显示光标移动设置
  142.   WriteCommandLCD(0x0C);     // 显示开,无游标,不反白
  143. }

  144. /********************清屏***************************/
  145. void LCDClear(void)
  146. {
  147.   WriteCommandLCD(0x01);     //显示清屏
  148.   WriteCommandLCD(0x34);     // 显示光标移动设置
  149.   WriteCommandLCD(0x30);     // 显示开及光标设置
  150. }

  151. void LCDSendWord(unsigned char *p)         //向LCD发送一个字符串,
  152. {
  153. while(*p>0)                            //比如void LCDSendWord('你好');就是让LCD显示"你好"
  154. {
  155.   WriteDataLCD(*p);
  156.   p++;
  157. }
  158. }
  159.   
  160. /************写数据或者指令***************/
  161. void LCDTestWord(bit i,unsigned char word)
  162. {
  163. if(i==0)
  164. {
  165.   WriteCommandLCD(word);             //i=0;则写入指令
  166. }
  167. else
  168. {
  169.   WriteDataLCD(word);                //i=1;则写入数据  
  170. }
  171. }

  172. void Displayqt(void)
  173. {
  174. LCDTestWord(0,0x80);
  175. LCDSendWord("如果你还在!");
  176. }

  177. void DisplayHour(void)                 //往LCD上填写小时数据
  178. {
  179. hour=ReadDs1302(0x85);
  180. LCDTestWord(0,0x98);
  181. LCDTestWord(1,(hour/16)+0x30);
  182. LCDTestWord(1,hour%16+0x30);
  183. }

  184. void DisplayMin(void)                  //往LCD上填写分钟数据   
  185. {
  186. min=ReadDs1302(0x83);
  187. LCDTestWord(0,0x99);
  188. LCDTestWord(1,0x3a);
  189. LCDTestWord(1,(min/16)+0x30);
  190. LCDTestWord(1,min%16+0x30);
  191. LCDTestWord(1,0x3a);
  192. }

  193. void DisplaySec(void)                  //往LCD上填写秒钟数据
  194. {
  195. unsigned char i=0;
  196. unsigned int a=0,b=0,c=0;
  197. sec=ReadDs1302(0x81);
  198. LCDTestWord(0,0x9b);
  199. LCDTestWord(1,(sec/16)+0x30);
  200. LCDTestWord(1,sec%16+0x30);
  201. }

  202. void DisplayTemp(void)
  203. {
  204. unsigned int i;
  205. unsigned char a,b,c;
  206. WriteCommandLCD(0x9c);
  207. LCDTestWord(0,0x9d);
  208. TempChange();
  209. i=GetTemp();
  210. a=i/100;
  211. LCDTestWord(1,a+0x30);
  212. b=i/10-a*10;
  213. LCDTestWord(1,b+0x30);
  214. LCDTestWord(1,0x2e);
  215. c=i-a*100-b*10;
  216. LCDTestWord(1,c+0x30);
  217. LCDSendWord("度");
  218. }

  219. //****************************************************************
  220. //DS1302部分子程序
  221. //****************************************************************
  222. /*********************写入操作*********************/
  223. void WriteDs1302Byte(unsigned  char temp)        
  224. {
  225.     unsigned char i;
  226.     for (i=0;i<8;i++)               //循环8次 写入数据
  227.     {
  228.         DS1302_CLK=0;
  229.         DS1302_IO=temp&0x01;      //每次传输低字节
  230.         temp>>=1;                //右移一位
  231.         DS1302_CLK=1;
  232.    }
  233. }

  234. /*********************写入数据*******************/
  235. void WriteDs1302( unsigned char address,unsigned char dat )     //先写地址,再写数据
  236. {
  237.   DS1302_RST=0;
  238. _nop_();
  239.   DS1302_CLK=0;
  240. _nop_();
  241.   DS1302_RST=1;
  242.     _nop_();                             //启动
  243.   WriteDs1302Byte(address);              //发送地址
  244.   WriteDs1302Byte(dat);                  //发送数据
  245.   DS1302_RST=0;                          //恢复
  246. }

  247. /************************************************/
  248. unsigned char ReadDs1302(unsigned char address)        //先送地址,再读数据
  249. {
  250.   unsigned char i,temp=0x00;
  251.   DS1302_RST=0;
  252. _nop_();
  253.   DS1302_CLK=0;
  254. _nop_();
  255.   DS1302_RST=1;
  256. _nop_();
  257.   WriteDs1302Byte(address);         //送地址函数
  258.   for (i=0;i<8;i++)               //循环8次 读取数据
  259.   {
  260.   DS1302_CLK=1;
  261.   _nop_();
  262.    if(DS1302_IO)
  263.    temp|=0x80;               //每次传输低字节
  264.   DS1302_CLK=0;
  265.   temp>>=1;               //右移一位
  266. }
  267.   DS1302_RST=0;
  268. _nop_();  
  269. DS1302_CLK=1;
  270. DS1302_IO=0;
  271. return (temp);              //返回
  272. }
  273. /*****************DS1302初始化********************/
  274. void InitDS1302()                        //DS1302中秒,分,时,日期,月份,星期,年的地址分别是0x80,0x82,0x84,0x86,0x88,0x8a,0x8c
  275. {                                        //初始化写入的时间是2010年4月1日15点整,星期六
  276. WriteDs1302(0x8e,0x00);                 //控制命令,WP位为0,允许写操作  控制位地址是0x8e
  277. DelayMs(5);                           
  278. WriteDs1302(0x84,0x00);                 //写入小时 20点
  279. DelayMs(5);
  280. WriteDs1302(0x82,0x00);                 //写入分钟 03分
  281. DelayMs(5);
  282. WriteDs1302(0x80,0x00);                 //写入秒钟 00秒
  283. DelayMs(5);                                 
  284. WriteDs1302(0x8e,0x80);                 //控制命令,WP为1,禁止写操作
  285. }
  286. //****************************************************************
  287. //DS18B20部分子程序
  288. //****************************************************************
  289. void DS18B20Init(void)          //DS18B20初始化
  290. {
  291. unsigned int i;               
  292. DS18B20=0;
  293. i=103*8;
  294. while(i>0)i--;
  295. DS18B20=1;
  296. i=103;
  297. while(i>0)i--;
  298. }

  299. bit TempReadBit(void)          // 读一位
  300. {
  301. unsigned int i;
  302.     bit dat;
  303.     DS18B20=0;i++;             //小延时一下
  304.     DS18B20=1;i++;i++;
  305.     dat=DS18B20;
  306.     i=32;while(i>0)i--;
  307.     return (dat);
  308. }

  309. unsigned char TempRead(void)   //读一个字节
  310. {
  311. unsigned char i,j,dat;
  312.     dat=0;
  313.     for(i=1;i<=8;i++)
  314.     {
  315.      j=TempReadBit();
  316.      dat=(j<<7)|(dat>>1); //读出的数据最低位在最前面,这样刚好一个字节在DAT里
  317.     }
  318.     return(dat);             //将一个字节数据返回
  319. }

  320. void TempWriteByte(unsigned char dat)  
  321. {                           //写一个字节到DS18B20里
  322. unsigned int i;
  323.     unsigned char j;
  324.     bit testb;
  325.     for(j=1;j<=8;j++)
  326.     {
  327.      testb=dat&0x01;
  328.      dat=dat>>1;
  329.      if(testb)          // 写1部分
  330.      {
  331.          DS18B20=0;
  332.          i++;i++;
  333.          DS18B20=1;
  334.          i=32;while(i>0)i--;
  335.         }
  336.      else
  337.      {
  338.          DS18B20=0;       //写0部分
  339.          i=32;while(i>0)i--;
  340.          DS18B20=1;
  341.          i++;i++;
  342.         }
  343.     }
  344. }

  345. void TempChange(void)  //发送温度转换命令
  346. {
  347. DS18B20Init();             //初始化DS18B20
  348.     delayb(8);             //延时
  349.     TempWriteByte(0xcc);  // 跳过序列号命令
  350.     TempWriteByte(0x44);  //发送温度转换命令
  351. }

  352. int GetTemp()               //获得温度
  353. {
  354. float tt;
  355.     unsigned char a,b;
  356.     DS18B20Init();
  357.     delayb(1);
  358.     TempWriteByte(0xcc);
  359.     TempWriteByte(0xbe);    //发送读取数据命令
  360.     a=TempRead();           //连续读两个字节数据
  361.     b=TempRead();
  362.     temp=b;
  363.     temp<<=8;            
  364.     temp=temp|a;            //两字节合成一个整型变量。
  365.     tt=temp*0.0625;         //得到真实十进制温度值,因为DS18B20 可以精确到0.0625度,所以读回数据的最低位代表的是0.0625度。                     
  366.     temp=tt*10+0.5;         //放大十倍,这样做的目的将小数点后第一位 也转换为可显示数字,同时进行一个四舍五入操作。                          
  367.     return temp;            //返回温度值
  368. }
  369. /****************************************************************************/
  370. void UpDate(void)
  371. {
  372. DS18B20=1;
  373. DisplayHour();             //显示时
  374. DisplayMin();              //显示分
  375. DisplaySec();              //显示秒
  376. DisplayTemp();                         //显示温度
  377. }

  378. //****************************************************************
  379. //延时部分子程序
  380. //****************************************************************
  381. void delayb(unsigned int count)   //delay
  382. {
  383.     unsigned char i;
  384.     while(count)
  385.     {
  386.        i=200;
  387.        while(i>0)
  388.        i--;
  389.        count--;
  390.     }
  391. }

  392. void DelayMs(unsigned int a)        //延时 1MS/次
  393. {
  394. unsigned char i;
  395. while(--a!=0)
  396. {
  397.   for(i=0;i<125;i++)
  398.   ;
  399. }
  400. }

  401. void Delay(unsigned char num)               
  402. {
  403. while(num--)
  404. ;
  405. }                                          


  406. void main()
  407. {
  408. LCDInit();
  409. LCDClear();
  410. InitDS1302();
  411. while(1)                        
  412. {
  413.   Displayqt();
  414.   UpDate();
  415.   }
  416. }
复制代码




评分

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

查看全部评分

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

使用道具 举报

沙发
ID:61140 发表于 2022-5-8 15:44 | 只看该作者
本程序已实测无BUG,若温度不显示,要按你的晶振来调DS18B20读写部分的延时,本程序使用STC12C5A60S2单片机和6M晶振实测
回复

使用道具 举报

板凳
ID:61140 发表于 2022-6-3 04:06 | 只看该作者
无事再来顶一下
回复

使用道具 举报

地板
ID:1027942 发表于 2022-9-19 21:31 | 只看该作者
我用串口显示秒,部分出现了乱码,是什么原因,开始时间为0秒
unsigned int ReadTime()      //接收并且转换为十进制
{
        dat = ReadDs1302(0x81) ;
       
        damp = (int)dat / 16*10 + (int)dat %16;
       
        return damp;
}
void main()
{
                uart_init();       
                SetTime();       //设置开始时间

        while(1)
        {               
                sec = ReadTime();
               
                printf("%d        ",sec);
                Delay100ms(10);
        }       
}
例如: 1        0        3        0        1        2        7        0        1        0        1        0        3        0        1        2        7        8        9        0        1        0        3        0        1        2        7        0        1        10        11        8        13        8        9        10        17        18        19        0        1        0       
回复

使用道具 举报

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

本版积分规则

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

Powered by 单片机教程网

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