MSP430G2333下位机乘法运算需要注意的一个问题

发布者:技术掌门最新更新时间:2016-12-26 来源: eefocus关键字:MSP430G2333  下位机  乘法运算 手机看文章 扫描二维码
随时随地手机看文章

背景:


  最近负责为主板管理电源的电源管理模块编写软体,使用的MCU为MSP430G2333。功能上很简单,即通过板子上的硬件拨码设定,或者通过IIC与主板通信,由主板的BIOS决定开机及关机的延时供电时间。


正文:


  所有功能均按预期实现,但有一个bug在最后蹦了出来,即在延时关机设定时,明明设定为15、18、48个小时,却每次在9个多小时的时候,电源被执行关闭动作。9个多小时,很有意思的数字。不用深究,问题直接锁定在时间比对函数内。



 1 // when the current time less than the setting time, return 0. Otherwize, return 1.

 2 char compare_timer(unsigned char h, unsigned char m, unsigned char s)    

 3 {

 4     unsigned long TimerCnt     = 0;

 5     unsigned long TimerSetCnt = 0;

 6     unsigned char i;

 7 

 8         // timer_s, timer_m, timer_h are increased in the 1s timer interrupt  

 9         TimerCnt = timer_h*3600  + timer_m*60 + timer_s; 

10     

11         TimerSetCnt = h*3600 + m*60 + s;    

12     

13 

14     if(TimerCnt >= TimerSetCnt) {

15           return 0;    //time is out

16     }

17     else {

18           return 1;

19     }

20 }    

 


  根据现象,首先考虑的是溢出问题,TimerCnt 为“unsigned long”型,以最久48个小时来算,也就172800,远小于4个字节的存量。排除!


  或许是中间变量存储问题,于是将代码更改如下(部分)


  


 1 char compare_timer(unsigned char h, unsigned char m, unsigned char s)    

 2 {

 3         ...    

 4 

 5     TimerCnt += timer_m*60 

 6     TimerCnt += timer_s; 

 7 

 8     TimerSetCnt += h*3600

 9     TimerSetCnt += m*60

10     TimerSetCnt += s;

11 

12         ...

13 }    


  结果然并卵。排除!


  前面说过,9个多少小时,9*3600 = 32400,很微妙的数字。65535(0xFFFF) / 2 = 32767,差不多相等。于是,想到了乘法寄存器的问题。


// *********此处理解有偏差,文末更新************************


  此处,虽说保存结果的位置给了四个字节空间(“unsigned long TimerCnt”),但是在做乘法运算的时候,运算结果会放在乘法结果寄存器,由以上现象可知,乘法结果寄存器最大存放2个字节,其中最高位还得预留给符号位,所以其最大的值为32767(0x7FFF)。改正代码如下:


// **************************************************** 



 1 /* 不再使用 TimerCnt = timer_h*3600 是因为其乘法结果会溢出 

 2  * 其实本可以有更漂亮的解决办法,但是Rom(4k)不够用了 T_T ···只能这么写    

 3  */

 4 char compare_timer(unsigned char h, unsigned char m, unsigned char s)    

 5 {

 6         ...    

 7 

 8     for(i = 0; i < timer_h; i++) { 

 9             TimerCnt += 3600; 

10     } 

11     TimerCnt += timer_m*60; 

12     TimerCnt += timer_s;

13 

14         ...

15 }         


/* 感谢老司机左栋,此处做个更新,更正之前的误区。-- 2016年9月7日

 *  此前理解有误,以为MSP430乘法运算的结果保存在乘法结果寄存器中,而乘法结果寄存器只能保存2个字节,

 *  最高位还得预留给符号位。其实不然。实际是没有遵守编译器的规则而已。

 *  MSG430是一个"16"位MCU,那么其"int"型即为2个字节(16位)。来看式子。 */

    TimerSetCnt += h*3600 // 此处h为"unsigned char"型,3600为"int"型。

    //那么最终的乘法结果也只能保存为"int"型变量的宽度(2个字节)。若代码改正如下:

    TimerSetCnt += h*3600L // 此处3600加了个"L",表示其为"long"型。

    //那么最终乘法结果就可保存为"long"型变量的宽度(4个字节)。

/*  所以跟乘法结果寄存器的大小无关,而是编译器有关。

 *  若是以以下方式编写。*/

    TimerSetCnt += 10*3600 // 此处h更改为10。

 /*  则编译器会报一个警告"Out of the range". */



  至此,总结完毕!下次在下位机的时候,一定要注意不能再犯!


关键字:MSP430G2333  下位机  乘法运算 引用地址:MSP430G2333下位机乘法运算需要注意的一个问题

上一篇:PCF8591应用程序
下一篇:单片机与PLC详细比较

推荐阅读最新更新时间:2024-03-16 15:27

第64节:大数据的乘法运算
开场白: 直接用C语言的 * 运算符进行乘法运算时, 被乘数 , 乘数 , 积 ,这三个数据的最大范围是unsigned long 类型,也就是数据最大范围是4个字节,十进制的范围是0至4294967295。一旦超过了这个范围,则运算会出错。因此,当进行大数据乘法运算时,我们要额外编程序,实现大数据的算法。其实这种算法并不难,就是我们在小学里学的四则运算算法。 我们先要弄清楚一个新的概念。不考虑小数点的情况下,数据有两种表现形式。一种是常用的变量形式,另外一种是BCD码数组形式。变量的最大范围有限,而BCD码数组的形式是无限的,正因为这个特点,所以我们可以进行大数据运算。 这一节要教大家一个知识点: 第一个:如何编写涉
[单片机]
单片C环境下位操作的实现方法
  C语言既有高级语言的各种特点,又可对硬件进行操作,并对进行结构化程序设计,用C语言编写的程序较容易移植,它们可生成简洁可靠的目标代码,在代码效率和代码执行速度上完全可以和汇编媲美。采用C语言进行单片机编程是嵌入式程序设计的发展趋势。但是,在嵌入式控制等领域,经常需要控制某一个二进制位,然而除了Keil C51等C环境外,很多单片机C环境都没有扩充对位变量定义的关键字,甚至单片机本身的硬件上也没有对单个位操作的汇编指令,这使得已习惯MCS-51内核单片机Keil C51编程的用户都为其C环境不能对位变量进行位操作而烦恼。 1 用“读-修改-写”方法实现对单个位的位操作 ANSIC中,一般采用“读-修改-写”的方法实现单个
[单片机]
小广播
添点儿料...
无论热点新闻、行业分析、技术干货……
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件
更多每日新闻
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved