基于AT89C51的电子钟(C语言编程)
来源:互联网 发布:linux shell while 编辑:程序博客网 时间:2024/05/22 11:38
先看看电路图
P3.0是设置选择位,按一次选择一个,再按一次,顺序往下执行
#include<reg52.h>
#include "intrins.h"
#define uchar unsigned char
#define uint unsigned int
int i,sec,min,h,date,month,year,flag;
uchar code digit[10]={"0123456789"};
sbit RS=P2^0; //寄存器选择位,将RS位定义为P2.0引脚
sbit RW=P2^1; //读写选择位,将RW位定义为P2.1引脚
sbit E=P2^2; //使能信号位,将E位定义为P2.2引脚
sbit BF=P0^7; //忙碌标志位,,将BF位定义为P0.7引脚
sbit key_ch=P3^0;
sbit key_add=P3^1;
sbit key_minus=P3^2;
sbit key5=P1^5;
sbit key6=P1^6;
sbit key7=P1^7;
void control(void);
void delay1ms()
{
unsigned char i,j;
for(i=0;i<10;i++)
for(j=0;j<33;j++)
;
}
/*****************************************************
函数功能:延时若干毫秒
入口参数:n
***************************************************/
void delay(uint n)
{
uint i;
for(i=0;i<n;i++)
delay1ms();
}
/*****************************************************
函数功能:判断液晶模块的忙碌状态
返回值:result。result=1,忙碌;result=0,不忙
***************************************************/
bit BusyTest(void)
{
bit result;
RS=0; //根据规定,RS为低电平,RW为高电平时,可以读状态
RW=1;
E=1; //E=1,才允许读写
_nop_(); //空操作
_nop_();
_nop_();
_nop_(); //空操作四个机器周期,给硬件反应时间
result=BF; //将忙碌标志电平赋给result
E=0;
return result;
}
/*****************************************************
函数功能:将模式设置指令或显示地址写入液晶模块
入口参数:dictate
***************************************************/
void Write_com (uchar dictate)
{
while(BusyTest()==1); //如果忙就等待
RS=0; //根据规定,RS和R/W同时为低电平时,可以写入指令
RW=0;
E=0; //E置低电平(写指令时,就是让E从0到1发生正跳变,所以应先置"0"
_nop_();
_nop_(); //空操作两个机器周期,给硬件反应时间
P0=dictate; //将数据送入P0口,即写入指令或地址
_nop_();
_nop_();
_nop_();
_nop_(); //空操作四个机器周期,给硬件反应时间
E=1; //E置高电平
_nop_();
_nop_();
_nop_();
_nop_(); //空操作四个机器周期,给硬件反应时间
E=0; //当E由高电平跳变成低电平时,液晶模块开始执行命令
}
/*****************************************************
函数功能:指定字符显示的实际地址
入口参数:x
***************************************************/
void WriteAddress(uchar x)
{
Write_com(x|0x80); //显示位置的确定方法规定为"80H+地址码x"
}
/*****************************************************
函数功能:将数据(字符的标准ASCII码)写入液晶模块
入口参数:y(为字符常量)
***************************************************/
void WriteData(uchar y)
{
while(BusyTest()==1);
RS=1; //RS为高电平,RW为低电平时,可以写入数据
RW=0;
E=0; //E置低电平(写指令时,就是让E从0到1发生正跳变,所以应先置"0"
P0=y; //将数据送入P0口,即将数据写入液晶模块
_nop_();
_nop_();
_nop_();
_nop_(); //空操作四个机器周期,给硬件反应时间
E=1; //E置高电平
_nop_();
_nop_();
_nop_();
_nop_(); //空操作四个机器周期,给硬件反应时间
E=0; //当E由高电平跳变成低电平时,液晶模块开始执行命令
}
/*****************************************************
函数功能:对LCD的显示模式进行初始化设置
***************************************************/
void LcdInt(void)
{
delay(15); //延时15ms,首次写指令时应给LCD一段较长的反应时间
Write_com(0x38); //显示模式设置:16×2显示,5×7点阵,8位数据接口0011 1000
delay(5); //延时5ms
Write_com(0x38);
delay(5);
Write_com(0x38); //3次写 设置模式
delay(5);
Write_com(0x0c); //显示模式设置:显示开,有光标,光标闪烁
delay(5);
Write_com(0x06); //显示模式设置:光标右移,字符不移 0000 0110
delay(5);
Write_com(0x01); //清屏幕指令,将以前的显示内容清除
delay(5);
}
void init()//初始化子函数
{
i=0;
sec=0;
min=0;
h=12;
date=28;
month=4;
year=14;
flag=0;
EA=1;
ET0=1;
TMOD=0x01;
TH0=(65536-50000)/256;
TL0=(65536-50000)%256;
TR0=1;
}
/*****************************************************
函数功能:显示秒
入口参数:x
***************************************************/
void DisplaySecond(uchar x)
{
uchar i,j; //j,k,l分别储存温度的百位、十位和个位
i=x/10; //取十位
j=x%10; //取个位
WriteAddress(0x4c); //写显示地址,将在第2行第7列开始显示
WriteData(digit[i]); //将百位数字的字符常量写入LCD
WriteData(digit[j]); //将十位数字的字符常量写入LCD
delay(50); //延时1ms给硬件一点反应时间
}
/*****************************************************
函数功能:显示分钟
入口参数:x
***************************************************/
void DisplayMinute(uchar x)
{
uchar i,j; //j,k,l分别储存温度的百位、十位和个位
i=x/10; //取十位
j=x%10; //取个位
WriteAddress(0x49); //写显示地址,将在第2行第7列开始显示
WriteData(digit[i]); //将百位数字的字符常量写入LCD
WriteData(digit[j]); //将十位数字的字符常量写入LCD
delay(50); //延时1ms给硬件一点反应时间
}
/*****************************************************
函数功能:显示小时
入口参数:x
***************************************************/
void DisplayHour(uchar x)
{
uchar i,j; //j,k,l分别储存温度的百位、十位和个位
i=x/10; //取十位
j=x%10; //取个位
WriteAddress(0x46); //写显示地址,将在第2行第7列开始显示
WriteData(digit[i]); //将百位数字的字符常量写入LCD
WriteData(digit[j]); //将十位数字的字符常量写入LCD
delay(50); //延时1ms给硬件一点反应时间
}
/*****************************************************
函数功能:显示日
入口参数:x
***************************************************/
void DisplayDay(uchar x)
{
uchar i,j; //j,k,l分别储存温度的百位、十位和个位
i=x/10; //取十位
j=x%10; //取个位
WriteAddress(0x0c); //写显示地址,将在第2行第7列开始显示
WriteData(digit[i]); //将百位数字的字符常量写入LCD
WriteData(digit[j]); //将十位数字的字符常量写入LCD
delay(500); //延时1ms给硬件一点反应时间
}
/*****************************************************
函数功能:显示月
入口参数:x
***************************************************/
void DisplayMonth(uchar x)
{
uchar i,j; //j,k,l分别储存温度的百位、十位和个位
i=x/10; //取十位
j=x%10; //取个位
WriteAddress(0x09); //写显示地址,将在第2行第7列开始显示
WriteData(digit[i]); //将百位数字的字符常量写入LCD
WriteData(digit[j]); //将十位数字的字符常量写入LCD
delay(50); //延时1ms给硬件一点反应时间
}
/*****************************************************
函数功能:显示年
入口参数:x
***************************************************/
void DisplayYear(uchar x)
{
uchar i,j; //j,k,l分别储存温度的百位、十位和个位
i=x/10; //取十位
j=x%10; //取个位
WriteAddress(0x06); //写显示地址,将在第2行第7列开始显示
WriteData(digit[i]); //将百位数字的字符常量写入LCD
WriteData(digit[j]); //将十位数字的字符常量写入LCD
delay(50); //延时1ms给硬件一点反应时间
}
void displaytime()
{
WriteAddress(0x00); //写Date的显示地址,将在第1行第1列开始显示
WriteData('D'); //将字符常量写入LCD
WriteData('a'); //将字符常量写入LCD
WriteData('t'); //将字符常量写入LCD
WriteData('e'); //将字符常量写入LCD
WriteData(':'); //将字符常量写入LCD
WriteAddress(0x08); //写年月分隔符的显示地址, 显示在第1行第9列
WriteData('-'); //将字符常量写入LCD
WriteAddress(0x0b); //写月日分隔符的显示地址, 显示在第1行第12列
WriteData('-'); //将字符常量写入LCD
WriteAddress(0x40); //写Date的显示地址,将在第1行第2列开始显示
WriteData('T'); //将字符常量写入LCD
WriteData('i'); //将字符常量写入LCD
WriteData('m'); //将字符常量写入LCD
WriteData('e'); //将字符常量写入LCD
WriteData(':'); //将字符常量写入LCD
WriteAddress(0x48); //写小时与分钟分隔符的显示地址, 显示在第2行第6列
WriteData(':'); //将字符常量写入LCD
WriteAddress(0x4b); //写分钟与秒分隔符的显示地址, 显示在第2行第9列
WriteData(':'); //将字符常量写入LCD
while(1)
{
DisplaySecond(sec);
DisplayMinute(min);
DisplayHour(h);
DisplayDay(date);
DisplayMonth(month);
DisplayYear(year);
control();
}
}
void control(void) //时间日期调整
{
if(!key_ch) //set键按下
{ key5=0;
delay(5); //去抖
if(!key_ch)
{
flag++;
if(flag==7)
flag=0;
}
}
while(!key_ch);//松手检测
if(flag==1 && key_add==0)//设置秒加1
{
while(!key_add);//松手检测
sec++;
if(sec==60)
sec=0;
key6=0;
}
if(flag==1 && key_minus==0)//设置秒减1
{
while(!key_minus);//松手检测
sec--;
if(sec==-1)
sec=59;
key7=0;
}
if(flag==2 && key_add==0)//设置分加1
{
while(!key_add);//松手检测
min++;
if(min==60)
min=0;
}
if(flag==2 && key_minus==0)//设置分减1
{ delay(5); //去抖1
while(!key_minus);//松手检测
min--;
if(min==-1)
min=59;
}
if(flag==3 && key_add==0)//设置时加1
{
while(!key_add);//松手检测
h++;
if(h==24)
h=0;
}
if(flag==3 && key_minus==0)//设置时减1
{
while(!key_minus);//松手检测
h--;
if(h==-1)
h=23;
}
if(flag==4 && key_add==0)//设置日加1
{
while(!key_add);//松手检测
date++;
if((date==29))//平年2月判断
if((year%4!=0)&&(month==2))
date=1;
if((date==30))//闰年2月判断
if((year%4==0)&&(month==2))
date=1;
if((date==31))//小月判断
if((month==4)||(month==6)||(month==9)||(month==11))
date=1;
if((date==32))//大月判断
if((month==1)||(month==3)||(month==5)||(month==7)||(month==8)||(month==10)||(month==12))
date=1;
}
if(flag==5 && key_add==0)//设置月加1
{
while(!key_add);//松手检测
month++;
if(month==13)
month=1;
}
if(flag==6 && key_add==0)//设置年加1
{
while(!key_add);//松手检测
year++;
if(year==99)
year=0;
}
if(flag==6 && key_minus==0)//设置年减1
{
while(!key_minus);//松手检测
year--;
if(year==0)
year=99;
}
}
void time()
{
if(i==20)
{
i=0;
sec++;
if(sec==60)
{
sec=0;
min++;
if(min==60)
{
min=0;
h++;
if(h==24)
{
h=0;
min=0;
sec=0;
date++;
if((date==29))//平年2月判断
if((year%4!=0)&&(month==2))
{
date=1;
month++;
if(month==13)
{
month=1;
year++;
}
}
if((date==30))//闰年2月判断
if((year%4==0)&&(month==2))
{
date=1;
month++;
if(month==13)
{
month=1;
year++;
}
}
if((date==31))//小月判断
if((month==4)||(month==6)||(month==9)||(month==11))
{
date=1;
month++;
if(month==13)
{
month=1;
year++;
}
}
if((date==32))//大月判断
if((month==1)||(month==3)||(month==5)||(month==7)||(month==8)||(month==10)||(month==12))
{
date=1;
month++;
if(month==13)
{
month=1;
year++;
}
}
}
}
}
}
}
void T0_rpt() interrupt 1 //定时器0中断子函数
{
TH0=(65536-50000)/256;//重新装入初始值50000us=50ms 100ms
TL0=(65536-50000)%256;
i++;
time();
}
void main()
{
init();
LcdInt();
while(1)
{
displaytime();
}
}
这是程序,已经可以实现大部分需要的功能!按键需要按下1~2s,才有改变!
但是LCD上面更改时间和日期的时候没有闪烁,可以通过延迟显示的方法实现!
再加一个按键OK,在显示函数里面加入即可完美实现!
- 基于AT89C51的电子钟(C语言编程)
- 基于FPGA的电子钟设计
- 基于AT89C51单片机的微型可编程控制器
- AT89C51与字符型液晶模块(KS0070)联接的C语言源程
- 基于BlueZ的C语言蓝牙编程
- 基于BlueZ的C语言蓝牙编程
- 基于BlueZ的C语言蓝牙编程
- 基于ARM的高效C语言编程
- 基于SQLITE数据库的C语言编程
- 基于sqlite数据库的C语言编程
- 基于SQLITE数据库的C语言编程
- 基于SQLITE数据库的C语言编程
- 基于BlueZ的C语言蓝牙编程
- 基于SQLITE数据库的C语言编程
- 基于SQLITE数据库的C语言编程
- 基于BlueZ的C语言蓝牙编程
- 基于ARM的高效C语言编程
- 基于C语言的面向对象编程
- BZOJ [Usaco2008 Oct]牧场行走
- 正则表达式手册
- 脱壳步骤一寻找OEP
- Huffman 编码压缩算法
- Windows下的getopt
- 基于AT89C51的电子钟(C语言编程)
- VS2008报错LINK:fatal error LNK1000: Internal error during IncrBuildImage
- 脱壳步骤二-修复
- 数据耦合与控制耦合
- Flex4 Spark Container
- Eclipse用svn管理Android项目问题
- ISP于IAP的区别
- 银行IT软件服务的公司 (不包括被收购的企业),统计国内员工人数比较多的企业
- Java String类和StringBuffer类的区别