INA219를 연결했는데 역방향 전류의 션트 전압이 큰 양수로 나오거나, 12V 부근의 버스 전압이 약 8배로 표시되는 경우가 있습니다. 먼저 I²C에서 받은 두 바이트를 그대로 기록하고, 바이트 결합 → 부호 처리 → 전압 비트 추출 → 상태 판정을 나눠 확인하면 계산 오류를 좁힐 수 있습니다.
이 글은 MCU 펌웨어에서 수집한 INA219 원시 레지스터를 PC에서도 재현하는 기술 가이드입니다. Python 3 표준 라이브러리만 사용하는 해독 예제를 실행하고, 같은 입력을 펌웨어의 정수 계산과 비교합니다. 실물 센서의 통신·정확도·교정 시험은 별도로 필요합니다.
1. 레지스터의 값과 상태 비트를 분리하기
기준은 TI INA219 공식 데이터시트 Rev. G의 §8.5.1, §8.6.3과 Figure 20~24입니다.
| 읽을 레지스터 | 해독 규칙 | 결과 단위 |
|---|---|---|
| Shunt Voltage, 0x01 | 16비트 2의 보수 × 10 | µV |
| Bus Voltage, 0x02 | raw를 오른쪽으로 3비트 이동한 값 × 4 | mV |
| Bus Voltage bit 1 | CNVR, 변환 완료 상태 | 참/거짓 |
| Bus Voltage bit 0 | OVF, 전류·전력 계산 오버플로 | 참/거짓 |
Bus Voltage bit 2는 예약 비트입니다. raw * 4로 계산하면 하위 상태 비트가 전압에 섞입니다. 센서 데이터와 무관하게 정수 연산의 순서를 먼저 검증할 수 있습니다.
2. 바이트 순서와 음수 처리를 함께 점검하기
입력은 I²C에서 수신한 상위 바이트, 하위 바이트 순서입니다. 드라이버가 이미 uint16_t로 결합한 값을 반환하는지, 두 바이트 배열을 반환하는지 인터페이스 계약부터 확인하세요. 이미 결합된 값을 한 번 더 바이트 교환하면 다른 오류를 만들 수 있습니다.
예제는 raw >= 0x8000인 션트 값에서 65536을 빼서 음수를 만듭니다. 계산 과정에 부동소수점을 쓰지 않아 로그와 기대값을 정수로 비교하기 쉽습니다. MCU에 옮길 때는 결합된 션트 값을 int32_t에 담은 뒤 65536을 빼고 10을 곱하면 이 순서를 유지할 수 있습니다. unsigned 변수에서 바로 빼면 원하는 음수가 되지 않는 점을 확인하세요.
3. 그대로 실행하는 해독 예제
아래 전체 코드를 ina219_decode.py로 저장하고 python -B ina219_decode.py를 실행합니다. Windows에서 Python 명령이 py인 경우 py -3 -B ina219_decode.py를 사용하세요. 라이브러리 설치와 센서 연결 없이 계산을 재현합니다.
def word_be(data):
if not isinstance(data, (bytes, bytearray)) or len(data) != 2:
raise ValueError("register must contain exactly two bytes")
return (data[0] << 8) | data[1]
def decode_ina219(shunt_bytes, bus_bytes):
shunt_raw = word_be(shunt_bytes)
bus_raw = word_be(bus_bytes)
signed_shunt = shunt_raw - 65536 if shunt_raw & 0x8000 else shunt_raw
return {
"shunt_uv": signed_shunt * 10,
"bus_mv": (bus_raw >> 3) * 4,
"conversion_ready": bool(bus_raw & 0x0002),
"math_overflow": bool(bus_raw & 0x0001),
}
if __name__ == "__main__":
print(decode_ina219(bytes.fromhex("07 D0"), bytes.fromhex("5D 98")))
print(decode_ina219(bytes.fromhex("F8 30"), bytes.fromhex("5D 9B")))
예상 출력은 다음과 같습니다.
{'shunt_uv': 20000, 'bus_mv': 11980, 'conversion_ready': False, 'math_overflow': False}
{'shunt_uv': -20000, 'bus_mv': 11980, 'conversion_ready': True, 'math_overflow': True}
첫 번째 입력 0x07D0, 0x5D98은 데이터시트 Table 8의 전압 예시와 비교할 수 있습니다. 두 번째 입력은 같은 버스 전압에 상태 비트 1·0을 설정하고 션트 방향을 바꾼 소프트웨어 검증용 벡터입니다. 센서에서 캡처한 측정값으로 제시하는 것이 아닙니다.
| 션트 raw | 션트 계산 결과 | 점검 목적 |
|---|---|---|
| 0x0000 | 0 µV | 영점 |
| 0x07D0 | +20000 µV | 양수 바이트 결합 |
| 0xF830 | -20000 µV | 음수 해독 |
| 0x7D00 | +320000 µV | 데이터시트 PGA /8 예시 |
| 0x8300 | -320000 µV | 데이터시트 PGA /8 음수 예시 |
4. 상태 비트를 샘플 번호처럼 사용하지 않기
CNVR은 변환·평균·계산 완료 후 설정되며, 새 동작 모드 설정 또는 Power 레지스터 읽기로 해제되는 조건이 있습니다(§8.6.3.2). Bus 레지스터를 읽을 때마다 새 샘플을 한 번 소비했다고 판단하면 안 됩니다. 연속 측정에서는 수집 시각과 변환 설정도 로그에 남기세요.
OVF는 전류·전력 계산 범위의 문제입니다. 예제는 플래그를 그대로 전달하므로 상위 코드가 해당 전류·전력 값을 경고 또는 무효로 처리할 수 있습니다. OVF == False만으로 입력 배선이나 모든 측정값의 정상 여부를 보장할 수는 없습니다.
션트 전압의 PGA 범위와 버스 전압의 BRNG 설정을 확인해야 합니다. 32V 레지스터 범위 설정을 실제 입력 허용 전압으로 해석하지 마세요. TI 제품 사양의 버스 동작 범위는 0~26V입니다. 전류·전력 레지스터를 사용하려면 션트 저항과 Calibration 설정도 맞춰야 합니다.
5. 계산 검증과 보드 검증을 나누기
게시 전 예제 함수에 션트 raw 65536개와 버스 raw 65536개를 각각 입력했습니다. 션트 기대값은 Python의 int.from_bytes(..., signed=True)로 독립 계산했고, 버스 기대값은 정수 나눗셈으로 구했습니다. 부호 전환, 바이트 결합, 예약 비트·CNVR·OVF의 분리를 확인했습니다. 빈 값·1바이트·3바이트 입력도 거부합니다. 이 검증은 레지스터 해독 연산을 대상으로 하며 I²C 전송 성공이나 센서의 아날로그 정확도를 시험한 결과는 아닙니다.
보드에서는 레지스터 주소, 수신 길이, 두 원시 바이트, 설정 값, 수집 시각을 함께 기록한 뒤 위 함수에 같은 바이트를 넣으세요. Python과 펌웨어 결과가 다르면 통신 계층보다 먼저 결합·부호·배율 순서를 비교할 수 있습니다.
| 증상 | 먼저 비교할 항목 |
|---|---|
| 음수가 매우 큰 양수로 표시됨 | 16비트 부호를 적용하기 전 곱셈했는지 |
| 전압이 기대보다 약 8배 큼 | bus raw를 3비트 이동했는지 |
| 값이 갑자기 크게 바뀜 | 원시 바이트 순서와 I²C 실패 처리 |
| 전압은 있는데 전류·전력은 0 | Calibration 값과 전원 재인가 후 설정 |
| 동일 값이 여러 번 저장됨 | CNVR만으로 새 샘플을 판단했는지 |
I²C 읽기가 실패했을 때 00 00을 정상 측정값으로 넘기지 말고 전송 오류로 구분하세요. 앱 표시용 V 변환은 해독 후 bus_mv / 1000으로 수행하고, 진단 로그에는 원시 바이트와 정수 단위를 함께 남기는 편이 비교에 도움이 됩니다.
공식 문서
- TI INA219 데이터시트 Rev. G: §8.5.1, §8.6.3.1~2, Table 8.
- TI INA219 제품 페이지: 입력 범위와 공식 문서.
- Python int.from_bytes 공식 문서: 독립 부호 해독 비교에 사용.
댓글
첫 댓글을 남겨 보세요.