fork download
  1. #include <avr/interrupt.h>
  2. #include <avr/io.h>
  3. #include <avr/sleep.h>
  4.  
  5. #include <stddef.h>
  6. #include <stdint.h>
  7.  
  8. #define ARRAY_SIZE(a) (sizeof (a) / sizeof *(a))
  9.  
  10. static const struct traffic_light {
  11. struct traffic_light_led {
  12. volatile uint8_t *port;
  13. uint8_t pin;
  14. } red, amber, green;
  15. } traffic_lights[] = {
  16. /* North traffic lights */
  17. {
  18. {&PORTA, _BV(PA0)},
  19. {&PORTA, _BV(PA1)},
  20. {&PORTA, _BV(PA2)}
  21. },
  22. /* South traffic lights */
  23. {
  24. {&PORTA, _BV(PA3)},
  25. {&PORTA, _BV(PA4)},
  26. {&PORTA, _BV(PA5)}
  27. },
  28. /* East traffic lights */
  29. {
  30. {&PORTA, _BV(PA6)},
  31. {&PORTA, _BV(PA7)},
  32. {&PORTB, _BV(PB0)}
  33. },
  34. /* West traffic lights */
  35. {
  36. {&PORTB, _BV(PB1)},
  37. {&PORTB, _BV(PB2)},
  38. {&PORTB, _BV(PB3)}
  39. },
  40. };
  41.  
  42. static void set_traffic_light_led(const struct traffic_light_led *led) {
  43. *(led->port) |= led->pin;
  44. }
  45.  
  46. static void reset_traffic_light_led(const struct traffic_light_led *led) {
  47. *(led->port) &= ~(led->pin);
  48. }
  49.  
  50. static void set_traffic_light_green(const struct traffic_light *light) {
  51. set_traffic_light_led(&light->green);
  52. reset_traffic_light_led(&light->amber);
  53. reset_traffic_light_led(&light->red);
  54. }
  55.  
  56. static void set_traffic_light_amber(const struct traffic_light *light) {
  57. reset_traffic_light_led(&light->green);
  58. set_traffic_light_led(&light->amber);
  59. reset_traffic_light_led(&light->red);
  60. }
  61.  
  62. static void set_traffic_light_red(const struct traffic_light *light) {
  63. reset_traffic_light_led(&light->green);
  64. reset_traffic_light_led(&light->amber);
  65. set_traffic_light_led(&light->red);
  66. }
  67.  
  68. static void reset_traffic_light(const struct traffic_light *light) {
  69. reset_traffic_light_led(&light->green);
  70. reset_traffic_light_led(&light->amber);
  71. reset_traffic_light_led(&light->red);
  72. }
  73.  
  74. typedef void (output_state)(const struct traffic_light *);
  75.  
  76. #define s_off &reset_traffic_light
  77. #define s_green &set_traffic_light_green
  78. #define s_amber &set_traffic_light_amber
  79. #define s_red &set_traffic_light_red
  80.  
  81. static output_state * const output_states[] = {
  82. s_green, s_off, s_green, s_off, s_green, s_off, s_green, s_off, s_amber,
  83. s_red, s_red, s_red, s_red, s_red, s_red, s_red, s_red, s_red,
  84. s_red, s_red, s_red, s_red, s_red, s_red, s_red, s_red, s_red,
  85. s_red, s_red, s_red, s_red, s_red, s_red, s_red, s_red, s_red
  86. };
  87.  
  88. enum {
  89. TCNT0_MAX = 250u,
  90. TCNT0_START = UINT8_MAX - TCNT0_MAX,
  91. TIMER0_PRESCALER = 8u,
  92. TIMER0_CLOCKS_PER_MS = F_CPU / TIMER0_PRESCALER / TCNT0_MAX / 1000u
  93. };
  94.  
  95. static volatile size_t ovf = 0;
  96.  
  97. /* State transition times in milliseconds */
  98. enum {
  99. GREEN_MS = 10000u,
  100. BLINK_MS = 500u,
  101. AMBER_MS = 3000u
  102. };
  103.  
  104. static const size_t times[] = {
  105. GREEN_MS, BLINK_MS, BLINK_MS,
  106. BLINK_MS, BLINK_MS, BLINK_MS,
  107. BLINK_MS, BLINK_MS, AMBER_MS
  108. };
  109.  
  110. static volatile size_t times_index = 0u;
  111. static volatile size_t ms = 5000u;
  112.  
  113. static void set_timers(void) {
  114. ms = times[times_index];
  115. TCCR0 |= _BV(CS01);
  116. TCNT0 = TCNT0_START;
  117. ovf = 0u;
  118. }
  119.  
  120. /* Indices in the states vector */
  121. static volatile size_t current_states[] = {
  122. 0u, /* North Traffic Light Start State */
  123. 27u, /* South Traffic Light Start State */
  124. 18u, /* East Traffic Light Start State */
  125. 9u /* North Traffic Light Start State */
  126. };
  127.  
  128. static void run_states(void) {
  129. for (size_t i = 0u; i < ARRAY_SIZE(current_states); ++i) {
  130. output_states[current_states[i]](traffic_lights + i);
  131. }
  132. }
  133.  
  134. static void advance(volatile size_t *index, size_t size) {
  135. ++*index;
  136. *index %= size;
  137. }
  138.  
  139. static void advance_states(void) {
  140. for (size_t i = 0u; i < ARRAY_SIZE(current_states); ++i) {
  141. advance(current_states + i, ARRAY_SIZE(output_states));
  142. }
  143. }
  144.  
  145. static void advance_times(void) {
  146. advance(&times_index, ARRAY_SIZE(times));
  147. set_timers();
  148. }
  149.  
  150. ISR(TIMER0_OVF_vect) {
  151. if (++ovf >= TIMER0_CLOCKS_PER_MS * ms) {
  152. advance_states();
  153. advance_times();
  154. run_states();
  155. }
  156. TCNT0 = TCNT0_START;
  157. }
  158.  
  159. static void set_io_registers(void) {
  160. DDRA = 0xffu;
  161. DDRB |= 0x0fu;
  162. }
  163.  
  164. static void set_interrupt_registers(void) {
  165. TIMSK |= _BV(TOIE0);
  166. sei();
  167. }
  168.  
  169. static void set_start_state(void) {
  170. run_states();
  171. }
  172.  
  173. int main(void) {
  174. set_io_registers();
  175. set_interrupt_registers();
  176. set_start_state();
  177. set_timers();
  178. set_sleep_mode(SLEEP_MODE_IDLE);
  179. for (;;) {
  180. sleep_mode();
  181. }
  182. return 0;
  183. }
  184.  
Not running #stdin #stdout 0s 0KB
stdin
Standard input is empty
stdout
Standard output is empty