implement no blocking blink
This commit is contained in:
231
main.c
231
main.c
@ -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 <util/delay.h>
|
||||
|
||||
#define PA1_SET_MASK 0x02 // LED 1 to 2
|
||||
#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 PA7_SET_MASK 0x80 // Red LED
|
||||
/** @defgroup LED_Masks LED bitmasks for PORTA
|
||||
* @{
|
||||
*/
|
||||
#define PA1_SET_MASK 0x02 ///< LED 1–2
|
||||
#define PA2_SET_MASK 0x04 ///< LED 3–6
|
||||
#define PA3_SET_MASK 0x08 ///< LED 7–8
|
||||
#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)
|
||||
{
|
||||
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)
|
||||
VPORTA.DIR |= PA1_SET_MASK;
|
||||
// --- ensure all LEDs off at startup ---
|
||||
leds_off();
|
||||
VPORTA.OUT &= (uint8_t)~(PA6_SET_MASK | PA7_SET_MASK);
|
||||
|
||||
// Configure PA2 as output (Pin 5 on ATTINY202-SSN)
|
||||
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)
|
||||
while (true)
|
||||
{
|
||||
VPORTA.OUT ^= PA6_SET_MASK; // toggle green LED
|
||||
VPORTA.OUT ^= PA7_SET_MASK; // toggle red LED
|
||||
// TODO: add status LED handling if needed
|
||||
// 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 1–2 + 7–8 on, wait 50 ms
|
||||
* - Step 5: all off, wait 100 ms
|
||||
* - Step 7: LED 1–2 + 7–8 on, wait 50 ms
|
||||
* - Step 10: all off, wait 250 ms
|
||||
* - Step 12: LED 3–6 on, wait 50 ms
|
||||
* - Step 14: all off, wait 100 ms
|
||||
* - Step 16: LED 3–6 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 (0–2)
|
||||
|
||||
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 1–2 + 7–8 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 1–2 + 7–8 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 3–6 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 3–6 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;
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user