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