《KeilC及其程序设计.ppt》由会员分享,可在线阅读,更多相关《KeilC及其程序设计.ppt(66页珍藏版)》请在taowenge.com淘文阁网|工程机械CAD图纸|机械工程制图|CAD装配图下载|SolidWorks_CaTia_CAD_UG_PROE_设计图分享下载上搜索。
1、(3 3)片外程序存储器)片外程序存储器code:外部程序存储器的64KB空间。程序存储区用来存放程序代码、数据及表格(数据及表格中的数据是不变的)。程序的代码(CODE)存储区是只读的,不能写入。硬件决定最多可能有64KB的程序存储区。【因为是16位】用code标识符来访问片内、片外统一编址的程序存储区,寻址范围为065535。对单片机编程,正确地正确地定义数据类型定义数据类型以及以及存储类型存储类型,是所有编程者在编程前都需要都需要首先考虑首先考虑的问题。的问题。在资源有限的条件下,如何节省存储单元并保证运行效率,是对开发者的一个考验。只有对C51中的各种数据类型以及存储类型非常熟练的掌握
2、,才能运用自如。1定义定义变量类型变量类型应考虑如下问题:应考虑如下问题:程序运行时该变量可能的取值范围,是否有负值,绝对值有多大,以及相应需要的存储空间大小。在够用的情况下,尽量选择8位即一个字节的char型,特别是unsiged char。对于51系列这样的定点机而言,浮点类型变量将明显增加运算时间和程序长度,如果可以的话,尽量使用灵活巧妙的算法来避免浮点变量的引入。定义数据的存储类型通常遵循如下原则:定义数据的存储类型通常遵循如下原则:只要条件满足,尽量选择内部直接寻址的存储类型data,然后选择idata即内部间接寻址。对于那些经常使用的变量要使用内2部寻址。在内部数据存储器数量有限或
3、不能满足要求的情在内部数据存储器数量有限或不能满足要求的情况下才使用外部数据存储器。况下才使用外部数据存储器。选择外部数据存储器可先选择pdata类型,最后选用最后选用xdata类型类型。扩展片外存储器,原理上虽很简单,但在实际开发中,很多时候,会带来不必要的麻烦,如可能降低系统稳定性、增加成本、拉长开发和调试周期等,推荐充分利用片内存推荐充分利用片内存储空间。储空间。通常的单片机应用都是面对小型的控制,代码比较短,对于程序存储区的大小要求很低,常常是片内RAM很紧张而片内Flash ROM很富裕,因此如果实时性3要求不高,可考虑使用可考虑使用宏宏,以及将一些子函数的常量数据做成数据表,放置在
4、程序存储区,当程序运行时,进入子函数动态调用下载至RAM即可,退出子函数后立即释放该内存空间。43.2.3 一个简单的一个简单的C51程序程序一个C51源程序是由一个个模块化的函数一个个模块化的函数所构成,函数是指程序中的一个模块,main()函数()函数为程序的主函数,其他若干个函数可以理解为一些子程序。一个C51源程序无论包含了多少函数,它总是从总是从main()函数()函数开始执行开始执行,不论不论main()函数()函数位于程序的什么位于程序的什么位置位置。程序设计者就是编写一系列的函数模块编写一系列的函数模块,并在需要的时候调用这个函数,实现程序所要求的功能。51.C51程序与函数程
5、序与函数下面通过一个简单C51程序,认识认识C51程序与函数。程序与函数。【例例3-1】在STC89C51的P1.0脚脚接有一只发光二极管,二极管的阴极接P1.0脚,阳极通过限流电阻接+5V,现在让发光二极管每隔800ms闪灭,占空比为50%。已知单片单片机时钟晶振为机时钟晶振为12MHz,即每个机器周期1s,采用软件延时的方法,参考程序如下:6#include /包含reg51.h 头文件sbit P10=P10;/定义位变量P1.0,也可使用也可使用 sbit P10=0 x90void delay(unsigned int count)/延时函数delay(),count是形式参数 /两
6、个花括号之间为函数delay()的函数体 unsigned int i,j;/定义变量i,jfor(i=0;icount;i+)/如果icount,则i加1/在时钟频率为在时钟频率为12MHz时,循环时,循环120次,大约为次,大约为1ms for(j=0;j120;j+)/如果j120,则j加1 /unsigned char j;可以节约一个单元空间可以节约一个单元空间7void main(void)/*主函数main()*/while(1)/*主程序轮询*/P10=1;/*P1.0输出高电平,发光二极管灭*/delay(800);/*将实际参数800传递给形式参数i,延时800ms*/P1
7、0=0;/*P1.0输出低电平,发光二极管亮*/delay(800)/*将实际参数800传递给形式参数i,延时800ms*/如果把如果把void delay(unsigned int count)改为改为void delay(unsigned char count),是否可行?是否可行?8下面对程序进行程序进行简要说明简要说明。程序的第第1行行是“文件包含文件包含”,是将另一个文件“reg51.h”的内容全部包含进来。文件“reg51.h”包含了51单片机全部的特殊功能寄存器的字节地址及可寻址位的位地址定义。程序包含程序包含reg51.h的的目的目的就是为了使用P1这个符号,即通知程序中所写的
8、P1是指STC89C51的P1端口,而不是其他变量。9打开打开reg51.h文件可以看到文件可以看到“sfr P1=0 x90;”,即定义符号P1与地址0 x90对应,而P1口的地址就是0 x90。虽然这里的“文件包含”只有一行,但C编译器在处理的时候却要处理几十行或几百行。程序的第第2行行用符号P10来表示P1.0引脚。在C51中,如果直接写“P1.0”编译器并不能识别,而且P1.0也不是一个合法的C51语言程序变量名,所以必须给它起一个另外的名字,这里起的名字是P10,可是P10是否就是P1.0呢,所以必须给它们建立联系,这里使用了使用了C51的的关键字关键字“sbit”来进行定义。10第
9、第3行行第第8行行对函数函数delay进行了事先定义事先定义,只有这样,才能在主程序中被主函数main()调用。自行编写的函数delay()的用途是软件延时,调用时使用的这个“800”被称为“实际参数”,以延时800ms的时间。注意,注意,若delay()的定义写在main函数的后面,则需要先作出声明,否则编译无法通过,因为编译到main函数中的delay()语句时,找不到相应的函数体。11main为“主函数主函数”,每一个C语言程序有且只有一个主函数,主函数后面一定有一对花括号“”,在花括号里面书写该函数的代码行。2.用户自定义函数与库函数用户自定义函数与库函数从结构上划分,函数分为主函数主
10、函数main()和普通函数普通函数两种。对普通函数对普通函数,从用户使用的角度划分有两种有两种:一种是标准库函数标准库函数;另一种是用户自定义函数用户自定义函数。(1)标准库函数)标准库函数Keil C51具有功能强大、资源丰富的标准库函数,由C51编译器提供。进行程序设计时,应该善于充分利用12这些功能强大、资源丰富的标准库函数,提高编程效率。用户可以直接调用用户可以直接调用C51的库函数的库函数而不需要为这个函数写任何代码,只需要包含具有该函数说明的头文件即可。例如例如调用输出函数printf时,要求程序在调用输出库函数前包含以下的include 命令:#include(2)用户自定义函数
11、)用户自定义函数用户根据自己需要所编写的函数。如例例3-1中的delay函数函数。编写时,需要注意以下几点。13函数的首部(函数的第首部(函数的第1行),行),包括函数名、函数类型、函数属性、函数参数(形式参数)名、参数类型。例如:例如:void Delay(unsigned int i)函数体,函数体,即函数首部下面的花括号“”内的部分。如果一个函数体内有多个花括号,则最外层的一对“”为函数体的范围。C51区分大小写区分大小写,例如Delay与delay,编译时是不同的两个名称。每个语句最后必须有一个语句最后必须有一个分号分号,分号是C语句的必要组成部分。14从函数的定义的形式上划分可以有三
12、种形三种形式:无参数函数、有参数函数和空函数。(1)无参数函数)无参数函数此种函数在被调用时,既无参数输入,也不返回结果给调用函数,只是为完成某种操作而编写的。(2)有参数函数)有参数函数调用此种函数时,必须提供实际的输入函数,必须说必须说明与实际参数一一对应的形式参数明与实际参数一一对应的形式参数,并在函数结束时返回结果,供调用它的函数使用。15(3)空函数)空函数函数体内无语句,是空白的无语句,是空白的。调用空函数时,什么工什么工作也不做,不起任何作用。作也不做,不起任何作用。定义空函数的目的目的,是为以后为以后程序功能的扩充程序功能的扩充。程序最初设计时,往往只涉及最基本的功能模块的函数
13、,其他模块的功能函数可以在以后补上。因此先将非基本模块的功能函数定义成空函数,用一个空语句“;”占好位置,并写好注释,以后再用一个编好的函数代替它。163.函数调用函数调用程序设计者的任务程序设计者的任务就是编写一系列的用户自定义函数模块,并在需要的时候调用这些函数以及库函数,实现程序所要求的功能。调用分为以下几种。(1)简单调用)简单调用调用格式为:调用格式为:函数名(实际参数函数名(实际参数1,实际参数,实际参数2,)例如,例例如,例3-1中主函数main()里的子函数调用语句“delay(800);”,其中800为实际参数。17(2)嵌套调用)嵌套调用是在被调用的函数中又调用其他函数的语
14、句又调用其他函数的语句。(3)递归调用)递归调用函数的递归调用就是一个函数在其函数体内有调用自身。再入函数再入函数是一种可以在函数体内直接或间接调用自身的一种函数,在Keil C51中递归函数必须是可重入的,可重入的函数需要加上reentrant。183.2.4 C51的运算符的运算符在程序中实现运算,要熟悉常用的运算符。本节对C51中用到的标准标准C运算符进行简单回顾运算符进行简单回顾,为C51的程序设计打下基础。1.算术运算符算术运算符如表表3-3所示。19表表3-3 算术运算符及其说明20符号符号说明说明+加法运算加法运算-减法运算减法运算*乘法运算乘法运算/除法运算除法运算(取商)(取
15、商)%取模运算取模运算(取余数)(取余数)+自增自增1-自减自减1对于“/”和“%”往往会有疑问。这两个符号两个符号都涉及除法运算,但“/”运算是取商,而“%”运算为取余数。例如例如“5/3”的结果(商)的结果(商)为1,而“5%3”的结果的结果为2(余数)。表3-3中的自增和自减运算符是使变量自动加1或减1,自增和自减运算符放在变量前和变量之后是不同的。+i,-i:在使用:在使用i之前,先使之前,先使i值加(减)值加(减)1。i+,i-:在使用:在使用i之后,再使之后,再使i值加(减)值加(减)1。21例如:例如:若i=4,则执行x=+i时,先使i加1,再引用结果,即x=5,运算结果为i=5
16、,x=5。再如:再如:若i=4,则执行x=i+时,先引用i值,即x=4,再使i加1,运算结果为i=5,x=4。2.逻辑运算符逻辑运算符逻辑运算符及其说明如表表3-4所示。22 表表3-4 逻辑运算符及其说明3.关系运算符关系运算符判断两个数之间的关系。关系运算符及其说明如表表3-5。23符号符号说明说明&逻辑与逻辑与逻辑或逻辑或!逻辑非逻辑非 表表3-5 关系运算符及其说明24符号符号说明说明大于大于=大于或等于大于或等于=小于或等于小于或等于=等于等于!=不等于不等于4.位运算位运算位运算符及其说明如表表3-6所示。表表3-6 位运算符说明25符号符号说明说明&位逻辑与位逻辑与位逻辑或位逻辑
17、或位异或位异或位取反位取反位右移位右移【例】设a=0 x54=01010100B,b=0 x3b=00111011B,则a&b、a|b、ab、a、a2分别为多少?a=0 x54=01010100B b=0 x3b=00111011B a&b=00010000b=0 x10 a|b=01111111B=0 x7f ab=01101111B=0 x6f a=10101011B=0 xab a2=01010000B=0 x50 【a2=00001110B=0 x0e 【b=2】265.赋值、指针和取值运算符赋值、指针和取值运算符是对变量操作的基本运算。赋值、指针和取值运算符及其说明如表表3-7所示。
18、表表3-7 位运算符说明27符号符号说明说明=赋值赋值*指向运算符指向运算符&取地址取地址C51语言中支持在赋值运算符“=”的前面加上其它运算符,组成复合赋值运算符复合赋值运算符。下面是C51中支持的复合赋值运算符:+=加法赋值加法赋值 -=减法赋值减法赋值*=乘法赋值乘法赋值 /=除法赋值除法赋值%=取模赋值取模赋值&=逻辑与赋值逻辑与赋值|=逻辑或赋值逻辑或赋值 =逻辑异或赋值逻辑异或赋值=逻辑非赋值逻辑非赋值 =右移位赋值右移位赋值 =2相相 当当 于于x=x2。293.2.5 C51的分支与循环程序结构的分支与循环程序结构程序结构上可把程序分为可把程序分为三类三类,即顺序、分支顺序、分
19、支和循环循环结构。顺序结构是程序的基本结构,程序自上而下,从main()的函数开始一直到程序运行结束,程序只有一条路可走,没有其他的路径可以选择。顺序结构比较简单和便于理解,这里重点介绍重点介绍分支结构分支结构和循环结构循环结构。301.分支结构程序分支结构程序(1)只有两条分支的时候用只有两条分支的时候用If(条件)分支1else 分支2(2)分支较多时分支较多时在分支较多时的情况下使用分支较多时的情况下使用switch语句。31switch()case():语句;break;case():语句;break;default:语句;break;注意:注意:每个每个switch分支必须有一个分支
20、必须有一个break语句,语句,否则程序并不能跳出switch,就会继续执行case后面的case语句。322.循环结构程序循环结构程序循环语句有以下三种三种。(1)for循环循环格式:格式:for(循环体初始化;循环体执行条件;循环体执行后操作)(循环体初始化;循环体执行条件;循环体执行后操作)花括号中为循环体内容。33(2)while循环循环格式为:while(循环体执行条件),花括号中为循环体内容。34(3)do while循环循环格式为:do ,花括号,花括号 中为循环体内容中为循环体内容while(循环体执行条件)(循环体执行条件)前两种循环前两种循环是先进行循环条件是否满足的判断,
21、才决定循环体是否执行;而而“do while循环循环”是在执行完循环是在执行完循环体后再判断条件是否满足,再决定循环体是否继续执行。体后再判断条件是否满足,再决定循环体是否继续执行。三种循环中,经常使用的是三种循环中,经常使用的是for语句语句。下面来说明for语句的应用。35【例例3-2】求求1到到100之间整数的和。之间整数的和。程序如下:程序如下:#include#include main()int nVar1,nSum;for(nVar1=0,nSum=1;nSum=100;nSum+)nVar1+=nSum;/*累加求和累加求和*/while(1);/unsigned char nS
22、um;unsigned int nVar1;能节省一个单元能节省一个单元36关于循环,需说明的是,在无操作系统的控制器和处理器上运行的程序,主体通常采用主体通常采用轮询方式轮询方式,即把所有的操作包含在一个while(1)中,如例3-1。这样的无限循环在面向通用计算机的软件设计中是不被允许的,然而嵌入式系统软件设计中,则由于其硬件构成和使用需求,常常采用这种无限循环。373.2.6 绝对地址访问绝对地址访问使用使用C51运行库中预定义宏运行库中预定义宏C51编编译译器器提提供供了了一一组组宏宏定定义义来来对对51系系列列单单片片机机的的code、data、pdata和和xdata空空间间进进行
23、行绝绝对对寻寻址址。规规定定只只能能以以无无符号数方式访问,定义了符号数方式访问,定义了8个宏定义,其函数原型如下:个宏定义,其函数原型如下:#define CBYTE(unsigned char volatile code *)0)#define DBYTE(unsigned char volatile data *)0)#define PBYTE(unsigned char volatile pdata*)0)#define XBYTE(unsigned char volatile xdata*)0)#define CWORD(unsigned int volatile code *)0)
24、#define DWORD(unsigned int volatile data *)0)#define PWORD(unsigned int volatile pdata*)0)#define XWORD(unsigned int volatile xdata*)0)38 这这些些函函数数原原型型放放在在absacc.h文文件件中中。使使用用时时须须用用预预处处理理命命令令把把该该头头文文件件包包含含到到文文件件中中,形形式式为为:#include 。其其中中:CBYTE以以字字节节形形式式对对code区区寻寻址址,DBYTE以以字字节节形形式式对对data区区寻寻址址,PBYTE以以字字节
25、节形形式式对对pdata区区寻寻址址,XBYTE以以字字节节形形式式对对xdata区区寻寻址址,CWORD以以字字形形式式对对code区区寻寻址址,DWORD以以字字形形式式对对data区区寻寻址址,PWORD以以字字形形式式对对pdata区区寻寻址址,XWORD以以字字形形式式对对xdata区区寻寻址。访问形式如下:址。访问形式如下:宏名宏名地址地址 宏宏名名为为CBYTE、DBYTE、PBYTE、XBYTE、CWORD、DWORD、PWORD或或XWORD。地地址址为为存存储储单单元元的的绝绝对对地址,一般用地址,一般用十六进制十六进制形式表示。形式表示。39【例例4-7】绝对地址对存储单
26、元的访问。绝对地址对存储单元的访问。#include /将绝对地址头文件包含在文件中将绝对地址头文件包含在文件中#include /将寄存器头文件包含在文件中将寄存器头文件包含在文件中#define uchar unsigned char /定义符号定义符号uchar为数据类型符为数据类型符unsigned char#define uint unsigned int /定义符号定义符号uint为数据类型符为数据类型符unsigned intvoid main(void)uchar var1;uint var2;var1=XBYTE0 x0005;/XBYTE0 x0005访问片外访问片外RAM
27、的的0005字字节单元节单元var2=XWORD0 x0002;/XWORD0 x0002访问片外访问片外RAM的的0002字单元字单元40 xval=XBYTE0 x0002;/把外部存储区地址把外部存储区地址0 x0002的数据存的数据存入变量入变量xval中中XWORD0 x0002=0 x2000;/把把0 x2000送到外部存储区地址送到外部存储区地址为为0 x0002的单元的单元#define DAC0832 XBYTE0 x7fff /定义定义DAC0832的端口的端口地址地址DAC0832=0 x80;/启动一次启动一次D/A转换转换.while(1);在上面程序中,其中在上面
28、程序中,其中XBYTE0 x0005就是以绝对地址方式访就是以绝对地址方式访问的片外问的片外RAM 0005字节单元字节单元;XWORD0 x0002就是以绝就是以绝对地址方式访问的片外对地址方式访问的片外RAM 0002字单元字单元。41 3.2.7 使用使用C51扩展关键字扩展关键字_at_ 使用使用_at_对指定的存储器空间的绝对地址进行访问,一般格式对指定的存储器空间的绝对地址进行访问,一般格式如下:如下:存储器类型存储器类型 数据类型说明符数据类型说明符 变量名变量名 _at_ 地址常数;地址常数;其中,存储器类型为其中,存储器类型为data、bdata、idata、pdata等等C
29、51能能识别的数据类型,如省略则按存储模式规定的默认存储器类型识别的数据类型,如省略则按存储模式规定的默认存储器类型确定变量的存储器区域;数据类型为确定变量的存储器区域;数据类型为C51支持的数据类型。地支持的数据类型。地址常数用于指定变量的绝对地址,必须位于有效的存储器空间址常数用于指定变量的绝对地址,必须位于有效的存储器空间之内;之内;使用使用_at_定义的变量必须为全局变量定义的变量必须为全局变量。42【例例】通过通过_at_实现绝对地址的访问。实现绝对地址的访问。#define uchar unsigned char/定义符号定义符号uchar为数据类为数据类型符型符unsigned
30、char#define uint unsigned int /定义符号定义符号uint为数据类型符为数据类型符unsigned intvoid main(void)data uchar x1 _at_ 0 x40;/在在data区中定义字节变区中定义字节变量量x1,它的地址为它的地址为40Hxdata uint x2 _at_ 0 x2000;/在在xdata区中定义字变量区中定义字变量x2,它的地址为它的地址为2000Hx1=0 xff;x2=0 x1234;.while(1);433.2.7 C51中断服务函数的定义中断服务函数的定义 由于标准由于标准C没有处理单片机中断的定义,为直接编写
31、没有处理单片机中断的定义,为直接编写中断服务程序,中断服务程序,C51编译器对函数的定义进行了扩展,编译器对函数的定义进行了扩展,增增加了一个扩展关键字加了一个扩展关键字interrupt,使用该关键字可以将一个,使用该关键字可以将一个函数定义成中断服务程序。由于函数定义成中断服务程序。由于C51编译器在编译时对声编译器在编译时对声明为中断服务程序的函数自动添加了相应的明为中断服务程序的函数自动添加了相应的现场保护、阻现场保护、阻断其他中断、返回时恢复现场断其他中断、返回时恢复现场等处理的程序段,因而在编等处理的程序段,因而在编写中断服务函数时可不必考虑这些问题,减轻了用汇编语写中断服务函数时
32、可不必考虑这些问题,减轻了用汇编语言编写中断服务程序的繁琐程度,而把精力放在如何处理言编写中断服务程序的繁琐程度,而把精力放在如何处理引发中断请求的事件上。引发中断请求的事件上。44中断服务函数的一般形式为:void 函数名(void)interrupt n using n在函数声明时,用“interrupt n”语句,可以把所声明的函数定义为一个中断服务程序。从定义中可以看出,中断函数必须是无参数、无返回值的函数。关键字interrupt后面的 n是中断号中断号,对于AT89S51,取值取值为为04,编译器从从8n+3处产生中处产生中断向量断向量。AT89S51中断源对应的中断号和中断向量见
33、表表3-3。45表表3-3 中断号中断号n和中断向量和中断向量中断号中断号n中断源中断源中断向量中断向量(8n+3)0外部中断外部中断00003H1定时器定时器0中断中断000BH2外部中断外部中断10013H3定时器定时器1中断中断001BH4串行口中串行口中断断0023H其他值其他值(531)预留预留(8n+3)46AT89S51在内部RAM中有4个工作寄存器区个工作寄存器区,每个寄存器区包含包含8个工作寄存器(个工作寄存器(R0-R7)。)。C51扩展了一个关键字关键字using,专门用来选择选择AT89S51的的4个不同的工作寄存器区个不同的工作寄存器区。在定义一个函数时,using是
34、一个选项,是一个选项,如果不选用该项,如果不选用该项,则由编译器选择一个寄存器区作为绝对寄存器区访问。例如:unsigned int interruptcnt;unsigned char second;void timer0(void)interrupt 1 using 2 /定时定时0中断服务程中断服务程序序 if(+interruptcnt=4000)second+;Interruptcnt=0;47关键字关键字using对函数目标代码的影响对函数目标代码的影响:在中断函数的入口处将当前工作寄存器区内容保护到堆栈中,函数返回前将被保护的寄存器区的内容从堆栈中恢复。使用关键字关键字using
35、在函数中确定一个工作寄存器区时必须小心,要保证工作寄存器区切换都只在指定的控制区指定的控制区域中发生域中发生,否则将产生不正确的函数结果。还要注意,带带using属性的函数原则上不能返回属性的函数原则上不能返回bit类型的值类型的值,且关键字键字using和 48关键字关键字interrupt都不允许用于外部函数,另外也都不允许有一个带运算符的表达式。例如例如,外中断外中断1(/int1)的中断服务函数书写如下:void int1(void)interrupt 2 using 0 /中断号n=2,选择0区工作寄存器区49编写编写AT89S51中断程序时,应遵循以下规则中断程序时,应遵循以下规则
36、:(1)中断函数没有返回值中断函数没有返回值,如果定义了一个返回值,将会得到不正确的结果。因此建议在定义中断函数时,将其定义为void类型,以明确说明没有返回值。(2)中断函数不能进行参数传递,中断函数不能进行参数传递,如果中断函数中包含任何参数声明都将导致编译出错。(3)在任何情况下都不能直接调用中断函数在任何情况下都不能直接调用中断函数,否则会产生编译错误。(4)如果在中断函数中再调用其他函数如果在中断函数中再调用其他函数,则被调用的函数所使用的寄存器区必须与中断函数使用的寄存器区不同。50(5)C51编译器对中断函数编译时会自动在程序开始和结束处加上相应的内容,具体如下:在程序开始处对A
37、CC、B、DPH、DPL和PSW入栈,结束时出栈。中断函数未加using n修饰符的,开始时还要将R0R1入栈,结束时出栈。如中断函数加using n修饰符,则在开始将PSW入栈后还要修改PSW中的工作寄存器组选择位。(6)C51编译器从绝对地址8m+3处产生一个中断向量,其中m为中断号,也即interrupt后面的数字。该向量包含一个到中断函数入口地址的绝对跳转绝对跳转。(7)中断函数最好写在文件的尾部中断函数最好写在文件的尾部,并且禁止使用extern存储类型说明。防止其它程序调用。513.3 C51的集成开发环境的集成开发环境Keil Vision3介绍介绍C51程序开发是在Keil V
38、ision3 开发环境下进行,首先介绍该开发环境。3.3.1 集成开发环境集成开发环境Keil Vision3简介简介Keil Software公司推出公司推出的Keil Vision3 是一款基于Windows的软件平台,它是一种用于51单片机的集成开发环境(IDEIntergrated Development Eviroment)。Vision3提供了对基于提供了对基于8051内核的各种型号单片机的支内核的各种型号单片机的支持持,完全兼容先前的Keil Vision2版本。目前当前较新的版本为Keil C51 V8.08a。52开发者可购买可购买Keil Vision3软件,软件,也可到K
39、eil software公司的主页免费下载主页免费下载Eval(评估)版本。(评估)版本。该版本同正式版本一样,但有一定的限制,最终生成的代码不能超过2KB,但用于学习已经足够。开发者还可以到Keil公司网站申请免费的软件试用光盘。Keil Vision3内包含了功能强大的包含了功能强大的编辑器编辑器和和调试器调试器。编辑器可以像一般的文本编辑器一样对源代码进行编辑,并允许用户在编辑时设置程序断点(可在源代码未经编译和汇编之前)。用户启动Vision3的调试器之后,断点即被激活。53 断点断点可被设为条件表达式、变量或存储器访问设为条件表达式、变量或存储器访问,断点被触发后,调试器的命令或调试
40、功能即可执行,因此用户可以在编辑器内调试程序,使用户快速地检查和修改程序。用户还可以在编辑器中选中变量和存储器来观察其值。并可在双层窗口中显示,还可对其进行适当的调整。此外,Vision3调试器具有符号调试特性符号调试特性以及历史跟踪历史跟踪,代码覆盖,复杂断点等功能。Keil C51编译器编译器在遵循ANSI C标准的同时,为51单片机进行了特别的设计和扩展,能让用户使用在应用中需要的所有资源。54Keil C51的的库函数库函数含有含有100多种功能多种功能,其中大多数是可再入的。函数库支持所有的ANSI C的程序。库函数中的程序还为硬件提供特殊指令,例如nop、testbit、rol、r
41、or等,方便了应用程序的开发。Keil Vision的串口调试器软件串口调试器软件comdebug.exe,用于用于在电脑端能够看到单片机发出的数据,在电脑端能够看到单片机发出的数据,该软件无需安装,可直接在当前位置运行这个软件在当前位置运行这个软件。若读者需最新版,可到有关搜索网站输入关键词“串口调试器”,找到一个合适的下载网站,可即下载最新版本。当然,使用Windows自带的“超级终端”也是不错的选择。553.3.2 Keil Vision3软件的安装、启动和运行软件的安装、启动和运行1.软件安装软件安装 Keil Vision3的安装,同大多数软件安装一样,根据提示进行。安装完毕后,可在
42、桌面上看到Keil Vision3软件的快捷图标快捷图标。2.软件启动软件启动 点击桌面上的Keil Vision3软件的快捷图标,即可启动该软件,几秒后,出现编辑界面。3.软件的运行软件的运行56(1)建立一个新工程)建立一个新工程Keil Vision3把用户每一个应用程序设计都当作一个用户每一个应用程序设计都当作一个项目项目,用项目管理的方法项目管理的方法把一个应用程序设计中所需要用到的、互相所需要用到的、互相关联的程序链接在同一项目关联的程序链接在同一项目中。这样,打开一个项目时,所需的关联程序也都跟着进入了调试窗口,方便用户对项目中各个程序的编写、调试和存储。用户也可能开发多个项目,
43、每个项目用到了相同或不同的程序文件和库文件,采用采用项目管理项目管理,很容易区分,很容易区分不同项目中不同项目中所所用到的程序文件和库文件用到的程序文件和库文件。因此,在编写一个新的应用程序前,先建立项目的良好习惯。下面首先介绍如何建立一个新项57目。在编辑界面下编辑界面下,首先要建立一个点击“Project”菜单,选择下拉式菜单中的“New Project”,弹出文件对话窗口,选择要保存的路径,在“文件名”中输入一个程序项目名称,保存后的文件扩展名为文件扩展名为“.uv2”,这是Keil Vision3项目文件的扩展名,以后可直接点击此文件就可打开先前做的项目。点击“保存”后,这是会弹出一个
44、对话框,要求选择单片机的型号,用户可根据所使用的单片机来选择。Keil Vision3支持几乎所有的支持几乎所有的51内核的单片机。内核的单片机。58开始开始编写第一个程序编写第一个程序。点击“File”菜单,再在下拉菜单中单击“New”选项。此时光标在编辑窗口里闪烁,这时,用户可以输入代码了。输入完毕,单击菜单上的“File”,在下拉菜单中单击“Save As”,在“文件名”栏的编辑框中,键入文件名,同时,必须键入正确的扩展名。注意注意,如果用C语言编写程序,则扩展名为“.c”;如果用汇编语言编写程序,则扩展名必须为“.asm”。然后,单击“保存”按钮。上述工作完成后,还有有关项目的设置,程
45、序的编译59和链接,程序的调试。这些内容,读者可按Keil Vision3开发环境的帮助功能,进行反复练习和操作,从而熟练地掌握该软件的使用。3.3.3 C51程序的开发流程程序的开发流程C51程序开发与在Windows中运行的项目工程的开发有所不同,在Windows中,一般程序的编译结果是后缀名为“.exe”的可执行文件,该文件在Windows系统中能直接运行,而单片机C51程序的开发属于嵌入式开发,遵循主流的交叉编译模式,即在宿主机宿主机(运行Keil Vision3的PC机)上开发编译,在目标机(51系列单片机)上运行。在在60宿主机上的宿主机上的编译结果编译结果为为COFF文件文件或是
46、满足Intel规范的文件,文件包含了可执行的机器码,要经过编程器烧写到经过编程器烧写到单片机的程序区单片机的程序区(Flash ROM)才能执行。才能执行。一个单片机一个单片机C51应用程序的开发流程如下:应用程序的开发流程如下:在Keil Vision3中新建项目工程新建项目工程建立并编辑源文件建立并编辑源文件编译调试项目工程编译调试项目工程生成目标文件生成目标文件下载到程序存储器下载到程序存储器中中程序运行。程序运行。有关Keil Vision3的具体使用,请见Keil Vision3的使用操作说明。3.4 C51与汇编语言的混合编程与汇编语言的混合编程目前多数开发人员都在用C51开发单片
47、机程序,但61在一些速度速度和和时序时序敏感的场合下敏感的场合下,C51略显不足,而有些特殊的要求必须通过汇编语言程序来实现,但是用汇编语用汇编语言编写的程序远不如用言编写的程序远不如用C51语言编写的可读性好和效率高语言编写的可读性好和效率高。因此采用C51与汇编语言混合编程与汇编语言混合编程是解决这类问题的最好方案。C51编编译译器器在在头头文文件件“reg51.h”中中定定义义了了全全部部sfr/sfr16和和sbit变变量量。用用一一条条预预处处理理命命令令#include 把把这这个个头头文文件件包包含含到到C51程程序序中中,无无需需重重定定义义即即可可直直接接使使用用它它们的名称
48、。们的名称。62n#ifndef _REG51_H_ /先测试是否被宏定义过先测试是否被宏定义过n#define _REG51_H_n/*BYTE Register */字节寄存器字节寄存器nsfr P0 =0 x80;nsfr P1 =0 x90;nsfr P2 =0 xA0;nsfr P3 =0 xB0;nsfr PSW =0 xD0;nsfr ACC =0 xE0;nsfr B =0 xF0;nsfr SP =0 x81;nsfr DPL =0 x82;nsfr DPH =0 x83;nsfr PCON=0 x87;nsfr TCON=0 x88;nsfr TMOD=0 x89;nsfr
49、 TL0 =0 x8A;nsfr TL1 =0 x8B;nsfr TH0 =0 x8C;nsfr TH1 =0 x8D;nsfr IE =0 xA8;nsfr IP =0 xB8;nsfr SCON=0 x98;nsfr SBUF=0 x99;63n/*BIT Register */可位寻址的位变量可位寻址的位变量n/*PSW */nsbit CY =0 xD7;nsbit AC =0 xD6;nsbit F0 =0 xD5;nsbit RS1 =0 xD4;nsbit RS0 =0 xD3;nsbit OV =0 xD2;nsbit P =0 xD0;n/*TCON */nsbit TF1
50、=0 x8F;nsbit TR1 =0 x8E;nsbit TF0 =0 x8D;nsbit TR0 =0 x8C;nsbit IE1 =0 x8B;nsbit IT1 =0 x8A;nsbit IE0 =0 x89;nsbit IT0 =0 x88;64n/*IE */nsbit EA =0 xAF;nsbit ES =0 xAC;nsbit ET1 =0 xAB;nsbit EX1 =0 xAA;nsbit ET0 =0 xA9;nsbit EX0 =0 xA8;n/*IP */nsbit PS =0 xBC;nsbit PT1 =0 xBB;nsbit PX1 =0 xBA;nsbit