lcd.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697
  1. //menu.cpp
  2. #include "lcd.h"
  3. #include <stdio.h>
  4. #include <stdarg.h>
  5. #include <avr/pgmspace.h>
  6. #include <avr/delay.h>
  7. #include "Timer.h"
  8. /*
  9. // commands
  10. #define LCD_CLEARDISPLAY 0x01
  11. #define LCD_RETURNHOME 0x02
  12. #define LCD_ENTRYMODESET 0x04
  13. #define LCD_DISPLAYCONTROL 0x08
  14. #define LCD_CURSORSHIFT 0x10
  15. #define LCD_FUNCTIONSET 0x20
  16. #define LCD_SETCGRAMADDR 0x40
  17. #define LCD_SETDDRAMADDR 0x80
  18. // flags for display entry mode
  19. #define LCD_ENTRYRIGHT 0x00
  20. #define LCD_ENTRYLEFT 0x02
  21. #define LCD_ENTRYSHIFTINCREMENT 0x01
  22. #define LCD_ENTRYSHIFTDECREMENT 0x00
  23. // flags for display on/off control
  24. #define LCD_DISPLAYON 0x04
  25. #define LCD_DISPLAYOFF 0x00
  26. #define LCD_CURSORON 0x02
  27. #define LCD_CURSOROFF 0x00
  28. #define LCD_BLINKON 0x01
  29. #define LCD_BLINKOFF 0x00
  30. // flags for display/cursor shift
  31. #define LCD_DISPLAYMOVE 0x08
  32. #define LCD_CURSORMOVE 0x00
  33. #define LCD_MOVERIGHT 0x04
  34. #define LCD_MOVELEFT 0x00
  35. // flags for function set
  36. #define LCD_8BITMODE 0x10
  37. #define LCD_4BITMODE 0x00
  38. #define LCD_2LINE 0x08
  39. #define LCD_1LINE 0x00
  40. #define LCD_5x10DOTS 0x04
  41. #define LCD_5x8DOTS 0x00
  42. */
  43. LiquidCrystal_Prusa lcd(LCD_PINS_RS, LCD_PINS_ENABLE, LCD_PINS_D4, LCD_PINS_D5,LCD_PINS_D6,LCD_PINS_D7); //RS,Enable,D4,D5,D6,D7
  44. FILE _lcdout = {0};
  45. int lcd_putchar(char c, FILE *stream)
  46. {
  47. lcd_write(c);
  48. return 0;
  49. }
  50. void lcd_command(uint8_t value)
  51. {
  52. lcd.send(value, LOW);
  53. }
  54. uint8_t lcd_write(uint8_t value)
  55. {
  56. if (value == '\n')
  57. {
  58. if (lcd._currline > 3) lcd._currline = -1;
  59. lcd_set_cursor(0, lcd._currline + 1); // LF
  60. return 1;
  61. }
  62. if (lcd._escape[0] || (value == 0x1b))
  63. return lcd.escape_write(value);
  64. lcd.send(value, HIGH);
  65. return 1; // assume sucess
  66. }
  67. void lcd_clear(void)
  68. {
  69. lcd_command(LCD_CLEARDISPLAY); // clear display, set cursor position to zero
  70. _delay_us(1600); // this command takes a long time
  71. }
  72. void lcd_set_cursor(uint8_t col, uint8_t row)
  73. {
  74. int row_offsets[] = { 0x00, 0x40, 0x14, 0x54 };
  75. if ( row >= lcd._numlines )
  76. row = lcd._numlines-1; // we count rows starting w/0
  77. lcd._currline = row;
  78. lcd_command(LCD_SETDDRAMADDR | (col + row_offsets[row]));
  79. }
  80. // Allows us to fill the first 8 CGRAM locations
  81. // with custom characters
  82. void lcd_createChar_P(uint8_t location, const uint8_t* charmap)
  83. {
  84. location &= 0x7; // we only have 8 locations 0-7
  85. lcd_command(LCD_SETCGRAMADDR | (location << 3));
  86. for (int i=0; i<8; i++)
  87. lcd.send(pgm_read_byte(&charmap[i]), HIGH);
  88. }
  89. int lcd_putc(int c)
  90. {
  91. return fputc(c, lcdout);
  92. }
  93. int lcd_puts_P(const char* str)
  94. {
  95. return fputs_P(str, lcdout);
  96. }
  97. int lcd_puts_at_P(uint8_t c, uint8_t r, const char* str)
  98. {
  99. lcd_set_cursor(c, r);
  100. return fputs_P(str, lcdout);
  101. }
  102. int lcd_printf_P(const char* format, ...)
  103. {
  104. va_list args;
  105. va_start(args, format);
  106. int ret = vfprintf_P(lcdout, format, args);
  107. va_end(args);
  108. return ret;
  109. }
  110. void lcd_print(const char* s)
  111. {
  112. while (*s) lcd_write(*(s++));
  113. }
  114. void lcd_print(char c, int base)
  115. {
  116. lcd_print((long) c, base);
  117. }
  118. void lcd_print(unsigned char b, int base)
  119. {
  120. lcd_print((unsigned long) b, base);
  121. }
  122. void lcd_print(int n, int base)
  123. {
  124. lcd_print((long) n, base);
  125. }
  126. void lcd_print(unsigned int n, int base)
  127. {
  128. lcd_print((unsigned long) n, base);
  129. }
  130. void lcd_print(long n, int base)
  131. {
  132. if (base == 0)
  133. lcd_write(n);
  134. else if (base == 10)
  135. {
  136. if (n < 0)
  137. {
  138. lcd_print('-');
  139. n = -n;
  140. }
  141. lcd_printNumber(n, 10);
  142. }
  143. else
  144. lcd_printNumber(n, base);
  145. }
  146. void lcd_print(unsigned long n, int base)
  147. {
  148. if (base == 0)
  149. lcd_write(n);
  150. else
  151. lcd_printNumber(n, base);
  152. }
  153. void lcd_print(double n, int digits)
  154. {
  155. lcd_printFloat(n, digits);
  156. }
  157. void lcd_printNumber(unsigned long n, uint8_t base)
  158. {
  159. unsigned char buf[8 * sizeof(long)]; // Assumes 8-bit chars.
  160. unsigned long i = 0;
  161. if (n == 0)
  162. {
  163. lcd_print('0');
  164. return;
  165. }
  166. while (n > 0)
  167. {
  168. buf[i++] = n % base;
  169. n /= base;
  170. }
  171. for (; i > 0; i--)
  172. lcd_print((char) (buf[i - 1] < 10 ? '0' + buf[i - 1] : 'A' + buf[i - 1] - 10));
  173. }
  174. void lcd_printFloat(double number, uint8_t digits)
  175. {
  176. // Handle negative numbers
  177. if (number < 0.0)
  178. {
  179. lcd_print('-');
  180. number = -number;
  181. }
  182. // Round correctly so that print(1.999, 2) prints as "2.00"
  183. double rounding = 0.5;
  184. for (uint8_t i=0; i<digits; ++i)
  185. rounding /= 10.0;
  186. number += rounding;
  187. // Extract the integer part of the number and print it
  188. unsigned long int_part = (unsigned long)number;
  189. double remainder = number - (double)int_part;
  190. lcd_print(int_part);
  191. // Print the decimal point, but only if there are digits beyond
  192. if (digits > 0)
  193. lcd_print('.');
  194. // Extract digits from the remainder one at a time
  195. while (digits-- > 0)
  196. {
  197. remainder *= 10.0;
  198. int toPrint = int(remainder);
  199. lcd_print(toPrint);
  200. remainder -= toPrint;
  201. }
  202. }
  203. uint8_t lcd_draw_update = 2;
  204. int32_t lcd_encoder = 0;
  205. uint8_t lcd_encoder_bits = 0;
  206. int8_t lcd_encoder_diff = 0;
  207. uint8_t lcd_buttons = 0;
  208. uint8_t lcd_button_pressed = 0;
  209. uint8_t lcd_update_enabled = 1;
  210. uint32_t lcd_timeoutToStatus = 0;
  211. uint32_t lcd_next_update_millis = 0;
  212. uint8_t lcd_status_update_delay = 0;
  213. uint8_t lcd_long_press_active = 0;
  214. lcd_longpress_func_t lcd_longpress_func = 0;
  215. lcd_charsetup_func_t lcd_charsetup_func = 0;
  216. lcd_lcdupdate_func_t lcd_lcdupdate_func = 0;
  217. uint32_t lcd_button_blanking_time = millis();
  218. ShortTimer longPressTimer;
  219. uint8_t lcd_clicked(void)
  220. {
  221. bool clicked = LCD_CLICKED;
  222. if(clicked) lcd_button_pressed = 1;
  223. return clicked;
  224. }
  225. void lcd_beeper_quick_feedback(void)
  226. {
  227. SET_OUTPUT(BEEPER);
  228. for(int8_t i = 0; i < 10; i++)
  229. {
  230. WRITE(BEEPER,HIGH);
  231. delayMicroseconds(100);
  232. WRITE(BEEPER,LOW);
  233. delayMicroseconds(100);
  234. }
  235. }
  236. void lcd_quick_feedback(void)
  237. {
  238. lcd_draw_update = 2;
  239. lcd_button_pressed = false;
  240. lcd_beeper_quick_feedback();
  241. }
  242. void lcd_update(uint8_t lcdDrawUpdateOverride)
  243. {
  244. if (lcd_draw_update < lcdDrawUpdateOverride)
  245. lcd_draw_update = lcdDrawUpdateOverride;
  246. if (!lcd_update_enabled)
  247. return;
  248. lcd_buttons_update();
  249. if (lcd_lcdupdate_func)
  250. lcd_lcdupdate_func();
  251. }
  252. void lcd_update_enable(uint8_t enabled)
  253. {
  254. if (lcd_update_enabled != enabled)
  255. {
  256. lcd_update_enabled = enabled;
  257. if (enabled)
  258. { // Reset encoder position. This is equivalent to re-entering a menu.
  259. lcd_encoder = 0;
  260. lcd_encoder_diff = 0;
  261. // Enabling the normal LCD update procedure.
  262. // Reset the timeout interval.
  263. lcd_timeoutToStatus = millis() + LCD_TIMEOUT_TO_STATUS;
  264. // Force the keypad update now.
  265. lcd_next_update_millis = millis() - 1;
  266. // Full update.
  267. lcd_clear();
  268. if (lcd_charsetup_func)
  269. lcd_charsetup_func();
  270. lcd_update(2);
  271. } else
  272. {
  273. // Clear the LCD always, or let it to the caller?
  274. }
  275. }
  276. }
  277. void lcd_buttons_update(void)
  278. {
  279. static bool _lock = false;
  280. if (_lock) return;
  281. _lock = true;
  282. uint8_t newbutton = 0;
  283. if (READ(BTN_EN1) == 0) newbutton |= EN_A;
  284. if (READ(BTN_EN2) == 0) newbutton |= EN_B;
  285. if (lcd_update_enabled)
  286. { //if we are in non-modal mode, long press can be used and short press triggers with button release
  287. if (READ(BTN_ENC) == 0)
  288. { //button is pressed
  289. lcd_timeoutToStatus = millis() + LCD_TIMEOUT_TO_STATUS;
  290. if (millis() > lcd_button_blanking_time)
  291. {
  292. lcd_button_blanking_time = millis() + BUTTON_BLANKING_TIME;
  293. if ((lcd_button_pressed == 0) && (lcd_long_press_active == 0))
  294. {
  295. longPressTimer.start();
  296. lcd_button_pressed = 1;
  297. }
  298. else
  299. {
  300. if (longPressTimer.expired(LONG_PRESS_TIME))
  301. {
  302. lcd_long_press_active = 1;
  303. if (lcd_longpress_func)
  304. lcd_longpress_func();
  305. }
  306. }
  307. }
  308. }
  309. else
  310. { //button not pressed
  311. if (lcd_button_pressed)
  312. { //button was released
  313. lcd_button_blanking_time = millis() + BUTTON_BLANKING_TIME;
  314. if (lcd_long_press_active == 0)
  315. { //button released before long press gets activated
  316. newbutton |= EN_C;
  317. }
  318. //else if (menu_menu == lcd_move_z) lcd_quick_feedback();
  319. //lcd_button_pressed is set back to false via lcd_quick_feedback function
  320. }
  321. else
  322. lcd_long_press_active = 0;
  323. }
  324. }
  325. else
  326. { //we are in modal mode
  327. if (READ(BTN_ENC) == 0)
  328. newbutton |= EN_C;
  329. }
  330. lcd_buttons = newbutton;
  331. //manage encoder rotation
  332. uint8_t enc = 0;
  333. if (lcd_buttons & EN_A) enc |= B01;
  334. if (lcd_buttons & EN_B) enc |= B10;
  335. if (enc != lcd_encoder_bits)
  336. {
  337. switch (enc)
  338. {
  339. case encrot0:
  340. if (lcd_encoder_bits == encrot3)
  341. lcd_encoder_diff++;
  342. else if (lcd_encoder_bits == encrot1)
  343. lcd_encoder_diff--;
  344. break;
  345. case encrot1:
  346. if (lcd_encoder_bits == encrot0)
  347. lcd_encoder_diff++;
  348. else if (lcd_encoder_bits == encrot2)
  349. lcd_encoder_diff--;
  350. break;
  351. case encrot2:
  352. if (lcd_encoder_bits == encrot1)
  353. lcd_encoder_diff++;
  354. else if (lcd_encoder_bits == encrot3)
  355. lcd_encoder_diff--;
  356. break;
  357. case encrot3:
  358. if (lcd_encoder_bits == encrot2)
  359. lcd_encoder_diff++;
  360. else if (lcd_encoder_bits == encrot0)
  361. lcd_encoder_diff--;
  362. break;
  363. }
  364. }
  365. lcd_encoder_bits = enc;
  366. _lock = false;
  367. }
  368. void lcd_implementation_init(void)
  369. {
  370. lcd.begin(LCD_WIDTH, LCD_HEIGHT);
  371. lcd_set_custom_characters();
  372. lcd_clear();
  373. }
  374. void lcd_implementation_init_noclear(void)
  375. {
  376. lcd.begin_noclear(LCD_WIDTH, LCD_HEIGHT);
  377. lcd_set_custom_characters();
  378. }
  379. void lcd_drawedit(const char* pstr, char* value)
  380. {
  381. lcd_set_cursor(1, 1);
  382. lcd_puts_P(pstr);
  383. lcd_print(':');
  384. #if LCD_WIDTH < 20
  385. lcd_set_cursor(LCD_WIDTH - strlen(value), 1);
  386. #else
  387. lcd_set_cursor(LCD_WIDTH -1 - strlen(value), 1);
  388. #endif
  389. lcd_print(value);
  390. }
  391. void lcd_drawedit_2(const char* pstr, char* value)
  392. {
  393. lcd_set_cursor(0, 1);
  394. lcd_puts_P(pstr);
  395. lcd_print(':');
  396. lcd_set_cursor((LCD_WIDTH - strlen(value))/2, 3);
  397. lcd_print(value);
  398. lcd_print(" mm");
  399. }
  400. ////////////////////////////////////////////////////////////////////////////////
  401. // Custom character data
  402. const uint8_t lcd_chardata_bedTemp[8] PROGMEM = {
  403. B00000,
  404. B11111,
  405. B10101,
  406. B10001,
  407. B10101,
  408. B11111,
  409. B00000,
  410. B00000}; //thanks Sonny Mounicou
  411. const uint8_t lcd_chardata_degree[8] PROGMEM = {
  412. B01100,
  413. B10010,
  414. B10010,
  415. B01100,
  416. B00000,
  417. B00000,
  418. B00000,
  419. B00000};
  420. const uint8_t lcd_chardata_thermometer[8] PROGMEM = {
  421. B00100,
  422. B01010,
  423. B01010,
  424. B01010,
  425. B01010,
  426. B10001,
  427. B10001,
  428. B01110};
  429. const uint8_t lcd_chardata_uplevel[8] PROGMEM = {
  430. B00100,
  431. B01110,
  432. B11111,
  433. B00100,
  434. B11100,
  435. B00000,
  436. B00000,
  437. B00000}; //thanks joris
  438. const uint8_t lcd_chardata_refresh[8] PROGMEM = {
  439. B00000,
  440. B00110,
  441. B11001,
  442. B11000,
  443. B00011,
  444. B10011,
  445. B01100,
  446. B00000}; //thanks joris
  447. const uint8_t lcd_chardata_folder[8] PROGMEM = {
  448. B00000,
  449. B11100,
  450. B11111,
  451. B10001,
  452. B10001,
  453. B11111,
  454. B00000,
  455. B00000}; //thanks joris
  456. const uint8_t lcd_chardata_feedrate[8] PROGMEM = {
  457. B11100,
  458. B10000,
  459. B11000,
  460. B10111,
  461. B00101,
  462. B00110,
  463. B00101,
  464. B00000}; //thanks Sonny Mounicou
  465. /*const uint8_t lcd_chardata_feedrate[8] PROGMEM = {
  466. B11100,
  467. B10100,
  468. B11000,
  469. B10100,
  470. B00000,
  471. B00111,
  472. B00010,
  473. B00010};*/
  474. /*const uint8_t lcd_chardata_feedrate[8] PROGMEM = {
  475. B01100,
  476. B10011,
  477. B00000,
  478. B01100,
  479. B10011,
  480. B00000,
  481. B01100,
  482. B10011};*/
  483. /*const uint8_t lcd_chardata_feedrate[8] PROGMEM = {
  484. B00000,
  485. B00100,
  486. B10010,
  487. B01001,
  488. B10010,
  489. B00100,
  490. B00000,
  491. B00000};*/
  492. const uint8_t lcd_chardata_clock[8] PROGMEM = {
  493. B00000,
  494. B01110,
  495. B10011,
  496. B10101,
  497. B10001,
  498. B01110,
  499. B00000,
  500. B00000}; //thanks Sonny Mounicou
  501. const uint8_t lcd_chardata_arrup[8] PROGMEM = {
  502. B00100,
  503. B01110,
  504. B11111,
  505. B00000,
  506. B00000,
  507. B00000,
  508. B00000,
  509. B00000};
  510. const uint8_t lcd_chardata_arrdown[8] PROGMEM = {
  511. B00000,
  512. B00000,
  513. B00000,
  514. B00000,
  515. B00000,
  516. B10001,
  517. B01010,
  518. B00100};
  519. void lcd_set_custom_characters(void)
  520. {
  521. lcd_createChar_P(LCD_STR_BEDTEMP[0], lcd_chardata_bedTemp);
  522. lcd_createChar_P(LCD_STR_DEGREE[0], lcd_chardata_degree);
  523. lcd_createChar_P(LCD_STR_THERMOMETER[0], lcd_chardata_thermometer);
  524. lcd_createChar_P(LCD_STR_UPLEVEL[0], lcd_chardata_uplevel);
  525. lcd_createChar_P(LCD_STR_REFRESH[0], lcd_chardata_refresh);
  526. lcd_createChar_P(LCD_STR_FOLDER[0], lcd_chardata_folder);
  527. lcd_createChar_P(LCD_STR_FEEDRATE[0], lcd_chardata_feedrate);
  528. lcd_createChar_P(LCD_STR_CLOCK[0], lcd_chardata_clock);
  529. //lcd_createChar_P(LCD_STR_ARROW_UP[0], lcd_chardata_arrup);
  530. //lcd_createChar_P(LCD_STR_ARROW_DOWN[0], lcd_chardata_arrdown);
  531. }
  532. void lcd_set_custom_characters_arrows(void)
  533. {
  534. lcd_createChar_P(1, lcd_chardata_arrdown);
  535. }
  536. const uint8_t lcd_chardata_progress[8] PROGMEM = {
  537. B11111,
  538. B11111,
  539. B11111,
  540. B11111,
  541. B11111,
  542. B11111,
  543. B11111,
  544. B11111};
  545. void lcd_set_custom_characters_progress(void)
  546. {
  547. lcd_createChar_P(1, lcd_chardata_progress);
  548. }
  549. const uint8_t lcd_chardata_arr2down[8] PROGMEM = {
  550. B00000,
  551. B00000,
  552. B10001,
  553. B01010,
  554. B00100,
  555. B10001,
  556. B01010,
  557. B00100};
  558. const uint8_t lcd_chardata_confirm[8] PROGMEM = {
  559. B00000,
  560. B00001,
  561. B00011,
  562. B10110,
  563. B11100,
  564. B01000,
  565. B00000};
  566. void lcd_set_custom_characters_nextpage(void)
  567. {
  568. lcd_createChar_P(1, lcd_chardata_arr2down);
  569. lcd_createChar_P(2, lcd_chardata_confirm);
  570. }
  571. void lcd_set_custom_characters_degree(void)
  572. {
  573. lcd_createChar_P(1, lcd_chardata_degree);
  574. }