implement no blocking blink

This commit is contained in:
2025-09-05 23:09:24 +02:00
parent ca747ab0f4
commit 0c6899c8a0

231
main.c
View File

@ -1,42 +1,215 @@
/**
* @file main.c
* @brief Bike rear light implementation for ATTINY202.
*
*/
#include <stdint.h>
#include <stdbool.h>
#include <avr/io.h> #include <avr/io.h>
#include <util/delay.h> #include <util/delay.h>
#define PA1_SET_MASK 0x02 // LED 1 to 2 /** @defgroup LED_Masks LED bitmasks for PORTA
#define PA2_SET_MASK 0x04 // LED 3 to 6 * @{
#define PA3_SET_MASK 0x08 // LED 7 to 8 */
#define PA6_SET_MASK 0x40 // Green LED #define PA1_SET_MASK 0x02 ///< LED 12
#define PA7_SET_MASK 0x80 // Red LED #define PA2_SET_MASK 0x04 ///< LED 36
#define PA3_SET_MASK 0x08 ///< LED 78
#define PA6_SET_MASK 0x40 ///< Green LED
#define PA7_SET_MASK 0x80 ///< Red LED
/** @} */
/** @brief Main loop delay in ms (system tick). */
#define MAIN_LOOP_SLEEP 10U
/** @brief Convert milliseconds to system ticks (integer division). */
#define MS_TO_TICKS(ms) ((ms) / MAIN_LOOP_SLEEP)
/** @brief Global flag: enable or disable LED output. */
volatile bool bLedEnabled = true;
// Function forward declarations
void blinkLed(void);
static inline void leds_off(void);
/**
* @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)
{ {
VPORTA.DIR = 0x0; // --- configure LED pins as outputs ---
VPORTA.DIR = (PA1_SET_MASK | PA2_SET_MASK | PA3_SET_MASK |
PA6_SET_MASK | PA7_SET_MASK);
// Configure PA1 as output (Pin 4 on ATTINY202-SSN) // --- ensure all LEDs off at startup ---
VPORTA.DIR |= PA1_SET_MASK; leds_off();
VPORTA.OUT &= (uint8_t)~(PA6_SET_MASK | PA7_SET_MASK);
// Configure PA2 as output (Pin 5 on ATTINY202-SSN) while (true)
VPORTA.DIR |= PA2_SET_MASK;
// Configure PA3 as output (Pin 7 on ATTINY202-SSN)
VPORTA.DIR |= PA3_SET_MASK;
// Configure PA6 as output (Pin 2 on ATTINY202-SSN)
VPORTA.DIR |= PA6_SET_MASK;
// Configure PA7 as output (Pin 3 on ATTINY202-SSN)
VPORTA.DIR |= PA7_SET_MASK;
VPORTA.OUT ^= !PA1_SET_MASK; // LED 1 to 2
VPORTA.OUT ^= !PA2_SET_MASK; // LED 3 to 6
VPORTA.OUT ^= !PA3_SET_MASK; // LED 7 to 8
while (1)
{ {
VPORTA.OUT ^= PA6_SET_MASK; // toggle green LED // TODO: add status LED handling if needed
VPORTA.OUT ^= PA7_SET_MASK; // toggle red LED // VPORTA.OUT ^= PA6_SET_MASK; // toggle green LED
// VPORTA.OUT ^= PA7_SET_MASK; // toggle red LED
VPORTA.OUT ^= PA2_SET_MASK; // toggle inner four LED blinkLed();
_delay_ms(500); _delay_ms(MAIN_LOOP_SLEEP);
}
}
/**
* @brief Switch off all controlled LEDs (PA1, PA2, PA3).
*
* @note Declared inline for speed (single instruction sequence).
*/
static inline void leds_off(void)
{
VPORTA.OUT &= (uint8_t)~(PA1_SET_MASK | PA2_SET_MASK | PA3_SET_MASK);
}
/**
* @brief LED blink state machine.
*
* Implements the following repeating sequence (non-blocking):
*
* Normal cycle:
* - Step 0: all off, wait 250 ms
* - Step 2: LED 12 + 78 on, wait 50 ms
* - Step 5: all off, wait 100 ms
* - Step 7: LED 12 + 78 on, wait 50 ms
* - Step 10: all off, wait 250 ms
* - Step 12: LED 36 on, wait 50 ms
* - Step 14: all off, wait 100 ms
* - Step 16: LED 36 on, wait 50 ms
* - Step 18: all off, wait 250 ms → restart
*
* Special behavior:
* - Every 3rd cycle, after step 18, all LEDs (PA1, PA2, PA3) are switched on for 250 ms.
*
* 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)
{
// --- precomputed constants (compile-time) ---
const uint8_t T50 = MS_TO_TICKS(50); ///< 50 ms in ticks
const uint8_t T100 = MS_TO_TICKS(100); ///< 100 ms in ticks
const uint8_t T250 = MS_TO_TICKS(250); ///< 250 ms in ticks
// --- persistent state ---
static uint16_t counter = 0; ///< counts ticks for current state
static uint8_t state = 0; ///< current step in the sequence
static uint8_t cycle = 0; ///< cycle counter (02)
if (!bLedEnabled)
return;
counter++;
switch (state)
{
case 0: // all LEDs off, wait 250 ms
leds_off();
if (counter >= T250)
{
counter = 0;
state = 2;
}
break;
case 2: // LED 12 + 78 on, wait 50 ms
VPORTA.OUT |= (PA1_SET_MASK | PA3_SET_MASK);
if (counter >= T50)
{
counter = 0;
state = 5;
}
break;
case 5: // all LEDs off, wait 100 ms
leds_off();
if (counter >= T100)
{
counter = 0;
state = 7;
}
break;
case 7: // LED 12 + 78 on, wait 50 ms
VPORTA.OUT |= (PA1_SET_MASK | PA3_SET_MASK);
if (counter >= T50)
{
counter = 0;
state = 10;
}
break;
case 10: // all LEDs off, wait 250 ms
leds_off();
if (counter >= T250)
{
counter = 0;
state = 12;
}
break;
case 12: // LED 36 on, wait 50 ms
VPORTA.OUT |= PA2_SET_MASK;
if (counter >= T50)
{
counter = 0;
state = 14;
}
break;
case 14: // all LEDs off, wait 100 ms
leds_off();
if (counter >= T100)
{
counter = 0;
state = 16;
}
break;
case 16: // LED 36 on, wait 50 ms
VPORTA.OUT |= PA2_SET_MASK;
if (counter >= T50)
{
counter = 0;
state = 18;
}
break;
case 18: // all LEDs off, wait 250 ms
leds_off();
if (counter >= T250)
{
counter = 0;
if (++cycle >= 3)
{
cycle = 0;
state = 20; // special all-LEDs-on state
}
else
{
state = 0; // restart normal cycle
}
}
break;
case 20: // special: all LEDs on for 250 ms
VPORTA.OUT |= (PA1_SET_MASK | PA2_SET_MASK | PA3_SET_MASK);
if (counter >= T250)
{
counter = 0;
state = 0; // restart normal sequence
}
break;
} }
} }