单片机课程设计my.docx
《单片机课程设计my.docx》由会员分享,可在线阅读,更多相关《单片机课程设计my.docx(23页珍藏版)》请在冰豆网上搜索。
单片机课程设计my
湖南科技大学
信息与电气工程学院
单片机微机原理课程设计报告
课程:
单片机微机原理及接口技术
题目:
基于STC15F2K60S的电子万年历
专业:
通信工程
班级:
通信一班
姓名:
孟焱
学号:
1204040101
指导教师:
宋芳
任务书
题目
基于STC15F2K60S单片机的电子万年历
时间安排
2015年6月6——6月19日(第15、16周)
目的:
通过《单片机原理与应用》这门课的课程设计,学生应能对STC15F2K60S单片机有一个全面的认识,掌握以STC15F2K60S单片机为核心的电子电路的设计方法和应用技术。
1.进一步掌握矩阵键盘电路的编程方法。
2.进一步掌握定时器的使用和编程方法。
3.进一步掌握中断处理程序的编程方法。
总体方案实现:
1、利用STC15F2K60S作为主控器组成一个电子日历和电子钟。
2、利用LED分别显示当前时间和日历。
3、利用开发板上自带的24个按键作为输入按钮(实际用到13个),实现手动输入时间信息。
4、利用开关k1,k2作为两个外部中断触发装置,利用两个中断子程序分别实现被修改位的选择和进入修改模式。
5利用扫描法实现对键盘矩阵的扫描,确定被按下的按键。
要求:
1、利用STC15F2K60S作为主控器组成一个电子日历和电子钟
2、利用开发板上提供的矩阵键盘电路,数码显示电路,设计一个电子钟(日历),用矩阵键盘控制电子钟(日历)的模式转换及修改时间。
指导教师评语:
评分等级:
【】
指导教师签名:
一、引言
单片机因将其主要组成部分集成在一个芯片上而得名,就是把中央处理器、随机存储器、只读存储器、中断系统、定时器/计数器以及I/O接口电路等部件集成在一个芯片上。
基于单片机设计的数字钟精确度较高,因为在程序的执行过程中,任何指令都不影响定时器的正常计数,即便程序很长也不会影响中断的时间。
数字钟是采用数字电路实现对日期、时、分、秒,数字显示的计时装置,由于数字集成电路的发展和石英晶体振荡器的广泛应用,使得数字钟的精度,远远超过老式钟表,钟表的数字化给人们生产生活带来了极大的方便,而且大大地扩展了钟表的报时功能。
数字钟已成为人们日常生活中的必需品,广泛应用于家庭、车站、码头、剧院、办公室等场所,给人们的生活、学习、工作带来极大的方便。
不仅如此,在现代化的进程中,也离不开电子钟的相关功能和原理,比如机械手的控制、家务的自动化、定时自动报警、按时自动打铃、时间程序自动控制、定时广播、自动起闭路灯、定时开关烘箱、通断动力设备、甚至各种定时电气的自动启用等,所有这些,都是以钟表数字化为基础的。
而且是控制的核心部分。
因此,研究数字钟及扩大其应用,有着非常现实的意义。
二、设计任务和要求
1、利用STC15F2K60S作为主控器组成一个电子日历和电子钟
2、利用开发板上提供的矩阵键盘电路,数码显示电路,设计一个电子钟(日历),用矩阵键盘控制电子钟(日历)的模式转换及修改时间。
三、设计方案
1、利用STC15F2K60S作为主控器组成一个电子日历和电子钟。
2、利用LED分别显示当前时间和日历。
3、利用开发板上自带的24个按键作为输入按钮(实际用到13个),实现手动输入时间信息。
4、利用开关k1,k2作为两个外部中断触发装置,利用两个中断子程序分别实现被修改位的选择和进入修改模式。
5利用扫描法实现对键盘矩阵的扫描,确定被按下的按键。
注:
电子钟做成如下两种格式(按B键两种格式可以切换):
XX-XX-XX由左向右分别为:
时、分、秒
XX-XX-XX由左向右分别为:
年、月、日
(1)矩阵键盘上0~9键分别对应数字0~9用于时间的输入
(2)矩阵键盘上A键用于两种模式之间转换,两种模式下分别显示年月日和时分秒
(3)矩阵键盘上B键用于对输入数字进行确认
(4)矩阵键盘上C键用于进入闹钟时间设定模式
(5)独立按键k1用于对被修改位的选择
(6)独立按键k2用于进入日历修改模式
三、程序设计
#defineMAIN_Fosc22118400L//定义主时钟
#include"STC15Fxxxx.H"
/******************************用户定义宏***********************************/
#defineTimer0_Reload(65536UL-(MAIN_Fosc/1000))//Timer0中断频率,1000次/秒
#defineDIS_DOT0x20
#defineDIS_BLACK0x10
#defineDIS_0x11
/*************本地常量声明**************/
u8codet_display[]={//标准字库
//0123456789ABCDEF
0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F,0x77,0x7C,0x39,0x5E,0x79,0x71,
//black-HJKLNoPUtGQrMy
0x00,0x40,0x76,0x1E,0x70,0x38,0x37,0x5C,0x73,0x3E,0x78,0x3d,0x67,0x50,0x37,0x6e,
0xBF,0x86,0xDB,0xCF,0xE6,0xED,0xFD,0x87,0xFF,0xEF,0x46};//0.1.2.3.4.5.6.7.8.9.-1
u8codeT_COM[]={0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80};//位码
/*************IO口定义**************/
sbitP_HC595_SER=P4^0;//pin14SERdatainput
sbitP_HC595_RCLK=P5^4;//pin12RCLkstore(latch)clock
sbitP_HC595_SRCLK=P4^3;//pin11SRCLKShiftdataclock
sbitled7=p1^7;
/*************本地变量声明**************/
u8LED8[8];//显示缓冲
u8display_index;//显示位索引
bitB_1ms;//1ms标志
u8ch;
u8mod;
u8hour,minute,second,day,month,year,one,two,three;//时间变量
u16msecond;
u8ahour,aminute,aa,ab,ach,atem;//闹钟时间变量
//----键盘相关变量------
u8IO_KeyState,IO_KeyState1,IO_KeyHoldCnt;//行列键盘变量
u8KeyHoldCnt;//键按下计时
u8KeyCode;//给用户使用的键码,1~16有效
u8cnt50ms;
u8a;
u8b;
u8tem;
u8codeT_KeyTable[16]={0,1,2,0,3,0,0,0,4,0,0,0,0,0,0,0};
/*************本地函数声明**************/
voidIO_KeyScan(void);//50mscall
voidIO_KeyDelay(void);
voidplay(u8ch,u8a,u8b);
voidalarm();
//-----延时子程序-----
voiddelay(unsignedintt)
{
unsignedintk,j;
for(k=0;k{
for(j=0;j<10000;j++);
if(0==0)
{
for(j=0;j<10000;j++);
for(j=0;j<10000;j++);
}
}
}
/******************************************
1、显示时钟函数************************/
voidDisplayRTC(void)
{
if(minute>=60)
{
minute=0;
}
if(hour>=24)
{
hour=0;
}
if(day>=30)
{
day=0;
}
if(month>=12)
{
month=0;
}
if(year>=99)
{
year=0;
}
if(mod==0)
{
one=hour;
two=minute;
three=second;
}
else
{
one=year;
two=month;
three=day;
}
LED8[0]=one/10;
LED8[1]=one%10;
LED8[2]=DIS_;
LED8[3]=two/10;
LED8[4]=two%10;
LED8[5]=DIS_;
LED8[6]=three/10;
LED8[7]=three%10;
}
/**********************
2、RTC演示函数************************/
voidRTC(void)
{
if(++second>=60)
{
second=0;
if(++minute>=60)
{
minute=0;
if(++hour>=24)
{
hour=0;
if(++day>30)
{
day=0;
if(++month>12)
{
month=0;
if(++year>=99)
{
year=0;
}
}
}
}
}
}
}
/*****************
3、外部中断0子程序**************/
voidint0()interrupt0
{
ch++;
if(ch>=6)
{
ch=0;
}
delay(8);
IE0=0;
}
/****************
4、外部中断1子程序******************/
voidint1()interrupt2
{
a=0;
b=0;
KeyCode=0;
while(KeyCode!
=28)//输入被修改位的高位,按下B键确认
{
if(++cnt50ms>=50)//50ms扫描一次行列键盘
{
cnt50ms=0;
IO_KeyScan();
}
if(KeyCode!
=28)
{
a=KeyCode-17;
play(ch,a,0);
}
}
RTC();
DisplayRTC();
KeyCode=0;
delay(8);
while(KeyCode!
=28)//输入被修改位的低位,按下B键确认
{
if(++cnt50ms>=50)//50ms扫描一次行列键盘
{
cnt50ms=0;
IO_KeyScan();
}
if(KeyCode!
=28)
{
b=KeyCode-17;
play(ch,a,b);
}
}
tem=a*10+b;//被修改后数据寄存在tem变量中
if(ch==0)//判断被修改的是哪一位,并赋予修改后值
{
hour=tem;
}
elseif(ch==1)
{
minute=tem;
}
elseif(ch==2)
{
second=tem;
}
elseif(ch==3)
{
year=tem;
}
elseif(ch==4)
{
month=tem;
}
elseif(ch==5)
{
day=tem;
}
else
{
alarm();
}
KeyCode=0;
DisplayRTC();
delay(8);
IE1=0;
}
/**********************
5、主函数************************/
voidmain(void)
{
u8i,k;
ch=0;
IP=0x03;//将定时器0中断赋予高优先级,使修改模式下能够正常显示修改结果
P0M1=0;P0M0=0;//设置为准双向口
P1M1=0;P1M0=0;//设置为准双向口
P2M1=0;P2M0=0;//设置为准双向口
P3M1=0;P3M0=0;//设置为准双向口
P4M1=0;P4M0=0;//设置为准双向口
P5M1=0;P5M0=0;//设置为准双向口
P6M1=0;P6M0=0;//设置为准双向口
P7M1=0;P7M0=0;//设置为准双向口
AUXR=0x80;//Timer0setas1T,16bitstimerauto-reload,
TH0=(u8)(Timer0_Reload/256);
TL0=(u8)(Timer0_Reload%256);
ET0=1;//Timer0interruptenable
TR0=1;//Tiner0run
EA=1;//打开总中断
EA=1;
EX0=1;
IT0=1;
EX1=1;
IT1=1;
display_index=0;
year=90;
month=01;
day=01;
hour=11;//初始化时间值
minute=59;
second=59;
KeyCode=0;
a=0;
b=0;
mod=0;
//for(i=0;i<8;i++)LED8[i]=DIS_BLACK;//上电消隐
for(i=0;i<8;i++)LED8[i]=i;//显示01234567
k=0;
while
(1)
{
if(++cnt50ms>=50)//50ms扫描一次行列键盘
{
cnt50ms=0;
IO_KeyScan();
}
if(KeyCode==27)//改变显示模式
{
if(mod==0)
{
mod=1;
}
else
{
mod=0;
}
RTC();
DisplayRTC();
delay(8);
KeyCode=0;
}
if(ahour==hour||aminute==minute)//判断是否到闹钟时间决定是否响铃
{
led7=0;//使用led7代替蜂鸣器,灯亮表示蜂鸣器响
}
else
{
led7=1;
}
if(KeyCode==29)
{
alarm();
KeyCode=0;
}
if(B_1ms)//1ms到
{
B_1ms=0;
if(++msecond>=500)//1秒到
{
msecond=0;
RTC();
DisplayRTC();
}
}
}
}
/****************
6、向HC595发送一个字节函数******************/
voidSend_595(u8dat)
{
u8i;
for(i=0;i<8;i++)
{
dat<<=1;
P_HC595_SER=CY;
P_HC595_SRCLK=1;
P_HC595_SRCLK=0;
}
}
/**********************
7、显示扫描函数************************/
voidDisplayScan(void)
{
Send_595(~T_COM[display_index]);//输出位码
Send_595(t_display[LED8[display_index]]);//输出段码
P_HC595_RCLK=1;
P_HC595_RCLK=0;//锁存输出数据
if(++display_index>=8)display_index=0;//8位结束回0
}
/**********************
8、Timer01ms中断函数************************/
voidtimer0(void)interruptTIMER0_VECTOR
{
DisplayScan();//1ms扫描显示一位
B_1ms=1;//1ms标志
}
voidIO_KeyDelay(void)
{
u8i;
i=60;
while(--i);
}
voidIO_KeyScan(void)//50mscall
{
u8j;
j=IO_KeyState1;//保存上一次状态
P0=0xf0;//X低,读Y
IO_KeyDelay();
IO_KeyState1=P0&0xf0;
P0=0x0f;//Y低,读X
IO_KeyDelay();
IO_KeyState1|=(P0&0x0f);
IO_KeyState1^=0xff;//取反
if(j==IO_KeyState1)//连续两次读相等
{
j=IO_KeyState;
IO_KeyState=IO_KeyState1;
if(IO_KeyState!
=0)//有键按下
{
F0=0;
if(j==0)F0=1;//第一次按下
elseif(j==IO_KeyState)
{
if(++IO_KeyHoldCnt>=20)//1秒后重键
{
IO_KeyHoldCnt=18;
F0=1;
}
}
if(F0)
{
j=T_KeyTable[IO_KeyState>>4];
if((j!
=0)&&(T_KeyTable[IO_KeyState&0x0f]!
=0))
KeyCode=(j-1)*4+T_KeyTable[IO_KeyState&0x0f]+16;//计算键码
}
}
elseIO_KeyHoldCnt=0;
}
P0=0xff;
}
/*************
9、修改模式下显示函数********************/
voidplay(u8ch,u8a,u8b)
{
u8tea,teb;
tea=a;
teb=b;
if(a>9)
{
tea=0;
}
if(b>9)
{
teb=0;
}
if(ch==0||ch==3)
{
LED8[0]=tea;
LED8[1]=teb;
if(ch==0)
{
LED8[2]=DIS_;
}
else
{
LED8[2]=DIS_BLACK;
}
LED8[3]=DIS_BLACK;
LED8[4]=DIS_BLACK;
if(ch==0)
{
LED8[5]=DIS_;
}
else
{
LED8[5]=DIS_BLACK;
}
LED8[6]=DIS_BLACK;
LED8[7]=DIS_BLACK;
}
elseif(ch==1||ch==4)
{
LED8[0]=DIS_BLACK;
LED8[1]=DIS_BLACK;
if(ch==1)
{
LED8[2]=DIS_;
}
else
{
LED8[2]=DIS_BLACK;
}
LED8[3]=tea;
LED8[4]=teb;
if(ch==1)
{
LED8[5]=DIS_;
}
else
{
LED8[5]=DIS_BLACK;
}
LED8[6]=DIS_BLACK;
LED8[7]=DIS_BLACK;
}
else
{
LED8[0]=DIS_BLACK;
LED8[1]=DIS_BLACK;
if(ch==2)
{
LED8[2]=DIS_;
}
else
{
LED8[2]=DIS_BLACK;
}
LED8[3]=DIS_BLACK;
LED8[4]=DIS_BLACK