系列文章目录

第一章 51单片机Proteus仿真(二)可调时钟


文章目录

  • 系列文章目录
  • 前言
  • 一、代码逻辑
  • 二、完整代码
  • 三、遇到问题
  • 四、遇到问题
  • 五、总结

前言

本文介绍51单片机Proteus仿真,实现可调时钟。
伪代码:
开机自动显示时间
按下第一个按键K1可以切换模式, 第一次按下K1,LCD1602显示刚才时间,可以进行更改操作。再次按下按键K1,显示修改后时间
按下第二个按键选择位(年月日),并且光标闪烁
第三个按下加一,假如越界判断,闰年判断
第四个按下减一


一、代码逻辑

当没有按键按下时,LCD显示数组存储的时间。
按下第一个按键K1,进入设置时间函数Set_Time()。此时LCD1602显示的是当前时间,LCD不会动,此时其实时钟芯片在工作。若没有其他按键按下则继续显示刚才时间,也只是经过微秒级别,接着写入刚才时间显示。若刚好检测到按键(K1 K2 K3)其中一个按下,返回按键值,加一或减一,写入时间,然后显示。
因为按键按下延时,时钟芯片还在工作。所以在执行完最后一次显示函数Show_Time()后,此时读取了一次数据,数组中保存的就是按键按下之前的时间,几乎就是按键按下时间,因为不再执行show函数,差几个机器周期。此时在对这些数据进行处理(操作也只是改变数组里的值),按键操作之后,再将这些数据写进寄存器(调用DS1302_SetTime()),下一次按键K1按下,就可以重新显示改变后的时间。

二、完整代码

#include <regx52.h>
sbit DS1302_SCLK=P3^6;
sbit DS1302_IO=P3^4;
sbit DS1302_CE=P3^5;//LCD1602
sbit LCD_RS=P2^6;
sbit LCD_RW=P2^5;
sbit LCD_EN=P2^7;
#define LCD_DataPort P0//
#define DS1302_SECOND       0x80
#define DS1302_MINUTE       0x82
#define DS1302_HOUR         0x84
#define DS1302_DATE         0x86
#define DS1302_MONTH        0x88
#define DS1302_DAY          0x8A
#define DS1302_YEAR         0x8C
#define DS1302_WP             0x8E//初始化时间0-6年月日小时分秒星期
char DS1302_Time[]={22,4,26,21,59,55,2};
//LCD1602º¯Êý
void LCD_Delay();
void LCD_Init();
void LCD_ShowString(unsigned char Line,unsigned char Column,char *String);
void LCD_ShowNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length);void DS1302_Init();
void DS1302_WriteByte(unsigned char command,Data);
unsigned char DS1302_ReadByte(unsigned char command);
void DS1302_ReadTime(void);
void DS1302_SetTime();
void Set_Time();
void Show_Time();void Timer0_Init();unsigned char key_value=0;
unsigned char key_set=0;
bit flag=0;sbit K1=P3^1;
sbit K2=P3^0;
sbit K3=P3^2;
sbit K4=P3^3;
unsigned char Key();
void Delay(unsigned int xms);
int main()
{bit mode=0;LCD_Init();DS1302_Init();LCD_ShowString(1,1,"  -  -  ");//LCD_ShowString(2,1,"  :  :  ");DS1302_SetTime();Timer0_Init();while(1){key_value=Key();if(key_value==1){mode=!mode;  key_set=0; }   if(mode==0){Show_Time();}else if(mode==1){Set_Time();   }}return 0;
}
void Delay(unsigned int xms)
{unsigned char i, j;while(xms--){i = 2;j = 239;do{while (--j);} while (--i);}
}
unsigned char Key()
{unsigned char KeyNumber=0;if(P3_1==0){Delay(20);while(P3_1==0);Delay(20);KeyNumber=1;}if(P3_0==0){Delay(20);while(P3_0==0);Delay(20);KeyNumber=2;}if(P3_2==0){Delay(20);while(P3_2==0);Delay(20);KeyNumber=3;}if(P3_3==0){Delay(20);while(P3_3==0);Delay(20);KeyNumber=4;}return KeyNumber;
}
void Timer0_Init()
{TMOD&=0XF0;TMOD|=0X01;TH0=(65536-1000)/256;TL0=(65536-1000)%256;TR0=1;EA=1;ET0=1;
}
void Timer0_Rountine() interrupt 1
{static int count=0;TH0=(65536-1000)/256;TL0=(65536-1000)%256;count++;if(count==500){count=0;flag=!flag;}}
//时间设置,用于修改时间,K2控制哪个位。K3加,K4减
void Set_Time()
{if(key_value==2){key_set++;if(key_set==6)key_set=0;}if(key_value==3){DS1302_Time[key_set]++;if(DS1302_Time[0]>99)DS1302_Time[0]=0;if(DS1302_Time[1]>12)DS1302_Time[1]=0;if(DS1302_Time[1]==1||DS1302_Time[1]==3||DS1302_Time[1]==5||DS1302_Time[1]==8||DS1302_Time[1]==7||DS1302_Time[1]==10||DS1302_Time[1]==12){if(DS1302_Time[2]>31)DS1302_Time[2]=1;}else if(DS1302_Time[1]==4||DS1302_Time[1]==6||DS1302_Time[1]==9||DS1302_Time[1]==11){if(DS1302_Time[2]>30)DS1302_Time[2]=1;}else{if(DS1302_Time[0]%4==0){if(DS1302_Time[2]>29) DS1302_Time[2]=1;}else{if(DS1302_Time[2]>28)DS1302_Time[2]=1;}}if(DS1302_Time[3]>23)DS1302_Time[3]=0;if(DS1302_Time[4]>59)DS1302_Time[4]=0;if(DS1302_Time[5]>59)DS1302_Time[5]=0;}if(key_value==4){DS1302_Time[key_set]--;if(DS1302_Time[0]<0){DS1302_Time[0]=99;}if(DS1302_Time[1]<1){DS1302_Time[1]=12;}if( DS1302_Time[1]==1 || DS1302_Time[1]==3 || DS1302_Time[1]==5 || DS1302_Time[1]==7 || DS1302_Time[1]==8 || DS1302_Time[1]==10 || DS1302_Time[1]==12){if(DS1302_Time[2]<1){DS1302_Time[2]=31;}if(DS1302_Time[2]>31){DS1302_Time[2]=1;}}else if(DS1302_Time[1]==4 || DS1302_Time[1]==6 || DS1302_Time[1]==9 || DS1302_Time[1]==11){if(DS1302_Time[2]<1){DS1302_Time[2]=30;}if(DS1302_Time[2]>30){DS1302_Time[2]=1;}}else{if(DS1302_Time[0]%4==0){if(DS1302_Time[2]<1){DS1302_Time[2]=29;}if(DS1302_Time[2]>29){DS1302_Time[2]=1;}}else{if(DS1302_Time[2]<1){DS1302_Time[2]=28;}if(DS1302_Time[2]>28){DS1302_Time[2]=1;}}}if(DS1302_Time[3]<0)DS1302_Time[3]=23;if(DS1302_Time[4]<0)DS1302_Time[4]=59;if(DS1302_Time[5]<0)DS1302_Time[5]=59;}//光标闪烁实现代码if(key_set==0&&flag==0){LCD_ShowString(1,1,"  ");}elseLCD_ShowNum(1,1,DS1302_Time[0],2);if(key_set==1&&flag==0){LCD_ShowString(1,4,"  ");}elseLCD_ShowNum(1,4,DS1302_Time[1],2);if(key_set==2&&flag==0){LCD_ShowString(1,7,"  ");}elseLCD_ShowNum(1,7,DS1302_Time[2],2);if(key_set==3&&flag==0){LCD_ShowString(2,1,"  ");}elseLCD_ShowNum(2,1,DS1302_Time[3],2);if(key_set==4&&flag==0){LCD_ShowString(2,4,"  ");}elseLCD_ShowNum(2,4,DS1302_Time[4],2);if(key_set==5&&flag==0){LCD_ShowString(2,7,"  ");}elseLCD_ShowNum(2,7,DS1302_Time[5],2);DS1302_SetTime();//这一句很重要,将修改后数组的时间数据存入时钟芯片寄存器}
//显示时间。第一句代码先读取时钟芯片寄存器数据,然后显示。
void Show_Time()
{DS1302_ReadTime();LCD_ShowNum(1,1,DS1302_Time[0],2);LCD_ShowNum(1,4,DS1302_Time[1],2);LCD_ShowNum(1,7,DS1302_Time[2],2);LCD_ShowNum(2,1,DS1302_Time[3],2);LCD_ShowNum(2,4,DS1302_Time[4],2);LCD_ShowNum(2,7,DS1302_Time[5],2);
}   void DS1302_Init()
{DS1302_CE=0;DS1302_SCLK=0;
}
/**
*@brief DS1302Ð写数据
*@param
*@retval
*/
void DS1302_WriteByte(unsigned char command,Data)
{int i;DS1302_CE=1;for(i=0;i<8;i++){DS1302_IO=command&(0x01<<i);DS1302_SCLK=1;DS1302_SCLK=0;}for(i=0;i<8;i++){DS1302_IO=Data&(0x01<<i);DS1302_SCLK=1;DS1302_SCLK=0;}DS1302_CE=0;
}
/**
*@brief DS1302读数据
*@param
*@retval
*/
unsigned char DS1302_ReadByte(unsigned char command)
{int i;unsigned char Data=0x00;DS1302_CE=1;command|=0x01;for(i=0;i<8;i++){DS1302_IO=command&(0x01<<i);DS1302_SCLK=0;DS1302_SCLK=1;//}for(i=0;i<8;i++){DS1302_SCLK=1;//DS1302_SCLK=0;//if(DS1302_IO==1) //Data|=(0x01<<i);//}DS1302_IO=0;DS1302_CE=0;return Data;}
void DS1302_SetTime(void)
{DS1302_WriteByte(DS1302_WP,0x00);DS1302_WriteByte(DS1302_YEAR,DS1302_Time[0]/10*16+DS1302_Time[0]%10);DS1302_WriteByte(DS1302_MONTH,DS1302_Time[1]/10*16+DS1302_Time[1]%10);DS1302_WriteByte(DS1302_DATE,DS1302_Time[2]/10*16+DS1302_Time[2]%10);DS1302_WriteByte(DS1302_HOUR,DS1302_Time[3]/10*16+DS1302_Time[3]%10);DS1302_WriteByte(DS1302_MINUTE,DS1302_Time[4]/10*16+DS1302_Time[4]%10);DS1302_WriteByte(DS1302_SECOND,DS1302_Time[5]/10*16+DS1302_Time[5]%10);DS1302_WriteByte(DS1302_DAY,DS1302_Time[6]/10*16+DS1302_Time[6]%10);DS1302_WriteByte(DS1302_WP,0x80);
}
void DS1302_ReadTime(void)
{unsigned char Temp;Temp=DS1302_ReadByte(DS1302_YEAR);DS1302_Time[0]=Temp/16*10+Temp%16;//Temp=DS1302_ReadByte(DS1302_MONTH);DS1302_Time[1]=Temp/16*10+Temp%16;Temp=DS1302_ReadByte(DS1302_DATE);DS1302_Time[2]=Temp/16*10+Temp%16;Temp=DS1302_ReadByte(DS1302_HOUR);DS1302_Time[3]=Temp/16*10+Temp%16;Temp=DS1302_ReadByte(DS1302_MINUTE);DS1302_Time[4]=Temp/16*10+Temp%16;Temp=DS1302_ReadByte(DS1302_SECOND);DS1302_Time[5]=Temp/16*10+Temp%16;Temp=DS1302_ReadByte(DS1302_DAY);DS1302_Time[6]=Temp/16*10+Temp%16;
}/*** @brief  LCD1602延时,12MHz1ms* @param  * @retval */
void LCD_Delay()
{unsigned char i, j;i = 2;j = 239;do{while (--j);} while (--i);
}/*** @brief  LCD1602дÃüÁî* @param  Command * @retval */
void LCD_WriteCommand(unsigned char Command)
{LCD_RS=0;LCD_RW=0;LCD_DataPort=Command;LCD_EN=1;LCD_Delay();LCD_EN=0;LCD_Delay();
}/*** @brief  LCD1602дÊý¾Ý* @param  Data * @retval */
void LCD_WriteData(unsigned char Data)
{LCD_RS=1;LCD_RW=0;LCD_DataPort=Data;LCD_EN=1;LCD_Delay();LCD_EN=0;LCD_Delay();
}/*** @brief  LCD1602ÉèÖÃÖ¸ÕëλÖÃ* @param  Line :1~2* @param  Column :1~16* @retval ?*/
void LCD_SetCursor(unsigned char Line,unsigned char Column)
{if(Line==1){LCD_WriteCommand(0x80|(Column-1));//}else if(Line==2){LCD_WriteCommand(0x80|(Column-1+0x40));}
}/*** @brief  LCD1602* @param  ?* @retval ?*/
void LCD_Init()
{LCD_WriteCommand(0x38);//LCD_WriteCommand(0x0c);//LCD_WriteCommand(0x06);//LCD_WriteCommand(0x01);//
}void LCD_ShowString(unsigned char Line,unsigned char Column,char *String)
{LCD_SetCursor(Line,Column);while(*String!='\0')//{LCD_WriteData(*String++);}
}
/**
*@brief
*@param  ·µ»ØXµÄY´Î·½
*@retval
*/
int LCD_Pow(int X,int Y)
{unsigned char i;int Result=1;for(i=0;i<Y;i++){Result*=X;}return Result;
}/*** @brief  LCD1602ÏÔʾʮ½øÖÆ* @param  Line :1~2* @param  Column :1~16* @param  Number :0~65535* @param  Length :1~5* @retval */
void LCD_ShowNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length)
{unsigned char i;LCD_SetCursor(Line,Column);for(i=Length;i>0;i--){LCD_WriteData(Number/LCD_Pow(10,i-1)%10+'0');}
}

三、遇到问题

四、遇到问题

(1) 将秒寄存器关掉,读出寄存器数据,最后再设置时间。其实这样做没有用,因为程序很快执行,已经读出寄存器数据了,不需要关时钟芯片。只需要操作读出的数据即可。读出的数据存储在数组里。
(2) 一直在设置时间函数Set_Time()里加个读取寄存器数据,希望操作按键之后出现理想结果(若不修改时间,再次按下K1显示第一次按下K1时的时间)。解决也很容易,软件实现。最关键是按键操作完,要重新给时钟芯片写入数组数据。保存修改后时间。
(3) 因为循环调用显示函数Show_Time(),时钟显示才变化
将显示函数放在while外面,只显示一个不动的时间,应该是只有循环才能出现变化的时间显示。原因是LCD显示一次时间初始化,而时钟在变化,只有再次显示,才能将寄存器实时时间读出来,从而显示在LCD1602上。

五、总结

写这套程序花费大约5个小时,而且最后参考了下其他老师程序。走了很多弯路,好歹最终实现目的。深刻明白代码逻辑的重要性,没有架构逻辑,写代码难如登山。通过一次次修改,还是有很大收获。诸君共勉。若能帮助到您,跪求点赞关注。如有问题,评论即可。

51单片机调整时钟Proteus仿真相关推荐

  1. 基于51单片机篮球计分器proteus仿真设计

    本设计是51单片机篮球计分器proteus仿真(源码+原理图+PCB+仿真+报告) 仿真:proteus 7.8 程序编译器:keil 4/keil 5 编程语言:C语言 编号C0004 资料文件下载 ...

  2. 基于51单片机简易数字示波器Proteus仿真

    功能介绍: 采用51单片机作为主控CPU:LCD12864可显示方波,三角波,锯齿波,正弦波等,可通过光标对波形进行测量,可以调节显示波形的幅度和频率,也可以将波形进行左右拖拉,完美的仿真出一个51单 ...

  3. 51单片机 AT24C04+蜂鸣器+Proteus仿真

    51单片机 AT24C02+蜂鸣器+Proteus仿真 Proteus仿真截图 由于是音频效果,只能以截图展示基本电路 实例代码 #include <reg52.h> #include & ...

  4. 51单片机模拟电子琴+Proteus仿真

    51单片机模拟电子琴+Proteus仿真 Proteus仿真 示例程序 #include<reg51.h> #include<intrins.h>#define uchar u ...

  5. 基于51单片机的电子秤proteus仿真设计

    本设计仅供学习参考 基于51单片机的电子秤proteus仿真设计(仿真+程序+原理图+报告+讲解) 原理图:Altium Designer 仿真图proteus 7.8 程序编译器:keil 4/ke ...

  6. 51单片机全自动洗衣机proteus仿真设计

    51单片机全自动洗衣机proteus仿真设计 目录标题 51单片机全自动洗衣机proteus仿真设计 设计介绍 仿真图 电动机驱动模块电路设计 电源模块电路设计 控制按键 进水阀和排水阀控制继电器 程 ...

  7. 51单片机DS18B20温度报警器proteus仿真设计_可调上下限

    51单片机DS18B20温度报警器proteus仿真设计_可调上下限 (仿真+源码+原理图+报告) 原理图:Altium Designer 仿真版本:proteus 7.8 程序编译器:keil 4/ ...

  8. 51单片机串口通讯 +Proteus仿真实验

    51单片机串口通讯 +Proteus仿真实验 ✨注意不要使用Proteus 8 Professional 8.13版本串口通信会出错.

  9. 基于51单片机的万年历proteus仿真原理图方案设计

    (末尾附文件) 系统框图 原理图 仿真图 最小系统电路 STC89C52的最小系统如图3-3所示,整个最小系统由三个部分组成,晶振电路部分.复位电路部分.电源电路等三个部分组成. 晶振电路包括2个30 ...

最新文章

  1. 新版 Edge 浏览器或将拥有两个不同的浏览器内核
  2. BZOJ3236 [Ahoi2013]作业
  3. python redis 性能测试台_Redis性能测试
  4. 大家整齐的qipaifans朗读声忽然乱了
  5. PHP(2):搭建PHP 运行环境中可能出现的问题及处理方法
  6. ssd目标检测训练自己的数据_目标检测Tensorflow object detection API之训练自己的数据集...
  7. SQL的注入式攻击方式和避免方法
  8. Mysql查询高速缓存区
  9. c语言中extern关键字_了解C语言中的extern关键字
  10. PCTFREEITLCONSISTANT READ
  11. Oracle 19c 安装教程
  12. java-高级编程课-实验题集标答整理
  13. python中path的用法_python中pathlib模块的基本用法与总结
  14. html网页url伪静态,动态url 静态url 伪静态url页面的区别
  15. 计算机考证包括cad吗
  16. 索尼相机手机控制对焦,操控指南丨 使用索尼微单的十个小技巧
  17. win7 管理iphone日历_iPhone和Windows同步文件,这7个技巧让你的效率成倍增加
  18. Udacity DNN
  19. webpack打包时提示:The following entrypoint(s) combined asset size exceeds the recommended limit
  20. 屋顶材料/光伏板美标ASTM E108防火阻燃等级怎么分类

热门文章

  1. 遗传算法之基因型与表现型的相互转换
  2. Go 语言中三个点的用法
  3. python镜像安装re模块_Python模块之re模块
  4. 男朋友向女朋友打的辞职报告
  5. DE2-115 以太网通信之一88E1111网卡接收PC数据
  6. 一球成谜!咪咕直播联合即构打造世界杯直播答题新玩法
  7. 联盟链中的Hyperledger Fabric、FISCO BCOS和CITA
  8. 4.2 Hive SQL
  9. 手机通过USB共享电脑宽带
  10. 抖音表情包项目怎么变现?普通人如何利用表情包短视频月入过万?