2013-04-15 5 views
5

I는 즉, data 16 비트 변수를 가지고엔디안 방식으로 하위 바이트에 대한 포인터를 가져올 수 있습니까?

volatile uint16_t data; 

내가 외부 센서에 2 개 개의 8 비트 레지스터의 내용에 따라이 값을 채울 필요가있다. 이들은 I2C/TWI를 통해 액세스됩니다.

내 TWI 루틴은 비동기 *이며, 서명이있다 : 이것은 *dataslareg의 값을 읽어

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

, 다음 callback()를 호출합니다.

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

그러나, 나는 내 코드에 엔디안 의존도를 베이킹 좋아하지 않는다 :

나는 그때 내가 할 수의 uint16_tMSB LSB, 말, 같은 메모리에 배열 된 알았다면. 엔디안 독립적 인 방식으로이를 달성 할 수있는 방법이 있습니까?

(보조 노트 : 순간에 내 실제 해결 방법은 구조체를 사용하는 것, 즉 :

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

하지만 간단한 uint16_t와 함께 할 수 있는지 궁금 해요)

편집

(* async는 split phase를 의미합니다 (즉, *data이 나중에 설정 될 예정이며, 요청시 callback 함수를 통해 호출 수신자에게 알립니다)

+1

는 왜 16 비트 값에 액세스 포인터 자신을 제한 하시겠습니까? 대부분 shift, add 또는 or 연산자를 사용하면됩니다. 그러나 포인터로 처리하고 싶다면 endian-ness를 감지하고 보정하는 매크로를 사용할 수 있습니다. –

+0

안심해도 안돼. 안정적이고 이식 가능한 코드를 원한다면 마스크와 교대를 사용하십시오. –

+0

실제로 마스크와 시프트가 작동하지 않습니까? –

답변

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; 

또는는 twi_read_register 그것을 쓸 필요가 휘발성이 매우 data입니다. 이 경우에는 엔디안 종속 코드가 붙어 있다고 생각합니다.

아래와 같이 data은 휘발성이 있습니다. 왜냐하면 아직 다른 기기에서 읽고 있기 때문입니다. 따라서 엔디안과 다를 수있는 두 장치간에 메모리 매핑 연결이 설정됩니다. 즉, 엔디안 종속 코드가 붙어 있습니다.

구조체를 해결 방법으로 언급했지만이 문제를 해결하는 표준 방법 중 하나입니다. union의 하나 개의 필드를 작성하고에서 읽을 수 있도록 명확한 의도로

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

당신은 후자의 C89 표준을 위반하는 union

union 
{  uint16_as_uint8_t as8; 
     uint16_t   as16; 
}; 

주를 둘 수 있었다 다른 하나는 지정되지 않은 값이됩니다. C99에서이 기능이 지원됩니다 (다행스럽게도). C89에서는 포인터 변환을 (char*)을 통해 이식 할 수 있습니다.

위의 내용은 이동식으로 엔디안을 숨기고있는 것처럼 보일 수 있지만 구조 패킹은 대상과 다를 수 있으며 여전히 일부 대상에서 중단 될 수 있습니다.위의 예에서 이것은 거의 발생하지 않지만 주위에 기괴한 목표가 있습니다. 내가 말하고자하는 것은 아마도이 장치 레벨에서 휴대용 프로그램을 프로그래밍 할 수 없다는 것이며,이를 수용하고 압축 된 대상 인터페이스에서 모든 세부 사항을 숨기기 위해 노력할 것이므로 대상에 대한 하나의 헤더 파일을 변경하십시오 그것을 지원하기에 충분할 것입니다. 나머지 코드는 대상을 독립적으로 볼 수 있습니다.

+1

왜 '휘발성'이라고 언급하는지 잘 모르겠다. –

+0

'twi_read_register'는 비동기/분리 단계이므로, 예제에서'v1'과'v2'는 미래에 불확실한 시간까지 설정되지 않을 것입니다. 'data'는 정의되지 않은 값을 갖습니다. 알았어. – sapi

+0

. 그렇다면 일단 값이 준비되었다는 것을 알게되면'uint16_t'에 결합을 할 수 있습니다. –

0

어때?

uint16_t myValue = ...; 
uint8_t LSB = (uint8_t)(myValue % 256); 
uint8_t MSB = (uint8_t)(myValue/256); 
+0

이 질문에 대한 나의 독서는 다른 방향으로 문제를 제기하여 두 개의 8 비트 코드에서 16 비트 값을 채우는 것이지만 일반적인 방법입니다. –

+0

"myValue = MSB * 256 + LSB;"와 관련된 문제가 없습니다. –

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); 
관련 문제