当前位置:首页 > 单片机 > 单片机
[导读]在单片机编程中,我们经常会用到一些无符号数与有符号数的混合运算,另外我们所用的单片机很有可能是16位或者8位的,这样,编程时所用的一些变量的取值范围会对我们的 运算有所限制.比如说8位的单片机无符号数最大值为25

单片机编程中,我们经常会用到一些无符号数与有符号数的混合运算,另外我们所用的单片机很有可能是16位或者8位的,这样,编程时所用的一些变量的取值范围会对我们的 运算有所限制.比如说8位的单片机无符号数最大值为255,有符号最大数为127;16位单片机无符号数最大值为65535,有符号数最大值为32767.对于32的单片机来说,因为我们一般所处理的值很少能超过有符号数的最大取值,所以比较少遇到下面出现的问题.

在一些运算中,我们希望有些数能表示正负,这就得用有符号数,而有些数的取值会超过有符号数的最大值,这时我们就得用无符数来表示.下面是我编程时遇到的两个问题(用的是MC9S12XS128处理器,16位的单片机).

变量的声明如下:

int iError;

unsigned int uiExpectSpeed;

unsigned int uiCurrentSpeed;

语句如下:

iError = (uiExpectSpeed - uiCurrentSpeed)/3; //(1) 第一个语句

在调试的过程中发现这个iError的值有时候会特别大,最后才发现是上面的这句语句出错了!然后修改成下面两句结果就对了:

iError = uiExpectSpeed - uiCurrentSpeed; //(2)第二个语句

iError = iError/3; //(3)第三个语句

不同类型的数据在进行混合运算时会有一个隐试的类型转换过程,有符号数与无符号数混合运算,有符号数会被转换成无符号数后再参加运算.

在上面的第一个语句中,如果uiExpectSpeed 比uiCurrentSpeed的值大,也就是uiExpectSpeed - uiCurrentSpeed结果为一正值,那不会出现啥问题,但当uiExpectSpeed 比uiCurrentSpeed的值小时就出现问题了,此时uiExpectSpeed - uiCurrentSpeed的临时结果存放在16位的寄存器中,且最高位1,对于有符号数来说会把这一个位解释为符号位,1表示负数,而对于无符号来说这个位就表示数值,接着这个临时的结果除以3后,所得到的结果的最高位变为了0此时该结果会转换为一个有符合数(不管是有符号数,还是无符号数,最高位为0时,所表示的数值就是一样的),赋给iError.本应该得到一个负数的,但最终却得到了一个比较大的正数!在第一个语句中,如果没有除以3,而是两个数作差后直接赋给iError则是不会出错的,虽然uiExpectSpeed - uiCurrentSpeed运算的结果是一个很大的正数(寄存器的最高位为1),但在这个临时结果赋给iError这个变量时,会先把这个值转换为一个有符号数赋给iError.其实,在把uiExpectSpeed - uiCurrentSpeed运算的结果赋给iError时是把所有的位原封不动的复制到iErrorr所表示的内存单元中的,只是我们是以有符号数来解释这个内存单元中的内容,所以这个很大的正数就变成了一个负数!(数据在处理器内是以补码表示的,对于数据是正还是负只是人们的解释不同而已).所以我就用后面的两句替换了第一句,这样不管uiExpectSpeed - uiCurrentSpeed的差值是正还是负都能得到正确的结果了.

下面是我在做超声波测距时遇到的又一个很隐蔽的问题:

unsigned int start; //表示计时开始时计数器的值

unsigned int end; //表示计时结束时计数器的值

unsigned int error;

unsigned int distance; //表示距离

unsigned int time; //表示从计时开始到结束所用的时间

unsigned int remainder;//余数

start = TCNT;// 计时开始, TCNT为16位的计时器寄存器

..............一段时间后(这段时间小于计时器TCNT从0计数到最大值65535所表示的时间)...........

end = TCNT; //计时结束

error = end - start; //注意,end有可能比start小,但由于都是无符号数,所以最后得到的差值就是这段时间内计数器TCNT的增量.

time = error/625; //单位为ms TCNT每1ms内数值增加625(这个数与TCNT所用的时钟有关)

distance = 17*time; //单位为cm, 距离为速度乘以时间再除以2就是声波所传波的距离

这块由于是分步计算的,所以会有比较大的误差(主要是由于error/625后的余数被丢弃了) 于是我改成如下语句:

start = TCNT;// 计时开始, TCNT为16位的计时器寄存器

..............一段时间后(这段时间小于计时器TCNT从0计数到最大值65535所表示的时间)...........

end = TCNT; //计时结束

error = end - start; //注意,end有可能比start小,但由于都是无符号数,所以最后得到的差值就是这段时间内计数器TCNT的增量.

distance = (17*error)/625; //单位为cm, 将上面的最后两句结合成一句,先乘后除就会减小误差

但改后上面distance = (17*error)/625; 这句就错了,因为error的值可能很大,最大可以达到65535,所以17*error结果很有可能会超过65535,但这个处理器是16位的,也就是说这个处理器的数据寄存器为16位,最大的表示数值也就65535,所以17*error大于65535后就会被截断存入寄存器中.也就是说存入寄存器中的值为(17*error)%65536,当再用这个值除以625时得到的很有可能就是0或者个位数的值,不管怎样,此时得到的结果都是错误的值了!!

结合上面两种情况,最后我改成如下:

start = TCNT;// 计时开始, TCNT为16位的计时器寄存器

..............一段时间后(这段时间小于计时器TCNT从0计数到最大值65535所表示的时间)...........

end = TCNT; //计时结束

error = end - start; //注意,end有可能比start小,但由于都是无符号数,所以最后得到的差值就是这段时间内计数器TCNT的增量.

time = error/625; //单位为ms

remainder = error - time*625;//计算上一句中丢弃的余数,没有用remainder = error%625,是因为除法很耗时!!

distance = 17*time + (17*remainder + 312)/625; //单位为cm,此处的312(625/2)是考虑到四舍五入的.

本站声明: 本文章由作者或相关机构授权发布,目的在于传递更多信息,并不代表本站赞同其观点,本站亦不保证或承诺内容真实性等。需要转载请联系该专栏作者,如若文章内容侵犯您的权益,请及时联系本站删除。
换一批
延伸阅读

LED驱动电源的输入包括高压工频交流(即市电)、低压直流、高压直流、低压高频交流(如电子变压器的输出)等。

关键字: 驱动电源

在工业自动化蓬勃发展的当下,工业电机作为核心动力设备,其驱动电源的性能直接关系到整个系统的稳定性和可靠性。其中,反电动势抑制与过流保护是驱动电源设计中至关重要的两个环节,集成化方案的设计成为提升电机驱动性能的关键。

关键字: 工业电机 驱动电源

LED 驱动电源作为 LED 照明系统的 “心脏”,其稳定性直接决定了整个照明设备的使用寿命。然而,在实际应用中,LED 驱动电源易损坏的问题却十分常见,不仅增加了维护成本,还影响了用户体验。要解决这一问题,需从设计、生...

关键字: 驱动电源 照明系统 散热

根据LED驱动电源的公式,电感内电流波动大小和电感值成反比,输出纹波和输出电容值成反比。所以加大电感值和输出电容值可以减小纹波。

关键字: LED 设计 驱动电源

电动汽车(EV)作为新能源汽车的重要代表,正逐渐成为全球汽车产业的重要发展方向。电动汽车的核心技术之一是电机驱动控制系统,而绝缘栅双极型晶体管(IGBT)作为电机驱动系统中的关键元件,其性能直接影响到电动汽车的动力性能和...

关键字: 电动汽车 新能源 驱动电源

在现代城市建设中,街道及停车场照明作为基础设施的重要组成部分,其质量和效率直接关系到城市的公共安全、居民生活质量和能源利用效率。随着科技的进步,高亮度白光发光二极管(LED)因其独特的优势逐渐取代传统光源,成为大功率区域...

关键字: 发光二极管 驱动电源 LED

LED通用照明设计工程师会遇到许多挑战,如功率密度、功率因数校正(PFC)、空间受限和可靠性等。

关键字: LED 驱动电源 功率因数校正

在LED照明技术日益普及的今天,LED驱动电源的电磁干扰(EMI)问题成为了一个不可忽视的挑战。电磁干扰不仅会影响LED灯具的正常工作,还可能对周围电子设备造成不利影响,甚至引发系统故障。因此,采取有效的硬件措施来解决L...

关键字: LED照明技术 电磁干扰 驱动电源

开关电源具有效率高的特性,而且开关电源的变压器体积比串联稳压型电源的要小得多,电源电路比较整洁,整机重量也有所下降,所以,现在的LED驱动电源

关键字: LED 驱动电源 开关电源

LED驱动电源是把电源供应转换为特定的电压电流以驱动LED发光的电压转换器,通常情况下:LED驱动电源的输入包括高压工频交流(即市电)、低压直流、高压直流、低压高频交流(如电子变压器的输出)等。

关键字: LED 隧道灯 驱动电源
关闭