单片机实训二程序课室打铃控制系统Word文档格式.docx
《单片机实训二程序课室打铃控制系统Word文档格式.docx》由会员分享,可在线阅读,更多相关《单片机实训二程序课室打铃控制系统Word文档格式.docx(16页珍藏版)》请在冰豆网上搜索。
unsignedchardataflag,vkey,skey;
//设置状态计数标志、按键先前值、按键当前值
bitalarm;
//标识是否启用闹钟,1--启用,0--关闭
sbitrs=P2^6;
//LCD数据/命令选择端(H/L)
sbitrw=P2^5;
//LCD读/写选择端(H/L)
sbitep=P2^7;
//LCD使能控制
sbitPRE=P1^6;
//调整键(k3)杜邦线将P1.6接到独立按键
sbitSET=P1^7;
//调整键(k4)杜邦线将P1.7接到独立按键
sbitSPK=P1^5;
//蜂鸣器
voiddelayms(unsignedcharms);
//延时程序
bitlcd_busy();
//测试LCD忙碌状态程序
voidlcd_wcmd(charcmd);
//写入指令到LCD程序
voidlcd_wdat(chardat);
//写入数据到LCD程序
voidlcd_pos(charpos);
//LCD数据指针位置程序
voidlcd_init();
//LCD初始化设定程序
voidpro_timedate();
//时间日期处理程序
voidpro_display();
//显示处理程序
voidpro_key();
//按键处理程序
voidtime_alarm();
//定时报警功能(闹钟)
unsignedcharscan_key();
//按键扫描程序
unsignedcharweek_proc();
//星期自动计算与显示函数
bitleap_year();
//判断是否为闰年
voidlcd_sef_chr();
//LCD自定义字符程序
voidupdate_disbuf(unsignedchart1,unsignedchart2[],unsignedchardis_h,unsignedchardis_m,unsignedchardis_s);
//更新显示缓冲区函数
//延时程序
voiddelay(unsignedcharms)
{while(ms--)
{unsignedchari;
for(i=0;
i<
250;
i++)
{
_nop_();
//执行一条_nop_()指令为一个机器周期
}
}
//测试LCD忙碌状态
bitlcd_busy()
{
bitresult;
rs=0;
rw=1;
ep=1;
result=(bit)(P0&
0x80);
//LCD的D0--D7中,D7=1为忙碌,D7=0为空闲
ep=0;
returnresult;
//写入指令到LCD
voidlcd_wcmd(charcmd)
while(lcd_busy());
//当lcd_busy为1时,再次检测LCD忙碌状态,lcd-busy为0时,开始写指令
rw=0;
P0=cmd;
//写入数据到LCD
voidlcd_wdat(chardat)
//当lcd_busy为1时,再次检测LCD忙碌状态,lcd-busy为0时,开始写数据
rs=1;
P0=dat;
//LCD数据指针位置程序
voidlcd_pos(charpos)
lcd_wcmd(pos|0x80);
//数据指针=80+地址码(00H~27H,40H~67H)
//设定二个自定义字符,(注意:
LCD1602中自定义字符的地址为0x00--0x07,即可定义8个字符)
//这里我们设定把一个自定义字符放在0x00位置(000),另一个放在0x01位子(001)
voidlcd_sef_chr()
{//第一个自定义字符
lcd_wcmd(0x40);
//"
01000000"
第1行地址(D7D6为地址设定命令形式D5D4D3为字符存放位置(0--7),D2D1D0为字符行地址(0--7))
lcd_wdat(0x1f);
XXX11111"
第1行数据(D7D6D5为XXX,表示为任意数(一般用000),D4D3D2D1D0为字符行数据(1-点亮,0-熄灭)
lcd_wcmd(0x41);
01000001"
第2行地址
lcd_wdat(0x11);
XXX10001"
第2行数据
lcd_wcmd(0x42);
01000010"
第3行地址
lcd_wdat(0x15);
XXX10101"
第3行数据
lcd_wcmd(0x43);
01000011"
第4行地址
第4行数据
lcd_wcmd(0x44);
01000100"
第5行地址
第5行数据
lcd_wcmd(0x45);
01000101"
第6行地址
lcd_wdat(0x0a);
XXX01010"
第6行数据
lcd_wcmd(0x46);
01000110"
第7行地址
第7行数据
lcd_wcmd(0x47);
01000111"
第8行地址
lcd_wdat(0x00);
XXX00000"
第8行数据
//第二个自定义字符
lcd_wcmd(0x48);
01001000"
第1行地址
lcd_wdat(0x01);
XXX00001"
第1行数据
lcd_wcmd(0x49);
01001001"
lcd_wdat(0x1b);
XXX11011"
lcd_wcmd(0x4a);
01001010"
lcd_wdat(0x1d);
XXX11101"
lcd_wcmd(0x4b);
01001011"
lcd_wdat(0x19);
XXX11001"
lcd_wcmd(0x4c);
01001100"
lcd_wcmd(0x4d);
01001101"
lcd_wcmd(0x4e);
01001110"
lcd_wcmd(0x4f);
01001111"
第8行数据
//LCD初始化设定
voidlcd_init()
lcd_wcmd(0x38);
//设置LCD为16X2显示,5X7点阵,八位数据借口
delay
(1);
lcd_wcmd(0x0c);
//LCD开显示及光标设置(光标不闪烁,不显示"
-"
)
lcd_wcmd(0x06);
//LCD显示光标移动设置(光标地址指针加1,整屏显示不移动)
lcd_wcmd(0x01);
//清除LCD的显示内容
//闰年的计算
bitleap_year()
bitleap;
if((year%4==0&
&
year%100!
=0)||year%400==0)//闰年的条件
leap=1;
else
leap=0;
returnleap;
//星期的自动运算和处理
unsignedcharweek_proc()
{unsignedcharnum_leap;
unsignedcharc;
num_leap=year/4-year/100+year/400;
//自00年起到year所经历的闰年数
if(leap_year()&
month<
=2)//既是闰年且是1月和2月
c=5;
c=6;
week=(year+para_month[month]+date+num_leap+c)%7;
//计算对应的星期
returnweek;
//更新显示缓冲区
voidupdate_disbuf(unsignedchart1,unsignedchart2[],unsignedchardis_h,unsignedchardis_m,unsignedchardis_s)
{dis_buf1[0]=t1;
//
dis_buf1[1]=0x20;
//空格
dis_buf1[2]=50;
//'
2'
dis_buf1[3]=48;
0'
dis_buf1[4]=year/10+48;
dis_buf1[5]=year%10+48;
dis_buf1[6]=0x2d;
dis_buf1[7]=month/10+48;
dis_buf1[8]=month%10+48;
dis_buf1[9]=0x2d;
-'
dis_buf1[10]=date/10+48;
dis_buf1[11]=date%10+48;
dis_buf1[12]=0x20;
dis_buf1[13]=dis_week[4*week];
dis_buf1[14]=dis_week[4*week+1];
dis_buf1[15]=dis_week[4*week+2];
dis_buf2[0]=t2[0];
dis_buf2[1]=t2[1];
dis_buf2[2]=t2[2];
dis_buf2[3]=t2[3];
dis_buf2[4]=t2[4];
dis_buf2[5]=t2[5];
dis_buf2[6]=0x20;
if(alarm)
dis_buf2[7]=0x01;
//alarm=1,显示闹钟启用标致(第二个自定义字符)
dis_buf2[7]=0x20;
//alarm=0,不显示闹钟启用标致
dis_buf2[8]=dis_h/10+48;
dis_buf2[9]=dis_h%10+48;
dis_buf2[10]=0x3a;
:
'
dis_buf2[11]=dis_m/10+48;
dis_buf2[12]=dis_m%10+48;
dis_buf2[13]=0x3a;
dis_buf2[14]=dis_s/10+48;
dis_buf2[15]=dis_s%10+48;
//时间和日期处理程序
voidpro_timedate()
sec++;
if(sec>
59)
{sec=0;
min++;
if(min>
59)
{min=0;
hour++;
if(hour>
23)
{hour=0;
date++;
if(month==1||month==3||month==5||month==7||month==8||month==10||month==12)
if(date>
31){date=1;
month++;
}//大月31天
if(month==4||month==6||month==9||month==11)
30){date=1;
}//小月30天
if(month==2)
{if(leap_year())//闰年的条件
{if(date>
29){date=1;
}}//闰年2月为29天
28){date=1;
}}//平年2月为28天
if(month>
12){month=1;
year++;
if(year>
99)year=0;
week_proc();
if(sec==armsec&
min==armmin&
hour==armhour)
{if(alarm)
TR1=1;
//闹钟启用时,报警时间到,启动Timer1
//显示处理程序
voidpro_display()
{unsignedchari;
lcd_pos(0x00);
for(i=0;
i<
=15;
i++)
{lcd_wdat(dis_buf1[i]);
lcd_pos(0x40);
{lcd_wdat(dis_buf2[i]);
//Timer0中断处理程序,秒的产生
voidtimer0()interrupt1
TH0=0xdc;
//Timer0置10ms定时初值dc00H(2^16=65536D,dc00H=56320D)
TL0=0x00;
//定时时间=(65536-56320)*(1/11.0592)*12=10ms(f0=11.0592Mhz)
sec100++;
if(sec100>
=100)//1秒时间(100*10ms=1000ms=1s)
{sec100=0;
pro_timedate();
//调用时间和日期处理程序
if(sec&
0x01)//"
willar"
闪一秒,停一秒
update_disbuf(0x00,"
"
hour,min,sec);
//0x00表示显示00位置的自定义字符
pro_display();
//调用显示处理函数
//按键扫描程序
unsignedcharscan_key()
skey=0x00;
//给变量vkey置初值
skey|=PRE;
//读取PRE键的状态
skey=skey<
<
1;
//将PRE键的状态存于skey的B1位
skey|=SET;
//读取SET键的状态,并存于skey的B0位
returnskey;
//返回skey的键值(即PRE,SET的状态)
//外部中断INT0中断处理程序
voidint0()interrupt0
TR0=0;
//禁止Timer0
IE=0;
//禁止中断
lcd_wcmd(0x0e);
//显示光标"
_"
整个光标不闪烁
alarm=1;
update_disbuf(0x50,"
alarm:
"
armhour,armmin,armsec);
//更新显示数据,0x50表示要显示"
P"
//调用显示处理程序
lcd_pos(0x47);
//使光标位于第一个调整项下
flag=0;
vkey=0x03;
while(flag^0x0a)
{skey=scan_key();
//扫描按键状态
if(skey^vkey)//若skey与vkey相同,跳出循环,相异执行循环体
{delay(10);
//去按键抖动
skey=scan_key();
//转回扫描按键状态
if(skey^vkey)//若skey与vkey相同,跳出循环,相异执行循环体{vkey=skey;
//将skey的值付给vkey
if(skey==0x01)//PRE键按下
{flag++;
//调整标志位加1
switch(flag)//将光标置于相应调整位置
case1:
lcd_pos(0x49);
break;
//光标置小时报警设置位置
case2:
lcd_pos(0x4c);
//光标置分钟报警设置位置
case3:
lcd_pos(0x4f);
//光标置秒时报警设置位置
case4:
time:
lcd_pos(0x05);
//光标置年调整位置
case5:
lcd_pos(0x08);
//光标置月调整位置
case6:
lcd_pos(0x0b);
//光标置日调整位置
case7:
//光标置时调整位置
case8:
//光标置分调整位置
case9:
//光标置秒调整位置
default:
if(skey==0x02)//SET键按下
{pro_key();
//转设置按键处理程序
//设置LCD开显示及光标不闪烁,不显示"
IE=0x8f;
//CPU开中断,INT0,INT1,开中断
TR0=1;
//Timer0启动
//主程序,初始化及初值设定
voidmain()
{lcd_init();
//初始化LCD
lcd_sef_chr();
//写入自定义字符号
hour=0;
min=0;
sec=0;
//开机时的时,分,秒显示
armhour=0;
armmin=0;
armsec=0;
//开机时的时,分,秒报警初值
year=5;
month=1;
date=1;
//开机时的年,月,日,星期显示
//初始开机,启用闹钟
IE=0x8f;
//CPU开中断,INT0,INT1,Timer0,Timer1开中断
IP=0x04;
//设置INT0为中断最高优先级
IT0=0;
IT1=0;
//外部INT0,INT1设置为电平触发方式(注意,触发不要选边沿方式,易误动)
TMOD=0x11;
//Timer0,Timer1工作于模式1,16位定时方式
TH0=0xdc;
TL0=0x00;
//Timer0置10ms定时初值
TH1=0xff;
TL1=0x00;
//Timer1置初值
TR0=1;
TR1=0;
while
(1);
}//设置按键处理程序
voidpro_key()
{switch(flag)
case0:
alarm=!
alarm;
//启用或关闭闹钟(alarm=1:
启用,alarm=0:
关闭)
//更新显示数据
//调用显示处理
//光标回到原调整位置case1:
armhour++;
if(armhour>
23)armhour=0;
pr