AVR driver for a group of 7-seg displays (with 70hc4094), controlled by UART.

main.c 5.5KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276
  1. #include <avr/io.h>
  2. #include <avr/pgmspace.h>
  3. #include <avr/interrupt.h>
  4. #include <util/delay.h>
  5. #include <stdint.h>
  6. #include <stdbool.h>
  7. #include "lib/iopins.h"
  8. #include "lib/uart.h"
  9. // Configure what pins to use
  10. #define IO_DATA D2
  11. #define IO_CLK D3
  12. #define IO_STR D4
  13. /*
  14. | LED display driver
  15. |
  16. | Two chained 70hc4094 are connected.
  17. |
  18. | One drives common cathodes, the other
  19. | the segments.
  20. |
  21. | Display is controlled over UART at 115200 baud.
  22. |
  23. | Commands:
  24. |
  25. | R - reset (clear display)
  26. |
  27. | Aaaaaaaaa - set value using ASCII. Supported are digits and letters A-F.
  28. | Period ('.') adds a decimal point to the last-entered symbol
  29. | (does not move "cursor"). It is not possible to add DP to the
  30. | last symbol using ASCII mode.
  31. |
  32. | Bbbbbbbbb - Set segments using binary mode (no conversion).
  33. | The bytes have the following format: 0bHGFEDCBA
  34. |
  35. | Ll - Set brightness. `l` is a byte (0-255) determining the level.
  36. |
  37. */
  38. // ---- Segment definitions -----------------------
  39. #define SEG_A 0x01
  40. #define SEG_B 0x02
  41. #define SEG_C 0x04
  42. #define SEG_D 0x08
  43. #define SEG_E 0x10
  44. #define SEG_F 0x20
  45. #define SEG_G 0x40
  46. #define SEG_DP 0x80
  47. /** Digits */
  48. enum {
  49. SYM_BLANK = 0,
  50. SYM_0 = SEG_A | SEG_B | SEG_C | SEG_D | SEG_E | SEG_F,
  51. SYM_1 = SEG_B | SEG_C,
  52. SYM_2 = SEG_A | SEG_B | SEG_G | SEG_E | SEG_D,
  53. SYM_3 = SEG_B | SEG_C | SEG_A | SEG_D | SEG_G,
  54. SYM_4 = SEG_F | SEG_G | SEG_B | SEG_C,
  55. SYM_5 = SEG_A | SEG_F | SEG_G | SEG_C | SEG_D,
  56. SYM_6 = SEG_A | SEG_F | SEG_E | SEG_D | SEG_C | SEG_G,
  57. SYM_7 = SEG_A | SEG_B | SEG_C,
  58. SYM_8 = SEG_A | SEG_B | SEG_C | SEG_D | SEG_E | SEG_F | SEG_G,
  59. SYM_9 = SEG_A | SEG_B | SEG_C | SEG_D | SEG_F | SEG_G,
  60. SYM_A = SEG_A | SEG_B | SEG_C | SEG_E | SEG_F | SEG_G,
  61. SYM_B = SEG_C | SEG_D | SEG_E | SEG_F | SEG_G,
  62. SYM_C = SEG_A | SEG_D | SEG_E | SEG_F,
  63. SYM_D = SEG_B | SEG_C | SEG_D | SEG_E | SEG_G,
  64. SYM_E = SEG_A | SEG_D | SEG_E | SEG_F | SEG_G,
  65. SYM_F = SEG_A | SEG_E | SEG_F | SEG_G,
  66. };
  67. /** Conversion table */
  68. const uint8_t num2seg[16] PROGMEM = {
  69. SYM_0, SYM_1, SYM_2, SYM_3,
  70. SYM_4, SYM_5, SYM_6, SYM_7,
  71. SYM_8, SYM_9, SYM_A, SYM_B,
  72. SYM_C, SYM_D, SYM_E, SYM_F
  73. };
  74. // ---- Routines for loading data to the display registers ----------
  75. void disp_load(uint8_t place, uint8_t segments)
  76. {
  77. uint16_t w;
  78. if (segments == 0) {
  79. w = 0;
  80. } else {
  81. w = (1 << (place + 8)) | segments;
  82. }
  83. for (uint8_t i = 0; i < 16; i++) {
  84. // bit value to data line
  85. set_pin(IO_DATA, (bool)(w & 0x8000));
  86. // pulse clock
  87. pin_high(IO_CLK);
  88. pin_low(IO_CLK);
  89. w <<= 1;
  90. }
  91. // pulse STR
  92. pin_high(IO_STR);
  93. pin_low(IO_STR);
  94. }
  95. /** Brightness table (for smoother brightness adjustment) */
  96. const uint8_t BRIGHT_128[128] PROGMEM = {
  97. 0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 4, 4, 4, 4,
  98. 5, 5, 6, 6, 6, 7, 7, 8, 8, 8, 9, 10, 10, 10, 11, 12, 13, 14,
  99. 14, 15, 16, 17, 18, 20, 21, 22, 24, 26, 27, 28, 30, 31, 32, 34, 35, 36,
  100. 38, 39, 40, 41, 42, 44, 45, 46, 48, 49, 50, 52, 54, 56, 58, 59, 61, 63,
  101. 65, 67, 68, 69, 71, 72, 74, 76, 78, 80, 82, 85, 88, 90, 92, 95, 98, 100,
  102. 103, 106, 109, 112, 116, 119, 122, 125, 129, 134, 138, 142, 147, 151,
  103. 153, 156, 160, 163, 165, 170, 175, 180, 185, 190, 195, 200, 207, 214, 218,
  104. 221, 225, 228, 232, 234, 241, 248, 254, 255
  105. };
  106. /** Buffer for input */
  107. uint8_t screen_buf[8];
  108. uint8_t scr_buf_i;
  109. /** Array of currently displayed segments */
  110. uint8_t screen[8];
  111. uint8_t level = 255;
  112. uint8_t delay_l = 255;
  113. enum {
  114. STATE_NONE,
  115. STATE_ASCII,
  116. STATE_BINARY,
  117. STATE_BRIGHTNESS
  118. } state;
  119. inline void cpy_buf2scr(void)
  120. {
  121. for (uint8_t i = 0; i < 8; i++) {
  122. screen[i] = screen_buf[i];
  123. }
  124. }
  125. // Incoming data IRQ
  126. ISR(USART_RX_vect)
  127. {
  128. uint8_t b = uart_rx();
  129. uart_tx(b); // send back
  130. switch (state) {
  131. case STATE_NONE:
  132. // Choose what to do
  133. if (b >= 'a' && b <= 'z') {
  134. b -= 'a' - 'A'; // make uppercase
  135. }
  136. switch (b) {
  137. case 'A':
  138. state = STATE_ASCII;
  139. scr_buf_i = 0;
  140. break;
  141. case 'B':
  142. state = STATE_BINARY;
  143. scr_buf_i = 0;
  144. break;
  145. case 'R':
  146. for (uint8_t i = 0; i < 8; i++) {
  147. screen[i] = SYM_BLANK;
  148. }
  149. break;
  150. case 'L':
  151. state = STATE_BRIGHTNESS;
  152. break;
  153. default:
  154. break;
  155. }
  156. break;
  157. case STATE_BRIGHTNESS:
  158. level = b;
  159. delay_l = pgm_read_byte(&BRIGHT_128[level >> 1]);
  160. state = STATE_NONE;
  161. break;
  162. case STATE_ASCII:
  163. if (b >= 'a' && b <= 'z') {
  164. b -= 'a' - 'A'; // make uppercase
  165. }
  166. if (b >= '0' && b <= '9') {
  167. // numbers
  168. screen_buf[scr_buf_i++] = pgm_read_byte(&num2seg[b - '0']);
  169. } else if (b >= 'A' && b <= 'F') {
  170. // hex
  171. screen_buf[scr_buf_i++] = pgm_read_byte(&num2seg[10 + (b - 'A')]);
  172. } else if (b == '-') {
  173. // numbers
  174. screen_buf[scr_buf_i++] = SEG_G; // minus
  175. } else if (b == '.') {
  176. // add period to previous symbol
  177. if (scr_buf_i > 0) {
  178. screen_buf[scr_buf_i - 1] |= SEG_DP;
  179. }
  180. } else {
  181. // default - blank
  182. screen_buf[scr_buf_i++] = SYM_BLANK;
  183. }
  184. if (scr_buf_i == 8) {
  185. cpy_buf2scr();
  186. state = STATE_NONE;
  187. }
  188. break;
  189. case STATE_BINARY:
  190. screen_buf[scr_buf_i++] = b; // no processing
  191. if (scr_buf_i == 8) {
  192. cpy_buf2scr();
  193. state = STATE_NONE;
  194. }
  195. break;
  196. }
  197. }
  198. void main()
  199. {
  200. _uart_init(8); // set usart @ 115200
  201. as_output(IO_DATA);
  202. as_output(IO_CLK);
  203. as_output(IO_STR);
  204. uart_isr_rx(true);
  205. sei();
  206. while (1) {
  207. // display loop
  208. for (register uint8_t i = 0; i < 8; i++) {
  209. disp_load(i, screen[i]);
  210. for (register uint8_t j = 0; j < 255; j++) {
  211. if (j == delay_l) disp_load(0, 0);
  212. __builtin_avr_delay_cycles(5);
  213. }
  214. }
  215. }
  216. }