3.2 单片机的C51程序设计
3.2.1 C51基础知识
C语言是一种编译型程序设计语言,它兼顾了多种高级语言的特点,并具备汇编语言的功能。用C语言开发系统可以大大缩短开发周期,明显增强程序的可读性,便于改进、扩充和移植。而针对8051C语言日趋成熟,成为了专业化的实用高级语言。
一、 C51的特点
C语言作为一种非常方便的语言而得到广泛的支持,很多硬件开发都用C语言编程,如:各种单片机、DSPARM等。
C语言程序本身不依赖于机器硬件系统,基本上不作修改或仅做简单修改就可将程序从不同的单片机中移植过来直接使用。
C语言提供了很多数学函数并支持浮点运算,开发效率高,故可缩短开发时间,增加程序可读性和可维护性。
. 单片机的C51与汇编ASM—51相比,有如下优点:
1)对单片机的指令系统不要求了解,仅要求对8051的存储器结构有初步了解;
2)寄存器分配、不同存储器的寻址及数据类型等细节可由编译器管理;     
3)程序有规范的结构,可分成不同的函数,这种方式可使程序结构化; 
4)提供的库包含许多标准子程序,具有较强的数据处理能力; 
5)由于具有方便的模块化编程技术,使已编好程序容易移植;
3.2.2 C51的基本数据类型
当给单片机编程时,单片机也要运算,而在单片机的运算中,这个“变量”数据的大小是有限制的,不能随意给一个变量赋任意的值,因为变量在单片机的内存中是要占据空间的,变量大小不同,所占据的空间就不同。所以在设定一个变量之前,必须要给编译器声明这个变量的类型,以便让编译器提前从单片机内存中分配给这个变量合适的空间。单片机的C语言中常用的数据类型如下表所示:
数据类型
关键字
长度(bit
长度(byte
值域范围
位类型
bit
1
——
01
无符号字符型
unsigned char
8
1
0255
有符号字符型
char
8
1
-128127
无符号整型
unsigned int
16
2
065535
有符号整型
int
16
2
-3276832767
无符号长整型
unsigned long
32
4
0232-1
有符号长整型
long
32
4
-231-231-1
单精度实型
float
32
4
3.4e-38~3.4e38
双精度实型
double
64
8
1.7e-308~1.7e308
3.2.3 C51的基本运算
C语言的运算符分以下几种:
1、 算术运算符
顾名思义,算术运算符就是执行算术运算的操作符号。除了一般人所熟悉的
四则运算(加减乘除)外,还有取余数运算,如下表所示:
符号
功能
范例
说明
+
A=x+y
xy的值相加,其和放入A变量
-
B=x-y
x变量的值减去y变量的值,其差放入B变量
*
C=x*y
xy的值相乘,其积放入B变量
/
D=x/y
x变量的值除以y变量的值,其商数放入D变量
%
取余数
E=x%y
x变量的值除以y变量的值,其余数放入E变量
程序范例:
main()
int A,B,C,D,E,x,y;
    x=8;
    y=3;
    A=x+y;
    B=x-y;
    C=x*y;
    D=x/y;
    E=x%y;
}
程序结果
  A=11B=5C=24D=2E=2
2、关系运算符
  关系运算符用于处理两个变量间的大小关系,如下表所示。
符号
功能
范例
说明
==
相等
x==y
比较xy变量的值,相等则结果为1,不相等则为0
!=
不相等
x!=y
比较xy变量的值,不相等则结果为1,相等则为0
>
大于
x>y
x变量的值大于y变量的值,其结果为1,否则为0
<
小于
x<y
x变量的值小于y变量的值,其结果为1,否则为0
>=
大等于
x>=y
x变量的值大于或等于y变量的值,其结果为1,否则为0
<=
小等于
x<=y
x变量的值小于或等于y变量的值,其结果为1,否则为0
程序范例:
main()
{
    Int A,B,C,D,E,F,x,y;
    x=9;
    y=4;
    A=(x==y);
    B=(x!=y);
    C=(x>y);
    D=(x<y);
    E=(x>=y);
    F=(x<=y);
}
程序结果:
    A=0B=1C=1D=0E=1F=0
3、逻辑运算符
逻辑运算符就是执行逻辑运算功能的操作符号。
符号
功能
范例
说明
&&
及运算
(x>y)&&(y>z)
x变量的值大于y变量的值,且y变量的值也大于z变量的值,其结果为1,否则为0
||
或运算单片机编程100例详解
(x>y)||(y>z)
x变量的值大于y变量的值,或y变量的值大于z变量的值,其结果为1,否则为0
反相运算
!x>y
x变量的值大于y变量的值,其结果为0,否则为1
程序范例:
main()
{
    int A,B,C,x,y,z;
    x=9;
    y=8;
    z=10;
    A=(x>y)&&(y<z);
    B=(x==y)||(y<=z);
    C=!(x>z);
}
程序结果:
A=0B=1C=1
4、位运算符
位运算符与逻辑运算符非常相似,它们之间的差异在于位运算符针对变量中的每一位,逻辑运算符则是对整个变量进行操作。位运算的运算方式如下表所示:
符号
功能
范例
说明
&
及运算
A=x&y
xy变量的每个位,进行与运算,其结果放入A变量
|
或运算
B=x|y
xy变量的每个位,进行或运算,其结果放入B变量
^
异或
C=x^y
xy变量的每个位,进行异或运算,其结果放入C变量
~
取反
D=~x
x变量的每一位进行取反
<<
左移
E=x<<n
x变量的值左移n位,其结果放入E变量
>>
右移
F=x>>n
x变量的值右移n位,其结果放入F变量
程序范例:
main()
{
    char A,B,C,D,E,F,x,y;
    x=0x25;/*0010 0101*/
y=0x62; /*0110 0010*/
A=x&y;
B=x|y;
C=x^y;
D=~x
E=x<<3;
F=x>>2
}
程序结果:
x:  0010 0101      x:  0010 0101    x:  0010 0101      x: ~ 0010 0101  
y: &0110 0010     y: |0110 0010    y: ^0110 0010           1101 1010
0010 0000          0110 0111        0100 0111         
A=0x20            B=0x67        C=0x47          D=0xda
x的值左移三位的结果为:
0 0 1 0 0 1 0 1
0 0 1 0 0 1 0 1 0 0 0
移出的三位“001”丢失,后面三位用0填充,因此运算后的结果是00101000B,即E=0x28
x的值右移两位的结果为:
0 0 1 0 0 1 0 1
0 0 0 0 1 0 0 1 0 1
移出去的两位“01”丢失,前面两位用“0”填充;因此,运算后的结果是00001001B,即F=0x09
6、递增/减运算符
递增/减运算符也是一种很有效率的运算符,其中包括递增与递减两种操作符号,如下表所示:
符号
功能
范例
说明
++
1
x++
x变量的值加1
--
1
x--
x变量的值减1
程序范例:
main()
{
    int A,B,x,y;
    x=6;
    y=4;
    A=x++;
    B=y--;
}
程序结果:
A=7,B=3
   
3.2.4 C51的流程控制语句
C51中的基础语句
1while循环语句的格式如下:
While (表达式)
{
语句;
}
特点:先判断表达式,后执行语句。
原则:若表达式不是0,即为真,那么执行语句。否则跳出while 语句往下执行。
程序范例:
while(1)//表达式始终为1,形成死循环
{
    语句;
}
2for循环语句
for语句是一个很实用的计数循环,其格式如下:
格式:for(表达示1;表达示2;表达示3)
        {
                语句;
}
执行过程:
1)求解一次表达式1
2)求解表达式2,若其值为真(非即为真),则执行for中语句。然后执行第3步。否则结束for 语句,直接跳出,不再执行第3步。
3)求解表达式3
4)跳到第2步重复执行。
程序范例1a=0;
        for(i=0;i<8;i++)//控制循环执行8
        {
                a++;
}
程序执行结果:a=8
程序范例2a=0;
            for(x=100;x>0;x--)//控制循环执行100
            {
                a++;
}
程序执行结果:a=100
3if选择语句
if-else语句提供条件判断的语句,称为条件选择语句,其格式如下:
if(表达示)
{   
      语句1
}
else
{
        语句2
}
在这个语句里,将先判断表达式是否成立,若成立,则执行语句1;若不成立,则执行语句2。如下图所示:
其中else部分也可以省略,写成如下格式,流程图如下所示:
if(表达示)
{
        语句;
}
其它语句;
3.2.5 C51的函数
1、无返回值、不带参数的函数的写法
【例1】写出一个完整的调用子函数的例子,用单片机控制一个LED灯闪烁发光。用P1口的第一个引脚控制一个LED灯,1秒钟闪烁一次。
#include<reg52.h>            //头文件
#define uint unsigned int    //宏定义
sbit D1=P1^0;              //声明单片机P1口的第一位
uint x,y;
void main()
{   
    while(1)          //大循环
    {
        D1=0;          //点亮第一个发光二极管
        for(x=500;x>0;x--)
            for(y=110;y>0;y--);
        D1=1;          //关闭第一个发光二极管
        for(x=500;x>0;x--)
            for(y=110;y>0;y--);
    }
}
在上面的程序中,可以看到在打开和关闭发光二极管的两条语句之后,是两个完全相同的for嵌套语句,for(x=500;x>0;x--)
                            for(y=110;y>0;y--);
C语言中,如果有些语句不止一次用到,而且语句的内容都相同,那么就可以把这样的一些语句写成一个不带参数的子函数,当在主函数中需要这些语句时,直接调用这些语句就可以了。上面的for嵌套语句就可以写成如下子函数的形式:
void delay()    //延时子程序延时约z毫秒
{
        for(x=500;x>0;x--)
        for(y=110;y>0;y--);
}
其中void表示这个函数执行完后不返回任何数据,即它是一个无返回值的函数,delay是函数名,一般写成方便记忆和读懂的名字,也就是一看到函数名就知道此函数实现的内容是什么,但注意不要和C语言中的关键字相同。紧跟函数名的是一个空括号,这个括号里没有任何数据或符号(即C语言中的参数),因此这个函数是一个无参数的函数。接下来的两个大括号中的语句是子函数中的语句。这就是无返回值、无参数函数的写法。