• 基于51单片机万年历设计—显示温度农历


    基于51单片机万年历设计

    (仿真+程序+原理图+设计报告)

    功能介绍

    具体功能:

    本系统采用单片机+DS1302时钟芯片+LCD1602液晶+18b20温度传感器+按键+蜂鸣器设计而成。

    1.可以显示年月日、时分秒、星期、温度值。

    2.DS18B20测温;

    3.按键可设置时间、闹钟,切换农历查看;

    ​演示视频:

    基于51单片机万年历设计—显示温度农历 

    添加图片注释,不超过 140 字(可选)

    程序

    1. #include //调用单片机头文件
    2. /***公众号:木子单片机****/
    3. #define uchar unsigned char //无符号字符型 宏定义 变量范围0~255
    4. #define uint unsigned int //无符号整型 宏定义 变量范围0~65535
    5. #include "eeprom52.h"
    6. #include "nongli.h"
    7. bit flag_200ms ;
    8. bit flag_100ms ;
    9. sbit beep = P3^7; //蜂鸣器定义
    10. bit flag_beep_en;
    11. uint clock_value; //用作闹钟用的
    12. sbit dq = P3^1; //18b20 IO口的定义
    13. uint temperature ; //温度变量
    14. uchar flag_nl; //农历 阳历显示标志位
    15. uchar menu_1,menu_2;
    16. uchar key_time,flag_value; //用做连加的中间变量
    17. bit key_500ms ;
    18. uchar n_nian,n_yue,n_ri; //农历显示的函数
    19. #include "ds1302.h"
    20. #include "lcd1602.h"
    21. /******************把数据保存到单片机内部eeprom中******************/
    22. void write_eeprom()
    23. {
    24. SectorErase(0x2000);
    25. byte_write(0x2000, fen1);
    26. byte_write(0x2001, shi1);
    27. byte_write(0x2002, open1);
    28. byte_write(0x2058, a_a);
    29. }
    30. /******************把数据从单片机内部eeprom中读出来*****************/
    31. void read_eeprom()
    32. {
    33. fen1 = byte_read(0x2000);
    34. shi1 = byte_read(0x2001);
    35. open1 = byte_read(0x2002);
    36. a_a = byte_read(0x2058);
    37. }
    38. /**************开机自检eeprom初始化*****************/
    39. void init_eeprom()
    40. {
    41. read_eeprom(); //先读
    42. if(a_a != 1) //新的单片机初始单片机内问eeprom
    43. {
    44. fen1 = 3;
    45. shi1 = 8;
    46. open1 = 1;
    47. a_a = 1;
    48. write_eeprom(); //保存数据
    49. }
    50. }
    51. /***********************18b20初始化函数*****************************/
    52. void init_18b20()
    53. {
    54. bit q;
    55. dq = 1; //把总线拿高
    56. delay_uint(1); //15us
    57. dq = 0; //给复位脉冲
    58. delay_uint(80); //750us
    59. dq = 1; //把总线拿高 等待
    60. delay_uint(10); //110us
    61. q = dq; //读取18b20初始化信号
    62. delay_uint(20); //200us
    63. dq = 1; //把总线拿高 释放总线
    64. }
    65. /*************写18b20内的数据***************/
    66. void write_18b20(uchar dat)
    67. {
    68. uchar i;
    69. for(i=0;i<8;i++)
    70. { //写数据是低位开始
    71. dq = 0; //把总线拿低写时间隙开始
    72. dq = dat & 0x01; //向18b20总线写数据了
    73. delay_uint(5); // 60us
    74. dq = 1; //释放总线
    75. dat >>= 1;
    76. }
    77. }
    78. /*************读取18b20内的数据***************/
    79. uchar read_18b20()
    80. {
    81. uchar i,value;
    82. for(i=0;i<8;i++)
    83. {
    84. dq = 0; //把总线拿低读时间隙开始
    85. value >>= 1; //读数据是低位开始
    86. dq = 1; //释放总线
    87. if(dq == 1) //开始读写数据
    88. value |= 0x80;
    89. delay_uint(5); //60us 读一个时间隙最少要保持60us的时间
    90. }
    91. return value; //返回数据
    92. }
    93. /*************读取温度的值 读出来的是小数***************/
    94. uint read_temp()
    95. {
    96. uint value;
    97. uchar low; //在读取温度的时候如果中断的太频繁了,就应该把中断给关了,否则会影响到18b20的时序
    98. init_18b20(); //初始化18b20
    99. write_18b20(0xcc); //跳过64位ROM
    100. write_18b20(0x44); //启动一次温度转换命令
    101. delay_uint(50); //500us
    102. init_18b20(); //初始化18b20
    103. write_18b20(0xcc); //跳过64位ROM
    104. write_18b20(0xbe); //发出读取暂存器命令
    105. EA = 0;
    106. low = read_18b20(); //读温度低字节
    107. value = read_18b20(); //读温度高字节
    108. EA = 1;
    109. value <<= 8; //把温度的高位左移8位
    110. value |= low; //把读出的温度低位放到value的低八位中
    111. value *= 0.625; //转换到温度值 小数
    112. return value; //返回读出的温度 带小数
    113. }
    114. /******************1ms 延时函数*******************/
    115. void delay_1ms(uint q)
    116. {
    117. uint i,j;
    118. for(i=0;i
    119. for(j=0;j<120;j++);
    120. }
    121. /******************写星期函数*******************/
    122. void write_week(uchar hang,uchar add,uchar week)//写星期函数
    123. {
    124. if(hang==1)
    125. write_com(0x80+add);
    126. else
    127. write_com(0x80+0x40+add);
    128. switch(week)
    129. {
    130. case 1:write_data('M');//星期数为1时,显示
    131. write_data('O');
    132. write_data('N');
    133. break;
    134. case 2:write_data('T');//星期数据为2时显示
    135. write_data('U');
    136. write_data('E');
    137. break;
    138. case 3:write_data('W');//星期数据为3时显示
    139. write_data('E');
    140. write_data('D');
    141. break;
    142. case 4:write_data('T');//星期数据为4是显示
    143. write_data('H');
    144. write_data('U');
    145. break;
    146. case 5:write_data('F');//星期数据为5时显示
    147. write_data('R');
    148. write_data('I');
    149. break;
    150. case 6:write_data('S');//星期数据为6时显示
    151. write_data('T');
    152. write_data('A');
    153. break;
    154. case 0:write_data('S');//星期数据为7时显示
    155. write_data('U');
    156. write_data('N');
    157. break;
    158. }
    159. }
    160. /*************时钟显示***************/
    161. void init_1602_ds1302()
    162. {
    163. write_sfm2_ds1302(1,1,shi); //显示时
    164. write_sfm2_ds1302(1,4,fen); //显示分
    165. write_sfm2_ds1302(1,7,miao); //显示秒
    166. write_week(2,12,week);
    167. // write_sfm1(1,14,week); //显示星期
    168. write_sfm3_18B20(1,11,temperature); //显示温度
    169. if(flag_nl == 0) //显示阳历
    170. {
    171. write_sfm2_ds1302(2,2,nian); //显示年
    172. write_sfm2_ds1302(2,5,yue); //显示月
    173. write_sfm2_ds1302(2,8,ri); //显示日
    174. }
    175. else //显示农历
    176. {
    177. write_sfm2_ds1302(2,2,n_nian); //显示年
    178. write_sfm2_ds1302(2,5,n_yue); //显示月
    179. write_sfm2_ds1302(2,8,n_ri); //显示日
    180. }
    181. }
    182. /*************定时器0初始化程序***************/
    183. void init_time0()
    184. {
    185. EA = 1; //开总中断
    186. TMOD = 0X01; //定时器0、工作方式1
    187. ET0 = 1; //开定时器0中断
    188. TR0 = 1; //允许定时器0定时
    189. }
    190. /*************闹钟报警函数***************/
    191. void menu_dis()
    192. {
    193. static uchar mm,value;
    194. if(flag_100ms == 1) //100ms执行一次
    195. {
    196. flag_100ms = 0;
    197. if(open1 == 1) //如果闹钟打开
    198. {
    199. if((miao == 0) && (fen == fen1) && (shi == shi1))
    200. {
    201. flag_beep_en = 1; //有报警 打开蜂鸣器响的标志位
    202. }
    203. if(flag_beep_en == 1) //闹钟以被打开
    204. {
    205. clock_value++;
    206. if(clock_value <= 30)
    207. beep = ~beep; //蜂鸣器叫3秒
    208. else if(clock_value > 30)
    209. {
    210. beep = 1; //蜂鸣器停1秒
    211. if(clock_value > 40)
    212. {
    213. clock_value = 0;
    214. }
    215. }
    216. // 1 分钟后自动关闭闹钟
    217. value ++;
    218. if(value >= 10)
    219. {
    220. value = 0;
    221. mm++;
    222. if(mm >= 60)
    223. {
    224. mm = 0;
    225. flag_beep_en = 0;
    226. beep = 1;
    227. }
    228. }
    229. }
    230. }
    231. }
    232. }
    233. /********************独立按键程序*****************/
    234. uchar key_can; //按键值
    235. void key() //独立按键程序
    236. {
    237. static uchar key_new;
    238. key_can = 20; //按键值还原
    239. P3 |= 0x78; //对应的按键IO口输出为1
    240. if((P3 & 0x78) != 0x78) //按键按下
    241. {
    242. delay_1ms(1); //按键消抖动
    243. if(((P3 & 0x78) != 0x78) && (key_new == 1))
    244. { //确认是按键按下
    245. key_new = 0;
    246. switch(P3 & 0x78)
    247. {
    248. case 0x70: key_can = 4; break; //得到按键值
    249. case 0x68: key_can = 3; break; //得到按键值
    250. case 0x58: key_can = 2; break; //得到按键值
    251. case 0x38: key_can = 1; break; //得到按键值
    252. }
    253. // write_sfm2(1,0,key_can); //显示按键值
    254. }
    255. }
    256. else
    257. key_new = 1;
    258. }
    259. /**********************设置函数************************/
    260. void key_with()
    261. {
    262. if(key_can == 1) //设置键
    263. {
    264. menu_1++;
    265. if(menu_1 == 1) //设置时间
    266. {
    267. menu_2 = 1;
    268. write_string(1,0," : : W: ");
    269. write_string(2,0," 20 - - ");
    270. }
    271. if(menu_1 == 2) //设置闹钟
    272. {
    273. menu_2 = 1;
    274. write_string(1,0," set clock ");
    275. write_string(2,0," Y 00:00 ");
    276. }
    277. if(menu_1 > 2) //回到正常显示
    278. {
    279. menu_1 = 0;
    280. write_guanbiao(1,2,0); //关闭光标
    281. init_1602_dis_csf(); //初始化液晶显示
    282. }
    283. }
    284. if(key_can == 2) //选择键
    285. {
    286. flag_200ms = 1;
    287. if(menu_1 == 1) //设置时间
    288. {
    289. menu_2 ++;
    290. if(menu_2 > 7)
    291. menu_2 = 1;
    292. }
    293. if(menu_1 == 2) //设置闹钟
    294. {
    295. menu_2 ++;
    296. if(menu_2 > 3)
    297. menu_2 = 1;
    298. }
    299. }
    300. if(menu_1 == 1)
    301. {
    302. if(menu_2 == 1) //设置时
    303. {
    304. if(key_can == 3) //加
    305. {
    306. shi+=0x01;
    307. if((shi & 0x0f) >= 0x0a)
    308. shi = (shi & 0xf0) + 0x10;
    309. if(shi >= 0x24)
    310. shi = 0;
    311. }
    312. if(key_can == 4) //减
    313. {
    314. if(shi == 0x00)
    315. shi = 0x24;
    316. if((shi & 0x0f) == 0x00)
    317. shi = (shi | 0x0a) - 0x10;
    318. shi -- ;
    319. }
    320. }
    321. if(menu_2 == 2) //设置分
    322. {
    323. if(key_can == 3) //加
    324. {
    325. fen+=0x01;
    326. if((fen & 0x0f) >= 0x0a)
    327. fen = (fen & 0xf0) + 0x10;
    328. if(fen >= 0x60)
    329. fen = 0;
    330. }
    331. if(key_can == 4) //减
    332. {
    333. if(fen == 0x00)
    334. fen = 0x5a;
    335. if((fen & 0x0f) == 0x00)
    336. fen = (fen | 0x0a) - 0x10;
    337. fen -- ;
    338. }
    339. }
    340. if(menu_2 == 3) //设置秒
    341. {
    342. if(key_can == 3) //加
    343. {
    344. miao+=0x01;
    345. if((miao & 0x0f) >= 0x0a)
    346. miao = (miao & 0xf0) + 0x10;
    347. if(miao >= 0x60)
    348. miao = 0;
    349. }
    350. if(key_can == 4) //减
    351. {
    352. if(miao == 0x00)
    353. miao = 0x5a;
    354. if((miao & 0x0f) == 0x00)
    355. miao = (miao | 0x0a) - 0x10;
    356. miao -- ;
    357. }
    358. }
    359. if(menu_2 == 4) //设置星期
    360. {
    361. if(key_can == 3) //加
    362. {
    363. week+=0x01;
    364. if((week & 0x0f) >= 0x0a)
    365. week = (week & 0xf0) + 0x10;
    366. if(week >= 0x08)
    367. week = 1;
    368. }
    369. if(key_can == 4) //减
    370. {
    371. if(week == 0x01)
    372. week = 0x08;
    373. if((week & 0x0f) == 0x00)
    374. week = (week | 0x0a) - 0x10;
    375. week -- ;
    376. }
    377. }
    378. if(menu_2 == 5) //设置年
    379. {
    380. if(key_can == 3) //加
    381. {
    382. nian+=0x01;
    383. if((nian & 0x0f) >= 0x0a)
    384. nian = (nian & 0xf0) + 0x10;
    385. if(nian >= 0x9a)
    386. nian = 1;
    387. }
    388. if(key_can == 4) //减
    389. {
    390. if(nian == 0x01)
    391. nian = 0x9a;
    392. if((nian & 0x0f) == 0x00)
    393. nian = (nian | 0x0a) - 0x10;
    394. nian -- ;
    395. }
    396. }
    397. if(menu_2 == 6) //设置月
    398. {
    399. if(key_can == 3) //加
    400. {
    401. yue+=0x01;
    402. if((yue & 0x0f) >= 0x0a)
    403. yue = (yue & 0xf0) + 0x10;
    404. if(yue >= 0x13)
    405. yue = 1;
    406. }
    407. if(key_can == 4) //减
    408. {
    409. if(yue == 0x01)
    410. yue = 0x13;
    411. if((yue & 0x0f) == 0x00)
    412. yue = (yue | 0x0a) - 0x10;
    413. yue -- ;
    414. }
    415. }
    416. if(menu_2 == 7) //设置日
    417. {
    418. if(key_can == 3) //加
    419. {
    420. ri+=0x01;
    421. if((ri & 0x0f) >= 0x0a)
    422. ri = (ri & 0xf0) + 0x10;
    423. if(ri >= 0x32)
    424. ri = 0;
    425. }
    426. if(key_can == 4) //减
    427. {
    428. if(ri == 0x01)
    429. ri = 0x32;
    430. if((ri & 0x0f) == 0x00)
    431. ri = (ri | 0x0a) - 0x10;
    432. ri -- ;
    433. }
    434. }
    435. write_sfm2_ds1302(1,2,shi); //显示时
    436. write_sfm2_ds1302(1,5,fen); //显示分
    437. write_sfm2_ds1302(1,8,miao); //显示秒
    438. write_sfm1(1,14,week); //显示星期
    439. write_sfm2_ds1302(2,3,nian); //显示年
    440. write_sfm2_ds1302(2,6,yue); //显示月
    441. write_sfm2_ds1302(2,9,ri); //显示日
    442. switch(menu_2) // 光标显示
    443. {
    444. case 1: write_guanbiao(1,2,1); break;
    445. case 2: write_guanbiao(1,5,1); break;
    446. case 3: write_guanbiao(1,8,1); break;
    447. case 4: write_guanbiao(1,14,1); break;
    448. case 5: write_guanbiao(2,3,1); break;
    449. case 6: write_guanbiao(2,6,1); break;
    450. case 7: write_guanbiao(2,9,1); break;
    451. }
    452. write_time(); //把时间写进去
    453. }
    454. /***************设置闹钟*********************/
    455. if(menu_1 == 2)
    456. {
    457. if(menu_2 == 1) //设置闹钟开关
    458. {
    459. if(key_can == 3)
    460. {
    461. open1 = 1; //闹钟开
    462. }
    463. if(key_can == 4)
    464. {
    465. open1 = 0; //闹钟关
    466. }
    467. }
    468. if(menu_2 == 2) //设置闹钟时
    469. {
    470. if(key_can == 3) //加
    471. {
    472. shi1+=0x01;
    473. if((shi1 & 0x0f) >= 0x0a)
    474. shi1 = (shi1 & 0xf0) + 0x10;
    475. if(shi1 >= 0x24)
    476. shi1 = 0;
    477. }
    478. if(key_can == 4) //减
    479. {
    480. if(shi1 == 0x00)
    481. shi1 = 0x5a;
    482. if((shi1 & 0x0f) == 0x00)
    483. shi1 = (shi1 | 0x0a) - 0x10;
    484. shi1 -- ;
    485. }
    486. }
    487. if(menu_2 == 3) //设置秒
    488. {
    489. if(key_can == 3) //加
    490. {
    491. fen1+=0x01;
    492. if((fen1 & 0x0f) >= 0x0a)
    493. fen1 = (fen1 & 0xf0) + 0x10;
    494. if(fen1 >= 0x60)
    495. fen1 = 0;
    496. }
    497. if(key_can == 4) //减
    498. {
    499. if(fen1 == 0x00)
    500. fen1 = 0x5a;
    501. if((fen1 & 0x0f) == 0x00)
    502. fen1 = (fen1 | 0x0a) - 0x10;
    503. fen1 -- ;
    504. }
    505. }
    506. if(open1 == 1)
    507. write_string(2,4,"Y");
    508. else
    509. write_string(2,4,"N");
    510. write_sfm2_ds1302(2,7,shi1); //显示闹钟时
    511. write_sfm2_ds1302(2,10,fen1); //显示闹钟分
    512. switch(menu_2) // 光标显示
    513. {
    514. case 1: write_guanbiao(2,4,1); break;
    515. case 2: write_guanbiao(2,7,1); break;
    516. case 3: write_guanbiao(2,10,1); break;
    517. }
    518. write_eeprom(); //保存闹钟时间
    519. }
    520. }
    521. /*****************主函数********************/

    硬件设计

    使用元器件:

    单片机:STC89C52;

    (注意:单片机是通用的,无论51还是52、无论stc还是at都一样,引脚功能都一样。程序也是一样的。)

    蜂鸣器;电池座;

    直插电解电容;直插瓷片电容;

    LCD1602液晶显示器;

    DC电源插座;排针4-Pin;

    PNP 三极管;色环电阻;

    按键6X6X5MM;12MHZ晶振;

    自锁开关;DS18B20;

    导线:若干;

    添加图片注释,不超过 140 字(可选)

    流程图:

     

    设计资料

    01仿真图

    本设计使用proteus7.8和proteus8.9两个版本设计!具体如图!

    添加图片注释,不超过 140 字(可选)

    02原理图

    本系统原理图采用Altium Designer19设计,具体如图!

    添加图片注释,不超过 140 字(可选)

    03程序

    本设计使用软件keil5版本编程设计!具体如图!

    添加图片注释,不超过 140 字(可选)

    04设计报告

    一万字设计报告,具体如下!

    添加图片注释,不超过 140 字(可选)

    05设计资料

            资料获取请关注同名公众号,全部资料包括仿真源文件 、AD原理图、程序(含注释)、任务书、开题报告、设计报告、流程图、实物图、元件清单、实物演示视频等。具体内容如下,全网最全! !

     

    可以关注下方公众号!

    点赞分享一起学习成长。

  • 相关阅读:
    计算机科学的抽象
    数据脱敏的场景与价值【总结】
    pyqt5 + socket 实现客户端A经socket服务器中转后主动向客户端B发送文件
    LeetCode ❀ 35.搜索插入位置 / python实现二分法
    嵌入式Linux入门-手把手教你初始化SDRAM(附代码)
    SpringBoot3 Actuator使用如何以及自定义端点
    LeetCode(27)两数之和 II - 输入有序数组【双指针】【中等】
    金九银十!阿里面试官告诉你面试Java后端开发面试会被问到什么问题?面试稳了!
    微信、支付宝、携程等多款app任意文件读取漏洞
    使用华为eNSP组网试验⑸-访问控制
  • 原文地址:https://blog.csdn.net/2401_82402501/article/details/139728041