Files
2026-08-22 19:14:55 +09:00

119 lines
4.0 KiB
C

/*
* main.c 안의 카운팅 로직(load_counts / drive / HAL_TIM_PeriodElapsedCallback)을
* 그대로 옮겨와 PC에서 돌려보는 검증용 프로그램.
* MCU/HAL 없이도 "틱이 몇 번 지나면 LED가 몇 번 깜박이는가"가 설계값과
* 정확히 일치하는지를 기계적으로 확인하기 위한 것.
*/
#include <stdio.h>
#include <stdint.h>
#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;
}