/* * main.c 안의 카운팅 로직(load_counts / drive / HAL_TIM_PeriodElapsedCallback)을 * 그대로 옮겨와 PC에서 돌려보는 검증용 프로그램. * MCU/HAL 없이도 "틱이 몇 번 지나면 LED가 몇 번 깜박이는가"가 설계값과 * 정확히 일치하는지를 기계적으로 확인하기 위한 것. */ #include #include #define LED_MASK 0x01FFu #define N_POINTS 9 #define COUNT_MIN 1 #define COUNT_MAX 15 #define TICKS_BURST 30 #define TICKS_IDLE 10 #define TICKS_CYCLE (TICKS_BURST + TICKS_IDLE) static uint16_t tick = 0; static uint16_t cycle = 0; static uint8_t cnt[N_POINTS]; /* --- 실제 main.c와 동일한 로직 --- */ static void load_counts(void) { for (uint8_t k = 0; k < N_POINTS; k++) { cnt[k] = (uint8_t)(((cycle + k) % COUNT_MAX) + COUNT_MIN); } } static uint32_t drive_bsrr(uint16_t bits) { /* 실제 GPIOC->BSRR 대신, 계산 결과만 반환 */ return ((uint32_t)( bits & LED_MASK) << 16) | ((uint32_t)(~bits & LED_MASK)); } /* 검증용 상태: 각 지점의 "실제 관측된" 상승 에지(꺼짐->켜짐) 횟수 */ static uint16_t rising_edges[N_POINTS]; static uint16_t prev_bits = 0; static void tick_step(void) { uint16_t bits = 0; if (tick < TICKS_BURST && (tick & 1u) == 0u) { for (uint8_t k = 0; k < N_POINTS; k++) { if (tick < (uint16_t)cnt[k] * 2u) { bits |= (uint16_t)(1u << k); } } } /* 검증: 상승 에지 카운트 (디코더가 세는 것과 동일한 방식) */ for (uint8_t k = 0; k < N_POINTS; k++) { uint16_t m = (uint16_t)(1u << k); if ((bits & m) && !(prev_bits & m)) rising_edges[k]++; } prev_bits = bits; (void)drive_bsrr(bits); /* 레지스터 계산이 죽지 않는지만 확인 */ if (++tick >= TICKS_CYCLE) { tick = 0; printf("CYCLE=%u 목표:", cycle + 1); for (uint8_t k = 0; k < N_POINTS; k++) printf(" G%u=%2u", k + 1, cnt[k]); printf("\n 실측:"); int all_match = 1; for (uint8_t k = 0; k < N_POINTS; k++) { printf(" G%u=%2u", k + 1, rising_edges[k]); if (rising_edges[k] != cnt[k]) all_match = 0; } printf(" [%s]\n", all_match ? "일치" : "!! 불일치 !!"); for (uint8_t k = 0; k < N_POINTS; k++) rising_edges[k] = 0; cycle++; load_counts(); } } int main(void) { load_counts(); printf("=== 사이클 하나가 정확히 40틱(8.0s)인지 확인 ===\n"); uint16_t total_ticks = 0; uint16_t start_cycle = cycle; while (cycle == start_cycle) { tick_step(); total_ticks++; } printf("1 사이클 = %u 틱 (기대값 %u) -> %s\n\n", total_ticks, (unsigned)TICKS_CYCLE, total_ticks == TICKS_CYCLE ? "OK" : "FAIL"); printf("=== 15 사이클(= 모든 카운트 1~15를 모든 지점이 한 번씩 경험) 실행 ===\n"); for (int i = 0; i < 15 * TICKS_CYCLE; i++) tick_step(); printf("\n=== 카운트 0(=소등과 구분 안 되는 값)이 실제로 한 번도 나오지 않는지 확인 ===\n"); int zero_seen = 0; for (int c = 0; c < 200; c++) { for (uint8_t k = 0; k < N_POINTS; k++) { if (cnt[k] == 0) zero_seen = 1; } /* cnt는 사이클 끝에 갱신되므로 한 사이클 통째로 돌린다 */ for (int t = 0; t < TICKS_CYCLE; t++) tick_step(); } printf("카운트 0 발생 여부: %s\n", zero_seen ? "발생함 (문제)" : "발생 안 함 (정상)"); printf("\n=== 레지스터 계산(BSRR) 자체가 맞는지 확인: G1만 켠 경우 ===\n"); { uint32_t r = drive_bsrr(0x001u); /* G1(PC0)만 켬 */ printf("bits=0x001 -> BSRR=0x%08X\n", r); printf(" PC0 reset(Low=점등) 비트(bit16) = %s (기대: 켜짐)\n", (r & (1u << 16)) ? "켜짐" : "꺼짐"); printf(" PC1 set(High=소등) 비트(bit1) = %s (기대: 켜짐, 즉 꺼짐 상태)\n", (r & (1u << 1)) ? "켜짐" : "꺼짐"); } return 0; }