首页 理论教育基于C语言的单片机原理与应用

基于C语言的单片机原理与应用

【摘要】:表4-3 C51支持的数据类型续表注:数据类型中加底色的部分为C51语言扩展的数据类型。C51语言中使用的数据类型包括C语言中标准的数据类型和C51语言扩展的数据类型。C51语言扩展的数据类型有位类型、可位寻址的位类型、特殊功能寄存器和16位特殊功能寄存器型等。另外,C51语言还支持由基本数据类型组成的数组、结构体、联合体和枚举类型等结构类型数据。

我们很早就和数字打交道,从自然数到分数,从分数到小数,从有理数到无理数,从实数到复数。计算机是处理数字的机器,我们平时使用的这些数据,计算机能直接处理吗?如果从使用者的角度来说是能直接使用的,但从开发的角度来说是不能直接使用的,首先任何计算机都是由处理位数限制的,换句话说,就是用计算机系统来表达数据是有一个范围的,而我们现实中,数的大小是无限的。其次,计算机内部表示数据都是用高低电平来表示,或者说是用二进制来表示,理论上可以无限表示,实际中由于表示位数不可能无限大,所以也是有一定范围的。如何用计算机内部有限的位数来表示现实中具体的数,这个问题在不同的学科和教材上都讲过,即“数据在计算机中表示方式和信息编码”,这个也是学习计算机入门的首要问题,许多同学在学习这部分知识时总是感觉很抽象,似懂非懂。今天,我们通过学习单片机最基本的工作原理来理解这一问题。

4.3.1 C51语言的数据类型

C语言对数据大小进行了限制。在C语言中,对数据类型的描述包括数据的表示方式、数据长度、数值范围和构造特点等。程序设计中用的数据可分为常量和变量,各种变量先说明类型,然后才能使用。这个地方有一点复杂的是,在C51里的数据范围和其他编程环境还可能不完全一样,因此表4-3仅仅代表的是C51支持的数据类型。

表4-3 C51支持的数据类型

续表

注:数据类型中加底色的部分为C51语言扩展的数据类型。

C51语言中使用的数据类型包括C语言中标准的数据类型和C51语言扩展的数据类型。C语言中标准的数据类型有无符号字符型、有符号字符型、有无符号整型、有符号整型、无符号长整型、有符号长整型、浮点型和指针型等。C51语言扩展的数据类型有位类型、可位寻址的位类型、特殊功能寄存器和16位特殊功能寄存器型等。

另外,C51语言还支持由基本数据类型组成的数组、结构体、联合体和枚举类型等结构类型数据。

实际使用时,应尽量避免使用有符号的数据类型,因为单片机处理无符号数更容易一些,生成的指令代码更简洁。另外,还要尽量避免使用浮点数据类型,因为使用浮点数时,C语言编译器要调用库函数,程序会变得庞杂,运算速度会变慢。常用的数据类型有“bit”和“unsigned char”,这两种数据类型可以直接支持机器指令,运算速度很快。

4.3.2 常量与变量

什么是变量?什么是常量?变量自然和常量是相对的。常量就是1、2、3、4.5、10.6……等固定的数字,而变量则和数学中学的x是一个概念,可以让它是 1,也可以让它是2,让它是几是程序说了算的。

1.常 量

是指在程序的运行过程中,其值不能被改变的量。常量可以有不同的数据类型,其中包括整型、浮点型、字符型、字符串型和位类型。

(1)整型常量:即整型常数,可以表示为十进制数、十六进制数等。十进制的整数表示方法非常简单,如29、-18、156等。十六进制的整数通常以0x(或0X)开头,如0xFE、0xD7A9、0x7D等。八进制的整数则以0开头,如057,其值相当于十进制的47。

(2)浮点型常量(实数):实数有两种表示方法,一种是十进制的小数形式,如0.625、-16.5等;另一种是采用指数形式,即用e(或E)后面跟一个整数,表示以10为底的幂指数,如256.5的表示方法是2.565e2。

(3)字符型常量:字符型常量的表示方法是用单引号引出,如‘a’、‘B’等。

(4)字符串常量:字符串常量用双引号引出,如“GOOD”“thank you”等。

(5)位类型常量:位类型的值是一位二进制数“0”或“1”。

常量可以是数值型常量,也可以是符号常量。数值型常量可以直接使用,符号常量在使用之前必须在程序开头,使用编译预处理命令“define”进行定义(宏定义),其格式如下:

符号常量通常用大写字母表示,以区别程序中的变量。在编写程序时,使用符号常量代替程序中多次出现的常量,便于修改程序。例如,

定义了符号常量以后,在程序中凡是用到3.14159的地方,可以用符号常量PI代替。又如,表示逻辑表达式值的符号常量TURE、FALSE,其定义如下:

2.变 量

变量是指在程序运行中,其值是可以改变的量。每个变量都有一个变量名,在内存中占据一定的存储空间,并在该存储单元中存放该变量的值。

变量由变量名和变量值组成,变量名是存储单元地址的符号表示,而变量值就是该单元存放的内容。在使用中区分变量名、变量值和变量地址这三个不同的概念,变量名和变量地址为一个变量的两种表示方式,在C51语言中一般使用变量名。

变量必须先定义、后使用,用标识符作为变量名,并指出所用的数据类型和存储模式,这样编译系统才能为变量分配相应的存储空间。变量的定义格式如下:

其中,数据类型和变量名是必要的,存储种类和存储器类型是可选项。下面通过任务4.1源程序清单来说明变量的应用。

任务4.1源程序清单:

在这个程序中定义了一个unsigned int i,用来控制循环的次数,通过keil调试状态下查看其Symbols,如图4-18所示,变量“i”的内存地址为0x08,当前值为0x7530,十进制表示为30000,存储类型为data。在这个图中也发现main是函数类型,其存储类型为code,地址为0x0003。

图4-18 keil软件调试状态下的Symbols

下面对与变量存储有关的存储种类和存储器类型进行介绍。

1)存储种类

存储种类是指变量在程序执行过程中的作用范围。C51变量的存储种类有四种,分别是动态(auto)、(extern)、静态(static)和寄存器(register)。

(1)动态变量。使用auto定义的变量为动态变量,动态变量是在函数内部定义的变量。只有在函数被调用时,系统才给动态变量分配存储单元,函数执行结束时释放存储空间。

定义变量时,如果省略存储种类,则系统默认为动态变量。

(2)外部变量。使用extern定义的变量为外部变量,外部变量是在函数外部定义的变量,也称为全局变量。

如果在函数体内,要使用一个该函数体外定义过的变量或使用一个其他文件中定义的变量,该变量在函数体外要予以说明。

例如,在文件ex1.c中定义了变量unsigned char i,在另一文件ex2.c中需要使用变量i,则需要在函数体外先进行外部变量说明。

(3)静态变量。使用static定义的变量为静态变量。静态变量可分为内部静态变量和外部静态变量,静态变量在程序运行过程中,始终占用存储单元。内部静态变量:在函数体内部定义的静态变量为内部静态变量,只能在函数体内部使用。外部静态变量:在函数体外部定义的静态变量为外部静态变量,在整个程序运行中一直存在,可以被当前文件中的多个函数使用。

(4)寄存器变量。使用register定义的变量称为寄存器变量。用register定义的变量放置于CPU内部RAM的寄存器中,其处理速度快。但是,可以定义的变量数目有限。

2)存储器类型

C51中通过存储器类型指定变量的存储区域,存储器类型可以由关键字直接指定。定义变量是可以省略存储器类型,C51编译器按默认模式确定存储器类型为data。

(1)bit位变量。是C51语言扩展数据类型。bit位变量定义的变量,存放在内部RAM可以位寻址的区域。存储器类型可以是data、bdata、idata。bit位变量定义的格式如下:

例如:

C51编译时,位地址是变化的。

2)sbit可位寻址的位变量。sbit可位寻址的位变量定义格式如下:

在C51编译时,sbit可位寻址的位变量对应的位地址是不变的,可以通过三种方式定义。

例如,对P1端口的P1.1位的定义,有三种方法。

方法一:sbit位变量名=位地址。

方法二:sbit位变量名=特殊功能寄存器名^位位置。

方法三:sbit位变量名=字节地址^位位置。

C51中,用符号“^”标识特殊功能寄存器中的位。例如:

这种方法和方法二本质上是一致的。

4.3.3 运算符与表达式

C语言的运算符非常丰富,在程序中使用这些运算符来处理各种基础操作,从而完成特定的功能。C语言的运算符主要有以下几种:

1.算术运算符与算术表达式(www.chuimin.cn)

+:加法运算符,或为取正值运算符。例如,3+5、A+B、+23。

-:减法运算符,或为取负值运算符。例如,18-17、TIME1-TIME2、-78。

*:乘法运算符。例如,5*8、AD*AF。

/:除法运算符。在这里除法运算符和一般的算术运算规则有所不同,如果是两个浮点数相除,结果也是浮点数。如果两个整数相除,结果也是整数。例如,10.0/20.0结果为0.5,7/2结果为3,而不是3.5。

%:求余运算符。%两侧均应是整数。例如,10%3结果为1。

在上述的运算符中,我们同样可以用“()”来改变运算的优先级,如(A+B)*C就需要先计算A与B的和,再计算与C的积。

由算术运算符和括号将操作数连接起来的式子称为算术表达式。

2.赋值运算符

=:赋值运算符。在C语言中用于给变量赋值,用赋值运算符将一个变量与一个表达式连接起来的式子称为赋值表达式。其格式如下:

在赋值表达式后面加“;”构成赋值语句。其格式如下:

例如:

在赋值运算中,当“=”两侧数据类型不一致时,系统自动将右边表达式的值转换为与左侧变量一致的数据类型,再赋值给变量。

3.自增、自减运算符

++:自增运算符。作用是使变量的值自增1。例如,I++,表示让变量I的值自增1。

——:自减运算符。作用是使变量的值自减1。例如,A——,表示让变量A的值自减1。

4.关系运算符与关系表达式

关系运算符通常是用来判别两个变量是否符合某个条件的,所以使用关系运算符的运算结果只有“真”或“假”,即“1”或“0”两种。

>:大于。例如,A>B。

<:小于。例如,NUM1<li="">

>=:大于等于。例如,U>=5。

<=:小于等于。例如,P<=7。

==:等于。例如,TEAM1==TEAM2,在这里要区别于赋值运算符“=”,它表示的意思不是将TEAM2的值赋给TEAM1,而是用来判定TEAM1是不是同TEAM2的值相等。

!=:不等于。例如,A!=B。

用关系运算符将两个表达式连接起来的表达式称关系表达式。

5.逻辑运算符与逻辑表达式

逻辑运算符有三种,“&&”“||”和“!”。逻辑表达式是由逻辑运算符连接起来的表达式。逻辑表达式的值为逻辑值,即“真”或“假”,分别用“1”或“0”表示。

6.位运算符与位表达式

单片机通常通过I/O端口控制外部设备完成相应的操作,例如,单片机控制电动机转动、信号灯的亮灭、蜂鸣器的发声及继电器的通断等。这些控制均需要使用I/O端口某一位或几位。因此,单片机应用中位操作运算符是很重要的运算分支,C51语言支持各种位运算。

位运算也是C语言的一大特色。所谓位运算,形象地说就是指将数值以二进制位的方式进行相关的运算,参与位运算的数必须是整型或字符型的数据,实型(浮点型)的数不能参与位运算。

&:按位“与”运算符。它是实现“必须都有,否则就没有”的运算。它的规则如下:

在实际应用中,按位“与”运算常用来对某些位清零或保留某些位。

例如,A的值为:A=1001 0010。

若只想保留A的高四位,则用:A&1111 0000。

“与”运算后A的值为:1001 0000。

|:按位“或”运算符。它是实现“只要其中之一有,就有”的运算。它的规则如下:

在实际应用中,“或”运算常用来将一个数值的某些位定值为“1”。

例如,A的值为:A=1001 0010。

想将A的低四位定值为1,则用:A|0000 1111。

“或”运算后A的值为:1001 1111。

^:按位“异或”运算符。它是实现“两个不同就有,相同就没有”的运算。它的规则如下:

在实际应用中,“异或”运算常用来使数值的特定位翻转。

例如,A的值为:A=1001 1010。

若想将A的低四位翻转,即0变1,1变0,则用:A^0000 1111。

“异或”运算后A的值为:1001 0101。

~:按位“取反”运算符。它是实现“是非颠倒”的运算。它的运算规则如下:

例如,A的值为:1001 1010。

按位“取反”运算后,其值为:0110 0101。

<<:“左移”运算符。它是实现将一个二进制数的每一位都左移若干位的运算。“左移”运算的方法如图4-19所示。

图4-19 左移运算

>>:“右移”运算符。它是实现将一个二进制数的每一位都右移若干位的运算。“右移”运算的方法如图4-20所示。

图4-20 右移运算

7.复合赋值运算符

在赋值运算符“=”之前加上其他双目运算符,就可以构成复合赋值运算符。复合赋值运算符有+=、-=、*=、/=、%=、<<=、>>=、&=、^=和|=。

构成复合赋值表达式的方式为:

它相当于:

例如:

num+=15相当于:num=num+15。

a*=b+23相当于:a=a*(b+23)。