24h自动打铃系统设计
常 熟 理 工 学 院
电气与自动化工程学院
《单片机技术》课程设计
姓 名: 学 号: 班 级: 指导教师: 起止日期:
题目: 自动打铃系统设计
课程设计答辩记录
系 专业 班级 答辩人 课程设计题目
说明:主要记录答辩时所提的问题及答辩人对所提问题的回答
课程设计(论文)
题 目 名 称
2013年 4月 11 日
第一章 目录
第一章. 目录..........................................1
第二章. 课程设计任务书................................2
第三章. 总体设计方案..................................3
第四章. 操作及使用说明................................6
第五章. 硬件原理图....................................8
第六章. 程序流程.......................................9
第七章. 调试. 运行及其结果............................10
第八章. 收获及体会...................................10
第九章. 参考文献.....................................11
第十章. 代码及元件清单...............................12
第二章. 《单片机技术》课程设计任务书
题目:自动打铃系统设计
一、课程设计任务
本课题要求应用以51单片机为核心设计一自动打铃系统,能完成基本计时和显示功能,用LCD 显示时间、铃声可用蜂鸣器发出。
二、课程设计目的
通过本次课程设计使学生掌握:1)掌握以单片机为核心的控制系统的分析和设计的基本方法;2)控制程序的设计及实现方法;3)提高学生对单片机实时控制系统的设计和调试能力。
三、课程设计要求
基本计时和显示功能(用24小时制显示) 。包括上下午标志,时、分的数字显示,秒信号指示,并能设置当前时间(含上、下午,时,分) 。 能实现基本打铃功能,规定:
上午8:00上课铃:打铃10秒、停2秒、再打铃10秒。 下午5:30下课铃:打铃10秒、停2秒、再打铃10秒。
四、课程设计内容
1、人机对话“界面”的设计; 2、内存端口及外设的设置; 3、硬件电路原理图、软件清单。
第三章. 总体设计方案
设计方案选择
方案一:数字电路设计的自动打铃系统
利用函数信号发生器来进行脉冲信号输出,利用74160N 来设置十进制和六进制的进位输出。利用数码显示器来显示时间,利用或门、与门、非门、与非门、等电路元件进行组合实现打铃的控制。
方案二:基于单片机的自动打铃系统设计
单片机内部存储器设三个字节分别存放时钟的时、分、秒信息。利用定时器与软件结合实现1秒定时中断,每产生一次中断,存储器内相应的秒值加1;若秒值达到60,则将其清零,并将相应的分字节值加1;若分值达到60,则清零分字节,并将时字节值加1;若时值达到24,则将时字节清零。建立完一个实时时钟后接下来进行定时处理和打铃输出,当主程序检测到有分进位标志时,便开始比较当前时间与信息时间表上的作息时间是否相同,相同者,则进行报时处理并控制打铃,不相同则返回主程序。
方案确定
方案一的设计只能事先设定打铃时间不能完全自动打铃,且在修改打铃时间上存在一定的困难。而方案二中的设计能完全实现自动化,诠释了我们这次毕业设计的主题。并在修改打铃时间上有了很大的方便,只需修改一部分程序便能实现不同的需要。
因此我选择方案二进行设计。
基本方案
1. 设计课题简要概述
自动打铃装置用于工厂、学校等地的时间控制,本设计是按照学校作息时问设定的,模拟了电了钟显示时、分、秒。还根据学校的作息时间按时打铃,本系统有4 个按钮,分别用来调时、调分、秒和强制打铃及强制关铃,以保证始终与标准时间相吻合。
首先设计出本系统的硬件基本框图,根据框图设计电气原理图,简要概述基本原理,按照设计技术参数设计出各部分程序。
.2.. 系统软硬件划分
由于需要最小系统设计,因此,极大地介于系统的硬件成本,所有能用软件实现的功能都用软件完成,如按键的去抖,采用延时,显示部分用动态显示等,这样硬件部分的设计可以采用单片机最小系统,所谓最小系统时仅有程序存储器和时钟及复位电路的单片机系统。
3.. 单片机选型
根据课题的具体内容,任务要求,计时、校时、定时、键盘显示等功能,经多方面考虑,所选系统选项用.与MSC-51单片机完全兼容的A T89C51 低功耗单片机。
AT89C51单片机性能介绍
A T89C51是一种带4K 字节闪烁可编程可擦除只读存储器的低电压,高性能CMOS8位微处理器,俗称单片机。该器件采用A TMEL 高密度非易失存储器制造技术制造,与工业标准的MCS-51指令集和输出管脚相兼容。由于将多功能8位CPU 和闪烁存储器组合在单个芯片中,A TMEL 的A T89C51是一种高效微控制器,为很多嵌入式控制系统提供了一种灵活性高且价廉的方案。 引脚说明:
VCC :供电电压。
P0口:P0口为一个8位漏级开路双向I/O口,每脚可吸收8TTL 门电流。当P1口的管脚第一次写1时,被定义为高阻输入。P0能够用于外部程序数据存储器,它可以被定义为数据/地址的第八位。在FIASH 编程时,P0 口作为原码输入口,当FIASH 进行校验时,P0输出原码,此时P0外部必须被拉高。
P1口:P1口是一个内部提供上拉电阻的8位双向I/O口,P1口缓冲器能接收输出4TTL 门电流。P1口管脚写入1后,被内部上拉为高,可用作输入,P1口被外部下拉为低电平时,将输出电流,这是由于内部上拉的缘故。在FLASH 编程和校验时,P1口作为第八位地址接收。
P2口:P2口为一个内部上拉电阻的8位双向I/O口,P2口缓冲器可接收,输出4个TTL 门电流,当P2口被写“1”时,其管脚被内部上拉电阻拉高,且作为输入。并因此作为输入时,P2口的管脚被外部拉低,将输出电流。这是由于内部上拉的缘故。P2口当用于外部程序存储器或16位地址外部数据存储器进行存取时,P2口输出地址的高八位。在给出地址“1”时,它利用内部上拉优势,当对外部八位地址数据存储器进行读写时,P2口输出其特殊功能寄存器的内容。P2口在FLASH 编程和校验时接收高八位地址信号和控制信号。
P3口:P3口管脚是8个带内部上拉电阻的双向I/O口,可接收输出4个TTL 门电流。当P3口写入“1”后,它们被内部上拉为高电平,并用作输入。作为输入,由于外部下拉为低电平,P3口将输出电流(ILL )这是由于上拉的缘故。P3口也可作为A T89C51的一些特殊功能口,如下表所示: 口管脚 备选功能
P3.0 RXD(串行输入口)P3.1 TXD(串行输出口)P3.2 /INT0(外部中断0)
P3.3 /INT1(外部中断1)P3.4 T0(记时器0外部输入)P3.5 T1(记时器1外部输入) P3.6 /WR(外部数据存储器写选通)P3.7 /RD(外部数据存储器读选通) P3口同时为闪烁编程和编程校验接收一些控制信号。89C51各部分引脚图如下:
引脚图
第四章. 操作及使用说明
按钮控制模块
三个按钮的一端分别接地,另一端接单片机一个端口的三个引脚,当某一个按钮按下的时候,其对应的引脚就由高电平变成低电平,然后通过单片机扫描读取引脚的电平来判断按钮是否按下。
采用动态扫描方式,通过一组单片机端口驱动并联在一起的LCD 发光管的一端(共阴或共阳端) ,LCD 发光管的另一脚接通用I/O口,控制其亮灭。该方法能驱动较多的LCD ,控制方式较灵活,而且节省单片机的资源
按钮控制 蜂鸣器
蜂鸣器驱动模块
采用无源式蜂鸣器,蜂鸣器根据结构不同分为压电式蜂鸣器和电磁式蜂鸣器;而两种蜂鸣
器又分为有源蜂鸣器和无源蜂鸣器,本设计只是通过简单延时达到驱动蜂鸣器的效果。 按钮S1:设置时间及日期按钮。 按钮S2:增加。
按钮S3:减少。
使用过程中注意按钮的使用,及反应时间。
显示器模块
LCD1062
液晶显示是通过液晶显示模块实现的。液晶显示模块(LCD Module)是一种将液晶显示器件,连接件,集成电路,PCB 板,背光源,结构件装配在一起的组件。
第五章. 硬件原理图
第六章. 程序流程及代码清单
N
第七章. 调试. 运行及其结果
实现计时和显示功能(24小时制),可设置当前时间(包括上下午标志,时、分的数字显示),能在上午8:00和下午5:30定点打铃,且每次打铃均为响铃10s ,停2s ,再响10s 。
系统误差及性能分析
经测试该简易自动打铃系统在一天内会出现时间误差,该误差主要是由于晶振自身的误差
所造成的。另外在中断的过程中,只会在第一次计时时产生时间的偏移,而它所产生累积误差很大。
第八章. 收获体会
通过这次课程设计,我得到了很多收获和体会,懂得了团队合作的重要性和必要性,以及工程设计的大体过程。
第一,巩固和加深了对单片机基本知识和理解,提高了综合运用所学知识的能力。 第二,增强了根据课程需要选学参考资料,查阅手册,图表和文献资料的自学能力。通过独立思考,深入研究有关问题,学会自己分析解决问题的方法。
第三,通过实际方案的分析比较,设计计算,安装调试等环节,初步掌握了简单使用电路的分析方法和工程设计方法。
第四,在这次课程设计过程中,光有理论知识是不够的,还必须懂一些实践中的知识。所以在课程设计的实践中,我们应将实验课与课堂教学结合起来,锻炼自己的理论联系实际的能力与实际动手能力。
第五,掌握了比较常用的仪器的使用方法,提高了动手能力。 第六,培养了严谨的工作作风和科学态度。
总之这次课程设计,培养了我们综合应用单片机原理及应用的理论知识和理论联系实际的能力;在设计的过程中还培养了我们的团队精神,同学共同协作,一齐商量讨论,解决了许多问题。这一切都令我们受益匪浅,在今后的学习工作中我们会一如既往,不断努力。 经过近几天的课程设计,我充分认识到理论知识和实践结合的重要性。经过半年多的理论
基础的学习,我成功的将理论运用如实践,并成功的运用单片机,以前只是在路上看见那些交通灯,但是并没有认真的研究交通灯的内部控制原理,还有单片机上那些芯片的功能和引脚图平常也不是常接触,通过这次系统设计让我清楚如果想做一个产品该怎样思考。此次课程设计持续的时间较长,对我的耐心是一种极大的考验,同时学校的支持力度也应该加强,而不应该对学生的提问表示不解,对有些程序的编写要及时的给予指导,当然学生也要积极的配合老师的工作,努力将自己所学的知识尽可能的运用到对方案的设计中去。感谢王小英老师的细心指导、和伙伴之间的配合。
第九章. 参考文献
[1] 张鑫. 单片机原理及应用[M].北京:电子工业出版社,2005.8. [2] 康光华. 电子技术基础. 模拟部分[M].北京:高等教育出版社,2006.1. [3] 康光华. 电子技术基础. 数字部分[M].北京:高等教育出版社,2006.1.
[4] 祁伟, 杨亭. 单片机C51程序设计教程与实验[M].北京:北京航空航天大学出版社,2006. [5] 楼然苗. 李光飞. 单片机课程设计指导[M].北京:北京航空航天大学出版社,2007.4 [6] 单片机学习网www.mcustudy.com
第十章. 代码及元件清单
代码:
#include #define uchar unsigned char #define uint unsigned int
#define datasend P0
sbit lcden=P3^4; //LCD使能端
sbit lcdrs=P3^5; //LCD 数据/指令(H/L)选择端 sbit s1=P1^0; //定义功能按键
sbit s2=P1^1; //定义时分秒 +1 按键 sbit s3=P1^2; //定义时分秒 -1 按键 sbit knock=P2^0;
uchar mytable0[]=" Hello "; uchar mytable1[]="Good moring";
uchar code line0[]=" 2013-04-10 "; //初始化显示
uchar code line1[]=" AM00:00:00 ";
uchar code month0[]={31,28,31,30,31,30,31,31,30,31,30,31}; //平年月 uchar code month1[]={31,29,31,30,31,30,31,31,30,31,30,31}; //闰年月 uchar count,hour,minute,second,year=1,month=1,date=1;
uchar s1num; //s1num:定义功能键按下次数变量 void delay_ms(int ms) {int i,j;
for(i=ms;i>0;i--)
for(j=0;j
void delay(unsigned int z) //延时子函数 z*1ms {
unsigned int x,y; for(x=z;x>0;x--) for(y=110;y>0;y--);
}
void write_com(unsigned char c) //写命令子函数 {
lcdrs=0; //低电平选择为 写指令 lcden=0;
datasend=c; //把指令写入P1口 delay(5); //参考时序图 lcden=1; //开使能 delay(5); //读取指令 lcden=0; //关闭使能 }
void write_data(unsigned char d) //写数据子函数 {
lcdrs=1; //高电平选择为 写数据 datasend=d; //把数据写入P0口 delay(5); //参考时序图 lcden=1; //开使能 delay(5); //读取数据 lcden=0; //关闭使能
}
void write_hms(uchar add,uchar dat) //时分秒写函数 add :输入位置设置变量 dat :输入时分秒数据
{
uchar sw,gw; //定义十位,个位变量 sw=dat/10;
gw=dat%10;
write_com(0x80+0x40+add); //从第二行(add)位开始写数据 write_data(0x30+sw); //写入十位 write_data(0x30+gw); //写入个位
}
void write_ymd(uchar add,uchar dat) //年月日写函数 add :输入位置设置变量 分秒数据
{
uchar sw,gw; //定义十位,个位变量 sw=dat/10; gw=dat%10;
write_com(0x80+add); //从第一行(add)位开始写数据 write_data(0x30+sw); //写入十位 write_data(0x30+gw); //写入个位
}
void t0() interrupt 1 //定时器0中断子程序 {
TH0=(65536-50000)/256; TL0=(65536-50000)%256; count++;
}
void gethms() //时分秒处理子程序 {
int i; second++;
if((( hour==8)&&(minute==0))||((hour==17)&&(minute==30))) {
if(((second>=0)&&(second=12)&&(second
for(i=0;i
dat :输入时
}
}
if(second==60) {
second=0; minute++; if(minute==60) {
minute=0; hour++; if(hour==24) {
hour=0; date++;
}
write_hms(2,hour); //时输出显示 }
write_hms(5,minute); //分输出显示 }
write_hms(8,second); //秒输出显示
}
void getymd() //年月日处理子程序 {
if(year%4==0) {
if(date==month1[month-1]+1) {
date=1; month++;
if(month==13) {
month=1; year++;
if(year==100) {
year=1; }
write_ymd(4,year); }
write_ymd(7,month); }
write_ymd(10,date); }
else
{
if(date==month0[month-1]+1) {
date=1; month++; if(month==13) { month=1; year++; if(year==100) {
year=1;
}
write_ymd(4,year); }
write_ymd(7,month); }
write_ymd(10,date); }
}
void keyscan() //按键扫描子程序 {
if(s1==0) //功能键 S1 功能设置 {
delay(5);
if(s1==0) //功能键按下
{
while(s1==0); //松手检测
s1num++; //功能键按下计数
TR0=0; //T0定时停止,进入时间调整
switch(s1num) {
case 1: write_com(0x80+0x40+0x09); break; //光标闪烁位定为秒个位 case 2: write_com(0x80+0x40+0x06); break; //光标闪烁位定为分个位 case 3: write_com(0x80+0x40+0x03); break; //光标闪烁位定为时个位 case 4: write_com(0x80+0x0b); break; //光标闪烁位定为日个位 case 5: write_com(0x80+0x08); break; //光标闪烁位定为月个位 case 6: write_com(0x80+0x05); break; //光标闪烁位定为年个位 }
write_com(0x0f); //光标闪烁 if(s1num==7) {
s1num=0; //按键计数复位
write_com(0x0c); //光标停止闪烁 TR0=1; //重新启动定时器 } } }
if(s2==0) //S2键 时分秒 +1 模块 {
delay(5); if(s2==0) {
while(s2==0);
switch(s1num) {
case 1: second++; //秒+ if(second==60) second=0; //复位
write_hms(8,second); //秒输出显示
write_com(0x80+0x40+0x09); //光标闪烁位定为秒个位 break;
case 2: minute++;
if(minute==60) minute=0; //复位
write_hms(5,minute); //分输出显示
write_com(0x80+0x40+0x06); //光标闪烁位定为分个位 break; case 3: hour++;
if(hour==24) hour=0; //复位
write_hms(2,hour); //时输出显示
write_com(0x80+0x40+0x03); //光标闪烁位定为时个位 break;
case 4: date++; //日+ if(year%4==0) //平闰年判断 {
if(date==month1[month-1]+1) { date=1; } } else {
if(date==month0[month-1]+1) { date=1; } }
write_ymd(10,date); //日输出显示
write_com(0x80+0x0b); //光标闪烁位定为日个位 break;
case 5: month++; //月+
if(month==13) month=1;
if(year%4==0) //判断日和月的配对关系 {
if(date>month1[month-1]) date=month1[month-1]; } else
{
if(date>month0[month-1]) date=month0[month-1]; }
write_ymd(10,date); //日输出显示
write_ymd(7,month); //月输出显示
write_com(0x80+0x08); //光标闪烁位定为月个位 break;
case 6: year++; //年+ if(year==100) year=1; //复位
write_ymd(4,year); //年输出显示
write_com(0x80+0x05); //光标闪烁位定为年个位 break; } } }
if(s3==0) //时分秒 -1 模块 {
delay(5); if(s3==0) {
while(s3==0);
switch(s1num) {
case 1: second--; //秒- if(second==255) second=59; //复位 write_hms(8,second); //秒输出显示
write_com(0x80+0x40+0x09); //光标闪烁位定为秒个位 break;
case 2: minute--;
if(minute==255) minute=59; //复位
write_hms(5,minute); //分输出显示
write_com(0x80+0x40+0x06); //光标闪烁位定为分个位 break;
case 3: hour--;
if(hour==255) hour=23; //复位
write_hms(2,hour); //时输出显示
write_com(0x80+0x40+0x03); //光标闪烁位定为时个位 break;
case 4: date--; //日- if(year%4==0) {
if(date==0) {
date=month1[month-1]; } } else {
if(date==0)
{
date=month0[month-1]; }
}
write_ymd(10,date); //日输出显示
write_com(0x80+0x0b); //光标闪烁位定为日个位 break;
case 5: month--; //月-
if(month==0) month=12;
if(year%4==0) //判断日和月的配对关系 {
if(date>month1[month-1]) date=month1[month-1]; } else
{
if(date>month0[month-1]) date=month0[month-1]; }
write_ymd(10,date); //日输出显示
write_ymd(7,month); //月输出显示
write_com(0x80+0x08); //光标闪烁位定为月个位 break;
case 6: year--; //年- if(year==0) year=99; //复位
write_ymd(4,year); //年输出显示
write_com(0x80+0x05); //光标闪烁位定为年个位 break; } }
}
void initialize() //LCD初始化函数 {
uchar num;
lcden=0;
write_com(0x38); //设置16x2显示,5x7点阵显示,8位数据接口
write_com(0x0c); //00001DCB,D(开关显示) ,C(是否显示光标) ,B(光标闪烁,光标不显示) write_com(0x06); //000001N0,N(地址指针+-1)
write_com(0x01); //清屏指令 每次显示下一屏内容时,必须清屏
write_com(0x80+0x10); //第一行,前头空5格显示 for(num=0;num
write_data(mytable0[num]); delay(10);
}
write_com(0x80+0x50); //第二行,从第一格开始显示 for(num=0;num
write_data(mytable1[num]);
delay(10); }
for(num=0;num
write_com(0x1c); //0001(S/C)(R/L)**; S/C:高电平移动字符,低电平移动光标; 高电平左移,低电平右移 delay(300); }
delay(1000);
write_com(0x01); //清屏指令 每次显示下一屏内容时,必须清屏 write_com(0x80); //第一行,顶格显示
for(num=0;num
write_data(line0[num]); delay(10);
}
write_com(0x80+0x40); //第二行,顶格显示
for(num=0;num
write_data(line1[num]); delay(10); }
R/L:
TMOD=0x01; //定时器0中断初值设置 TH0=(65536-50000)/256; TL0=(65536-50000)%256; EA=1; ET0=1; TR0=1; }
void main()
{
initialize(); //初始化 while(1)
{
keyscan(); //按键扫描
if(count==20) //定时1s 运行模块 {
count=0;
gethms(); //时分秒数据处理 getymd(); //年月日数据处理 } }
}
元件清单: