5

我有一个 16 位变量data,即:

volatile uint16_t data;

我需要根据外部传感器上两个 8 位寄存器的内容来填充这个值。这些通过 I2C/TWI 访问。

我的 TWI 例程是 async*,并且具有以下签名:

bool twi_read_register(uint8_t sla, uint8_t reg, uint8_t *data, void (*callback)(void));

reg这会将on的值读sla*data,然后调用callback()

如果我知道uint16_t在内存中被安排为 ,MSB LSB那么我可以这样做:

twi_read_register(SLA, REG_MSB, (uint8_t *)&data, NULL);
twi_read_register(SLA, REG_LSB, (uint8_t *)&data + 1, NULL);

但是,我不喜欢在我的代码中加入对字节序的依赖。有没有办法以独立于字节序的方式实现这一目标?

(旁注:我目前的实际解决方法涉及使用结构,即:

typedef struct {
    uint8_t msb;
    uint8_t lsb;
} SensorReading;

但我很好奇我是否可以用一个简单的方法做到这一点uint16_t

编辑

(*我所说的异步是指分阶段,*data即将在将来的某个时间设置,此时callback如果请求,将通过函数通知被调用者)

4

3 回答 3

4

以下不工作吗?

uint8_t v1, v2;
twi_read_register(SLA, REG_MSB, &v1, NULL);
twi_read_register(SLA, REG_LSB, &v2, NULL);
data = ((uint16_t)v1<<8)|v2;

或者是data如此易变以至于twi_read_register需要编写它。在那种情况下,我认为您会遇到依赖字节序的代码。

正如您在下面指出的那样,data确实是不稳定的,因为还有另一个设备正在读取它。因此,在字节序可能不同的两个设备之间建立了内存映射连接。这意味着你被字节序依赖的代码困住了。

您提到该结构是一种解决方法,但这是一种处理此问题的标准方法。

#ifdef BIGENDIAN
typedef struct
{       uint8_t  msb, lsb;
} uint16_as_uint8_t;
#else
typedef struct
{       uint8_t  lsb, msb;
} uint16_as_uint8_t;
#endif

最重要的是,你可以放一个union

union
{       uint16_as_uint8_t  as8;
        uint16_t           as16;
};

请注意,后者违反了 C89 标准,因为您的明确意图是写入一个字段union并从另一个字段读取,这会导致未指定的值。从 C99 开始,这是(幸运的)支持的。在 C89 中,人们将使用指针转换来(char*)以可移植的方式执行此操作。

请注意,上述内容似乎以可移植的方式隐藏了字节顺序,结构包装也可能因目标而异,并且可能仍会在某些目标上中断。对于上面的例子,这不太可能,但周围有一些奇怪的目标。我想说的是,可能无法在此设备级别上进行可移植编程,最好接受这一点并努力将所有细节隐藏在紧凑的目标界面中,因此为目标更改一个头文件足以支持它。然后代码的其余部分可以看起来独立于目标。

于 2013-04-15T01:04:31.440 回答
0

这样的事情怎么样?

uint16_t myValue = ...;
uint8_t LSB = (uint8_t)(myValue % 256);
uint8_t MSB = (uint8_t)(myValue / 256);
于 2013-04-15T11:56:45.870 回答
0
  volatile uint16_t data;  
  uint16_t v = 1;
  twi_read_register(SLA, REG_MSB, (uint8_t *)&data + *((uint8_t *)&v), NULL);
  twi_read_register(SLA, REG_LSB, (uint8_t *)&data + *((uint8_t *)&v + 1), NULL);
于 2013-04-16T04:02:45.993 回答