第4章MCS-51系列单片机C语言程序设计_第1页
第4章MCS-51系列单片机C语言程序设计_第2页
第4章MCS-51系列单片机C语言程序设计_第3页
第4章MCS-51系列单片机C语言程序设计_第4页
已阅读5页,还剩238页未读 继续免费阅读

付费下载

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

第4章MCS-51系列单片机

C语言程序设计4.1MCS-51系列单片机的C编译器4.2IAREW8051的集成开发环境4.3IAREW8051的C语言流程控制语句4.4IAREW8051的C语言数据类型4.5函数和模块化程序设计习题四

1.TaskingCrossview51

Tasking公司原名为BSO/Tasking,是一家专业开发和销售嵌入式系统软件工具的公司,于1974年创建于荷兰。Tasking公司一直为Intel、LSI、Motorola、Philips、Siemens、TexasInstruments等著名半导体厂商的微处理器、数字信号处理器(DSP)以及单片机编写高级语言编译器等配套软件开发工具,先后开发过8bit、16bit、32bit、64bit的MCU/DSP/RISC交叉编译程序。该公司生产多种单片机的交叉模拟程序(Simulators),可在无目标机的情况下模拟单片机的运行以及I/O口的行为。4.1MCS-51系列单片机的C编译器

Tasking公司还生产基于Windows下的嵌入式系统集成开发环境软件(EDE),使用高级连接定位器。EDE是面向工程(Project)的集成开发环境,能够完成从Edit、Make到Debug的“一条龙”服务。环境可以扩展和配置,支持鼠标,界面友好。EDE除开发工具一条龙服务外,还配套有辅助性服务,如Setup集成化、在线屏幕手册(Manual)集成化、出错管理(ErrorHandling)集成化、操作记录(Log)集成化。EDE支持第三方软件的运行,如Intel的Apbuilding,Aisys的DriveWay,INFOM的fuzzyTE、CK和MCU-51逻辑编译器等。Tasking公司具有10年生产Intel80C51软件开发工具的经验,其主要产品有:ASM51(包括Intel兼容宏汇编,Intel兼容Linker、Make、Converter及PL/M51)和C51Crossview51调试器(早期名XRAY51,包括ROMDebugger、IceDebuggs及Simulator)。其软件工具生成的代码可以在大多数著名的仿真器(如Nohau、Metalink、Ashling等公司的相关产品)上使用,软件格式符合IEEE-695、IntelDMF-51、IntelHEX、MotorolaS-records等国际标准。Tasking公司的最新产品为Philips16位80C51XA

应用软件工具套件,包括C编译器、宏汇编、连接器、定位器、Crossview模拟调试器等。

2.Keil/FranklinC51

Franklin的鼻祖是Keil,该编译器在代码生成方面比较有优势,可产生最少的代码。它支持浮点和长整数、重入和递归,不提供库源代码,不能生成能编译的汇编代码,仅产生混合代码,只有修改后才能作为汇编程序编译。若使用汇编语言,必须分开编译程序,然后用手工方式连接。

KeilC51标准C编译器为MCS-51系列单片机的软件开发提供了C语言环境,同时保留了汇编代码高效、快速的特点。KeilC51编译器的功能不断增强,使程序设计者可以更加贴近MCS-51系列单片机本身以及其他的MCS-51单片机衍生产品。KeilC51已被完全集成到uVision2的集成开发环境(IDE)中,这个集成开发环境包含C51编译器、汇编和连接,以及Tiny51实时操作系统(Real-timeOS)、项目管理器和调试器。KeilC51是一种高效、灵活的MCS-51系列单片机的C语言开发平台。它可以支持的8051及其衍生产品有上百种之多,也可以支持所有兼容的仿真器,同时支持其他第三方开发工具。KeilC51及相关工具的优点是优化后生成的代码效率可接近汇编,提供对所有硬件功能单元的操作。KeilC51支持Atmel,Dallas,Infineon,Philips,Winbond和Temic等公司生产的8051及其衍生产品。KeilC51指派寄存器变量,在整个应用程序中执行全局寄存器优化,所有工具均可产生详细的警告信息和错误信息,以帮助程序开发者快速查找、排除错误。它支持可重入函数和寄存器区的独立代码,以便于中断服务程序和多任务应用程序的执行。

3.IAREW8051

IARSystem公司是世界著名的软件生产厂家之一,其总部设在瑞典。IARSystem公司生产的IAREmbeddedWorkbench(简称IAREW)是一整套集成开发环境(IDE),适用于MCS-51系列单片机的IAREmbeddedWorkbench简称EW8051,EW8051集成开发环境包括嵌入式C/C++编译器、汇编器、连接定位器、库管理、项目管理及调试器等。IAREW早期主要是为8051、80196系列单片机提供的重要开发、调试工具,今天IAREW已经可以支持35种以上的8~32位处理器,它以卓越的性能价格比受到用户的普遍欢迎。IAR公司针对不同的体系结构,只需一个解决方案,旨在为用户提供一套通用的支持多种处理器的IDE。IAREW当前除了支持8051及其衍生的微处理器外,还支持Atmel、ARM、Hitachi、Infineon、Intel、Microchip、Mitsubishi、Motorola、NationalSemiconductor、NEC、OKI、Philips、Samsung、Sharp、TI、Toshiba、Triscend、WesternDesignCenter、Zilog等半导体厂商生产的多种微处理器。可支持的工作平台包括Windows95/98/2000、NT、UNIX等。上面提到的这些C51编译器都非常相似,特别是KeilC51和IAREW8051编译器的集成开发环境的外观和使用方法甚至与可视化C/C++的开发环境相似。它们都支持用户采用模块化结构开发和设计大的、复杂的应用程序,在视窗操作系统中使用集成开发环境编译、汇编、连接多模块结构程序都可以由IDE代理一次性完成。在开发嵌入式系统应用软件时提倡模块化结构的好处是:①方便分工协作方式完成复杂项目的开发;②开发阶段对部分代码进行单独仿真和跟踪调试;③可更好地发挥C语言的可移植性(Portable),减少不同项目中重复代码的开发;④系统软件功能具有可裁减性(Scalable)。这些C51的集成开发环境都提供无需硬件仿真器(HardwareDebugger)的模拟仿真器(Simulator),在单片机应用系统的软件中,有些代码与单片机的硬件无关,开发这部分代码时可以利用模拟仿真器实现快速仿真。本书中的C语言程序源码都是在IAREW8051集成开发环境下编写的,有关IAREW8051集成开发环境(IDE)的使用说明请参考下一节的内容,或者直接到IARSystem公司的主页()下载IAREW8051集成开发环境学习版及其用户手册或IAREW8051C编译器用户手册。4.2IAREW8051的集成开发环境4.2.1IAREmbeddedWorkbench开发平台的使用方法

IAREmbeddedWorkbench开发平台能够支持数百种8~32位微控制器,针对各种不同的微控制器需要不同的编译器,这个平台是一种通用的平台。

IAREmbeddedWorkbench开发平台的工作窗口如图4-1所示。它在外观上看起来与可视化编程的VisualC/C++非常相似。它包括项目管理器窗口(Projectwindow)、源文件编辑器窗口(Editorwindow)、信息窗口(Messageswindow)、二进制编辑器窗口(BinaryEditorwindow)等4个窗口,以及菜单栏(Menubar)、编辑栏(Editbar)、项目栏(Projectbar)和状态栏(Statusbar),其中编辑栏和项目栏组成了快捷工具栏。图4-1IAREmbeddedWorkbench开发平台的工作窗口

1.菜单栏菜单栏包括IAREmbeddedWorkbench开发平台的所有操作按钮。所有操作被分为8类:

(1) File(文件操作类):包括新创建、打开、保存、另存、打印文件以及打印设置和关闭开发平台等操作。

(2) Edit(编辑操作类):包括剪贴、拷贝、查找、替换等操作。

(3) View(视图控制操作类):包括打开或关闭编辑栏、项目栏和状态栏的控制操作。

(4) Project(项目管理类):提供给项目添加文件、创建工作组、编译和连接当前项目以及在当前项目下运行IAR工具等操作。

(5) Tools(工具类):提供在IAREmbeddedWorkbench开发平台上增加或删除用户自定义的辅助开发工具的操作,IAR允许用户在IAREW平台上使用自己更习惯的编辑器等辅助开发工具。

(6) Options(选项类):提供IAREmbeddedWorkbench开发平台的个性化风格界面的设置操作,允许用户设置自己更习惯的字体、关键字颜色等。

(7) Window(窗口控制类):提供子界面的位置、排列、分割等操作,以及正在被放置在后台的已经打开的文件列表。

(8) Help(帮助类):提供IAREmbeddedWorkbench开发平台的所有帮助操作。

2.快捷工具栏快捷工具栏包括文件编辑器常用操作的快捷按钮和项目管理器常用的操作按钮。文件编辑器常用的快捷工具按钮如图4-2所示。项目管理器常用的快捷按钮和窗口位置、排列控制的快捷按钮如图4-3所示。图4-2文件编辑器常用的快捷工具栏图4-3项目管理器和窗口排列的快捷按钮其中编译器常用的快捷按钮包括:

(1)“编译”当前被激活的源文件编辑窗口中的程序。注意,如果当前打开的项目由多个源文件(模块)构成,“编译”按钮仅编译当前被激活的源文件编辑窗口中的一个源文件,项目中的其他源文件不会被编译。

(2)“编译和连接”重新将当前项目中所有被修改过的源文件(模块)进行编译,然后连接,产生项目输出目标文件(如列表文件、MCS-51单片机可执行文件)。

(3)“停止编译”停止当前正在执行的单个源文件或项目编译操作。

(4)“打开C-SPY模拟器”首先编译、连接产生项目输出的目标文件和模拟器文件,然后自动打开IAREW平台的C-SPY软件模拟器,并自动将当前项目的模拟器文件加载到模拟器,这个过程会因为当前的项目编译或连接失败而停止,用户可以通过信息窗口看到出错的信息。

3.项目管理器窗口项目管理器窗口包括当前项目的名称、工作组子目录结构和项目包含的所有源文件(模块)名称列表。所有列表项前面有“+”的项可以被展开,能够看到该项的子目录项,譬如展开源文件项,可以看到该源文件包含的所有头文件(HeadFiles),如图4-4所示。

IAREW为用户提供方便使用的项目管理器快捷菜单功能,在项目管理器窗口的任何地方点击鼠标右键便弹出快捷菜单,如图4-5所示。图4-4项目管理器窗口图4-5项目管理器快捷菜单

4.编辑器窗口在编辑器窗口中,用户可以修改或编辑源文件(包括*.C、*.h等)。IAREW开发平台默认的语言为C语言,编辑窗口的源文件中所有C语法关键字、注释等特殊内容都使用不同的字体或颜色以高亮显示(见图4-6),这个特点与其他C语言编辑器非常相似,符合C语言程序员的习惯。图4-6源文件编辑窗口当前的项目如果是一个多模块结构的,IAREW允许用户在源文件编辑器中打开项目所属的所有源文件,每个源文件使用一个编辑器窗口。但是,任何时刻仅有一个窗口被激活,允许用户在该编辑器窗口修改和编辑某一个源文件,其他源文件被放置在后台。源文件编辑器需要切换到放置在后台的其他源文件,激活另一个编辑器窗口,可以通过菜单栏的“Window”下拉菜单选择另一个放置在后台的源文件,该源文件编辑窗口被激活并推到编辑器窗口的最上层。

5.信息窗口信息窗口显示IAREW开发平台对用户各项命令的运行结果。信息窗口包括多个页面,如图4-7所示。“Build”信息窗口给出用户执行单源文件编译或当前项目编译、连接项目的结果,包括出错信息(ErrorMessage)、警告信息(WarningMessage)等,每条信息为1行。如果出错或警告的信息是在编译时产生的,用户可以用鼠标双击某一条Error或Warning信息,IAREW将自动跳到源文件出错或警告的行位置,IAREW可以通过这种方法帮助用户快速查找、排除错误或警告。“FindinFiles”信息窗口给出编辑菜单下执行“FindinFiles…”命令查找的结果,给出符合查找条件的所有项,每项1行。用户可以用鼠标双击某一项,IAREW将自动跳到对应的行位置。“ToolOutput”显示用户在工具菜单中定义的工具给出的输出信息。图4-7信息窗口

6.二进制编辑窗口在二进制编辑窗口中将所有被打开的文件以二进制方式码方式显示,并允许用户在该窗口修改和编辑二进制码,显示时按照每8个二进制位组成一个十六进制字节数的方式。该窗口分为两个区域,一个区域是十六进制码显示区,另一个区域是对应的ASCII码显示区,如图4-8所示。对二进制方式打开的文件的修改和编辑可以直接在十六进制显示区进行,也可以在ASCII码显示区进行。可以在“Tools(工具)”菜单下选择“BinaryEditor…”来打开二进制编辑窗口,见图4-8。利用二进制编辑窗口可以打开并查看IAREW编译、连接产生的项目输出文件,MCS-51单片机能够执行的文件为二进制文件,用户只能通过二进制编辑窗口查看它的内容。图4-8二进制编辑窗口

7.File(文件操作类)菜单文件菜单提供了打开和保存各种文件以及退出IAREW开发平台等操作。点击File的下拉菜单可以看到的具体操作命令如图4-9所示。图4-9文件操作类命令菜单

8.Edit(编辑操作类)菜单编辑菜单提供编辑器窗口常用的操作,点击Edit的下拉菜单可以看到图4-10所示的命令菜单。图4-10编辑操作类命令菜单

9.View(视图类)菜单视图菜单下的命令可以让用户依据需要打开或关闭快捷工具栏操作按钮。点击View的下拉菜单可以看到图4-11所示的命令菜单。图4-11视图类命令菜单

10.Project(项目操作类)菜单项目菜单下的命令可以帮助用户给项目添加文件、创建文件组、确立项目选项,以及在当前项目下运行IAREW系统高级工具。点击Project的下拉菜单可以看到图4-12所示的命令菜单。图4-12项目管理器操作类命令菜单

(1)利用“Project→Files…”命令可以为当前的项目添加源文件或将源文件从当前项目中删除。打开的ProjectFiles窗口如图4-13所示。用户利用项目管理器的文件管理功能将当前的项目包含的所有源文件添加到项目中,或从项目中删除源文件,在执行项目编译(产生目标文件)、汇编(产生列表文件)和连接(产生二进制可执行文件)操作时,用户不需要干预项目编译、汇编和连接过程,IAREW开发平台会将项目管理器包含的所有源文件按模块结构分别进行编译和汇编,然后将各模块产生的目标文件连接产生项目的输出文件。譬如在图4-13中显示的这个例子项目至少由7个源文件组成。如果一个项目的源程序代码有数万行之多,把数万行源程序代码放在一个源文件中的做法是蹩脚程序员才使用的方法,而且这种方法不方便调试和维护。根据功能把数万行的源程序分割成多个源文件的做法是聪明的选择。图4-13项目管理器的文件管理窗口

(2)利用“Project→NewGroup…”命令可以将多模块结构的项目中的源文件按文件组方式来管理。打开“NewGroup…”窗口可以为当前项目创建新的文件组标识,如图4-14所示。一旦为当前的项目创建了一个新的文件组标识后,在项目管理窗口就可以看到这个新的文件组标识,然后用户可以利用“Project→Files…”命令为新创建的文件组添加源文件。图4-14创建新的文件组对话框

(3)利用“Project→Targets…”命令可以为当前项目添加一个新的目标输出。IAREW开发平台允许一个项目产生多组输出文件,打开维护当前项目的Targets对话框,如图4-15所示。图4-15项目输出目标维护的对话框

(4)利用“Project→Option”命令可以选择确定当前项目的编译、汇编、连接控制选项。IAREW允许用户对当前项目的不同“Targets”选择使用不同的编译、汇编、连接选项,图4-16是确定“Release”目标的编译、汇编、连接选择的对话框。图4-16输出目标编译、汇编、连接控制选项的维护对话框用户对当前项目目标的编译、汇编、连接控制选项进行维护操作时,IAREW开发平台编译、汇编、连接当前项目的所有控制选项都在这里设置。选择不同的选项,编译、汇编、连接当前项目时,可以产生所要求的列表文件、目标文件、输出文件等,包括各源文件对应的汇编文件、MCS-51单片机硬件资源使用的列表文件、出错和警告列表文件、目标文件等,以及产生的项目输出文件名称和格式。IAREW开发平台允许用户把项目输出文件按照用户的习惯(或要求)命名,输出格式可以选择Debug和Intel-Stand、debug-Intel-Stand、Intel-Extended或debug-Intel-extended等数十种不同的格式。选择Debug格式时,要求IAREW编译、汇编和连接时仅产生调试、模拟器用的输出文件;用Intel-xxxx格式时,不产生调试和模拟器使用的输出文件,而仅产生Intel格式的可执行文件;用debug-Intel-xxxx格式时,编译、汇编、连接后既产生调试和模拟器用的输出文件,同时也产生Intel格式的可执行文件。对MCS-51单片机来讲,可执行文件的格式一般都使用Intel标准。确定项目编译、汇编、连接控制选项的详细操作说明非常多,限于篇幅,这里不再详细阐述,请参考IAREW提供的使用向导“8051IAREmbeddedWorkbenchUserGuide”,这个文件可以在网站免费得到,或者直接向IARSystem公司索取。4.2.2C-SPY模拟器的使用方法

C-SPY是IAREmbeddedWorkbench开发平台中一个非常有用的仿真工具,利用这个工具,用户可以在PC上仿真正在开发、设计的应用程序,而且可以在没有专用的硬件仿真器的情况下进行仿真。IAREW也允许用户使用C-SPY结合ROM-Monitor或INTELRISM硬件仿真器在线仿真、调试应用程序。在“Project→Option”对话框中选择“C-SPY”选项,在Setup页面中可设置C-SPY的控制参数,如图4-17所示。其中“Driver”选项用于选择C-SPY模拟器使用的仿真器,有三种选择:Simulator、ROM-Monitor和INTELRISM。这里选择Driver使用Simulator选项,即对当前的项目进行软件模拟调试(不需要硬件仿真器)。图4-17C-SPY模拟器的控制选项在项目管理器的快捷工具栏中点击C-SPY按钮,即可进入模拟调试器窗口调试当前项目,如图4-18所示。

C-SPY模拟器界面包括菜单栏、文件和窗口控制操作常用的快捷工具栏、常用调试控制快捷工具栏和状态栏,以及源文件窗口(Sourcewindow)、报告窗口(Reportwindow)、寄存器窗口(Registerwindow)、查看变量窗口(Watchwindow)和代码及存储器窗口(Memorywindow)。当用户打开C-SPY并进入模拟调试器后,光标首先停留在程序中惟一的main()函数的第一句程序,模拟MCS-51单片机被复位后的状态。然后用户可以选择调试模式:手工单步跟踪调试、自动单步跟踪调试、连续运行到指定的行位置、连续运行。图4-18C-SPY模拟器窗口

C-SPY模拟器快捷工具栏的按钮及其功能如图4-19所示。当用户进入模拟器之后,光标所在的行被C-SPY使用特殊颜色“高亮”显示,点击手工单步跟踪调试按钮,光标自动移到下一行,并且这一行也被“高亮”。手工单步跟踪调试每次仅运行一句C语句,而且C-SPY的跟踪调试与可视化VisualC/C++的Debug相似,可以选择进入子程序单步跟踪执行或者不进入子程序的单步跟踪调试,以及由单步转为连续运行到当前的子程序出口,连续运行到最近的断点,自动单步跟踪调试等。C-SPY允许用户采用连续跟踪调试方式模拟程序的执行。点击“复位”快捷按钮,无论模拟调试器处于任何状态,C-SPY立即终止运行,并将光标移到main()函数的第一句。无论模拟调试器处于任何状态,点击“停止”快捷按钮即可停止模拟调试器跟踪调试,并且光标停止在当前执行的行位置。图4-19C-SPY模拟器快捷工具栏4.3IAREW8051的C语言流程控制语句4.3.1判断语句判断选择语句是控制一句或若干句C语句是否被执行的控制语句。C语言支持两种类型的选择语句:if和switch。另外,在某些特殊情况下,操作符“?”可作为if的另一种表示形式。

1.if语句

if语句的格式为:

if(条件表达式)

{

C语句;//注释

}

if语句的功能是,当“条件表达式”的值为真(除0外的任何值)时则执行“{}”里面的语句,否则执行if语句的下一条可执行语句。如果if语句中“{}”里的可执行语句只有一条,则包围该语句的“{}”可以略去。if语句的程序结构如图4-20所示。图4-20if语句执行流程

例4.1

下面的程序对I/O端口P1的第1位(P1.1)进行判断,如果读入值为0(低电平),则将端口1的第0位置为1(高电平)。if(P1.1==0)

{

P1.0=1;}下面的程序与上面的程序完全相同,但是少了“{}”:if(P1.1==0)

P1.0=1;需要注意的是,如果if条件表达式后面没有语句体(多个连续C语句构成C语句体),而只有一个分号“;”,如下面的代码:

if(条件表达式);语句;则在执行if语句时首先判断“条件表达式”的结果,无论“条件表达式”的结果是真或假,总是顺序执行if语句后面的可执行C语句。

2.if…else复合语句

if…else复合语句的格式为:

if(条件表达式)语句1;

else语句2;

if…else语句的执行过程为:如果if语句的“条件表达式”的值为真,则执行语句1,否则就执行语句2。执行时,每次要么执行与if相关的语句,要么执行与else相关的语句,只能是两者取其一。if…else语句的程序结构如图4-21所示。图4-21if…else语句执行流程

if和else同属于一个if语句,else不能作为语句单独使用,它只是if语句的一部分,与if配对使用。如果两个分支中需要执行的语句不止一条,必须用“{}”括起来,作为一个复合语句使用。若只有一条C语句,“{}”可以省略。例如:

if(P3.2==0)

P1=0x0;

else

P1=0xFF;该例程用扫描方式读取MCS-51单片机的P3.2引脚电平,如果P3.2引脚的电平为低电平,那么if语句的“条件表达式”结果为真,执行P1=0x0,即将P1口的所有位清0;如果P3.2引脚的电平为高电平,那么if语句的“条件表达式”结果为假,执行P1=0xFF,即P1口的所有位被置位。

3.if语句的嵌套一条if语句只能判断给定条件的两个方面(真或假),当供选择的情况较多时,可以用if语句的嵌套来实现。if语句嵌套的格式为:

if(条件表达式1)

{语句1;

}

else

{

if(条件表达式2)

{语句2;

}

else

{

if(条件表达式3)

{语句3;

}

else

{语句4;

}

}

}语句5;上面是一个3级“if…else”嵌套语句,该嵌套语句从上往下对条件进行判断,如果一个条件为真,就执行与此条件有关的语句,并将越过其余部分而直接转到语句5;如果无一条件为真,那么就执行最后一个else所属的C语句;如果最后一个else不存在,并且所有条件都为假,则什么都不执行。下例程序以根据键码的值进行不同的处理来说明if语句的嵌套用法:voidmain(void){

unsignedcharkeypad;

unsignedcharascii;

//调键盘扫描程序,得到键码,存放在keypad变量中

keypad=getchar();

if(keypad==0x0)

ascii='0';

else

if(keypad==0x01)

ascii='1';

else

if(keypad==0x02)

ascii='2';

else

if(keypad==0x03)

ascii='3';

else

if(keypad==0x04)

ascii='4';

printf("CurrentKeypadis%c",ascii);}上例中,由于不同keypad值对应着不同的ascii值,且keypad的值有多种情况,因而使用了两个以上if…else语句嵌套进行判断。需要注意的是,在if语句出现嵌套形式时,必须搞清楚if和else的配对关系。C语言规定:else与前面最接近它而又没有和其他else语句配对的if语句配对。

4.条件运算符“?”条件运算符的语法格式为:变量或表达式=(条件表达式)?(条件为真时的表达式):(条件为假时的表达式)其中“?”被称为三目操作符,因为它要求三个操作数。执行条件运算符“?”语句的过程为,执行时首先判断“条件表达式”的值,当“条件表达式”的值为真时,将“条件为真时的表达式”的值赋给“=”前面的变量或表达式;当“条件表达式”的值为假时,将“条件为假时的表达式”的值赋给“=”前面的变量或表达式。例如:

Larger_Value=(a>b)?a:b;首先判断“?”前面的条件表达式“a>b”的值。如果a大于b,则将a的值赋给变量Larger_Value,否则将b的值赋给变量Larger_Value。若使用if…else语句,则与其执行结果完全相同的程序为:

if(a>b)

Larger_Value=a;

else

Larger_Value=b;

5.switch语句

if语句是两分支选择控制语句,而switch语句是多分支选择控制语句,使用switch可以使判断更加直观。

switch语句的格式为:

switch(表达式)

{

case常量表达式1:语句组1;break;

case常量表达式2:语句组2;break;

case常量表达式n:语句组n;break;

default:语句组n+1;

}

例4.2

用switch语句编写程序,根据keypad=0x00~0x0F的值,对应转换为ASCII码的值ascii,然后利用“printf()”函数将其显示在屏幕上。实现的程序如下:

#include<io51.h>

#include<stdio.h>

voidmain(void)

{

unsignedcharkeypad;

unsignedcharascii;

while(1)

{

keypad=getch();

//读取键码

switch(keypad)

{

case0x00:ascii='0';break;

case0x01:ascii='1';break;

case0x02:ascii='2';break;

case0x03:ascii='3';break;

case0x04:ascii='4';break;

case0x05:ascii='5';break;

case0x06:ascii='6';break;

case0x07:ascii='7';break;

case0x08:ascii='8';break;

case0x09:ascii='9';break;

case0x0A:ascii='A';break;

case0x0B:ascii='B';break;

case0x0C:ascii='C';break;

case0x0D:ascii='D';break;

case0x0E:ascii='E';break;

case0x0F:ascii='F';break;

default:ascii='';

}

printf("CurrentKeyPadcode:%c",ascii);

}

}

switch语句的执行过程为,根据case语句中给出的常量值,按顺序对switch语句的“表达式”的值进行匹配。当常量与表达式相符时,就执行与这个常量所在case语句相关的语句块,直到碰到break或者switch语句执行完为止。若没有一常量与表达式值相符,则执行default语句。default是可选择的,如果default不存在,并且所有的常量表达式都不相符,则不进行任何处理。

break语句是C语言的转移语句之一。它既可用在循环语句中,也可用在switch语句中。如果在switch语句中遇到break,程序就转移执行switch语句后面的可执行C语句。从技术上讲,switch语句中的break语句是可以选择的,它们通常被用来终止与每个常量有关的语句序列。如果break语句被省略了,就继续在下一个case语句中执行,一直到break或者switch的尾部为止。在同一个switch语句中,任意两个case的常量均不允许有相同值。

switch后面括号中的“表达式”结果的数据类型只能是整型、字符型或枚举表达式,case后面的常量表达式的数据类型必须与之匹配。case语句中的常量表达式起标号作用,各常量表达式必须互不相同。此外,switch语句还可实现嵌套。C编程语言的switch语句与汇编语言中的散转指令应用比较相似。4.3.2循环控制语句在许多实际问题中,需要进行有规律性的重复操作,如求累加和、数据块的移动等。所谓循环,是指任何一种类型的重复性控制结构。这种结构让代码的某一块被重复执行。使用循环是编程时最复杂的情形之一,知道如何及何时使用哪种循环是编写高质量软件的决定性因素。在C语言中用来实现循环的语句有三种:while语句、do-while语句和for语句。

1.while语句

while语句的格式为:

while(条件表达式)

{语句;

}

while语句的执行过程为,首先判断“条件表达式”的值,以便决定是否应当进入、执行循环体语句。在这里,“条件表达式”是while循环能否继续的条件,而语句部分则是循环体,是执行重复操作的部分。只要表达式为真,就执行循环体内的语句,语句执行完毕后,再次判断条件表达式的真假,如果为真就重复上述步骤;反之,则终止while循环,执行循环之外的下一条语句。

while循环语句的执行流程如图4-22所示。图4-22while语句的执行流程

例4.3

使用while语句计算1+2+3+…+99+100的值。程序如下:

voidmain(void)

{

unsignedintcount=1,sum=0;

while(count<=100)

{

sum+=count;

count++;

}

printf("Resultofsum=%d",sum);

}该程序的执行结果为sum=5050。该程序首先初始化循环变量count和累加和sum,然后进入while循环,不断进行累加计算。当count的值为101时,则条件表达式“count<=100”的值为假,退出循环。

while循环结构的最大特点在于,其循环条件测试处于循环体的开头,要想执行重复操作首先必须进行循环条件测试,若条件不成立则循环体内的重复操作一次也不能执行。在单片机程序中,主程序首先连续执行各个初始化程序,然后必须进入一个无限循环的循环体中执行程序。经常要用到如下形式的while语句格式:

voidmain(void)

{

Init_8051();

//初始化8051的特殊功能寄存器以及中断

Init_Parament();

//初始化变量

while(1)

//循环条件永远为真,循环体是一个无限循环

{

//循环语句

}

}在这里,while语句中的条件表达式永远为真,这实际上是设置了一个“死循环”或称之为“无限次循环”,以使程序的主模块在循环里面不断运行。但有时需要程序在符合某些条件时退出无限循环体,实现的方法是使用break语句。下面的程序是使用break语句计算1+2+3+…+99+100的值。

voidmain(void)

{

unsignedintcount=1,sum=0;

while(1)

{

if(count>100)

break;

sum+=count;

count++;

}

printf("Resultofsum=%d",sum);

}该程序的执行结果为sum=5050。在MCS-51单片机系统中,需要等待某事件的发生,需要编写一个循环体实现等待,但是如果发生事件的通道出现了故障,将使得程序无法满足条件而退出循环,使程序陷入“死循环”。为了保证软件具有一定的容错性,需要等待一定时间,在此期间如果仍没有事件发生,那么就退出等待循环。

例4.4

下面是等待P1.0端口电平变化的程序。如果P1.0为低电平,就循环等待P1.0变为高电平,当P1.0为高电平时便退出等待循环。如果等待循环计数器大于10000,则认为等待超时,也退出等待循环。程序如下:#include<io51.h>#include<stdio.h>voidmain(void){

unsignedintwatCnt=0;

while(P1.0==0)

{

watCnt++;

//循环计数器加1

if(watCnt>10000

)

//判断循环计数器是否大于10000

break;

//如果循环计数器大于10000,则认为等待超时,退出循环

}

if(watCnt>10000)

printf("WatingOvertime!");

else

printf("P1.0tohigh"); }比较下面的程序:#include<io51.h>#include<stdio.h>voidmain(void){

while(P1.0==0)

{

;

//循环等待P1.0转为高电平

}

printf("P1.0tohigh");}如果由于MCS-51单片机系统的硬件出现故障,造成P1.0引脚的电平被外部电路钳位在低电平,使P1.0引脚电平无法变为高电平,那么造成“P1.0==0”的条件永远为真,程序的循环中没有容错处理而成为“无限循环”,无法继续运行其他程序。

2.do-while语句

do-while语句的格式为:

do

{语句;

}while(条件表达式);

do-while循环语句的执行过程为:首先执行“{}”中的循环体语句,然后判断while语句中的“条件表达式”的结果。如果“条件表达式”的结果为真,则继续执行“{}”中的循环语句,然后再判断while语句中的“条件表达式”的结果,结果为真仍继续循环。只有当“条件表达式”的结果为假时,循环才会终止,并以正常方式执行while语句后面的程序语句。

do-while程序的流程控制如图4-23所示。图4-23do-while语句流程

例4.5

使用do-while语句计算1+2+3+…+99+100的值。程序如下:

voidmain(void)

{

unsignedintcount=1,sum=0;

do

{

sum+=count;

count++;

}while(count<=100);

printf("Resultofsum=%d",sum);

}该程序的执行结果为sum=5050。使用do-while语句的程序循环体至少被执行一次,无论while语句的“条件表达式”的结果是否为真。这是由于程序顺序执行时,首先执行循环体中的程序语句,然后才计算“条件表达式”的结果,判断结果为真或假,然后再决定是否继续循环。这是do-while语句与while语句的最大区别。另外还需要注意的是do-while循环中,“while(条件表达式)”后面的分号是必需的,而while循环语句中的“while(条件表达式)”后面不允许有分号,否则,while循环体不会被执行。

3.for循环语句

for循环语句的格式为:

for(表达式1;表达式2;表达式3)

{语句;

}

for循环语句的执行过程分为下面5步:

(1)执行表达式1对循环变量赋初值。

(2)判断表达式2是否满足给定的循环条件。若满足,则执行循环体内的语句,然后执行第(3)步;若不满足循环条件,则结束循环。

(3)若表达式2为真,则在执行完指定的循环体语句后继续执行表达式3。

(4)回到第(2)步继续执行。

(5)退出for循环,执行下面一条语句。

for循环语句的执行流程如图4-24所示。相对于while循环语句和do-while循环语句来讲,for循环语句显得更加灵活,它不仅可以用于循环次数已经确定的情况,而且也可以用于循环次数不确定的情况。图4-24for循环的执行流程

例4.6

使用for循环语句计算1+2+3+…+99+100的值。程序如下:

voidmain(void)

{

unsignedinti,sum;

sum=0;

for(i=1;i<=100;i++)

{

sum+=i;

}

printf("Resultofsum=%d",sum);

}该程序的执行结果为sum=5050。在上面的程序中,for循环表达式1是给循环变量i赋初始值,即“i=0”。表达式2是“i<=100”,其作用是对循环条件进行测试,当i≤100时,表达式2为真,则执行循环体内的语句,即执行“sum+=i”程序语句。然后执行表达式3,即“i++”,其作用是将循环变量加1,然后进入下一轮循环。若循环变量i>100,表达式2的结果为假,则退出for循环。使用for循环语句时,需要注意以下几个特殊的地方。

(1) for语句中小括号内的三个表达式全部为空。如:

for(;;)

{语句;

}在for语句的小括号里仅有两个分号,无任何表达式。这意味着没有设初值,无判断条件,这是一个使用for循环语句构成的无限循环。对for循环的三个表达式都没有要求,因此可以运用空的条件表达式而使得循环无休止地执行下去。当循环的次数预先不能确定时,一般采用无限循环方式。这和“while(1){}”、“do{}while(1);”的功能是一样的,如果需要退出无限循环,也可以使用break语句。

例4.7

利用for循环语句构成无限循环,计算1+2+3+…+99+100的值。程序如下:

voidmain(void)

{

unsignedinti,sum;

sum=0;

i=1;

//循环变量在for循环之外被赋初始值1

for(;;)

{

sum+=i;

//计算累加和

i++;

//循环变量加1

if(i>100)

//判断循环变量是否大于100

break;//循环变量大于100时,退出无限循环

}

printf("Resultofsum=%d",sum);

}该程序的执行结果为sum=5050。

(2) for循环中的3个表达式部分为空。如:

for(表达式1;;)

{语句;

}或者

for(;表达式2;表达式3)

{语句;

}在for语句的小括号里仅有1个表达式或2个表达式。如果没有表达式1,意味着没有对循环变量赋初始值的语句,那么初始值必须在for循环语句之前被明确;如果没有表达式2,意味着没有循环条件,这又是一个使用for循环语句构成的无限循环,而使得循环无休止地执行下去,当循环的次数预先不能确定时,一般采用无限循环方式,如果需要退出无限循环,也可以使用break语句;如果没有表达式3,意味着没有修改循环变量的表达式,那么在循环体内必须有修改循环变量的语句,否则会造成“死循环”。

例4.8

省略表达式1,求1+2+3+…+99+100的值。程序如下:

voidmain(void)

{

unsignedinti=1,sum=0;

//声明循环变量同时对其赋初始值1

for(;i<=100;i++)

//没有对循环变量赋初始值的表达式

{

sum+=i;

}

printf("Resultofsum=%d",sum);

}这里循环变量i的初始化提到for循环之外进行。程序的执行结果为sum=5050。

(3)循环体可以为空,即没有循环语句。这通常用在某些需要延时的地方,以达到特定的要求。如:

voidDelay(unsignedintDelayTime)

{

unsignedinti;

for(i=DelayTime;i>0;i--);

//没有循环体

}由于循环体是空语句,因此上面的循环只是将i从DelayTime递减到1,然后退出循环,执行这个程序的作用是CPU被延时若干时间。4.4IAREW8051的C语言数据类型4.4.1IAREW8051的C语言数据类型和变量

1.数据类型数据类型组成了IAREW8051编译器的C语言的基本元素。IAREW8051开发平台的编译器支持所有ANSIC的基本格式。表4-1给出了C数据类型、占用的位或字节数、取值(大小)范围。

C语言是一种增强类型语言,它要求程序设计者在使用数据变量之前必须对数据的类型进行声明,以便编译器按照表4-1的数据类型占用的字节数给被声明的变量分配存储空间。如果在程序中使用未经声明的变量,则编译器会产生编译错误。增强类型语言的一个优点是它能够检查出尽可能多的数据类型方面的错误。

IAREW8051的数据类型与ANSIC的数据类型相比有以下特殊之处:

(1) bit(位)类型。在x86结构的PC系统中使用BorlandC或VisualC/C++等,也有位(变量)数据类型。但是,在x86结构的系统中不支持专用的位变量存储区域,使得C编程语言编译器分配一个字节的存储单元用于存放一个位变量。而MCS-51单片机的CPU内部支持128bit的可位寻址、可位操作的存储区(参见第二章有关内容),当程序设计者在程序中使用了位变量,并且使用的位变量个数小于128个时,IAREW8051编译器自动将这些变量存放在MCS-51单片机的可位寻址、可位操作的存储区,每个变量占用1位存储空间,一个字节可以存放8个位变量。

(2) sfr(特殊功能寄存器)类型。这种数据类型在IAREW8051编译器中等同于unsignedchar数据类型,而且IAREW8051为sfr类型的变量分配存储位置时,它固定在MCS-51单片机的特殊功能寄存器区。在IAREW8051开发平台调试完成的C语言程序代码中,如果使用的是sfr类型变量,那么移植这些C源代码到其他结构的C编译器中执行编译时,会造成代码移植失败。

(3) char(字符)类型。MCS-51单片机在简单的控制领域中应用时,目标系统不使用带有符号的字符型数据类型,用户可以在IAREW8051项目管理器的选项(“Project→Option”)中将ICC8051的CodeGeneration选项页面的“'char'is'signed'”选项去掉,让IAREW8051编译器将char类型等同于unsignedchar类型。这时用下面的格式声明一个变量abc:

charabc;那么这个声明等同于下面的变量声明:

unsignedcharabc;两种变量声明的C语句在IAREW8051中是相同的,声明的变量abc都是“无符号字符型”数据类型。但是其他的C编程语言编译器不一定兼容,将在IAREW8051中编译成功的C源代码移植到其他的C编译器中使用,可能会出现意想不到的错误。

(4) pointer(指针)类型。绝大多数的C编程语言编译器都为声明的指针类型变量分配4个字节大小的存储单元,但是由于MCS-51单片机硬件的特殊性,其最大寻址空间仅为64KB,因此IAREW8051为程序中声明的指针分配存储单元时,最大仅需要3个字节,其格式如下:在IAREW8051编译器中,“Memorytype”表示当前被声明的指针将指向哪种存储区域,MCS-51单片机的存储区域分为data、idata、xdata、pdata、code等。指向不同存储区域的指针变量的“Memorytype”的标识码见表4-2。由于MCS-51单片机的存储器类型的特殊性,IAREW8051编译器要求用户在声明指针变量时必须指明指针指向的地址属于哪种存储器类型。那么相应在声明变量时也需要指明变量存储空间属于哪种存储器类型,以便于在使用指针访问变量时明确变量存放的存储器类型。

pointer不是一个有效的C数据类型说明符,声明指针时都使用“*”标识指针。注意:上面的IAREW8051特殊性之处是在代码移植时将出现不同编译器之间的不兼容,它们不仅表现在MCS-51单片机硬件结构与x86结构或MC68结构等CPU之间的区别,而且不同的MCS-51单片机C编程语言编译器之间也有许多互相不兼容的特殊之处,如KeilC51和IAREW8051之间也有互相不兼容的地方。

2.变量变量和变量操作构成C语言的基本C语句,多个C语句又组合成C源程序。变量是存储信息的基本单元,它对应于某个存储空间,用变量代表存储单元,程序对变量赋值、变量之间相互赋值,实际上是对存储单元进行存取操作。用变量名代表其存储空间,是C编程语言与汇编语言相比,前者能够作为高级编程语言的优势。

1)变量名的命名所有的C编程语言对大小写字母都是敏感的,即C编程语言认为大写字母和小写字母是不同的字母。变量名的命名要遵循如下规则:①不能是C关键字;②第一个字符必须是字母或下划线;③不能以数字开头;④中间不能有空格;⑤不能包含“.;"+-”之类的特殊字符;⑥变量名不能同函数名相同。下面命名的变量都是非法的:

data,do,1a,abc,a.b,a+c下面命名的变量是合法的:

abc,_do,_data,a1,a_bc在给变量命名时应当使变量名完全而准确地描述变量所代表的意义,比较有效的方法是使用自然语言(一般是英语)描述变量,或者使用汉语拼音等,因为这样能有效保证容易读懂,这对于程序的维护是极为重要的。

2)变量的声明格式

IAREW8051要求的变量声明格式是:数据类型说明符[<存储器类型说明符>]变量名;或者

[<存储器类型说明符>]数据类型说明符变量名;其中,数据类型说明符必须是有效的C数据类型,参见表4-1(除了表中的pointer,它不是有效的数据类型说明符)。同一数据类型的多个变量可以在一个语句里建立,只要在类型名后写上多个变量名,中间用逗号分隔开,如:

inti,count,sum;

C语言允许程序设计者在声明变量时就为被声明的变量赋初始值,如:

inti=1;在IAREW8051编译器中声明变量时,IAR建议程序设计者指明存储器类型,一旦程序设计者指明了被声明的变量的存储器类型后,IAREW8051编译器将被声明的变量存放在程序设计者要求的存储区域内。因为MCS-51单片机的内部数据存储器空间比较小,为了得到高效的代码,需要指明变量的存储器类型。但是,根据前面的内容可以知道,在IAREW8051中指明了存储器类型的C源程序移植到其他编译器时,会造成不兼容。如果程序设计者需要兼容其他C语言编译器,以便将写好的C源代码移植到其他C语言编译器中使用,在声明变量时也可以不指明存储器类型,由IAREW8051编译器自动为程序分配存储器类型。IAREW8051编译器将没有指明存储器类型的变量统统认为是data型存储器,除非声明的变量的个数非常多,需要大于128B的存储空间,或大于256B的存储空间时,才自动被分配到xdata存储器中。

IAREW8051编译器能够识别的变量存储器类型见表4-2。不允许对同一个变量赋予两种不同的存储器类型标识。在声明变量时,数据类型说明符和存储器类型说明符的位置可以交换。如:

unsignedcharidataabc;和

idatausignedcharabc;是相同的。从减小程序代码的角度来讲,在使用数据类型定义变量时要注意两个原则。一是在满足需要的情况下尽可能使用最小数据类型。譬如,在使用char型变量已经能满足应用的情况下却使用了int型变量,这样用int型变量执行运算时就可能需要调用库函数,增加了不必要的代码,而且int型变量本身就比char型变量占用了更多的数据存储器的单元。二是尽量使用“unsigned”数据类型,因为MCS-51系列单片机并不直接支持有符号数据运算,必须通过编译器连接调用库函数,产生相关的代码才能支持有符号数的运算。

3)变量的生命周期

C语言变量按其生命周期可分为全局变量和局部变量。凡是在所有的函数之外声明的变量都属全局变量;在一个子程序(或过程或函数)内部声明的变量都属局部变量。全局变量的生命周期是无限长的,只要程序开始运行,它就一直存在,并且固定占用相应大小的存储单元。局部变量仅在CPU执行某一个函数或过程时有效,一旦退出这个函数或过程后,局部变量就会消失,它原来占用的存储单元被编译器分配给其他局部变量使用。绝大多数的C语言编译器都能够将局部变量的存储单元优化,保证这些存储单元被不同的、不重叠的函数、过程重复利用。但是,全局变量不能被编译器优化且被重复利用。

IAREW8051编译器是一种带有高级优化功能的编译器,编译器的优化处理可为资源较少的MCS-51系列单片机系统有效地节省资源。可以将程序中的局部变量得到最大限度的重复利用。由于MCS-51单片机的内部存储器单元较少,建议程序设计者尽量少使用全局变量。

4)变量空间

MCS-51系列单片机的存储器包括:8个通用寄存器,片内的可以直接和间接寻址的128B存储区,片内可位寻址、位操作的位存储区(128bit),片内仅可以直接寻址的特殊功能寄存器区,片内仅可以间接寻址的高128B存储区,片外扩展的数据存储器区,程序存储器区。其中程序存储器区的数据(或代码、常数表)是只读(Read-Only)的ROM型存储器,其他存储区都是可以随机存取的RAM型存储器。在C语言中声明的变量可以存放在这些存储区域中的某些单元。

IAREW8051编译器要求声明变量时指明变量的存储器类型,在编译程序时,编译器会按照程序设计者的意图将被声明的变量存放在指定的存储区域中。声明变量时指明的存储器类型说明在MCS-51单片机的存储器区域中的位置如图4-25所示。图中,code区域(程序存储器区域)用于存放程序代码和常数表格,它的最大可寻址空间为64KB,地址范围为0000H~FFFFH,包括片内的code区域和片外扩展的code区域。对于没有内部ROM的单片机如8031/8032,必须在片外扩展程序存储器。此外,如果片内code区域不够用时也需外扩程序存储器。程序存储器中的0000H地址是系统程序复位后的起始地址,MCS-51单片机在复位结束后从该单元开始执行程序。下面定义的变量是只读的,IAREW8051或其他编译器都禁止在程序中对这些变量赋值:

codeunsignedcharASCIICode[]="0123456789ABCDEF";

codeunsignedintCRC16Table[]={0x1020,0x3410,0x8249,0x9A75,0x7F30};

codeunsignedcharabc='0';图4-25存储器类型说明与存储器区域之间的关系对于这里声明的变量,如果出现下面的赋值语句,IAREW8051和其他C语言编译器认为是非法的:

abc='A';

ASCIICode[4]='A';这是由于IAREW8051编译器将用户声明的code存储器类型的变量分配在程序存储器中,MCS-51单片机禁止在正常执行程序时升级或改写程序存储器中的内容,那么上面声明的变量是只读的。下面的语句对这些变量的操作是允许的:

unsignedcharasc;

unsignedintcrc16;

asc=ASCIICode[4];

asc=abc;

crc16=CRC16Table[0];这些语句都是将code存储器区域的常数赋给随机存取的变量,所以它们是合法的。当程序需要访问(仅限于读操作)定义为code的变量时,IAREW8051编译器将这些操作对应为汇编语言的MOVC(查表)指令。

IAREW8051编译器把xdata、pdata和data、idata都归属随机存取的RAM型存储器类型,被声明的变量如果加上这些存储器类型说明符后,IAREW8051编译器将它们对应为汇编语言的MOVX@DPTR、MOVX@R0和MOVR0、MOV@R0等指令。显然,xdata的有效地址范围为0000H~FFFFH,共64KB;pdata的有效地址范围为0000H~00FFH,共256B;data的有效地址范

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论