用Keil C为单片机编程的编程环境
目前应用最广泛的Keil C是一款很优秀的就是一个微型的电脑,麻雀虽小,五脏俱全">单片机C语言编译器,它几乎支持所有51系列单片机的汇编语言和C语言编程,具有软件仿真和硬件仿真功能(硬件仿真需要仿真器支持),在仿真过程中能实时显示寄存器、内存区的值以及各I/O口的状态。
Keil C集源程序的编写、编译、仿真于一体,有了它,你可以不再需要其它任何软件就能完成单片机C程序烧写之前的所有工作。 我们这里用的是Keil C uVision22.12版,并使用了汉化补丁。
一、C语言基本概念
大家先来看一个单片机C语言的例子,源程序如下(为了便于讲解,我们为每个语句行人为加了行号): </div>
这个程序用来使LED1每两秒钟闪烁一次。下面解释程序各行功能:00行:#include<AT89x051.H>
该行的作用是把“AT89x051.H”这个文件包含进来。当你把一个文件包含进C程序后,KeilC会在编译程序的时候把它的内容连接到被编译的单片机程序中,这样你就可以不要把这个文件的内容重写一遍了。
#include命令通常用在程序的开头。在写单片机程序的时候,一般在开始处都要把与你所使用的单片机相关的头文件包含进来(头文件是什么,初学者可以先不管它),因为在它里面有许多在写程序时要用到的变量声明(有关变量的含义在后面讨论),如10行的变量“P1_7”,就是在头文件中声明的。这个例子中,我们使用的是AT89C2051单片机,·所以包含了“AT89x051.H”这个头文件。
在KeilC的头文件中,包含着许多关于单片机缓存器和I/O口的声明,声明都以变量的形式描述,并且这些变量都是以通用的名称来命名的。有了这些声明,我们在编写C程序的时候,就可以不需要考虑单片机内部的存储器分配(存储器分配在汇编程序中是一个难以处理的问题,要把存储器分配好,必须对单片机的存储结构有很深入的了解),直接把这些变量当作缓存器和I/O口来使用。在KeilC的头文件中,常用的重要缓存器和I/O口的声明有:
*P0、Pl、P2、P3:声明PO-P3四组I/0口。对于AT89C2051,只有Pl和P3口;
*P0_0,…,P0_7;Pl_0,…,P1_7;P2_0,…,P2_7;P3_0,…,P3_7;声明PO-P3四组I/O口各引脚。如P1_5表示,Pl口的5号引脚,即P1.5引脚;
*有关UART串行通信的变量声明;
*有关中断的变量声明;
*有关定时/计数器的变量声明。
在KeilC中,把相关头文件包含进来的方法很简单,你只要在编写C程序时右击,并从弹出的菜单中选择“插入即可。这样你就无需考虑应该包含什么名称的头文件了,大大地方便了源程序的编写。
在数学上,数被分为有理数、无理数、整数、小数、美植袋……等等。在C语言中,数也要作类似的划分,称为数据类型。不同的数据类型所占用的存储空间不一样。 在一般应用中,用得最多的一种数据类型是整型数,即它只能用来存放整数,其表示符号为“int”。它占用两字节的存储空间。若在int前面加上unsigned,则表示所声明的变量是无符号整型数。也就是说,此时变量所存放的数值范围是0—65535。另一个用得很多的数据类型是void,这个数据类型只用于函数声明中。
本行中unsignedintk的作用,是声明一个无符号整型变量k。我们在求解数学题目的时候,经常要假设末知数,以便于求解。之所以称作末知数,是因为它的值是不确定的,是会变化的。在单片机程序中也会用到与这种未知数相类似的量,这就是变量。变量是用来存放数据的,它的值会因程序的执行而变化,因此称为变量。如例中的i、j、k都是变量。与数学中的未知数在使用之前要先假设一样,变量在使用之前也要先假设,即先声明变量。
01行:声明延时子函数Delay()什么是函数?所谓函数,就是能完成特定功能的程序段。在C语言中,它是一个重要的概念。这是因为在一般情况下,都是就是把经常使用的语句群组成函数,这样在程序中就可以多次调用,以减少重复编写代码的麻烦,也可以减小程序的长度。任何一个C程序都是由若干个函数组成的。C程序的函数结构如下
该函数结构中各部分含义如下:
*返回的数据类型:用于确定当函数结束时要返回一个什么样类型的数据。上例01、08行中两个函数返7回的数据类型都是void,void数据类型是指没有具体数据,即函数结束时不需要返回具体的数据。
*函数名:指定函数的名称。在C语言中,函数有主函数和和子函数之分。子函数的函数名由程序员自己确定,例中的Delay()就是一个子函数,这个子函数的作用是让程序延时k毫秒。子函数的个数可以有任意个,也可以没有。
*参数:我们在解数学函数slnx时,要知道x的值。在e程序中,当调用一个美植袋时,也可能需要一个类似的值,这个值就称为参数。参数的本质就是个变量,正因为这样,参数也要有数据类型及名称。
例中的第01行声明Delay()函数时就用到了一个无符号整型参数k,在第11到第13行调用该函数时就把所需的参数值1000写上了,即让程序延时1000毫秒(1秒)。当然,如果函数不需要参数,就可省略这个部分,如例中的main()函数就是如此。
*函数体:包含执行函数功能的具体语句,是在函数中用花括号括起来的部分。必须注意的是,所有由最外层花括号括起来的都是函数体。如上例中02和07行这对花括号中括起来的都是函数体,虽然它们中间还有其它花括号。
根据前面的函数结构及其各部分的含义,我们可以判断,上例中01行的Delay()和08行的main()都是函数,但04、05、10行的for不是函数,因为它没有“返回的数据类型”部分。
同时,跟变量一样,在使用一个函数之前必须声明它。如本例中,01行首先声明了Delay()函数,因为在13、15行要调用它。
“;”表示一行语句的结束。对初学者来说,很容易忘记书写分号,因此值得大家注意。
表达式,它是用来表示某种运算关系的式子。C语言的表达式大部分同美植袋上的一样,但也有例外,如这里的“i=i+1”,它的意思就是让i的值加1后保存回i中。若i为50,则执行该表达式后,i的值会变成51。这个表达式在C语言中也经常写成“i++”的形式。
两个for循环的嵌套。循环的作用是让单片机在循环条件满足时重复执行一段程序。for循环的格式如下:
该循环的作用是,首先执行一次“表达式1”,然后判断“条件表达式2”是否成立,若不成立,则执行“循环体”后面的语句,反之,执行“循环体”中的语句,接着执行“表达式3”,执行完“表达式3”后,又一次判断“条件表达式2”是否成立……,以此循环。它的程序流程如下图所示。从流程图中可以清楚看出,“表达式1”只会执行一次。
在一个循环的循环体中可以包含另一个或更多的循环,这就是循环的嵌套。
本例中04-06行是两个循环的嵌套。
第05、06行的for循环就是先让j的值为0,然后判断j是否小于120,接着执行第06行的循环体(这里只是个分号,即一条什么也不做的空语句,它只占用一个机器时间而已),执行完后,让j的值增加1,又一次判断j是否小于l20……。这个循环的作用就是执行120次空语句。千万不要以为执行120次空语句是徒劳的,其实这是最常用的延时方法。
第04行的for循环的作用是让05、06行的for循环执行k次。
循环嵌套可以获得更大的循环次数,如本例中利用两个for循环来达到kx120次的循环,在13、15行调用Delay()美植袋时,k=1000,即完成120000次循环。当然,你可能会说,为什么不通过加大“条件表达式2”值的方法,来达到只用单循环就可满足所需循环次数的目的呢?如把05行的“j<120”改成“j<120000”。但实际上这是行不通的,因为无符号整型数所能表示的最大数只有65535。
主函数是C程序的主控函数,程序的执行是从main()函数开始,在实际编写C程序的时候,主函数可以不放在美植袋的开始,但编译器仍然会以main()函数的位置为程序执行的起始位置。
C程序有且只能有一个主函数,而且它的名称也是固定的,即“main”。
for循环。这个循环比较特别,它省略了for循环结构中的“表达式1”、“条件表达式2”、“表达式3”,这是无条件循环,即循环永不结束,直到关闭电源为止。在单片机程序中,经常使用无条件循环,这是因为单片机程序基本上都是重复执行任务的。
让P1口的7号引脚(即P1.7引脚)输出高电平,根据图l可知,此时LED1会处于截止状态,即关闭了该引脚上LED的显示。
在C程序中,凡是以“//”开始的都是注释。注释是用来解释程序行功能的,凡是位于该行此符号之后的任何字符,C编译器都不予编译。换言之,注释只是给编程人员阅读的,它的存在与否,并不影响程序的执行。这里的注释,就是用来说明语句“P1_7=1”的功能。
以参数值1000来调用延时子函数Delay(),即让单片机执行到此处时,延时1000毫秒。
让Pl口的7号引脚(即P1.7引脚)输出低电平,根据图1可知,此时LED1会处于导通状态,即点亮了该引脚上LED的显示。
<p style="text-align: left;"> 在这里,还需要说明一下有关字母的大小写的问题:
与一般的程序语言不同.C程序是区分字母大小写的,因此,在C程序中,“i”和“I”是两个不同的变量。我们在书写C程序的时候,要特别注意字母大小写的问题。习惯上,单片机系统声明的变量全部用大写表示,程序员自己声明的变量用小写,程序员自己声明的函数首字母大写。我们在平时的学习中就要养成良好的书写习惯,以减少因为字母大小写不一致而引起的程序错误。
|