51单片机LCD1602显示电子时钟 带按键设置和星期显示
当时看书看到lcd那章,就想利用定时器做一个电子时钟,当时也不知道有时钟模块的,以为都是定时器定时产生的时间,也是一个main文件从头到尾的版本,注释倒不少,不要说什么模块化编程和代码优化,想到什么就写什么,业余的就是可以随便写,所以思路肯定比别人的清楚明白,随便谁都看得懂,当然后来就把自己写的例程都自己做了个c51的库,傻瓜型的库,以后有空想到就慢慢记录下来
#include <reg52.h>
#include <string.h>#define uchar unsigned char
#define uint unsigned int//sbit u1la=P2^6; //U1锁存器 为1则打开锁存器 为0则关闭锁存器
//sbit u2la=P2^7; //U2锁存器
sbit lcdrs=P2^5; //lcd数据命令选择端 rs为L(ledrs=0)则写命令 H(ledrs=1)则写数据
sbit lcdrw=P2^6;
sbit lcden=P2^7; //lcd使能 lcden=1 则写入 //sbit key1=P3^0; //矩阵键盘中第4列中从上到下 第一个按键轮流3种状态 按一下小时闪烁 分钟闪烁 不闪烁则继续加秒数
//sbit key2=P3^1; // 第二个按键增加当前选中的秒 小时或者 分钟 等
//sbit key3=P3^2; // 第三个按键减少当前选中的数字
//sbit rd=P3^7; //置低电平后分离出第4列四个独立按键
sbit key1=P3^6; //独立 按键 由于P34 P35端口已经被lcd占用 所以只有两个独立按键可以用
sbit key2=P3^7;
sbit sbeep=P2^3; //蜂鸣器uchar code table1[]=" 2019-08-05";
uchar code table2[]=" 00:00:00";
int code month[12]={31,28,31,30,31,30,31,31,30,31,30,31}; //每个月天数 第二月有两种情况 运用时闰年判断下后处理
char code *week[7]={"SUN","MON","TUE","WED","THU","FRI","SAT"}; //每周一天英文缩写 元素从0 星期天开始
void delayms(uint ms) ; //延迟子函数
void display(uchar *table,uchar line); //显示字符串子函数 table为字符串,最大16字符 line为显示的行数,1为第一行 2为第二行 函数目前不容错
void write_com(uchar cmd); //lcd写命令子函数 一次写入一个命令 例如0x80
void write_data1(uchar); //lcd写数据子函数 一次写入一个字符
void write_data(uchar ,uchar , uchar ); //写数据 第几行 第几个开始 数据 第三个参数必须是1-2位数
void init(); //初始化函数
void day_add(); //增加一天后处理函数
void calweek(); //计算某一天星期几并刷新显示
void mybeep(); //蜂鸣器
void keyscan(); //检测 处理按键
void settime_add(); //按键修改时间后刷新时间
void settime_minus(); //修改时间
void cursor_blink(); //判断blink状态 更新光标闪烁
uchar num0; //num0为定时器0中断次数
char months,weeks, days, hours,minutes,seconds,comparemonth,m; //月 周几 日 小时 分钟 秒 每月天数 m用来公式计算周几
char blink; //第一个设置按键状态 循环7中状态 秒闪烁 分钟闪烁 小时闪烁 月 日 年 不闪烁
unsigned int years; //年份超过255数字void main()
{init();display(table1,1);display(table2,2);while(1){keyscan();delayms(5);cursor_blink();}
}void init()
{TMOD = 0x01; //定时器1工作方式1 定时器0工作方式1 定时器1在高四位TH0=(65536-45872)/256; //定时器0 16位计数器高8位初始计数TL0=(65536-45872)%256; //定时器0 16位计数器低8位初始计数EA=1; //中端使能 中端总开关ET0=1; //定时器0 中断允许位 TR0=1; //初始中断开始启动
// rd=0; //初始化rd******此处用来分离矩阵键盘独立按键第四列*******
// u1la=0; //关闭U1
// u2la=0; //关闭U2lcden=0; //lcd关闭写入lcdrw=0;years=2019; //初始化显示 2019/08/05 程序开始测试的日子months=8;days=5;weeks=1;blink=0;write_com(0x38); //设置16x2显示 5x7点阵 8位数据接口write_com(0x0c); //开显示 不显示光标write_com(0x06); //写一个字符后地址指针加1write_com(0x01); //显示清零 数据指针清零 要写入数据先写入命令 write_cmd(0x80) 第一行第一个字符地址 0x80+0x40 第二行开头地址写入write_com(0x80+0x40+6);write_data1(':');write_com(0x80+0x40+9);write_data1(':'); calweek();
}
void T0_time() interrupt 1 //*******定时器0的中断序号是1*********
{ TH0=(65536-45872)/256; //进入中断再次初始化计数 TRO=1 所以计数会不停 下次中断仍然是50ms后TL0=(65536-45872)%256; //16位计数器低8位初始计数num0++; if(num0 == 20) //中断20次后 50ms20次为1s{ num0=0;seconds++;if(seconds==60) //60秒加1分钟{seconds=0;minutes++;if(minutes==60) //60分钟加1小时{minutes=0;hours++;if(hours==24) //超过24小时增加一天{hours=0; day_add();}write_data(2,4,hours);}write_data(2,7,minutes);}write_data(2,10,seconds);}
}
void keyscan()
{if(key1==0) //第一个按键轮流7种状态 按一下秒闪烁 分钟闪烁 小时闪烁 月 日 年 不闪烁则继续加秒数 0 1 2 3 4 5{delayms(10);if(key1==0){mybeep();blink++; //循环blink状态if(blink ==7) {blink=0; write_com(0x0c); //取消光标闪烁TR0=1; //继续计时}if(blink != 0){TR0=0; //暂停计时
// cursor_blink();}}while(!key1); //等待按键弹起}if(key2==0) //第二个按键在闪烁时增加 小时、分钟等数字 各数字不联动{delayms(10);if(key2==0) //确认按下按键{mybeep();switch (blink){case 1: seconds++; //秒settime_add(); break;case 2: minutes++; //分settime_add();break;case 3: hours++; //时settime_add();break;case 4: days++; //天settime_add();break;case 5: months++; //月settime_add();break; case 6: years++; //年settime_add();break; default : ; //光标不闪烁的时候按增加键 不处理 }}while(!key2); //按键弹起后继续}
// if(key3==0)
// {// delayms(10);
// if(key3==0) //按键3 减小数字
// {// mybeep();
// switch (blink)
// {// case 1: seconds--; //秒
// settime_minus();
// break;
// case 2: minutes--; //分
// settime_minus();
// break;
// case 3: hours--; //时
// settime_minus();
// break;
// case 4: days--; //天
// settime_minus();
// break;
// case 5: months--; //月
// settime_minus();
// break;
// case 6: years--; //年
// settime_minus();
// break;
// default : ; //光标不闪烁的时候按减小键 不处理
// }
// }
// while(!key3);
// }
}void settime_add() //增大时间时,不进位 只处理溢出情况
{if(seconds==60) seconds=0;if(minutes==60) minutes=0;if(hours==24) hours=0; comparemonth=month[months-1]; //comparemonth除了2月不确定,其他每月天数都是数组中的数字if(months==2) { if(years%4==0) comparemonth=29; } //闰年二月29天if(days>comparemonth) days=1; if(months>12) months=1; if(years%100==0) write_data(1,3,years/100); //年份后两位进位就增加年份前两位更新write_data(1,5,years%100); //年份后两位没进位,只要更新后两位write_data(2,4,hours);write_data(2,7,minutes);write_data(2,10,seconds); write_data(1,8,months); //更新月份write_data(1,11,days); //更新天数calweek(); //计算周几并更新
}
void settime_minus() //减小时间时,不退位 只处理溢出情况
{if(seconds<0) seconds=59;if(minutes<0) minutes=59;if(hours<0) hours=23; comparemonth=month[months-1]; //comparemonth除了2月不确定,其他每月天数都是数组中的数字if(months==2) { if(years%4==0) comparemonth=29; } //闰年二月29天if(days==0) days=comparemonth; if(months==0) months=12; if(years%100==0) write_data(1,3,years/100); //年份后两位进位就增加年份前两位更新write_data(1,5,years%100); //年份后两位没进位,只要更新后两位write_data(2,4,hours);write_data(2,7,minutes);write_data(2,10,seconds); write_data(1,8,months); //更新月份write_data(1,11,days); //更新天数calweek(); //计算周几并更新
}
void calweek()
{char numi; //显示字符串for 循环用if(months==1 || months==2) //如果是1 2月份,要看成前一年的13 14月{m=months+12;years--;}else m=months;weeks=(days+2*m+3*(m+1)/5+years+years/4-years/100+years/400+1)%7; //基姆拉尔森公式算星期几write_com(0x80+0x40+13);for(numi=0;numi<3;numi++) //for循环写入字符串每一个字符{ write_data1(week[weeks][numi]);delayms(5);}
}
void cursor_blink()
{switch (blink){case 1: write_com(0x80+0x40+11); //秒 光标定位到秒write_com(0x0f); //光标开始闪烁break;case 2: write_com(0x80+0x40+8); //分write_com(0x0f); break;case 3: write_com(0x80+0x40+5); //时write_com(0x0f); break;case 4: write_com(0x80+12); //天write_com(0x0f); break;case 5: write_com(0x80+9); //月write_com(0x0f); break; case 6: write_com(0x80+6); //年write_com(0x0f); break; default : ; //光标不闪烁 }
}void day_add()
{comparemonth=month[months-1];if(months==2) //闰年二月29天{if(years%4==0)comparemonth=29;} days++;if(days>comparemonth) //days超过当月天数 回归1日 月份加一{days=1;months++;if(months>12) //加一年{months=1;years++;if(years%100==0) //加一个世纪{write_data(1,3,years/100); //年份后两位近位就前两位更新}write_data(1,5,years%100); //年份后两位没进位,只要更新后两位}write_data(1,8,months); //更新月份}write_data(1,11,days); //更新天数calweek(); //计算周几
}void write_com(uchar cmd)
{lcdrs=0; //lcd数据命令选择端 rs为L(ledrs=0)则写命令 H(ledrs=1)则写数据P0=cmd; //P0数据与lcd数据口相连delayms(1);lcden=1; //写入命令delayms(1); lcden=0; //关闭写入
}
void write_data1(uchar data2)
{lcdrs=1; //lcd数据命令选择端 rs为L(ledrs=0)则写命令 H(ledrs=1)则写数据P0=data2; delayms(1);lcden=1;delayms(1);lcden=0;
}
void write_data(uchar line,uchar add, uchar data1) //写数据 第几行 第几个开始 数据 data1必须是1-2位数 此程序中不会溢出
{uchar address,shi,ge;shi=data1/10;ge=data1%10;address=0x80+(line-1)*0x40+add; //根据行数和add参数定位写数据位置write_com(address); write_data1(0x30+shi); 输出十位字符****写完后光标自动下移一个,无需再定位地址****write_data1(0x30+ge); 输出个位字符
}
void display(uchar *table,uchar line) //显示字符串子函数 table为字符串,最大16字符 line为显示的行数,1为第一行 2为第二行 函数目前容错
{uchar strlen1;uchar num;strlen1=strlen(table); //strlen函数得到当前字符串长度if(strlen1>16) strlen1=16; //超出16字符后只取前16字符if(line==1) //第一行写入地址0x80write_com(0x80);else if(line==2) //第二行写入地址0xc0write_com(0x80+0x40);if(line==1 || line==2) //line参数1或者2才操作,不然不处理{for(num=0;num<strlen1;num++) //for循环写入字符串每一个字符{write_data1(table[num]);delayms(1);}}else //行数溢出 bibi两声{mybeep();mybeep();}
}
void delayms(uint ms) //延迟毫秒函数 参数为需要延迟的毫秒数
{uint i,j;for(i=ms;i>0;i--)for(j=110;j>0;j--);
}
void mybeep() //蜂鸣器发声
{sbeep=0;delayms(100);sbeep=1;
}
51单片机LCD1602显示电子时钟 带按键设置和星期显示相关推荐
- 51单片机+ds1302+lcd1602简易电子时钟(带闹钟功能)
51单片机+ds1302+lcd1602简易电子时钟(带闹钟功能) AT89C52.LCD1602.DS1302.speaker. Proteus仿真 实例代码 #include<reg52.H ...
- 基于51单片机的数字电子时钟
基于51单片机的数字电子时钟 单片机课程设计要求使用51单片机完成一个电子时钟,要求满足基本功能的同时增添丰富的功能参考了很多大佬的方案代码才勉强完成,工程文件下载点击此链接欢迎交流.如遇下载问题可以 ...
- 51单片机实战之电子时钟
自制电子时钟–总结 源代码https://gitee.com/kiloGrand/electronic-clock 使用到的模块及其功能: DS1302:低功耗实时时钟芯片,它可以对年.月.日.周.时 ...
- 基于51的数码管电子时钟(显示时、分、秒)——定时器
视频效果: 基于51单片机的数码管时钟设计 Proteus 仿真电路图: C51代码: #include<reg51.h>typedef unsigned char uchar; type ...
- 电子时钟万年历+51单片机+1602液晶屏+DS1302+DS18B20+按键
电子时钟万年历+51单片机+1602液晶屏+DS1302+DS18B20+按键 这次课程设计要完成的是制作一个基于51单片机的电子时钟的万年历(protues仿真),需要用到1602液晶屏+DS130 ...
- 基于51单片机LCD1602电子时钟实物制作
之前写了51单片机的LCD1602的程序,现在画了电路图,焊接了电路板,做出了基于51单片机LCD1602电子时钟的实物. 注意事项: 焊接过程中,注意提前布局电路. 对应好端口(避免接线错误),我由 ...
- 基于51单片机的简易电子计算器——有温度显示和万年历等额外功能
基于51单片机的简易电子计算器--有温度显示和万年历等额外功能 设计实际所实现的功能 模式一可显示日期.时钟.温度,模式二可进行计算器的计算,且显示日期温度模式和计算器模式可随意切换,模式三可以滚动显 ...
- 51驱动DS1302制作电子时钟1602显示
51驱动DS1302制作电子时钟1602显示 模组选型 模组选型解析 设计思路 产品接线 部分代码解析 总结 原文链接:https://www.yourcee.com/newsinfo/2928557 ...
- 【031】基于51单片机的超声波倒车雷达系统(带温度显示补偿)Proteus仿真设计
一.压缩包资料内容 (1).基于51单片机的超声波倒车雷达系统(带温度显示补偿)系统proteus仿真设计一份: (2).基于51单片机的超声波倒车雷达系统(带温度显示补偿)系统proteus仿真设计 ...
最新文章
- 浅析企业网站建设潜在价值有哪些?
- 在 Android 开发中使用 Kotlin 协程 (一) -- 初识 Kotlin 协程
- 比较TFS与SVN,你必须知道的10点区别
- mysql将最大金额加1000_Mysql数据库笔记
- java中窗口怎么添加动态图_java 点击按钮在窗口中加载图片
- Excel 如何解决下标越界问题
- 新版quartus_prime破解与altera官网下载器件库
- oracle数据导出工具sqluldr2安装及使用
- 仙童的ua741运算放大器内部电路
- 计算机usb接口不工作原理,电脑usb接口不能用,详细教您电脑usb接口不能用怎么办...
- ffmpeg 多个音频合并 截取 拆分
- AHRS系统的基本构成
- sa8155 qnx开发笔记之一设备共享
- 如何彻底解决顽固mysql
- mysql leng() 与 char_length() 的区别,注意一下。
- 华为VRRP+BFD配置
- Day651.NoSQL与RDBMS合理搭配问题 -Java业务开发常见错误
- 阿里云接口手机归属地查询API
- 实训总结(图书管理系统java)
- Windows下查看端口占用情况
热门文章
- KSO-Linux下Centos7.5防火墙开放某个端口号权限
- leetcode: Largest Rectangle in Histogram,Maximal Square,Maximal Square问题
- Java生成与解析二维码
- python小白系列2
- 数据分析真题日刷 | 京东2019春招京东数据分析类试卷
- windows和linux系统文件目录
- HTML文件里开头的!Doctype有什么作用?
- android SurfaceView + Camera全屏自适应屏幕尺寸
- 【直播报名】Location Cache 模块浅析及 OCP 监控、报警详解
- 长沙 22 岁女子长期过量喝奶茶进ICU,血糖值过高,血液呈乳白色几乎变「甜饮」,奶茶喝多少会有危险?