1.2 简单C程序介绍

为了说明C语言源程序结构的特点,先看下面例1-1所示的程序。这个程序用C语言编写,其功能是:控制单片机内部的一个数据不断加1递增,用8个发光二极管显示变化过程;当按下开关时,蜂鸣器鸣叫。用Keil C51执行C程序时,由于单片机没有标准的显示输出设备,只能通过单片机的串行口进行仿真显示,需调用串行口初始化子函数init_rs232()。从这个例子中可以了解到组成一个C语言源程序的基本部分和书写格式。

【例1-1】

      #pragma symbols code                 /* 定义编译环境:产生符号列表、产生汇编程序列表*/
      #include<stdio.h>                   // 包含输入、输出库函数
      sfr P0=0x80;                        // 定义特殊功能寄存器P0的地址
      sfr P1=0x90;                        // 定义特殊功能寄存器P1的地址
      sfr P4=0xe8;                        // 定义特殊功能寄存器P4的地址
      sfr T2CON=0xc8;                     // 定义特殊功能寄存器T2CON的地址
      sfr SCON=0x98;                      // 定义特殊功能寄存器SCON的地址
      sfr RCAP2H=0xcb;                    // 定义特殊功能寄存器RCAP2H的地址
      sbit kg=P4^3;                       // 定义开关的位地址
      sbit fmq=P1^5;                      // 定义蜂鸣器的位址
      void delay(int time)                /* 延时子函数,单位为ms */
      { unsigned char tt;                 // 定义辅助无符号字符变量tt
        while(time!=0){                   // 循环执行,次数由变量time的值确定
        --time;
        for(tt=0;tt<226;++tt){}           // 内部循环执行226次
        }
      }
      void init_rs232(void)               // 串行口初始化子函数
      { T2CON=0x34;                       // 定时器2作为波特率发生器,自动重装
        SCON=0xda;                        // 方式3,9位数据,单机通信,允许接收,TB8=1
        RCAP2H=0xff;
      }
      main()                              // 主函数
      { unsigned char kk=0;               // 定义辅助无符号字符变量kk
        init_rs232();                     // 调用串行口初始化子函数,用于仿真显示
        printf("Hello! I am C51\n");      // 仿真显示字符串"Hello! I am C51"
        printf("I will be your friend!\n");// 仿真显示"I will be your friend!"
        for(;;){                           // 无限循环
        kk=kk+1;                           // 变量kk加1
        P0=kk;                             // 变量kk的值通过8个发光二极管显示,“0”——亮
        printf("%bu\n",kk);                // 仿真显示变量kk的值
        if(kg==0){ fmq=0; }                // 如果按下开关,蜂鸣器响
        else{ fmq=1; }                     // 否则蜂鸣器不响
        delay(1000);                       // 调用延时子函数,延时1000ms
        }
      }

和上面C语言程序对应的汇编语言程序如下。

        ORG 0000H;                1——伪指令,表示程序存放的首地址
      begin: MOV P0,R1;           2——将R1的数据送到P0口引脚,输出0V时发光二极管点亮
              CALL DELAY;         3——调用0.5s延时子程序
              INC R1;             4——将R1的数据加1
              JB  0EBH,ddd;       5——如果未按下开关(P4.4=0EBH) ,跳到ddd
              CLR P1.5;           6——按下开关,引脚P1.5输出0V,蜂鸣器响
              JMP begin;          7——跳到begin
        ddd: SETB P1.5;           8——未按下开关,引脚P1.5输出5V,蜂鸣器不响
              JMP begin;          9——跳到begin
      ;---------------------     10——延时子程序
      DELAY: MOV R5,#04H;        11——R5=延时时间
      H0:   MOV R6,#0ffH;        12——R6=循环次数
      H1:   MOV R7,#0ffH;        13——R7=循环次数
      H2:   DJNZ R7,H2;          14——R7减1,如果不等于0,跳到H2
            DJNZ R6,H1;          15——R6减1,如果不等于0,跳到H1
            DJNZ R5,H0;          16——R5减1,如果不等于0,跳到H0
            RET;                 17——子程序结束标志
      ;---------------------
            END ;                18——伪指令,表示程序结束

通过上述例子,可知C语言程序具有以下基本结构特点。

(1)一个C语言程序一般由3个部分组成:预处理部分、子函数部分和主函数部分。

(2)预处理部分类似于汇编语言的伪指令,是在C语言程序执行前对编译器所下的指示,主要用于控制编译过程和定义变量。

(3)函数的主体必须以大括号“{}”包含其中。

(4)子函数部分类似于汇编语言的子程序,完成一些使用较频繁且比较通用的功能。子函数一般由自己编写,同时C语言提供大约100多个常用子函数(常称为库函数)。

(5)一个C语言程序不论由多少个部分组成,都有一个且只能有一个main函数,即主函数。

(6)一个C语言程序,总是从main()函数开始执行,而不论其在程序中的位置。当主函数执行完毕时,即程序执行完毕。

(7)如果调用库函数,需在预处理中进行说明。如printf为库函数,其函数声明在文件stdio.h中,在预处理中需加入#include<stdio.h>命令进行说明。

(8)每一个说明,每一个语句都必须以分号结尾。但预处理命令,函数头和花括号“}”之后不能加分号。

(9)标识符、关键字之间必须至少加一个空格以示间隔。若已有明显的间隔符,也可不再加空格来间隔。

(10)C语言程序注释有两种写法。一种以“//”开头,编译器会把“//”之后的文字全部当做注释,直到此行的尾端。另一种方式是用“/* ……… */”的形式,可以为C程序的任一部分做注释,在“/*”开始后,一直到“*/”为止,它中间的任何内容都被认为是注释,两者之间不限制行数。

(11)C语言程序行的书写格式自由。既允许一行内写几条语句,也允许一条语句分写在几行上。

(12)C语言程序区分字母大小写,所以不要将字母大小写混用,如main不可写成MAIN。