C51语言

C51语言

  C51语言与标准C语言间有许多相同地方,但也有自身特点。不同的嵌入式C语言编译系统之所以与标准C语言有不同的地方,主要是由于它们所针对的硬件系统不同。对于8051单片机,目前广泛使用的是C51语言。
  C51语言基本语法与标准C相同,是在标准C的基础上进行适合8051内核单片机硬件的扩展,但与标准c又有不同之处:

  • 库函数不同:
      例如,在标准C中,库函数printf和scanf,常用于屏幕打印和接收字符,而在C51语言中,主要用于串行口数据的收发。
  • 数据类型有一定区别:
      例如,8051单片机包含位操作空间和丰富的位操作指令,因此,C51语言与标准C语言相比增加了位类型。
  • C51语言变量存储模式与标准C语言中变量存储模式数据不同:
      标准C最初是为通用计算机设计的,在通用计算机中只有一个程序和数据统一寻址的内存空间,而C51语言中变量的存储模式与8051单片机的各种存储器区紧密相关。
  • 数据存储类型不同:
      8051存储区可分为内部数据存储区、外部数据存储区以及程序存储区。
  • 其他不同:
      中断。标准C语言没有处理单片机中断的定义,而C51语言中有专门的中断函数。
      头文件。C51语言头文件必须把8051单片机内部的外设硬件资源(如定时器、中断、I/O等)相应的特殊功能寄存器写入到头文件内,而标准C不用。
      程序结构。由于8051单片机的硬件资源有限,它的编译系统不允许太多的程序嵌套。其次,标准C语言所具备的递归特性不被C51语言支持。

Keil C51支持的基本数据类型见下表
C51的数据类型
C51的注释写法有两种:
(1) //…… ,两个斜杠后面跟着的为注释语句,本写法只能注释一行,当换行时,必须在新行上重新写两个斜杠。
(2) /*……*/ ,一个斜杠与星号结合使用,本写法可注释任一行,即斜杠星号与星号斜杠之间的所有文字都作为注释,即注释有多行时,只需在注释的开始处,加斜杠星号,在注释的结尾处,加上星号斜杠即可。

  加注释的目的是为了便于读懂程序,所有注释都不参与程序编译,编译器在编译过程中会自动删去注释。

  C51语言允许通过使用关键字sfr、sbit或直接引用编译器提供的头文件来对特殊功能寄存器(SFR)进行访问,特殊功能寄存器分布在片内RAM高128字节中,只能采用直接寻址方式。
  (1)使用关键字定义sfr。为能直接访问特殊功能寄存器SFR,C51提供了一种定义方法,即引入关键字sfr,语法如下:
  sfr 特殊功能寄存器名字=特殊功能寄存器地址,例如:

sfr  IE=0xA8;	       //中断允许寄存器IE地址A8H
sfr  TCON=0x88;        //定时器/计数器控制寄存器地址88H

  在8051中,要访问16位SFR,要用关键字sfr16。16位SFR的低字节地址须作为“sfr16”的定义地址,例如:

sfr16  DPTR=0x82	//DPTR 的低8位地址为82H,高8位地址为83H。

  (2)通过头文件访问SFR。各种衍生型的8051单片机的特殊功能寄存器的数量与类型有时是不相同的,对其访问可通过头文件访问来进行。为用户处理方便,C51把8051(或8052单片机)常用的特殊功能寄存器和其中的可寻址位进行了定义,放在一个reg51.h(或reg52.h)的头文件中。当用户要使用时,只需在使用之前用一条预处理命令#include<reg51.h>把这个头文件包含到程序中,就可使用特殊功能寄存器名和其中的可寻址位名称了。用户可对头文件进行增减。头文件引用举例如下:

#include<reg51.h>	//包含8051单片机的头文件
void  main(void) 
{	
	TL0=0xf0;	//给T0低字节TL0设置时间常数,已在reg51.h中定义
 	TH0=0x3f;	//给T0高字节TH0设置时间常数,已在reg51.h中定义
 	TR0=1;	    //启动定时器0
	……
}

  (3)特殊功能寄存器中的位定义。对SFR中的可寻址位的访问,要使用关键字来定义可寻址位,共3种方法。

  • sbit 位名=特殊功能寄存器^位置;例如:
sfr   PSW=0xd0//定义PSW 寄存器的字节地址0xd0
sbit  CY=PSW^7//定义CY位为PSW.7,地址为0xd0
sbit  OV=PSW^2//定义OV位为PSW.2,地址为0xd2
  • sbit 位名=字节地址^位置; 例如:
sbit  CY=0xd0^7// CY位地址为0xd7
sbit  OV=0xd0^2// OV位地址为0xd2
  • sbit 位名=位地址(将位的绝对地址赋给变量,位地址必须在0x80~0xff。)例如:
sbit  CY=0xd7// CY位地址为0xd7
sbit  OV=0xd2// OV位地址为0xd2

【例】AT89C51单片机片内P1口的各寻址位的定义如下:

sfr   P1=0x90;    
sbit  P1_7= P1^7;   
sbit  P1_6= P1^6;   
sbit  P1_5= P1^5;   
sbit  P1_4= P1^4;   
sbit  P1_3= P1^3;   
sbit  P1_2= P1^2;   
sbit  P1_1= P1^1;   
sbit  P1_0= P1^0; 

1.算术运算符
c51算数运算符
c51算数运算
2.逻辑运算符
与或非
3.关系运算符
c51关系运算符
4.位运算
c51位运算
5.指针和取地址运算符
在这里插入图片描述

目标变量=*指针变量   //将指针变量所指的存储单元内容赋值给目标变量
指针变量=&目标变量	//将目标变量的地址赋值给指针变量

例如:

a=&b;		    //取b变量的地址送至变量a
c=*b;		    //把以指针变量b为地址的单元内容送至变量c

  指针变量中只能存放地址(即指针型数据),不能将非指针类型的数据赋值给指针变量。

1.分支控制语句
  (1)if语句用来判定所给定的条件是否满足,根据判定结果决定执行两种操作之一。
        if语句的基本结构1如下:
                    if (表达式) {语句}
  括号中的表达式成立时,程序执行大括号内的语句,否则程序跳过大括号中的语句部分,而直接执行下面的其他语句。例如:

   if (x>y)  {max=x; min=y;}    //如果x>y,则x赋给max,y赋给min。如果x>y不成立,则不执行大括号中的赋值运算。

        if语句的基本结构2如下:
                 if (表达式) {语句1;} else {语句2;}
  括号中的表达式成立时,程序执行大括号内的语句1,否则程序跳过大括号中的语句1部分,而直接执行else部分大括号内的语句2。例如:

if (x>y){max=x; }     //如果x>y,则max赋值为x
else {max=y;}         //否则max赋值为y

        if语句的基本结构3如下:
                 if (表达式1) {语句1;}
                 else if (表达式2) {语句2;}
                 else if (表达式3) {语句3;}
                 ……
                 else {语句n;}
  if 和 else if 本质上是互斥的,当if(表达式1) {语句1;}执行后直接跳过else if(表达式) {语句;},若执行else if (表达式2) {语句2;}时,表示if(表达式1)为假,语句1没有被执行。例如:

if (x>100) {y=1;}            //若x>100,则y=1
else  if (x>50) {y=2;}       //若100>x>50,则y=2
else  if (x>30) {y=3;}       //若50>x>30,则y=3
else  if (x>10) {y=4;}       //若30>x>10,则y=4
else  {y=5;}                 //若x<10,则y=5

  (2)switch语句。if语句只有两个分支可选择,而switch语句是多分支选择语句。switch语句的一般形式如下:
                 switch (表达式1)
                 {
                  case 常量表达式1:{语句1;}break;
                  case 常量表达式2:{语句2;}break;
                  ……
                  case 常量表达式n:{语句n;}break;
                  default:{语句n+1;}
                 }
  switch语句说明:

  1. 每一case常量表达式须互不相同,否则将混乱。
  2. 各个case和default出现次序,不影响程序执行的结果。
  3. switch括号内表达式的值与某case后面的常量表达式的值相同时,就执行它后面的语句,遇到break语句则退出switch语句。
  4. 若所有的case中的常量表达式的值都没有与switch语句表达式的值相匹配时,就执行default后面的语句。
  5. 如果在case语句中遗忘了break语句,则程序执行了本行之后,不会按规定退出switch语句,而是将执行后续的case语句。
  6. switch语句的最后一个分支可以不加break语句,结束后直接退出switch结构。

   【例】在单片机程序设计中,常用switch语句作为键盘中按键按下的判别,并根据按下键的键号跳向各自的分支处理程序。

input:  keynum=keyscan( )  //keyscan( )是另行编写的一个键盘扫描函数,如有键按下,该函数就会得到按下键的键值,将键值赋予变量keynum
switch(keynum) 
{	
	case 1:	key1( ); break;	//如果按下键为1键,则执行函数key1( )
	case 2:	key2( ); break;	//如果按下键为2键,则执行函数key2( )
	case 3:	key3( ); break;	//如果按下键为3键,则执行函数key3( )
	……
	case n:	keyn( ); break;	//如果按下键为n键,则执行函数keyn( )
 	default:goto input
}

2.循环控制语句
  实现循环结构的语句有以下3种:while语句、do-while语句和for语句。
(1)while语句。语法形式为:
                  while(表达式)
                  {
                   循环体语句;
                  }

  先判断表达式是否为真,如果表达式为真,就重复执行循环体语句;反之,则终止循环体内的语句。

(2)do-while语句。语法形式为:
                  do
                  {
                   循环体语句;
                  }
                  while(表达式);

  先执行循环体语句,然后判断表达式是否为真,如果表达式为真,就重复执行循环体语句;反之,则终止循环体内的语句。

(3)for语句。for语句不仅可用于循环次数已知的情况,也可用于循环次数不确定而只给出循环条件情况。语法形式为:
                 for(表达式1;表达式2;表达式3)
                 {
                   循环体语句;
                 }

  表达式可为空,但不能省略,若for(;;),小括号内只有两分号,无表达式,这意味着没有设初值,无判断条件,循环变量为增值,它的作用相当于while(1),为无限循环。若for语句的3个表达式中,表达式1缺省,即不对i设初值(可在循环之前设置初值)。或表达式2缺省,即不判断循环条件。或表达式3缺省,即每次循环后变量i不变化,那么判断条件2会一直为真(或一直为假,不执行循环。表达式2变量可在循环语句中手动添加),则认为表达式始终为真,循环将无休止地进行下去,相当于while(1),为无限循环。

  • 表达式1是进入第一次for循环之前运行了,并且只会执行一次
  • 表示式2是for循环的执行条件,满足这个条件后才能进知入循环里面的语句
  • 表达式3是在执行一次循环后执行的语句

  若for循环没有循环体,则为软件延时,即循环执行指令,消磨一段已知的时间。如果使用12MHz晶振,则12个时钟周期花费的时间为1µs。
  
  
(1)break语句
  循环结构中,可使用break语句跳出本层循环体,马上结束本层循环。
(2)continue语句
  循环结构中,可使用continue语句跳出本层循环体,停止当前这一层循环,然后直接尝试下一层循环。
(3)goto语句
  无条件转移语句,当执行goto语句时,将程序指针跳转到goto给出的下一条代码。

3.数组

(1)一维数组
    类型说明符 数组名[元素个数];
  可对数组进行整体初始化,即对数组中每个元素都进行赋值(可以不定义元素个数);也可定义元素个数,对其中一些元素进行赋值,未赋值的默认为0。可以在定义时进行整体初始化,也可在定义后单个地进行赋值。
例:int a[3]={2,4,6};
(2)多维数组
    类型说明符 数组名[元素行数][元素列数];
  可对数组进行整体初始化,即对数组中每个元素都进行赋值(可以不定义元素行数列数);也可定义元素行数列数,对其中一些元素进行赋值,未赋值的默认为0。可以在定义时进行整体初始化,也可在定义后单个地进行赋值。
例:int a[3][4]={1,2,3,4},{5,6,7,8},{9,10,11,12};
(3)字符数组
  若一个数组的元素是字符型的,则该数组就是一个字符数组。
例:char a[7]= {‘B’,‘E’,‘I’,‘J’,‘I’,‘N’,‘G’};
  还允许用字符串直接给字符数组置初值,数组的元素数目一定要比字符多一个,以便C51编译器自动在其后面加入结束符‘\0’。
例:char a[10]= {“BEI JING”};

  • 20
    点赞
  • 112
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值