简简单单学通51单片机开发(光盘内容另行下载,地址见书封底)(txt+pdf+epub+mobi电子书下载)


发布时间:2020-09-26 04:09:18

点击下载

作者:王晋凯

出版社:清华大学出版社

格式: AZW3, DOCX, EPUB, MOBI, PDF, TXT

简简单单学通51单片机开发(光盘内容另行下载,地址见书封底)

简简单单学通51单片机开发(光盘内容另行下载,地址见书封底)试读:

前言

单片机的出现可以追溯到20世纪70年代。在1970~1974年期间,诞生了第一代4位单片机。在1978~1983年期间,Intel公司推出了MCS-51系列单片机(即51单片机),标志着单片机进入了8位时代。几十年来,以8051系列为代表的8位单片机在世界范围内长盛不衰,得到了不断发展和加强。51系列单片机也以其强大的功能在工业控制领域得到了广泛的应用。近年来,以ARM为代表的32位控制器开始流行起来。所以有些人可能会觉得51单片机即将退出历史的舞台。然而,事实上51系列单片机在工控领域依然有着非常广泛的应用,而且也会在相当长的一段时间内继续发挥重要作用。

国内在较早的时期就引入了51单片机,而且相关院校也普遍开设了51单片机的课程,这使得单片机在国内的院校中广为流行。相应地,图书市场上也出版了大量的单片机教程。然而这些教程大多都是以生涩的理论知识讲解为主,缺乏实践教学。这给读者的学习造成了很多困惑:所学知识不能很好地应用于实际开发。时至今日,这种现象依然还存在。

笔者从大学期间就是一个电子技术的狂热爱好者,毕业后又从事了多年的电子产品的研发工作。作为一个过来人和从业者,想尽自己的绵薄之力,给广大的51单片机爱好者提供一些学习上的帮助,于是便有了这本《简简单单学通51单片机开发》的图书。学习单片机开发离不开实践,所以本书强调实践性教学,每个知识点都结合了相应的实例来讲解。这些实例都是通过仿真软件Proteus进行演示,效果很直观。而且大部分实例采用了汇编和C两种语言开发,一方面可以弥补读者在语言方面的不足,更为关键的是可以加深读者对单片机的理解。另外,为了帮助读者更加高效、直观地学习,笔者专门为本书详细录制了长达21小时的高清配套教学视频,以辅助读者学习。

相信在笔者的带领下,读者不但可以很好地掌握51单片机开发的知识,而且还可以感受到51单片机学习过程中的极大乐趣和做出实实在在产品的兴奋!本书特色

1. 实例运用Proteus进行仿真

很多读者花费了大量的时间和金钱,去制作一块资源有限的调试开发板。而Proteus完全可以取代这个过程。Proteus中包含了非常多的资源模块,供开发人员快捷、方便地搭建一个学习系统。本书便很好地利用了Proteus,清晰地演示了每个实例的最终运行效果。

2. 重点介绍软件仿真

大型软件项目的调试和排错并非常规分析就能实现,而需要借助仿真调试。51单片机开发环境Keil具有软件仿真的功能。本书将重点介绍利用软件仿真调试程序的方法。

3. 同步使用汇编语言和C语言

很多单片机书籍鼓励读者放弃汇编语言。这是非常不合理的。汇编语言在单片机的开发中是无法完全被C语言所取代的。一些要求实时性非常高的控制场合还得依赖于汇编代码而实现。此外,学习汇编语言有助于读者对单片机的内部资源有一个全面的认识,从而提高代码的编写效率。在本书中,大部分实例采用了汇编和C两种编程语言进行开发。

4. 使用大量的程序流程图

程序流程图可以将繁杂的语言叙述简化,让人看后一目了然,非常直观。这对于读者理解相关知识至关重要,是编程图书中不可或缺的讲解方式。本书讲解过程中使用了大量的程序流程图,几乎每个程序模块,甚至一些程序语句都使用了程序流程图。

5. 使用外部资源

51单片机的内部资源并不是非常丰富,但可以通过使用外部扩展资源来对它的功能进行增强。本书中使用的外部扩展主要有两方面:一是硬件系统,包括功能芯片的使用和程序资源的扩充;二是软件系统,包括使用C51库函数和移植外部软件包。

6. 提供大量的习题和实例扩展

本书每章最后都提供了笔者精心编写的多个填空题、选择题、解答题和实例扩展题等。读者通过完成这些题目不但以检查自己对相关内容的掌握情况,而且可以巩固和提高所学的知识。这些题目的参考答案和解题思路需要读者自行按照本书封底的下载说明下载。

7. 提供21小时高清配套教学视频

笔者为本书录制了长达21小时的高清教学视频。这些视频不是泛泛而谈,而是非常详细和直观地再现了书中的大量操作。这对于实践性要求较高的单片机学习有很大的帮助。这些视频和书中涉及的所有实例源文件及电路图一并收录于配书DVD光盘中。另外,光盘中还收录了本书所用工具软件(Keil编译器与Proteus演示版)的获取方式。本书内容

第1章 简单了解51单片机

本章涵盖的内容有:51单片机的内部资源,包括引脚结构、存储器空间分配、一个最小系统的开发等;开发环境Keil和仿真软件Proteus介绍;一个实例电路和程序的演示。

第2章 从I/O端口开始学习51单片机

本章结合一个流水灯实例,讲解了51单片机I/O端口的控制方法。其中需要重点掌握的内容有:汇编语言的数据传送指令和C语言赋值语句;几个特殊功能的寄存器;使用Proteus绘制电路图。

第3章 51单片机对中断的控制

本章主要介绍了单片机的中断控制技术。需要掌握的内容有:汇编语言及C语言的循环语句和移位指令;通过一个外中断的实例改进流水灯控制方法;理解汇编语言和C语言处理中断的区别。

第4章 51单片机对时间的控制

本章涵盖两大知识点:一是单片机软件定时编程方法;二是单片机定时器,主要介绍单片机内部的两个定时器的4种工作方式,对于每种工作方式都提供了对应的程序实例。

第5章 数码管显示技术

本章主要介绍了数码管显示技术。需要掌握的内容有:数码管静态显示的方法;内部数据存储器的读取方法和内部程序存储器的使用方法;数码管动态显示方法。

第6章 通信利器——串口

本章主要介绍了串口通信技术。需要掌握的内容有:51单片机串口通信的4种模式;串口双机通信的实现方法;串并互转的编程思想。

第7章 数字电子时钟的设计

本章介绍了利用单片机的内部资源完成一个电子时钟的设计,使用了包括定时器、串口、外中断等单片机的固有资源。这是一个综合型的实例,需要重点掌握分模块编程的思路。

第8章 更先进的电子时钟

本章主要介绍了运用外扩资源,配合单片机的控制而实现一个功能更加强大的电子时钟的实例。本章使用的外部设备有字符液晶1602和时钟芯片DS1302等。读者需要重点掌握51单片机外部资源和单片机接口的方法。

第9章 51单片机外设扩展

51单片机的内部资源并不丰富,所以进行外部资源的扩展就变得非常重要。本章为51单片机扩展了一片外部数据存储器和两组8位键盘。通过本对章内容的学习,应该掌握汇编语言和C语言进行外部扩展程序的实现方法。

第10章 点阵液晶LCD和矩阵键盘

本章主要介绍了单片机系统的两个常用电路模块:点阵液晶LCD和矩阵键盘。需要掌握的内容有:点阵液晶接口电路和驱动程序;矩阵键盘按键电路原理及扫描的方法。

第11章 计算器程序分析与设计

本章主要有两个任务:一是完成对Proteus自带计算器(汇编语言编写)的分析;二是对另外一个Proteus自带计算器(C语言编写)进行改造。需要读者重点掌握的内容是C51库函数的调用。

第12章 ZLG/GUI在51单片机中的移植及运用

ZLG/GUI是广州周立功公司研发的轻型图形用户界面,具有较为强大的功能。本章重点内容是将该软件包移植到51单片机之中,并掌握综合运用该软件包提供的功能函数。通过对本章内容的学习,读者不仅可以学习一个外部程序资源移植的范例,而且还可以更进一步理解使用外部函数简化单片机开发过程的思想。

附录

本书最后提供了3个附录,以方便读者学习时查阅相关资料。附录A给出了51单片机的汇编指令集;附录B提供了ASCII码表;附录C给出了C语言运算符及其优先级。本书读者对象

□ 51单片机初学者;

□ 想全面学习51单片机开发技术的人员;

□ 单片机产品开发人员;

□ 单片机开发爱好者;

□ 电子产品设计爱好者;

□ 大中专院校的学生;

□ 社会培训班学员。本书作者

本书由王晋凯主笔编写。参与本书编写的人员还有吴万军、项延铁、谢邦铁、许黎民、薛在军、杨佩璐、杨习伟、于洪亮、张宝梅、张功勤、张建华、张建志、张敬东、张倩、张庆利、赵剑川、赵薇、郑强、周静、朱盛鹏、祝明慧、张晶晶。

读者阅读本书的过程中,有任何疑问都可以发邮件到bookservice2008@163.com,我们会及时解决您的问题。编者第1章 简单了解51单片机

现在开始学习51单片机的征程。本章将要介绍51单片机的基础硬件知识,学习51单片机的开发环境,对51单片机的程序语言做一些简单的介绍。重点学习仿真软件Proteus的安装及使用方法。最后做一个小例子来了解51单片机项目的开发。本章的学习目的是让大家对51单片机感兴趣,尽可能简化学习的过程。

1.1 51单片机硬件简述

51单片机是对目前所有兼容Intel 8031指令系统的单片机的俗称。该系列单片机的始祖是Intel公司。80C51单片机目前已成为8位单片机的经典代表,原因是Intel公司将51单片机技术公开,授权给其他公司生产。生产单片机的公司很多,常见的公司及他们生产的51系列单片机主要产品如下:

□ Intel公司的80C31、80C51、87C51,80C32、80C52、87C52系列等。

□ ATMEL公司的89C51、89C52、89S52系列等。

□ Philips、华邦、Dallas、Siemens(Infineon)等公司生产的产品也占有很大的市场。

随着Flash ROM技术的发展,80C51单片机取得了更长足的进展,尤其是ATMEL公司的AT89系列,它广泛应用于工业测控系统之中。在我国,高校学生和电子发烧友等学习所用的单片机很多都是ATMEL公司的AT89系列,因为它除了性能稳定之外,程序烧录过程特别简单。所以在本书的学习中就以ATMEL公司的AT89C52单片机为例来介绍51单片机。

如图1-1所示为常见的51单片机的两种封装。图中左侧所示的封装较为常见,使用较为方便;图中右侧所示的封装因为体积较小,便于集成,所以在工业运用中较为常见。图1-1 51单片机的外形封装

1.1.1 51单片机的逻辑结构及信号引脚

如图1-2所示为51单片机的内部逻辑结构图,够复杂吧,不过我们不必害怕。因为不需要重点来研究这个图,只需要对51单片机的内部逻辑结构有一个大概的理解即可。在这个图中,可以了解51单片机的内部结构和外设资源等信息。图1-2 51单片机的逻辑结构图

看完了内部结构,我们来认识一下51单片机各引脚的名称吧,如图1-3所示。

在图1-3中,将单片机的各引脚做了分类,以帮助大家理解。(1)VDD(40脚):接电源+5V,每一个芯片都需要电源来提供能量。(2)VSS(20脚):接地,也就是GND,同理,每个芯片都需要接地来保证回路。(3)XTAL1(19脚)和XTAL2(18脚):单片机需要时钟的支持,就得有时钟信号的产生或者输入。一般来说,这两个引脚接的是石英晶体,但也可以直接接入外部的时钟信号。(4)PSEN(29脚):51单片机有时候需要扩展程序存储器(ROM),为了方便目标的选取,特意安排了此引脚。当对外部存储器进行读取数据时,此引脚为低电平。当涉及程序存储器的时候,我们再来深入地讨论。图1-3 51单片机的引脚分类(5)ALE(30脚):这个引脚的作用是地址锁存信号的产生。现在提起这个概念可能比较抽象,当学习到存储器扩展时,会为大家来解答。在这里,仅需了解ALE引脚输出的是六分之一晶体频率的正脉冲波。(6)RST(9脚):复位信号输入端。就像我们的电脑需要开启或者重启一样,51单片机需要在次引脚输入两个机器周期以上的高电平来确保单片机进入正常的工作状态。有一套成熟的复位电路将在后面的章节中介绍。(7)(7脚):访问程序存储器控制信号。当为低电平时,对程序存储器(ROM)的访问限定在外部程序存储器。当为高电平时,对程序存储器的访问从内部程序存储器开始,并延续至外部存储器。(8)P0(32~39脚):8个双向I/O端口,每一个端口都是完全相同的,但是相互独立的。在实际应用过程中,P0口在很多情况下都是用做单片机的地址和数据总线的。用做外部设备的扩展,如存储器、I/O设备等。P0口和ALE引脚配合来完成外设数据的传输。不过随着串行传输技术的不断发展,P0口将会被解放出来单独作为一个普通的I/O端口。在图中我们看到,P0口有第二功能(AD0~AD7),为数据和信号共用端口。

P0口在做普通I/O端口的时候,必须外接上拉电阻才会有高电平输出。所谓上拉电阻,就是此端口通过一个电阻来连接电源。如图1-4所示为上拉电阻和下拉电阻的连接方法。图1-4 上拉电阻和下拉电阻(9)P1口(1~8脚):8个准双向通用I/O口。P1口是51单片机唯一一组只能用作普通I/O的端口。

和P0口不同,当作为输出口时,P1口不必再加上拉电阻。但作为输入时,应先向P1口寄存器写入1,才可使用。(10)P2口(21~28脚):准双向I/O口。当P0口作为地址和数据线时,P2口用于为系统提供高位地址。它和P0口配合完成外部数据的存储和访问。当然P2口也可以作为一个普通的I/O端口。(11)P3口(10~17脚):P3口是可以作为一个I/O端口的,但是它的第二功能却更加重要。我们后续讲解的内容很多都是围绕P3口的第二功能展开的。关于P3口的第二功能说明,如表1-1所示。表1-1 P3口的第二功能说明

1.1.2 51单片机的存储器

提到存储器,必须讲到存储器的分类。存储器分为ROM(程序存储器)和RAM(数据存储器)。

1. 程序存储器

ROM(Read-Only Memory,只读内存),是一种只能读出事先所存数据的固态半导体存储器。其特性是一旦储存资料就无法再将之改变或删除并且资料不会因为电源关闭而消失。通常用在不需要经常变更资料的电子或电脑系统中。

电脑所用的硬盘就是程序存取器。我们的Windows操作系统和各种应用程序都存储在硬盘之中,这些资料不会因为电脑断电而消失。但也有读者有疑问,我们的电影、音乐、照片不是都存储在硬盘之中吗?我们可以任意修改、添加和删除;还有我们电脑里面的各种应用软件,也可以灵活地安装和修改;我们的操作系统也是可以重新安装的。这和上面所提到的概念相悖吗?

这就提到了一种新型的程序存储器,即Flash存储器。它属于内存器件的一种,是一种不挥发性(Non-Volatile)内存。这种新的存储器内部的数据可以在一定的条件下,被任意的修改、删除和添加,而断电之后还可以长期保存。本书所讲的AT89C52单片机正因采用这种程序存储器,才得到如此广泛的应用。通过简单的编程器我们可以方便地将程序写入单片机之中。

在这里要记住,程序存储器就是存放程序文件的,就像Windows操作系统存放在硬盘之中一样。

2. 数据存储器

电脑的内存条采用的就是RAM(Random Access Memory,随机存储器),即存储单元的内容可按需随意取出或存入,且存取的速度与存储单元的位置无关。这种存储器在断电时将丢失其存储内容,故主要用于存储短时间使用的程序。

在编写程序的过程中,需要用到一些中间变量,来帮助实现所要求的功能。这些变量和最终要求的结果无关,但是需要它们帮助我们实现程序要求。自然而然,在用过这些变量以后,就可以释放它们,无需让它们保持一定的值。当然在断电以后,它们的存储值是无法保存的。

RAM几乎是所有访问设备中写入和读取速度最快的,它的存储速度要比ROM速度快得多。因此在单片机系统中,它的作用是不可代替的。

3. 存储器的单位

存储器的最小单位是“位”。一个位可以表示两种状态:1和0。举个简单的例子,开关的接通和断开这两种状态就可以用位来表示。如图1-5所示,当单刀双掷打到VCC,输出状态为高电平,称之为1状态。当开关打到GND这一端时,输出电平为低电平,称之为0状态。

接着来讲字节的概念。一个字节由8个位组成,如图1-6所示。在单片机系统中,甚至是计算机系统中,计数的方法通常是从0开始的。例如,每一个字节有8位,从低位往高位数的顺序是BIT0、BIT1、BIT2、BIT3、BIT4、BIT5、BIT6、BIT7,它不像平时数数是从1开始。后面章节涉及存储地址的概念也是如此,希望读者习惯这种计数的方法。图1-5 位的概念图1-6 字节的概念

一个位有两种状态,那么一个字节能表示几种状态呢?大家计算一下吧,不过肯定不是16种状态。各位数据表示的状态,如表1-2所示。表1-2 各位数据表示状态2

通过表1-2可知:2位数据表示4种状态(2=4),3位数据表示834种状态(2=8),4位数据表示16种状态(2=16),一个字节有8位数8据,当然可以表示2=256种状态了。

下面介绍存储器单位“字”,一个字由两个字节组成,那就是由1616个位组成,可以表示2=65536种状态。

4. 存储单位及数值转换

51单片机具有256字节的内部RAM。表示的地址范围为00H~0FFH(0D~255D)。在后面章节中将频繁地提到地址的概念。在单片机系统,通常将1个字节表示一个地址,从地址0至地址255,总共有256个字节。

刚刚讲到地址的表示方法为00H~0FFH,加上后缀H表示数据为十六进制,加上后缀D表示是十进制。加上B表示是二进制,在汇编语言中常用二进制表示方法。而在C语言中,常在数值前面加上0X表示十六进制数。例如0X32表示十六进制数32H。

无论是单片机系统,还是微机系统。在大多情况下,都用十六进制表示数值。后面的章节中将讲到的地址的范围都采用的是十六进制表示的方法。

至于数值转换的问题,许多书籍都介绍过计算的方法,在这里不做讲解。但向大家介绍一种最直接有效的方法,就是运用计算机。在电脑中有一个计算器的软件,里面有数值转换的功能。具体的步骤如下所述。(1)打开Windows自带的计算器软件。单击电脑桌面的“开始”菜单,会弹出图1-7所示的状态。找到“计算器”以后,可以建立一个快捷图标,方便下次使用。(2)打开这个软件,会看到如图1-8所示的界面。在这个界面,还不能进行数据转换,不过可以进行一些简单的数值运算。图1-7 Windows自带计算器的路径图1-8 计算器界面(3)单击菜单栏上的“查看”菜单,如图1-9所示,然后选择“科学型”选项,就可以跳转到科学型计算器界面,如图1-10所示。图1-9 设置科学计算器的方法图1-10 科学型计算器的界面

如图1-10所示的界面,可以看到有各种进制的点选按钮。首先单击十进制点选按钮,使其处于被选中的位置,然后输入要转换的数字,再单击要转换的进制点选按钮,就在数值框里面看到转换后的数值。

5. 传统的51单片机内部存储器配置

在本节,介绍传统的51单片机的存储器的配置。为什么是传统的51单片机呢,前面讲到,现在许多公司都在生产51系列的单片机,许多增强型的51单片机存储器容量超过了Intel公司的80C51单片机。而且各个公司的产品是有区别的。所以为了方便学习,在此介绍的是80C51单片机的存储器的容量。

80C51单片机的存储器配置为内部数据存储器(RAM)256B,内部程序存储器(ROM)4KB。另外,可以扩展的外部数据存储器(RAM)64KB,可以扩展的外部程序存储器(ROM)64KB。这个配置对于现在的数码产品来说实在是不高,如当下比较热门的手机小米2的存储器配置是内置RAM为2GB,内置ROM容量为16GB。

现在来学习更大的存储器单位“字节(Byte,缩写为B)”,1字节由8个位组成;1KB=1024B;1MB=1024KB;1GB=1024MB;1TB=1024GB。通过计算小米手机内置的ROM容量是80C51单片机的4194304倍,内置的RAM容量是80C51单片机的8388608倍。从这点来说,我们单片机的存储容量是不够大的,但对于初学者来说完全够用了。

很多人说,现在51单片机几近落伍了,新型的32位处理器,如ARM处理器、DSP处理器要比51单片机强大得多。这些32位微控制器具有很强的功能,但是不建议大家在初学阶段就去学习这类微控制器,在学好51单片机的情况下,再学习这些芯片会更容易。

80C51单片机内部的256字节的RAM分为两个部分。内部低128字节地址空间和内部高128字节地址空间。

其中,低128单元是单片机中供用户使用的数据存储器单元。它的地址范围为00H~7FH。按用途我们可以将这128字节分为3个区域,如图1-11所示。

寄存器区(00H~1FH),在图1-11中可以看到这一区域又分为4组,每组有8个寄存器,这就是汇编语言经常用的R0~R7。这4组是不可同时使用的,在同一时刻只能运用一组。到底使用哪一组由程序状态位寄存器PSW决定。寄存器区是存取效率最高的寄存器,因此我们在汇编语言中经常会用到,在C语言中,也经常用到。

位寻址区(20H~2FH),顾名思义在这个区间我们可以对于每个数据位进行操作,当然也可以进行字节操作。位寻址区共有16字节的存储容量,共有16×8=128位,我们可以灵活地使用。当用作字节变量时,可以使用它的字节地址来进行存储;但我们选用位来进行存储时,可以用它特有的位地址,如图1-12所示。

剩下的区域(30H~7FH)就是用户RAM区了。在此区域可以不受限制,可以灵活地使用。但是在一般的运用之中,我们常把堆栈开辟在此区域之中。

80C51单片机内部低128字节RAM,大部分是在我们编程的过程中当作一般变量进行使用的,因为这些变量的存储速度最快,效率很高,尤其是寄存器区的4组寄存器。图1-11 内部RAM低128个字节图1-12 位存储区各位地址

高128个字节的地址范围为80H~FFH。这是51单片机特殊寄存器存放的位置。特殊寄存器的概念就是51单片机设置的一些变量,通过修改这些变量的值,可以控制单片机的某些外设,如控制定时器、控制串口、控制I/O口等。

如图1-13所示,所有的51单片机的寄存器都放在内部数据存储器的高128个字节,包括上面提到的程序状态位寄存器PSW。图中列举除了所有的51单片机寄存器,为了查看方便,没有按照存储顺序来放置它们。我们看到了4个I/O端口的寄存器P0、P1、P2、P3,通过对这4个寄存器写入数据,可以控制I/O端口的输出状态,也可以通过读取任何I/O端口寄存器的数值,能了解当前端口的状态,这就是特殊寄存器的用途。图1-13 51单片机寄存器地址

51单片机内含有4KB的ROM,其地址为0000H~0FFFH。程序存储器就是放置代码的空间。在程序存储器中有一组特殊的保留单元0000H~002AH。在汇编语言中使用语句ORGxxxx(程序开始执行的单元)。我们一般将程序执行单元放置在002AH之后。

其中0000H~002A是系统的启动单元。因为系统复位后,程序从0000H开始执行。而0003H~002AH共40个单元被分为5段,当发生中断之时,程序就跳转到相应的地址。具体划分如表1-3所示。表1-3 各中断发生跳转ROM地址

6. 51单片机的外部存储器

编写一些小的程序,51单片机内部程序存储器(ROM)和数据存储器(RAM)是够用的,但是要做一些大的项目的话,内部存储单元,尤其是内部RAM就会显得捉襟见肘。因此,需要对存储器进行扩展。(1)外部程序存储器:在前一节学到,外部程序存储器最大可达到64KB的容量,这是由地址线决定的。大家知道51单片机有多少根地址线吗?前面讲到P0口和P2口共同作为51单片机的地址线。P0口提供低位地址,而P2口则提供了高位地址,两个端口加起来共1616个数据位,能够表示2=65536种状态,表示它可以寻址的范围为0~65535,也就是说可以找到65536个字节的地址。那么就可找到64KB=64×1024B=65536B的字节单元,也就是说51单片机最多可以扩展64KB的ROM。

还有一些引脚也是供存储器扩展的,如ALE用于提供地址数据锁存控制,PSEN用于外部程序存储器的选通,信号用于内外程序存储区的访问控制。如图1-14所示,当为低电平时,对程序存储器(ROM)的访问限定在外部存取器;当为高电平时,对程序存储器的访问从内部程序存储器开始,并延续至外部存储器。(2)外部数据存储器:51单片机外部数据存储器的扩展最大也可为64KB。如图1-15所示,和外部程序存储器一样,同样也用了16条地址线进行片外RAM的扩展,51单片机没有给特殊的选通信号引脚,但是和片内RAM比,采用的指令是不一样的。图1-14 外部程序存储器的读取方式图1-15 外部数据存储器的读取方式

随着单片机技术的不断发展,出现了许多增强型的51单片机,它们具有很大的程序存储器空间和数据存储器空间。我们做项目的时候很有可能不再需要外部扩展存储器了。

1.1.3 51单片机的时钟电路和时序

在介绍单片机引脚的时候,我们介绍到了51单片机的第18脚和第19脚为外接晶振引线端。单片机需要一个时钟信号来驱动,保证各个操作按一定的顺序完成,就像汽车需要汽油机、机械设备需要电机的驱动一样。第19脚XTAL1为时钟信号输入端;第18脚XTAL2为输出端。当然,单片机可以外接一个时钟信号,但是这样做比较麻烦。通常按照如图1-16所示的电路连接方法,外接一个晶体振荡器,同时添加两个陶瓷电容,电容值在30pF左右。图1-16 51单片机的时钟电路

图中X1表示一个晶体振荡器,单片机时钟的值就是由它的选值决定的。假设使用的振荡值为12MHZ(晶体振荡器上面有标识),那么它能产生的频率信号就为12MHZ。

单片机不能直接运用12MHZ的时钟信号,机器周期是经过晶振信号的12分频。假如用12MHz晶振的话,51单片机的时钟周期为1÷(12MHZ÷12)=1μs。如果晶振选择6MHz的话,机器周期就为2μs。

为什么要讲机器周期这个概念呢?因为在汇编语言中,每条执行程序都有固定的机器周期数。最多为2个机器周期。运用这个我们就能轻松地算出程序的执行时间,帮助我们编写出效率更高的程序。

1.1.4 51单片机的复位电路

51单片机只要供应电压,就能马上启动吗?答案是否定的。就像电脑启动的过程,51单片机需要一定的条件启动才能正常地工作。51单片机的第9脚(RST)为复位信号的输入端。当输入的复位信号延续2个机器周期以上,才能完成复位操作。假如我们的晶振选择的是12MHz,则输入高电平的时间不能低于2μs。对于我们来说,这样的时间是微不足道的,但对于单片机来说,这点时间是非常敏感的。

如图1-17和图1-18所示,提供了两种复位电路。图1-17所示为上电复位电路,一旦单片机提供上电压,就可以正常地工作。电容和电阻的取值保证复位端提供不低于2个机器周期的高电平。图1-18所示为改进版的复位电路,增加了一个按键开关,当程序执行的过程中出现了“跑飞”的状况,就像我们的电脑出现死机的情况时,按此按键就可以重新启动单片机。图1-17 上电复位电路图1-18 按键复位电路

1.1.5 增强型51单片机AT89C52的特点介绍

AT89C52是一个低电压、高性能CMOS 8位单片机,片内含8K字节的可反复擦写的Flash只读程序存储器和256字节的随机存取数据存储器(RAM)。器件采用ATMEL公司的高密度、非易失性存储技术生产,兼容标准MCS-51指令系统,片内置通用8位中央处理器和Flash存储单元,功能强大的AT89C52单片机可为用户提供许多较复杂系统控制应用场合。图1-19 AT89C52的PQFP/TQFP封装外观图1-20 AT89C52的PDIP封装外观

如图1-19和图1-20所示为我们常见的AT89C52的封装形式,和其他系列的51单片机几乎一致。通过前面的讲解我们知道,传统的80C51的内置ROM为4KB,AT89C52在这方面得到了升级,提高到8KB,而且还是可反复擦写的Flash。这使单片机的学习得到了巨大的帮助,一方面存储的容量增加了一倍,可以编写更加复杂的程序,而不用担心容量不够的问题;另外,这个可反复擦写的Flash,对于程序调试有着巨大的帮助。

传统的程序存储器的烧写方式为紫外线烧写或电烧写,程序一旦写入程序存储器中就很难再改变。另外程序的编写不可能一次就成功,需要反复地调试,才能达到预想的效果。传统的方法是用价格昂贵的仿真器进行仿真。但对于Flash存储器,我们只需要一个非常简单的编程器,就可以反复烧写程序,对于一些简单的功能程序我们不再借助于仿真器就可以调试成功。

再看图1-20所示,画圈的地方和前面讲到51单片机有所区别。那是因为AT89C52多配置了一个定时器,那就是定时器2。P1.0和P1.1在AT89C52单片机中有了第二功能。P1.0(T2)可作为定时/计数器外部脉冲输入或时钟输出端口。P1.1(T2EX)定时/计数器2捕获/重装载触发和方向控制寄存器。当然51单片机内置RAM高128字节的特殊功能寄存器会增加一部分寄存器来对应新的功能。

1.2 51单片机的程序设计语言和软件编译环境

在学习51单片机之前,大概都应该了解到了51编程的两种语言:C语言和汇编语言。现在大多数读者将中心转移至C语言上。因为C语言相对容易读懂,通用性好。但是汇编语言具有它不可代替的优点和准确的控制能力。在本书中,重点学习C语言编程的方法,对待汇编语言,依然不抛弃、不放弃。下面我们将这两种语言作比较和分析,以帮助同学们理解。

1.2.1 来看一段汇编语言吧

很多人都说汇编语言复杂,看了上面的语句,你应该怀疑这种说法。通过右侧给出的注释,我们知道这段程序的功能是让51单片机的各个I/O口输出不同的数值。需要注意的是,如果要给所编写的程序加注释的话,别忘了在注释前面加分号“;”,否则,在程序编译过程中会报错。

通过上面一段小程序能看出编写程序的一般流程。涉及的具体语言的格式,我们将在后面的章节详细介绍。

1.2.2 看看更容易理解的C语言吧

这段C语言程序和上面的汇编语言实现的功能是一样的。不管你是否学过C语言,通过注释,都能够理解这段程序所表达的意思。

上述的C语言程序和汇编程序是在Keil环境下编写的。C语言的第一行#include<AT89X52.H>,是ATEML单片机的库文件,是在Keil软件中包含的,里面声明了AT89C52单片机的寄存器信息,不需要我们自己编写。main是C语言主程序的标志,也是程序开始执行的地方。

P0、P1、P2和P3都是51单片机的特有寄存器,在库文件里面得到了声明。在C语言中,如果是51特有的寄存器,必须用大写字母,汇编语言则没有这方面的要求。

再来复习一下十六进制数的表示方法。在汇编语言中常在数字后面加上H来表示十六进制数,而在C语言中,是在数字前面加0X来表示。

C语言加注释的方法和汇编语言是不同的。在C语言中,一般在注释之前加上“//”,或“/*注释的内容*/”。每一条完整的C语句后面必须加分号“;”。

1.2.3 两种程序编程语言的关系及相互的优缺点

前两节内容我们介绍了分别用C语言和汇编语言编写的功能相同的程序。下面我们将这两段程序来做一下比较:

这两段程序除了表达形式的不同之外,最主要的区别在于程序的第一行。汇编语言在程序的开端有一句“org 0000h”,表示程序是从程序存储器的0000H地址开始的。而C语言则没有限定程序开始执行的地址,其实不是没有,是Keil为我们做好了,我们没有办法去决定。

另外,在讲到单片机时序的时候,每条汇编程序都有固定的机器周期,在本书的附录A中有列举了每一条汇编语言的执行时间的表格,可以通过这个表格来了解汇编语言程序执行的时间。通过技巧的编写,我们可以将程序的时间控制在毫秒级,甚至微秒级。而C语言是不可能做到这一点的。

通过这两点的比较,我们了解到汇编语言的优势。一是和硬件系统、存储结构紧密联系,二是执行的时间是绝对精确的,另外汇编语言因为直接关联硬件,所以执行效率特别高。在一些要求精密控制的场合,汇编语言绝对是编程的主力。

相对来说,学习C语言是比较简单的。我国大多数高校都开设了C语言这门课程。实际上,C51(C语言在51上的实现)比高校开的普通C语言课程要简单。

C语言的运用是非常广泛的。不管是软件平台(如Windows系统),还是我们的手机操作系统Android,甚至其他硬件平台(如ARM、FPGA、DSP的应用开发),C语言绝对是不二选择。只需要学一种语言就可以进入到这么多的领域,是多么合算的一件事。几乎每一个硬件平台,都有自己的一套汇编语言。就算同为8位单片机的51单片机、AVR单片机、PIC单片机之间的汇编语言也是有很大的差异。而C语言可以在诸多平台之间相互移植。

另外,在互联网上有许多用C语言编写的子程序供我们调用,可以加快程序开发的过程。这一点也是汇编语言无法比拟的优势。

在学习初期,C语言和汇编语言的区别相对较小。因此在本书中,这两种语言我们同时给予讲述。希望读者能有所侧重,争取同时掌握这两种语言。

1.2.4 51单片机的编译开发环境介绍

51单片机的编译开发环境有很多。像国外著名的Keil和国产的WAVE等。我们在本书着重介绍Keil开发环境,这是我们本章学习的重点。

Keil C51是美国Keil Software公司出品的51系列兼容单片机C语言软件开发系统,当然汇编语言也可以使用。Keil提供了包括C编译器、宏汇编、连接器、库管理和一个功能强大的仿真调试器等在内图1-21 Keil uVision4图标的完整开发方案,通过一个集成开发环境(uVision)将这些部分组合在一起。运行Keil软件需要Windows 98、Windows NT、Windows 2000、Windows XP、Windows 7、Windows 8等操作系统。如果你使用的是C语言编程,那么Keil是最佳选择,即使使用汇编语言编程,其方便易用的集成环境、强大的软件仿真调试工具也会令你事半功倍。图1-21所示为Keil uVision4的图标。

免费测试版可在Keil官方网站www.Keil.com下载,最新版本是V9.50,虽然有2KB代码的限制,但是足够初学者来用。随书附带的光盘里面有一个Keil的安装文件,是从Keil公司官方网站下载的2KB代码限制版。

1.3 51单片机开发环境Keil的介绍

Keil uVision4是众多单片机应用开发软件中优秀的软件之一。它支持众多不同公司的MCS51架构的芯片,它集编辑、编译、仿真等于一体,同时还支持PLM、汇编和C语言的程序设计,它的界面和常用的VC++的界面相似,界面友好,易学易用,在调试程序、软件仿真方面也有很强大的功能。因此,很多开发51应用的工程师和单片机爱好者都视它为首要选择。

1.3.1 Keil开发环境的介绍

Keil的安装是比较简单的,在本书附带的光盘中有个Keil的安装文件夹,这是在官方网站http://www.Keil.com下载的限制版,因为Keil并不是免费的,这个限制版的编译的程序最大不能超过2KB。

Keil安装的过程很简单,只需单击安装文件,一直单击“下一步”按钮就可以完成安装。图1-22所示为Keil打开后的界面。

现在介绍一个例子来帮读者更好地图1-22 Keil的版本介绍认识Keil编译程序的过程。打开图标,映入眼帘就是图1-22的所示的内容,这是Keil的版本介绍。在这个图中我们了解到,Keil现为ARM公司的一个产品。

然后会跳转到图1-23所示的界面,这就是Keil编程环境的界面,我们所有的工作都在这个界面下展开。图1-23 Keil的界面

1.3.2 项目建立的方法

下面就正式开始介绍在Keil环境下建立项目的方法。(1)单击Project菜单,在弹出的下拉式菜单中选择New μVison Project,如图1-24所示。我们将要建立一个项目,这是程序编译的一般流程,大多数程序编译器采取项目管理的方式,比如VC、VB或者其他单片机的编译环境。

接着弹出一个项目保存的对话框,如图1-25所示。在“文件名”文本中输入项目名称,这里我们用test,然后找到我们要保存项目的路径。在建立项目之前,在保存项目的路径下建立一个文件夹,用于保存项目。最后单击“保存”按钮,就完成了对项目的保存。图1-24 建立项目菜单图1-25 建立项目菜单(2)接下来弹出如图1-26所示的对话框,让我们选择要用到哪种型号的单片机。51单片机有诸多型号系列供选择。本书选用的是ATMEL公司的AT89C52,所以先找到ATMEL的列表,如图1-27所示,再找到AT89C52这个型号。Keil公司做的非常全面,对每款单片机都编出了启动代码,让我们尽可能地简化设计过程。完成了相应的选择之后,将弹出如图1-28所示的对话框。然后单击“是”按钮,表示添加启动代码到我们所建的项目之中。

谈到启动代码,在这里顺便提一下,因为C语言和硬件没有直接联系,所以需要一段代码的牵线搭桥帮助C语言控制单片机。这段代码当然是用汇编语言编写的,所以要强调一下学习汇编语言的重要性。启动代码一般是Keil给我们提供,现阶段不必去考虑它的含义,我们仅需要将其添加到项目之中即可。

如果我们用到了一款单片机,如现在国内比较流行的宏晶单片机,但是在图1-26所示的列表中找不到它怎么办呢?不必着急,我们也可以用其他公司的其他型号的单片机代替。因为它们采用的都是51单片机内核,差异并不大。图1-26 Keil支持的单片机公司列表图1-27 ATEML公司单片机列表图1-28 选择是否添加启动文件到项目中

这样项目就完成了,大家可以看项目栏左侧是否有文件STARTUP.A51,这就是我们这个项目的启动文件。接下来我们要在这个项目里面添加文件了。(3)创建一个新的文件。如图1-29所示为两种新建文件的方法,都是比较简单的,我们任意选用一种就可以了。图1-29 新建文件的两种方法(4)在创建的区域内编写程序代码,编写的程序是1.2.2节介绍的C语言代码。可以将程序直接输入,也可以灵活地复制、粘贴,如图1-30所示。图1-30 在编辑区内输入程序(5)完成程序的编辑之后,要对程序进行保存,直接单击“保存”按钮即可,如图1-30所示。也可以在刚新建完文件的时候,就保存它。(6)单击完“保存”按钮之后,会弹出图1-31所示的对话框,这是要完成对程序文件保存的选项。在默认情况下,文件是保存在项目文件的根目录下。在图中,test.uvproj表示项目文件。将要保存的文件名,命名为test.c。文件名前面的test可以任意选取,但是.c表示所选用的是C语言文件格式,所以必须添加这个后缀。如果这里添加的是汇编文件的话,那后缀名必须改为a或.asm,这是所有单片机编译器的规则。选择完保存格式后,单击图1-31中的“保存”按钮就可了。(7)还需要将刚刚保存的文件添加到项目中去,如图1-32所示。选择Add Files to Group to “Source Group1”选项弹出如图1-33所示的对话框。选中我们刚刚创建的c文件,并单击Add按钮,这样就将程序文件添加到项目中去了。如果是汇编文件的话,也是同样的添加方法。也可以不在Keil环境下编辑c文件,直接在记事本里面编辑文件,保存为c格式或asm格式。图1-31 程序文件的保存图1-32 项目文件的添加1图1-33 项目文件的添加2

这样我们的项目就完成了。这个项目可以正常的编译和仿真。

1.4 51单片机学习的利器——仿真软件Proteus

传统的单片机实验过程都是通过Keil或其他的单片机开发软件把源代码编译为HEX或BIN等程序文件,然后用编程器把程序文件烧写入单片机中;再将单片机插入实验板中,才能看到软件的执行结果。对于一个单片机初学者来说,这样不仅非常麻烦,而且必须配置一套编程器和实验板,这样的花费不是一个小数目。如此一来,使很多想学单片机,但又不想花太多钱的爱好者望而止步。

幸运的是,有一款软件提供了一个平台,我们可以在这个平台上搭建电路,既不需要手动的焊接,也不需要额外投资购买元件。对于初学者来说,这款软件会给我们的学习带来很大的便利。下面就来介绍这个软件——Proteus。

1.4.1 Proteus简介

Proteus是英国Labcenter electronics公司开发的EDA工具软件。它不仅具有其他EDA工具软件的仿真功能,还能仿真单片机及外围器件,是目前最好的仿真单片机的工具。Proteus是目前世界上图1-34 Proteus图标唯一将电路仿真软件、PCB设计软件和虚拟模型仿真软件三合一的设计平台,其处理器模型支持8051、HC11、PIC10/12/16/18/24/30、AVR、ARM、8086和MSP430等,2010年又增加了Cortex和DSP系列处理器,它的模型库还在持续增加其他系列的处理器模型。在编译方面,它也支持IAR、Keil和MPLAB等多种编译器。如图1-34所示为Proteus的图标。

同样,在Proteus官方网站http://www.labcenter.com能够下载限制版本的Proteus。限制版Proteus是不能保存文件的。在随书配带的光盘中,有一个Proteus7.10的软件包,用户可以安装一下。软件的安装方法比较简单的,我们还专门录制了一个视屏教程在光盘里面,希望读者可以看一下。(1)打开软件,会出现如图1-35所示的界面,这是软件的版本介绍。图1-35 Proteus自述界面(2)经过短暂的加载就进入了如图1-36所示的界面。和大多数应用软件一样,Protesus大致分为工具栏、菜单栏、编辑区、预置元件区和预览区。(3)学会在Proteus中寻找元件的方法。如图1-37所示,可按照图中的操作步骤进行操作。首先单击右侧工具栏中的“运放”符号,再单击预选元件区的按钮P,出现元件搜索对话框。在步骤3所示的对话框中输入要寻找的元件名称。这个元件的名称,可以是一个模糊的值,也可以是它的关键字。(4)假设要寻找一个100欧姆的电阻,直接在“关键字”的搜索框输入100,如图1-38所示。则在右边的搜索结果框中出现与100相关的选项。单击左侧的导航栏中的Resistors(电阻)选项,可以筛选出相关的元件。然后到右面的搜索结果中寻找需要的元件,然后单击“确定”按钮。图1-36 Proteus编辑界面图1-37 Proteus寻找元件的方法图1-38 在Proteus中寻找电阻的方法(5)同理,如果要找一个47pF的电容,在搜索框中输入47p,如图1-39所示。然后单击左侧的导航栏中的Capacitors(电容),在右侧的搜索结果中找到需要的元件,最后单击“确定”按钮。图1-39 在Proteus中寻找电容器的方法(6)接下来要找到一个集成元件。假设找一个常用的74138(3-8译码器),如图1-40所示。可以看到左侧的导航栏中有各种74系列的选项,从这一点可以看出Proteus元件的全面性。选择74LS138,然后单击“确定”按钮,就可以选定该元件。图1-40 在Proteus中寻找集成元件的方法(7)如果要寻找一个NPN型的三极管,它的型号是2N5769,如图1-41所示。直接在搜索框中输入2n,再在导航栏中单击Transistors(三极管)选项,在显示结果中找到所需元件,然后单击“确定”按钮即可。图1-41 在Proteus寻找集成三极管的方法(8)接下来该寻找51单片机了,如图1-42所示。直接在搜索框中输入8051,再单击Micriporcesor ICs(微控制芯片)选项,可以看到很多51单片机系列,直接找到AT89C52,然后单击“确定”按钮。Proteus中容纳的元件非常多,怎样从一个庞大的元件库中找到所需的元件,得靠大量的练习。左边的导航是元件系列的英文名称,大家可以利用翻译工具软件配合查寻。图1-42 在Proteus寻找51单片机的方法(9)完成了对元件的选择后,需要将元件放置在编辑区并绘制电路图,如图1-43所示。左侧的元件预置栏为我们找到的元件。选中任意一个元件名,在编辑区内单击鼠标就可以放置该元件了。假如我们要放置三极管2n4769,可以单击左侧元件预置区的2n4769,再将鼠标移动到编辑区单击一下就完成了元件的放置,连续地单击将放置相同的元件。

怎样移动我们放置在编辑区内的元件呢?可以单击一个元件,此元件将会变成红色,表示该元件已被选中,然后拖动鼠标,这时可以看到元件同样也在移动,到达指定的地方后停止拖动鼠标,就完成了元件的移动。(10)该怎样建立两个元件的电气连接呢?首先,在当前状态下,保证没有选定任意一个元件。然后用鼠标靠近要连接的元件管脚,如果距离足够近的话,此管脚的状态将会出现一个红色的小框,单击鼠标左键拖曳,我们可以看到一条引线被拉出,然后找到另外一个需要连接的引脚,当同样出现红色小框状态时,单击即可完成两个引脚连接,如图1-44所示。图1-43 将选定的元件放入编辑区内图1-44 建立两个元件之间的电气连接(11)接下来该介绍电源和信号地了。电源和信号地并不能通过上述元件查找的方法去寻找,需要按照如图1-45所示的步骤来寻找。单击步骤1所指向的符号,可以看到元件预置栏出现几个选项。单击POWER(电源)选项,然后在编辑区内单击鼠标,即可放置这个符号,和普通元件的放置方法是一样的。Proteus的电源和我们常用的元件符号是有区别的,这个电源提供的电压值为5V。以后会经常用到这个电源符号,所以大家必须记住这个符号。

同样,信号地也是在这个选项框中,如图1-46所示。可以单击GROUND(地)选项完成放置信号地,信号地还是比较直观的。图1-45 Proteus中电源的位置图1-46 Proteus中信号地的位置(12)假设要对一个元件进行修改,例如修改它的项目代号及它的值。该怎么操作呢?可以双击添加在编辑区的电阻,打开它的属性对话框,如图1-47所示。在这个对话框里面,可以看到该元件的项目代号、阻值等选项,这些值都是可以修改的。对于不同的元件有不同的属性,随着我们学习的深入,大家就会慢慢看到。(13)如果想对一个元件进行删除、旋转,该如何操作呢?当鼠标靠近元件的时候,该元件就会被一个红色小框围绕,此时右击即可出现如图1-48所示的效果。可以看到图中所示的元件操作选项。另外,有一个比较常用的删除快捷快捷操作,就是靠近要删除的元件双击鼠标右键即可。图1-47 电阻属性对话框图1-48 元件操作选项

1.4.2 用Proteus建立一个51单片机最小系统的电路图

在这一节来完成一个单片机最小系统的电路图的绘制。在本章的第一节,我们了解到要使51单片机正常工作,就必须有复位电路和时钟电路。所以最小系统必须添加上这些电路。接下来就依次来添加这两个电路。(1)涉及时钟电路,自然需要时钟源了,所以我们需要找到晶体振荡器。按照如图1-49所示的方法找到搜索框,然后在搜索框中,输入关键字cry,在micellaneous库中找到元件晶体振荡器crystal(晶体),如图1-50所示。图1-49 找到元件搜索框图1-50 寻找晶体振荡器(2)上电复位需要一个按键来完成,还是按照如图1-49所示的方法找到搜索框,在搜索框中输入button,如图1-51所示。在witches&Relays(开关和继电器)库中就可以找到开关BUTTON了。图1-51 按键的寻找方法(3)找到需要的元件后,按照如图1-52所示的连接方式,就可完成51单片机的最小系统的连接。从图1-52中可以看到,51单片机管脚不是40脚,它只有38个引脚,少了第20脚和第40脚。我们知道单片机的第20脚为单片机的接地脚,第40脚为单片机的电源接入点。难道是Proteus失误没有设计这两个引脚吗?不是的,因为这两个引脚都是Proteus隐藏的。也就是在运行仿真时,软件自动给我们接地和电源。不仅是单片机,Proteus中所有的集成电路的接地引脚和电源引脚都是软件自动连接的,这样可以减小我们的工作量。图1-52 单片机的最小系统

双击51单片机,出现如图1-53所示的“编辑元件”对话框。从图中可以看到51单片机的Clock Frequency(时钟频率)这个选项,这个选项是确定单片机的时钟的,在Proteus中可以不用添加时钟电路甚至复位电路。

Proteus考虑得很全面,尽量简化设计过程。我们不需要添加时钟电路和复位电路,为什么又要求大家刻意画呢?这是想让大家养成良好的习惯,上图所画的51单片机最小系统完全可以运用到实际项目之中。同时也希望读者明白仿真不能完全代替实际的电路,所以不仅要将仿真做好,还应该做些实际电路。图1-53 “编辑元件”对话框

1.5 通过一个小实例了解51单片机开发

本节,将通过一个实例来介绍51单片机项目开发的过程。

1.5.1 在Keil中编译一段程序

在做一个项目之前,首先要确定该项目要实现的功能,然后根据功能来编写程序。在前面介绍过一段程序,此处直接来运用这段程序吧。(1)在1.3我们建立了一个Keil项目,现在就来验证一下此程序的功能是否正确。找到项目的文件夹,打开这个项目,如图1-54所示。如果项目丢失的话,可以再新建一个项目,如图1-55所示为打开项目的视图。图1-54 Keil项目所在的位置图1-55 Keil项目打开后的视图(2)编译这个项目,查看是否有错误。操作顺序如图1-56所示。第1步(快捷键为Ctrl+F7)为编译当前文件,第2步(快捷键为F7)为编译整个项目,第3步是重新对项目进行编译。图1-56 程序编译的方法(3)一般情况下,此时会在Keil下方出现如图1-57所示的输出信息,这是程序编译结果输出。这个输出内容框里可以看到程序的编译是否出错,如果编译程序的时候出现错误或者警告,请仔细检测程序里面是否有不合理的地方。图1-57 程序编译结果输出(4)经过编译证明了程序是没有问题的。如何将输出代码烧录到单片机程序寄存器之中呢?可以按照图1-58所示的步骤进行操作。(5)这时会出现一个对话框,如图1-59所示,然后按照图中的步骤进行操作。步骤2所指的为Create HEX File,译为中文为生成HEX文件。HEX文件是烧写到单片机里面的程序文件,这就是所谓的机器码,在没有开发出汇编语言和高级语言之前,科学家就是直接编写这种代码来控制计算机的。图1-58 设置输出执行文件1图1-59 设置输出执行文件2(6)我们按照如图1-56所示的步骤对程序再做一次编译,观察程序编译结果输出,如图1-60所示。可以将此图和图图1-60 编译结果输出21-57比较一下,看看它们的内容有什么不同。如图1-60所示,图中框选的部分creating hex file from test,表示程序已编译生成了机器码。(7)我们可以看一下生成机器码的庐山真面目。打开我们建立的项目所在的文件夹,找到文件test.hex,如图1-61所示,这就是可烧写进单片机的程序文件。图1-61 机器码在项目中的位置(8)如图1-62所示的机器码,是用记事本软件直接打开的。我们不必读懂它,这是毫无意义的。图1-62 机器码的内容

1.5.2 在Proteus中演示程序

若想验证程序执行的效果,最好的方法是在查看电路图。既然有了Proteus这个软件,就不需要再去焊接实际的硬件电路。编译程序的功能,是让各个I/O端口输出不同的值,最好的验证方法就是用小灯了。如图1-63所示给出了电路图,希望读者耐心完成这个电路图的绘制,图中的电阻选择100欧姆的就可以了。图1-63 验证程序的电路图(1)在图1-64中列举了小灯的寻找方法,我们用的小灯是LED小灯,所以在搜索框中输入LED,然后在元件类别Optoelectronics(光电子)中寻找,里面有很多小灯,可随便挑选一个。图1-64 LED小灯的寻找方法(2)按照图1-64所示完成电路的连接,打开“编辑元件”对话框,如图1-65所示,然后给单片机添加程序文件。单击图1-65中椭圆圈起来的文件夹图标,跳转到如图1-66所示的“选择文件名”框,找到我们上一小节Keil项目下的文件test.hex的路径,然后单击“确定”按钮。这样就完成了程序文件的添加,相当于在实际电路中将程序烧写进单片机中,但是过程要比实际电路简单得多。图1-65 “编辑元件”对话框图1-66 “选择文件名”对话框(3)最激动人心的时刻到了。回到Proteus界面,如图1-67所示,单击开始仿真按钮,就可看到最终的仿真效果了。图1-67 开始仿真界面

仔细观察仿真效果是不是如程序所描述的那样:P0口所有的灯都不亮;P1口的灯一半亮,一半不亮,其中P1.0~P1.3亮,P1.4~P1.7不亮;P2口的灯也是一半亮,一半不亮,不过和P1口正好相反,其中P2.0~P2.3不亮,P2.4~P2.7亮;P3口的灯全亮。

实际证明,最终的仿真效果是完全符合我们的程序要求的。为了加深理解,希望读者好好地练习,并用汇编语言做一下测试。

1.6 习题及操作练习

1. 填空题(1)AT89C52单片机共有引脚__________多少根;其中接地端为第__________引脚,接电源端为第__________引脚。(2)存储器分为__________和__________,其中__________存放的数据,断电后消失。(3)一个字节由__________位组成,一个字节可以表示__________种状态。(4)传统51单片机唯一只能作为普通I/O口的端口为__________。(5)十进制数据56,用十六进制可以表达为__________,用二进制可表达为__________。(要求写出进制后缀)。(6)内部RAM低128单元的位寻址区地址范围为__________。(7)特殊功能寄存器P0在内部RAM的地址为__________;P1的地址为__________;P2的地址为__________;P3的地址为__________。(8)传统8051单片机内部RAM有__________字节;内部ROM有__________字节。(9)AT89C52单片机内部ROM的容量为__________;采用的存储技术为__________。

2. 选择题(1)单片机的执行程序存放在__________,中间运算数据存放在__________。

a)RAM

b)ROM

c)寄存器

d)CPU(2)51系列单片机是__________位单片机。

a)4

b)6

c)8

d)16(3)单片机复位端接入__________晶振周期的高电平,才能触发复位。

a)1

b)2

c)4

d)6(4)端口ALE输出__________晶振频率的正脉冲波。

a)二分之一

b)四分之一

c)八分之一

d)六分之一(5)P3端口__________为外设读控制信号;__________为外设写选通信号。

a)P3.1

b)P3.2

c)P3.6

d)P3.7(6)51单片机共有__________根地址线;__________根数据线。

a)4

b)8

c)12

d)16

3. 解答题(1)叙述P3口的第二功能。(2)列出存储器各个单位,并给出其对应关系。(3)试分析为什么单片机最大可扩展64KB ROM和RAM。(4)假设51单片机使用了6MHz晶振,计算出晶振周期、机器周期和ALE引脚输出信号周期。

4. 实例练习(1)在Proteus中寻找100Ω的电阻、47pF的电容、三极管2N5769、2N5771,以及逻辑芯片74HC04、74HC163。(2)重新绘制单片机最小系统。(3)试绘制电路图,如图1-68所示。图1-68 电路图(4)在Keil中新建一个汇编语言项目,使用本章中给出的汇编代码对该项目进行编译,并设置输出可执行代码。

第2章 从I/O端口开始学51单片机

学习51单片机的序幕就从I/O端口开始展开。为了提高大家的学习兴趣,将给大家演示一个非常漂亮的流水灯,这个流水灯是用51单片机的I/O端口来驱动的。本章将详细讲解程序语言,会更深入地学习Proteus绘制电路图的方法,并介绍一些软件方面应该注意的知识。希望读者除了努力学习之外,还应该多多地练习。

2.1 从一个漂亮的流水灯看I/O端口

很多书籍介绍单片机的知识都是从一个流水灯开始的,本书也不例外。本节的任务就是对流水灯的硬件电路做出阐述,详细讲解如何在Proteus软件中绘制一个流水灯,以及51单片机I/O端口的内部结构。本节将提出程序设计的方案,完成程序流程图的绘制,为下一节的程序编写做准备。

2.1.1 演示流水灯实例

(1)在本书的光盘里,包含了一个已经完成的项目。我们假设把光盘里所有的内容复制在电脑桌面上,这个流水灯和程序的路径如图2-1所示。图2-1 流水灯实例所在的位置(2)打开如图2-1所示的“流水灯.DSN”文件。要保证在我们的电脑里面已经安装了Proteus软件,否则这个文件是打不开的。打开文件后,效果如图2-2所示。图2-2 流水灯电路图(3)给单片机添加可执行程序文件,双击51单片机,就会弹出“编辑元件”对话框,如图2-3所示。我们来为51单片机添加程序文件,已经在第1章介绍了程序文件添加的方法,单击图中框选的文件夹图标,就会打开如图2-4所示的“选择文件名”对话框。图2-3 “编辑元件”对话框(4)图2-4所示为程序选择路径。单击同一目录下的“流水灯C语言项目”文件夹,打开就可显示一个程序文件。这个项目是为了方便大家参考而提前建立的一个C程序Keil项目。同样,也可打开同一目录下的“流水灯汇编语言项目”文件夹,找到相同的程序文件,这是提前建立的一个汇编项目文件夹。图2-4 “选择文件名”对话框(5)现在可以演示仿真了。如图2-5所示,单击图中的仿真开始按钮就可以开始仿真,如果想停止仿真的话,单击最右侧的仿真停止按钮即可。图2-5 执行仿真的效果(6)查看仿真信息。开始仿真后,各个器件包括单片机的引脚都有电平的变化,我们可以清楚地看到仿真的效果,还会出现如图2-6所示的仿真信息。图2-6 正确的仿真信息(7)如果仿真失败,则会自动弹出如图2-7所示的仿真信息。一般情况下,出现错误的原因是我们没有给51单片机添加程序文件。图2-7 错误的仿真信息

2.1.2 流水灯电路图的绘制

第1章已经介绍了Proteus的基本用法,并绘制了单片机的I/O端口驱动小灯的实例,但是在图2-2中,我们看到了用总线方式绘制的流水灯,是不是感觉特别的简洁?在本节,除了教会大家绘制总线的方法,同时也补充一点Proteus绘图的小技巧。(1)打开Proteus软件,会出现如图2-8所示的界面。系统给了我们一个选择,单击“取消”按钮,Proteus系统就会默认新建一个空白的文件;单击“确定”按钮,就会演示系统创建的一系列有趣的实例文件。图2-8 是否选择打开系统自带的实例文件(2)在图2-8中单击“确定”按钮,就会出现如图2-9所示的文件选择对话框,Proteus包含一个实例文件夹,这个文件夹的名称叫SAMPLES。这个文件夹在Proteus安装文件的根目录下。

在这个文件夹里面,Proteus给我们提供了很多实例,不仅有单片机方面的,还有模拟电路和数字电路方面的。不仅有8051单片机,还有非常流行的AVR单片机、PIC单片机、微机8086,甚至是32位处理器ARM和DSP等。图2-9 Proteus提供的实例(3)打开这个文件夹后,可以看到有多个51单片机演示实例,打开文件夹8051 Calculator,如图2-10所示,这是一个计算器仿真实例,当然读者也可以打开其他实例来看一看。图2-10 计算器实例的路径(4)打开这个文件夹目录下的Proteus文件,可以看到如图2-11所示的效果图,一个非常华丽的界面,这就是用51单片机制作的计算器电路图。这个图对于初学者来说还是比较复杂的,可以单击开始仿真按钮,看一下这个计算器的仿真效果如何。

这个计算器是比较复杂的,因为它涉及了51单片机很多方面的知识。本书的后半部分,将详细介绍怎样设计一个计算器,想把这个项目完成,必须打好基础,认真地仿真每个章节提供的内容,多学多用,不能好高骛远。图2-11 计算器的仿真电路图(5)言归正传,我们还是得去绘制一个流水灯。打开Proteus的时候,出现如图2-8所示的界面,单击“取消”按钮,就会新建一个空白的Proteus文件,如图2-12所示。绘图的过程中一定要及时保存,这样才能很好地保护我们的劳动成果。

另外补充一点,在图2-12中,标示了预览视图的位置。预览视图可以对在编译框中所有的器件做一个小的预览。左击预览视图,拖曳鼠标,可以定位到编辑区的任何位置;定位结束,再一次左击鼠标则会退出。图2-12 Proteus新建文件的界面

现在开始绘制流水灯电路图,步骤如下所述。(1)还记得第1章学过Proteus查找组件的方法吧,如果忘了,可以返回第1章好好地复习一下吧。找到如图2-13所示的组件列表,如图2-14所示为各个元件放置的位置。图2-13 绘制流水灯所需元件列表图2-14 流水灯各个元件摆放的位置(2)先绘制一段总线,通俗来说就是一条线缆,里面包含多根线。绘制总线的按钮如图2-15所示,先单击总线按钮,回到编辑区内,然后单击一下鼠标开始绘制,绘制完毕后再次单击鼠标左键停止绘制,绘制效果如图2-16所示。图2-15 总线按钮位置图2-16 绘制总线的效果(3)绘制完总线之后,还要完成普通导线和总线的接口,如图2-17所示。绘制接口线和普通导线的方法是一样的。首先鼠标靠近引脚P1.0时会出现一个红色的小框,单击鼠标左键会引出一条导线,这时拖曳鼠标到达总线上,然后单击鼠标左键就会连接上。按照此方法将P1口的其他线一一连接到总线上,如图2-18所示。图2-17 总线接口图2-18 P1全部连接到总线上

我们来看一下计算器实例给出的总线连接方法,如图2-19所示。图中它的总线接口都是用的折线,这是绘制总线的规矩。图2-18中的电路图是可以用于仿真的,但是还想让总线画得更完美,就要学会绘制折线。图2-19 绘制总线的标准方法(4)怎样画出折线的效果呢?很简单,当引出导线的时候,按住Ctrl键,不要松开,同时拖曳线,就会发现导线可以画成任意的角度,如图2-20所示。下面我们来画标准的总线吧。如图2-21所示,先引出一条线,到达需要转折的位置的时候,先单击一下鼠标,再按Ctrl键接到总线上,这样就完成了总线接口的绘制。图2-20 任意角度导线的绘制图2-21 一个总线接口的绘制方法(5)分别完成P1口总线和发光二极管接口的总线的连接,如图2-22和图2-23所示。图2-22 P1口和总线的连接图2-23 LED灯和总线的连接(6)总线绘制还没有结束,还需要添加网络标号。如果不用总线的方法,而是直接连线的话,绘制的效果如图2-24所示。在图中,P1.0和小灯D1相连,在总线中如何表示这两个引脚相互连接呢?其实给它们取同样的标号就可以了。图2-24 直接连线的方法绘制流水灯电路(7)添加网络标号的方法如图2-25所示,在左侧的工具栏中,单击LBL按钮,放置在图中标定的位置,再单击鼠标,就会自动弹出如图2-25所示的对话框。在对话框里面输入网络标号,然后单击“确定”按钮即可。图2-25 网络标号的添加方法(8)这样就完成了给P1.0添加网络标号,如图2-26所示。然后在发光二极管D1和总线的连接处,添加相同的网络标号,如图2-27所示。图2-26 给P1.0添加网络标号图2-27 给D1添加网络标号(9)如图2-28和图2-29所示,给P1口的其他端口和发光二极管添加网络标号。注意一一对应的关系,如果关系不对应的话,程序执行就会出错。图2-28 给P1口添加网络编号图2-29 给所有的发光二极管添加网络标号(10)完成其他组件的连接,就完成了流水灯电路,如图2-30所示。图2-30 完成了流水灯电路

2.1.3 P1端口介绍

流水灯电路是将P1口作为一个驱动输出端口,如图2-31所示。传统的80C51单片机中,P1口只能用作普通的I/O端口,这正是我们选用它目的,因为P0、P2、P3都有重要的第二功能。虽然AT89C52将P1.0、P1.1作为定时器2的复用输入端口,在这里先不考虑这一点。图2-31为P1口每个端口的电路逻辑图,当然还是按照80C51单片机来绘制的,没有体现出P1.0、P1.1的第二功能。电路逻辑主要是由一个D触发器构成,大家可以看一下能否理解这个图,不能理解也没有关系,了解即可,在这里不做详细的介绍。

大家都知道单片机属于数字电路的范畴。虽然也会涉及一些模拟电路,但总体来说,单片机处理的数据都是数字量。谈到数字电路,只有两种状态:0和1,单片机所有端口输出的状态当然也只有这两种。那么流水灯电路是否可以简化为如图2-32所示的形式呢?图2-31 P1口内部逻辑结构图2-32 流水灯简化电路

当开关拨动到电源这一端时,端口输出高电平,不能形成电位差,所以没有电流通过,LED小灯是不会亮的;当开关打到地这一端时,端口输出低电平,形成了电位差,所以LED小灯就可以亮了。我们在这里先提出一个疑问;到底谁来控制开关的拨动呢?

一个字节是由8个位构成,每个位有两种状态。图中拨动开关的控制是由一个字节变量来完成的,我们将这个字节变量称之为寄存器。在第1章讲数据存储器时,谈到高128字节的RAM的时候,提到过寄存器的概念,高128字节的存储器配置如表2-1所示。表2-1 内部RAM高128字节

在表中,我们看到了P1口锁存器,它在高128字节RAM的地址为90H,它就是控制图2-32开关的“幕后黑手”,而这个寄存器的值,是由我们写入的,所以我们才是控制单片机I/O端口的真正主人。其他端口P0、P2、P3的控制方法也是如此。

在程序编写的过程中,可以直接将值写入到P1,也可以将值写入到P1的地址90H,在编程的时候我们会着重介绍。

2.1.4 流水灯程序设计流程图

谈到流程图,许多读者认为在做一个大项目的时候才需要,一个小的程序是不需要专门绘制流程图的。其实在初学阶段,画好流程图能帮助我们整理好程序设计的脉络,让程序变得有条理。在编程的时候,流程图像一个指路明灯引领着程序的走向,所以应该养成良好的习惯,在编写程序之前,绘制一份流程图。

流程图的绘制方法很简单,一些编程类书籍有过专门的介绍,在本书就不再讲述了。怎样才能达到我们演示的流水灯的效果,就是让P1端口在间隔一段时间后,输出不同的值?假设我们想要的效果是某一时刻,只有一个LED小灯亮,而间隔的时间是一秒,则小灯执行的流程如图2-33所示。图2-33 流水灯执行的流程图

如图2-34所示,当I/O端口输出高电平的时候,LED小灯是不亮的,当I/O端口输出低电平的时候,LED小灯才亮。如图2-35所示,P1的值用十六进制可以表示为FEH,因为四位二进制数可以表示一位十六进制数。图2-34 LED小灯的布局图2-35 端口的状态转换为16进制数

根据图2-35所示的转换方法,我们得出在不同LED小灯被点亮的时候,P1端口输出的状态,如表2-2所示。表2-2 各LED灯对应P1口输出值

程序的流程图如图2-36所示。程序流程图还是比较简单的,P1口在间隔一段时间之后,输出不同的值,然后返回到程序执行的起点,重新开始执行,这样就会循环往复不断地出现流水的效果。图2-36 流水灯的程序流程图

2.2 用汇编语言实现流水灯

本节将用汇编语言来实现流水灯的功能。上一节完成了硬件电路的绘制,并提出了流水灯的程序设计方案,画出了流程图,这为程序编写打下了基础。用汇编语言来实现流水灯会更加简单。当然从本节开始也会介绍汇编语言的语法。

2.2.1 用汇编语言小试牛刀

根据如图2-37所示的流程,逐条写出汇编程序。图2-37 根据流程图编写程序

我们将流程图的程序整理一下,写出它的完整形式:

2.2.2 测试流水灯汇编程序

测试程序,当然要将程序编译、进行仿真,那么就得建立一个Keil项目。上一章我们建立过一个C程序的Keil项目,那么本节就建立一个汇编程序的项目,过程是大同小异的。(1)建立一个文件夹,项目文件就放在这个文件夹里面。文件夹的名称最好能重点突出程序功能,方便管理。(2)打开Keil,新建一个项目,如图2-38所示,操作完毕后自动弹出如图2-39所示的对话框,让我们给这个项目起一个名字,并且指定它的存放路径,如图2-40所示为选择器件的选择栏,在这里选择ATEML的AT89C52芯片。

选择好单片机型号以后,弹出如图2-41所示的选择框,注意在这里选择的是“否”按钮,表示不在项目中添加启动代码,这和建立Keil的C项目是不一样的。因为汇编语言直接控制硬件,不再需要添加启动代码。(3)新建程序文件,如图2-42所示。单击新建按钮或者按快捷键Ctrl+N,就会新建一个程序文件。单击保存按钮就会显示如图2-43所示的保存路径选择对话框,在这里给程序文件命名,注意文件的名称后加上后缀“asm”或“a”,表示此文件为汇编文件。图2-38 建立一个新项目图2-39 保存项目图2-40 选择单片机型号图2-41 是否添加启动代码图2-42 新建程序文件图2-43 程序文件保存(4)将程序文件添加到项目中,按照如图2-44所示的步骤进行操作,右击Source Group 1会弹出一系列选项,再单击Add File to Group‘Source Group 1’…,就会弹出如图2-45所示的对话框,这是让我们选择添加的文件。在默认情况下,Keil添加的都是C语言类型的文件,但这次添加的是汇编文件,在“文件类型”下拉菜单中选择第二项Asm Source File(*.s;*.src;*.a*),表示添加的文件类型为汇编文件。图2-44 项目添加文件的步骤图2-45 添加文件的类型选择

完成上述操作,就会显示出我们刚刚新建好的汇编文件“流水灯.asm”,如图2-46所示。选中“流水灯.asm”,再单击Add按钮,然后单击Close按钮就完成了程序的添加。(5)在编辑区内编辑程序,将流水灯程序写入编辑区内,如图2-47所示。图2-46 添加文件图2-47 编辑程序(6)生成“可执行程序文件”,按照如图2-48所示的步骤来操作。右击Target 1,在弹出的列表中选择“Option for Target ‘Target 1’”按钮,就会弹出如图2-49所示的对话框,按照图中所示的步骤进行操作。(7)编译项目。按照如图2-50所示的操作步骤进行编译程序文件。(8)进行仿真。将Proteus绘制的电路图放到Keil项目中,如图2-51所示,这样做是为了方便管理,这一步可不操作。图2-48 生成hex文件选项1图2-49 生成hex文件选项2图2-50 编译项目图2-51 Proteus电路图放置在Keil项目里面

打开绘制的流水灯电路图,如图2-52所示。单击51单片机,就会弹出“编辑元件”对话框,如图2-53所示,给单片机添加可执行程序。图2-52 流水灯电路图图2-53 “编辑元件”对话框

如图2-54所示,找到刚刚完成的Keil项目文件夹的路径,系统就会识别出“流水灯.hex”文件,然后单击“打开”按钮,为单片机添加可执行文件。(9)单击开始仿真按钮,如图2-55所示,观察仿真的最终效果。图2-54 找到可执行程序路径图2-55 仿真按钮

2.2.3 51单片机汇编语言指令介绍——数据传送指令

上一节涉及许多语法方面的知识,本书会根据每章的程序,来给大家讲一点汇编程序的语法。

1. 立即寻址指令MOV P1, #0EFH

在流水灯汇编程序中大量使用了这条指令。通俗来讲,此指令的用途是直接将数值0EFH直接传送给P1这个寄存器,这个数值称为立即数。立即数寻址的数字前面都会加上“#”符号。在汇编语言中,涉及数字的,都要加上“#”符号。

需要注意的是,如果数字的高位的值大于等于十六进制数A,也就是十进制10的话,前面必须加上0。例如程序中不能直接用#EFH,要使用#0EFH,否则程序编译就会报错。如果数值高位小于十六进制数A的话,可以加0,也可以不加,如#7FH和#07FH都是可以的。

MOV是英语单词MOVE(移动)的简写。立即数传送指令,如图2-56所示。图2-56 立即数传送指令

在汇编语言中,也可以用其他数值表示,如二进制、十进制。不过最常用的还是十六进制,因为十六进制正好表达了寄存器的8位数据,这一点虽然二进制更清晰,但是编写程序的时候会比较麻烦。

P1在内部RAM高128位的地址为90H,所以也可以用指令“MOV 90H,#0EFH”来代替“MOV P1,#0EFH”。

2. 无条件转移指令

JMP是无条件程序跳转指令。JMP的全称是JUMP(跳),表示无条件直接执行跳转到指定的地址编号。我们在后面会讲到有条件跳转指令。在程序中“START:”表示程序标号,程序标号的名称是可以随便用的,但是后面必须加“:”,程序标号可以标定当前程序的地址,方便跳转或是被调用。

流水灯要实现流水效果,就必须循环执行,不断地重复,所以需要再跳回到开始执行的地方,让它重复下去,这时必须要用到跳转指令。

需要说明的是,不管是我们用的8位图2-57 无条件跳转指令执行过单片机,还是更高级的32位处理器,如程果不涉及操作系统,程序的执行都是在一个循环体里面,就像流水灯程序一样,在后面的学习过程中大家会越发体会到这一点。

3. 调用子程序CALL DELAY1S

这就是我们在流水灯程序中,使用的调用子程序的语句。汇编语言中程序语句的格式如下:CALL 程序标号

在流水灯程序中调用的是一个延时一秒的子程序。子程序是一个程序标号开始的,如果调用这个子程序,就直接CALL这个程序标号。子程序的编写方法和主程序没有什么区别,具体的内容,我们会在以后的章节中讲述。

本节讲的程序语法都是流水灯程序中用到的,没有讲述太多的内容。也许学完本节,大家还是不会独立完成一个程序,但是可以对现有的程序进行修改,原有程序是某一时刻只有一盏灯亮,读者可以试一下让两盏灯同时亮,或者让更多的流水灯亮起了。

2.3 用C语言实现流水灯

用C语言实现流水灯和用汇编语言大同小异,在本节我们重点学习,C语言的数据类型,以及一些简单的语法知识。假如你有一定的C语言的知识,这当然是更好的;如果没有,也不要灰心,我们讲的内容还是依附于实例,是非常容易理解的。

2.3.1 根据流程图来编写程序

上一节根据流程图编写出了汇编语言,本节再次利用流水灯的流程图来编写出C语言程序,流水灯的流程图,如图2-58所示。图2-58 根据流程图来编写C语言程序

根据图2-58中的流程图,写出该程序的完整形式:

这样流水灯的C语言程序就编写好了,如果想要验证程序的准确性,就在Keil中建立一个C语言项目,进行编译,然后在Proteus中进行仿真,观察程序执行的效果。我们在第一章中教过大家如何建立一个C语言的项目,希望大家参考一下,用流水灯C语言程序建立项目,然后仿真,这样便于加深理解学习的内容。

2.3.2 当代最优秀的程序设计语言——C语言介绍

早期的C语言主要用于UNIX系统。由于C语言的强大功能和各方面的优点逐渐为人们认识,到了20世纪80年代,C语言开始进入其他操作系统,并很快在各类大、中、小和微型计算机上得到了广泛的使用,成为当代最优秀的程序设计语言之一。

美国国家标准协会(American National Standards Institute,ANSI)制定了一个C语言标准,于1983年发表,通常称之为ANSI C,因此在本书中谈到的标准C语言就是ANSI C。

运用于51单片机的C语言称为C51。C51只是在标准C语言的基础上进行了一点修改和扩展,以符合51单片机的实际控制,但是C51的语言格式和普通C语言是完全相同的。本章将介绍这一强大的编程语言。

1. C语言源程序的基本结构main(){while(1){P1=0XEF;Delay500ms();…………;…………;…………;}}(1)main是主函数的函数名,表示这是一个主函数。每一个C源程序都必须有,且只能有一个主函数。(2)每一个独立完整的语句都必须以“;”结尾,在我们给出的程序中,读者可能有疑问为什么while(1)语句的后面没有“;”,因为while(1)并不是一个完整的语句,通过程序可以看出while(1){ },才构成一个完整的语句。(3)用{ }括起来的部分,通常表示程序的某一层次结构。我们给出的程序中,{ }中的内容表示主函数的程序范围。涉及子函数等其他结构体,包含一个层次的内容,都可以包含在{ }中。{ }是可以嵌套在一起的,嵌套的形式在程序中经常出现。

2. while语句

流水灯程序是一个不断循环的过程,就需要一个循环语句来完成这一过程,这个过程就由while语句来完成。while语句的流程,如图2-59所示。(1)“()”里面的内容为循环的条图2-59 while语句的流程图件,在C语言中,1表示条件为真,“0”表示条件为假。在例程中,while(1)表示在任何条件下,都循环执行{ }里面的程序。(2)while语句的另一种常用的格式为:while(执行的条件)符合条件的语句;

例如while(a>0)P1=0x32;…………;

表示是只有当a大于0时,才会执行P1=0X32这条语句,否则执行下一条语句。

3. 程序的注释方法P1=0XEF, //赋值语句,不是等号

注释最主要的作用就是解释程序的功能,方便程序的识别和传播,注释是不参与程序的编译和执行的。(1)在符号“//”后,是注释的内容。(2)还有一种注释的方法,用“/*注释内容*/”括起来的内容也为注释部分,如:P1=0XEF; /*赋值语句,不是等号*/ Delay500ms();

程序中虽然添加了注释,但注释后面的Delay500ms()子程序仍然有效。

4. 赋值语句P1=0XEF;

在C语言中“=”不是等于的意思,而是表示赋值的意思。这条程序表达的意思就是将十六进制数EF赋值给P1。

5. 常量与变量

对于基本数据类型,按其取值是否可改变又分为常量和变量两种。在程序执行过程中,其值不发生改变的量称为常量,其值可变的量称为变量。程序中0XEF表示常量,而P1则表示变量。

6. 子函数

C源程序是由函数组成的。虽然在前面程序中有一个主函数main(),但实际程序往往由多个函数组成。函数是C源程序的基本模块,通过函数模块的调用可以实现特定的功能。在流水灯的C程序中void Delay500ms()表示一个延时子程序。

从函数定义的角度看,函数可分为库函数和用户定义函数两种:

库函数:由C系统提供,用户无需定义,也不必在程序中做类型说明,只需在程序前包含该函数原型的头文件,即可在程序中直接调用。在标准C语言中会多次用到printf、scanf、getchar、putchart等函数,它们均属库函数。

用户定义函数:由用户按需要定义的函数。对于用户自定义函数,不仅要在程序中定义函数本身,在主调函数模块中还必须对该被调函数进行类型说明。

我们在流水灯程序的开始,就对这个子程序给予了声明。如果这个子程序在主程序之前,也就是在main()函数之前定义的话,可以不用声明。但为了保险起见,不管子程序定义在什么位置,都应该在程序最前面进行声明。

7. 预处理命令——文件包含

以“#”号开头的命令。如包含命令#include、宏定义命令#define等。在源程序中,这些命令都放在函数之外,而且一般都放在程序文件的前面,它们被称为预处理部分。

所谓预处理是指在进行编译的第一遍扫描(词法扫描和语法分析)之前所做的工作。预处理是C语言的一个重要功能,它由预处理程序负责完成。当对一个源文件进行编译时,系统将自动引用预处理程序对源程序中的预处理部分做处理,处理完毕自动进入对源程序的编译。

在流水灯程序中,第一行#include<AT89x52.h>就是预处理命令中的文件包含。51单片机里面有一些独立寄存器定义在AT89x52.h这个文件里面,在C51编程中,必须在程序中包含这个文件。AT89x52.h这个文件是Keil公司为我们编写的,它的位置如图2-60所示。图2-60 AT89x52.文件路径

从图中可以看到在Keil安装目录下可以找到AT89x52.h,可以看到很多后缀为“h”的文件,这是为ATEML公司的其他产品准备的。打开这个文件看看里面的内容如下:

这段程序中声明了寄存器的地址,还有其他向量的地址等。我们可以看到,网上的一些资料和书籍上讲的实例明明用的是AT89C52单片机,但是用的文件包含却是#include“reg51.h”,这个reg51.h文件在哪里呢?我们同样在Keil的安装目录下可以找到它,如图2-61所示。图2-61 reg51.h文件的位置

大家可以打开文件看一下,文件内容和AT89X52.H的文件内容基本类似。它的开头有这样一段“Header file for generic 80C51 and 80C31 microcontroller.Copyright(c)”意思是通用80C51和80C31单片机的头文件。表示这个文件可以为所有51类的单片机做头文件。

而AT89X52.H则是这样写的“Header file for the low voltage Flash Atmel AT89C52 and AT89LV52.Copyright”意思是低压型Flash存储器单片机AT89C52和AT89LV52头文件,表示AT89X52.H是AT89C52专用的。

因为AT89C52单片机比传统80C51单片机的ROM容量增加了一倍,而且增加了一个定时器T2,所以在运用AT89C52这些功能时,reg51.h头文件就不再适合了,希望大家注意这一点。

2.4 I/O端口的输入控制

前面讲到流水灯是将I/O口作为一个输出口来驱动LED小灯,这对I/O的讲述还不是很完整,51单片机的I/O口还可以作为一个输入口来获取信息。我们本节就会介绍一个I/O口作为输入口来查询信息,将通过一个开关控制电路来介绍它的输入功能。

2.4.1 用开关控制流水灯

本节我们用一个开关来控制流水灯的执行,所以此电路就在原有流水灯的电路上进行添加。

如图2-62所示,这是我们要完成的电路图,大家仅仅需要在流水灯电路的基础上添加一个开关就可以了。图2-62 开关控制的流水灯

有一个开关需要我们来寻找,可以按照如图2-63所示的提示来操作。图2-63 开关的寻找方法

2.4.2 程序设计流程

同样,画出程序的流程图来帮助我们理清程序,如图2-64所示。菱形符号表示判断语句的执行。我们将P0.0口作为输入查询端口,程序的走向就是根据P0.0口的状态来决定的,如果P0.0为高电平,则执行流水灯程序;如果为低电平,则跳回到程序源处并重新查询P0.0口的状态,此时流水灯是不工作的。执行完流水灯程序再跳回到程序源处,实现整个程序的循环。图2-64 开关控制流水灯流程图

2.4.3 汇编语言实现开关控制流水

在编程之前我们介绍一组汇编指令,这组指令是我们在开关控制流水灯汇编程序执行判断的核心指令。这组指令有3种不同的形式,都是通过判断位的状态来决定程序的走向。(1)JB bit,rel位状态为1,则执行跳转,如图2-65所示。图2-65 指令执行流程图1(2)JNB bit,rel位状态为0,则执行跳转,如图2-66所示。图2-66 指令执行流程图2(3)JBC bit,rel位状态为1,则执行跳转,并清零该位,如图2-67所示。图2-67 指令执行流程图3

1. 完整代码

介绍完上面的指令,大家是否可以编写出程序了呢?我们就在流水灯汇编语言原有的基础上进行一些修改,完整的代码如下所示。

在程序中,我们仅用了jnb P0.0, START这一条语句就完成了编程,那么再用其他两条语句来试试吧。运用jb指令来编程,代码如下:…………..START:jb P0.0, goonjmp STARTgoon:MOV P1,#0FEH…………..

运用jb指令比jnb稍显复杂,我们要进行两次跳转才能完成流程需要的效果。

运用jbc指令是不可行的,因为jbc在执行成功之后,需要清零判断位,但是P0.0是由外部的状态决定的,所以我们无法使用该指令。

2. 程序仿真实验结果

在原有的流水灯汇编项目下,我们修改一下程序就可以执行看效果了。在Proteus仿真开始后,如图2-68所示,开关的两端有两个红色的小点,单击这两个小点就可以拨动开关了。图2-68 开关仿真执行操作方法

默认将开关拨到接地这一端,然后单击仿真按钮,LED小灯是不执行流水的。当拨动开关打到接电源这一端,流水灯就开始执行了,在流水灯运行的过程中,将开关拨到接地这一端无法停止流水,只是进行完这次流水就不再循环。可能读者会质疑开关的功能不“彻底”,解决的方法我们将在下一章来讲。

2.4.4 汇编语言知识扩充——专用寄存器介绍

我们在前面介绍过了,数据存储器高128字节是为专用寄存器准备的,因此我们称之为专用寄存器区,其地址范围是80H~FFH。本节将讲解几个特殊的寄存器,这些寄存器对于我们编写汇编程序来说是非常重要的,如表2-3所示。表2-3 各个特殊寄存器存储地址

在第1章讲到有22个专用的寄存器,其中寄存器PC在图中不显示。该表中的寄存器加上PC寄存器共26个,因为AT89C52增加了定时器2的功能,所以多出了4个用于控制定时器2的寄存器。

本节将主要介绍5个特殊的寄存器。

1. 程序计数器PC

PC是一个16位的计数器,其内容表示当前执行程序在ROM中的地址,PC具有自动加一的功能,随着程序的执行,它是在不断变化的。因为它是16位的寄存器,如图2-69所示。它的寻址范围为160~2(65536),涵盖了ROM的所有范围。图2-69 特殊寄存器PC

编写程序时一般不会用到它的,但是在程序的软件仿真中,却可以时时感受到它的存在。这里说的软件仿真,并不是指在Proteus中仿真,而是指我们在Keil的调试环境中的仿真,将在下一章向大家重点介绍这一种方法。

2. 累加器

累加器A或ACC,累加器是一个8位寄存器。在数据存储器高128单元的地址为E0H。

在汇编语言的编程中,累加器是使用频率最高的一个寄存器。累加器用于存放操作数,是数据传送的中转站,单片机大部分的数据操作都是通过累加器来完成的。

累加器每一位都具有自己的地址,我们可以对每个数据位进行寻址,如表2-4所示。表2-4 累加器A各位地址

3. B寄存器

B寄存器是一个8位寄存器,在数据存储器高128单元的地址为F0H,主要用于乘除运算。进行乘法运算时,B为乘数,累加器ACC为被乘数;得到的乘积结果高位放在B寄存器中,而低位放在ACC。进行除法运算时,ACC为被除数,B为除数,得到的结果,商放在ACC中,而余数放在B寄存器中。

除了用于乘除运算,B寄存器还可用于一般的数据寄存器,用来存放临时数据。同样,B寄存器每一位都具有自己的地址,也可以对每个数据位进行寻址,如表2-5所示。表2-5 B寄存器各位地址

4. 程序状态字PSW

程序状态字是一个8位的寄存器,在数据存储器高128单元的地址为D0H。它的功能是用于指示程序执行的状态信息,它的有效位是7位,PSW.1是没有定义的。PSW每一位都有它的地址,如表2-6所示。表2-6 程序状态字PSW各位的地址

在这7个位中,CY、AC、0V、P这4位表示程序执行的状态,也就是说可以读取它们的数值来判断程序的状态。RS1和RS0是通过写入数据来实现控制。F0是51单片机交给我们自由定义的标志位,我们既可写,也可读。下面我们简单地介绍一下这几个位的功能。

□ CY或C——进位标志位

CY或C是PSW最常用的标志位,它主要有两个功能,一是存放算数运算的进位标志;二是在位操作中,可作为暂时存放点,参与位运算。

□ AC——辅助进位标志位

在加法运算时,当有低4位向高4位进位或借位时,AC就置1。

□ OV——溢出标志位

在带符号数的加减运算中,OV=1表示加法运算的结果超出了累加器A所能表示的数值范围。

□ P——奇偶标志位

表明累加器A中1的个数的奇偶性。若1的个数为偶数,P=0;若1的个数为奇数,P=1。

□ F0——用户标志位

这是一个由使用者定义的表示位,根据需要来对这个位来进行置位或是查询。

这些标志位大家可以初步了解,在后面的程序中用到时,我们会详细讲解它们的用法。

继续讲解两个用于写入的位:RS1和RS0——寄存器组选择位。

第1章讲到内部数据存储区低128字节有一个寄存器区,大家可以复习这一部分的内容。

如图2-70所示,内部RAM的前32个单元是作为寄存器区(00H~1FH),共分为4组,每组有8个寄存器,序号为R0~R7。这些寄存器的使用频率在汇编语言中仅次于累加器A,在我们学习汇编语言的过程中,这些寄存器的地位是举足轻重的。但是在同一时间内,我们只能使用其中的一组,到底使用哪一组,就由RS1、RS0这两位来决定。在默认情况下,RS1和RS0这两位都为0,所以我们未对PSW寄存器写入数据的时候,我们用的是工作组1。图2-70 寄存器区设置

5. 数据指针(DPH,DPL)

DPH,DPL是两个8位的寄存器。我们最常使用的方法就是将两个合为一个,叫做DPTR,合并后数据指针就和PC一样,也是一个16位的寄存器,在对存储器操作时,它的功能非常重要。

2.4.5 用C语言实现开关控制流水灯

1. 判断语句

汇编语言有汇编的判断语句,而C语言同样也有自己的判断语句,而且更简单,更容易理解。在这里我们介绍一种判断语句——if语句。

If语句有同样也有3种表达方法。(1)第一种形式:if(表达式)语句;

或是if(表达式){语句}

其语义是:如果表达式的值为真,则执行其后的语句,否则不执行该语句。其执行过程如图2-71所示。在这里补充一点,在C语言中“=”表示赋值,而“==”则表示等于。在将要给出的程序中if(P1.0==1),则是判断P1.0是否等于1。(2)第二种形式为:if-else语句,其使用方法如下所示。if(表达式)语句1;else语句2;

其语义是:如果表达式的值为真,则执行语句1,否则执行语句2。其执行过程如图2-72所示。图2-71 if语句第一种表达方式图2-72 if语句第二种表达方式(3)第三种形式为if-else-if。

前两种形式的if语句一般都用于两个分支的情况。当有多个分支选择时,可采用if-else-if语句,其使用方法为:

其语义是:依次判断表达式的值,当出现某个值为真时,则执行其对应的语句,然后跳到整个if语句之外继续执行程序。如果所有的表达式均为假,则执行语句n,然后继续执行后续程序。if-else-if语句的执行过程,如图2-73所示。图2-73 if第三种表达方式

2. 完整的程序

同样,我们也在原有的流水灯C语言程序的基础上进行修改,就可实现要求的功能。完整的C语言程序如下所示。

在这里我们用的是if语句的第一种形式,在本例中如果运用if语句的另外两种形式就显得画蛇添足了,所以在这里我们就不再讨论其他两种形式。

3. 仿真

程序完成后该进行仿真了。在流水灯的C项目中进行修改,并且编译,就可以在Proteus中仿真了。

和汇编语言遇到了一样的问题,默认将开关拨到接地这一端,然后单击仿真按钮,LED小灯是不执行流水的。当拨动开关打到接电源这一端时,流水灯就开始执行了,在流水灯运行的过程中,将开关拨到接地这一端时无法停止流水,只是进行完这次流水后就不再循环。

2.4.6 C语言知识扩展

本节将介绍C语言的基本知识。

1. C51数据类型

数据类型是按被定义变量的性质、表示形式、占据存储空间的多少,以及构造特点来划分的。在C语言中,数据类型可分为基本数据类型、构造数据类型、指针类型和空类型四大类,如图2-74所示。图2-74 C语言的数据类型

此处不一一介绍这些数据类型了,在后面章节中,将在实例中介绍,这样更便于理解。

下面介绍4种我们现阶段较常用的数据类型,如表2-7所示。表2-7 现阶段常用的C语言数据类型

前面讲到C51和标准C语言所兼容的数据类型,8051系列微处理器提供一些新的数据类型,如表2-8所示。表2-8 C51派生新的数据类型

bit型是为方便我们读取位变量而设置的,其他两种数据类型主要是为定义我们使用的特殊寄存器的地址,编程的时候是不用的,这些类型主要是用在头文件中,就是前面提到的AT89X52.H。可以打开这个文件看一下。(1)sfr和char型都是8位的数据类型。下面一段程序是从AT89X52.H中摘取的,程序的作用是定义各个I/O口的地址。//声明4组I/O口的地址sfr P0 = 0x80;/* port-0,address 80h */sfr P1 = 0x90;/* port-1,address 90h */sfr P2 = 0xA0;/* port-2,address 0A0h */sfr P3 = 0xB0;/* port-3,address 0B0h */(2)sbit型是特殊功能寄存器位型。有些特殊寄存器的位是可以寻址的,就如下面的程序,程序中定义了P0口的每个端口的地址,在C程序中就可以直接运用P0口的每个端口。//声明P0每个端口的位地址sbit P0_0 = 0x80;sbit P0_1 = 0x81;sbit P0_2 = 0x82;sbit P0_3 = 0x83;sbit P0_4 = 0x84;sbit P0_5 = 0x85;sbit P0_6 = 0x86;sbit P0_7 = 0x87;(3)bit型在程序中是常用到的,例如定义一个位变量作为一个标志位:bit flag;

2. 51单片机的存储类型

为了编写出有效率的程序,把51单片机内部不同的存储区进行了分类,不管是在C语言中,还是在汇编语言中,都可以指定变量的存储类型。想变成有经验的编程高手,必须了解51单片机的各个存储类型,如表2-9所示。表2-9 51单片机的存储类型(1)CODE区:存储空间是代码段,用来存放可执行代码,还可在代码段中存储查寻表。

试读结束[说明:试读内容隐藏了图片]

下载完整电子书


相关推荐

最新文章


© 2020 txtepub下载