我正在嵌入式系统上编程C.处理器架构是32位(sizeof(int)
是32位,sizeof(short)
是16位)。有一个32位变量,它是一个内存映射控制寄存器(CTRL_REG
),它被指定为只使用了最后16位,它们包含一个带符号的16位整数值(写入更高位有没有效果)。内存访问必须是32位对齐,所以我不能只是将指针碰到几个字节,我也不能假设一个字节序。我担心通过将符号位扩展到第31位而不是将它留在我想要的第15位,自动类型提升会使我正在存储的内容混乱。在这个位置存储东西的最佳方法是什么?
这是我的原始代码,我几乎肯定是错的:
#define CTRL_REG *((volatile unsigned int *)0x4000D008u)
short calibrationValue;
CTRL_REG = -2 * calibrationValue;
然后我尝试了这个,但我认为它仍然可能会在作业点进行整数提升:
CTRL_REG = (short)(-2 * calibrationValue);
然后我终于想到了这个:
CTRL_REG = (unsigned short)(short)(-2 * calibrationValue);
我无法很好地评估这些选项,因为它们都在我的测试中工作,因为calibrationValue
恰好是负数(它是特定于每个设备的校准参数,因此在某些设备上可能是正数),所以在乘以-2之后,我最终存储了一个正值,因此我实际上并没有遇到我在测试中期待的问题。
非常感谢您的帮助,即使只是说“您的想法太多了”。
答案 0 :(得分:4)
而不是unsigned int,定义unsigned int和2个short signed int的联合。
这就是我在ARM系统中处理“有趣的硬件控制寄存器”的方式,在这种情况下,这里和那里的奇数位通常都是“不关心”或“不能写入1”。
RGDS, 马丁
答案 1 :(得分:4)
想想16位中的-16(例如)是什么样的:'0xFFF0',以及33位:'0xFFFFFFF0'。符号扩展正是您希望确保在正确的位置有一个符号位。由于鞋帮16不在乎,所以可以用1来填充它们。因此,创建一个带符号的32位值,然后将其转换为无符号32以放入您的寄存器:
Int32 calreg= -2L * calibrationValue;
CTRl_REG = (Uint32)calreg;
如果您希望将0写入高位,则在强制转换前使用0xFFFF进行掩码。
答案 2 :(得分:0)
如果忽略写入最高16位的值,我认为您可以放心地依赖类型转换。总而言之,你不关心更高的位。
#define CTRL_REG *((volatile signed int *)0x4000D008u)
short calibrationValue;
CTRL_REG = -2 * calibrationValue;
请注意,CTRL_REG现在被声明为签名整数。
答案 3 :(得分:0)
#define SS2L(sh,sl) ( ((sh) <<16) | ((sl) & 0xffff) )
将两个16位短路组合成一个32位长。
最好使用无符号类型来完成bitops;升级到int可以抓住你。也许添加一些额外的强制转换为无符号的上述宏。