This commit is contained in:
2025-09-06 00:56:48 +02:00
parent ef86085343
commit 10609e169f

90
main.c
View File

@ -9,62 +9,53 @@
#include <avr/io.h> #include <avr/io.h>
#include <util/delay.h> #include <util/delay.h>
/** @defgroup LED_Masks LED bitmasks for PORTA #define BUTTON_PIN_MASK 0x01 // PA0 TODO: using RESET/UPDI pin
* @{
*/
#define BUTTON_PIN_MASK 0x01 // PA0
#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 pin #define PA6_SET_MASK 0x40 ///< Green LED pin
#define PA7_SET_MASK 0x80 ///< Red LED #define PA7_SET_MASK 0x80 ///< Red LED
/** @} */
#define MAIN_LOOP_SLEEP 10U // Main loop delay in ms (system tick) #define MAIN_LOOP_SLEEP 10U // Main loop delay in ms
#define BUTTON_LONG_PRESS_DURATION_MS 1000U // Long press detection threshold #define BUTTON_LONG_PRESS_DURATION_MS 1000U // Long press threshold
#define BUTTON_IGNORE_DURATION_MS 1000U // Time that the button is ignored after a long press #define BUTTON_IGNORE_DURATION_MS 1000U // Time button ignored after long press
/** @brief Convert milliseconds to system ticks (integer division). */ /** Convert milliseconds to system ticks */
#define MS_TO_TICKS(ms) ((ms) / MAIN_LOOP_SLEEP) #define MS_TO_TICKS(ms) ((ms) / MAIN_LOOP_SLEEP)
/** @brief Global flags */ /** Global flags */
volatile bool bLedEnabled = true; volatile bool bLedEnabled = true;
volatile bool bBtnPressed = false; volatile bool bBtnPressed = false;
// Function forward declarations // Forward declarations
void blinkLed(bool resetCounters); void blinkLed(bool resetCounters);
static inline void leds_off(void); static inline void leds_off(void);
static inline void leds_on(void); static inline void leds_on(void);
static void handleSwitch(void); static void handleSwitch(void);
/** /**
* @brief Main entry point. * @brief Main entry point
*
* Initializes I/O ports and runs the main loop, periodically calling @ref blinkLed().
*
* @return never returns
*/ */
int main(void) 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 PA0 as input with pull-up // Configure PA0 as input with pull-up
VPORTA.DIR &= ~BUTTON_PIN_MASK; // Input VPORTA.DIR &= ~BUTTON_PIN_MASK; // Input
PORTA.PIN0CTRL = PORT_PULLUPEN_bm; // Pull-up enabled PORTA.PIN0CTRL = 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) ~(PA7_SET_MASK); VPORTA.OUT &= (uint8_t)~PA7_SET_MASK;
bool bLedEnabledOld = bLedEnabled; bool bLedEnabledOld = bLedEnabled;
while (true) while (true)
{ {
handleSwitch(); // check switch state handleSwitch(); // Check switch state
// Light LEDs while button is pressed
if (bBtnPressed) if (bBtnPressed)
{ {
leds_on(); leds_on();
@ -74,23 +65,25 @@ int main(void)
leds_off(); leds_off();
} }
// Long press detected → show confirmation blink
if (bLedEnabledOld != bLedEnabled) if (bLedEnabledOld != bLedEnabled)
{ {
// A long press detected --> confirm with a blink
bLedEnabledOld = bLedEnabled; bLedEnabledOld = bLedEnabled;
leds_off(); leds_off();
_delay_ms(BUTTON_IGNORE_DURATION_MS / 10); _delay_ms(BUTTON_IGNORE_DURATION_MS / 10);
leds_on(); leds_on();
_delay_ms(BUTTON_IGNORE_DURATION_MS / 10); _delay_ms(BUTTON_IGNORE_DURATION_MS / 10);
leds_off(); leds_off();
_delay_ms(BUTTON_IGNORE_DURATION_MS); _delay_ms(BUTTON_IGNORE_DURATION_MS);
blinkLed(true); // reset the persistent counters
blinkLed(true); // reset blink state machine
} }
else else
{ {
if ((bLedEnabled) && (!bBtnPressed)) if (bLedEnabled && !bBtnPressed)
{ {
blinkLed(false); blinkLed(false); // run normal blink
} }
} }
@ -99,9 +92,7 @@ int main(void)
} }
/** /**
* @brief Switch off all controlled LEDs (PA1, PA2, PA3). * @brief Turn off all controlled LEDs (PA1, PA2, PA3)
*
* @note Declared inline for speed (single instruction sequence).
*/ */
static inline void leds_off(void) static inline void leds_off(void)
{ {
@ -109,9 +100,7 @@ static inline void leds_off(void)
} }
/** /**
* @brief Switch on all controlled LEDs (PA1, PA2, PA3). * @brief Turn on all controlled LEDs (PA1, PA2, PA3)
*
* @note Declared inline for speed (single instruction sequence).
*/ */
static inline void leds_on(void) static inline void leds_on(void)
{ {
@ -119,26 +108,22 @@ static inline void leds_on(void)
} }
/** /**
* @brief Handle momentary switch input on PA6. TODO: Switch to PA0 * @brief Handle momentary switch input on PA0
* *
* A press longer than 2 seconds toggles ::bLedEnabled. * A long press toggles ::bLedEnabled.
* Uses simple state and counters for debouncing and long-press detection.
*/ */
static void handleSwitch(void) static void handleSwitch(void)
{ {
static uint16_t pressTicks = 0; ///< press duration counter static uint16_t pressTicks = 0; ///< Press duration counter
static bool prevPressed = false; ///< previous switch state static bool prevPressed = false; ///< Previous button state
bool pressed = !(VPORTA.IN & BUTTON_PIN_MASK); // active-low bool pressed = !(VPORTA.IN & BUTTON_PIN_MASK); // Active-low
if (pressed) if (pressed)
{ {
bBtnPressed = true; bBtnPressed = true;
if (pressTicks < 0xFFFF) if (pressTicks < 0xFFFF)
{ pressTicks++; // Prevent overflow
// prevent overflow
pressTicks++;
}
} }
else else
{ {
@ -148,15 +133,14 @@ static void handleSwitch(void)
if (prevPressed && pressTicks >= MS_TO_TICKS(BUTTON_LONG_PRESS_DURATION_MS)) if (prevPressed && pressTicks >= MS_TO_TICKS(BUTTON_LONG_PRESS_DURATION_MS))
{ {
// long press detected → toggle blinking bLedEnabled = !bLedEnabled; // Toggle LED blinking
bLedEnabled = !bLedEnabled;
} }
prevPressed = pressed; prevPressed = pressed;
} }
/** /**
* @brief LED blink state machine (bike rear light style). * @brief LED blink state machine (bike rear light style)
* *
* Normal cycle: * Normal cycle:
* 0: all off, wait 250 ms * 0: all off, wait 250 ms
@ -172,15 +156,13 @@ static void handleSwitch(void)
*/ */
void blinkLed(bool resetCounters) void blinkLed(bool resetCounters)
{ {
// --- precomputed constants --- const uint8_t T50 = MS_TO_TICKS(50);
const uint8_t T50 = MS_TO_TICKS(50); ///< 50 ms in ticks const uint8_t T100 = MS_TO_TICKS(100);
const uint8_t T100 = MS_TO_TICKS(100); ///< 100 ms in ticks const uint8_t T250 = MS_TO_TICKS(250);
const uint8_t T250 = MS_TO_TICKS(250); ///< 250 ms in ticks
// --- persistent state --- static uint16_t counter = 0;
static uint16_t counter = 0; ///< ticks for current state static uint8_t state = 2; // start with LEDs-on state
static uint8_t state = 2; ///< start with first LEDs-on state static uint8_t cycle = 0;
static uint8_t cycle = 0; ///< cycle counter
if (resetCounters) if (resetCounters)
{ {