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