diff --git a/main.c b/main.c index b9438c9..e77d1f8 100644 --- a/main.c +++ b/main.c @@ -20,6 +20,7 @@ #define MAIN_LOOP_SLEEP 10U // Main loop delay in ms #define BUTTON_LONG_PRESS_DURATION_MS 1000U // Long press threshold +#define BUTTON_SHORT_PRESS_DURATION_MS 50U // Short press threshold #define BUTTON_IGNORE_DURATION_MS 2000U // Time button ignored after long press #define BUTTON_CONFIRMATION_BLINK_LOOPS 10U // Blink animation for confirmation #define BUTTON_CONFIRMATION_BLINK_DURATION_MS 50U @@ -27,18 +28,32 @@ /** Convert milliseconds to system ticks */ #define MS_TO_TICKS(ms) ((ms) / MAIN_LOOP_SLEEP) +typedef enum _Mode +{ + ANIMATION_BLINK, + ANIMATION_GLOW, + STATIC_FULL, + MAX_COUNT, +} eMode; + /** Global flags */ volatile bool bLedEnabled = true; volatile bool bBtnPressed = false; +volatile eMode eModeCurrent = ANIMATION_BLINK; // Forward declarations -void blinkLed(bool resetCounters); +ISR(PORTA_PORT_vect); +static void software_reset(void); +void initPWM(void); +void setPWM_PA2(uint8_t duty); static inline void leds_off(void); static inline void leds_on(void); static void battery_level_indicator(void); -static void handleSwitch(void); -static void software_reset(void); -ISR(PORTA_PORT_vect); +static bool handleSwitch(void); +static inline void switchMode(void); +void ledAnimationBlink(bool resetCounters); +void ledAnimationGlow(void); +void ledStaticFull(void); /** * @brief Main entry point @@ -47,20 +62,21 @@ int main(void) { // Configure LED pins as outputs VPORTA.DIR = (PA1_SET_MASK | PA2_SET_MASK | PA3_SET_MASK | PA6_SET_MASK | PA7_SET_MASK); + initPWM(); // Configure PA0 as input with pull-up VPORTA.DIR &= ~BUTTON_PIN_MASK; // Input PORTA.PIN0CTRL = PORT_PULLUPEN_bm; // Pull-up enabled - // Ensure all LEDs off at startup - leds_off(); + leds_off(); // Ensure all LEDs off at startup battery_level_indicator(); // TODO: Implement bool bLedEnabledOld = bLedEnabled; + eModeCurrent = ANIMATION_BLINK; // Set the mode to start with while (true) { - handleSwitch(); // Check switch state + bBtnPressed = handleSwitch(); // Check switch state // Light LEDs while button is pressed if (bBtnPressed) @@ -103,7 +119,20 @@ int main(void) { if (bLedEnabled && !bBtnPressed) { - blinkLed(false); // run normal blink + switch (eModeCurrent) + { + case ANIMATION_BLINK: + ledAnimationBlink(false); // run normal blink + break; + case ANIMATION_GLOW: + ledAnimationGlow(); + break; + case STATIC_FULL: + ledStaticFull(); + break; + default: + break; + } } } @@ -111,12 +140,46 @@ int main(void) } } +/** + * @brief Move to next mode + */ +static inline void switchMode(void) +{ + eModeCurrent = (eModeCurrent + 1) % MAX_COUNT; +} + +/** + * @brief Init PWM for PA2 + */ +void initPWM(void) +{ + // No PORTMUX needed - PA2 is WO2 by default + + // TCA0 in normal mode (single slope PWM) + TCA0.SINGLE.CTRLB = TCA_SINGLE_CMP2EN_bm | TCA_SINGLE_WGMODE_SINGLESLOPE_gc; + + // Set period for ~19.5kHz PWM (5MHz / 256 = ~19.5kHz) + TCA0.SINGLE.PER = 0xFF; + + // Start timer with DIV1 (no prescaler) + TCA0.SINGLE.CTRLA = TCA_SINGLE_CLKSEL_DIV1_gc | TCA_SINGLE_ENABLE_bm; +} + +/** + * @brief Set PWM duty cycle for PA2 + */ +void setPWM_PA2(uint8_t duty) +{ + TCA0.SINGLE.CMP2 = duty; +} + /** * @brief Turn off all controlled LEDs (PA1, PA2, PA3) */ static inline void leds_off(void) { - VPORTA.OUT &= (uint8_t) ~(PA1_SET_MASK | PA2_SET_MASK | PA3_SET_MASK); + VPORTA.OUT &= (uint8_t) ~(PA1_SET_MASK | PA3_SET_MASK); + setPWM_PA2(0U); } /** @@ -124,7 +187,8 @@ static inline void leds_off(void) */ static inline void leds_on(void) { - VPORTA.OUT |= (PA1_SET_MASK | PA2_SET_MASK | PA3_SET_MASK); + VPORTA.OUT |= (PA1_SET_MASK | PA3_SET_MASK); + setPWM_PA2(255U); } /** @@ -139,9 +203,10 @@ static void battery_level_indicator(void) /** * @brief Handle momentary switch input on PA0 * - * A long press toggles ::bLedEnabled. + * A long press toggles bLedEnabled. + * A short press swiches the mode. */ -static void handleSwitch(void) +static bool handleSwitch(void) { static uint16_t pressTicks = 0; ///< Press duration counter static bool prevPressed = false; ///< Previous button state @@ -150,22 +215,32 @@ static void handleSwitch(void) if (pressed) { - bBtnPressed = true; if (pressTicks < 0xFFFF) pressTicks++; // Prevent overflow } else { - bBtnPressed = false; + // Button released + if (prevPressed) + { + // Check if it was a short press (not a long press) + if (pressTicks >= MS_TO_TICKS(BUTTON_SHORT_PRESS_DURATION_MS) && + pressTicks < MS_TO_TICKS(BUTTON_LONG_PRESS_DURATION_MS)) + { + switchMode(); + } + } + pressTicks = 0; } - if (prevPressed && pressTicks >= MS_TO_TICKS(BUTTON_LONG_PRESS_DURATION_MS)) + if (pressed && pressTicks >= MS_TO_TICKS(BUTTON_LONG_PRESS_DURATION_MS)) { bLedEnabled = !bLedEnabled; // Toggle LED blinking } prevPressed = pressed; + return pressed; } /** @@ -209,7 +284,7 @@ ISR(PORTA_PORT_vect) * 18: all off, wait 250 ms → restart * Special: every 3rd cycle, all LEDs ON for 250 ms */ -void blinkLed(bool resetCounters) +void ledAnimationBlink(bool resetCounters) { const uint8_t T50 = MS_TO_TICKS(50); const uint8_t T100 = MS_TO_TICKS(100); @@ -276,7 +351,7 @@ void blinkLed(bool resetCounters) break; case 12: // LED 3–6 on, wait 50 ms - VPORTA.OUT |= PA2_SET_MASK; + setPWM_PA2(255U); if (counter >= T50) { counter = 0; @@ -294,7 +369,7 @@ void blinkLed(bool resetCounters) break; case 16: // LED 3–6 on, wait 50 ms - VPORTA.OUT |= PA2_SET_MASK; + setPWM_PA2(255U); if (counter >= T50) { counter = 0; @@ -320,7 +395,7 @@ void blinkLed(bool resetCounters) break; case 20: // special: all LEDs on for 250 ms - VPORTA.OUT |= (PA1_SET_MASK | PA2_SET_MASK | PA3_SET_MASK); + leds_on(); if (counter >= T250) { counter = 0; @@ -329,3 +404,38 @@ void blinkLed(bool resetCounters) break; } } + +/** + * @brief All LEDs with static full power + */ +void ledStaticFull(void) +{ + leds_on(); +} + +/** + * @brief Inner LEDs with glow animation + */ +void ledAnimationGlow(void) +{ + static uint8_t brightness = 0; + static int8_t direction = 1; + + // Update brightness level every call (10ms) + brightness += direction; + + // Reverse direction at limits + if (brightness >= 100U) + { + brightness = 100U; + direction = -1; + } + else if (brightness == 10U) + { + brightness = 10U; + direction = 1; + } + + // Apply PWM brightness to LED 3-6 + setPWM_PA2(brightness * 255 / 100); // Scale 0-100 to 0-255 +} \ No newline at end of file