智能电子钟课程设计论文
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
专业方向课程设计报告题目:智能电子钟
智能电子钟
一、设计要求
制作一个LCD显示的智能电子钟:
(1) 计时:秒、分、时、日、月、年、星期。
(2) 闰年自动判别。
(3) 时间、年、月、日、星期交替显示。
(4) 自定任意时刻自动开/关屏。
(5) 计时精度:误差≤1秒/月(具有微调设置)。
二、方案论证
1.时钟方案
方案一:软件时钟。
可以节约硬件成本,但是软件编写更为复杂,且误差较大。
方案二:硬件时钟。
使用时钟芯片DS1302,虽然增加了硬件成本,但可直接从芯片读取时间及日期数据,大大简化软件的编写,且计时精度高,满足设计要求。
因此,本智能电子钟采用硬件时钟。
2.软件编程方案
方案一:所有子程序均处于主程序中。
虽然最终仅一个程序文件,但由于本智能电子钟需用液晶显示屏显示且需根据不同按键状态转换至不同的功能,子程序较多,相应程序的层次结构也较复杂,若采用该方案,不仅很大程度地加大了软件编写的难度,而且会使程序显得复杂冗长,易读性很差。
方案二:监控程序。
将各种功能定义为多个任务,用监控程序进行任务调度的工作,主函数进行各种初始化、控制及调用子函数等工作,而各子函数则完成相应功能。
该方案虽然要使用监控程序并且最终会有多个源程序文件,但由于移植性很好,各种功能模块定义清晰,体现了模块化的思想,不仅降低了软件编写的难度,也增强了程序的易读性。
因此,本智能电子钟采用监控程序进行任务调度工作。
3.按键方案
方案一:一键一义型按键。
每按下一个按键,就获得一个键盘编码信息,由键码散转到对应功能模块的入口,启动对应作业。
该方案可使用以下三种方式获取键值:①单纯查询,主程序用扫描键盘等方式来获取键盘信息,执行对应作业。
②键盘中断,按下任何按键都引起一个外部中断请求,键码分析过程放在外部中断子程序中。
③定时查询,每隔一段时间查询一次键盘,键盘查询过程安排在定时中断中完成。
但由于一个按键只对应一个功能,在实现功能较多的情况下,所需按键数较多,不仅会加大成品体积,不易操作,也会增加总的硬件成本。
方案二:一键多义型按键。
不根据当前获得的一个键码来决定哪一个作业投入运行,而是根据一个按键操作系列来启动一个作业,同一按键在不同操作系列中有不同的含义。
该方案所需按键较少,因此占用的端口数较少,并且减少了硬件成本,成品体积也较小,虽然在一定程度上,增加了按键功能分配的难度,但综合考虑,本智能电子钟采用一键多义型按键。
三、理论设计
1.硬件系统
1.1硬件原理图
1.2硬件总体框图
1.3工作原理
以单片机为核心,结合软件及硬件完成设计要求。
在硬件上,时钟芯片DS1302提供时间及日期数据,LCD1602则显示时间、日期、闹钟等信息,闹钟铃声用蜂鸣器发出,而软件上,主程序通过对各子程序的调用,初始化时钟芯片、液晶显示屏,接收时间、日期数据,按键信息等,并输出显示信息及各种控制信息。
2.软件系统
2.1软件流程图
2.2监控程序
2.2.1OS_CORE.C
OSIntSendSignal中断中给指定任务发送信号,使指定任务就绪OSSendSignal任务中给指定任务发送信号,使指定任务就绪OSClearSignal清除指定任务信号,使指定任务休眠
OSIntExit中断退出处理函数,在此进行中断后的任务切换OSSched非中断的任务切换函数
OSTimeTick系统时钟处理函数,处理各个任务的延时
OSWait系统等待函数,任务调用此函数可以等待一定时间或信号2.2.2OS_Q.C
OSQCreate初始化消息队列
OSQPend等待消息队列中的消息
OSQAccept无等待从消息队列中取得消息
OSQIntPost中断中FIFO方式发送消息
OSQIntPostFront中断中LIFO方式发送消息
OSQPostFIFO方式发送消息
OSQPostFrontLIFO方式发送消息
OSQNMsgs取得消息队列中消息数
OSQSize取得消息队列总容量
OSQFlush清空队列
2.2.3OS_SEM.C
OSSemCreate初始化消息队列
OSSemPend等待一个信号量
OSSemAccept无等待请求信号量
OSSemIntPost中断中发送一个信号量
OSSemPost发送一个信号量
OSSemQuery查询信号量
2.2.4OS_CPU_C.C
OSIdle优先级最低的任务
OSStartSmall RTOS 51初始化函数,调用此函数后多任务开始运行,首先执ID为0的任务OSTickISR系统时钟中断服务函数
2.2.5OS_CPU_A.ASM
LoadCtx任务环境恢复函数
OSCtxSw任务主动放弃CPU环境保存函数
C_OSCtxSw 堆栈处理函数
OSIntCtxSw中断使任务放弃CPU环境保存函数
2.2.6key.C
KeyInput键盘输入服务任务
2.3子程序
2.3.1DS1302.C
#include"config.h"
uint8 xdata DS1302GetData[7];//秒、分、时、日、月、星期、年
uint8 xdata DS1302Temp0[9] = {"23-59-50"};//秒、分、时
uint8 xdata DS1302Temp1[11] = {"2012-01-01"};//年、月、日
uint8 xdata DS1302Week[4] = {"Mon"};//星期
void DS1302WriteByte(uint8 Data);
uint8 DS1302ReatByte();
void DS1302Write(uint8 Addr,uint8 Data);
uint8 DS1302Read(uint8 Addr);
uint8 GetTime();
void DS1302Time();
void WriteTime(uint8 Num,uint8 Tdat);
void DS1302Init();
2.3.2LCD1602.C
#include "config.h"
void Delay1602US();/*延时*/
void LCD1602SendComm(uint8 Command);/*液晶显示屏写命令*/
void LCD1602SendData(uint8 Data);/*液晶显示屏写数据*/
void LCD1602DispStr(uint8 x, uint8 y, char *Data);/*在lcd指定位置显示一个字符串*/ void LCD1602Disp(uint8 x,uint8 y,char Str);/*在lcd指定位置显示一个字符串*/
void LCD1602Clr(uint8 y);/*清除lcd的指定行*/
void LCD1602Init(void);/*lcd初始化*/
void LCD1602LoadC(uint8 Addr, uint8 *Data, uint8 NChar);/*从lcd指定地址处写多个字节数据*/
2.4主程序main.c
#include"config.h"
sbit led = P2^0;
sbit SwitchOn = P2^1;
uint8 Flag0 = 0;/*时间闪烁标志*/
uint8 Flag1 = 0;/*时间闪烁暂存标志*/
uint8 Flag2 = 0;/*显示数据标志*/
uint8 Flag3 = 0;/*闹钟暂存标志*/
uint8 Flag4 = 0;/*闹钟闪烁标志*/
uint8 Flag6 = 0;/*自定义开关屏闪烁标志*/
uint8 Flag7 = 0;/*自定义开关屏闪烁标志*/
bit Flag5 = 0;/*秒表显示标志*/
bit Flag8 = 0;/*日期显示标志*/
bit AlarmSwitch0;/*闹钟开标志*/
bit AlarmSwitch1;/*闹钟关标志*/
bit Flag9 = 0;/*自动校时标志*/
bit Flag10 = 0;/*自动校时标志*/
bit Flag11 = 0;/*自定义开关屏标志*/
bit Flag12 = 0;/*自定义开关屏标志*/
uint8 Ahour,Amin;/*闹钟变量*/
uint8 Shour,Smin;/*自定义开屏变量*/
uint8 Ehour,Emin = 1;/*自定义关屏变量*/
uint8 Day1;/*自定义校时变量*/
uint16 Sec;/*秒表变量*/
uint8 xdata Temp3[] = {"00-00"};/*闹钟数据显示变量*/
uint8 xdata Temp4[] = {"00-00"};/*秒表数据显示变量*/
uint8 xdata Temp5[] = {"00-00"};/*自定义开屏数据显示变量*/
uint8 xdata Temp6[] = {"00-00"};/*自定义关屏数据显示变量*/
uint8 code Temp1[] = {31,29,31,30,31,30,31,31,30,31,30,31};/*闰年月份天数*/
uint8 code Temp2[] = {31,28,31,30,31,30,31,31,30,31,30,31};/*平年月份天数*/
void main()
{
TMOD = 0x11;
ET0 = 1;
ET1 = 1;
TR0 = 1;
TH1 = (65536 - 20000) / 256;
TL1 = (65536 - 20000) % 256;
LCD1602Init();
DS1302Init();
OSStart();
}
void TaskA();/*按键扫描并查找高优先级任务*/
void TaskB();/*时间按键处理任务*/
void TaskC();/*日期按键处理任务*/
void TaskD();/*闹钟按键处理任务*/
void TaskE();/*秒表按键处理任务*/
void TaskF();/*自定义开关屏按键处理任务*/
void TaskG();/*液晶扫描及显示处理任务*/
void TaskH();/*蜂鸣器处理任务*/
void Time1() interrupt 3/*定时10毫秒*、
{
TH1 = (65536 - 20000) / 256;
TL1 = (65536 - 20000) % 256;
if(++Sec >= 10000)
{
Sec = 0;
}
Temp4[4] = Sec % 10 + 0x30;
Temp4[3] = Sec / 10 % 10 + 0x30;
Temp4[1] = Sec / 100 % 10 + 0x30;
Temp4[0] = Sec / 1000 % 10 + 0x30;
//OSLCD1602DispStr(6,2,Temp4);
}
void Alarm();/*闹钟显示计时*、
{
Temp3[4] = Amin % 10 + 0x30;
Temp3[3] = Amin / 10 + 0x30;
Temp3[1] = Ahour % 10 + 0x30;
Temp3[0] = Ahour / 10 + 0x30;
}
void Flash()/*时间位标志*/
{
switch(Flag0)
{
case 1: OSLCD1602DispStr(8,1," ");break;
case 2: OSLCD1602DispStr(5,1," ");break;
case 3: OSLCD1602DispStr(13,1," ");break;
case 4: OSLCD1602DispStr(10,1," ");break;
case 5: OSLCD1602DispStr(7,1," ");break;
case 6: OSLCD1602DispStr(2,1," ");break;
default:break;
}
}
void AlarmFlash()/*闹钟闪烁*/
{
switch(Flag4)
{
case 1: OSLCD1602DispStr(9,1," ");break;
case 2: OSLCD1602DispStr(6 ,1," ");break;
default: break;
}
}
void SwitchFlash()/*自定义开关屏*/
{
switch(Flag7)
{
case 1: OSLCD1602DispStr(9,1," ");break;
case 2: OSLCD1602DispStr(6 ,1," ");break;
case 3: OSLCD1602DispStr(9,2," ");break;
case 4: OSLCD1602DispStr(6 ,2," ");break;
default: break;
}
}
void TimeCompare()/*时间与闹钟时间及自定义开关屏时间比较*/
{
if((DS1302GetData[2] == Shour) && (DS1302GetData[1] == Smin) && Flag11)
{
led = 1;
Flag11 = 0;
OSLCD1602Clr(1);
OSLCD1602Clr(2);
OSLCD1602DispStr(2,1,"Yu Li ling shi ke shui chong");
}
if((DS1302GetData[2] == Ehour) && (DS1302GetData[1] == Emin) && Flag12)
{
led = 0;
Flag12 = 0;
OSLCD1602Clr(1);
OSLCD1602Clr(2);
}
if((DS1302GetData[2] == Ahour) && (DS1302GetData[1] == Amin) && AlarmSwitch0) {
AlarmSwitch1 = 1;
Flag9 = 1;
}
else
{
AlarmSwitch1 = 0;
SwitchOn = 1;
}
if(((DS1302GetData[1] - Amin) % 5 == 0) && AlarmSwitch0 && Flag9)
{
AlarmSwitch1 = 1;
}
if(!AlarmSwitch0)
{
Flag9 = 0;
}
if((DS1302GetData[2] == 23) && (DS1302GetData[1] == 59) && (DS1302GetData[0] == 59)&& Flag10)
{
DS1302GetData[0] = DS1302GetData[0] - 1; //时间校准
WriteTime(0,DS1302GetData[0]);
Flag10 = 0;
}
if(DS1302GetData[3] !=Day1)
{
Flag10 = 1;
}
Day1 = DS1302GetData[3];
}
四、电路仿真及仿真结果分析
1.仿真电路图
2.仿真过程及结果分析
将生成的HEX文件加载至单片机中,然后启动仿真。
由于对液晶显示屏进行仿真要进行忙状态检测,但该仿真软件无该检测机制,所以需对程序进行相应修改,然后即可看见仿真结果。
五、测试方案与测试结果
连接计算机并下载相应程序,进行实际的硬件功能测试。
1.日期显示
2.时钟显示
3.闹钟显示
4.秒表显示
六、作品功能和使用说明
本智能电子钟共有四个可切换显示状态,可实现时间、日期、闹钟、秒表及自定义开关屏功能。
在不同的显示状态下,各按键基本功能如下:
Reset:复位
Key1:组合按键
Key2:加1
Key3:定位或开始/停止
Key4:显示切换
在任意显示状态下,Key1与Key2组合可实现背光灯开/关功能;当显示时间时, Key1与Key3组合可实现开启闹钟的功能, Key1与Key4组合可实现日期显示功能;当自定义开关屏时, Key1与Key3组合可实现该功能。
七、心得体会
本次设计硬件结构较简单,然而由于要进行多种功能切换,虽然使用了监控程序进行任务调度的工作,软件编写仍有一定难度,不仅在不同的状态下,要在液晶显示屏上显示不同的信息,变化不同的显示状态,并且在该状态下还要响应按键操作,进行不同的功能切换。
虽然将程序结构进行了模块化划分,其层次结构仍较为复杂,子函数、标志变量也较多,所以软件编写是本系统设计的一大难点。
通过本次设计,体会到一个功能的实现方式并不唯一,也许某种方式可以实现该功能,但仍可以找到另外的一种或多种方式实现同种功能,对于方案的选择,要进行方案对照,分析各种方案的优缺点,综合权衡,选择出在当前情况下的最优方案,才能在最大限度上缩短软件开发周期,减少硬件成本,同时又能实现满足要求的功能。
八、参考文献
[1]周航慈,朱兆优,李跃忠.智能仪器原理与设计.北京:航空航天大学出版社,2005.3
[2]胡汉才.单片机原理及其接口技术.北京:清华大学出版社,2010.5
[3]何小艇.电子系统设计.杭州:浙江大学出版社,2013.1。