1、武汉理工大学能力拓展训练课程设计说明书 目 录1软件简介11.1 PROTEUS11.2 KEIL22 MCS-51芯片简介33硬件电路及主要模块设计及其原理53.1单片机最小系统53.2震荡电路模块和原理53.3复位电路模块和原理53.4按键电路及原理63.5 LED模块和显示原理63.6蜂鸣器电路和原理73.7设计总电路和原理84程序框图105资源分配106源程序116.1主程序:116.2按键控制程序:167性能分析207.1系统调试工具KEIL UVISION4207.2 系统调试工具PROTEUS207.3仿真与分析218心得体会229参考文献231软件简介1.1 PROTEUSPr
2、oteus ISIS是英国Labcenter公司开发的电路分析与实物仿真软件.它运行于Windows操作系统上,可以仿真、分析(SPICE)各种模拟器件和集成电路,该软件的特点是:(1)实现了单片机仿真和SPICE电路仿真相结合.具有模拟电路仿真、数字电路仿真、单片机及其外围电路组成的系统的仿真、RS232动态仿真、I2C调试器、SPI调试器、键盘和LCD系统仿真的功能;有各种虚拟仪器,如示波器、逻辑分析仪、信号发生器等.(2)支持主流单片机系统的仿真.目前支持的单片机类型有:68000系列、8051系列、AVR系列、PIC12系列、PIC16系列、PIC18系列、Z80系列、HC11系列以及
3、各种外围芯片.(3) 提供软件调试功能.在硬件仿真系统中具有全速、单步、设置断点等调试功能,同时可以观察各个变量、寄存器等的当前状态,因此在该软件仿真系统中,也必须具有这些功能;同时支持第三方的软件编译和调试环境,如Keil C51 uVision2等软件.(4) 具有强大的原理图绘制功能.总之,该软件是一款集单片机和SPICE分析于一身的仿真软件,功能极其强大.本章介绍Proteus ISIS软件的工作环境和一些基本操作.特点:支持ARM7,PIC ,AVR,HC11以及8051系列的微处理器CPU模型,更多模型正在开发中: 交互外设模型有LCD显示、RS232终端、通用键盘、开关、按钮、L
4、ED等;强大的调试功能,如访问寄存器与内存,设置断点和单步运行模式;支持如IAR、Keil和Hitech等开发工具的源码C和汇编的调试;一键“make”特性:一个键完成编译与仿真操作;内置超过6000标准SPICE模型,完全兼容制造商提供的SPICE模型;DLL界面为应用提供特定的模式;基于工业标准的SPICE3F5混合模型电路仿真器14种虚拟仪器:示波器、逻辑分析仪、信号发生器、规程分析仪等;高级仿真包含强大的基于图形的分析功能:模拟、数字和混合瞬时图形;频率;转换;噪声;失真;付立叶;交流、直流和音频曲线;模拟信号发生器包括直流、正旋、脉冲、分段线性、音频、指数、单频FM;数字信号发生器包
5、括尖脉冲、脉冲、时钟和码流;集成PROTEUS PCB设计形成完整的电子设计系统.1.2 KEIL Keil C51是美国Keil Software公司出品的51系列兼容单片机C语言软件开发系统,与汇编相比,C语言在功能上、结构性、可读性、可维护性上有明显的优势,因而易学易用.Keil提供了包括C编译器、宏汇编、连接器、库管理和一个功能强大的仿真调试器等在内的完整开发方案,通过一个集成开发环境(uVision)将这些部分组合在一起.运行Keil软件需要WIN98、NT、WIN2000、WINXP等操作系统.如果你使用C语言编程,那么Keil几乎就是你的不二之选,即使不使用C语言而仅用汇编语言编
6、程,其方便易用的集成环境、强大的软件仿真调试工具也会令你事半功倍.Keil C51开发系统基本知识Keil C51开发系统基本知识 (1)系统概述 Keil C51软件提供丰富的库函数和功能强大的集成开发调试工具,全Windows界面.另外重要的一点,只要看一下编译后生成的汇编代码,就能体会到Keil C51生成的目标代码效率非常之高,多数语句生成的汇编代码很紧凑,容易理解.在开发大型软件时更能体现高级语言的优势.下面详细介绍Keil C51开发系统各部分功能和使用. (2)Keil C51单片机软件开发系统的整体结构 C51工具包的整体结构,uVision与Ishell分别是C51 for
7、Windows和for Dos的集成开发环境(IDE),可以完成编辑、编译、连接、调试、仿真等整个开发流程.开发人员可用IDE本身或其它编辑器编辑C或汇编源文件.然后分别由C51及C51编译器编译生成目标文件(.OBJ).目标文件可由LIB51创建生成库文件,也可以与库文件一起经L51连接定位生成绝对目标文件(.ABS).ABS文件由OH51转换成标准的Hex文件,以供调试器dScope51或tScope51使用进行源代码级调试,也可由仿真器使用直接对目标板进行调试,也可以直接写入程序存贮器如EPROM中. Keil C51生成的目标代码效率非常之高,多数语句生成的汇编代码很紧凑,容易理解.在
8、开发大型软件时更能体现高级语言的优势.2 MCS-51芯片简介单片机它不是完成某一个逻辑功能的芯片,而是把一个计算机系统集成到一个芯片上.作为嵌入式系统控制核心的单片机具有其体积小、功能全、性价比高等诸多优点.51系列单片机是国内目前应用最广泛的单片机之一,随着嵌入式系统、片上系统等概念的提出和普遍接受及应用,51系列单片机的发展又进入了一个新的阶段.在今后很长一段时间内51系列单片机仍将占据嵌入式系统产品的中低端市场.C语言是本设计的程序设计语言,它比低级语言更通俗易懂,设计更为方便,故采用它来设计程序.单片机全称为单片微型计算机(Single Chip Microcomputer).因为单
9、片机主要用于控制系统中,所以又称微控制器(Microcontroller Unit,MCU)或嵌入式控制器(Embedded Controller).它具有嵌入式应用系统所要求的体系结构,微处理器,指令系统,总线方式,管理模式等.他把计算机的基本部件都微型化集成到一块芯片上了,通常片内部都含有中央处理部件(CPU),数据存储器(RAM),程序存储器(ROM,EPROM,Flsh ROM),定时器/计数器和各种输入/输出(I/O)接口他们之间的相互连接结构如图1-1所示.图1-1 单片机结构8051是MCS-51系列单片机的典型产品,我们以这一代表性的机型进行系统的讲解. 8051单片机包含中央
10、处理器、程序存储器(ROM)、数据存储器(RAM)、定时/计数器、并行接口、串行接口和中断系统等几大单元及数据总线、地址总线和控制总线等三大总线,现在我们分别加以说明:1)中央处理器:中央处理器(CPU)是整个单片机的核心部件,是8位数据宽度的处理器,能处理8位二进制数据或代码,CPU负责控制、指挥和调度整个单元系统协调的工作,完成运算和控制输入输出功能等操作.2)数据存储器(RAM):8051内部有128个8位用户数据存储单元和128个专用寄存器单元,它们是统一编址的,专用寄存器只能用于存放控制指令数据,用户只能访问,而不能用于存放用户数据,所以,用户能使用的RAM只有128个,可存放读写的
11、数据,运算的中间结果或用户定义的字型表.3)程序存储器(ROM):8051共有4096个8位掩膜ROM,用于存放用户程序,原始数据或表格.4)定时/计数器(ROM):8051有两个16位的可编程定时/计数器,以实现定时或计数产生中断用于控制程序转向.5)并行输入输出(I/O)口:8051共有4组8位I/O口(P0、 P1、P2或P3),用于对外部数据的传输.6)全双工串行口:8051内置一个全双工串行通信口,用于与其它设备间的串行数据传送,该串行口既可以用作异步通信收发器,也可以当同步移位器使用.7)中断系统:8051具备较完善的中断功能,有两个外中断、两个定时/计数器中断和一个串行中断,可满
12、足不同的控制要求,并具有2级的优先级别选择.8)时钟电路:8051内置最高频率达12MHz的时钟电路,用于产生整个单片机运行的脉冲时序,但8051单片机需外置振荡电容.单片机的结构有两种类型,一种是程序存储器和数据存储器分开的形式,即哈佛(Harvard)结构,另一种是采用通用计算机广泛使用的程序存储器与数据存储器合二为一的结构,即普林斯顿(Princeton)结构.INTEL的MCS-51系列单片机采用的是哈佛结构的形式,而后续产品16位的MCS-96系列单片机则采用普林斯顿结构.3硬件电路及主要模块设计及其原理3.1单片机最小系统 最小系统就是单片机在发挥具体测控功能时所必须的组成部分.图
13、2-1 最小系统方框图3.2震荡电路模块和原理本次设计要使用到AT89C51单片机的时钟振荡功能.AT89C51中有一个用于构成内部震荡器的高增益反相放大器,引脚XTAL1和XTAL2分别是该放大器的输入和输出端.这个放大器与作为反馈元件的片外石英晶体或者陶瓷谐振器一起构成自激振荡器.3.3复位电路模块和原理8051的复位方式可以是自动复位,也可以是手动复位,见下图2-2.此外,RESET/Vpd还是一复用脚,Vcc掉电其间,此脚可接上备用电源,以保证单片机内部RAM的数据不丢失.图2-2 复位电路图复位电路虽然简单,但其作用非常重要.一个单片机系统能复正常运行,首先要检查是否能复位成功,其中
14、手动复位开关比较常用,手动开关未按下之前,电容正极处于充电状态,当按键按下去后,VCC与GND导通,电容放电,从而实现放电.3.4按键电路及原理采用矩阵键盘方式输入设计键盘控制电路部分,其中用到5个按键,分别是时分秒的置数控制位,启动和报警控制位.其键盘结构图如下所示:图2-3 键盘结构 图2-4 上拉电阻结构上拉电阻阻值的选择原则包括: (1)从节约功耗及芯片的灌电流能力考虑应当足够大;电阻大,电流小.(2)从确保足够的驱动电流考虑应当足够小;电阻小,电流大.(3)对于高速电路,过大的上拉电阻可能边沿变平缓.上拉电阻阻值通常在1k到10k之间选取.故选择的是10K的电阻.3.5 LED模块和
15、显示原理LED显示器又称为数码管,LED显示器由8个发光二极管组成.中7个长条形的发光管排列成“日”字形,另一个贺点形的发光管在显示器的右下角作为显示小数点用,它能显示各种数字及部份英文字母.LED显示器有两种不同的形式:一种是8个发光二极管的阳极都连在一起的,称之为共阳极LED显示器;另一种是8个发光二极管的阴极都连在一起的,称之为共阴极LED显示器本次电路设计采用的是共阴极数码管,通过动态扫描方式驱动,其电路模块如下:图2-5 数码管结构3.6蜂鸣器电路和原理 蜂鸣器部分采用IO口输出,单片机P1端口驱动蜂鸣器.蜂鸣器有两类三大品种.一类是压电式,一类是电磁式,电磁式又有两大品种,铁振膜式
16、和动圈式,二者原理一样只是结构不同.所有蜂鸣器都有两种类型:纯蜂鸣器和带驱动的蜂鸣器,蜂鸣器都是用音频信号驱动的,都是交流驱动.报警器的种类很多,比如:扬声器,蜂鸣器等,本次设计采用的是电磁式蜂鸣器作为报警器.电磁式蜂鸣器由振荡器、电磁线圈、磁铁、震动膜片以及外壳等组成.接通电源后,振荡器产生的音频信号通过电磁线圈,使得电磁线圈产生了一个磁场.振动膜片在电磁线圈和磁铁的相互作用下,周期性地振动发声.蜂鸣器电路图如图所示:图2-6 蜂鸣器结构3.7设计总电路和原理本课设使用AT89C51 加上少许的外围电路就可做成一个时分秒倒计时器,并在达到设定计数时输出一音频信号.系统由主单片机和外围电路构成
17、,系统整体硬件电路包括,显示部分、按键调整部分以及单片机主板部分.主机包括定时输入电路,按键控制电路,LED 显示电路等,从机包括LED显示电路,扬声器输出电路等.其中主机的秒表定时值默认为0,由几个按键控制需要定时的时间;主机LED 采用7段共阴极数码管,从机LED 采用多个发光二极管阵列组成字形段码,以满足较远距离清晰显示.74LS245是常用用来驱动LED或者其他的设备的芯片,它是8路同相三态双向总线收发器,可双向传输数据当8051单片机的P0口总线负载达到或超过P0最大负载能力时,必须接入74LS245等总线驱动器. 当片选端/CE低电平有效时,DIR=“0”,信号由 B 向 A 传输
18、(接收). 仿真电路设计如下所示:图2-7 总体电路图4程序框图 显示00:00:00定时中断10ms定时到 达蜂鸣器报警闹钟键按下 秒表清零闹钟键再按下用三个键键设置定时时间 开始 减计时开始 保持否是否是是否5资源分配编程之前,应先将可用资源和需要资源列举出来,就能清楚的了解整个设计结构.AT89C51单片机IO口有P0、P1、P2、P3,中断源有外部中断0、1两个,定时器中断0、1两个,一个串口中断.现分配如下:8位数码管的数据端连接在一起,然后接入AT89C51 P0端口;其8个共阴极引脚接入P3口作为选通.P1为标准双向IO口,因而将5个按键接到P1上.蜂鸣器则接到P1.7口上.为了
19、计时1秒以及动态扫描数码管,使用一个定时器0作为时钟.6源程序6.1主程序:#include Key.h#include led.huchar timeSetBuff8=0,0,LED_MODE_COUNT,0,0,LED_MODE_COUNT,0,0;/时钟数据缓冲区 uchar alarmSetBuff8=0,0,LED_MODE_ALARM,0,0,LED_MODE_ALARM,0,0;/闹钟时间数据缓冲区 uchar timeDisMod=0x24; /00100100uchar secondTemp,minuteTemp,tenmsTemp;uchar secondAlarm,min
20、uteAlarm, tenmsAlarm;uchar timer0Temp;uchar alarmKeyCount; /闹钟起停键计数 uchar keyRead;bit alarm_is_ok; /闹钟起停状态 bit time_is_ok; /时间是否到 bit interface_mod; / 显示界面模式,0为主时间界面,1为设置界面 void command(void);/控制命令void delay_20s(void);/延迟20s/* 函数名称:定时器0* 功 能:定时器0初始化* 入口参数:无* 出口参数:无*/ void initTimer0(void) /定时10ms TM
21、OD |= 0x01; /GATE=0,TR=1运行;C/T=1,counter,0,timer;01十六进制 TH0 = 0xdc; TL0 = 0x00; TR0 = 1; /timer0 控制位,为1时启动timer0 ET0 = 1; /timer0 中断使能 /* 函数名称:时钟比较* 功 能:比较时钟和闹钟的时间缓冲区,只比较时和分* 入口参数:无* 出口参数:无*/void timeCompare(void) if(minuteTemp = minuteAlarm) & (hourTemp = hourAlarm) time_is_ok = 1; alarm_is_ok = 0;
22、 interface_mod = 1; /* 函数名称:主函数* 功 能:调用并执行各个子函数* 入口参数:无* 出口参数:无*/void main() init_led(); init_key(); initTimer0(); timer0Temp = 0x00; secondTemp = 00; minuteTemp = 00; tenmsTemp = 00; secondAlarm = 0x00; minuteAlarm = 0x00;tenmsAlarm = 0x00; alarmKeyCount = 0x02; alarm_is_ok = 0; /默认状态停止 time_is_ok
23、= 0; /默认时间未到 interface_mod = 0; sei(); while(1) if(interface_mod = 1) ledSweepDisplay(alarmSetBuff,timeDisMod); else ledSweepDisplay(timeSetBuff,timeDisMod); if(alarm_is_ok = 1) timeCompare(); keyRead = get_key_value(); while(P1_4=1) TR0=0; if(interface_mod = 1) ledSweepDisplay(alarmSetBuff,timeDisM
24、od); else ledSweepDisplay(timeSetBuff,timeDisMod); if(alarm_is_ok = 1) timeCompare(); keyRead = get_key_value(); command() ;/ TR0=1; command() ; /* 函数名称:定时器0中断函数* 功 能:定时器0溢出中断入口处,定时10ms* 入口参数:无* 出口参数:无*/void timer0_overflow(void) interrupt 1 TH0 = 0xdc; TL0 = 0x00; if(secondTemp=0&minuteTemp=60&tenm
25、sTemp=0) /报警 time_is_ok = 1 ; if(time_is_ok = 1) /报警 WARN_TRUMPET = WARN_TRUMPET; timer0Temp = 0x00; if(tenmsTemp 99) /判断1min是否到 tenmsTemp+;else tenmsTemp = 00; if(secondTemp59) /判断1hour是否到 secondTemp+; else secondTemp = 00;if(minuteTemp 60) minuteTemp+;else minuteTemp = 00; timeSetBuffS_L = tenmsTe
26、mp%10+0; timeSetBuffS_H = tenmsTemp/10+0; timeSetBuffM_L = secondTemp%10+0; timeSetBuffM_H = secondTemp/10+0; timeSetBuffH_L = minuteTemp%10+0; timeSetBuffH_H = minuteTemp/10+0; sei();void command(void) if(keyRead =KEY_ALARM) if(alarm_is_ok = 1 | time_is_ok = 1) alarm_is_ok = 0;time_is_ok = 0;interf
27、ace_mod = 0;alarmKeyCount = 0x00; else if(alarmKeyCount 0x02) alarmKeyCount+;else alarmKeyCount = 0x00;if(alarmKeyCount = 0x01) interface_mod = 1;if(alarmKeyCount = 0x02) alarm_is_ok = 1; interface_mod = 0; if(keyRead = KEY_TENMS) if(interface_mod = 1) if(tenmsAlarm 99) tenmsAlarm+; else tenmsAlarm
28、= 0x00; alarmSetBuffS_L = tenmsAlarm % 10 + 0; alarmSetBuffS_H = tenmsAlarm / 10 + 0; if(keyRead = KEY_SECOND) if(interface_mod = 1) if(secondAlarm 59) secondAlarm+; else secondeAlarm=0x00; alarmSetBuffM_L=secondAlarm%10+0; alarmSetBuffM_H= secondAlarm/10+0; if(keyRead = KEY_MINUTE) if(interface_mod
29、 = 1) if(minuteAlarm 0;c-) for(b=209;b0;b-) for(a=249;a0;a-); for(n=2;n0;n-);6.2按键控制程序:#define KEY_GLOBAL 1#include Key.huchar keyValueBuff; / 读取键值的缓冲区 uchar keyValueOld; / 前一次的键值 uchar keyValueTemp;uint stillTimes; / 键按下保持次数 uint stillTimesMax;uchar get_data_1_count(uchar number);void read_all_key(
30、uchar *buff);/* 函数名称:init_key(void)* 功 能:键盘驱动初始化* 入口参数:无* 出口参数:无*/void init_key(void) keyValueBuff = 0x00; keyValueOld = 0x00; keyValueTemp = 0x00; stillTimes = 0; stillTimesMax = FIRST_TIMES;void read_all_key(uchar *buff) if(IN_PRESS_TENMS = KEY_FORCE_VALUE) READ_KEY(1,KEY_TENMS,*buff); else READ_K
31、EY(0,KEY_TENMS,*buff); if(IN_PRESS_SECOND = KEY_FORCE_VALUE) READ_KEY(1,KEY_SERCOND*buff); else READ_KEY(0,KEY_SECOND,*buff); if(IN_PRESS_MINUTE = KEY_FORCE_VALUE) READ_KEY(1,KEY_MINUTE,*buff); else READ_KEY(0,KEY_MINUTE,*buff); if(IN_PRESS_ALARM = KEY_FORCE_VALUE) READ_KEY(1,KEY_ALARM,*buff); else
32、READ_KEY(0,KEY_ALARM,*buff);/* 函数名称:uchar get_key_value(void)* 功 能:获取键盘的键值* 入口参数:无* 出口参数:键盘的键值编码(keyValueTemp)*/uchar get_key_value(void) keyValueBuff = 0x00; read_all_key(&keyValueBuff); keyValueTemp = keyValueBuff; delay_us(KEY_DELAY_TIME); read_all_key(&keyValueBuff); /* 两次读到的键盘值相同 则为有效键盘值 */ if(
33、 keyValueTemp = keyValueBuff ) if(keyValueTemp = 0) keyValueOld = 0; stillTimes = 0; stillTimesMax = FIRST_TIMES; return 0; else if(keyValueOld != keyValueTemp) stillTimes = 0; keyValueOld = keyValueTemp; #if CAN_MORE_PRESS return keyValueTemp; #else if( 1 = get_data_1_count(keyValueTemp) ) return k
34、eyValueTemp; else return 0; #endif else if(keyValueOld = keyValueTemp) #if CAN_MORE_PRESS = 0 if( 1 != get_data_1_count(keyValueTemp) ) stillTimes = 0; return 0; #endif #if CAN_REPEAT stillTimes +; if(stillTimes stillTimesMax) stillTimes = 0; #if REPEAT_MODE if(FIRST_TIMES = stillTimesMax) stillTime
35、sMax = OTHER_TIMES; #endif return keyValueTemp; #else stillTimes = 0; return 0; #endif else stillTimes = 0; return 0; return 0; /* 函数名称:uchar get_data_1_count(uchar number)* 功 能:判断同时按下的键的数目* 入口参数:键值(uchar number)* 出口参数:同时按下的键的数目*/uchar get_data_1_count(uchar number) register uchar i,j = 0; for(i = 0; i 8; i +) if( (number&_BV(i) ) j +; return j; /* 函数名称:delay_us(uint us)* 功 能:延时一段时间* 入口参数:us* 出口参数:无*/void delay_us(uint us) uch