5

私は16ビット変数を持っていますdata、すなわち:

volatile uint16_t data;

外部センサーの 2 つの 8 ビット レジスタの内容に基づいて、この値を入力する必要があります。これらは I2C/TWI を介してアクセスされます。

私の TWI ルーチンは async* で、署名があります:

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

regonの値を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)

編集

(* async とは分割フェーズを意味します。つまり*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さらに別のデバイスがそれを読み取っているため、実際には揮発性です。そのため、エンディアンが異なる可能性がある 2 つのデバイス間でメモリ マップド接続が確立されます。これは、エンディアンに依存するコードで立ち往生していることを意味します。

回避策として構造体に言及していますが、これはこれを処理する標準的な方法です。

#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 標準に違反していることに注意してください。これは、 の 1 つのフィールドに書き込みunion、別のフィールドから読み取るという明確な意図があるため、値が指定されていない結果になるためです。C99以降、これは(幸いなことに)サポートされています。C89(char*)では、移植可能な方法でこれを行うために、ポインタ変換を使用します。

上記は移植可能な方法でエンディアンを隠しているように見えるかもしれません.構造体のパッキングもターゲットごとに異なり、一部のターゲットでは壊れる可能性があることに注意してください. 上記の例では、これはありそうにありませんが、奇妙なターゲットがいくつかあります。私が言おうとしているのは、このデバイス レベルでポータブルをプログラムすることはおそらく不可能であり、それを受け入れて、コンパクトなターゲット インターフェイスですべての詳細を非表示にするよう努めた方がよいかもしれないということです。そのため、ターゲットのヘッダー ファイルを 1 つ変更します。それをサポートするのに十分でしょう。コードの残りの部分は、ターゲットに依存しないように見えます。

于 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 に答える