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, PA0},
  19. {&PORTA, PA1},
  20. {&PORTA, PA2}
  21. },
  22. /* South traffic lights */
  23. {
  24. {&PORTA, PA3},
  25. {&PORTA, PA4},
  26. {&PORTA, PA5}
  27. },
  28. /* East traffic lights */
  29. {
  30. {&PORTA, PA6},
  31. {&PORTA, PA7},
  32. {&PORTB, PB0}
  33. },
  34. /* West traffic lights */
  35. {
  36. {&PORTB, PB1},
  37. {&PORTB, PB2},
  38. {&PORTB, PB3}
  39. },
  40. };
  41.  
  42. static void set_traffic_light_led(const struct traffic_light_led *led) {
  43. *(led->port) |= _BV(led->pin);
  44. }
  45.  
  46. static void reset_traffic_light_led(const struct traffic_light_led *led) {
  47. *(led->port) &= ~(_BV(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 = 256u - TCNT0_MAX,
  91. PRESCALER = 8u,
  92. CLOCKS_PER_MS = F_CPU / 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. /* Indices in the states vector */
  105. enum {
  106. NORTH_TRAFFIC_LIGHTS_START_STATE = 0u,
  107. SOUTH_TRAFFIC_LIGHTS_START_STATE = 27u,
  108. EAST_TRAFFIC_LIGHTS_START_STATE = 18u,
  109. WEST_TRAFFIC_LIGHTS_START_STATE = 9u,
  110. };
  111.  
  112. static const size_t times[] = {
  113. GREEN_MS, BLINK_MS, BLINK_MS,
  114. BLINK_MS, BLINK_MS, BLINK_MS,
  115. BLINK_MS, BLINK_MS, AMBER_MS
  116. };
  117.  
  118. static volatile size_t times_index = 0u;
  119. static volatile size_t ms = 5000u;
  120.  
  121. static void set_timers(void) {
  122. ms = times[times_index];
  123. TCCR0 |= (_BV(CS01));
  124. TCNT0 = TCNT0_START;
  125. ovf = 0u;
  126. }
  127.  
  128. static volatile size_t current_states[] = {
  129. NORTH_TRAFFIC_LIGHTS_START_STATE,
  130. SOUTH_TRAFFIC_LIGHTS_START_STATE,
  131. EAST_TRAFFIC_LIGHTS_START_STATE,
  132. WEST_TRAFFIC_LIGHTS_START_STATE
  133. };
  134.  
  135. static void run_states(void) {
  136. for (size_t i = 0u; i < ARRAY_SIZE(current_states); ++i) {
  137. output_states[current_states[i]](traffic_lights + i);
  138. }
  139. }
  140.  
  141. static void advance(volatile size_t *index, size_t array_size) {
  142. if (*index != array_size) {
  143. ++*index;
  144. } else {
  145. *index = 0;
  146. }
  147. }
  148.  
  149. static void advance_states(void) {
  150. for (size_t i = 0u; i < ARRAY_SIZE(current_states); ++i) {
  151. advance(current_states + i, ARRAY_SIZE(current_states));
  152. }
  153. }
  154.  
  155. static void advance_times(void) {
  156. advance(&times_index, ARRAY_SIZE(times));
  157. set_timers();
  158. }
  159.  
  160. ISR(TIMER0_OVF_vect) {
  161. if (++ovf >= CLOCKS_PER_MS * ms) {
  162. advance_states();
  163. advance_times();
  164. run_states();
  165. }
  166. }
  167.  
  168. static void set_io_registers(void) {
  169. DDRA = 0xffu;
  170. DDRB |= _BV(PB0) | _BV(PB1) | _BV(PB2) | _BV(PB3);
  171. }
  172.  
  173. static void set_interrupt_registers(void) {
  174. TIMSK |= (_BV(TOIE0));
  175. sei();
  176. }
  177.  
  178. static void set_start_state(void) {
  179. run_states();
  180. }
  181.  
  182. int main(void) {
  183. set_io_registers();
  184. set_interrupt_registers();
  185. set_start_state();
  186. set_timers();
  187. set_sleep_mode(SLEEP_MODE_IDLE);
  188. for (;;) {
  189. sleep_mode();
  190. }
  191. return 0;
  192. }
  193.  
Not running #stdin #stdout 0s 0KB
stdin
Standard input is empty
stdout
Standard output is empty