TI C2000不支持uint8_t时float32_t转uint16_t数组发CAN的实现问题
问题根因
TI C2000系列28x内核最小可寻址单元为16位字,不支持原生8位字节寻址,编译器默认不定义标准uint8_t类型,所有类字节变量实际占用16位存储空间,编译器内置宏CHAR_BIT值为16,而非通用平台的8。
这直接导致两个问题:
- 所有C标准库中以“字节”为单位的接口(
memcpy、sizeof等),统计单位都是16位字,你原有代码中sizeof(float32_t)返回值为2,sizeof(uint16_t)返回值为1,计算得到的拷贝长度为1,memcpy仅拷贝了1个16位字到tmp数组,tmp[1]是未初始化的随机值,拆分后的数据必然出错。 - 直接对浮点数做位移操作属于C标准未定义行为,所有合规C编译器都会直接报错,和硬件平台无关。
可行实现方案
使用C标准允许的联合体(union)类型双关方式完成浮点数到16位数组的转换,完全规避平台字节寻址差异、memcpy长度计算错误的问题,实现逻辑兼容C2000全系列编译器,高优化等级下也不会出现异常。
参考实现代码如下:
// 类型转换联合体,C99标准明确允许该用法,无严格别名违规问题 typedef union { float32_t f_val; uint16_t u16_blk[2]; // C2000平台下float32固定占用2个16位字 } FloatPackUnion; void pack_can_float_data(uint16_t cmd_addr, float32_t tx_float) { FloatPackUnion conv; conv.f_val = tx_float; // 填充地址字段,保证值在0~255范围内 canComVars.txMsgData[0] = cmd_addr & 0xFF; // 以下为小端(Intel格式)字节序拆分,如果需要大端(Motorola格式)调整高低字/字节顺序即可 // 拆分高16位字的两个字节 canComVars.txMsgData[1] = (conv.u16_blk[1] >> 8) & 0xFF; canComVars.txMsgData[2] = conv.u16_blk[1] & 0xFF; // 拆分低16位字的两个字节 canComVars.txMsgData[3] = (conv.u16_blk[0] >> 8) & 0xFF; canComVars.txMsgData[4] = conv.u16_blk[0] & 0xFF; // 剩余未使用的缓冲区位置清零,避免发送无效随机值 canComVars.txMsgData[5] = 0; canComVars.txMsgData[6] = 0; canComVars.txMsgData[7] = 0; }
开发注意事项
- 禁止在C2000平台编写依赖8位字节偏移寻址的代码,所有内存地址步长固定为16位,直接强转
uint8_t*指针读写内存会出现数据错位。 - 填充到
txMsgData数组的所有值必须和0xFF做与运算,保证取值严格落在0~255区间,避免CAN控制器发送时出现数据异常。 - 字节序需要和接收端匹配:如果接收端为x86、ARM Cortex-M等常见小端架构,上述代码可直接使用;如果需要大端传输,调换
u16_blk[0]和u16_blk[1]的拆分顺序即可。 - 不要使用直接指针强转的方式做浮点数类型转换,联合体类型双关是C标准明确兼容的写法,跨编译器兼容性更好。
内容的提问来源于stack exchange,提问作者HansPeterLoft
相关产品推荐
相关产品推荐

