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

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

Keil C51的数据类型如表1-2所示。

本书大多数案例使用的都是无符号数,对于255以内的整数,本书全部定义为INT8U类型(相当于字节类型byte),对于0~65 535范围内的整数,本书定义为INT16U类型(相当于字类型word)。有关案例因为涉及正负数的处理,例如,温度控制程序中有零上温度与零下温度,由于温度传感器实际上可处理的范围为-55~125℃,为了使程序对温度值进行正确比较,程序中将温度类型定义为char类型(Keil C默认char为signed char类型,其取值范围为-128~127)。

表1-2 Keil C51的数据类型

另外,本书大量用到的延时程序中可能有INT8U类型,也可能有INT16U类型。在编写代码时,如给某变量x赋值2000(0x07D0),如果变量x定义为INT8U类型而不是INT16U类型,编译时并不会报错,但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类型而不是INT8U类型,使用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端口的液晶屏发送显示数据时,需要先判断液晶是否忙,其忙标志在读取字节的最高位,因此又有类似语句: 3qdTSYzT0wzFPSn29zH17FWvHTTVaU82bHAwU8RbEjJI3bTFbNm+EuG7aKkv5SuK

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