온도 숫자보다 고장 상태를 먼저 확인하세요
MAX31855는 열전대 전압을 냉접점 보상 온도로 바꾸어 SPI 호환 읽기 인터페이스로 내보냅니다. MCU가 받은 4바이트를 정수로만 변환하면 단선 때의 비트 패턴까지 높은 온도로 표시할 수 있습니다. 이 글은 프레임 검증 → 고장 판정 → 부호 확장 → 단위 변환 순서로 디코더를 구성합니다.
대상은 MAX31855를 연결하는 MCU 펌웨어 개발자입니다. MAX31856이나 MAX6675에는 프레임을 그대로 적용할 수 없습니다. 근거는 Analog Devices 공식 MAX31855 데이터시트 Rev.5의 Serial Interface와 표 2~5입니다.
32비트 프레임을 두 온도와 상태로 나누기
| 비트 | 의미 | 처리 |
|---|---|---|
| D31~D18 | 열전대 온도, 부호 있는 14비트 | 부호 확장 후 0.25°C 곱하기 |
| D17 | 예약 비트 | 0인지 검사 |
| D16 | 고장 요약 | 1이면 측정값 사용 중단 |
| D15~D4 | 기준 접점 내부 온도, 부호 있는 12비트 | 부호 확장 후 0.0625°C 곱하기 |
| D3 | 예약 비트 | 0인지 검사 |
| D2 | VCC 단락 | 고장 원인에 포함 |
| D1 | GND 단락 | 고장 원인에 포함 |
| D0 | 열전대 단선 | 고장 원인에 포함 |
첫 수신 바이트가 D31~D24입니다. int.from_bytes(frame, "big")로 순서를 고정합니다. MCU에서는 uint32_t로 각 바이트를 시프트해 조립하세요. 온도 필드의 부호 비트를 검사하기 전에 무부호 오른쪽 시프트만 적용하면 음수가 큰 양수로 바뀝니다.
예를 들어 열전대 필드 0x3FFF는 -1 코드이므로 -0.25°C입니다. 내부 온도 필드 0xFF0는 -16 코드, 즉 -1°C입니다. 내부 온도를 열전대 결과에 다시 더하지 않습니다. 이미 보상된 열전대 온도를 출력하는 부품입니다.
재현 가능한 Python 디코더
아래 코드를 max31855_decode.py로 저장하세요. Python 3 표준 라이브러리만 사용합니다. 하드웨어 통신 없이 캡처한 프레임을 검증하는 예제이며 MCU SPI 드라이버는 별도로 연결해야 합니다.
def signed(value, bits):
return value - (1 << bits) if value & (1 << (bits - 1)) else value
def decode(frame):
if not isinstance(frame, (bytes, bytearray)):
raise TypeError("frame must be bytes or bytearray")
if len(frame) != 4:
raise ValueError("exactly four bytes required")
word = int.from_bytes(frame, "big")
if word & ((1 << 17) | (1 << 3)):
raise ValueError("reserved bit is not zero")
detail = word & 7
if bool(word & (1 << 16)) != bool(detail):
raise ValueError("fault flag/detail mismatch")
faults = tuple(name for mask, name in
((1, "open"), (2, "short_gnd"), (4, "short_vcc"))
if detail & mask)
if faults:
return {"ok": False, "faults": faults, "tc_c": None, "cj_c": None}
tc = signed((word >> 18) & 0x3FFF, 14) / 4
cj = signed((word >> 4) & 0xFFF, 12) / 16
return {"ok": True, "faults": (), "tc_c": tc, "cj_c": cj}
예약 비트와 고장 요약/상세 비트의 모순은 이 예제에서 잘못된 프레임으로 거르는 정책입니다. CRC가 있는 프로토콜은 아니므로 이 검사만으로 통신 무결성을 보장할 수 없습니다. 고장이 있으면 두 온도를 모두 None으로 내보내도록 보수적으로 정했습니다. 제어기에서는 이 결과를 히터 출력 허용 조건과 분리하고, 마지막 정상값을 현재 정상값처럼 덮어 쓰지 마세요.
정상·음수·단선 예제 실행
다음 코드를 check_vectors.py로 저장하고 두 파일을 같은 폴더에 둡니다.
from max31855_decode import decode
assert decode(bytes.fromhex("01901900"))["tc_c"] == 25.0
r = decode(bytes.fromhex("FFFCFF00"))
assert (r["tc_c"], r["cj_c"]) == (-0.25, -1.0)
r = decode(bytes.fromhex("00010001"))
assert r["faults"] == ("open",) and r["tc_c"] is None
for raw in ("00000001", "00010000", "00020000", "00000008"):
try:
decode(bytes.fromhex(raw))
except ValueError:
pass
else:
raise AssertionError("invalid frame accepted")
print("PASS: normal, negative, open, malformed")
python -B check_vectors.py
출력은 PASS: normal, negative, open, malformed입니다. 01901900은 열전대 25°C와 내부 온도 25°C, FFFCFF00은 열전대 -0.25°C와 내부 온도 -1°C입니다. 00010001은 D16과 D0이 함께 켜진 단선 예제입니다. 고장 원인을 하나만 표시하지 않도록 여러 상세 비트를 함께 보존합니다.
2026-10-21 검증에서는 공식 표의 고정 벡터 4개, 열전대 필드 16,384개와 내부 온도 필드 4,096개를 각각 독립적으로 전수 검사했습니다. 총 20,480개 필드 코드와 7개 고장 조합, 잘못된 길이·타입·예약 비트·고장 비트 모순도 통과했습니다. 이는 합성 데이터에 대한 디코더 검증입니다. 두 필드 전체 조합이나 실물 보드의 정확도·배선을 시험한 결과는 아닙니다. 비트 표현 범위가 실제 측정 가능한 온도 범위를 뜻하지도 않습니다.
MCU에서 읽을 때 확인할 순서
- 부품의 열전대 종류와 모듈 전압 회로를 확인합니다. IC 자체 권장 전원은 3.0~3.6V이므로 5V 내성 여부를 모듈 이름으로 추정하지 않습니다.
- CS를 내리고 MSB 우선으로 32클록을 한 번의 읽기 구간에 보냅니다. 네 바이트 사이에서 CS가 올라가지 않도록 드라이버 설정과 로직 분석기로 확인합니다.
- SCK 유휴 LOW, 상승 에지 샘플 방식으로 데이터시트 타이밍과 대조합니다. SPI 상한은 5MHz이며 처음에는 더 낮은 클록으로 시작합니다.
- CS를 다시 HIGH로 놓아 다음 변환 데이터가 갱신되도록 합니다. 연속 변환 최대 시간은 100ms입니다. 첫 전원 투입 뒤에는 전원이 권장 최저 전압을 넘은 시점부터 초기 변환 대기 시간 200ms를 별도로 확보합니다. 자주 읽는다고 새 변환이 생기지 않습니다.
- 단선을 만들어 D16·D0과 UI 오류 표시를 확인하고, 실제 온도는 별도 기준 온도계와 비교합니다. 단락 시험은 회로 조건을 확인한 뒤 수행합니다.
값이 이상할 때
| 증상 | 먼저 볼 항목 |
|---|---|
| 음수가 4천°C 근처 큰 양수 | 14비트 부호 확장 누락 |
| 내부 온도가 16배 또는 4배 차이 | 두 필드의 배율 혼용 |
| 예약 비트가 1 또는 고장 비트 모순 | CS 구간, 클록 에지, 비트 밀림, 바이트 순서 |
| 단선인데 높은 온도 표시 | D16 확인 전에 온도 사용 |
| 값이 반복되거나 갱신이 늦음 | CS HIGH 유지, 변환 시간, 읽기 주기 |
| 정상 통신인데 온도 오차 큼 | 열전대 종류·극성, 접점, 주변 발열과 냉접점 온도 |
검증된 프레임이라도 열전대 자체의 오차와 설치 조건은 남습니다. 공식 제품 정보와 데이터시트의 열전대 종류별 범위·정확도 조건을 함께 확인하세요.
댓글
첫 댓글을 남겨 보세요.