15.9 单片机电子时钟程序设计

这篇博客介绍了如何利用DS1302设计电子时钟程序,通过封装底层操作为DS1302.c文件,提供实时时间接口。文章提到了定义sTime结构体来存储日期时间,并用变量setIndex控制设置状态。此外,还增加了1602液晶屏光标功能,用于时间调整时的显示。主要功能如时间显示、增减和设置等实现在main.c中,以保持代码组织清晰。
摘要由CSDN通过智能技术生成
共用体除非必要,否则我们不推荐使用,枚举的用法比较简单,在本书 19 章的项目实践中有很好的示例,这节课我们先来练习一下结构体的使用。下边这个程序的功能是一个带日期的电子钟,相当于一个简易万年历了,并且加入了按键调时功能。学有余力的同学看到这里,不妨先不看我们提供的代码,自己写写试试。如果能够独立写一个按键可调的万年历程序,单片机可以说基本入门了。如果自己还不能够独立完成这个程序,那么还是老规矩,先抄并且理解,而后自己独立默写出来,并且要边默写边理解。

本例直接忽略了星期这项内容,通过上、下、左、右、回车、ESC 这 6 个按键可以调整时间。这也是一个具有综合练习性质的实例,虽然在功能实现上没有多少难度,但要进行的操作却比较多而且烦琐,同学们可以从中体会到把繁杂的功能实现分解为一步步函数操作的必要性以及方便灵活性。简单说一下这个程序的几个要点,方便大家阅读理解程序。
  1. 把 DS1302 的底层操作封装为一个 DS1302.c 文件,对上层应用提供基本的实时时间的操作接口,这个文件也是我们的又一个功能模块了,我们的积累也越来越多了。
  2. 定义一个结构体类型 sTime 用来封装日期时间的各个元素,又用该结构体定义了一个时间缓冲区变量 bufTime 来暂存从 DS1302 读出的时间和设置时间时的设定值。需要注意的是在其它文件中要使用这个结构体变量时,必须首先再声明一次 sTime 类型;
  3. 定义一个变量 setIndex 来控制当前是否处于设置时间的状态,以及设置时间的哪一位,该值为 0 就表示正常运行,1~12 分别代表可以修改日期时间的 12 个位;
  4. 由于这节课的程序功能要进行时间调整,用到了 1602 液晶的光标功能,添加了设置光标的函数,我们要改变哪一位的数字,就在 1602 对应位置上进行光标闪烁,所以 Lcd1602.c在之前文件的基础上添加了两个控制光标的函数;
  5. 时间的显示、增减、设置移位等上层功能函数都放在 main.c 中来实现,当按键需要这些函数时则在按键文件中做外部声明,这样做是为了避免一组功能函数分散在不同的文件内而使程序显得凌乱。
   
   
   
  1. /***************************DS1302.c 文件程序源代码*****************************/
  2. #include <reg52.h>
  3. sbit DS1302_CE = P1^7;
  4. sbit DS1302_CK = P3^5;
  5. sbit DS1302_IO = P3^4;
  6. struct sTime { //日期时间结构体定义
  7. unsigned int year; //年
  8. unsigned char mon; //月
  9. unsigned char day; //日
  10. unsigned char hour; //时
  11. unsigned char min; //分
  12. unsigned char sec; //秒
  13. unsigned char week; //星期
  14. };
  15. /* 发送一个字节到 DS1302 通信总线上 */
  16. void DS1302ByteWrite(unsigned char dat){
  17. unsigned char mask;
  18. for (mask=0x01; mask!=0; mask<<=1){ //低位在前,逐位移出
  19. if ((mask&dat) != 0){ //首先输出该位数据
  20. DS1302_IO = 1;
  21. }else{
  22. DS1302_IO = 0;
  23. }
  24. DS1302_CK = 1; //然后拉高时钟
  25. DS1302_CK = 0; //再拉低时钟,完成一个位的操作
  26. }
  27. DS1302_IO = 1; //最后确保释放 IO 引脚
  28. }
  29. /* 由 DS1302 通信总线上读取一个字节 */
  30. unsigned char DS1302ByteRead(){
  31. unsigned char mask;
  32. unsigned char dat = 0;
  33. for (mask=0x01; mask!=0; mask<<=1){ //低位在前,逐位读取
  34. if (DS1302_IO != 0){ //首先读取此时的 IO 引脚,并设置 dat 中的对应位
  35. dat |= mask;
  36. }
  37. DS1302_CK = 1; //然后拉高时钟
  38. DS1302_CK = 0; //再拉低时钟,完成一个位的操作
  39. }
  40. return dat; //最后返回读到的字节数据
  41. }
  42. /* 用单次写操作向某一寄存器写入一个字节,reg-寄存器地址,dat-待写入字节 */
  43. void DS1302SingleWrite(unsigned char reg, unsigned char dat){
  44. DS1302_CE = 1; //使能片选信号
  45. DS1302ByteWrite((reg<<1)|0x80); //发送写寄存器指令
  46. DS1302ByteWrite(dat); //写入字节数据
  47. DS1302_CE = 0; //除能片选信号
  48. }
  49. /* 用单次读操作从某一寄存器读取一个字节,reg-寄存器地址,返回值-读到的字节 */
  50. unsigned char DS1302SingleRead(unsigned char reg){
  51. unsigned char dat;
  52. DS1302_CE = 1; //使能片选信号
  53. DS1302ByteWrite((reg<<1)|0x81); //发送读寄存器指令
  54. dat = DS1302ByteRead(); //读取字节数据
  55. DS1302_CE = 0; //除能片选信号
  56. return dat;
  57. }
  58. /* 用突发模式连续写入 8 个寄存器数据,dat-待写入数据指针 */
  59. void DS1302BurstWrite(unsigned char *dat){
  60. unsigned char i;
  61. DS1302_CE = 1;
  62. DS1302ByteWrite(0xBE); //发送突发写寄存器指令
  63. for (i=0; i<8; i++){ //连续写入 8 字节数据
  64. DS1302ByteWrite(dat[i]);
  65. }
  66. DS1302_CE = 0;
  67. }
  68. /* 用突发模式连续读取 8 个寄存器的数据,dat-读取数据的接收指针 */
  69. void DS1302BurstRead(unsigned char *dat){
  70. unsigned char i;
  71. DS1302_CE = 1;
  72. DS1302ByteWrite(0xBF); //发送突发读寄存器指令
  73. for (i=0; i<8; i++){ //连续读取 8 个字节
  74. dat[i] = DS1302ByteRead();
  75. }
  76. DS1302_CE = 0;
  77. }
  78. /* 获取实时时间,即读取 DS1302 当前时间并转换为时间结构体格式 */
  79. void GetRealTime(struct sTime *time){
  80. unsigned char buf[8];
  81. DS1302BurstRead(buf);
  82. time->year = buf[6] + 0x2000;
  83. time->mon = buf[4];
  84. time->day = buf[3];
  85. time->hour = buf[2];
  86. time->min = buf[1];
  87. time->sec = buf[0];
  88. time
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值