51单片机LCD1602 定时器时钟 实现年月日时分秒显示
实现功能:利用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 定时器时钟 实现年月日时分秒显示相关推荐
- php 当前年月日时分秒,显示当前日期:年月日时分秒
var str = ""; var oDiv = document.getElementsByTagName("div")[0]; setInterval(fu ...
- 51单片机LCD1602温度时钟万年历带闹钟DS18B20实践制作DIY- GC0046-出租车计价器
一.功能说明: 基于51单片机设计-万年历带闹钟 功能介绍: STC89C52最小系统板. LCD1602 .DS1302.DS18B20.4个按键.蜂鸣器. 1.单片机获取DS1302的年月日时分秒 ...
- 单片机自制时钟(年月日星期时分秒显示、按键校准)
单片机自制时钟(可实现年月日星期时分秒显示.按键校准) 单片机自制时钟 /*RS->p1.0;RW->p1.1;EN->p2.5;A->VCC;K->GND*/ /*K1 ...
- oracle在数据表中获取年月日时分秒
最近在用oracle数据库select数据,因为之前都是在用mysql,总是会遇到一些问题,记录一下. 如时间的取出问题,在数据库中格式是"年-月-日 时:分:秒"的格式,但是取出 ...
- oracle中获取年月日时分秒
我写sql的时间为2016年10月10日下午15:18完事,这个时间下面要做对比: --获取年 select to_char(sysdate,'yyyy') from dual--2016 selec ...
- 基于51单片机LCD1602显示
基于51单片机LCD1602显示 要在1602上显示字符,要大概明白1602液晶显示屏工作原理. 一般的液晶显示器(Liquid Crystal Display, LCD) 的主要原理是以电流刺激液晶 ...
- 使用51单片机+lcd1602转接板-iic接口进行显示
使用51单片机+lcd1602转接板-iic接口进行显示 某宝上有卖lcd1602与iic芯片pcf8574的整合,虽然lcd1602能直接用51单片机使用,不过经过整合之后只需要对SCL和SDA两个 ...
- Proteus8仿真:51单片机LCD1602显示
51单片机LCD1602显示 元器件 原理图部分 代码 main.c 工程文件 元器件 元器件 名称 排阻 RESPACK-8 51单片机 AT89C51 LCD1602 LM016L 按键 BUTT ...
- java时间格式年月日时分秒_java日期格式(年月日时分秒毫秒)
java日期格式(年月日时分秒毫秒) 2020-08-13 07:09 阅读数 79 package test.remote.tools.combine; import java.text.Simpl ...
最新文章
- 常见的Java WEB服务器
- Spring之面向切面编程AOP(三)
- P6800-[模板]Chirp Z-Transform【NTT】
- python函数星号参数
- 关于学习Python的一些心得
- Atitit 装备工具分类 attilax总结 艾龙著 工具链体系 武器与软件行业工具也是很近似的的。 1. 分类思维	1 1.1. 总分类:冷、热	1 1.2. 轻、重、大规模杀伤性	1
- 音乐直链php,【原创】百度音乐直链 + 实现方法
- 内网远程控制安卓设备软件推荐
- unity 2d文字跟随主角移动_用Unity制作GalGame/视觉小说游戏的模型素材与插件推荐...
- julia常用矩阵函数_Julia语言入门
- t999主页劫持/篡改木马
- linux查询ip命令
- Python 中还藏着这些稀奇古怪的东西...
- java实现-强智教务系统API文档-全部java封装
- Jmeter常用快捷键
- excel公式不自动计算_公式 | Excel根据起止日期,自动计算每月的计息天数
- outlook——分类及密送
- C语言学习(三)内存初识、数据在内存中的保存形式、程序载入内存
- 【FFmpeg】flv转码测试2: 24fps gop为24 恒定码率
- Python实现 天天向上的力量(嵩天老师)