RTC 모듈의 자정이 12시로 표시되거나, 전원을 다시 넣은 뒤 그럴듯한 시각이 계속 기록된다면 시(hour) 해독과 시각 신뢰 상태를 함께 점검하세요. 아래 예제는 DS3231의 시 레지스터를 0~23으로 바꾸는 작은 함수와, 모든 바이트 입력을 검사하는 독립 실행 테스트입니다.
1. 시 레지스터의 모드를 먼저 구분하기
Analog Devices DS3231 공식 데이터시트 Rev.10의 Figure 1과 Clock and Calendar, Status Register 절을 기준으로 읽습니다. 시 레지스터는 0x02, 상태 레지스터는 0x0F입니다. 시 레지스터 bit 6이 1이면 12시간제이고 bit 5는 PM 표시입니다. 24시간제에서는 bit 5가 20시 자리의 일부입니다. 시 숫자는 BCD이므로 0x23을 십진수 35로 출력하면 안 됩니다.
| 원시 시 바이트 |
해석 |
24시간 출력 |
0x00 |
24시간제 0시 |
00시 |
0x23 |
24시간제 23시 |
23시 |
0x52 |
12시간제 12 AM |
00시 |
0x72 |
12시간제 12 PM |
12시 |
0x61 |
12시간제 1 PM |
13시 |
0x1A / 0x24 / 0x40 |
잘못된 BCD / 24시 / 12시간제 0시 |
거부 |
변환식은 12시간제에서 (hour12 % 12) + (PM ? 12 : 0)입니다. 먼저 모드에 맞춰 제어 비트를 분리한 다음, BCD 자리와 시 범위를 검사하는 순서로 구현합니다. bit 7이 켜진 입력도 거부합니다.
2. OSF가 켜진 값을 정상 시각으로 쓰지 않기
상태 bit 7인 OSF는 발진기가 멈췄거나 멈춘 이력이 있음을 나타내며, 0을 쓸 때까지 유지됩니다. 이 예제는 OSF가 1이면 시 해독 결과를 사용하지 않는 정책을 택합니다. OSF=0만으로 날짜나 외부 표준시와의 일치를 보장할 수는 없습니다. 공식 데이터시트의 OSF 설명을 확인하세요.
제품에서는 실패를 정상적인 00:00으로 바꾸지 마세요. time_valid=false 같은 상태를 로그에 남기고, 신뢰할 수 있는 기준으로 RTC를 다시 설정한 뒤 OSF를 처리하는 별도 복구 흐름을 두는 편이 좋습니다. 상태 레지스터에 0을 통째로 쓰면 다른 비트까지 영향을 받으므로 레지스터별 쓰기 규칙을 검토해야 합니다.
3. PC에서 실행하는 C11 예제
코드를 rtc_hour.c로 저장하고 gcc -std=c11 -Wall -Wextra -Werror rtc_hour.c -o rtc_hour로 빌드하세요. Linux에서는 ./rtc_hour, Windows에서는 rtc_hour.exe로 실행합니다. MCU HAL과 I²C 드라이버에 의존하지 않습니다.
#include <assert.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
/* Decode only the hours register (0x02), with status (0x0F). */
static bool rtc_hour(uint8_t raw, uint8_t status, uint8_t *out)
{
if (out == NULL || (status & 0x80u) || (raw & 0x80u))
return false;
const bool mode12 = (raw & 0x40u) != 0u;
const uint8_t bcd = raw & (mode12 ? 0x1Fu : 0x3Fu);
const unsigned ones = bcd & 0x0Fu;
const unsigned tens = bcd >> 4;
if (ones > 9u || tens > 9u)
return false;
unsigned hour = tens * 10u + ones;
if (mode12) {
if (hour < 1u || hour > 12u)
return false;
hour = (hour % 12u) + ((raw & 0x20u) ? 12u : 0u);
} else if (hour > 23u) {
return false;
}
*out = (uint8_t)hour;
return true;
}
static unsigned bcd_encode(unsigned n)
{
return (n / 10u) * 16u + n % 10u;
}
int main(void)
{
/* Construct the valid encodings from known decimal hours. */
int expected[256];
for (unsigned i = 0; i < 256u; ++i)
expected[i] = -1;
for (unsigned h = 0; h < 24u; ++h) {
expected[bcd_encode(h)] = (int)h;
const unsigned h12 = (h % 12u == 0u) ? 12u : h % 12u;
const unsigned raw12 = 0x40u | (h >= 12u ? 0x20u : 0u)
| bcd_encode(h12);
expected[raw12] = (int)h;
}
unsigned accepted = 0;
for (unsigned raw = 0; raw < 256u; ++raw) {
uint8_t hour = 77u;
const bool ok = rtc_hour((uint8_t)raw, 0u, &hour);
assert(ok == (expected[raw] >= 0));
if (ok) {
assert(hour == (uint8_t)expected[raw]);
++accepted;
} else {
assert(hour == 77u); /* failure leaves output untouched */
}
hour = 77u;
assert(!rtc_hour((uint8_t)raw, 0x80u, &hour));
assert(hour == 77u);
}
assert(accepted == 48u);
const uint8_t raw_demo[] = {0x52u, 0x72u, 0x61u, 0x23u};
const uint8_t hour_demo[] = {0u, 12u, 13u, 23u};
for (unsigned i = 0; i < sizeof raw_demo; ++i) {
uint8_t hour = 0u;
assert(rtc_hour(raw_demo[i], 0x0Fu, &hour));
assert(hour == hour_demo[i]);
printf("raw=0x%02X -> %02u:xx\n",
(unsigned)raw_demo[i], (unsigned)hour);
}
assert(!rtc_hour(0x12u, 0u, NULL));
puts("PASS: 256 hour bytes x 2 OSF states; 48 valid encodings");
return 0;
}
예상 출력:
raw=0x52 -> 00:xx
raw=0x72 -> 12:xx
raw=0x61 -> 13:xx
raw=0x23 -> 23:xx
PASS: 256 hour bytes x 2 OSF states; 48 valid encodings
검사에서는 십진수 0~23으로부터 정상 인코딩 표를 만들고, 원시 바이트 0x00~0xFF 전체를 대조합니다. OSF=0에서 48개 인코딩이 허용되고, OSF=1에서는 256개 모두 거부되어야 합니다. 실패할 때 출력 변수가 바뀌지 않는지도 검사합니다. BCD 오류를 조용히 보정하는 코드가 섞이면 이 테스트가 실패합니다.
4. 펌웨어에 연결할 때 확인할 것
I²C 전송 성공과 읽은 바이트 수를 먼저 확인한 뒤 함수에 전달하세요. 날짜·분·초를 서로 다른 시점에 읽으면 경계 시각에서 섞일 수 있습니다. DS3231은 START에서 시간용 사용자 버퍼를 갱신하므로 시간·날짜 레지스터를 연속해서 읽는 방식을 검토합니다. 버퍼 동작은 데이터시트 Clock and Calendar 절에 설명되어 있습니다.
이 함수는 시 값 하나만 검사합니다. 전체 날짜의 범위·윤년·요일·세기 기준, 분·초 해독, 시간대 정책, I²C 오류, OSF 읽기와 시간 읽기 사이의 상태 변화는 별도로 다뤄야 합니다. RTC에 UTC를 저장할지 현지 시각을 저장할지도 제품 규약에 적어 두세요. 알람용 시 레지스터는 제어 비트가 다르므로 이 함수를 그대로 사용하지 않습니다.
본 예제는 PC에서 바이트 해독과 512개 입력 조합을 검증하는 용도입니다. DS3231 실물의 배터리 전환이나 I²C 파형은 측정하지 않았습니다. 원시 시 바이트와 상태 바이트를 함께 기록하면 현장에서 12/24시간 설정 오류와 신뢰 상태를 구분하기 쉽습니다.
댓글
첫 댓글을 남겨 보세요.