1-Wire tester, shows ROM code and temperature on an LCD screen

lcd.c 5.5KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355
  1. #include <stdbool.h>
  2. #include <stdint.h>
  3. #include <avr/io.h>
  4. #include <avr/pgmspace.h>
  5. #include <util/delay.h>
  6. #include "calc.h"
  7. #include "iopins.h"
  8. #include "nsdelay.h"
  9. #include "lcd.h"
  10. // Start address of rows
  11. const uint8_t LCD_ROW_ADDR[] = {0x00, 0x40, 0x14, 0x54};
  12. // Internal prototypes
  13. void _lcd_mode_r();
  14. void _lcd_mode_w();
  15. void _lcd_clk();
  16. void _lcd_wait_bf();
  17. void _lcd_write_byte(uint8_t bb);
  18. uint8_t _lcd_read_byte();
  19. // Write utilities
  20. #define _lcd_write_low(bb) _lcd_write_nibble((bb) & 0x0F)
  21. #define _lcd_write_high(bb) _lcd_write_nibble(((bb) & 0xF0) >> 4)
  22. #define _lcd_write_nibble(nib) do { \
  23. pin_set(LCD_D7, get_bit((nib), 3)); \
  24. pin_set(LCD_D6, get_bit((nib), 2)); \
  25. pin_set(LCD_D5, get_bit((nib), 1)); \
  26. pin_set(LCD_D4, get_bit((nib), 0)); \
  27. } while(0)
  28. // 0 W, 1 R
  29. bool _lcd_mode;
  30. struct
  31. {
  32. uint8_t x;
  33. uint8_t y;
  34. } _pos;
  35. enum
  36. {
  37. TEXT = 0,
  38. CG = 1
  39. } _addrtype;
  40. /** Initialize the display */
  41. void lcd_init()
  42. {
  43. // configure pins as output
  44. as_output(LCD_E);
  45. as_output(LCD_RW);
  46. as_output(LCD_RS);
  47. _lcd_mode = 1; // force data pins to output
  48. _lcd_mode_w();
  49. // Magic sequence to invoke Cthulhu (or enter 4-bit mode)
  50. _delay_ms(16);
  51. _lcd_write_nibble(0b0011);
  52. _lcd_clk();
  53. _delay_ms(5);
  54. _lcd_clk();
  55. _delay_ms(5);
  56. _lcd_clk();
  57. _delay_ms(5);
  58. _lcd_write_nibble(0b0010);
  59. _lcd_clk();
  60. _delay_us(100);
  61. // Configure the display
  62. lcd_command(LCD_IFACE_4BIT_2LINE);
  63. lcd_command(LCD_DISABLE);
  64. lcd_command(LCD_CLEAR);
  65. lcd_command(LCD_MODE_INC);
  66. // mark as enabled
  67. lcd_enable();
  68. _pos.x = 0;
  69. _pos.y = 0;
  70. _addrtype = TEXT;
  71. }
  72. /** Send a pulse on the ENABLE line */
  73. void _lcd_clk()
  74. {
  75. pin_up(LCD_E);
  76. delay_ns(450);
  77. pin_down(LCD_E);
  78. }
  79. /** Enter READ mode */
  80. void _lcd_mode_r()
  81. {
  82. if (_lcd_mode == 1) return; // already in R mode
  83. pin_up(LCD_RW);
  84. as_input_pu(LCD_D7);
  85. as_input_pu(LCD_D6);
  86. as_input_pu(LCD_D5);
  87. as_input_pu(LCD_D4);
  88. _lcd_mode = 1;
  89. }
  90. /** Enter WRITE mode */
  91. void _lcd_mode_w()
  92. {
  93. if (_lcd_mode == 0) return; // already in W mode
  94. pin_down(LCD_RW);
  95. as_output(LCD_D7);
  96. as_output(LCD_D6);
  97. as_output(LCD_D5);
  98. as_output(LCD_D4);
  99. _lcd_mode = 0;
  100. }
  101. /** Read a byte */
  102. uint8_t _lcd_read_byte()
  103. {
  104. _lcd_mode_r();
  105. uint8_t res = 0;
  106. _lcd_clk();
  107. res = (pin_read(LCD_D7) << 7) | (pin_read(LCD_D6) << 6) | (pin_read(LCD_D5) << 5) | (pin_read(LCD_D4) << 4);
  108. _lcd_clk();
  109. res |= (pin_read(LCD_D7) << 3) | (pin_read(LCD_D6) << 2) | (pin_read(LCD_D5) << 1) | (pin_read(LCD_D4) << 0);
  110. return res;
  111. }
  112. /** Write an instruction byte */
  113. void lcd_command(uint8_t bb)
  114. {
  115. _lcd_wait_bf();
  116. pin_down(LCD_RS); // select instruction register
  117. _lcd_write_byte(bb); // send instruction byte
  118. }
  119. /** Write a data byte */
  120. void lcd_write(uint8_t bb)
  121. {
  122. if (_addrtype == TEXT)
  123. {
  124. if (bb == '\r')
  125. {
  126. // CR
  127. _pos.x = 0;
  128. lcd_xy(_pos.x, _pos.y);
  129. return;
  130. }
  131. if (bb == '\n')
  132. {
  133. // LF
  134. _pos.y++;
  135. lcd_xy(_pos.x, _pos.y);
  136. return;
  137. }
  138. _pos.x++;
  139. }
  140. _lcd_wait_bf();
  141. pin_up(LCD_RS); // select data register
  142. _lcd_write_byte(bb); // send data byte
  143. }
  144. /** Read BF & Address */
  145. uint8_t lcd_read_bf_addr()
  146. {
  147. pin_down(LCD_RS);
  148. return _lcd_read_byte();
  149. }
  150. /** Read CGRAM or DDRAM */
  151. uint8_t lcd_read()
  152. {
  153. if (_addrtype == TEXT) _pos.x++;
  154. pin_up(LCD_RS);
  155. return _lcd_read_byte();
  156. }
  157. /** Write a byte using the 4-bit interface */
  158. void _lcd_write_byte(uint8_t bb)
  159. {
  160. _lcd_mode_w(); // enter W mode
  161. _lcd_write_high(bb);
  162. _lcd_clk();
  163. _lcd_write_low(bb);
  164. _lcd_clk();
  165. }
  166. /** Wait until the device is ready */
  167. void _lcd_wait_bf()
  168. {
  169. uint8_t d = 0;
  170. while (d++ < 120 && (lcd_read_bf_addr() & _BV(7)))
  171. _delay_us(1);
  172. }
  173. /** Send a string to LCD */
  174. void lcd_puts(char* str_p)
  175. {
  176. char c;
  177. while ((c = *str_p++))
  178. lcd_putc(c);
  179. }
  180. /** Print from progmem */
  181. void lcd_puts_P(const char* str_p)
  182. {
  183. char c;
  184. while ((c = pgm_read_byte(str_p++)))
  185. lcd_putc(c);
  186. }
  187. /** Sedn a char to LCD */
  188. void lcd_putc(const char c)
  189. {
  190. lcd_write(c);
  191. }
  192. /** Set cursor position */
  193. void lcd_xy(const uint8_t x, const uint8_t y)
  194. {
  195. _pos.x = x;
  196. _pos.y = y;
  197. lcd_addr(LCD_ROW_ADDR[y] + (x));
  198. }
  199. uint8_t _lcd_old_cursor = CURSOR_NONE;
  200. bool _lcd_enabled = false;
  201. /** Set LCD cursor. If not enabled, only remember it. */
  202. void lcd_cursor(uint8_t type)
  203. {
  204. _lcd_old_cursor = (type & CURSOR_BOTH);
  205. if (_lcd_enabled) lcd_command(LCD_CURSOR_NONE | _lcd_old_cursor);
  206. }
  207. /** Display display (preserving cursor) */
  208. void lcd_disable()
  209. {
  210. lcd_command(LCD_DISABLE);
  211. _lcd_enabled = false;
  212. }
  213. /** Enable display (restoring cursor) */
  214. void lcd_enable()
  215. {
  216. _lcd_enabled = true;
  217. lcd_cursor(_lcd_old_cursor);
  218. }
  219. /** Go home */
  220. void lcd_home()
  221. {
  222. lcd_command(LCD_HOME);
  223. _pos.x = 0;
  224. _pos.y = 0;
  225. _addrtype = TEXT;
  226. _delay_ms(1);
  227. }
  228. /** Clear the screen */
  229. void lcd_clear()
  230. {
  231. lcd_command(LCD_CLEAR);
  232. _pos.x = 0;
  233. _pos.y = 0;
  234. _addrtype = TEXT;
  235. _delay_ms(1);
  236. }
  237. /** Define a glyph */
  238. void lcd_glyph(const uint8_t index, const uint8_t* array)
  239. {
  240. lcd_addr_cg(index * 8);
  241. for (uint8_t i = 0; i < 8; ++i)
  242. {
  243. lcd_write(array[i]);
  244. }
  245. // restore previous position
  246. lcd_xy(_pos.x, _pos.y);
  247. _addrtype = TEXT;
  248. }
  249. /** Define a glyph */
  250. void lcd_glyph_P(const uint8_t index, const uint8_t* array)
  251. {
  252. lcd_addr_cg(index * 8);
  253. for (uint8_t i = 0; i < 8; ++i)
  254. {
  255. lcd_write(pgm_read_byte(&array[i]));
  256. }
  257. // restore previous position
  258. lcd_xy(_pos.x, _pos.y);
  259. _addrtype = TEXT;
  260. }
  261. /** Set address in CGRAM */
  262. void lcd_addr_cg(const uint8_t acg)
  263. {
  264. _addrtype = CG;
  265. lcd_command(0b01000000 | ((acg) & 0b00111111));
  266. }
  267. /** Set address in DDRAM */
  268. void lcd_addr(const uint8_t add)
  269. {
  270. _addrtype = TEXT;
  271. lcd_command(0b10000000 | ((add) & 0b01111111));
  272. }