基于51单片机电子钟闹钟LCD1602显示12-24时制切换( proteus仿真+程序+设计报告+讲解视频)
仿真图proteus8.17(有低版本)
程序编译器:keil 4/keil 5
编程语言:C语言
设计编号:P21
1. 主要功能:
1、用 LCD 1602 作为显示设备,设计时钟功能;
2、可以分别调校小时、分钟和秒,复位后时间为00:00:00,并可设置为24 或 12 小时格式;
3、可以有其他扩展功能。
扩展功能:
具有闹钟功能,可以通过按键设定闹钟时间;
能显示年月日星期,设置时间考虑大小月限制和自动设置星期;
12/24小时制有对应的指示灯。
主要硬件 51单片机 DS1302 LCD1602 独立按键 LED 蜂鸣器。
(目前仅完全适配普中51-实验板234,其他普中开发板型号需要接线)
需注意仿真中51单片机芯片是兼容的,AT89C51,AT89C52是51单片机的具体型号,内核是一样的。相同的原理图里,无论stc还是at都一样,引脚功能都是一样的,程序是兼容的,芯片可以替换为STC89C52/STC89C51/AT89C52/AT89C51等51单片机芯片。
资料下载链接:
P21 时钟闹钟LCD1602 12-24小时制切换
链接: https://pan.baidu.com/s/1l-JULY9Xw4hCJkXDrII3ug?pwd=w4us
提取码: w4us
以下为本设计资料展示图:
2. 实物图:
3. 仿真
打开仿真工程,双击proteus中的单片机,选择hex文件路径,然后开始仿真。
显示时间的情况下,按下切换键进入设置模式,设置的变量闪烁,默认先设置年份,通过按键加和按键减调整,通过下一个按键切换设置月份,设置月份时同样通过加减键调整。如此类推设置日期,星期,时分秒。
设置好时钟后按下切换按键设置闹钟。同样通过按键加减调整闹钟时间,通过下一个按键切换设置时钟/分钟。
按下12/24小时制切换可以切换时制。上午显示AM,下午显示PM,方便区分时间。
4. 程序代码
使用keil4或者keil5编译,代码有注释,可以结合视频理解代码含义。
#include <reg51.h>
#include "lcd1602.h"
#include"ds1302.h"
完整代码见文章后面下载链接
#define uchar unsigned char
#define uint unsigned int
//功能设计:调整时间、调整闹钟、正常
sbit key2=P3^3;//下一个设置点
sbit key3=P3^2;//加
sbit key4=P3^0;//减
sbit key5=P3^1;//12,24小时制切换
sbit beep=P2^5;//蜂鸣器
sbit led_12=P2^0;//12小时制
sbit led_24=P2^1;//24小时制
//===============================================================
uchar mode=0;//模式 设置,工作
uchar beep_flag=0;
uchar t=0;
uchar fen=1,shi=0;//闹钟分钟和闹钟时间设置
uchar cixu=0,flag=0;//小模式
uchar moshi=0;//12,24控制
uchar hang1[]="2000/00/00 ";//日期
uchar hang2[]="00:00:00 ";//时间
uchar hang3[]="00:00 "; //闹钟 时+分
unsigned char cnt = 0,cnt1,cnt2;
void Delay1(uint j)//延时函数
{
uchar i;
for(;j>0;j--)
{
for(i=0;i<27;i++);
}
}
void suan()//正常显示的计算
{
uchar i=0;
hang1[2]=(TIME[6]>>4)+0x30;
hang1[3]=(TIME[6]&0x0f)+0x30;
hang1[5]=(TIME[4]>>4)+0x30;
hang1[6]=(TIME[4]&0x0f)+0x30;
hang1[8]=(TIME[3]>>4)+0x30;
hang1[9]=(TIME[3]&0x0f)+0x30;
// hang1[12]=TIME[5]+0x30;
switch(TIME[5])
{
case 0://星期数据为0时显示
hang1[11]='S';
hang1[12]='U';
hang1[13]='N';
break;
case 1://星期数据为1时显示
hang1[11]='M';
hang1[12]='O';
hang1[13]='N';
break;
case 2://星期数据为2时显示
hang1[11]='T';
hang1[12]='U';
hang1[13]='E';
break;
case 3://星期数据为3时显示
hang1[11]='W';
hang1[12]='E';
hang1[13]='D';
break;
case 4://星期数据为4时显示
hang1[11]='T';
hang1[12]='H';
hang1[13]='U';
break;
case 5://星期数据为5时显示
hang1[11]='F';
hang1[12]='R';
hang1[13]='I';
break;
case 6://星期数据为6时显示
hang1[11]='S';
hang1[12]='T';
hang1[13]='A';
break;
}
if(moshi==0)//小时
{
hang2[0]=(TIME[2]>>4)+0x30;
hang2[1]=(TIME[2]&0x0f)+0x30;
hang2[11]=' ';
hang2[12]=' ';
}
else
{
i=(TIME[2]>>4)*10+(TIME[2]&0x0f);
if(TIME[2]<=0x12)
{
hang2[0]=i/10+0x30;
hang2[1]=i%10+0x30;
hang2[11]='A';
hang2[12]='M';
}
else
{
hang2[0]=(i-12)/10+0x30;
hang2[1]=(i-12)%10+0x30;
hang2[11]='P';
hang2[12]='M';
}
}
hang2[3]=(TIME[1]>>4)+0x30;//分钟
hang2[4]=(TIME[1]&0x0f)+0x30;
hang2[6]=(TIME[0]>>4)+0x30;
hang2[7]=(TIME[0]&0x0f)+0x30;
hang3[0]=shi/10+0x30;
hang3[1]=shi%10+0x30;
hang3[3]=fen/10+0x30;
hang3[4]=fen%10+0x30;
}
void xian()//显示
{
suan();//计算
if(mode==0)//正常
{
write_string(1,0,hang1);
write_string(2,0,hang2);
}
else
{
switch(cixu)
{
case 0: //年
if(flag)
{
hang1[2]=(TIME[6]>>4)+0x30;
hang1[3]=(TIME[6]&0x0f)+0x30;
}
else
{
hang1[2]=' ';
hang1[3]=' ';
}
break;
case 1: //月
if(flag)
{
hang1[5]=(TIME[4]>>4)+0x30;
hang1[6]=(TIME[4]&0x0f)+0x30;
}
else
{
hang1[5]=' ';
hang1[6]=' ';
}
break;
case 2: //日
if(flag)
{
hang1[8]=(TIME[3]>>4)+0x30;
hang1[9]=(TIME[3]&0x0f)+0x30;
}
else
{
hang1[8]=' ';
hang1[9]=' ';
}
break;
case 3: //星期
if(flag)
{
hang1[12]=TIME[5]+0x30;
}
else
{
hang1[12]=' ';
}
break;
case 4: //时
if(flag)
{
hang2[0]=(TIME[2]>>4)+0x30;
hang2[1]=(TIME[2]&0x0f)+0x30;
}
else
{
hang2[0]=' ';
hang2[1]=' ';
}
break;
case 5: //分
if(flag)
{
hang2[3]=(TIME[1]>>4)+0x30;
hang2[4]=(TIME[1]&0x0f)+0x30;
}
else
{
hang2[3]=' ';
hang2[4]=' ';
}
break;
case 6: //秒
if(flag)
{
hang2[6]=(TIME[0]>>4)+0x30;
hang2[7]=(TIME[0]&0x0f)+0x30;
}
else
{
hang2[6]=' ';
hang2[7]=' ';
}
break;
case 7: //时,闹钟
if(flag)
{
hang3[0]=shi/10+0x30;
hang3[1]=shi%10+0x30;
}
else
{
hang3[0]=' ';
hang3[1]=' ';
}
break;
case 8: //分,闹钟
if(flag)
{
hang3[3]=fen/10+0x30;
hang3[4]=fen%10+0x30;
}
else
{
hang3[3]=' ';
hang3[4]=' ';
}
}
if(cixu<7) //显示结果
{
write_string(1,0,hang1);
write_string(2,0,hang2);
}
else
{
write_string(1,0,"CLOCK: ");
write_string(2,0,hang3);
}
}
}
int MonthDays(int year, int month) { //区分闰年大小月
int days;
if (month == 2) { // 二月份
if ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0)) { // 闰年2月29天,其他年份28天
days = 29;
} else {
days = 28;
}
} else if (month == 4 || month == 6 || month == 9 || month == 11) { // 四、六、九、十一月份各30天
days = 30;
} else { // 其他月份各31天
days = 31;
}
return days;
}
//主函数
void main()
{
uchar i,j,k;
int year,month;
// TMOD|=0X01;//选择为定时器0模式,工作方式1,仅用TR0打开启动。
// TH0=0X3C; //定时50ms
// TL0=0Xb0;
// ET0=1;//打开定时器0中断允许
// EA=1;//打开总中断
// TR0=1;//打开定时器
TMOD = 0X11; //初始化定时器
TH0 = (65536-50000)/256; //50ms计时初值
TL0 =(65536-50000)%256;
TH1 = (65536-1000)/256; //1ms计时初值
TL1 =(65536-1000)%256;
EA = 1; //开总中断
ET0 = 1; //开T0中断
TR0=1;
ET1 = 1; //开T1中断
TR1=0;
init_1602();//LCD初始化
write_string(1,0,hang1);
write_string(2,0,hang2);
// Ds1302ReadTime();//启动DS1302
TIME[0]=0;
Ds1302Init();
cixu=8;//不设置
while(1)
{
if(moshi){
led_12=0;//12小时制指示灯亮
led_24=1;
}else{
led_12=1;
led_24=0;//24小时制指示灯亮
}
if(key5==0)//12,24切换
{
Delay1(200);
if(key5==0){
moshi=!moshi;
}
while(!key5);
}
//判断
k=0;
i=(shi/10<<4)+shi%10;
j=(fen/10<<4)+fen%10;
if((TIME[2]==i)&&(TIME[1]==j)&&(TIME[0]==1))//闹钟开始 时分 秒=1
{
beep_flag=1;
}
if((TIME[2]==i)&&(TIME[1]==j)&&(TIME[0]>58))//闹钟结束
{
beep_flag=0;
}
if(beep_flag){
//响铃
TR1=1;
}else{
TR1=0;//不响
}
//按键检测
if(key2==0)//功能
{
Delay1(200);
if(key2==0){
if(beep_flag){//手动关闹钟
beep_flag=0;
}else{
if(mode==0){
mode=1;
cixu=0;
}else{
if(cixu<8){
cixu++;
if(cixu==3){
cixu=4;//跳过星期设置
}
}else{
mode=0;
// cixu=0;
}
}
}
}
while(!key2);
}
if(!key3&&mode==1)//加
{
switch(cixu)
{
case 0: //年
i=(TIME[6]>>4)*10+(TIME[6]&0X0F);
if(i<99)
i++;
TIME[6]=(i/10<<4)+i%10;
Ds1302Init();
break;
case 1: //月
i=(TIME[4]>>4)*10+(TIME[4]&0X0F);
if(i<12)
i++;
TIME[4]=(i/10<<4)+i%10;
Ds1302Init();
break;
case 2: //日
i=(TIME[3]>>4)*10+(TIME[3]&0X0F);
year=((TIME[6]>>4)*10+(TIME[6]&0X0F)+2000);
month=(TIME[4]>>4)*10+(TIME[4]&0X0F);
if(i<MonthDays(year,month)){
i++;
}
TIME[3]=(i/10<<4)+i%10;
Ds1302Init();
break;
case 3: //星期
i=(TIME[5]>>4)*10+(TIME[5]&0X0F);
if(i<7)
i++;
TIME[5]=(i/10<<4)+i%10;
Ds1302Init();
break;
case 4: //时
i=(TIME[2]>>4)*10+(TIME[2]&0X0F);
if(i<23)
i++;
TIME[2]=(i/10<<4)+i%10;
Ds1302Init();
break;
case 5: //分
i=(TIME[1]>>4)*10+(TIME[1]&0X0F);
if(i<59)
i++;
TIME[1]=(i/10<<4)+i%10;
Ds1302Init();
break;
case 6: //秒
i=(TIME[0]>>4)*10+(TIME[0]&0X0F);
if(i<59)
i++;
TIME[0]=(i/10<<4)+i%10;
Ds1302Init();
break;
case 7: //闹钟,时
if(shi<23)
shi++;
break;
case 8: //闹钟,分
if(fen<59)
fen++;
}
while(!key3);
}
if(!key4&&mode==1)//减
{
switch(cixu)
{
case 0: //年
i=(TIME[6]>>4)*10+(TIME[6]&0X0F);
if(i>0)
i--;
TIME[6]=(i/10<<4)+i%10;
Ds1302Init();
break;
case 1: //月
i=(TIME[4]>>4)*10+(TIME[4]&0X0F);
if(i>1)
i--;
TIME[4]=(i/10<<4)+i%10;
Ds1302Init();
break;
case 2: //日
i=(TIME[3]>>4)*10+(TIME[3]&0X0F);
if(i>1)
i--;
TIME[3]=(i/10<<4)+i%10;
Ds1302Init();
break;
case 3: //星期
i=(TIME[5]>>4)*10+(TIME[5]&0X0F);
if(i>1)
i--;
TIME[5]=(i/10<<4)+i%10;
Ds1302Init();
break;
case 4: //时
i=(TIME[2]>>4)*10+(TIME[2]&0X0F);
if(i>0)
i--;
TIME[2]=(i/10<<4)+i%10;
Ds1302Init();
break;
case 5: //分
i=(TIME[1]>>4)*10+(TIME[1]&0X0F);
if(i>0)
i--;
TIME[1]=(i/10<<4)+i%10;
Ds1302Init();
break;
case 6: //秒
i=(TIME[0]>>4)*10+(TIME[0]&0X0F);
if(i>0)
i--;
TIME[0]=(i/10<<4)+i%10;
Ds1302Init();
break;
case 7: //闹钟,时
if(shi>0)
shi--;
break;
case 8: //闹钟,分
if(fen>0)
fen--;
}
while(!key4);
}
}
}
void Timer0() interrupt 1 //定时器0中断
{
if(t<2)
t++;
else
{
t=0;
flag=!flag;
Ds1302ReadTime();//读取时间
xian();
}
TH0=0X3C; //定时50ms
TL0=0Xb0;
5. 设计报告
6403字设计报告,内容包括硬件设计、软件设计、软硬件框图、调试、结论等
6. 设计资料内容清单&&下载链接
资料设计资料包括仿真,程序代码、讲解视频、功能要求、设计报告、软硬件设计框图等。
0、常见使用问题及解决方法–必读!!!!
1、程序
2、proteus仿真
3、功能要求
4、软硬件流程图
5、开题报告
6、设计报告
7、烧录工具
8、讲解视频
9、实物图
Altium Designer 安装破解
KEIL+proteus 单片机仿真设计教程
KEIL安装破解
Proteus元器件查找
Proteus安装
Proteus简易使用教程
单片机学习资料
相关数据手册
答辩技巧
设计报告常用描述
鼠标双击打开查找嘉盛单片机51 STM32单片机课程毕业设计.url
资料下载链接(可点击):
P21 时钟闹钟LCD1602 12-24小时制切换
链接: https://pan.baidu.com/s/1l-JULY9Xw4hCJkXDrII3ug?pwd=w4us
提取码: w4us