기술 가이드

SHT3x 온습도 센서 6바이트 읽기: 두 CRC-8을 각각 검증하는 C 예제

SHT3x 단발 측정 응답의 온도·습도 순서와 CRC-8 범위를 확인하고, 손상된 프레임을 거르는 C 예제를 실행합니다.

목차

SHT30·SHT31·SHT35 계열을 MCU의 I²C 버스에 연결할 때, 읽은 6바이트를 곧바로 온습도로 바꾸면 통신 오류를 정상 측정값으로 저장할 수 있습니다. Sensirion SHT3x-DIS 데이터시트의 4.3·4.4·4.12·4.13절을 기준으로 응답을 나누고 각각의 체크섬을 확인해 보겠습니다.

응답의 순서와 측정 명령

단발 측정에서 0x2C06은 고반복성·클록 스트레칭 사용 명령입니다. 클록 스트레칭을 사용하지 않는 고반복성 명령은 0x2400입니다. 드라이버는 선택한 명령의 완료 조건에 맞춰 읽어야 합니다. 스트레칭을 사용하지 않는 모드에서 아직 측정값이 없으면 읽기 헤더에 NACK가 올 수 있으므로, 이를 CRC 오류로 혼동하지 마세요.

측정 결과는 온도 MSB, 온도 LSB, 온도 CRC, 습도 MSB, 습도 LSB, 습도 CRC 순서입니다. 마지막 습도 CRC를 받은 뒤 마스터는 NACK와 STOP을 보냅니다. 두 CRC는 각각 앞선 2바이트만 검사합니다. 온도·습도 4바이트를 이어서 한 번만 CRC 계산하는 방식은 이 프레임에 맞지 않습니다.

CRC-8과 변환식

데이터시트의 CRC-8 조건은 다항식 0x31, 초기값 0xFF, 입력·출력 비반사, 최종 XOR 0x00입니다. 공식 시험 벡터 BE EF의 CRC는 92입니다. 양쪽 CRC가 모두 맞을 때만 16비트 빅엔디언 원시값을 조립합니다. 온도는 -45 + 175 × rawT / 65535 °C, 상대습도는 100 × rawRH / 65535 %RH입니다.

다음 코드는 센서 접근을 제외한 프레임 디코더와 시험용 main을 담았습니다. 실제 펌웨어에서는 I²C가 정확히 6바이트를 읽었는지 먼저 확인한 다음 decode에 넘기세요. 통신이 실패하거나 CRC가 틀리면 이전 정상값을 새 측정값으로 덮어쓰지 않는 정책이 안전합니다.

#include <assert.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>

static uint8_t sht3x_crc(const uint8_t bytes[2]) {
uint8_t crc = 0xff;
for (int i = 0; i < 2; ++i) {
crc ^= bytes[i];
for (int bit = 0; bit < 8; ++bit) {
crc = (crc & 0x80u) ? (uint8_t)((crc << 1) ^ 0x31u)
: (uint8_t)(crc << 1);
}
}
return crc;
}

static bool decode(const uint8_t frame[6], double *celsius, double *rh) {
if (sht3x_crc(frame) != frame[2] ||
sht3x_crc(frame + 3) != frame[5]) {
return false;
}
const uint16_t raw_t = (uint16_t)((uint16_t)frame[0] << 8 | frame[1]);
const uint16_t raw_rh = (uint16_t)((uint16_t)frame[3] << 8 | frame[4]);
*celsius = -45.0 + 175.0 * raw_t / 65535.0;
*rh = 100.0 * raw_rh / 65535.0;
return true;
}

int main(void) {
const uint8_t vector[2] = {0xbe, 0xef};
assert(sht3x_crc(vector) == 0x92); /* 제조사 데이터시트 시험값 */

uint8_t frame[6] = {0x66, 0x66, 0, 0x80, 0x00, 0};
frame[2] = sht3x_crc(frame);
frame[5] = sht3x_crc(frame + 3);
double celsius = 0, rh = 0;
assert(decode(frame, &celsius, &rh));
printf("valid: %.2f C, %.2f %%RH\n", celsius, rh);

frame[3] ^= 0x01; /* 습도 데이터 1비트 손상 */
assert(!decode(frame, &celsius, &rh));
puts("corrupt humidity: rejected");
return 0;
}

Windows의 GCC 또는 Linux의 GCC에서 gcc -std=c11 -Wall -Wextra -Werror sht3x_frame.c -o sht3x_frame으로 빌드하고 실행한 결과입니다. 첫 assert가 공식 벡터를 검증하며, 마지막 시험은 습도 데이터 비트 하나를 바꿔 프레임을 거부하는지 확인합니다.

valid: 25.00 C, 50.00 %RH
corrupt humidity: rejected

보드에서 확인할 점

센서의 I²C 주소, 전원, 풀업과 사용 MCU의 I²C 완료·타임아웃 처리는 보드 구성에 맞춰 확인하세요. I²C 전송 실패와 CRC 실패를 별도로 기록하면 버스 문제와 데이터 손상을 구분하기 쉽습니다. 이 예제는 프레임 계산을 PC에서 검증한 것으로, 특정 보드의 타이밍이나 실제 센서 동작을 시험한 결과는 아닙니다.

관련 글

댓글

첫 댓글을 남겨 보세요.

관리자 확인 후 게시됩니다.

처리 중입니다...

잠시만 기다려주세요.