实现功能:利用51单片机的定时器原理制作时钟,显示使用LCD1602,可以显示时分秒年月日和星期 ,识别平年闰年,按键可调整时间日期,整点报时。

1、定时器中断实现时钟基本原理

若系统晶振为12MHZ,定时器工作在mode1模式时,每次最多可计数至65536,花费时间约为65ms。若只计数至50000,需要时间50ms,实现1s的定时需要重复上述过程20次。如此就利用

定时器实现了一秒钟的产生。我们仅需对定时器赋初值TH0=(65536-50000)/256;TL0=(65536-50000)%256;代码段如下

   TH0 = 0x4c;  //高八位赋初值   晶振位11.0592,赋初值位0x4c00TL0 = 0x00;  //低八位赋初值     i++;if(i == 20){i = 0;  //满一秒清零miao++; //i = 100 为一,秒标志位加 1if(miao == 60){miao = 0;  //满一分清零fen++;if(fen == 60){fen = 0;  //满一时清零shi++;mybeeplongplus();  //整点报时if(shi == 24){shi = 0;  //24小时制fen = 0;miao = 0;

2、LCD1602基本原理介绍

关于lcd1602的介绍网上资源实在太多可以参考这位博主的文章LCD1602介绍。他讲解的挺详细的,其中有关于LCD1602自定义字符的介绍与使用,我在这里推荐一款字符取模软件zimo221,百度直接可以搜索下载。

3、C语言如何利用数组存储“变量”

c语言的数组时不能够直接储存变量的,但是却可以储存变量的地址,再利用指针来间接储存变量。此处引用c语言指针数组的使用介绍。

4、protues仿真图

此处未添加蜂鸣器,需要的可以直接接在P1^5口。

5、完整程序代码

main.c文件

//设计思路 1、利用定时器中断0二十次产生1s时间变量miao增加到60变量分+1并把miao清零,shi同理
//         2、采用4个按键 长按key4进入设置模式后, key1选择调整对象 key2k3加减
//         #include"LCD1602.h"
#include<reg52.h>
void LCD_display(void);
void keykan(void);
int num[10]={0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39};  // lcd1602 0~9字码uchar miao=0, fen=0, shi=0 , zhou=1 , yue=7 , nian=21 ;  //进位标志位  秒 分 时 周 月 年
uchar ri=9;                                              //进位标志位 日 不知道为啥放在上面会报错,单独定义就可以
uint i=0;       //定时器计时标志位uchar *time[]={&miao , &fen , &shi, &zhou ,&ri ,&yue , &nian};  //指针变量time存放进位标志位的地址,由于数组不能存放标量,但是却可以存放标量的地址,采用指针的方式来间接修改变量的值//
uchar   SetPlace=0;     //功能选择标志
bit mod =0;            //设置模式标志位
sbit key1=P3^1;         //定义四个按键 key1选择需要调整的位
sbit key2=P3^0;         //key2加
sbit key3=P3^2;         //key3减
sbit key4=P3^3;         //长按两秒钟进入或退出设置模式,前面三个按键需要进入设置模式才能使用void main(void)
{T0_init();  //定时器初始化LCD_init();  //lcd1602初始化IT1=1;      //外部中断1初始化  下降沿触发EX1=1;      //启用外部中断1LCD_disp_char(2,5,0x00);        //显示自定义字符“周”delay(50);while(1)    //死循环                 {  keykan();LCD_display();     //lcd1602显示时分秒年月日周}}
void keykan(void)
{if (mod==0)                     //如果没有进入设置模式 调整提示区域显示字符串time{LCD_row(2);LCD_DispString("TIME");delay(50);}LCD_disp_char(1,14,' ');        //清空第一行第15位的显示内容delay(50);if (mod==1)                     //如果进入设置模式显示一个1602字符库的一个特定字符{LCD_disp_char(1,14,0xef);delay(50);  if(key1==0)        //检测按键key1是否按下{delay(10);   //消除抖动if(key1==0){                            //按一下功能选择位就+1,加到7就清零SetPlace++;if(SetPlace>=7)SetPlace=0;                    }if (SetPlace==0)              //功能选择位为0就显示“miao”  为1就显示“fen” 以此类推,shi zhou ri yue nian{LCD_row(2);LCD_DispString("miao");delay(50);}if (SetPlace==1){LCD_row(2);LCD_DispString(" fen");delay(50);}if (SetPlace==2){LCD_row(2);LCD_DispString(" shi");delay(50);}if (SetPlace==3){LCD_row(2);LCD_DispString("zhou");delay(50);}if (SetPlace==4){LCD_row(2);LCD_DispString("  ri");delay(50);}if (SetPlace==5){LCD_row(2);LCD_DispString(" yue");delay(50);}if (SetPlace==6){LCD_row(2);LCD_DispString("nian");delay(50);}mybeep();                   //蜂鸣器发声while(key1==0)  //检测按键是否松开{delay(10);  }}if(key2==0)     //检测按键key2是否按下{delay(10);   //消除抖动if(key2==0){(*time[SetPlace])++;                            //按键按一次 指针数组*time[SetPlace]里对应的地址的数据值就+1,也就是说进位标志位年月日时分秒的值就会+1if ((((*time[SetPlace]))>=60) && (SetPlace==0)){(*time[SetPlace])=0;                            //秒只能加dao59}if ((((*time[SetPlace]))>=60) && (SetPlace==1)){(*time[SetPlace])=0;                            //分只能加到59}if ((((*time[SetPlace]))>=24) && (SetPlace==2)){(*time[SetPlace])=0;                            //时只能加到23}if ((((*time[SetPlace]))>=8) && (SetPlace==3))       //周只能加到7{(*time[SetPlace])=1; }if ((((*time[SetPlace]))>=29) && (SetPlace==4) && (yue==2) && ((nian%4)!=0)){                                                                                   //平年的2月只能加到28(*time[SetPlace])=1;}if ((((*time[SetPlace]))>=30) && (SetPlace==4) && (yue==2) && ((nian%4)==0))            //闰年的2月29天{(*time[SetPlace])=1;}if ((((*time[SetPlace]))>=31) && (SetPlace==4) && ((yue==4)||(yue==6)||(yue==9)||(yue==11)))        //4 6 9 11 月只有30天{(*time[SetPlace])=1;}if ((((*time[SetPlace]))>=32) && (SetPlace==4) && ((yue==1)||(yue==3)||(yue==5)||(yue==7)||(yue==8)||(yue==10)||(yue==12)))     {(*time[SetPlace])=1;                                                                            //1 3 5 7 8 10 12月有31天}if ((((*time[SetPlace]))>=13) && (SetPlace==5))         //月份只能加到12{(*time[SetPlace])=1;}   mybeep();    //蜂鸣器响while(key2==0)     //检测按键是否松开{delay(10);  }}}if(key3==0)        //检测按键key3是否按下{                                                  //key3与key2按钮基本原理相同,key3表示对应值减1delay(10);   //消除抖动if(key3==0){if ((((*time[SetPlace]))<=0) && (SetPlace==0)){(*time[SetPlace])=60;}if ((((*time[SetPlace]))<=0) && (SetPlace==1)){(*time[SetPlace])=60;}if ((((*time[SetPlace]))<=0) && (SetPlace==2)){(*time[SetPlace])=24;}if ((((*time[SetPlace]))<=1) && (SetPlace==3)){(*time[SetPlace])=8;  }if ((((*time[SetPlace]))<=1) && (SetPlace==4) && (yue==2) && ((nian%4)!=0)){(*time[SetPlace])=29;}if ((((*time[SetPlace]))<=1) && (SetPlace==4) && (yue==2) && ((nian%4)==0)){(*time[SetPlace])=30;}if ((((*time[SetPlace]))<=1) && (SetPlace==4)&&((yue==4)||(yue==6)||(yue==9)||(yue==11))){(*time[SetPlace])=31;}if ((((*time[SetPlace]))<=1) && (SetPlace==4)&&((yue==1)||(yue==3)||(yue==5)||(yue==7)||(yue==8)||(yue==10)||(yue==12))){(*time[SetPlace])=32;}if ((((*time[SetPlace]))<=1) && (SetPlace==5)){(*time[SetPlace])=13;   }(*time[SetPlace])--;}mybeep();while(key3==0)   //检测按键是否松开{delay(10);  }}}
}
void timer0_int() interrupt 1       //定时器中断服务函数
{ TH0 = 0x4c;  //高八位赋初值  晶振11.0592MHZ 赋初值TL0 = 0x2c;   //低八位赋初值      i++;if(i == 20){i = 0;  //满一秒清零miao++;    //i = 100 为一,秒标志位加 1if(miao == 60){miao = 0;  //满一分清零fen++;if(fen == 60){fen = 0;  //满一时清零shi++;mybeeplongplus();  //整点报时if(shi == 24){shi = 0;  //24小时制fen = 0;miao = 0;zhou++;ri++;if ((ri==31)&&((yue==1)||(yue==3)||(yue==5)||(yue==7)||(yue==8)||(yue==10)||(yue==12))){yue++;              //  满31号回到1号ri=1;}if ((ri==28)&&(yue==2) && ((nian%4)!=0)){yue++;              //平年28天回到一号ri=1;}if ((ri==29)&&(yue==2) && ((nian%4)==0)){yue++;                  //闰年29天ri=1;}if ((ri==30)&&((yue==4)||(yue==6)||(yue==9)||(yue==11))){yue++;                  //4 6 9 11月每月30天                         ri=1;}if (zhou==7)  //满一周回到周一{zhou=1;}if (yue==12)            //满12个月, 年份加1{nian++;yue=1;}}}}}}void LCD_display(void)      //lcd1602显示年月日时分秒周{  LCD_disp_char(2,6,*time[3]);   //显示周几 此处显示的为自定义字符 当zhou=1的时候即*time[3]=1  对应地址0x01的字符为 一 ;以此类推delay(50);LCD_disp_char(2,15,num[*time[0]%10]);     //显示秒的个位 当miao%10的值为0时即(*time[0])==0, 此时num[0]=0x30 对应1602字符库中的0 ,lcd1602对应第2行第16位显示0delay(50);                                  //当miao%10的值为1时即(*time[1])==1, 此时num[1]=0x31 对应1602字符库中的1LCD_disp_char(2,14,num[*time[0]/10]);       //秒的十位delay(50);LCD_disp_char(2,13,'-');delay(50);LCD_disp_char(2,12,num[*time[1]%10]);            //分的各位delay(50);LCD_disp_char(2,11,num[*time[1]/10]);               //分的十位delay(50);LCD_disp_char(2,10,'-');                            //字符‘-’delay(50);LCD_disp_char(2,9,num[*time[2]%10]);                //时的个位delay(50);LCD_disp_char(2,8,num[*time[2]/10]);                //时的十位delay(50);LCD_disp_char(1,0,'2');delay(50);//显示字符 2 0 表示21世纪LCD_disp_char(1,1,'0');delay(50);LCD_disp_char(1,2,num[*time[6]/10]);              //年的个位delay(50);LCD_disp_char(1,3,num[*time[6]%10]);                //年的十位delay(50);LCD_disp_char(1,4,'-');delay(50);LCD_disp_char(1,5,num[*time[5]/10]);                //月的个位delay(50);LCD_disp_char(1,6,num[*time[5]%10]);                //月的十位delay(50);LCD_disp_char(1,7,'-');delay(50);LCD_disp_char(1,8,num[*time[4]/10]);                    //日的个位delay(50);LCD_disp_char(1,9,num[*time[4]%10]);                    //日的十位delay(50);}void my_int1(void)interrupt 2                 //外部中断1服务程序{delay_n40us(50000);               //消抖if (key4==0){mod=~mod;        //进入或退出设置mybeeplong();    //蜂鸣器TR0=~TR0;       //打开或关闭定时器中断SetPlace=0;     //模式选择位清零}while (key4==!key4);     }

lcd1602.h文件

 #ifndef _LCD1602_H          //相当于if not define 防止程序中头文件被多次编译
#define _LCD1602_H
#include<reg52.h>
#define uchar unsigned char
#define uint unsigned int
//lcd 1602 硬件接线端口
#define LCD_DB P0
sbit LCD_RS=P2^6;
sbit LCD_RW=P2^5;
sbit LCD_E=P2^7;
sbit  BEEP=P1^5;   //蜂鸣器
void LCD_init(void);   //lcd初始化函数
void LCD_write_command(uchar command);    // 写指令函数
void LCD_write_data(uchar dat);             //写数据函数
void LCD_disp_char(uchar x , uchar y, char dat);  //在某一位置显示单个字符
void LCD_check_busy(void);              //检查忙函数
void LCD_row(uchar row);                //选择显示行数
void LCD_DispString(char str[]);            //显示字符串
void delay_n40us( uint n);                  //延时函数
void T0_init(void);                         //定时器初始化
void delay(uint x);                            //延时
void CgramWrite(void);                          //自定义字符装载
void mybeep(void);                               //蜂鸣器用于key123
void mybeeplong(void);                              //用于key4
void mybeeplongplus(void);                            //用于整点报时
#endif

lcd1602.c文件

 #include"LCD1602.h"uint code Xword[]={0x1F,0x15,0x1D,0x17,0x11,0x15,0x01,0x00,  //周,代码 0x00(由于这个lcd1602像素太小了5*8,这个周字属实有点认不出)0x00,0x00,0x00,0x00,0xff,0x00,0x00,0x00,  //一,代码 0x010x00,0x00,0x00,0x0e,0x00,0xff,0x00,0x00,  //二,代码 0x020x00,0x00,0xff,0x00,0x0e,0x00,0xff,0x00,  //三,代码 0x030x00,0x00,0xff,0xf5,0xfb,0xf1,0xff,0x00,  //四,代码 0x040x00,0xfe,0x08,0xfe,0x0a,0x0a,0xff,0x00,  //五,代码 0x050x00,0x04,0x00,0xff,0x00,0x0a,0x11,0x00,  //六,代码 0x060x00,0x1f,0x11,0x1f,0x11,0x11,0x1f,0x00,  //日,代码 0x07
};void CgramWrite(void) { // 装入CGRAM //uint i;LCD_write_command(0x06);   // CGRAM地址自动加1LCD_write_command(0x40);   // CGRAM地址设为00处for(i=0;i<64;i++) {LCD_write_data(Xword[i]);// 按数组写入数据}
}void LCD_init(void)
{LCD_write_command(0x38);delay_n40us(300);LCD_write_command(0x38);LCD_write_command(0X0c);   //开显示 关光标 不闪烁LCD_write_command(0x06);        //设定输入方式LCD_write_command(0X01);        //清除显示delay_n40us(300);CgramWrite();               //装载自定义字符
}void LCD_write_command(uchar dat){LCD_DB=dat;LCD_RS=0;          //指令LCD_RW=0;         //写入LCD_E=1;          //允许LCD_E=0;delay_n40us(2);
}void LCD_write_data(uchar dat ){LCD_DB=dat;LCD_RS=1;           //数据LCD_RW=0;                   //写入LCD_E=1;                //允许LCD_E=0;delay_n40us(2);
}void LCD_disp_char(uchar y , uchar  x , uchar dat ){    //x为列  y为行uchar address;if (y==1)                   //传入参数为1 使用第一行显示address=0x80+x;            //将lcd地址确定为第一行起始地址加上x为最终地址elseaddress=0xc0+x;                //参数不为1则显示第二行LCD_write_command(address);     //写入地址 LCD_write_data(dat);        //写入数据delay_n40us(2);
}void LCD_check_busy(){do{LCD_E=0;LCD_RS=0;LCD_RW=1;LCD_DB=0Xff;LCD_E=1;} while (LCD_DB^7==1);}void LCD_row(uchar row){uchar pos;if (row==1)pos=0x00;elsepos=0x40;LCD_write_command(pos | 0x80);
}void LCD_DispString(char str[]){uchar i =0;while (str[i] !='\0'){LCD_write_data(str[i]);delay_n40us(2);++i;}
}void delay_n40us(uint n){uint i;uchar j;for (i=n ; i>0; i--)for(j=0 ; j<2 ; j++);
}void T0_init(){                     //定时器 0 初始化 TMOD = 0x01; //工作方式 1TH0 = 0x4c;  //高八位赋初值    TL0 = 0x00;    //低八位赋初值EA = 1;        //开总中断ET0 = 1;     //开 T0 中断TR0 = 1;     //启动 T0
}void delay(uint x){  //延时函数 while(x--);
}void mybeep(void){uint n;for ( n = 0; n < 100; n++){BEEP=~BEEP;delay(10);}}void mybeeplong(void){uint n;for (n = 0; n < 1000; n++){BEEP=~BEEP;delay(10);}}void mybeeplongplus(void){uint n;for (n = 0; n < 5000; n++){BEEP=~BEEP;delay(10);}}

51单片机LCD1602 定时器时钟 实现年月日时分秒显示相关推荐

  1. php 当前年月日时分秒,显示当前日期:年月日时分秒

    var str = ""; var oDiv = document.getElementsByTagName("div")[0]; setInterval(fu ...

  2. 51单片机LCD1602温度时钟万年历带闹钟DS18B20实践制作DIY- GC0046-出租车计价器

    一.功能说明: 基于51单片机设计-万年历带闹钟 功能介绍: STC89C52最小系统板. LCD1602 .DS1302.DS18B20.4个按键.蜂鸣器. 1.单片机获取DS1302的年月日时分秒 ...

  3. 单片机自制时钟(年月日星期时分秒显示、按键校准)

    单片机自制时钟(可实现年月日星期时分秒显示.按键校准) 单片机自制时钟 /*RS->p1.0;RW->p1.1;EN->p2.5;A->VCC;K->GND*/ /*K1 ...

  4. oracle在数据表中获取年月日时分秒

    最近在用oracle数据库select数据,因为之前都是在用mysql,总是会遇到一些问题,记录一下. 如时间的取出问题,在数据库中格式是"年-月-日 时:分:秒"的格式,但是取出 ...

  5. oracle中获取年月日时分秒

    我写sql的时间为2016年10月10日下午15:18完事,这个时间下面要做对比: --获取年 select to_char(sysdate,'yyyy') from dual--2016 selec ...

  6. 基于51单片机LCD1602显示

    基于51单片机LCD1602显示 要在1602上显示字符,要大概明白1602液晶显示屏工作原理. 一般的液晶显示器(Liquid Crystal Display, LCD) 的主要原理是以电流刺激液晶 ...

  7. 使用51单片机+lcd1602转接板-iic接口进行显示

    使用51单片机+lcd1602转接板-iic接口进行显示 某宝上有卖lcd1602与iic芯片pcf8574的整合,虽然lcd1602能直接用51单片机使用,不过经过整合之后只需要对SCL和SDA两个 ...

  8. Proteus8仿真:51单片机LCD1602显示

    51单片机LCD1602显示 元器件 原理图部分 代码 main.c 工程文件 元器件 元器件 名称 排阻 RESPACK-8 51单片机 AT89C51 LCD1602 LM016L 按键 BUTT ...

  9. java时间格式年月日时分秒_java日期格式(年月日时分秒毫秒)

    java日期格式(年月日时分秒毫秒) 2020-08-13 07:09 阅读数 79 package test.remote.tools.combine; import java.text.Simpl ...

最新文章

  1. 常见的Java WEB服务器
  2. Spring之面向切面编程AOP(三)
  3. P6800-[模板]Chirp Z-Transform【NTT】
  4. python函数星号参数
  5. 关于学习Python的一些心得
  6. Atitit 装备工具分类 attilax总结 艾龙著 工具链体系 武器与软件行业工具也是很近似的的。 1. 分类思维 1 1.1. 总分类:冷、热 1 1.2. 轻、重、大规模杀伤性 1
  7. 音乐直链php,【原创】百度音乐直链 + 实现方法
  8. 内网远程控制安卓设备软件推荐
  9. unity 2d文字跟随主角移动_用Unity制作GalGame/视觉小说游戏的模型素材与插件推荐...
  10. julia常用矩阵函数_Julia语言入门
  11. t999主页劫持/篡改木马
  12. linux查询ip命令
  13. Python 中还藏着这些稀奇古怪的东西...
  14. java实现-强智教务系统API文档-全部java封装
  15. Jmeter常用快捷键
  16. excel公式不自动计算_公式 | Excel根据起止日期,自动计算每月的计息天数
  17. outlook——分类及密送
  18. C语言学习(三)内存初识、数据在内存中的保存形式、程序载入内存
  19. 【FFmpeg】flv转码测试2: 24fps gop为24 恒定码率
  20. Python实现 天天向上的力量(嵩天老师)

热门文章

  1. 各领域公开数据集下载-收藏
  2. Android基础笔记(十七)- 多媒体编程
  3. GitHub仓库的常用功能
  4. 产品读书《魔鬼经济学2:拥有清晰思维的艺术》
  5. Oracle19c安装(4) - Oracle Sql developer连接数据库
  6. 你对你的工作满意吗?为您解密员工满意度调查的6个问题
  7. python 网络爬虫开发第五天
  8. css 通过background将两张图合成一张图显示
  9. python小程序之七段数码管的绘制
  10. 基于stm32f103zet6(精英版)vct6 vet6的通用定时器(TIM2~TIM5)的pwm输出