单片机课程设计报告

物理与机电学院课程设计报告

课程名称:单片机课程设计

系 部:物理与机电工程学院

专业班级:07级电子信息工程(1)班

完成时间:20XX年5月24日~28日

报告成绩:

【摘 要】单片机自1976年由Intel公司推出MCS-48开始,迄今已有三十多年了。由于单片机集成度高、功能强、可靠性高、体积小、功耗地、使用方便、价格低廉等一系列优点,目前已经渗入到人们工作和生活的方方面面,几乎“无处不在,无所不为”。单片机的应用领域已从面向工业控制、通讯、交通、智能仪表等迅速发展到家用消费产品、办公自动化、汽车电子、PC机外围以及网络通讯等广大领域。目前,各个行业,各个领域,在新产品的设计中,都尽可能的应用单片机技术,来提高产品的智能化程度,增强产品的竞争力,适应技术的进步。

电子钟已成为人们日常生活中的必需品,广泛应用于家庭、车站、码头、剧院、办公室等场所。本系统采用本系统以AT89S52为主控芯片,设计并实现一个多功能电子时钟的设计,并考虑节约系统的硬件,能用软件实现的功能尽量都用软件实现。这款多功能电子钟,首先采用24小时的计时方式,能够同时在LCD1602液晶显示器上显示年、月、日、时、分、秒和星期;其次具有快速校准年、月、日、时、分和星期的功能;然后还能进行闹钟的设置,按人们预定的时刻发出音响信号来起到提醒的作用;最后采用数字温度传感器DS18B20作为单片机外部温度信号源,来实时显示当前温度,方便人们了解当前温度数值。

这款多功能电子钟,不仅功能齐全,系统稳定度高,显示数据准确而且成本低,能够广泛应用于各种场合。

【关键词】单片机、多功能电子钟、LCD1602、DS18B20。

目 录

1.设计目的与要求 …………………………………………………………4

1.1设计目的 …………………………………………………………4

1.2设计任务和要求 … ………………………………………………4

2.方案设计与论证 ……………………………………………………………4

2.1设计分析 …………………………………………………………4

2.2方案论证………………………………………………………………4

2.3方案选择 ……………………………………………………………4

3.硬件电路设计 ………………………………………………………………5

4.软件设计 ………………………………………………………………………7

5.安装与调试 ……………………………………………………………………9

6.结论与心得……………………………………………………………………10

7.参考文献………………………………………………………………………10

附录1 程序 …………………………………………………………………11

附录2 原理图 …………………………………………………………………21

多功能电子钟

1.设计目的与要求

1.1设计目的

通过课程设计的教学实践,进一步学习、掌握单片机应用系统的有关知识,加深了解单片机的工作原理。初步掌握简单单片机应用系统的设计、制作、调试的方法。提高动手实践能力、提高科学的思维能力。

1.2设计任务和要求

(1)、设计一个多功能电子钟。

(2)、用LCD1602显示年、月、日、时、分、星期以及当前温度。

(3)、能够快速校准年、月、日、时、分和星期。

(4)、具有闹钟功能,能够随时设定闹钟。

(5)、编写完整、条理分明、排版工整、符合格式要求的设计报告。

2.方案设计与论证

2.1设计分析

多功能电子钟,采用24小时的计时方式,能够同时显示年、月、日、时、分、秒和星期;具有快速校准年、月、日、时、分和星期的功能;还能进行闹钟的设置;还能实时显示当前温度。

2.2方案论证

时间数据的产生:

方案一:采用单片机内部定时器中断产生秒,然后用软件的方式对年、月、日、时、分、星期的自动运算以及闰年的计算等进行处理。

方案二:采用时钟芯片DS1302产生日期和时间数据。

显示方式的选择:

方案一:采用LED数码管来显示。

方案二:采用LCD1602液晶显示。

2.3方案选择

1,对于时间数据的产生:虽然时钟芯片DS1302一种高性能、低功耗、带RAM的实时时钟电路,它可以对年、月、日、周日、时、分、秒进行计时,具有闰年补偿功能等多种功能,但采用单片机内部定时器产生秒,然后用软件的方式对年、月、日、时、 分、星期的自动运算以及闰年的计算等进行处理,这样也能实现时钟芯片DS1302的功能,而且这样也降低了成本。所以选择方案一。

2,对显示方式的选择:虽然LED数码管价格便宜,但其显示方式单一,不能显示各种字符。LCD1602液晶显示器价格虽较高,但能方便的显示各种字符和数字,所以选择方案二。

3,对于温度数据的采集就选用DS18B20温度传感器。该传感器采用“一线总线”接口,体积小,价格便宜,使用灵活方便。

3.硬件电路设计

硬件电路的设计主要包括:控制部分的单片机最小系统、温度采集电路、按键设置电路和液晶显示电路。系统工作的原理框图如图1所示:

单片机课程设计报告

图1硬件系统原理框图

(1),单片机最小系统

单片机最小系统是指一个单片机能开始独立工作所需的最基本的外部电路连接,主要包括有晶振电路、复位电路和电源等,实现单片机的驱动。单片机最小系统原理图如图2所示。

(2),温度采集电路

美国Dallas半导体公司生产的DS18B20温度传感器适应电压范围宽,稳定性很好,反应也较快,测温范围为-55℃- +125℃,该温度传感器的分辨率为9-12位,测温精度高。

主机控制DS18B20完成温度转换必须经过初始化、ROM操作指令、存储器操作指令这三个步骤。首先启动初始化DS18B20开始转换,再读出温度转换值。在软件设计中使用默认的12位转换精度,外接供电电源,温度数据的传输,由于只有一根数据线,故可直接将数据线与单片机的P2.7相连,由单片机通过此数据线读取数据。温度采集电路如图3所示。

单片机课程设计报告

图2,单片机最小系统原理图

单片机课程设计报告

图3,DS18B20温度采集电路

(3),显示电路

选用字符型液晶模块1602,它是采用的5*7的点阵图形显示字符,共两行每行16个字。在本设计中一共要显示包括年、月、日、时、分、秒、星期及温度值等28个字符和数字。故可以满足要求。显示电路接口原理图如图4所示。

单片机课程设计报告

图4,液晶显示接口电路原理图

(4),按键设置电路

按键设置电路用来设置日期和时间,以及设置闹钟等。其具体电路如图5所示。

单片机课程设计报告

图5,按键设置电路

4.软件设计

本系统利用单片机作为控制核心,因此主要对其进行软件编程。汇编语言虽然语言语法简单,但实现如此功能的程序会很繁琐,可读性差。C语言相对简洁,可读性好,故本系统采用 C语言进行编程。

系统软件设计主要包括主程序设计、时间数据的产生程序设计、实时温度采集模块程序设计、按键调用子程序和数据显示程序设计。

(1)、主程序设计

主程序设计主要完成系统的初始化,判断有无按键按下,并根据判断的结果调用相应的子程序模块。主程序流程图如图6所示。

单片机课程设计报告

图6,主程序流程图

(2)、温度采集程序设计

在进行温度采集时,必须首先进行初始化,然后发ROM操作指令,再发存储器操作指令,最后才能进行温度数据的传输。温度采集程序流程图如图7所示。

单片机课程设计报告

图7,温度采集程序流程图

(3)、按键处理程序设计

按键处理程序设计主要完成时间日期值得重设以及闹钟的开启和闹钟时刻的设置。按键处理程序流程图如图7所示。

图7,按键处理程序流程图

5.安装与调试

按照硬件电路原理图设计硬件电路,设计好后进行PCB的设计,设计好PCB后将其打印输出,然后进行转印、腐蚀、钻孔和焊接。

按照软件设计流程图编写软件程序。编写完毕后进行编译并进行软件调试,无误后将其下载到AT89S52单片机芯片中。

将整个系统安装好后进行系统调试。刚开始调试的时候,日期和时间以及温度数据能够正确显示,但设置闹钟后,闹钟时间到时蜂鸣器并没有鸣叫,经仔细检查发现是蜂鸣器损坏,换了一个蜂鸣器后,刚才出现的问题得以解决。

调试最终结果:该多功能电子钟采用24小时的计时方式,能够同时显示年、月、日、时、分、秒和星期;具有快速校准年、月、日、时、分和星期的功能;具有闹钟功能,能进行闹钟的设置;具有数字温度计功能,能实时显示当前温度值。

6.结论与心得

首先,通过此次的课程设计我又进一步学习和掌握单片机应用系统的有关知识,加深了对单片机工作原理的理解。同时初步掌握简单单片机应用系统的设计、制作、调试的方法。提高了自己动手实践能力和科学的思维能力。

其次,在课程设计过程中,能够不断地发现问题,并想办法解决,如此提高了我自己解决问题的能力。在编写程序方面,我对单片机编程结构和技巧也有了深刻的理解和领会。此次课程设计还让我明白了流程图的重要性,以前在编程的时候,我从不写流程图,直接开始写程序,这样出现了不该出现的问题。但这次课程设计时,我试着先写出流程图然后按照流程图编写程序,结果错误少了很多,即使有错误只要根据流程图一查就知道错在哪里,这让我节省了大量的时间和精力。所以我认识到,以后要编写程序时,先写流程图是很有必要的。

最后,我感觉这一周的课程设计我自己的效率太低。有时候被一些问题困惑了很久,但经过老师的指点,我才恍然大悟,原来只要换个方式思考问题就能想到很好的方法。

7.参考文献

[1] 苏家健.《单片机原理及应用技术》[M].北京:高等教育出版社,2007.

[2] 向继文,廖立新.基于AT89C51电子钟系统设计[J],机电产品开发与创新,2007.

[3] 祁伟,杨婷.《单片机程序设计教程与实验》[M].北京:北京航空航天大学.

[4] 万胜前.基于KeilC51软件的电子钟设计与制作[J].鄂州大学学报,2007.

[5] 冯育长.单片机系统设计与实例分析[M],西安:西安电子科技大学出版社,2007,5.

附录1

多功能电子钟系统程序如下:

//按S3,依次进入闹钟功能是否启用,闹钟时,分秒,年,月,日及时间时,分,秒的设置,直到退出设置状态

//按S1,调整是否起用闹钟和调节闹钟时,分,秒,年,月,日,时间的时,分,秒的数字

//LCD第二排中间显示小喇叭,表示启用闹钟功能,无则禁止闹钟功能(可在调整状态进行设置)

//年代变化2000--2099,星期自动转换

#include <reg51.h>

#include <intrins.h>

unsigned char code dis_week[]={"SUN,MON,TUE,WED,THU,FRI,SAT"};

unsigned char code para_month[13]={0,0,3,3,6,1,4,6,2,5,0,3,5}; //星期月参变数

unsigned char data dis_buf1[16]; //lcd上排显示缓冲区

unsigned char data dis_buf2[16]; //lcd下排显示缓冲区

unsigned char data year,month,date,week;//年、月、日、星期

unsigned char data armhour,armmin,armsec;//闹钟时、分、秒

unsigned char data hour,min,sec,sec100; //时、分、秒、百分之一秒

unsigned char data flag,vkey,skey;//设置状态计数标志、按键先前值、按键当前值

bit alarm; //标识是否启用闹钟,1--启用,0--关闭

sbit rs = P2^4; //LCD数据/命令选择端(H/L)

sbit rw = P2^5; //LCD读/写选择端(H/L)

sbit ep = P2^6; //LCD使能控制

sbit PRE = P1^6; //调整键(AN3)

sbit SET = P1^7; //调整键(AN4)

sbit SPK = P2^3 ; //蜂鸣器接口

sbit DQ=P2^7; //温度输入口

unsigned char data temp_data[2] = {0x00,0x00} ;

unsigned char data display[5] = {0x00,0x00,0x00,0x00,0x00} ;

unsigned char code ditab[16] = {0x00,0x01,0x01,0x02,0x03,0x03,0x04,0x04,

0x05,0x06,0x06,0x07,0x08,0x08,0x09,0x09} ;

unsigned char code mytab[8] = {0x0C,0x12,0x12,0x0C,0x00,0x00,0x00,0x00} ;

// 延时程序

void delay(unsigned char ms)

{ while(ms--)

{ unsigned char i;

for(i = 0; i< 250; i++)

{ _nop_();_nop_();_nop_();_nop_(); //执行一条_nop_()指令为一个机器周期

}

}

}

//测试LCD忙碌状态

bit lcd_busy()

{ bit result;

rs = 0;

rw = 1;

ep = 1;_nop_();_nop_();_nop_();_nop_();

result =(bit)(P0&0x80); //LCD的D0--D7中,D7=1为忙碌,D7=0为空闲

ep = 0;

return result;

}

//写入指令到LCD

void lcd_wcmd(char cmd)

{ while(lcd_busy()); //当lcd_busy为1时,再次检测LCD忙碌状态,lcd-busy为0时,开始写指令

rs = 0;

rw = 0;

ep = 0;_nop_();_nop_();_nop_();

P0 = cmd;_nop_();_nop_();_nop_();_nop_();

ep = 1;_nop_();_nop_();_nop_();_nop_();

ep = 0;

}

//写入数据到LCD

void lcd_wdat(char dat)

{ while(lcd_busy()); //当lcd_busy为1时,再次检测LCD忙碌状态,lcd-busy为0时,开始写数据

rs = 1;

rw = 0;

ep = 0;

P0 = dat;_nop_();_nop_();_nop_();_nop_();

ep = 1; _nop_();_nop_();_nop_();_nop_();

ep = 0;

}

//LCD数据指针位置程序

void lcd_pos(char pos)

{ lcd_wcmd(pos|0x80); //数据指针=80+地址码(00H~27H,40H~67H)

}

//初始化ds1820 */

Init_DS18B20(void)

{

DQ = 1 ; //DQ复位

Delay(8) ; //稍做延时

DQ = 0 ; //单片机将DQ拉低

Delay(90) ; //精确延时 大于 480us

DQ = 1 ; //拉高总线

Delay(8) ;

presence = DQ ; //如果=0则初始化成功 =1则初始化失败

Delay(100) ;

DQ = 1 ;

return(presence) ; //返回信号,0=presence,1= no presence

}

// 读一个字节 */

ReadOneChar(void)

{

uchar i = 0 ;

uchar dat = 0 ;

for (i = 8 ; i > 0 ; i--)

{

DQ = 0 ; // 给脉冲信号

dat >>= 1 ;

DQ = 1 ; // 给脉冲信号

if(DQ) dat |= 0x80 ;

Delay(4) ;

}

return (dat) ;

}

// 写一个字节 */

WriteOneChar(unsigned char dat)

{

uchar i = 0 ;

for (i = 8 ; i > 0 ; i--)

{

DQ = 0 ;

DQ = dat&0x01 ;

Delay(5) ;

DQ = 1 ;

dat>>=1 ;

}

}

///读取温度 */

Read_Temperature(void)

{

Init_DS18B20() ;

WriteOneChar(0xCC) ; // 跳过读序号列号的操作

WriteOneChar(0x44) ; // 启动温度转换

Init_DS18B20() ;

WriteOneChar(0xCC) ; //跳过读序号列号的操作

WriteOneChar(0xBE) ; //读取温度寄存器

temp_data[0] = ReadOneChar() ; //温度低8位

temp_data[1] = ReadOneChar() ; //温度高8位

}

//设定二个自定义字符,(注意:LCD1602中自定义字符的地址为0x00--0x07,即可定义8个字符)

//这里我们设定把一个自定义字符放在0x00位置(000),另一个放在0x01位子(001)

void lcd_sef_chr()

{ //第一个自定义字符

lcd_wcmd(0x40); //"01 000 000" 第1行地址 (D7D6为地址设定命令形式 D5D4D3为字符存放位置(0--7),D2D1D0为字符行地址(0--7))

lcd_wdat(0x1f); //"XXX 11111" 第1行数据(D7D6D5为XXX,表示为任意数(一般用000),D4D3D2D1D0为字符行数据(1-点亮,0-熄灭)

lcd_wcmd(0x41); //"01 000 001" 第2行地址

lcd_wdat(0x11); //"XXX 10001" 第2行数据

lcd_wcmd(0x42); //"01 000 010" 第3行地址

lcd_wdat(0x15); //"XXX 10101" 第3行数据

lcd_wcmd(0x43); //"01 000 011" 第4行地址

lcd_wdat(0x11); //"XXX 10001" 第4行数据

lcd_wcmd(0x44); //"01 000 100" 第5行地址

lcd_wdat(0x1f); //"XXX 11111" 第5行数据

lcd_wcmd(0x45); //"01 000 101" 第6行地址

lcd_wdat(0x0a); //"XXX 01010" 第6行数据

lcd_wcmd(0x46); //"01 000 110" 第7行地址

lcd_wdat(0x1f); //"XXX 11111" 第7行数据

lcd_wcmd(0x47); //"01 000 111" 第8行地址

lcd_wdat(0x00); //"XXX 00000" 第8行数据

//第二个自定义字符

lcd_wcmd(0x48); //"01 001 000" 第1行地址

lcd_wdat(0x01); //"XXX 00001" 第1行数据

lcd_wcmd(0x49); //"01 001 001" 第2行地址

lcd_wdat(0x1b); //"XXX 11011" 第2行数据

lcd_wcmd(0x4a); //"01 001 010" 第3行地址

lcd_wdat(0x1d); //"XXX 11101" 第3行数据

lcd_wcmd(0x4b); //"01 001 011" 第4行地址

lcd_wdat(0x19); //"XXX 11001" 第4行数据

lcd_wcmd(0x4c); //"01 001 100" 第5行地址

lcd_wdat(0x1d); //"XXX 11101" 第5行数据

lcd_wcmd(0x4d); //"01 001 101" 第6行地址

lcd_wdat(0x1b); //"XXX 11011" 第6行数据

lcd_wcmd(0x4e); //"01 001 110" 第7行地址

lcd_wdat(0x01); //"XXX 00001" 第7行数据

lcd_wcmd(0x4f); //"01 001 111" 第8行地址

lcd_wdat(0x00); //"XXX 00000" 第8行数据

}

//LCD初始化设定

void lcd_init()

{ lcd_wcmd(0x38); //设置LCD为16X2显示,5X7点阵,八位数据借口

delay(5);

lcd_wcmd(0x0c); //LCD开显示及光标设置(光标不闪烁,不显示"-")

delay(5);

lcd_wcmd(0x06); //LCD显示光标移动设置(光标地址指针加1,整屏显示不移动)

delay(5);

lcd_wcmd(0x01); //清除LCD的显示内容

delay(5);

}

//闰年的计算

bit leap_year()

{

bit leap;

if((year%4==0&&year%100!=0)||year%400==0)//闰年的条件

leap=1;

else

leap=0;

return leap;

}

//星期的自动运算和处理

unsigned char week_proc()

{ unsigned char num_leap;

unsigned char c;

num_leap=year/4-year/100+year/400;//自00年起到year所经历的闰年数

if( leap_year()&& month<=2 ) //既是闰年且是1月和2月

c=5;

else

c=6;

week=(year+para_month[month]+date+num_leap+c)%7;//计算对应的星期

return week;

}

//更新显示缓冲区

void update_disbuf(unsigned char t1,unsigned char t2[],unsigned char dis_h,unsigned char dis_m,unsigned char dis_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]=t2[6]; //空格

if (alarm)

dis_buf2[7]=0x01; //alarm=1,显示闹钟启用标致(第二个自定义字符)

else

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;

}

//时间和日期处理程序

void pro_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)

if (date>30) {date=1;month++;} //小月30天

if (month==2)

{if( leap_year()) //闰年的条件

{if (date>29) {date=1;month++;}} //闰年2月为29天

else

{if (date>28) {date=1;month++;}} //平年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

}

}

//显示处理程序

void pro_display()

{ unsigned char i;

lcd_pos(0x00);

for (i=0;i<=15;i++)

{lcd_wdat(dis_buf1[i]);}

lcd_pos(0x40);

for (i=0;i<=15;i++)

{lcd_wdat(dis_buf2[i]);}

}

//Timer0中断处理程序,秒的产生

void timer0() interrupt 1

{

TH0=0xD8;

TL0=0xF0;

sec100++;

if(sec100 >= 100) //1秒时间 (100*10ms=1000ms=1s)

{sec100 = 0;

pro_timedate();//调用时间和日期处理程序

}

if (sec&0x01) //"RICHMCU"闪一秒,停一秒

update_disbuf(0x00," ",hour,min,sec); //0x00表示显示00位置的自定义字符

else

update_disbuf(0x00,"FMCLOCK",hour,min,sec);

Read_Temperature() ; //读取温度数值

pro_display(); //调用显示处理函数

}

//按键扫描程序

unsigned char scan_key()

{

skey=0x00; //给变量vkey置初值

skey|=PRE; //读取PRE键的状态

skey=skey<<1; //将PRE键的状态存于skey的B1位

skey|=SET; //读取SET键的状态,并存于skey的B0位

return skey; //返回skey的键值(即PRE,SET的状态)

}

//外部中断INT0中断处理程序

void int0() interrupt 0

{

TR0=0; //禁止Timer0

IE=0; //禁止中断

lcd_wcmd(0x0e); //显示光标"_",整个光标不闪烁

alarm=1;

update_disbuf(0x50,"alarm:",armhour,armmin,armsec); //更新显示数据,0x50表示要显示"P"

pro_display(); //调用显示处理程序

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) //将光标置于相应调整位置

{ case 1: lcd_pos(0x49);break; //光标置小时报警设置位置

case 2: lcd_pos(0x4c);break; //光标置分钟报警设置位置

case 3: lcd_pos(0x4f);break; //光标置秒时报警设置位置 case 4: update_disbuf(0x50,"time: ",hour,min,sec);pro_display();

lcd_pos(0x05);break; //光标置年调整位置 case 5: lcd_pos(0x08);break; //光标置月调整位置

case 6: lcd_pos(0x0b);break; //光标置日调整位置

case 7: lcd_pos(0x49);break; //光标置时调整位置

case 8: lcd_pos(0x4c);break; //光标置分调整位置

case 9: lcd_pos(0x4f);break; //光标置秒调整位置

default:break;} }

if (skey==0x02) //SET键按下

{ pro_key(); //转设置按键处理程序

} } }

}

lcd_wcmd(0x0c); //设置LCD开显示及光标不闪烁,不显示"-"

lcd_wcmd(0x01); //清除LCD的显示内容

IE=0x8f; //CPU开中断,INT0,INT1,开中断

TR0=1; //Timer0启动

}

//主程序,初始化及初值设定

void main()

{

lcd_init(); //初始化LCD

lcd_sef_chr(); //写入自定义字符号

hour=0;min=0;sec=0; //开机时的时,分,秒显示

armhour=9;armmin=0;armsec=0; //开机时的时,分,秒报警初值

year= 10; month=5;date=28; //开机时的年,月,日,星期显示

week_proc();

alarm=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; //Timer0启动

TR1 = 0;

while(1);

}

//设置按键处理程序

void pro_key()

{ switch (flag)

{

case 0:alarm=!alarm; //启用或关闭闹钟(alarm=1:启用,alarm=0:关闭)

update_disbuf(0x50,"alarm:",armhour,armmin,armsec); //更新显示数据

pro_display(); //调用显示处理

lcd_pos(0x47);break; //光标回到原调整位置

case 1:armhour++;

if (armhour>23) armhour=0;

update_disbuf(0x50,"alarm:",armhour,armmin,armsec); //更新显示数据

pro_display(); //调用显示处理

lcd_pos(0x49);break; //光标回到原调整位置

case 2:armmin++;

if (armmin>59) armmin=0;

update_disbuf(0x50,"alarm:",armhour,armmin,armsec);

pro_display();lcd_pos(0x4c);break;

case 3:armsec++;

if (armsec>59) armsec=0;

update_disbuf(0x50,"alarm:",armhour,armmin,armsec);

pro_display();lcd_pos(0x4f);break;

case 4:year++;

if (year> 99) year= 0;

week_proc(); //星期自动运算

update_disbuf(0x50,"time: ",hour,min,sec);

pro_display();lcd_pos(0x05);break;

case 5:month++;

if (month>12) month=1;

week_proc(); //星期自动运算

update_disbuf(0x50,"time: ",hour,min,sec);

pro_display();lcd_pos(0x08);break;

case 6:date++;

if (month==1||month==3||month==5||month==7||month==8||month==10||month==12)

if (date>31) date=1; //大月31天

if (month==4||month==6||month==9||month==11)

if (date>30) date=1; //小月30天

if (month==2)

{if(leap_year()) //闰年的条件

{if (date>29) date=1;} //闰年2月为29天

else

{if (date>28) date=1;}} //平年2月为28天

week_proc(); //星期自动运算

update_disbuf(0x50,"time: ",hour,min,sec);

pro_display();lcd_pos(0x0b);break;

case 7:hour++;

if (hour>23) hour=0;

update_disbuf(0x50,"time: ",hour,min,sec);

pro_display();lcd_pos(0x49);break;

case 8:min++;

if (min>59) min=0;

update_disbuf(0x50,"time: ",hour,min,sec);

pro_display();lcd_pos(0x4c);break;

case 9:sec++;

if (sec>59) sec=0;

update_disbuf(0x50,"time: ",hour,min,sec);

pro_display();lcd_pos(0x4f);break;

default: break ;

}

}

//Timer1中断处理程序,产生报警的声音

void timer1() interrupt 3

{ TH1=0xff;

TL1=0x00;

SPK=~SPK;

led=~led;

}

void int1() interrupt 2 //外部中断INT1中断处理程序,停止报警声音

{ if(TR1)TR1=0;

SPK=1;

}

附录2

系统总体原理图:

单片机课程设计报告

相关推荐