basic button toggle

This commit is contained in:
2025-09-06 00:05:39 +02:00
parent 0c6899c8a0
commit ddd8932ffa

124
main.c
View File

@ -15,22 +15,25 @@
#define PA1_SET_MASK 0x02 ///< LED 12 #define PA1_SET_MASK 0x02 ///< LED 12
#define PA2_SET_MASK 0x04 ///< LED 36 #define PA2_SET_MASK 0x04 ///< LED 36
#define PA3_SET_MASK 0x08 ///< LED 78 #define PA3_SET_MASK 0x08 ///< LED 78
#define PA6_SET_MASK 0x40 ///< Green LED #define PA6_SET_MASK 0x40 ///< Switch input (was green LED pin) TODO: Switch to PA0
#define PA7_SET_MASK 0x80 ///< Red LED #define PA7_SET_MASK 0x80 ///< Red LED
/** @} */ /** @} */
/** @brief Main loop delay in ms (system tick). */ #define MAIN_LOOP_SLEEP 10U // Main loop delay in ms (system tick)
#define MAIN_LOOP_SLEEP 10U #define BUTTON_PRESS_DURATION 1000U // Button needs to be pressed for at least 1000ms
/** @brief Convert milliseconds to system ticks (integer division). */ /** @brief Convert milliseconds to system ticks (integer division). */
#define MS_TO_TICKS(ms) ((ms) / MAIN_LOOP_SLEEP) #define MS_TO_TICKS(ms) ((ms) / MAIN_LOOP_SLEEP)
/** @brief Global flag: enable or disable LED output. */ /** @brief Global flags */
volatile bool bLedEnabled = true; volatile bool bLedEnabled = true;
volatile bool bBtnPressed = false;
// Function forward declarations // Function forward declarations
void blinkLed(void); void blinkLed(void);
static inline void leds_off(void); static inline void leds_off(void);
static inline void leds_on(void);
static void handleSwitch(void);
/** /**
* @brief Main entry point. * @brief Main entry point.
@ -43,19 +46,45 @@ int main(void)
{ {
// --- configure LED pins as outputs --- // --- configure LED pins as outputs ---
VPORTA.DIR = (PA1_SET_MASK | PA2_SET_MASK | PA3_SET_MASK | VPORTA.DIR = (PA1_SET_MASK | PA2_SET_MASK | PA3_SET_MASK |
PA6_SET_MASK | PA7_SET_MASK); /*PA6_SET_MASK |*/ // PA6 now input (switch)
PA7_SET_MASK);
// Configure PA6 as input with pull-up TODO: Switch to PA0
VPORTA.DIR &= ~PA6_SET_MASK; // Input
PORTA.PIN6CTRL = PORT_PULLUPEN_bm; // Pull-up enabled
// --- ensure all LEDs off at startup --- // --- ensure all LEDs off at startup ---
leds_off(); leds_off();
VPORTA.OUT &= (uint8_t)~(PA6_SET_MASK | PA7_SET_MASK); VPORTA.OUT &= (uint8_t) ~(PA7_SET_MASK);
bool bLedEnabledOld = bLedEnabled;
while (true) while (true)
{ {
// TODO: add status LED handling if needed handleSwitch(); // check switch state
// VPORTA.OUT ^= PA6_SET_MASK; // toggle green LED
// VPORTA.OUT ^= PA7_SET_MASK; // toggle red LED
if (bBtnPressed)
{
leds_on();
}
else
{
leds_off();
}
if (bLedEnabledOld != bLedEnabled)
{
bLedEnabledOld = bLedEnabled;
leds_off();
_delay_ms(1000);
}
else
{
if ((bLedEnabled) && (!bBtnPressed))
{
blinkLed(); blinkLed();
}
}
_delay_ms(MAIN_LOOP_SLEEP); _delay_ms(MAIN_LOOP_SLEEP);
} }
@ -68,32 +97,72 @@ int main(void)
*/ */
static inline void leds_off(void) 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 | PA2_SET_MASK | PA3_SET_MASK);
} }
/** /**
* @brief LED blink state machine. * @brief Switch on all controlled LEDs (PA1, PA2, PA3).
* *
* Implements the following repeating sequence (non-blocking): * @note Declared inline for speed (single instruction sequence).
*/
static inline void leds_on(void)
{
VPORTA.OUT |= (PA1_SET_MASK | PA2_SET_MASK | PA3_SET_MASK);
}
/**
* @brief Handle momentary switch input on PA6. TODO: Switch to PA0
* *
* Normal cycle: * A press longer than 2 seconds toggles ::bLedEnabled.
* - Step 0: all off, wait 250 ms * Uses simple state and counters for debouncing and long-press detection.
* - Step 2: LED 12 + 78 on, wait 50 ms */
* - Step 5: all off, wait 100 ms static void handleSwitch(void)
* - Step 7: LED 12 + 78 on, wait 50 ms {
* - Step 10: all off, wait 250 ms static uint16_t pressTicks = 0; ///< press duration counter
* - Step 12: LED 36 on, wait 50 ms static bool prevPressed = false; ///< previous switch state
* - Step 14: all off, wait 100 ms
* - Step 16: LED 36 on, wait 50 ms bool pressed = !(VPORTA.IN & PA6_SET_MASK); // active-low
* - Step 18: all off, wait 250 ms → restart
if (pressed)
{
bBtnPressed = true;
if (pressTicks < 0xFFFF)
{
// prevent overflow
pressTicks++;
}
}
else
{
bBtnPressed = false;
pressTicks = 0;
}
if (prevPressed && pressTicks >= MS_TO_TICKS(BUTTON_PRESS_DURATION))
{
// long press detected → toggle blinking
bLedEnabled = !bLedEnabled;
}
prevPressed = pressed;
}
/**
* @brief LED blink state machine (bike rear light style).
*
* Implements a "rounded" pulsing blink sequence:
*
* Normal cycle (~1 s total):
* - Step 0: all off, wait 100 ms
* - Step 1: LED 12 + 78 ON, wait 100 ms
* - Step 2: all LEDs ON, wait 200 ms
* - Step 3: only LED 12 ON, wait 100 ms
* - Step 4: all off, wait 400 ms → restart
* *
* Special behavior: * Special behavior:
* - Every 3rd cycle, after step 18, all LEDs (PA1, PA2, PA3) are switched on for 250 ms. * - Every 3rd cycle, after step 4, all LEDs are switched on for 300 ms.
* *
* Timing is based on @ref MAIN_LOOP_SLEEP ticks. * Timing is based on @ref MAIN_LOOP_SLEEP ticks.
*
* @note Must be called periodically every 10 ms from the main loop.
* @note Depends on global flag ::bLedEnabled. If false, does nothing.
*/ */
void blinkLed(void) void blinkLed(void)
{ {
@ -107,9 +176,6 @@ void blinkLed(void)
static uint8_t state = 0; ///< current step in the sequence static uint8_t state = 0; ///< current step in the sequence
static uint8_t cycle = 0; ///< cycle counter (02) static uint8_t cycle = 0; ///< cycle counter (02)
if (!bLedEnabled)
return;
counter++; counter++;
switch (state) switch (state)