1602液晶时钟程序
程序按郭天袢《新概念51单片机C语言教程》第十四章扩展显示年、月、日、星期调节功能。
1) 时间显示在1602液晶上,并按秒实时更新
2) 能调节按键调整时、分、秒、年、月、日和星期
3) 每次按键按下时有短滴声响声
4) 断电后下次上电会接着上次断电前的时间数继续运行
原理图如图
//原代码如下:
#include
//#include"24c02.h"
#define uchar unsigned char
#define uint unsigned int
#include"24c02.h"
sbit dula=P2^6;
sbit wela=P2^7;
sbit LCDEN=P3^4;
sbit LCDRS=P3^5;
sbit s1=P3^0;//定义按键--功能键
sbit s2=P3^1;//定义按键--增大键
sbit s3=P3^2;//定义按键--减小键
sbit rd=P3^7;//按键公共脚
sbit beep=P2^3;//定义蜂鸣器脚
uchar count,s1_num;//定义中断次数计数变量 功能键按键次数变量
uchar week,day,month,year;//定义变量:星期 日 月 年
char miao,shi,fen;//定义秒分时变量
uchar code table[]=" 2012-11-28 Wed";
//void write_week(char we);//显示星期几函数
void delay(uint z)
{
uint x,y;
for(x=z;x>0;x--)
for(y=110;y>0;y--);
}
void di()//蜂鸣器响一声函数
{
beep=0;
delay(100);
beep=1;
}
void write_com(uchar com) //液晶写命令函数
{
LCDRS=0;
P0=com;
delay(5);
LCDEN=1;
delay(5);
LCDEN=0;
}
void write_date(uchar date) //液晶写数据函数
{
LCDRS=1;
P0=date;
delay(5);
LCDEN=1;
delay(5);
LCDEN=0;
}
void write_week(char we) //写星期几显示函数
{
write_com(0x80+12);
switch(we)
{
case 1: write_date('M');delay(5); //星期一 Monday
write_date('o');delay(5);
write_date('n');delay(5);
break;
case 2: write_date('T');delay(5); //星期二 Tuesday
write_date('u');delay(5);
write_date('e');delay(5);
break;
case 3: write_date('W');delay(5); //Wednesday
write_date('e');delay(5);
write_date('d');delay(5);
break;
case 4: write_date('T');delay(5); //Thursday
write_date('h');delay(5);
write_date('u');delay(5);
break;
case 5: write_date('F');delay(5); //星期五 Friday
write_date('r');delay(5);
write_date('i');delay(5);
break;
case 6: write_date('S');delay(5); //星期六 Saturday
write_date('a');delay(5);
write_date('t');delay(5);
break;
case 7: write_date('S');delay(5); //星期日 Sunday
write_date('u');delay(5);
write_date('n');delay(5);
break;
default: break;
}
}
void write_sfm(uchar add,uchar date) //写时分秒函数
{
uchar shiwei,gewei;
shiwei=date/10;
gewei=date%10;
write_com(0x80+0x40+add);//设置显示位置
write_date(0x30+shiwei);//加上0x30是因为数字变成字符串需要加上0x30,看ASCII码值与字符的关系
write_date(0x30+gewei);
}
void write_year_month_day(uchar add,uchar day) //写年月日数函数
{
uchar shi,ge;
shi=day/10;
ge=day%10;
write_com(0x80+add);//设置显示位置
write_date(0x30+shi);//加上0x30是因为数字变成字符串需要加上0x30,看ASCII码值与字符的关系
write_date(0x30+ge);
}
void init() //初始化函数
{
uchar num;
rd=0;
beep=1;
dula=0;
wela=0;
LCDEN=0;//将使能端置0以完成高脉冲
fen=0;
miao=0;
shi=0;
count=0;//计数初始为0
init_24c02();
write_com(0x38);//设置16*2显示,5*7点阵,8位数据接口
write_com(0x0c);//设置开显示,不显示光标
write_com(0x06);//写一个字符后地址指针自动加1
write_com(0x01);//显示清0,数据指针清0
write_com(0x80); //设置显示初始坐标
for(num=0;num
{
write_date(table[num]);
delay(5);
}
write_com(0x80+0x40+6); //写出时间显示部分的两个冒号
write_date(0x3a);
delay(5);
write_com(0x80+0x40+9);
write_date(0x3a);
delay(5);
miao=read_add(1);//开机上电时读取24c02 IIC的数据赋值
fen=read_add(2);
shi=read_add(3);
week=read_add(4);//读取星期几
day=read_add(5);//读取多少日
month=read_add(6);
year=read_add(7);
write_sfm(10,miao);//分别送去液晶显示
write_sfm(7,fen);
write_sfm(4,shi);
write_week(week);//开机从24c02读取的星期几数从新写入液晶显示出来
write_year_month_day(9,day);
write_year_month_day(6,month);
write_year_month_day(3,year);
//定时器初始化
TMOD=0x01; //设置定时器0工作模式1
TH0=(65536-45876)/256; //定时器装初值
TL0=(65536-45876)%256;
EA=1; //开总中断
ET0=1; //打定时器0中断
TR0=1; //启动定时器0
}
void keyscan() //按键扫描函数
{
if(s1==0)
{
delay(5);
if(s1==0)
{
s1_num++; //功能键按下次数记录
while(!s1); //按键释放确认
di();
if(s1_num==1) //只按一次按键时
TR0=0; //关闭定时器
write_com(0x80+0x40+11);
write_com(0x0f); //打开光标闪烁
}
if(s1_num==2) //第二次按下光标闪烁定位到分钟位置
{
write_com(0x80+0x40+8);
}
if(s1_num==3) //第三次按下光标闪烁定位到小时位置
{
write_com(0x80+0x40+5);
}
/**************************************
if(s1_num==4) //第三四次按下退出
{
s1_num=0;
write_com(0x0c); //取消光标闪栎
TR0=1; //启动定时器使时钟开始走
}
***************************************/
if(s1_num==4) //光标处星期
{
write_com(0x80+14);
}
if(s1_num==5) //光标处日
{
write_com(0x80+10);
}
if(s1_num==6) //光标处月
{
write_com(0x80+7);
}
if(s1_num==7) //光标处年
{
write_com(0x80+4);
}
if(s1_num==8) //当第八次按功能键时退出光标闪烁及开始计时
{
s1_num=0;
write_com(0x0c); //取消光标闪栎
TR0=1; //启动定时器使时钟开始走
}
}
if(s1_num!=0)
{
if(s2==0)//增加键确认按下
{
delay(5);
if(s2==0)
{
while(!s2);
di();
if(s1_num==1)
{
miao++;
if(miao==60)
miao=0;
write_sfm(10,miao);
write_com(0x80+0x40+11);
write_add(1,miao);
}
if(s1_num==2)
{
fen++;
if(fen==60)
fen=0;
write_sfm(7,fen);
write_com(0x80+0x40+8);
write_add(2,fen);
}
if(s1_num==3)
{
shi++;
if(shi==24)
shi=0;
write_sfm(4,shi);
write_com(0x80+0x40+5);
write_add(3,shi);
}
if(s1_num==4)//按四次功能键后光标至星期几处,可调节星期几 {
week++;
if(week==8)
week=1;
write_week(week);
write_com(0x80+14); //写一个字符后光标会移一位,所以要重新定义光标位置
write_add(4,week);
}
if(s1_num==5) //光标至显示日处,可调节多少日
{
day++;
if(day==32)
day=1;
write_year_month_day(9,day);
write_com(0x80+10);
write_add(5,day);
}
if(s1_num==6) //光标至显示月处调节月份
{
month++;
if(month==13)
month=1;
write_year_month_day(6,month);
write_com(0x80+7);
write_add(6,month);
}
if(s1_num==7)
{
year++;
if(year==100)
year=00;
write_year_month_day(3,year);
write_com(0x80+4);
write_add(7,year);
}
}
}
if(s3==0) //确认减小键被按下
{
delay(5);//按键防抖延时
if(s3==0) //确认减小键被按下
{
while(!s3);
di();
if(s1_num==1)
{
miao--;
if(miao==-1)
miao=59;
write_sfm(10,miao);
write_com(0x80+0x40+11); write_add(1,miao);
}
if(s1_num==2)
{
fen--;
光标位置
if(fen==-1) fen=59; write_sfm(7,fen); write_com(0x80+0x40+8); write_add(2,fen); } if(s1_num==3) { shi--; if(shi==-1) shi=23; write_sfm(4,shi); write_com(0x80+0x40+5); write_add(3,shi); } if(s1_num==4) { week--; if(week==0) week=7; write_week(week); write_com(0x80+14); //写一个字符后光标会移一位,所以要重新定义 write_add(4,week); } if(s1_num==5)//光标至显示日处,可调节多少日 { day--; if(day==0) day=31; write_year_month_day(9,day); write_com(0x80+10);//光标位置移回在显示多少日的个位 write_add(5,day); } if(s1_num==6) //光标至显示月处调节月份
{
month--;
if(month==0)
month=12;
write_year_month_day(6,month); write_com(0x80+7);
write_add(6,month);
}
if(s1_num==7)
{
year--;
if(year==-1)
year=99;
write_year_month_day(3,year); write_com(0x80+4);
write_add(7,year);
}
}
}
}
}
void main()
{
init();//首先初始化各数据
while(1)
{
keyscan(); //按键扫描函数
}
}
void timer0() interrupt 1 //定时器0中断服务程序 {
TH0=(65536-45876)/256;
TL0=(65536-45876)%256;
count++; //中断次数累加,计数
if(count==20) //50微秒乘以20等于1秒 {
count=0;
miao++;
if(miao==60) //秒加到60则进位分钟 {
miao=0; //同时秒数清0
fen++;
if(fen==60) //分钟加到60则进位小时
{
fen=0; //同时分钟清0
shi++;
if(shi==24) //小时加到24则小时清0
{
shi=0;
}
write_sfm(4,shi);//小时若变化则重新写入
write_add(3,shi);//写入24c02存储起来,小时数的写入地址为3 }
write_sfm(7,fen);//分钟若变化则重新写入
write_add(2,fen);
}
write_sfm(10,miao);//秒若变化则重新写入
write_add(1,miao);
}
}
/***********************************
24C02.h头文件,将以下源代码需存为
与保存的C代码根目录下。
***********************************/
/bit write=0; //写24c02的标志
//#define uchar unsigned char
//#define uint unsigned int
sbit sda=P2^0;
sbit scl=P2^1;
void delay0()
{;;}
void start() //开始信号
{
sda=1;
delay0();
scl=1;
delay0();
sda=0;
delay0();
}
void stop() //停止信号
{
sda=0;
delay0();
scl=1;
delay0();
sda=1;
delay0();
}
void respons() //应答信号
{
uchar i=0;
scl=1;
delay0();
while((sda==1)&&(i
scl=0;
delay0();
}
void init_24c02() //IIC初始化函数
{
sda=1;
delay0();
scl=1;
delay0();
}
void write_byte(uchar date) //写一个字节函数
{
uchar i,temp;
temp=date;
for(i=0;i
{
temp=temp
scl=0;
delay0();
sda=CY;
delay0();
scl=1;
delay0();
}
scl=0;
delay0();
sda=1;
delay0();
}
uchar read_byte() //读一个字节
{
uchar i,k;
scl=0;
delay0();
sda=1;
for(i=0;i
{
scl=1;
delay0();
k=(k
scl=0;
delay0();
}
return k;
}
void write_add(uchar address,uchar date) //指定地址写一个字节 {
start();
write_byte(0xa0);
respons();
write_byte(address);
respons();
write_byte(date);
respons();
stop();
}
uchar read_add(uchar address) //指定地址读一个字节 {
uchar date;
start();
write_byte(0xa0);
respons();
write_byte(address);
respons();
start();
write_byte(0xa1);
respons();
date=read_byte();
stop();
return date;
}
选择功能键时光标闪烁时
:
1602液晶时钟程序
程序按郭天袢《新概念51单片机C语言教程》第十四章扩展显示年、月、日、星期调节功能。
1) 时间显示在1602液晶上,并按秒实时更新
2) 能调节按键调整时、分、秒、年、月、日和星期
3) 每次按键按下时有短滴声响声
4) 断电后下次上电会接着上次断电前的时间数继续运行
原理图如图
//原代码如下:
#include
//#include"24c02.h"
#define uchar unsigned char
#define uint unsigned int
#include"24c02.h"
sbit dula=P2^6;
sbit wela=P2^7;
sbit LCDEN=P3^4;
sbit LCDRS=P3^5;
sbit s1=P3^0;//定义按键--功能键
sbit s2=P3^1;//定义按键--增大键
sbit s3=P3^2;//定义按键--减小键
sbit rd=P3^7;//按键公共脚
sbit beep=P2^3;//定义蜂鸣器脚
uchar count,s1_num;//定义中断次数计数变量 功能键按键次数变量
uchar week,day,month,year;//定义变量:星期 日 月 年
char miao,shi,fen;//定义秒分时变量
uchar code table[]=" 2012-11-28 Wed";
//void write_week(char we);//显示星期几函数
void delay(uint z)
{
uint x,y;
for(x=z;x>0;x--)
for(y=110;y>0;y--);
}
void di()//蜂鸣器响一声函数
{
beep=0;
delay(100);
beep=1;
}
void write_com(uchar com) //液晶写命令函数
{
LCDRS=0;
P0=com;
delay(5);
LCDEN=1;
delay(5);
LCDEN=0;
}
void write_date(uchar date) //液晶写数据函数
{
LCDRS=1;
P0=date;
delay(5);
LCDEN=1;
delay(5);
LCDEN=0;
}
void write_week(char we) //写星期几显示函数
{
write_com(0x80+12);
switch(we)
{
case 1: write_date('M');delay(5); //星期一 Monday
write_date('o');delay(5);
write_date('n');delay(5);
break;
case 2: write_date('T');delay(5); //星期二 Tuesday
write_date('u');delay(5);
write_date('e');delay(5);
break;
case 3: write_date('W');delay(5); //Wednesday
write_date('e');delay(5);
write_date('d');delay(5);
break;
case 4: write_date('T');delay(5); //Thursday
write_date('h');delay(5);
write_date('u');delay(5);
break;
case 5: write_date('F');delay(5); //星期五 Friday
write_date('r');delay(5);
write_date('i');delay(5);
break;
case 6: write_date('S');delay(5); //星期六 Saturday
write_date('a');delay(5);
write_date('t');delay(5);
break;
case 7: write_date('S');delay(5); //星期日 Sunday
write_date('u');delay(5);
write_date('n');delay(5);
break;
default: break;
}
}
void write_sfm(uchar add,uchar date) //写时分秒函数
{
uchar shiwei,gewei;
shiwei=date/10;
gewei=date%10;
write_com(0x80+0x40+add);//设置显示位置
write_date(0x30+shiwei);//加上0x30是因为数字变成字符串需要加上0x30,看ASCII码值与字符的关系
write_date(0x30+gewei);
}
void write_year_month_day(uchar add,uchar day) //写年月日数函数
{
uchar shi,ge;
shi=day/10;
ge=day%10;
write_com(0x80+add);//设置显示位置
write_date(0x30+shi);//加上0x30是因为数字变成字符串需要加上0x30,看ASCII码值与字符的关系
write_date(0x30+ge);
}
void init() //初始化函数
{
uchar num;
rd=0;
beep=1;
dula=0;
wela=0;
LCDEN=0;//将使能端置0以完成高脉冲
fen=0;
miao=0;
shi=0;
count=0;//计数初始为0
init_24c02();
write_com(0x38);//设置16*2显示,5*7点阵,8位数据接口
write_com(0x0c);//设置开显示,不显示光标
write_com(0x06);//写一个字符后地址指针自动加1
write_com(0x01);//显示清0,数据指针清0
write_com(0x80); //设置显示初始坐标
for(num=0;num
{
write_date(table[num]);
delay(5);
}
write_com(0x80+0x40+6); //写出时间显示部分的两个冒号
write_date(0x3a);
delay(5);
write_com(0x80+0x40+9);
write_date(0x3a);
delay(5);
miao=read_add(1);//开机上电时读取24c02 IIC的数据赋值
fen=read_add(2);
shi=read_add(3);
week=read_add(4);//读取星期几
day=read_add(5);//读取多少日
month=read_add(6);
year=read_add(7);
write_sfm(10,miao);//分别送去液晶显示
write_sfm(7,fen);
write_sfm(4,shi);
write_week(week);//开机从24c02读取的星期几数从新写入液晶显示出来
write_year_month_day(9,day);
write_year_month_day(6,month);
write_year_month_day(3,year);
//定时器初始化
TMOD=0x01; //设置定时器0工作模式1
TH0=(65536-45876)/256; //定时器装初值
TL0=(65536-45876)%256;
EA=1; //开总中断
ET0=1; //打定时器0中断
TR0=1; //启动定时器0
}
void keyscan() //按键扫描函数
{
if(s1==0)
{
delay(5);
if(s1==0)
{
s1_num++; //功能键按下次数记录
while(!s1); //按键释放确认
di();
if(s1_num==1) //只按一次按键时
TR0=0; //关闭定时器
write_com(0x80+0x40+11);
write_com(0x0f); //打开光标闪烁
}
if(s1_num==2) //第二次按下光标闪烁定位到分钟位置
{
write_com(0x80+0x40+8);
}
if(s1_num==3) //第三次按下光标闪烁定位到小时位置
{
write_com(0x80+0x40+5);
}
/**************************************
if(s1_num==4) //第三四次按下退出
{
s1_num=0;
write_com(0x0c); //取消光标闪栎
TR0=1; //启动定时器使时钟开始走
}
***************************************/
if(s1_num==4) //光标处星期
{
write_com(0x80+14);
}
if(s1_num==5) //光标处日
{
write_com(0x80+10);
}
if(s1_num==6) //光标处月
{
write_com(0x80+7);
}
if(s1_num==7) //光标处年
{
write_com(0x80+4);
}
if(s1_num==8) //当第八次按功能键时退出光标闪烁及开始计时
{
s1_num=0;
write_com(0x0c); //取消光标闪栎
TR0=1; //启动定时器使时钟开始走
}
}
if(s1_num!=0)
{
if(s2==0)//增加键确认按下
{
delay(5);
if(s2==0)
{
while(!s2);
di();
if(s1_num==1)
{
miao++;
if(miao==60)
miao=0;
write_sfm(10,miao);
write_com(0x80+0x40+11);
write_add(1,miao);
}
if(s1_num==2)
{
fen++;
if(fen==60)
fen=0;
write_sfm(7,fen);
write_com(0x80+0x40+8);
write_add(2,fen);
}
if(s1_num==3)
{
shi++;
if(shi==24)
shi=0;
write_sfm(4,shi);
write_com(0x80+0x40+5);
write_add(3,shi);
}
if(s1_num==4)//按四次功能键后光标至星期几处,可调节星期几 {
week++;
if(week==8)
week=1;
write_week(week);
write_com(0x80+14); //写一个字符后光标会移一位,所以要重新定义光标位置
write_add(4,week);
}
if(s1_num==5) //光标至显示日处,可调节多少日
{
day++;
if(day==32)
day=1;
write_year_month_day(9,day);
write_com(0x80+10);
write_add(5,day);
}
if(s1_num==6) //光标至显示月处调节月份
{
month++;
if(month==13)
month=1;
write_year_month_day(6,month);
write_com(0x80+7);
write_add(6,month);
}
if(s1_num==7)
{
year++;
if(year==100)
year=00;
write_year_month_day(3,year);
write_com(0x80+4);
write_add(7,year);
}
}
}
if(s3==0) //确认减小键被按下
{
delay(5);//按键防抖延时
if(s3==0) //确认减小键被按下
{
while(!s3);
di();
if(s1_num==1)
{
miao--;
if(miao==-1)
miao=59;
write_sfm(10,miao);
write_com(0x80+0x40+11); write_add(1,miao);
}
if(s1_num==2)
{
fen--;
光标位置
if(fen==-1) fen=59; write_sfm(7,fen); write_com(0x80+0x40+8); write_add(2,fen); } if(s1_num==3) { shi--; if(shi==-1) shi=23; write_sfm(4,shi); write_com(0x80+0x40+5); write_add(3,shi); } if(s1_num==4) { week--; if(week==0) week=7; write_week(week); write_com(0x80+14); //写一个字符后光标会移一位,所以要重新定义 write_add(4,week); } if(s1_num==5)//光标至显示日处,可调节多少日 { day--; if(day==0) day=31; write_year_month_day(9,day); write_com(0x80+10);//光标位置移回在显示多少日的个位 write_add(5,day); } if(s1_num==6) //光标至显示月处调节月份
{
month--;
if(month==0)
month=12;
write_year_month_day(6,month); write_com(0x80+7);
write_add(6,month);
}
if(s1_num==7)
{
year--;
if(year==-1)
year=99;
write_year_month_day(3,year); write_com(0x80+4);
write_add(7,year);
}
}
}
}
}
void main()
{
init();//首先初始化各数据
while(1)
{
keyscan(); //按键扫描函数
}
}
void timer0() interrupt 1 //定时器0中断服务程序 {
TH0=(65536-45876)/256;
TL0=(65536-45876)%256;
count++; //中断次数累加,计数
if(count==20) //50微秒乘以20等于1秒 {
count=0;
miao++;
if(miao==60) //秒加到60则进位分钟 {
miao=0; //同时秒数清0
fen++;
if(fen==60) //分钟加到60则进位小时
{
fen=0; //同时分钟清0
shi++;
if(shi==24) //小时加到24则小时清0
{
shi=0;
}
write_sfm(4,shi);//小时若变化则重新写入
write_add(3,shi);//写入24c02存储起来,小时数的写入地址为3 }
write_sfm(7,fen);//分钟若变化则重新写入
write_add(2,fen);
}
write_sfm(10,miao);//秒若变化则重新写入
write_add(1,miao);
}
}
/***********************************
24C02.h头文件,将以下源代码需存为
与保存的C代码根目录下。
***********************************/
/bit write=0; //写24c02的标志
//#define uchar unsigned char
//#define uint unsigned int
sbit sda=P2^0;
sbit scl=P2^1;
void delay0()
{;;}
void start() //开始信号
{
sda=1;
delay0();
scl=1;
delay0();
sda=0;
delay0();
}
void stop() //停止信号
{
sda=0;
delay0();
scl=1;
delay0();
sda=1;
delay0();
}
void respons() //应答信号
{
uchar i=0;
scl=1;
delay0();
while((sda==1)&&(i
scl=0;
delay0();
}
void init_24c02() //IIC初始化函数
{
sda=1;
delay0();
scl=1;
delay0();
}
void write_byte(uchar date) //写一个字节函数
{
uchar i,temp;
temp=date;
for(i=0;i
{
temp=temp
scl=0;
delay0();
sda=CY;
delay0();
scl=1;
delay0();
}
scl=0;
delay0();
sda=1;
delay0();
}
uchar read_byte() //读一个字节
{
uchar i,k;
scl=0;
delay0();
sda=1;
for(i=0;i
{
scl=1;
delay0();
k=(k
scl=0;
delay0();
}
return k;
}
void write_add(uchar address,uchar date) //指定地址写一个字节 {
start();
write_byte(0xa0);
respons();
write_byte(address);
respons();
write_byte(date);
respons();
stop();
}
uchar read_add(uchar address) //指定地址读一个字节 {
uchar date;
start();
write_byte(0xa0);
respons();
write_byte(address);
respons();
start();
write_byte(0xa1);
respons();
date=read_byte();
stop();
return date;
}
选择功能键时光标闪烁时
: