购买
下载掌阅APP,畅读海量书库
立即打开
畅读海量书库
扫码下载掌阅APP

1.6 有符号与无符号数应用、数位分解、位操作

Keil C51的数据类型如表1-8所示。大量案例中会使用到无符号数,对于255以内的整数,可定义为u8类型(相当于字节类型BYTE);对于0~65 535范围内的整数,可定义为u16类型(相当于字类型WORD)。涉及正负数(有符号数)处理的案例,例如,温度控制程序中有零上温度与零下温度,由于其温度传感器实际上可处理范围为温55~125℃,为使程序对温度值进行正确比较,程序中将温度数据类型定义为char类型(Keil C默认char为signed char类型,即有符号字符型,其取值范围为其128~127)。

表1-8 Keil C51的数据类型

另外,大量案例用到的延时程序中可能有u8类型,也可能有u16类型。编写C程序时,例如,给某延时参数x赋值2000(0x07D0),如果参数x定义为u8类型而不是u16类型,编译时并不会报错,但x实际所获得的值将为0x07D0的低字节0xD0(208),编写的语句为x=2000,而实际上x=208。这一点在单片机C语言程序设计过程中要特别注意。

大量设计涉及用数码管显示整数或浮点数,这就要对显示数据进行数位分解,例如:

又如:

如果要得到x的各个数位,可以先将x乘以100,然后再分解各数位:

上面for循环中的循环条件本来要写成i>=0,但当i=0时,如果将i再减1,i变为0xFF,这个无符号数仍被认为大于或等于0,这样就不能保证5次循环了,因此要改写成i !=0xFF。如果将i定义成char类型而不是u8类型,使用i>=0时才能得到正确结果,这是因为前面已提到Keil C默认char为signed char类型。

上述数位分解常用于数码管数字显示,这是因为数码管显示时要根据各数位提取数码管段码。

在设计一般的C语言程序时,位操作较少被使用,但在单片机应用系统设计过程中,位操作将被大量使用。在有关发光二极管(LED)流水灯、数码管位扫描控制、串行收/发信息、键盘扫描等大量案例中,位的各相关操作符及相关函数均会频繁出现。因此,要熟练掌握字节位循环左移函数(_crol_)、字节位循环右移函数(_cror_)、位左移(<<)、位右移(>>)、与(&)、或(|)、取反(~)、异或(^)、非(!)等。要注意,对于单个位,非(!)操作与取反(~)操作是等价的;但对于单个位以外的其他类型或定义,其操作则不等价。

下面是有关位操作的几个简单应用。

例如,将P1的P1.7~P1.0引脚逐个循环轮流置1,可先设字节变量c=0x01,然后在循环语句中执行c=_cror_(c,1),并使P1=c,这样即可使P1依次为10000000,01000000,00100000,…, 00000001,如此重复。如果要将P1.7~P1.0引脚逐个循环轮流置0,可先设c=0xFE,然后使用同样的循环移位操作即可。对于这两项操作,如果已经有循环语句及控制变量i(取值为0~7),还可以有P1=0x80>>i及P1=~(0x80>>i)语句。这类位操作在LED流水灯或集成式数码管位扫描中时常会被用到。

又如,已知P2.3连接外部LED或蜂鸣器,如果要使LED闪烁或蜂鸣器发声,可先定义sbit LED=P2^3或sbit BEEP=P2^3,然后在循环语句中执行语句LED=~LED或BEEP=~BEEP即可。对于独立的位定义,执行取反(~)与非(!)操作效果是一样的,但对于字节变量则是不同的。对于这里的LED闪烁或蜂鸣器发声操作,可以使用等效语句LED=!LED及BEEP=!BEEP。

如果熟悉“异或”操作符,还可以用P2 ^=(1<<3)这样的写法。这个写法可以省略位定义。

另外,在本书4×4键盘矩阵扫描程序中,假设P1端口高4位引脚连接矩阵行,低4位引脚连接矩阵列。为判断16个按键中是否有键被按下,通常会先在矩阵行上发送4位扫描码0000,即P1=0x0F,然后检查矩阵列上是否出现0。这时,使用位操作语句:

由于“!=”的优先级高于“&”,因此要给该语句中的“与操作”表达式加括号。

在本书涉及的多个字符液晶显示器案例中,当向连接在P0端口的液晶屏发送显示数据时,要先判断液晶屏是否忙。因此,又有类似语句: KHqBLHd+w26fIYO0vOtmHvy9jpyk38gRAsdSBWkp7FGzG4UxVc6487LHncMonXyH

点击中间区域
呼出菜单
上一章
目录
下一章
×