单片机电子万年历课程设计
单片机课程设计~
姓名:吕长明
学号:021
专业班级:机电四班
)
一、单片机原理及应用简介
随着国内超大规模集成电路的出现,微处理器及其外围芯片有了迅速的发展。集成技术的最新发展之一是将CPU和外围芯片,如程序存储器、数据存储器、并行、串行I/O口、定时/计数器、中断控制器及其他控制部件集成在一个芯片之中,制成单片计算机(Single-Chip Microcomputer)。而近年来推出的一些高档单片机还包括有许多特殊功能单元,如A/D、D/A 转换器、调制解调器、通信控制器、锁相环、DMA、浮点运算单元等。因此,只要外加一些扩展电路及必要的通道接口就可以构成各种计算机应用系统,如工业控制系统、数据采集系统、自动测试系统、万年历电子表等。
二、系统硬件设计
(
8052 是标准的40引脚双列直插式集成电路芯片,引脚分布请参照----单片机引脚图图1:
(
图1 8052引脚
~ P0口8位双向口线(在引脚的39~32号端子)。
*
~ P1口8位双向口线(在引脚的1~8号端子)。
~ P2口8位双向口线(在引脚的21~28号端子)。
~ P2口8位双向口线(在引脚的10~17号端子)。
8052芯片管脚说明:
VCC:供电电压。
GND:接地。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口也可作为AT89C51的一些特殊功能口,如表1所示:
表1 特殊功能口
P3口同时为闪烁编程和编程校验接收一些控制信号。
RST:复位输入。当振荡器复位器件时,要保持RST脚两个机器周期的高电平时间。
#
ALE/PROG:当访问外部存储器时,地址锁存允许的输出电平用于锁存地址的地位字节。在FLASH编程期间,此引脚用于输入编程脉冲。一般情况下,ALE端以不变的频率周期输出正脉冲信号,此频率为振荡器频率的1/6。因此它可用作对外部输出的脉冲或用于定时目的。然而要注意的是:每当用作外部数据存储器时,将跳过一个ALE脉冲。如想禁止ALE的输出可在SFR8EH地址上置0。此时,ALE只有在执行MOVX,MOVC指令是ALE才起作用。另外,该引脚被略微拉高。如果微处理器在外部执行状态ALE禁止,置位无效。
/PSEN:外部程序存储器的选通信号。在由外部程序存储器取指期间,每个机器周期两次/PSEN有效。但在访问外部数据存储器时,这两次有效的/PSE N 信号将不出现。
/EA/VPP:当/EA保持低电平时,则在此期间外部程序存储器(0000 H- FFFFH),不管是否有内部程序存储器。注意加密方式1时,/EA将内部锁定为RESET;当/EA端保持高电平时,此间内部程序存储器。在FL ASH 编程期间,此引脚也用于施加12V编程电源(VPP)。
XTAL1:反向振荡放大器的输入及内部时钟工作电路的输入。
XTAL2:来自反向振荡器的输出。
三、系统总体方案
我选用的是单片机(8052)来实现电子万年历的功能。共具备两个功能:
(1)显示年月日及分秒信息
#
(2)具有可调整日期和时间功能。
该电子万年历能够成功实现时钟运行,调整功能,且精确度经调试一天的误差在2S内。
1微处理器
在设计过程中我使用12MHZ晶振与单片机8052相连接,通过软件编程的方法实现了以24小时为一个周期同时显示小时,分钟和秒的要求,该定时闹钟设有九个按键,使之具备了校时、定时功能。利用单片机定时器及计数器产生定时效果通过编程形成数字钟效果,再利用数码管动态扫描显示单片机内部处理的数据。同时通过端口读入当前外部控制状态来改变程序的不同状态,实现不同功能。
在PROTEUS软件环境下的8052芯片如图4所示:
#
(
图4 PROTEUS软件环境下的8052芯片
2显示电路
就时钟而言,通常可采用液晶显示或数码管显示。由于一般的段式液晶屏,需要专门的驱动电路,而且液晶显示作为一种被动显示,可视性相对较差;对于具有驱动电路和微处理器接口的液晶显示模块(字符或点阵),一般多采用并行接口,对微处理器的接口要求较高,占用资源多。另外,89C2051本身无专门的液晶驱动接口,因此,本设计采用点阵式数码管显示,点阵式数码管是由八行八列的发光二极管组成,对于显示文字比较适合。初始化时,由软件编写的指令就集中在显示功能的设置上。LGM12641BS1R的指令可带一个、两个参数,或无参数。若指令中含有参数,则每条指令执行时均须先送入参数,再送入指令代码。由于状态位作用不一样,因此执行不同指令必须检测不同状态位。液晶显示模块LGM12641BS1R如图5所示:
^
图5 显示电路LGM12641BS1R
3按键电路
由于我设计的是电子万年历,需要实现多种功能的显示,并要能够切换显示和调节年月日,因此,在设计过程中按键的设计就显得尤为重要。
在设计过程中我一共采用了4个按键,尽量在小的空间里实现最多的功能。其中MODE键是年月日与时间显示切换键,按下一次就能够更换一次显示位。在调整显示环境下UP和DONW键是显示调整位的的加1减1键,FUNCTION键实现清零,并提高万年历显示的精确性。按键电路如图6所示:
图6 按键电路
四、硬件电路的总体框图设计
{
该设计的硬件电路的总体框图如图7所示:
,
—
|
图7 总体框图
C P U
按键与按钮 电路
复位等辅助电路 液晶显示电路
总体开关
电源系统
五、硬件电路原理图设计
该万年历是以单片机8052为核心来完成的。
在硬件电路中采用P0口作为6位液晶显示电路的驱动接口,这是由于P0口输出驱动电路工作处于开漏状态,它的驱动能力强,故只需外接上拉电阻便可以把LED 数码管点亮。因为共阴的LED 数码管它的驱动电流是分开的,在单片机进行动态扫描的时候不会影响彼此的电流,故该电路中的8位LED 数码管均用共阳阴极的数码管。8位LED 数码管的位选线分别由相应的P2. 0~P2. 5控制,而将其
相应的段选线并联在一起,由一个8位的I/O 口控制,即P0
口。P3口与八个校时按键相连,以成功实现万年历校时的功能。电路原理图如图8所示:
图8 硬件电路
。
六、主程序流程图设计
该设计主程序流程图如图9所示:
"
图9 主程序流程图
基本显示模块设计的重点是由显示代码取得相应的段码、显示段码数据的串行发送,程序流程如图1-11所示。其中时个位的段码必须加上小数点,即带小数点显示时个位,目的是以小数点符代替时间分割符“-”。
软件秒脉冲发生器其实质是利用了定时器0的定时溢出中断,将它设定为100ms溢出中断,则10次中断的时间正好为1s。将时间参数设计为100ms的原因有两个:
1)根据系统时钟主频为6M的特点,16位定时器最大定时时间为65536×2M(M为机器周期,这里是2μS),即131ms,取整数100便于计次数;
:
2)如取的太短,如10ms,则定时器频繁中断,干扰系统正常运行效果。
有了秒脉冲发生器,10次中断为1s,秒指示灯闪亮1次,秒变量单元加1,60后分变量单元加1,如果为60分则时变量单元加1。任何一个变量的变化,则显示刷新一次(更新)。上述思想的实现均集成在定时器0的中断子程序中。该设计显示模块流程图如图10所示:
~
图10 基本显示模块的程序流程图
七、仿真过程
1、仿真:打开WAVE6000,输入所编写的源程序并对程序进行编译,在软件的帮助下检查其中的错误并进行反复修改,知道编译正确后运行,确保没有错误以后对正确的源程序进行保存,保存时给其命名,以便将来载入程序时容易找到。
2、打开PROTEUS软件,并出画单片机电子万年历具体运行电路图。
3、检查所画电路运行图,确保没有错误以后,在PROTEUS下对原理图进行加载WAVE6000下的源程序。
>
4、加载完成后,单击电路图框下的开始按钮,进行仿真,观察LED数码管现实情况,此时LED数码管开始显示数字。调节开关进行时间的调节。当秒的显示间隔快与或慢与实际间隔时,调节石英晶体震荡器的频率参数,从而使秒的间隔达到标准。然后检查电路其它问题,并对其的各参数进行调整,使之正确。
八、仿真结果
通过在WAVE6000下对源程序的编译,改正了其中的很多错误,然后运行,保证源程序的正确性。然后按原理图选择正确合理的电器元件,画出正确的电路图,加载源程序运行,顺利实现了单片机数字电子钟的“小时”、“分钟”、“秒”的显示。该电子万年历的显示效果及电子万年历时间和日期的调节效果分别如图12和图13所示:
图12 电子万年历的运行效果
图13 电子万年历时间和日期的调节效果
九、课程设计体会
!
通过这一周的课程设计,我学到了不少的知识。把以前没有学好的模拟电路的知识进行了补充和加强。这使我受益很大。加深了我对于单片机和数字电路的
认识,相信在以后的学习和工作中碰到这些基础的元器件我会更加得心应手。通过查阅大量的资料,我获得了以前在课堂上学不到的东西,我想这对于以后的毕业设计,或者工作也好,都是很有帮助的。我很认真地对待这个过程中的每一个细节,希望自己能做得更好。希望今后还有这样的机会,能够让我学到更多的知识。在此次的数字钟设计过程中,更进一步地熟悉了芯片的结构及掌握了各芯片的工作原理和其具体的使用方法。
在连接六进制,十进制,六十进制的进位及十二进制的接法中,要求熟悉逻辑电路及其芯片各引脚的功能,那么在电路出错时便能准确地找出错误所在并及时纠正了。
在设计电路中,往往是先仿真后连接实物图,但有时候仿真和电路连接并不是完全一致的,例如仿真的连接示意图中,往往没有接高电平的16脚或14脚以及接低电平的7脚或8脚,因此在实际的电路连接中往往容易遗漏。在设计电路的连接图中出错的主要原因都是接线和芯片的接触不良以及接线的错误所引起的。
对该设计的建议:
此次的电子万年历设计重在于仿真和接线,虽然能把电路图接出来,并能正常显示,但对于电路本身的原理并不是十分熟悉.总的来说,通过这次的设计实验更进一步地增强了实验的动手能力。
学无止境,我们现在所做的一切都还只是一个开始。
附1 源程序代码
#include < >
\
#include < >
#include < >
#include < >
#include < >
#include < >
#include < >
/*****************************预定义**************************************/
#define uchar unsigned char
;
#define uint unsigned int
/****************************************************************************/ sbit bell = P2 ^ 0; //定义蜂鸣器端口
sbit in = P2 ^ 7; //定义红外检测端口
/***************************************************************************** * 名称: Timer0_Service() inturrupt 1
* 功能: 中断服务程序整点报时 3声嘟嘟的声音
* 入口参数:
\
* 出口参数:
*****************************************************************************/ void Timer0_Service() interrupt 1
{
static uchar count = 0;
static uchar flag = 0; //记录鸣叫的次数
count = 0;
TR0 = 0; //关闭Timer0
$
TH0 = 0x3c;
TL0 = 0XB0; //延时 50 ms
TR0 = 1 ; //启动Timer0
count ++;
if( count == 20 ) //鸣叫 1 秒
{
bell = ~ bell;
count = 0;
》
flag ++;
}
if( flag == 6 )
{
flag = 0;
TR0 = 0; //关闭Timer0
}
}
…
/***************************************************************************** * 名称: Timer2_Servie() interrupt 5
* 功能: 中断服务程序整点报时一分钟
* 入口参数:
* 出口参数:
*****************************************************************************/ void Timer3_Service() interrupt 5
{
`
static uchar count;
TF2 = 0; //软件清除中断标志
count ++;
if( in == 1 )
{
count = 0; //计算清0
TR2 = 0; //关闭Timer2
bell = 1; //关闭蜂鸣器
。
}
if( count == 120 ) // 一分钟后关闭报警
{
count = 0; //计算清0
TR2 = 0; //关闭Timer2
bell = 1; //关闭蜂鸣器
}
}
)
/****************************************************************************** * 函数名称:main()
* 功能:
* 入口参数:
* 出口参数:
******************************************************************************/ void main( void )
{
:
uchar clock_time[7] = { 0x00, 0x00, 0x02, 0x30, 0x06, 0x08 }; //定义时间变量秒分时日月年
uchar alarm_time[2] = { 0, 0}; //闹钟设置 alarm_time[0]: 分钟 alarm_time[1] :小时
uchar temperature[2]; //定义温度变量 temperature[0] 低8位temperature[1] 高8位
Lcd_Initial(); //LCD初始化
Clock_Initial( clock_time ); //时钟初试化
/***********************中断初始化***************************/
EA = 1; //开总中断
ET0 = 1; //Timer0 开中断
^
ET2 = 1; //Timer2 开中断
TMOD = 0x01 ; //Timer0 工作方式 1
RCAP2H = 0x3c;
RCAP2L = 0xb0; //Timer2 延时 50 ms
while( 1 )
{
switch( Key_Scan() )
{
;
case up_array:
{
Key_Idle();
}
break;
case down_array:
{
Key_Idle();
}
break;
case clear_array:
{
Key_Idle();
}
break;
case function_array:{
Key_Function( clock_time, alarm_time );
}
case null:
{
Clock_Fresh( clock_time ); //时间刷新
Lcd_Clock( clock_time ); //时间显示
Sensor_Fresh( temperature ); //温度更新
Lcd_Temperture( temperature ); //温度显示
Calendar_Convert( 0 , clock_time );
Week_Convert( 0, clock_time );
//整点报时
if( ( * clock_time == 0x59 ) && ( * ( clock_time + 1 ) == 0x59 ) )
{
bell = 0;
TR2 = 1; //启动Timer2
}
//闹钟报警
if( * alarm_time == * ( clock_time + 1 ) ) //分钟相吻合 if( * ( alarm_time + 1 ) == *( clock_time + 2 ) ) //小时相吻合
{
bell = 0;
TR2 = 1; //启动Timer2
}
}
break;
}
}
}