Files
templates/c/led-indicator/README.md

5.9 KiB
Raw Blame History

LED Indicator

Неблокирующая C99-библиотека для индикации состояний STARTUP, WORK, ACTIVITY, WARNING, ERROR и CRITICAL с разными рисунками и частотами. Один экземпляр обслуживает несколько светодиодов.

Ядро не знает о GPIO, PWM, сдвиговом регистре, RTOS и модели таймера. Порт передаёт логическое состояние канала наружу и читает монотонное время в миллисекундах. В библиотеке нет задержек, динамической памяти, прерываний и изменяемого глобального состояния.

приложение -> LedIndicator_SetMode/Process -> ядро -> write/now_ms -> GPIO/PWM/expander + TIM

Файлы

Файл Назначение Зависимости
led_indicator.h/.c режимы, шаблоны и планировщик C99, stdint.h
ports/stm32-hal GPIO и выбранный аппаратный TIM STM32 HAL
tests/test_led_indicator.c host-тесты, включая переполнение uint32_t libc

Встроенные режимы

Режим Сигнал
OFF / ON постоянно выключен / включён
STARTUP три коротких импульса, затем постоянно включён
WORK 100 мс включён, 900 мс выключен
ACTIVITY 50/50 мс
WARNING 250/250 мс
ERROR два импульса и пауза
CRITICAL три импульса и пауза

Частоты не зашиты в алгоритм. Скопируйте встроенную таблицу и измените duration_ms до инициализации:

static LedIndicator_Pattern patterns[LED_INDICATOR_MODE_COUNT];

LedIndicator_CopyDefaultPatterns(patterns, LED_INDICATOR_MODE_COUNT);
patterns[LED_INDICATOR_MODE_WORK].duration_ms[0] = 50U;
patterns[LED_INDICATOR_MODE_WORK].duration_ms[1] = 1950U;
config.patterns = patterns;
config.pattern_count = LED_INDICATOR_MODE_COUNT;

Таблица должна существовать всё время работы экземпляра. До восьми шагов описываются длительностями и битовой маской levels; шаблон может повторяться или после одного прохода перейти в final_level.

Контракт порта

void write(void *context, uint8_t channel, uint8_t logical_on);
uint32_t now_ms(void *context);

write получает именно логический уровень. Инверсию active-low, управление PWM или запись общего регистра расширителя выполняет порт. Переполнение 32-битной миллисекундной метки обработано разностью беззнаковых чисел.

Если время уже есть в планировщике приложения, now_ms можно оставить NULL и вызывать варианты LedIndicator_SetModeAt/LedIndicator_ProcessAt.

Быстрый старт без привязки к HAL

static LedIndicator led;
static LedIndicator_Channel state[2];
LedIndicator_Config cfg;
LedIndicator_Port port = {Board_LedWrite, Board_TimerMs, &board};

LedIndicator_ConfigDefault(&cfg);
LedIndicator_Init(&led, state, 2U, &port, &cfg);
LedIndicator_SetMode(&led, 0U, LED_INDICATOR_MODE_WORK);
LedIndicator_SetMode(&led, 1U, LED_INDICATOR_MODE_ERROR);

for (;;) {
    LedIndicator_Process(&led);
}

SetMode идемпотентен: повторный вызов того же режима в каждом проходе цикла не начинает рисунок заново. Для нового импульса события служит LedIndicator_RestartMode.

STM32F103, STM32F4, STM32G431 и STM32G474

Порт ports/stm32-hal принимает конкретный TIM_HandleTypeDef *; библиотека не использует HAL_GetTick() и не занимает SysTick. Настройте TIM как free-running, запустите его и передайте частоту счётчика после prescaler.

Скопируйте подходящий led_indicator_stm32_hal_config.*.template.h в каталог платы под именем led_indicator_stm32_hal_config.h.

static const LedIndicator_Stm32HalOutput outputs[] = {
    {STATUS_GPIO_Port, STATUS_Pin, 0U},
    {ERROR_GPIO_Port,  ERROR_Pin,  1U}
};
static LedIndicator_Stm32HalPort hw;
static LedIndicator_Port port;

HAL_TIM_Base_Start(&htim6); /* CNT = 1 кГц в данном примере. */
LedIndicator_Stm32HalPortInit(&hw, &htim6, 1000U,
                              outputs, 2U, &port);

LedIndicator_Process() должен вызываться чаще, чем переполняется выбранный TIM. Для 16-битного CNT на 1 кГц это не реже одного раза за 65 секунд. Сам таймер и его prescaler/period задаются в CubeMX или board-порте, а не в ядре.

Для К1921ВК028 и C28x используется тот же основной порт: now_ms возвращает счётчик, увеличиваемый обработчиком выбранного TIMER/CPU Timer, а write обращается к GPIO SDK. Такое разделение оставляет номер таймера и выводы в проекте конкретной платы.

Проверка

cmake -S c/led-indicator -B build/led-indicator
cmake --build build/led-indicator
ctest --test-dir build/led-indicator --output-on-failure