I2C 协议有问题

问题描述 投票:0回答:1

我正在和几个朋友一起做一个项目,我正在尝试解决从 I2C 压力传感器读取数据时遇到的问题。

所附的代码是我遇到的问题的负责人。我正在使用的压力传感器的数字计数范围为 81 到 16128。当从传感器读取原始数据时,变化为 256(1 字节),因此从 8017 到 8273 到 8529,而不是像 8017 到 8018 等那样逐个数字. 因此,函数(值)不会像预期的那样平滑地变化。关于为什么在 256 次计数后每次都这样计数的任何想法?似乎由于某种原因它一口一口地改变(1000 0000)。

void get_inputs(void)
{
        I2C_Master_Start();
        I2C_Master_Write(0x50);
        I2C_Master_Write(0x01);
        I2C_Master_RepeatedStart();
        I2C_Master_Write(0x51);
        rawHighByte = I2C_Master_Read(true);//Read the first byte and send an ACK
        rawLowByte = I2C_Master_Read(false); //shift the previously read value into the upper byte 
        I2C_Master_Stop();

        // Calculate the pressure from the received data
    
       uint16_t rawValue = ((uint16_t)rawLowByte << 8) | rawHighByte;
       
 
     // Convert to [-351, 351] range   
     float value = (((float)rawValue - 81.0f) * 702.0f / 16128.0f) - 351.0f;
     
     sprintf(pressure_str, "P: %f", value);

      
       lcd_clear();
}
c i2c
1个回答
2
投票

我认为你应该使用以下内容:

uint16_t rawValue = ( ( (uint16_t)rawHighByte << 8 ) | rawLowByte ) & 0x3FFF;

float value = ( ( rawValue - 0x2000 ) / (float)0x4000 ) * 702.0;

这都是猜测,因为你提供的信息很少,而你提供的信息很少是相互矛盾的。


错误 #1:转换公式不正确

您的输入预计应该在 [0,0x3FFF] ([0,16383]) 范围内。[1]

论文应该映射到输出 [-351,351]。

他们没有。

输入 (((float)rawValue - 81.0f) * 702.0f / 16128.0f) - 351.0f
0x0000 -354.525665283203125
0x3FFF 358.57366943359375

要将 [0,0x3FFF] 映射到 [-351.0,351.0)[2],可以使用以下内容:

float value = ( ( rawValue - 0x2000 ) / (float)0x4000 ) * 702.0;
输入 ( ( rawValue - 0x2000 ) / (float)0x4000 ) * 702.0
0x0000 -351
0x3FFF 350.9571533203125

Bug #2:高低字节颠倒了

您正在使用

rawLowByte
作为高字节,而
rawHighByte
作为低字节。所以要么你用反了,要么名字错了。

前一种解释更有可能,因为你观察到的行为将直接导致反向使用它们。如果您将低字节用作高字节,则低字节中的 1 变化将导致

rawValue
中的 256 变化。

您使用了以下内容:

uint16_t rawValue = ( (uint16_t)rawLowByte << 8 ) | rawHighByte;
原始高字节 原始低字节 ( (uint16_t)rawLowByte << 8 ) | rawHighByte 价值
0x0000 -351
0x51 0x1F 0x1F51 -7.4981689453125
0x51 0x20 0x2051 3.4705810546875
0x51 0x21 0x2151 14.4393310546875
0x3FFF 350.9571533203125

你可能应该使用以下内容:

uint16_t rawValue = ( (uint16_t)rawHighByte << 8 ) | rawLowByte;
原始高字节 原始低字节 ( (uint16_t)rawHighByte << 8 ) | rawLowByte 价值
0x0000 -351
0x51 0x1F 0x511F 538.7969970703125
0x51 0x20 0x5120 538.83984375
0x51 0x21 0x5121 538.8826904296875
0x3FFF 350.9571533203125

错误#3:输入中剩余的额外位

但是通过上述修复,我们得到超出预期 [0,0x3FFF] 范围的

rawValue
值,因此我们得到超出预期 [-351.0,351.0) 范围的
value
值。

由于

rawValue
预计正好是低 14 位的整个范围,因此第 14 位和第 15 位可能用于其他目的,应该被过滤掉。这可以通过以下方式实现:

uint16_t rawValue = ( ( (uint16_t)rawHighByte << 8 ) | rawLowByte ) & 0x3FFF;
原始高字节 原始低字节 ( ... ) & 0x3FFF 价值
0x0000 -351
0x51 0x1F 0x111F -163.2030029296875
0x51 0x20 0x1120 -163.16015625
0x51 0x21 0x1121 -163.1173095703125
0x3FFF 350.9571533203125

  1. 在问题中,您说输入在 [81,16128] 范围内。问题中的公式假设输入在 [0,16127] 范围内。在评论中,您说输入在 [0,0x3FFF] 范围内。我用了你提到的最后一个。
  2. 让范围的两端都包含在内是“棘手的”。
© www.soinside.com 2019 - 2024. All rights reserved.