#include "gpio.h" #include #include "ch32v003fun.h" #include "systick.h" #define LED_BLINK_SLOW 1000 // Warning blink interval (ms) #define LED_BLINK_FAST 500 // Error blink interval (ms) #define LED_BREATH_PERIOD 2000 // Breathing effect period (ms) #define STATE_STABILITY 500 // Minimum time before state change (ms) #define LED_G (1 << 4) #define LED_B (1 << 3) typedef struct { uint32_t last_update; uint32_t stable_since; led_state_t current_state; led_state_t target_state; uint8_t blink_state; uint32_t last_blink; } led_status_t; static led_status_t led_status = {0}; void gpio_init(void) { // Enable clock for GPIOB RCC->APB2PCENR |= RCC_APB2Periph_GPIOB; // GPIOB: Pins 3 and 4 as Output, Push-Pull, 10MHz GPIOB->CFGLR &= ~((0xF << (4 * 3)) | (0xF << (4 * 4))); GPIOB->CFGLR |= ((GPIO_Speed_10MHz | GPIO_CNF_OUT_PP) << (4 * 3)) | ((GPIO_Speed_10MHz | GPIO_CNF_OUT_PP) << (4 * 4)); // GPIOB: Pin 9 as Output, Push-Pull, 10MHz GPIOB->CFGHR &= ~(0xF << (4 * (9 - 8))); GPIOB->CFGHR |= (GPIO_Speed_10MHz | GPIO_CNF_OUT_PP) << (4 * (9 - 8)); led_status.current_state = LED_STATE_OFF; led_status.target_state = LED_STATE_OFF; GPIOB->BSHR = LED_G | LED_B; } void led_status_set(led_state_t state) { uint32_t now = millis(); // stability timer upd on state change if (led_status.target_state != state) { led_status.stable_since = now; led_status.target_state = state; } } static inline void leds(bool g, bool b) { uint32_t val = (g ? LED_G << 16 : LED_G) | (b ? LED_B << 16 : LED_B); GPIOB->BSHR = val; } void led_status_process(void) { uint32_t now = millis(); if (now - led_status.stable_since < STATE_STABILITY) { return; } switch (led_status.target_state) { case LED_STATE_OFF: GPIOB->BSHR = LED_G | LED_B; break; case LED_STATE_ON: leds(1, 0); // green on, blue off break; case LED_STATE_WARNING: if (now - led_status.last_blink >= LED_BLINK_SLOW) { led_status.blink_state = !led_status.blink_state; led_status.last_blink = now; leds(led_status.blink_state, 0); } break; case LED_STATE_ERROR: if (now - led_status.last_blink >= LED_BLINK_FAST) { led_status.blink_state = !led_status.blink_state; led_status.last_blink = now; leds(led_status.blink_state, !led_status.blink_state); } break; case LED_STATE_BUSY: bool blue_on = (now % LED_BREATH_PERIOD) < LED_BREATH_PERIOD / 2; leds(0, blue_on); break; } }