#include<reg52.h>
#include<stdlib.h>
#include<intrins.h> //包含_nop_()函数定义的头文件
unsigned char code digit[ ]={"0123456789"}; //LCD1602初始化字符
unsigned char code str_1[ ]={"Set delay time:"};
unsigned char code str_2[ ]={" Count time: "};
unsigned char count; //Timer0计数溢出中断次数
unsigned char s,m,h; //即时的(秒,分,时)变量
unsigned char ss,mm,hh;//预设定时(秒,分,时)变量
unsigned char i; //循环变量
sbit RS=P2^0; //LCD寄存器选择位,将RS位定义为P2.0引脚
sbit RW=P2^1; //LCD读写选择位,将RW位定义为P2.1引脚
sbit E=P2^2; //LCD使能信号位,将E位定义为P2.2引脚
sbit BF=P0^7; //LCD忙碌标志位,
sbit run=P1^0; //启动计时按钮检测
unsigned char runing=0; //0非计时运行,1计时运行
sbit h_up=P1^1; //h+ 按钮检测
sbit h_dn=P1^2; //h- 按钮检测
sbit set=P1^3; //pause钮检测
sbit m_up=P1^4; //m+按钮检测
sbit m_dn=P1^5; //m-按钮检测
sbit alarm=P2^7; //引脚用于触发音乐IC模块播放音乐
// 延时ms函数////////////////////////
void delayms(unsigned char ms)
{
unsigned char i;
while(ms--)
{
for(i = 0; i < 120; i++);
}
}
/////////////////////////////////////
//函数:判断LCD状态,result=1忙碌;result=0就绪
unsigned char BusyTest(void)
{
bit result;
RS=0; //RS低电平,RW高电平,可读状态
RW=1;
E=1; //允许读写
_nop_();
_nop_();
_nop_();
_nop_();
result=BF; //rultes ← LCD状态标志
E=0; //恢复低电平
return result;
} /////////////////////////////////////////
//函数:将模式设置指令或显示地址写入LCD ////
void WriteInstruction (unsigned char dictate)
{
while(BusyTest()==1); //如果忙就等待
RS=0; //RS和R/W同时为低电平时,可以写入指令
RW=0;
E=0; //准备E从0到1发生正跳变,作为写指令
_nop_();
_nop_(); //空操作两个机器周期,给硬件反应时间
P0=dictate; //将数据送入P0口,即写入指令或地址
_nop_();
_nop_();
_nop_();
_nop_();
E=1; //E置高电平
_nop_();
_nop_();
_nop_();
_nop_();
E=0; //当E由高电平跳变成低电平时,LCD开始执行命令
} //////////////////////////////////////////
//函数:指定字符显示的实际地址///////////////
void WriteAddress(unsigned char x)
{
WriteInstruction(x|0x80); //显示位置地址码
} //////////////////////////////////////////
//函数:将数据字符的ASCII码写入LCD///////////
void WriteData(unsigned char y)
{
while(BusyTest()==1);
RS=1; //RS为高电平,RW为低电平时,可以写入数据
RW=0;
E=0; //E置低电平(根据表8-6,写指令时,E为高脉冲,
//就是让E从0到1发生正跳变,所以应先置"0"
P0=y; //将数据送入P0口,即将数据写入液晶模块
_nop_();
_nop_();
_nop_();
_nop_(); //空操作四个机器周期,给硬件反应时间
E=1; //E置高电平
_nop_();
_nop_();
_nop_();
_nop_(); //空操作四个机器周期,给硬件反应时间
E=0; //当E由高电平跳变成低电平时,液晶模块开始执行命令
} /////////////////////////////////////////
//函数:LCD显示模式初始化设置 //////////////
void LcdInitiate(void)
{
delayms(15);
WriteInstruction(0x38); //显示模式设置:16×2显示,5×7点阵,8位数据接口
delayms(5);
WriteInstruction(0x38);
delayms(5);
WriteInstruction(0x38); //连续三次,确保初始化成功
delayms(5);
WriteInstruction(0x0c); //显示模式设置:显示开,无光标,光标不闪烁
delayms(5);
WriteInstruction(0x06); //显示模式设置:光标右移,字符不移
delayms(5);
WriteInstruction(0x01); //清屏幕指令,将以前的显示内容清除
delayms(5);
} /////////////////////////////////////////
//函数:显示小时 //////////////////////////
void DisplayHour(h)
{
unsigned char i,j;
i=h/10; //取整运算,求得十位数字
j=h%10; //取余运算,求得各位数字
WriteAddress(0x44); //写显示地址,将十位数字显示在第2行第5列
WriteData(digit[i]); //将十位数字的字符常量写入LCD
WriteData(digit[j]); //将个位数字的字符常量写入LCD
} //////////////////////////////////////////////
//函数:显示分钟 ///////////////////////////////
void DisplayMinute(m)
{
unsigned char i,j;
i=m/10; //取整运算,求得十位数字
j=m%10; //取余运算,求得各位数字
WriteAddress(0x47); //写地址,将十位数字显示在第2行第8列
WriteData(digit[i]); //将十位数字的字符常量写入LCD
WriteData(digit[j]); //将个位数字的字符常量写入LCD
} //////////////////////////////////////////////
//函数:显示秒 /////////////////////////////////
void DisplaySecond(s)
{
unsigned char i,j;
i=s/10; //取整运算,求得十位数字
j=s%10; //取余运算,求得各位数字
WriteAddress(0x4a); //写地址,将十位数字显示在第2行第11列
WriteData(digit[i]); //将十位数字的字符常量写入LCD
WriteData(digit[j]); //将个位数字的字符常量写入LCD
} //////////////////////////////////////////////
void Display_str_1()//函数:显示str_1 ////////////
{
WriteAddress(0x01); //写地址,从第1行第2列开始显示
i=0; //从字符数组的第1个元素开始显示
while(str_1[i]!='\0') //若未到字串结束标志'\0',则显示
{
WriteData(str_1[i]); //将第i个字符数组元素写入LCD
i++; //数组元素指针+1
}
}//////////////////////////////////////////////
void Display_str_2()//函数:显示str_1 ////////////
{
WriteAddress(0x01); //写地址,从第1行第2列开始显示
i=0; //从字符数组的第1个元素开始显示
while(str_2[i]!='\0') //若未到字串结束标志'\0',则显示
{
WriteData(str_2[i]); //将第i个字符数组元素写入LCD
i++; //数组元素指针+1
}
}//////////////////////////////////////////////
void Display_symbol() //函数:显示分隔符号////////
{
WriteAddress(0x46); //写地址,第1分号显示在第2行第7列
WriteData(':');
WriteAddress(0x49); //写地址,第2个分号显示在第2行第10列
WriteData(':');
} ////////////////////////////////////////////
//主函数///////////////////////////////////////////////
void main(void)
{
LcdInitiate(); //调用LCD初始化函数
Display_symbol();
Display_str_1();
hh =0;
mm =0;
ss =0;
s=0; //秒
m=0; //分钟
h=0; //小时
TMOD=0x01; //使用定时器T0的模式1
TH0=(65536-46083)/256; //定时器T0的高8位设置初值
TL0=(65536-46083)%256; //定时器T0的低8位设置初值
EA=1; //开总中断
ET0=1; //定时器T0中断允许
while(1)
{ //while_A
if (run ==0) //按下run按钮
{ //if_run
delayms(20); //消除按键抖动
if (run ==0 )
{ // if_run-1
runing =1; // 处于计时运行状态
Display_str_2();
TR0=1; //启动定时器T0
count=0; //Time0计数溢出中断次数
while(set !=0)
{ // while_B
DisplayHour(h); //显示小时即时值
delayms(5);
DisplayMinute(m); //显示分钟时值
delayms(5);
DisplaySecond(s); //显示秒时值
delayms(5);
if (h >=hh & m>= mm ) //当计时达设定值
{ //if_finish
TR0=0; //停止Time0计时
//ET0=0; //关Time0中断
DisplayHour(hh); //显示小时
delayms(5);
DisplayMinute(mm); //显示分钟
delayms(5);
DisplaySecond(ss); //显示秒
delayms(5);
alarm = ~alarm; //P2.7脚由高电平亦低电平,触发音乐IC模块
} // end if_finish
} // end while_B
runing =0 ; //非计时运行标志
Display_str_1();
DisplayHour(hh); //显示小时设定值
delayms(5);
DisplayMinute(mm); //显示分钟设定值
delayms(5);