1. 问题现象与背景分析
最近在调试STM32F103的硬件IIC通信时,遇到了一个奇怪的现象:当发送char类型的负数时,接收端总是收到0x00。这个问题困扰了我好几天,经过反复测试和排查,终于找到了原因和解决方案。这里把整个排查过程和解决方法分享给大家。
先描述下具体现象:在硬件IIC通信中,发送正数时一切正常,比如发送0x55,接收端就能正确收到0x55。但是当发送char类型的负数时,比如-1(二进制补码表示为0xFF),接收端却总是收到0x00。这个问题在调试I2C设备时特别容易遇到,尤其是需要传输有符号数据时。
注意:这个问题不仅限于STM32F103,在其他STM32系列芯片上也可能出现,根本原因是数据类型处理和硬件IIC的工作机制导致的。
2. 硬件IIC与char类型的基础知识
2.1 STM32硬件IIC的工作机制
STM32的硬件IIC外设是通过特定的数据寄存器(DR)来发送数据的。当我们调用HAL_I2C_Master_Transmit()等函数发送数据时,数据会被写入I2C的数据寄存器,然后由硬件自动完成时序控制并发送出去。
关键点在于:硬件IIC的数据寄存器是8位的,它只关心数据的低8位,不会对数据类型做任何处理。这意味着无论你传入的是char、int还是其他类型,最终都只会取其低8位发送出去。
2.2 char类型在C语言中的特性
在C语言中,char类型默认情况下是否有符号取决于编译器和平台。对于ARM架构的STM32,通常char是有符号的(signed char),范围是-128到127。当char被当作负数时,其二进制表示是补码形式。
例如:
- char a = -1; // 实际存储为0xFF
- char b = -128; // 实际存储为0x80
3. 问题根源分析
3.1 数据类型转换问题
问题的核心在于从char到I2C数据寄存器的隐式类型转换。当我们传递一个char类型的负数给I2C发送函数时,会发生以下转换过程:
- char负数(如-1,即0xFF)被隐式转换为int类型(变为0xFFFFFFFF)
- 这个int值被传递给I2C发送函数
- I2C函数只取低8位(0xFF)发送
但是为什么接收端收到的是0x00呢?这就要看I2
