基于Proteus的单片机项目实践教程
上QQ阅读APP看本书,新人免费读10天
设备和账号都新为新人

项目1 点亮LED

【项目引入】

在现代各种常用的电器中都有LED灯的使用,要求LED按照一定的频率闪烁,这实际上就是一个最简单的单片机控制电路。发光二极管LED是一种最简单和常用的电子器件,如图1-1所示。单片机的学习就从点亮LED灯开始。本节任务就是利用单片机驱动LED电路,设计程序使其点亮或闪烁。

图1-1 发光二极管LED

【知识目标】

● 了解单片机的基本结构;

● 掌握单片机的引脚;

● 掌握单片机最小系统的组成;

● 掌握C51基本语法。

【技能目标】

● 会安装和使用Keil、Proteus;

● 能制作单片机的最小系统硬件电路。

1.1 任务描述

设计简单的单片机驱动LED闪烁的控制电路,借助Keil Vision完成程序的编写,在Proteus中完成仿真。

1.2 准备知识

1.2.1 认识单片机

1.单片机的概念

(1)计算机

要清楚什么是单片机,还要从计算机讲起。图1-2所示的计算机是由中央处理器(CPU)、存储器、输入/输出接口电路(I/O)和外设,依靠系统总线(地址、数据、控制)相连而形成的硬件系统。它的硬件结构图如图1-3所示。

图1-2 计算机

图1-3 计算机硬件结构图

(2)单片机

随着大规模集成电路技术的发展,构成微型计算机的CPU、ROM、RAM、I/O接口等主要功能部件及总线集成在同一块芯片上,成为单芯片的微型计算机(Single Chip MicroComputer),简称单片机(微控制器),如图1-4所示。图1-5是由ATMEL公司生产的一个最常用的单片机芯片AT89S52。

图1-4 单片机内部结构

图1-5 单片机芯片

(3)嵌入式系统

嵌入式系统一般由嵌入式微处理器、外围硬件设备、嵌入式操作系统以及用户的应用程序等4个部分组成。它与一般单片机的区别,一是带有嵌入式操作系统,二是它是32位或更高位系统,一般的核心为ARM、DSP、FPGA等。单片机系统一般不带操作系统,其实ARM就是单片机的进一步发展。

2.单片机的发展与分类

1975出现了第一块4位单片机。单片机的发展经历了4位、8位、16位、32位机的各个阶段。出现较早也是较成熟的单片机为Intel公司的MCS-51系列,如Intel 8031、Intel 8051、Intel 8751等型号。该单片机的字长为8位,具有完善的结构和优越的性能,以及较高的性价比和要求较低的开发环境。因此,后来很多厂商或公司沿用或参考了Intel公司的MCS-51内核,相继开发出了自己的单片机产品,如PHILIPS、Dallas、ATMEL等公司,并增加和扩展了单片机的很多功能。单片机型号很多,将采用MCS-51内核的单片机常简称为51系列单片机。目前市场流行的8位单片机多为ATMEL公司的AT89系列、国内品牌STC系列等。

STC单片机为增强51系列,支持串口在线下载(ISP)、内部看门狗和内部E2PROM在应用编程(IAP),个别型号内部设计有A/D转换器。由于STC单片机功能强且价格低,市场容易购置,实验和研发成本较低。

国内应用的单片机型号有:

● INTEL公司——8031,8051。

● ATMEL公司——AT89系列(AT89S51),AVR单片机(ATMEGA48)。

● 宏晶公司——STC12C5410AD。

● MICROCHIP公司——PIC系列(PIC16F877)。

● MOTOROLA公司——M68HC08系列(MC68HC908GP32)。

● TI公司——德州仪器,TMS370和MSP430系列,MSP430系列单片机。

3.单片机应用

单片机的应用非常广泛,涉及到我们生活中的各个领域。它有较强的数据运算和处理的能力,它可以嵌入到很多电子设备的电路系统中,实现智能化检测和控制。单片机应用主要集中在以下几个方面。

(1)自动控制

工业自动化控制是最早采用单片机控制的领域之一。单片机结合不同类型的传感器,可实现电信号、湿度、温度、流量、压力、速度和位移等物理量的测量。例如:智能电度表,可用于家用电器的功率、用电量及电费的测量计算,如图1-6所示。它在测控系统、工业生产机器人的过程控制、医疗、机电一体化设备和仪器仪表中有着广泛的应用。典型产品如机器人、数控机床、自动包装机、验钞机(如图1-7所示)、医疗设备、打印机、传真机、复印机等。

图1-6 智能电度表

图1-7 验钞机

(2)家用电器

单片机系统具有体积小、功耗低、扩展灵活、微型化和使用方便等优点,在家用电器方面也有着广泛应用。单片机系统能够完成电子系统的输入和自动操作,非常适合于对家用电器的智能控制。嵌入单片机的家用电器实现了智能化,使传统型家用电器更新换代,现已广泛应用于全自动洗衣机、空调、电视机、微波炉、电冰箱以及各种视听设备中。

(3)其他领域

智能化的集中显示系统、动力监测控制系统、自动驾驶系统、通信系统和运行监视各种仪表等装置中都离不开单片机。单片机在机器人、汽车、航空航天、军事等领域也有广泛的应用。

4.单片机产品的开发

(1)单片机产品的开发

单片机的运行需要必要的硬件和软件,而程序就是单片机系统的软件。通过程序下载到单片机内部ROM中,可以让单片机运行,从而实现微型计算机的基本功能,这就是单片机的开发,如图1-8所示。虽然单片机不能加载复杂的操作系统,但它是一种程序简单芯片化的计算机,各功能部件在芯片中的布局和结构达到最优化,抗干扰能力加强,工作亦相对稳定。

图1-8 单片机开发过程

(2)单片机产品的开发工具

① 单片机应用开发软件。单片机完成各种操作是通过程序来实现控制的,编程的语言可以是汇编语言或C语言,汇编语言直接面向机器,而C语言通读性强。编程的调试软件较多,有伟福、MedWin、Keil μVision等,常用的是Keil μVision。它是德国Keil软件公司开发的基于8051内核的微控制器软件开发平台,如图1-9所示。

图1-9 Keil μVision操作界面

② Proteus仿真软件。Proteus仿真软件是以英国LabCenter Electronics公司开发的目前较好的单片机及外围器件的仿真工具。它由ISIS和ARES两个软件构成,其中ISIS是原理图编辑与仿真软件,ARES是布线编辑软件。利用该仿真软件,在没有硬件的情况下,不仅可将许多单片机实例功能形象化,也可将许多单片机实例运行过程形象化,易于理解系统硬件的组成和提高学习兴趣,是单片机教学的先进手段。Proteus界面如图1-10所示。

图1-10 Proteus界面

③ 单片机硬件电路设计的器件及调试工具。在单片机的硬件电路设计中,有些常用的电子元器件,例如:单片机、LCD、矩阵键盘、发光二极管、数码管、晶振等,如图1-11所示。在完成电路焊接后,需要用到烧录器把编制的程序烧录到电路板的单片机芯片中,烧录器如图1-12所示。现在很多简单实用的单片机开发板已慢慢代替了烧录器,如图1-13所示。单片机开发板不仅可以烧录程序,还可以作为学习工具用来完成各种单片机实验,有的还可以作为仿真器使用。

图1-11 常用的电子元器件

图1-12 专门烧录器

图1-13 单片机开发板

1.2.2 单片机最小系统

单片机型号很多,采用MCS-51内核的单片机常简称为51系列单片机。目前市场流行的8位单片机多为ATMEL公司的AT89系列、国内品牌STC系列等。所以本书主要讲述ATMEL公司的AT89S51芯片。

1.单片机内部结构

AT89S51芯片的内部结构如图1-14所示,它主要由以下几个部件组成。

图1-14 AT89S51芯片内部结构

(1)中央处理器

中央处理器(CPU)是整个单片机的核心部件,是8位数据宽度的处理器,能处理8位二进制数据或代码。CPU负责控制、指挥和调度整个单元系统协调的工作,完成运算和控制输入输出功能等操作。

(2)数据存储器(RAM)

AT89S51内部有128字节数据存储器(RAM)和21个专用寄存器单元,它们是统一编址的。专用寄存器有专门的用途,通常用于存放控制指令数据,不能用做用户数据的存放。用户能使用的RAM只有128个字节,可存放读/写的数据、运算的中间结果或用户定义的字型表。

(3)程序存储器(ROM)

AT89S51共有4K字节程序存储器(FLASH ROM),用于存放用户程序和数据表格。

(4)定时/计数器

AT89S51有两个16位的可编程定时/计数器,以实现定时或计数。当定时/计数器产生溢出时,可用中断方式控制程序转向。

(5)并行输入输出(I/O)口

AT89S51共有4个8位的并行I/O口(P0、P1、P2、P3),用于对外部数据的传输。

(6)全双工串行口

AT89S51内置一个全双工异步串行通信口,用于与其他设备间的串行数据传送。该串行口既可以用做异步通信收发器,也可以当同步移位器使用。

(7)中断系统

AT89S51具备较完善的中断功能,有5个中断源(两个外中断、两个定时/计数器中断和一个串行中断),可基本满足不同的控制要求,并具有2级的优先级别选择。

(8)时钟电路

AT89S51内置最高频率达12MHz的时钟电路,用于产生整个单片机运行的时序脉冲,但需外接晶体振荡器和振荡电容。

2.单片机的外部引脚

常用的AT89S51/52、STC89C51单片机都采用DIP40封装。图1-15(a)所示为DIP40单片机封装外形引脚的分布,图1-15(b)所示为40个引脚单片机的电路符号。40个引脚按功能分为4个部分,即电源引脚、时钟引脚、控制信号引脚以及I/O端口引脚。

图1-15 DIP40单片机的引脚分布、电路符号与外形图

(1)电源引脚

VCC(40脚):单片机电源正极引脚。

VSS(20脚):单片机的接地引脚。

在正常工作情况下,VCC接+5V电源。为了保证单片机运行的可靠性和稳定性,提高电路的抗干扰能力,电源正极与地之间可接有0.1μF独立电容。

(2)时钟引脚

单片机有两个时钟引脚,用于提供单片机的工作时钟信号。单片机是一个复杂的数字系统,内部CPU以及时序逻辑电路都需要时钟脉冲,所以单片机需要有精确的时钟信号。

XTAL1(19脚):内部振荡电路反相放大器的输入端。

XTAL2(18脚):内部振荡电路反相放大器的输出端。

单片机的振荡电路有两种组成方式,片内振荡器和片外振荡器,如图1-16所示。

图1-16 单片机时钟电路

① 图1-16(a)使用内部振荡电路,外接石英晶体。

② 图1-16(b)是利用外部振荡脉冲输入,XTAL1接外部时钟振荡脉冲,XTAL2可以悬空不用或接地。

(3)控制信号引脚

RST/VPD(9脚):复位/备用电源引脚。

● 正常工作时,RST(RESET)端为复位信号输入端。对此引脚施加两个机器周期的高电平可使单片机复位(Reset)。单片机正常工作时,此引脚应为低电平。

● 在VCC掉电情况下,该引脚还可接上备用电源(+5V),在系统工作的过程中,如果VCC

低于规定的电压值,VPD向片内RAM提供电源,以保持RAM内的信息不丢失。(30脚):地址锁存允许信号输出/编程脉冲引脚。

● ALE:在扩展了外部存储器的单片机系统中,单片机访问外部存储器时,ALE用于锁存低8位的地址信号。如果系统没有扩展外部存储器,ALE端输出周期性的脉冲信号,频率为时钟振荡频率的1/6,可用于对外输出的时钟。

:对于EPROM型单片机中,对闪存进行编程期间(也称“烧录程序”)时,此引脚用于输入编程脉冲。

(29脚):输出访问片外程序存储器的读选通信号。在CPU从外部程序存储器取指令期间,该信号每个机器周期两次有效。在访问片外数据存储器期间,这个信号将不出现。(31脚):内外ROM选择/编程电源引脚。

● 正常工作时,EA为内外ROM选择端,用于区分片内外低4KB范围程序存储器空间。该引脚接高电平时,CPU访问片内程序存储器4KB的地址范围,若PC值超过4KB的地址范围,CPU将自动转向访问片外程序存储器;当此引脚接低电平时,则只访问片外程序存储器,忽略片内程序存储器。8031单片机没有片内程序存储器,此引脚必须接地。

● 对于EPROM型单片机,在编程期间,此引脚用于施加较高的编程电压VPP,一般为+21V。

(4)单片机的I/O端口引脚

单片机的I/O端口是用来输入信息和控制输出的端口,51单片机共有P0、P1、P2、P3四组端口,分别与单片机内部P0、P1、P2、P3四个寄存器对应,每组端口有8位,因此DIP40封装的51单片机共有32个I/O端口。

P0口(32~39脚):分别是P0.0~P0.7,与其他I/O口不同,P0口是漏极开路型双向I/O端口。它的功能如下:

● 作为普通的I/O端口使用,则要求外接上拉电阻或排阻,每位以吸收电流的方式驱动8个LSTTL门电路或其他负载。

● 在访问片外存储器时,作为与外部传送数据的8位数据总线(D0~D7),此时不需外接上拉电阻。

● 在访问片外存储器时,也作为扩展外部存储器时的低8位地址总线(A0~A7),此时不需外接上拉电阻。

P1口(1~8脚):分别是P1.0~P1.7,P1口是一个带内部上拉电阻的8位双向I/O端口,每位能驱动4个LSTTL门负载。这种接口没有高阻状态,输入不能锁存,因而不是真正的双向I/O端口。

P2口(21~28脚):分别是P2.0~P2.7,P2口也是一个带内部上拉电阻的8位双向I/O口,它的功能如下:

● 作为普通I/O端口使用,每位也可以驱动4个LSTTL负载。

● 在访问外部存储器时,P2口输出高8位地址。

P3口(10~17脚):分别是P3.0~P3.7,P3是双功能端口,它的功能如下:

● 作为普通I/O端口使用时,同P1、P2口一样,

● 作为第二功能使用时,引脚定义如表1-1所述。P3口引脚具有的第二功能,能使硬件资源得到充分利用。

表1-1 P3口的第二功能表

3.单片机最小系统

所谓单片机的最小系统是指由单片机和一些基本的外围电路所组成的一个可以工作的基本单片机系统,也是一个微型的计算机系统。复杂的单片机系统电路都是以单片机最小系统为基本电路进行扩展设计的。一般来说,它包括晶振电路、复位电路等。

(1)晶振电路

单片机是一个复杂的数字系统,内部CPU以及时序逻辑电路都需要时钟脉冲,所以单片机需要有精确的时钟信号。单片机有两个时钟引脚,用于提供单片机的工作时钟信号。

单片机内部有一个由高增益放大器组成的振荡电路,如图1-17所示。XTAL1、XTAL2分别为内部振荡电路反相放大器的输入端和输出端,单片机的振荡电路有两种组成方式,如图1-16所示。

图1-17 51系列单片机的时钟电路

片内振荡器方式如图1-16(a)所示,片内的高增益反相放大器通过XTAL1、XTAL2外接作为反馈元件的片外晶体振荡器(呈感性)与电容组成的并联谐振回路构成一个自激振荡器,向内部时钟电路提供振荡时钟。振荡器的频率主要取决于晶体的振荡频率,一般晶体可在1.2~12MHz之间任选,电容C1、C2可在5~30pF之间选择,电容的大小对振荡频率有微小的影响,可起频率微调作用。

片外振荡器方式如图1-16(b)所示,XTAL1是外部时钟信号的输入端,XTAL2可悬空。

(2)时序

单片机内的各种操作都是在一系列脉冲控制下进行的,而各脉冲在时间上的先后顺序称为时序。51系列单片机的工作时序共有4个,从小到大依次是节拍、状态、机器周期和指令周期。

① 节拍与状态。晶体振荡信号的一个周期称为节拍,用P表示,振荡脉冲经过二分频后,就是单片机的时钟周期,其定义为状态,用S表示。这样,一个状态包含两个节拍,前半周期对应的节拍叫节拍1,记为P1,后半周期对应的节拍叫节拍2,记为P2,如图1-18所示。CPU以时钟P1、P2为基本节拍,指挥单片机的各个部分协调工作。

图1-18 单片机的指令时序图

② 机器周期。单片机的基本操作周期为机器周期。一个机器周期的宽度为6个状态,并依次表示为S1~S6。由于一个状态又包括两个节拍,因此,一个机器周期总共有12个节拍,分别记为S1P1、S1P2、…、S6P2。实际上一个机器周期有12个振荡脉冲周期,因此机器周期就是振荡脉冲信号的十二分频。

当外接的晶体振荡脉冲频率为12MHz时,一个机器周期为1μs;当振荡脉冲频率为6 MHz时,一个机器周期为2μs。

③ 指令周期。单片机执行一条指令所需要的时间称为指令周期。指令周期是单片机最大的工作时序单位,不同的指令所需要的机器周期数也不相同。如果单片机执行一条指令占用一个机器周期,则这条指令为单周期指令,如简单的数据传输指令;如果执行一条指令需要两个机器周期,称为双周期指令,如乘法运算指令。单片机的运算速度与程序执行所需的指令周期有关,占用机器周期数越少的指令则单片机运行速度越快。在51系列单片机的111条汇编指令中,共有单周期指令、双周期指令和四周期指令三种。

(3)复位电路

复位是指使中央处理器CPU及其他功能部件都处于一个确定的初始状态,并从这个状态开始工作。例如单片机上电后,需要对单片机的初始化复位,程序运行出错或操作错误进入死锁状态需要复位重新开始。

在单片机的RST端(9脚)至少维持2个机器周期以上的高电平,单片机会进入复位状态。在实际应用中,复位操作通常有上电自动复位、手动复位两种方式。上电复位要求接通电源后,自动实现复位操作。常用的上电自动复位电路如图1-19(a)所示。图中电容和电阻电路对+5V电源构成微分电路,单片机系统上电后,单片机的RST端会得到一个时间很短暂的高电平。单片机系统开始运行时必须先进行复位操作,如果单片机运行期间出现故障,也需要对单片机复位,使单片机初始化。这时可用到图1-19(b)所示电路的按键手动复位,图中电容器采用电解电容,一般取4.7~10μF,电阻取1~10kΩ。

图1-19 单片机复位电路

单片机复位以后,P0~P3口输出高电平,SP赋初值07H,程序计数器PC被清0,但不影响片内RAM低128B存放的内容,单片机内部特殊功能寄存器的状态都会被初始化。单片机的特殊功能寄存器复位状态如表1-2所示。单片机完成复位后,RST引脚从高电平到低电平,单片机进入启动状态,从0000H地址开始执行程序。

表1-2 内部寄存器复位状态表

(4)最小系统电路

单片机的组成的最小系统如图1-20所示,图中单片机型号采用AT89S51,电路包括电源、振荡电路、复位电路,单片机内部有512B的RAM和4KB ROM以及输入/输出接口等。电路中采用的是上电复位和外部振荡器方式。

图1-20 单片机最小系统

1.2.3 单片机的存储器

单片机内部包含随机存取存储器RAM和程序存储器ROM,RAM用于保存单片机运行的中间数据。单片机的ROM不只是用来装载程序,增强51系列也可以在单片机运行过程中利用程序把数据存储在ROM的部分空间内。51系列单片机在系统结构上采用哈佛结构(Harvard Architecture),即程序存储器和数据存储器的寻址空间是分开管理的。它共有4个物理上独立的存储器空间,即内部和外部程序存储器及内部和外部数据存储器。从用户的角度看,单片机的存储器逻辑上分为三个存储空间,如图1-21所示,即统一编址的64KB的程序存储器地址空间(包括片内ROM和外部扩展ROM),地址为0000H~FFFFH;256B的片内数据存储地址空间(包括128B的片内RAM和特殊功能寄存器的地址空间);64KB的外部扩展的数据存储器地址空间。图中是单片机的程序扩展控制引脚。

1.单片机的片内RAM

51单片机芯片中共有256个字节的RAM单元,但其中高128个字节被专用寄存器占用,能作为存储单元供用户使用的只是低128B,用于存放可读/写的数据。因此通常所说的内部数据存储器就是指低128B,简称片内RAM,如图1-22所示。当程序比较复杂,且运算变量较多而导致51内部RAM不够用时,可根据实际需要在片外扩展,最多可扩展64KB,但在实际应用中如需要大容量RAM时,往往会利用增强型的51单片机而不再扩展片外RAM。增强型的51系列单片机如52和58子系列分别有256 B和512B的RAM。

图1-21 51单片机的存储器空间分布

图1-22 片内256B分布

(1)低128B

51单片机片内低128B RAM根据功能又划分为工作寄存器区(地址00H~1FH)、位寻址区(地址20H~2FH),一般RAM区(地址30H~7FH),其中位寻址区共16字节128个位单元,如图1-22所示。

① 工作寄存器区。工作寄存器区是指00H~1FH区,共分4个组,每组有8个字节单元,共32个内部RAM单元。作为工作寄存器使用的8个单元,又称为R0~R7,每组8个寄存器每个寄存器都是8位。程序状态字PSW中的PSW.3(RS0)和PSW.4(RS1)两位用来选择哪一组作为当前工作寄存器使用,如表1-3所示。CPU通过软件修改PSW中RS0和RS1两位的状态,就可任选一个工作寄存器工作。每次只能有1组作为工作寄存器使用(R0,R1,R2,R3,R4,R5,R6,R7),其他各组可以作为一般的数据缓冲区使用。

表1-3 通用寄存器选择

② 位寻址区。位寻址区是指20H~2FH单元,共16个单元。位寻址区的16个单元(共计128位)的每1位都有一个8位表示的位地址,位地址范围为00H~1FH,如图1-23所示。位寻址区的每1位都可当作软件触发器,由程序直接进行位处理。同样,位寻址的RAM单元也可以按字节操作作为一般的数据缓冲区使用。

③ 数据缓冲区。数据缓冲区是指30H~37H,这是用户可以随意使用用来存储数据的区域,堆栈区也在此区中。可在初始化程序时设定SP的初值,确定堆栈区的范围,通常情况下将堆栈区设在30H~TFH范围之内。

图1-23 位寻址区

(2)高128B

51单片机片内高128B RAM是由21个特殊功能寄存器(Special Function Register,SFR)占用的。它是单片机内部很重要的部件,用于对片内各功能模块进行监控和管理,是一些控制寄存器和状态寄存器,与片内RAM单元统一编址。

51系列单片机内部堆栈指针SP、累加器A、程序状态字PSW以及I/O锁存器、定时器、计数器以及控制寄存器和状态寄存器等都是特殊功能寄存器,和片内RAM统一编址,分散占用80~FFH单元,共有21个,增强型的52系列单片机则有26个。表1-4列出了单片机的特殊功能寄存器名称、标识符和对应的字节地址,其中含有52系列的寄存器T2,T2CON等。在单片机C语言编程应用中,单片机的特殊功能寄存器标识符经常用到。下面只介绍其中部分寄存器,一些控制寄存器会在单片机内部资源编程应用中详细介绍。

表1-4 特殊功能寄存器

① 累加器ACC/A(Accumulator)。累加器A为8位寄存器,是最常用的专用寄存器,功能较多,使用最为频繁。它既可用于存放操作数,也可用来存放运算的中间结果。51系列单片机中大部分单操作数指令的操作数就取自累加器,许多双操作数指令中的一个操作数也取自累加器。累加器有自己的地址,因而可以进行地址操作。

② B寄存器。它是一个8位寄存器,主要用于乘除运算。乘法运算时,B提供乘数。乘法操作后,乘积的高8位存于B中。除法运算时,B提供除数。除法操作后,余数存于B中。此外,B寄存器也可作为一般数据寄存器使用。

③ 程序状态字PSW(Program Status Word)。它是一个8位寄存器,用于存放程序运行中的各种状态信息。其中有些位的状态是由程序执行结果决定的,硬件自动设置的,而有些位的状态则使用软件方法设定。PSW的位状态可以用专门指令进行测试,也可以用程序读出。一些条件转移程序可以根据PSW特定位的状态,进行程序转移。PSW各位标示符定义格式为:

PSW.7 为进/借位标志(Carry,CY):表示运算是否有进位或借位。其功能有二:一是存放算术运算的进/借位标志,在进行加或减运算时,如果操作结果的最高位有进位或借位时,CY由硬件置“1”,否则清“0”;二是在位操作指令中,做位累加器使用。

PSW.6为辅助进/借位标志位(Auxiliary Carry,AC),也叫半/借进位标志位。在进行加减运算中,当低4位向高4位进位或借位时,AC由硬件置“1”,否则AC位被清“0”。在BCD码的加法调整中也要用到AC位。

PSW.5为用户标志位F0(Flag 0),是一个供用户定义的标志位,需要利用软件方法置位或复位,用以控制程序的转向。

PSW.4/PSW.3为寄存器组选择位RS1/RS0(Register Selection),用于选择CPU当前使用的工作寄存器组,其对应关系如表1-5所示。

表1-5 寄存器组的映射表

这两个选择位的状态是由程序设置的,被选中的寄存器组即为当前寄存器组。单片机上电或复位后,RS1/RS0=00,即默认的工作寄存器组是第0组。

PSW.2为溢出标志位OV(Overflow)。在带符号数的加减运算中,OV=1表示加减运算超出了累加器A所能表示的符号数有效范围(-128~+127),即产生了溢出,表示A中的数据只是运算结果的一部分;OV=0表示运算正确,即无溢出产生,表示A中的数据就是全部运算结果。在乘法运算中,OV=1表示乘积超过255,即乘积分别在B与A中;否则,OV=0,表示乘积只在A中。在除法运算中,OV=1表示除数为0,除法不能进行;否则,OV=0,除数不为0,除法可正常进行。

PSW.1为用户标志位F1(Flag 1),也是一个供用户定义的标志位,与F0类似。

PSW.0为奇偶标志位P(Parity),表示累加器A中“1”的个数奇偶性。如果A中有奇数个“1”,则P置“1”,否则置“0”,即完全由累加器的运算结果中“1”的个数为奇数还是偶数决定。注意标志位P并非用于表示累加器A中数的奇偶性。凡是改变累加器A中内容的指令均会影响P标志位。P标志对串行通信中的数据传输有重要的意义。在串行通信中常采用奇偶校验的办法来校验数据传输的可靠性。

④ 数据指针DPTR(Data Pointer)。数据指针DPTR为16位寄存器。编程时,DPTR既可以按16位寄存器使用,也可以按两个8位寄存器分开使用,即DPTR的高位字节DPH和DPTR的低位字节DPL。

在系统扩展中,DPTR作为程序存储器和片外数据存储器的地址指针,用来指示要访问的ROM和片外RAM的单元地址。由于DPTR是16位寄存器,因此,通过DPTR可寻址64KB的地址空间。

⑤ 堆栈指针SP(Stack Pointer)。堆栈是一个特殊的存储区,用来暂存系统的数据或地址,它是按“先进后出”或“后进先出”的原则来存取数据的,而系统对堆栈的管理是通过8位的堆栈指针寄存器SP来实现的,SP总是指向最新的栈顶位置。堆栈的操作分为进栈和出栈两种。

MCS-51系列单片机的堆栈设在片内RAM中,SP是一个8位寄存器,所以系统复位后,SP的初值为07H,但堆栈实际上是从08H单元开始的。由于08H~1FH单元分别属于工作寄存器1~3区,20H~2FH是位寻址区,如果程序要用到这些单元,最好把SP值改为2FH或更大的值。一般在片内RAM的30H~7FH单元中设置堆栈。SP的内容一经确定,堆栈的位置也就跟着确定下来。由于SP可初始化为不同值,因此堆栈的具体位置是浮动的。

⑥ P0~P3。P0~P3是和输出/输入有关的4个特殊寄存器,实际上是4个锁存器。每个锁存器加上相应的驱动器和输入缓冲器就构成一个并行口,并且为单片机外部提供32根I/O引脚,命名为P0~P3口。

⑦ PC。程序计数器PC是一个16位的加1计数器,其作用是控制程序的执行顺序,而其内容为将要执行指令的ROM地址,寻址范围是64KB。它并不在片内RAM的高128B内。

(3)特殊功能寄存器在程序设计中的应用

在程序设计过程中,单片机的功能发挥很多情况下是通过设置和检测单片机内部的特殊功能寄存器来实现的。字节地址能被8整除的SFR既可以位寻址,也可以字节寻址。如果采用C语言设计单片机的程序,只需要记住特殊功能的寄存器和每个特殊功能寄存器的位的标示符和作用就可以了。对特殊功能寄存器的操作很简单,只需对某个寄存器或位标示符赋值即可。

例如在外部中断操作中,假设需要首先设置IE寄存器的EA位为1(其他位为0)。可以字节操作IE=0X80,也可以位操作EA=1。单片机C语言程序设计中常用的特殊功能寄存器如表1-6所示,其中T2CON为增强51系列。

表1-6 特殊功能寄存器位标识符和位地址表

2.内部程序存储器(内部ROM)

单片机的工作是按照事先编制好的程序命令一条条顺序执行的,程序存储器就是用来存放这些已编好的程序和表格常数的。51单片机共有4 KB的ROM,单片机的生产商不同,内部程序存储器可以是E2PROM或Flash ROM。可根据实际需要在片外扩展,最多可扩展64KB。增强型的51单片机内部ROM空间可以达到64KB,在使用时不须再扩展片外ROM。

数据存储器、程序存储器以及位地址空间的地址有一部分是重叠的,但在具体寻址时,可由不同的指令格式和相应的控制信号来区分不同的地址空间,因此不会造成冲突。

1.2.4 单片机C语言基础

51单片机的编程语言常用的有两种,一种是汇编语言,另一种是C语言。C语言是一种结构化的高级程序设计语言,且能直接对计算机的硬件进行操作,与汇编语言相比,它有如下优点:

● 对单片机的指令系统不要求了解,仅要求对MCS-51的存储器结构有初步了解。

● 寄存器分配、不同存储器的寻址及数据类型等细节可由编译器管理。

● 程序有规范的结构,可分为不同的函数,这种方式可使程序结构化。

● 采用自然描述语言、以近似人的思维过程方式使用,改善了程序的可读性。

● 编程及程序调式时间显著缩短,大大提高效率。

● 提供的库包含许多标准子程序,且具有较强的数据处理能力。

● 程序易于移植。

所以本书的案例全部采用C语言进行程序设计。国内在MCS-51中使用的C高级语言基本上都是采用Keil/Franklin C语言,简称C51语言。

1.C51程序结构

C51程序结构和一般的C语言程序没有什么差别。C51的程序总体上是一个函数定义的集合,但还包括其他一些定义。一个完整的C51程序通常包括如下部分:

● 头文件包含

● 宏定义

● 单片机端口位功能定义

● 子函数声明

● 主函数(一个)

● 自定义子函数(多个)

C51的程序也是从main()函数(主函数)开始执行的,主函数是程序的入口,主函数中的语句执行完毕,则程序执行结束。单片机程序一般需要我们自行编写一定数量的子函数,供主函数调用,来简化书写及逻辑分析工作。

例如:下面为一个完整的C51程序。

            #include<reg52.h>          //头文件
            #define uint unsigned int      //宏定义
            sbit D1=P1^0;              //声明单片机P1口的第一位
            void delay();               //声明子函数
            void main()               //主函数
            {
                while(1)             //大循环
                {
                    D1=0;            //点亮第一个发光二极管
                    delay();           //延时500ms
                    D1=1;            //关闭第一个发光二极管
                    delay();           //延时500ms
                }
            }
            void delay()               //延时子函数
            {
                uint x,y;
                for(x=500;x>0;x--)
                for(y=110;y>0;y--);
            }

2.函数

C51的函数由类型、函数名、参数表、函数体组合而成。函数名是一个标识符,它是大小写可以区别的,最长可为255个字符。参数表是用圆括号()括起来若干个参数,项与项之间用逗号隔开。函数体是用大括号括起来的若干C语句,语句之间用分号隔开。最后一个语句一般是return(主函数中可以省略),有时也可以省略。函数类型就是返回值的类型,函数类型除了整型外,需要在函数名前加以指定。

C51的函数定义如下:

            类型  函数名(参数表)
            参数说明;
            {
            数据说明部分;
            执行语句部分;
            }

3.C51的数据类型

单片机在编程使用各种变量之前,首先要对变量定义,数据类型是变量一个很重要的概念,数据类型指该类型的数据能表示的数值范围。单片机在执行程序运算过程中,因为这个变量的大小是有限制的,所以不能随意给一个变量赋任意的值,因为变量在单片机的内存中是要占据空间的,变量大小不同,所占据的空间就不同。所以在设定一个变量之前,必须要给编译器声明这个变量的类型,以便让编译器提前从单片机内存中分配给这个变量合适的空间。

(1)基本数据类型

单片机的C语言中常用的数据类型如表1-7所示。

表1-7 单片机的C语言中常用的数据类型

例如:

            unsigned int a;      //a为无符号整型,值域范围0~65535

当计算的结果隐含另一种数据类型时,数据类型可以自动进行转换。例如将一个位变量赋值给一个整型变量时,位变量值自动转换为整型,也可以采用人工强制对数据类型进行转换。

数据类型强制转换的书写格式为:

           (要转换成的数据类型)(变量)

例如:

         (double)a;        //将a强制转换为double型

(2)扩充的数据类型

① SFR/SFR16。这是单片机中特殊功能寄存器(SFR)的定义,有8位和16位的。SFR,对8位特殊功能寄存器的定义,占一个字节单元;SFR16,对16位特殊功能寄存器的定义,占一个字单元。定义格式为:

            SFR  特殊功能寄存器名= 地址;

例如:

            SFR P1 = 0X90;
            SFR16 T2 = 0xCC;

C51对特殊功能寄存且做好了定义存在头文件中(REG51.H),用户可直接使用特殊功能寄存器名一般用大写字母表示。

② sbit。用于定义片内可位寻址区(20H~2FH)和SFR中的可位寻址的位。定义格式为:

            sbit  位变量名 =SFR名^位号;

例如:

            sbit led0 = P1^0;
            sbit OV = PSW^2;

4.常量与变量

单片机在操作时会涉及各种数据,包括常量与变量。

(1)变量

变量定义的语法格式为:

            变量数据类型说明  变量存储位置说明  变量名

C51是面向MCS-51系列单片机及其硬件控制系统的开发工具,它定义的任何数据类型都必须以一定的存储类型的方式定位于MCS-51系列单片机的某一存储区中。在MCS-51系列单片机中,程序存储器与数据存储器是严格分开的,且都分为片内和片外两个独立的寻址空间,特殊功能寄存器与片内RAM统一编址,数据存储器与I/O口统一编址,这是MCS-51系列单片机与一般微机存储器结构不同的显著特点。

C51存储类型与MCS-51系列单片机实际存储空间的对应关系如表1-8所示。

表1-8 C51存储类型与MCS-51实际存储空间的对应关系

访问片内数据存储器(data、idata、bdata)比访问片外数据存储器(xdata、pdata)相对要快很多,其中尤其以访问data型数据最快,因此,可将经常使用的变量置于片内数据存储器中,而将较大以及很少使用的数据单元置于外部数据存储器中。

例如:

            char data var1;            /*字符变量Var1定义为data存储类型*/

其中data常可以省略。

(2)常量

常量分数字常量、字符常量、字符串常量三种。在串口数据传输、液晶显示等操作时,经常会用到字符常量和字符串常量。我们通常将变量定义在程序存储区做常量使用,例如:

            char  code  CHAR_ARRAY[]={“Start working!”};

5.C51运算符

C51语言的运算符分以下几种。

(1)算术运算符

算术运算符除了一般人所熟悉的四则运算(加、减、乘、除)外,还有取余数运算,如表1-9所示。

表1-9 算术运算符

(2)关系运算符

关系运算符用于处理两个变量间的大小关系,如表1-10所示。

表1-10 关系运算符

(3)逻辑运算符

逻辑运算符就是执行逻辑运算功能的操作符号,如表1-11所示。

表1-11 逻辑运算符

(4)位运算符

位运算符与逻辑运算符非常相似,它们之间的差异在于位运算符针对变量中的每一位,逻辑运算符则是对整个变量进行操作。位运算的运算方式如表1-12所示。

表1-12 位运算符

程序范例:

            main()
            {
             char A,B,C,D,E,F,x,y;
             x=0x25;
             y=0x62;
             A=x&y;
             B=x|y;
             C=x^y;
             D=~x
             E=x<<3;
             F=x>>2
            }

程序结果:

            A=0x20   B=0x67   C=0x47    D=0xda     E=0x28   F=0x09。

(5)递增/减运算符

递增/减运算符也是一种很有效率的运算符,其中包括递增与递减两种操作符号,如表1-13所示。

表1-13 算术运算符

程序范例:

            main()
          {
            int A,B,x,y;
            x=6;
            y=4;
            A=x++;
            B=y--;
          }

程序结果:

            A=7,B=3

6.C51的流程控制语句

(1)While循环语句

它的格式如下:

            while(表达式)
            {
            语句;
            }

特点:先判断表达式的值,后执行语句。

原则:若表达式不是0,即为真,那么执行语句。否则跳出while语句往下执行。

程序范例:

            while(1)         //表达式始终为1,形成死循环
            {
            语句;
            }

(2)for循环语句

for语句是一个很实用的计数循环,其格式如下:

            For(表达式1;表达式2;表达式3)
            {
            语句;
            }

执行过程:

① 求解一次表达式1。

② 求解表达式2,若其值为真(非0即为真),则执行for中语句。然后执行第③步。否则结束for语句,直接跳出,不再执行第③步。

③ 求解表达式3。

④ 跳到第②步重复执行。

程序范例1:

            a=0;
            for(i=0;i<8;i++)    //控制循环执行8次
            {
              a++;
             }

程序执行结果:a=8

(3)if-else语句

if-else语句提供条件判断的语句,称为条件选择语句,其格式如下:

            if(表达式)
            {
            语句1;
            }
            else
            {
            语句2;
            }

在这个语句里,将先判断表达式是否成立,若成立,则执行语句1;若不成立,则执行语句2。

其中else部分也可以省略,写成如下格式:

            If(表达式)
            {
            语句;
            }

除此以外,还有一种选择语句:

            If(条件表达式1)       语句1
                  else if(条件表达式2)语句2
                  ……
                  else if(条件表达式n)语句n
                  ……
                  else               语句p

含义:从条件表达式1开始顺次向下判断,当遇到为真的那个条件表达式,如“条件表达式n”,执行语句n,之后不再判断余下的条件表达式,程序直接跳转到“语句p”之后。如果所有的条件表达式没有一个为真,则执行“语句p”。

(4)开关语句

            Switch(表达式)
            {
            case  常量1: 语句1
                        break;
             case  常量2:语句2
                        break;
              ……
             case  常量m:语句m
                          break;
             ……
            case  常量n: 语句n
                        break;
            default :    语句p
           }

含义:将表达式的值同常量1到常量n逐个比较,如果表达式的值与某个常量相等,假设与常量m相等,则执行语句m,然后通过语句m后的break语句直接退出switch开关。如果没有一个常量与表达式相等,则执行语句p,然后结束switch开关。

(5)文件包含

C51为我们提供了大量标准的库函数,这些库函数按照功能被打包成几个文件,如表1-14所示。如果我们要使用某个现成的库函数,则需要把该库函数所在的文件包含进单片机程序中。文件包含的语法有两种,两者功能相同:

表1-14 函数库

              #include  <文件名>   或   #include  “文件名”

前面提到的声明特殊功能寄存器的文件可以通过如下写法包含进来:

            #include  <reg52.h>

1.3 项目实现

1.3.1 设计思路

本项目要求设计单片机驱动LED闪烁的电路,选用1个LED和单片机I/O口相连,利用C语言编制程序驱动1个LED闪烁。

1.3.2 硬件电路设计

在了解单片机的最小系统后,我们可以设计出最简单的单片机控制LED灯电路。单片机的I/O口可以直接驱动一些器件,通过单片机运行程序,达到单片机对一些器件的控制。LED是一种常用的显示器件,单片机的I/O可以直接驱动。

图1-24所示是单片机驱动LED电路,图中P1.0端口与电源之间接有一个电阻R2,当P1.0口输出低电平时,从电源正极出发经过电阻的电流通过P1.0口进入单片机,此时LED亮,当此时P0口输出高电平时,此时LED不亮。

图1-24 单片机驱动LED电路原理

1.3.3 程序设计

单片机的P0~P3口都可以进行位操作。本项目要实现LED闪烁,只要让P1.0电平周期性变化即可。LED闪烁程序流程如图1-25所示。

图1-25 LED闪烁程序流程

在Keil程序设计软件中,P0.0口定义为P0^0,因此在利用C语言程序设计时,要想让P0.0为低电平,只要编写P0^0 = 0一条语句即可。为了使程序简单明了,也可以利用sbit LED1 = P0^0语句,让LED1代替P0^0。

程序清单如下:

            /*****************************************************************************/
            #include<reg51.h>               //包含头文件,文件内包含了51单片机的功能定义
            sbit LED1=P1^0;               //LED接P1.0。在kell C51软件中,定义P1.0为P1^0,
            void delay(unsigned char x)        //延时函数
            {
                unsigned char i,j;
                for(i = 0;i < x;i++)
                for(j = 0;j < 255;j++);
            }
            void main(void)                //主函数
            {
                while(1)                 //程序死循环
                {
                    LED1=0;             //P1.0输出低电平,LED1亮
                    delay(100);            //调用延时函数,延时一段时间,约0.3秒,不精确
                    LED1=1;             //P1.0输出高电平,LED1灭
                    delay(100);
                }
            }
            /*****************************************************************************/

程序说明:

● 因为使用的单片机芯片为STC89C51,因此程序包含reg51.h文件。reg51.h文件定义了51单片机所有特殊功能寄存器的名称定义和相对应的地址值。所谓文件包含,是指一个文件将另外一个文件的内容全部包含进来。reg51.h是Keil软件中定义51系列单片机内部资源的头文件,在编写单片机程序时,只要用到51单片机内部资源,程序前面必须把此文件包含进来。

● 利用位定义命令让LED1等价于P1.0,程序执行LED1 = 1后,单片机内部位寄存器相应位设置为高电平,P1.0端口输出高电平,单片机的所有I/O口都可以位定义,也可以字节定义。

● 由于单片机执行速度快,如果不进行延时,点亮之后马上熄灭,速度很快。由于人眼有视觉暂留效应,根本无法分辨,所以要加入延时程序,让人眼能够看到亮变灭。

● 延时程序delay是定义在前,使用在后。这里用了两条for语句构成双重循环,循环体是空的,以实现延时的目的。在执行delay()的过程中,单片机只能忙这一件事情,单片机在执行此函数相关指令时浪费和占用的时间就是执行延时函数获得的时间,但利用delay()不能得到精确的延时。

● 单片机程序是顺序执行程序,先执行主函数,在主函数内可以调用分函数,分函数可以再调用分函数,但分函数不能调用主函数,程序执行一条命令再执行下一条,执行完毕后返回到主函数入口进行下次循环。

1.3.4 仿真调试

单片机系统的设计与开发包括硬件和软件两方面。硬件是单片机系统的基本组成,要求设计者具备一定的电路基础和元器件应用能力、电路设计能力等;软件的设计必须依照硬件结构和电气特性要求,程序以硬件功能的稳定实现为目的。本章从单片机系统软件设计入手,介绍单片机程序开发使用的程序和设计平台与仿真平台,硬件设计将在以后章节中介绍。

1.单片机程序设计与开发平台——Keil C

Keil是美国Keil Software公司推出的一款51系列兼容单片机C语言程序设计软件,目前,Keil使用较多的版本为μVision3,它集可视化编程、编译、调试、仿真于一体,支持51汇编、PLM和C语言的混合编程,界面友好、易学易用、功能强大。它具有功能强大的编辑器、工程管理器以及各种编译工具,包括C编译器、宏汇编器、链接/装载器和十六进制文件转换器。

(1)Keil μVision3的工作界面

Keil μVision3软件的安装属于标准Windows软件安装。安装之后在桌面或者开始菜单中运行Keil,启动后的工作界面如图1-26所示,主要分为菜单工具栏、项目工作区、源码编辑区和输出提示区。

图1-26 Keil μVision3 IDE的工作界面

Keil为用户提供了可以快速选择命令的工具栏和菜单栏以及源代码窗口、对话框。菜单栏提供各种操作命令菜单,用于编辑操作、项目维护、工具选项、程序调试、窗口选择以及帮助。另外,工具条按钮和键盘快捷键允许快速执行命令。下面通过一个实例说明Keil常用的菜单、命令的应用。

(2)Keil应用

Keil集成的工程管理器使得开发的应用程序更加容易,Keil平台把单片机系统软件部分作为一个工程对待,完整的程序设计过程包括选择工具集(对基于ARM的工程)、创建新的工程和选择CPU、添加工作手册、创建新的源文件、在工程里加入源文件、创建文件组、设置目标硬件的工具选项、配置CPU启动代码、编译工程和创建应用程序代码、为PROM编程创建HEX文件等。

针对单片机的程序设计,可以把Keil应用分工程文件的创建、新建源文件并添加到工程中、程序编写、编译调试4个基本步骤。为了便于说明各个过程,现以单片机控制LED灯闪烁为例进行讲解,电路原理如图1-24所示。

① 创建工程文件,选择单片机芯片。选择Keil菜单栏中“Project”→“New μVision Project….”命令,μVision 3将打开“新建工程”对话框,输入工程名称后即可创建一个新的工程。注意,新建工程要使用独立的文件夹,需要在“新建工程”对话框上单击新建一个文件夹,并取一个熟悉的英文名,比如“LED闪烁”。在Project Workspace区域的Files选项卡里可以查阅项目结构,如图1-27所示。

图1-27 工作空间项目结构

当确定工程文件建立后,此时μVision 3会自动弹出对话框要求为目标工程选择CPU,如图1-28所示。对话框包含了μVision3的设备数据库,在左侧一栏选定公司和机型以后在右侧一栏显示对此单片机的基本说明,选择将会为目标设备设置必要的工具选项,通过这种方法可简化工具配置。如果使用的单片机为STC89C51,应选择ATMEL的AT89C51或Intel的8051,它们与STC89C51有相同的内核。

图1-28 选择目标工程的CPU

程序需要通过CPU的初始化代码来配置目标硬件。启动代码负责配置设备微处理器和初始化编译器运行时系统。对于大部分设备来说,μVision3会提示复制CPU指定的启动代码到工程中去。如果这些文件可能需要作适当的修改以匹配目标硬件,应当将文件复制到工程文件夹中。

工程中需要使用这些启动代码,应选择“是(Y)”,如果不使用Keil编写启动代码可以选择“否(N)”。单击“是(Y)”后,工程建立完成。在本例单击“否(N)”。

② 创建新的源文件并添加在工程中。

第一步,新建一个C语言文件。选择“File”→“New”(如图1-29所示)或单击图标以创建一个新的源文件,选项会打开一个空的编辑窗口,也就是编写程序的页面。用户可以在此窗口中输入源代码,然后选择“File”→“Save”命令,以扩展名*.c保存文件,这里保存的文件名为led.c。

图1-29 创建新文件

第二步,在工程里加入源文件。源文件创建完后,需要在工程里加入这个文件。在工程工作区中,移动鼠标选择“Source Group 1”然后右击,将弹出一个下拉窗口,如图1-30所示。选择“Add Files to Group‘Source Group 1’”选项,会打开一个标准的文件对话框,在对话框中选择前面所创建的C源文件,然后单击“Add”按钮。这时文件已被添加到工程,再单击“Close”按钮关闭该对话框即可。文件被添加到工程后即可开始编写程序代码了,除了添加程序代码文件到工程外,还可以添加头文件(*.h)和库文件(*.lib)。

图1-30 添加文件到工作组中

在Project Workspace区域Files选项卡中会列出用户工程的文件组织结构,如图1-31所示。用户可以通过用鼠标拖拉的方式来重新组织工程的源文件。双击工程工作空间的文件名,可以在编辑窗口打开相应的源文件进行编辑。

图1-31 文件组织结构

③ 程序编写。在程序设计页面输入以下语句或指令,其中reg51.h为51系列单片机内部资源的头文件,含各个特殊寄存器和可寻址位的地址定义等。“//”符号后面为对指令的说明。

程序清单如下:

            /*****************************************************************************/
            #include<reg51.h>       //包含头文件,文件内包含了51单片机的功能定义
            sbit LED=P1^0;        //位声明,P1.0在Keil应写成P1^0,LED接P1.0口,位P1.0可寻址
            delay(unsigned int x)    //延时子函数
            {
                unsigned char i,j;    //定义两个局部变量
                for(i=0;i<x;i++)   //for循环套嵌
                for(j = 0;j<100;j++);
            }
            void main(void)        //主函数
            {
                while(1)
                {
                    LED=1;      //LED这时亮
                    delay(100);    //延时1000ms,时间不准,单片机执行这个函数浪费的时间
                    LED = 0;
                    delay(100);
                }
            }
            /*****************************************************************************/

上面程序是利用单片机的1个I/O口驱动1个LED闪烁程序,如果不了解单片机C语言程序,从中很难看出单片机的影子,如果学过C语言,则会熟悉程序的每一行。人们在掌握单片机内部的寄存器基础以后,这个程序实际上很简单。这就是为什么要选用C语言进行单片机的程序设计的原因。利用C语言编写单片机程序,不用考虑单片机内部数据在单片机内部怎样运行,只要了解单片机执行程序按照编写的程序顺序单步执行就可以了。

单片机程序在格式上要求严谨,结构层次比较鲜明。为了增强程序的稳定性,所有函数没有返回值就用void声明,没有形参也需要写void。另外,为了避免程序编写错误,逻辑运算符号、左移右移、比较等符号左右留有一个空格,每一条命令占用一行,在程序中“{”、“}”上下对齐,在“{”下一行命令要后退一个Tab键。

④ 编译调试,并创建HEX文件。

第一步,编译工程。鼠标按下按钮,则让Keil对程序进行编译,同时也对程序进行保存,图1-32所示的是编译结果显示窗口。如果程序有错误,会在窗口提示,鼠标双击错误提示,将会看到一个箭头指向程序的错误处,便于修改。

图1-32 编译结果显示窗口

第二步,工程配置。编写的程序最终要在单片机内部运行,下载到单片机内部的程序为二进制格式,编译过程主要目的就是让Keil自动创建一个HEX文件。程序设计设置需要根据目标硬件的实际情况对工程进行配置。通过单击目标工具栏图标或“Project”菜单下的“Options for Target”命令,在弹出的“Options for Target‘Target 1’”对话框中可指定目标硬件和所选择设备片内组件的相关参数,如图1-33所示。“Options for Target‘Target 1’”对话框中各选项说明如表1-15所示。

图1-33 “Options for Target‘Target 1’”对话框

表1-15 Target页面选项说明

第三步,创建HEX文件。在“Options for Target‘Target 1’”对话框中选择“Output”选项,打开“Output”选项卡,选择“Create HEX File”选项,μVision 3会在编译过程中同时产生HEX文件,如图1-34所示。

图1-34 “Output”选项卡

⑤ 调试程序。Keil调试器可用于调试应用程序,调试器提供了在PC上调试和使用评估板/硬件平台进行的目标调试。工作模式的选择在如图1-35所示的“Debug”选项卡内进行。

图1-35 “Debug”选项卡

在没有目标硬件情况下,可以使用仿真器(Simulator)将μVision3调试器配置为软件仿真器。它可以仿真微控器的许多特性,还可以仿真许多外围设备包括串口、外部I/O口及时钟等。所能仿真的外围设备在为目标程序选择CPU时就被选定了。在目标硬件准备好之前,可用这种方式测试和调试嵌入式应用程序。

用μVision3已经内置了多种高级GDI驱动设备,如果使用其他的仿真器则需要首先安装驱动程序,然后在此列表里面选取。在此也可配置与软件Proteus的接口,使两个软件联合工作。具体配置在Proteus软件的介绍部分详细说明。

第一步,动调试模式。通过菜单命令“Debug”→“Start/Stop Debug Session”或者工具栏图标,可以启动/关闭μVision3的调试模式,如图1-36所示。

图1-36 Debug工作界面

在调试过程中,若程序执行停止,μVision 3会打开一个显示源文件的编辑窗口或显示CPU指令的反汇编窗口,下一条要执行的语句以黄色箭头指示。

在调试时,编辑模式下的许多特性仍然可用。如可以使用查找命令或修改程序中的错误,应用程序中的源代码也在同一个窗口中显示。

但调试模式与编辑模式有所不同,调试菜单与调试命令是可用的,其他的调试窗口和对话框、工程结构或工具参数不能被修改,所有的编译命令均不可用。

第二步,程序调试。程序调试要使用“Debug”菜单下的常用命令和热键,也可使用按钮进行。“Debug”菜单下的命令和热键功能说明如下。

● Run(F5):全速运行,直到运行到断点时停止,等待调试指令。

● Step into(F11):单步运行程序。每执行一次,程序运行一条语句。对于一个函数,程序指针将进入到函数内部。

● Start Over(F10):单步跨越运行程序。与单步运行程序很相似,不同点是跨越当前函数,运行到函数的下一条语句。

● Step Out of current Function(Ctrl+F11):跳出当前函数。程序运行到当前函数返回的下一条语句。

● Run to Cursor line(Ctrl+F10):运行到当前指针。程序将会全速运行,运行到光栅所在语句时将停止。

● Stop Running:停止全速运行。停止当前程序的运行。

设置断点的作用是当程序全速运行时,需要在程序不同的地方停止运行然后进行单步调试,可以通过设置断点来实现。断点的设置只能在有效代码处设置,如图1-37所示左侧栏中的有效代码深灰色处。

图1-37 断点的设置

将鼠标移到有效代码处,然后双击会出现一个红色标记,表示断点已成功设置;鼠标在红色标记处又双击,红色标记消失,表示断点已成功删除。当程序运行到设置的断点的位置停止运行。

此时,可以打开“View”→“Watch & Call Stack Window”命令,对程序中的数值进行监视,例如对i的值进行监视,如图1-38所示。每按下一次“Step into”按钮,i的数值增加一次。数值Value可以在十六进制和十进制之间选择。

图1-38 对数值i的监视

同时也可以在“Project Workspace”的“Register”内看到运行时间,此例中此时的时间为0.0326秒,如图1-39所示。如果要调整闪烁的时间间隔可以调整x的数值,以达到调整闪烁时间的目的。

图1-39 仿真运行时间

Keil μVision3集成开发环境的功能相当强大,本节只是简单地介绍其一些基本的使用方法,如果需要对Keil μVision3集成开发环境有更深入和全面的了解请阅读该软件自带的帮助文档。

2.单片机系统仿真与调试

程序仿真与调试是单片机软件开发过程的必要环节。一般开发可以在电路原理基础上利用软件进行仿真与调试,以便减少硬件的重复设计和成本。在学习单片机程序设计时,也会经常用到软件仿真和调试,以验证程序设计的正确性、完整性、可靠性。软件仿真是一种依靠PC系统资源进行的硬件模拟、指令模拟和运行模拟。在软件仿真和调试过程中,不需要任何在线的硬件和目标板可以完成软件的开发全部过程。

单片机软件仿真调试工具常用的软件为Proteus,该软件是由英国Labcenter electronics公司开发的EDA工具软件。Proteus主要由ARES和ISIS两个程序组成。前者主要用于PCB自动或人工布线及其电路仿真,后者主要采用原理布图的方法绘制电路并进行相应的仿真。Proteus电路仿真过程是互动的,针对微处理器的应用可以直接在基于原理图的虚拟原型上编程,并实现软件代码级的调试,还可以直接实时动态地模拟按钮、键盘的输入,LED、液晶显示的输出,同时配合虚拟工具如示波器、逻辑分析仪等进行相应的测量和观测。Proteus软件的应用范围十分广泛,涉及PCB制版、Spice电路仿真、单片机仿真。

本节主要以单片机最小系统电路为基础,对上节程序设计进行仿真调试,使读者初步掌握Proteus应用过程。

(1)Proteus ISIS的工作界面

Proteus是标准的Windows安装程序。在安装完成后出现Proteus 7 Professional程序组,首先运行Licence Manager进行授权认证,之后可以运行ARES 7 Professional或者ISIS 7 Professional。这里主要讲解Proteus ISIS 7 Professional的使用方法。

Proteus ISIS 7 Professional启动后的工作界面如图1-40所示。工作区域主要分为:标题栏、菜单栏、标准工具栏、绘图工具栏、状态栏、对象选择按钮、预览对象方位控制按钮、仿真进程控制按钮、预览窗口、对象选择器窗口、图形编辑窗口。

图1-40 Keil μVision3 IDE的工作界面

① 预览窗口(The Overview Window)。此窗口可显示两个内容,整个图纸或者一个元件原理图。当鼠标在此区域单击后,鼠标图形变为,显示整张原理图的缩略图,并会显示一个绿色的方框。绿色的方框里面的内容是当前原理图窗口中显示的内容,此时绿框跟随鼠标运动,在适当位置再次单击就可改变右边原理图的可视范围。当选择一个元件列表中元件时,该区域则显示该元件的原理图。

② 原理图编辑窗口(The Editing Window)。此区域是主要工作区域,主要用来绘制原理图。蓝色方框内为可编辑区,各种元件都要放置在蓝色区域中。

③ 模型选择工具栏(Mode Selector Toolbar)。该区域分为Main Modes(主要模型)、Gadgets(配件)、2D Graphics(两维图形)三个部分,如图1-41所示。为了显示方便在此改为了横排版。

图1-41 模型选择工具栏

Main Modes(主要模型)包括选择元件、放置连接点、放置标签、放置文本、绘制总线、放置子电路、即时编辑元件参数。

Gadgets(配件)包括终端接口(电源、接地、输出、输入等接口)、器件引脚、仿真图表(各种分析)、录音机、信号发生器、电压探针(用于仿真图表)、电流探针、虚拟仪表(示波器等)。

2D Graphics(两维图形)包括直线、方框、圆、圆弧、多边形、文本、符号、画原点。

④ The Object Selector(元件选择器)。它用于选择已经在库中调出来的元器件、终端接口、信号发生器、仿真图表等。单击按钮会打开“挑选元件”对话框,选择一个元件后,该元件会在该元件列表中显示,以后要用到该元件时,只需在元件列表中选择即可。

⑤ 仿真控制栏。分别表示运行、单步运行、暂停、停止。

(2)电路原理设计

利用软件仿真要把单片机系统电路设计完整。Proteus ISIS 7 Professional仿真系统创建单片机仿真电路执行以下步骤:选择单片机芯片、放置其他器件或者仿真仪器、用导线或者总线连接各个器件。需要注意,原理图编辑窗口的操作是不同于常用的Windows应用程序的。正确的操作是用左键放置元件;右键选择元件;双击右键删除元件;右键拖选多个元件;先右键后左键编辑元件属性;先右键后左键拖动元件;连线用左键,删除用右键;改连接线:先右击连线,再左键拖动;中键或者滚轮放缩原理图。下面对上一节LED闪烁程序进行仿真。

① 选择元件。单击工具箱的“元器件”按钮,使其选中,再单击ISIS对象选择器左边中间的“P”按钮,出现“Pick Devices”对话框,如图1-42所示。或者在编辑窗口单击鼠标右键,选择“Place”,再选择“Component”,再选择“From Libraries”即可。

图1-42 “Pick Devices”对话框

左边栏分别为关键字、类别、子类别和制造商。可以先从类别中选取后,到子类别点选,在实际操作中应该了解计划放置的元件的类型和型号才能在软件的器件库中找到,如要放置一个LED,需要先单击“类别”中“Optoelectronics”,然后在“子类别”中单击“ELDS”。“Pick Devices”对话框中间区域是元器件型号以及主要参数。右边是所选元件的预览图和PCB引脚图。

当不知道元件的类别时可以从搜索“关键字”处查询。在这里搜索“89C51”后出现如图1-43所示界面。

图1-43 搜索“89C51”后所出现的界面

选择“AT89C51”,双击可将其添加到元件列表中。照此方法可以一次添加所需要的全部元器件,也可以在需要时再次调用元件库进行添加。这里一次调用全部元件。“Optoelectronics”类别下的LED-birg(发光二极管),“Resistors”类别下的RESPACK-8(排阻)。在全部选择完毕以后单击“确定”按钮,关闭元件库。元件列表如图1-44所示。

图1-44 元件列表

② 放置元器件。在元件列表中选取AT89C51,在原理图编辑窗口中单击左键,AT89C51被放到原理图编辑窗口中。用同样方法可以放置LED-BIRG和RESPACK-8。在放置的过程中可能遇到下列问题。

● 对象的放置。在左边的对象选择器选定这个元件,单击这个元件,然后把鼠标指针移到右边的原理图编辑区的适当位置,再单击就把相应的元件放到了原理图区。

● 放置电源及接地符号。许多器件没有VCC和GND引脚,但事实是这些引脚隐藏了,在使用时可以不用加电源,单片机芯片、LCD的VSSVDDVEE不需连接,默认VSS=0V、VDD=5V、VEE=-5V、GND=0V。如果需要加电源可以单击工具箱的“接线端”按钮,这时对象选择器将出现一些接线端,如图1-45所示。

图1-45 添加了电源的对象选择器

在器件选择器里单击图1-45中的“POWER”,鼠标移到原理图编辑区,单击即可放置电源符号;同理也可以把接地符号GROUND放到原理图编辑区。

● 对象的编辑。调整对象的位置和放置方向以及改变元器件的属性等,有选中、删除、拖动等基本操作,可以通过右击器件,弹出右键菜单进行操作。

这些操作主要有:

a.拖动标签。许多类型的对象有一个或多个属性标签附着。可以很容易地移动这些标签使电路图看起来更美观。移动标签的步骤如下:首先右击选中对象,然后用鼠标指向标签,按下鼠标左键。一直按着左键就可以拖动标签到需要的位置,释放鼠标即可。

b.对象的旋转。许多类型的对象可以调整旋转为0°、90°、270°、360°以及以x轴或者y轴镜象旋转。

c.编辑对象的属性。对象一般都具有文本属性,这些属性可以通过一个对话框进行编辑。编辑单个对象的具体方法是:先右击选中对象,然后单击对象,此时出现属性编辑对话框。也可以单击工具箱的按钮,再单击对象,也会出现编辑对话框。图1-46是AT89C51的编辑对话框,这里可以改变元件的标号、元件值、PCB封装时钟频率以及是否把这些东西隐藏等,修改完毕,单击“确定”按钮即可。

图1-46 AT89C51的编辑对话框

③ 绘制导线。

a.画导线。Proteus的智能化可以在想要画线的时候进行自动检测。当鼠标的指针靠近一个对象的连接点时,鼠标的指针就会出现一个“”符号,再单击元器件的连接点,移动鼠标到需要连接的连接点,鼠标再次变为绿色,单击就出现了连接线。此时软件自动定出线路径,如图1-47所示。这就是Proteus的线路自动路径功能(简称WAR),如果只是在两个连接点单击,WAR将选择一个合适的线径。WAR可通过使用工具栏里的“WAR”命令来关闭或打开,也可以在菜单栏的“Tools”菜单下找到这个图标。如果想自己决定走线路径,只需在想要拐点处单击即可。在引线的过程中需要放置连接点,需要在放置的位置双击,就放置了一个圆点,此点可以连接4条导线。

图1-47 连接导线

在绘制导线的过程中,随时可以按Esc键或者右击来放弃画线。

b.画总线。为了简化原理图,也可以用一条导线代表数条并行的导线,这就是所谓的总线。当电路中多根数据线、地址线、控制线并行时经常使用总线设计。单击工具箱的“总线”按钮,即可在编辑窗口画总线。单击则开始绘制,双击则结束本段绘制,右击则取消继续绘制。

单击鼠标右键,选择菜单“Place”→“Bus”放置点线,然后再画总线分支线,它是用来连接总线和元器件管脚的。画总线的时候为了和一般的导线区分,一般画斜线来表示分支线,此时需要关闭自动布线功能,可单击图标。画好分支线还需要给分支线放置网络标号,放置方法是用鼠标单击连线工具条中图标,这时光标放置在支线上变成十字形并且将有一虚线框,如图1-48所示。再单击,系统弹出“Edit Wire Label”对话框,如图1-49所示。定义网络标号比如P01,将设置好的网络标号放在的短导线上,鼠标左键拖动即可将之定位。注意,在标定导线标签的过程中,相互接通的导线必须标注相同的标签名。

图1-48 选定要标号的支线

图1-49 “Edit Wire Label”对话框

c.放置线路节点。如果在交叉点有电路节点,则认为两条导线在电气上是相连的,否则就认为它们在电气上是不相连的。ISIS在画导线时能够智能地判断是否要放置节点。但在两条导线交叉时是不放置节点的,这时要想两个导线电气相连,只有手工放置节点了。单击工具箱的“节点放置”按钮,当把鼠标指针移到编辑窗口,指向一条导线的时候,会出现一个“”号,单击左键就能放置一个节点。

通过以上步骤就可以得到如图1-50所示的电路图。在此图中,单片机连接晶振,电容、电解电容组成最小系统电路,同时P1.0口需要连接限流电阻,连接LED。由于本例只有一个端口使用,因此也没有使用总线。

图1-50 电路连接图

(3)仿真与调试

① 添加仿真文件。此时用鼠标左键双击AT89C51,在弹出的图1-51的“编辑元件”对话框的“Program File”内添加上一节程序设计生成的HEX文件。

图1-51 创建HEX文件

在“Program File”中单击按钮出现“文件浏览”对话框,找到.hex文件,单击“确定”按钮完成添加文件,在“Clock Frequency”中把频率改为12MHz,单击“确定”按钮退出。

② 运行仿真。单击按钮中的“运行”按钮,程序开始仿真运行,运行效果如图1-52所示。

图1-52 仿真运行状况

从界面上可以直接看出仿真效果,发光二极管不断闪烁,单片机的端口呈现红色或蓝色的点,红色代表高电平,蓝色代表低电平,灰色代表不确定电平。运行时,在“Debug”菜单栏中可以查看单片机的相关资源。例如可以打开“Debug”菜单下的“Watch Window”窗口,通过右键添加观察对象,此时观察的是P1口的数值输出,如图1-53所示。

图1-53 仿真运行时的P0口输出

③ 调试。调试的过程是指通过观察仿真结果中出现的问题对程序进行修改的过程。在利用Keil程序设计时,简单的程序往往依据编译的通过与否就可以判断程序设计的准确性,但较大程序,编译成功并不能代表程序运行一定成功,需要通过软件仿真结果对程序修改多次才能达到设计目的。

【项目总结】

1.单片机是把CPU、RAM、ROM、定时/计数器以及I/O口等功能模块集成在一块芯片上的微型计算机。生产单片机的厂家很多,但最基本还是采用MCS-51结构。

2.单片机最小系统是指用最少的元件组成的单片机系统,也就是单片机在工作时至少具备的电路系统。

3.单片机的开发工具包括软件和硬件两部分。软件开发工具包括调试程序的Keil μVision软件,仿真程序的Proteus软件;硬件开发工具包括仿真器、编程器、ISP下载线。

4.C51语言是基于51单片机的C语言,学习时侧重和C语言的不同。

思考与练习

1.AT89C51单片机由哪些主要功能部件组成?

2.简述单片机应用研发过程和研发工具。

3.画图说明AT89C51单片机的存储空间结构。

4.当AT89C51单片机外接晶振为6MHz时,其振荡周期、状态时钟周期、机器周期、指令周期的值各为多少?

5.请画出单片机的最小系统。

6.请完成用1个开关控制、1个LED闪烁快和慢两种效果的电路及其C语言程序设计。