basic button toggle
This commit is contained in:
122
main.c
122
main.c
@ -15,22 +15,25 @@
|
|||||||
#define PA1_SET_MASK 0x02 ///< LED 1–2
|
#define PA1_SET_MASK 0x02 ///< LED 1–2
|
||||||
#define PA2_SET_MASK 0x04 ///< LED 3–6
|
#define PA2_SET_MASK 0x04 ///< LED 3–6
|
||||||
#define PA3_SET_MASK 0x08 ///< LED 7–8
|
#define PA3_SET_MASK 0x08 ///< LED 7–8
|
||||||
#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);
|
||||||
}
|
}
|
||||||
@ -72,28 +101,68 @@ static inline void leds_off(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @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 1–2 + 7–8 on, wait 50 ms
|
*/
|
||||||
* - Step 5: all off, wait 100 ms
|
static void handleSwitch(void)
|
||||||
* - Step 7: LED 1–2 + 7–8 on, wait 50 ms
|
{
|
||||||
* - Step 10: all off, wait 250 ms
|
static uint16_t pressTicks = 0; ///< press duration counter
|
||||||
* - Step 12: LED 3–6 on, wait 50 ms
|
static bool prevPressed = false; ///< previous switch state
|
||||||
* - Step 14: all off, wait 100 ms
|
|
||||||
* - Step 16: LED 3–6 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 1–2 + 7–8 ON, wait 100 ms
|
||||||
|
* - Step 2: all LEDs ON, wait 200 ms
|
||||||
|
* - Step 3: only LED 1–2 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 (0–2)
|
static uint8_t cycle = 0; ///< cycle counter (0–2)
|
||||||
|
|
||||||
if (!bLedEnabled)
|
|
||||||
return;
|
|
||||||
|
|
||||||
counter++;
|
counter++;
|
||||||
|
|
||||||
switch (state)
|
switch (state)
|
||||||
|
Reference in New Issue
Block a user