본문 바로가기
기술정보 및 자료/EBIMU9DOFV2

2의 보수값 계산하기



1. 서론

EBIMU-9DOFV2, EBIMU24GV2, EBRF24GRCV 등의 센서 출력모드에는 Hex(binary)모드가 있습니다.

Hex(binary)출력모드는 ASCII출력모드에 비해 byte수가 적으며, 데이터의 길이도 고정적이기

때문에 parsing시 유리합니다.


Hex(binary)출력모드에서 각 DATA항목의 형식은 2byte이며, 음수 표현은 2의 보수

형식을 따릅니다.


2의 보수는 1을 0으로, 0을 1로 반전 시킨 후(1의 보수) 1을 더한 값이 2의 보수가 됩니다.

parsing 코드을 짠다면 다음과 같을 것입니다.

1. 2byte 를 받은 후 16bit변수에 저장 (shift 후 OR연산)

2. 최상위 bit 조사(최상위 bit가 1이면 음수, 즉 2의 보수 형식)

3. 음수일 경우 반전 시킨후 1을 더함.

4. -1을 곱함.


위와 같이 하면 되겠지만 자료형을 안다면 보다 효율적으로 처리 할 수 있습니다.


다음에 나오는 C코드는 2의 보수형식을 가진 데이타를 받아 쉽게(cpu부하없이) 처리하는 방법에 대한 참조용 코드 입니다.




2. 2의 보수 처리 방법

2-1. union사용


// 선언

typedef union {

  signed short value;

  unsigned char byte[2];

} S2BYTE;


S2BYTE EulerRoll, EulerPitch, EulerYaw;

float Roll, Pitch, Yaw;


// 사용 (Little-Endian 의 경우)

EulerRoll.byte[1] = serial_data[1];

EulerRoll.byte[0] = serial_data[2];


EulerPitch.byte[1] = serial_data[3];

EulerPitch.byte[0] = serial_data[4];


EulerYaw.byte[1] = serial_data[5];

EulerYaw.byte[0] = serial_data[6];


Roll = EulerRoll.value / 100.;

Pitch = EulerPitch.value / 100.;

Yaw = EulerYaw.value / 100.;




// 사용 (Big-Endian 의 경우)

EulerRoll.byte[0] = serial_data[1];

EulerRoll.byte[1] = serial_data[2];


EulerPitch.byte[0] = serial_data[3];

EulerPitch.byte[1] = serial_data[4];


EulerYaw.byte[0] = serial_data[5];

EulerYaw.byte[1] = serial_data[6];


Roll = EulerRoll.value / 100.;

Pitch = EulerPitch.value / 100.;

Yaw = EulerYaw.value / 100.;




2-2. 형변환(cast) 사용


// 선언

signed short EulerRoll, EulerPitch, EulerYaw;

float Roll, Pitch, Yaw;


// 사용 (Little-Endian 의 경우)

EulerRoll  = (serial_data[1] << 8) | serial_data[2];

EulerPitch = (serial_data[3] << 8) | serial_data[4];

EulerYaw   = (serial_data[5] << 8) | serial_data[6];


Roll  = EulerRoll / 100.;

Pitch = EulerPitch / 100.;

Yaw   = EulerYaw / 100.;



// 사용 (Big-Endian 의 경우)

EulerRoll  = (serial_data[2] << 8) | serial_data[1];

EulerPitch = (serial_data[4] << 8) | serial_data[3];

EulerYaw   = (serial_data[6] << 8) | serial_data[5];


Roll  = EulerRoll / 100.;

Pitch = EulerPitch / 100.;

Yaw   = EulerYaw / 100.;




2-3. Pointer 사용


// 선언

unsigned short EulerRoll, EulerPitch, EulerYaw;

signed short *pRoll, *pPitch, *pYaw;

float Roll, Pitch, Yaw;


pRoll  = (signed short*)&EulerRoll;

pPitch = (signed short*)&EulerPitch;

pYaw   = (signed short*)&EulerYaw;



// 사용 (Little-Endian 의 경우)

EulerRoll  = (serial_data[1] << 8) | serial_data[2];

EulerPitch = (serial_data[3] << 8) | serial_data[4];

EulerYaw   = (serial_data[5] << 8) | serial_data[6];


Roll  = *pRoll / 100.;

Pitch = *pPitch / 100.;

Yaw   = *pYaw / 100.;



// 사용 (Big-Endian 의 경우)

EulerRoll  = (serial_data[2] << 8) | serial_data[1];

EulerPitch = (serial_data[4] << 8) | serial_data[3];

EulerYaw   = (serial_data[6] << 8) | serial_data[5];


Roll  = *pRoll / 100.;

Pitch = *pPitch / 100.;

Yaw   = *pYaw / 100.;