/firmware/src/shared/LiquidCrystal.cc

http://github.com/makerbot/G3Firmware · C++ · 343 lines · 227 code · 60 blank · 56 comment · 25 complexity · 7e68b8169f0c423623739dd6498b1d87 MD5 · raw file

  1. #include "LiquidCrystal.hh"
  2. #include <stdio.h>
  3. #include <string.h>
  4. #include <util/delay.h>
  5. // When the display powers up, it is configured as follows:
  6. //
  7. // 1. Display clear
  8. // 2. Function set:
  9. // DL = 1; 8-bit interface data
  10. // N = 0; 1-line display
  11. // F = 0; 5x8 dot character font
  12. // 3. Display on/off control:
  13. // D = 0; Display off
  14. // C = 0; Cursor off
  15. // B = 0; Blinking off
  16. // 4. Entry mode set:
  17. // I/D = 1; Increment by 1
  18. // S = 0; No shift
  19. //
  20. // Note, however, that resetting the Arduino doesn't reset the LCD, so we
  21. // can't assume that its in that state when a sketch starts (and the
  22. // LiquidCrystal constructor is called).
  23. LiquidCrystal::LiquidCrystal(Pin rs, Pin rw, Pin enable,
  24. Pin d0, Pin d1, Pin d2, Pin d3,
  25. Pin d4, Pin d5, Pin d6, Pin d7)
  26. {
  27. init(0, rs, rw, enable, d0, d1, d2, d3, d4, d5, d6, d7);
  28. }
  29. LiquidCrystal::LiquidCrystal(Pin rs, Pin enable,
  30. Pin d0, Pin d1, Pin d2, Pin d3,
  31. Pin d4, Pin d5, Pin d6, Pin d7)
  32. {
  33. init(0, rs, Pin(), enable, d0, d1, d2, d3, d4, d5, d6, d7);
  34. }
  35. LiquidCrystal::LiquidCrystal(Pin rs, Pin rw, Pin enable,
  36. Pin d0, Pin d1, Pin d2, Pin d3)
  37. {
  38. init(1, rs, rw, enable, d0, d1, d2, d3, Pin(), Pin(), Pin(), Pin());
  39. }
  40. LiquidCrystal::LiquidCrystal(Pin rs, Pin enable,
  41. Pin d0, Pin d1, Pin d2, Pin d3)
  42. {
  43. init(1, rs, Pin(), enable, d0, d1, d2, d3, Pin(), Pin(), Pin(), Pin());
  44. }
  45. void LiquidCrystal::init(uint8_t fourbitmode, Pin rs, Pin rw, Pin enable,
  46. Pin d0, Pin d1, Pin d2, Pin d3,
  47. Pin d4, Pin d5, Pin d6, Pin d7)
  48. {
  49. _rs_pin = rs;
  50. _rw_pin = rw;
  51. _enable_pin = enable;
  52. _data_pins[0] = d0;
  53. _data_pins[1] = d1;
  54. _data_pins[2] = d2;
  55. _data_pins[3] = d3;
  56. _data_pins[4] = d4;
  57. _data_pins[5] = d5;
  58. _data_pins[6] = d6;
  59. _data_pins[7] = d7;
  60. _rs_pin.setDirection(true);
  61. // we can save 1 pin by not using RW. Indicate by passing 255 instead of pin#
  62. if (!_rw_pin.isNull()) { _rw_pin.setDirection(true); }
  63. _enable_pin.setDirection(true);
  64. if (fourbitmode)
  65. _displayfunction = LCD_4BITMODE | LCD_1LINE | LCD_5x8DOTS;
  66. else
  67. _displayfunction = LCD_8BITMODE | LCD_1LINE | LCD_5x8DOTS;
  68. begin(16, 1);
  69. }
  70. void LiquidCrystal::begin(uint8_t cols, uint8_t lines, uint8_t dotsize) {
  71. if (lines > 1) {
  72. _displayfunction |= LCD_2LINE;
  73. }
  74. _numlines = lines;
  75. _currline = 0;
  76. // for some 1 line displays you can select a 10 pixel high font
  77. if ((dotsize != 0) && (lines == 1)) {
  78. _displayfunction |= LCD_5x10DOTS;
  79. }
  80. // SEE PAGE 45/46 FOR INITIALIZATION SPECIFICATION!
  81. // according to datasheet, we need at least 40ms after power rises above 2.7V
  82. // before sending commands. Arduino can turn on way befer 4.5V so we'll wait 50
  83. _delay_us(50000);
  84. // Now we pull both RS and R/W low to begin commands
  85. _rs_pin.setValue(false);
  86. _enable_pin.setValue(false);
  87. if (!_rw_pin.isNull()) {
  88. _rw_pin.setValue(false);
  89. }
  90. //put the LCD into 4 bit or 8 bit mode
  91. if (! (_displayfunction & LCD_8BITMODE)) {
  92. // this is according to the hitachi HD44780 datasheet
  93. // figure 24, pg 46
  94. // we start in 8bit mode, try to set 4 bit mode
  95. write4bits(0x03);
  96. _delay_us(4500); // wait min 4.1ms
  97. // second try
  98. write4bits(0x03);
  99. _delay_us(4500); // wait min 4.1ms
  100. // third go!
  101. write4bits(0x03);
  102. _delay_us(150);
  103. // finally, set to 8-bit interface
  104. write4bits(0x02);
  105. } else {
  106. // this is according to the hitachi HD44780 datasheet
  107. // page 45 figure 23
  108. // Send function set command sequence
  109. command(LCD_FUNCTIONSET | _displayfunction);
  110. _delay_us(4500); // wait more than 4.1ms
  111. // second try
  112. command(LCD_FUNCTIONSET | _displayfunction);
  113. _delay_us(150);
  114. // third go
  115. command(LCD_FUNCTIONSET | _displayfunction);
  116. }
  117. // finally, set # lines, font size, etc.
  118. command(LCD_FUNCTIONSET | _displayfunction);
  119. // turn the display on with no cursor or blinking default
  120. _displaycontrol = LCD_DISPLAYON | LCD_CURSOROFF | LCD_BLINKOFF;
  121. display();
  122. // clear it off
  123. clear();
  124. // Initialize to default text direction (for romance languages)
  125. _displaymode = LCD_ENTRYLEFT | LCD_ENTRYSHIFTDECREMENT;
  126. // set the entry mode
  127. command(LCD_ENTRYMODESET | _displaymode);
  128. }
  129. /********** high level commands, for the user! */
  130. void LiquidCrystal::clear()
  131. {
  132. command(LCD_CLEARDISPLAY); // clear display, set cursor position to zero
  133. _delay_us(2000); // this command takes a long time!
  134. }
  135. void LiquidCrystal::home()
  136. {
  137. command(LCD_RETURNHOME); // set cursor position to zero
  138. _delay_us(2000); // this command takes a long time!
  139. }
  140. void LiquidCrystal::setCursor(uint8_t col, uint8_t row)
  141. {
  142. int row_offsets[] = { 0x00, 0x40, 0x10, 0x50 };
  143. if ( row > _numlines ) {
  144. row = _numlines-1; // we count rows starting w/0
  145. }
  146. command(LCD_SETDDRAMADDR | (col + row_offsets[row]));
  147. }
  148. // Turn the display on/off (quickly)
  149. void LiquidCrystal::noDisplay() {
  150. _displaycontrol &= ~LCD_DISPLAYON;
  151. command(LCD_DISPLAYCONTROL | _displaycontrol);
  152. }
  153. void LiquidCrystal::display() {
  154. _displaycontrol |= LCD_DISPLAYON;
  155. command(LCD_DISPLAYCONTROL | _displaycontrol);
  156. }
  157. // Turns the underline cursor on/off
  158. void LiquidCrystal::noCursor() {
  159. _displaycontrol &= ~LCD_CURSORON;
  160. command(LCD_DISPLAYCONTROL | _displaycontrol);
  161. }
  162. void LiquidCrystal::cursor() {
  163. _displaycontrol |= LCD_CURSORON;
  164. command(LCD_DISPLAYCONTROL | _displaycontrol);
  165. }
  166. // Turn on and off the blinking cursor
  167. void LiquidCrystal::noBlink() {
  168. _displaycontrol &= ~LCD_BLINKON;
  169. command(LCD_DISPLAYCONTROL | _displaycontrol);
  170. }
  171. void LiquidCrystal::blink() {
  172. _displaycontrol |= LCD_BLINKON;
  173. command(LCD_DISPLAYCONTROL | _displaycontrol);
  174. }
  175. // These commands scroll the display without changing the RAM
  176. void LiquidCrystal::scrollDisplayLeft(void) {
  177. command(LCD_CURSORSHIFT | LCD_DISPLAYMOVE | LCD_MOVELEFT);
  178. }
  179. void LiquidCrystal::scrollDisplayRight(void) {
  180. command(LCD_CURSORSHIFT | LCD_DISPLAYMOVE | LCD_MOVERIGHT);
  181. }
  182. // This is for text that flows Left to Right
  183. void LiquidCrystal::leftToRight(void) {
  184. _displaymode |= LCD_ENTRYLEFT;
  185. command(LCD_ENTRYMODESET | _displaymode);
  186. }
  187. // This is for text that flows Right to Left
  188. void LiquidCrystal::rightToLeft(void) {
  189. _displaymode &= ~LCD_ENTRYLEFT;
  190. command(LCD_ENTRYMODESET | _displaymode);
  191. }
  192. // This will 'right justify' text from the cursor
  193. void LiquidCrystal::autoscroll(void) {
  194. _displaymode |= LCD_ENTRYSHIFTINCREMENT;
  195. command(LCD_ENTRYMODESET | _displaymode);
  196. }
  197. // This will 'left justify' text from the cursor
  198. void LiquidCrystal::noAutoscroll(void) {
  199. _displaymode &= ~LCD_ENTRYSHIFTINCREMENT;
  200. command(LCD_ENTRYMODESET | _displaymode);
  201. }
  202. // Allows us to fill the first 8 CGRAM locations
  203. // with custom characters
  204. void LiquidCrystal::createChar(uint8_t location, uint8_t charmap[]) {
  205. location &= 0x7; // we only have 8 locations 0-7
  206. command(LCD_SETCGRAMADDR | (location << 3));
  207. for (int i=0; i<8; i++) {
  208. write(charmap[i]);
  209. }
  210. }
  211. /*********** mid level commands, for sending data/cmds */
  212. inline void LiquidCrystal::command(uint8_t value) {
  213. send(value, false);
  214. }
  215. inline void LiquidCrystal::write(uint8_t value) {
  216. send(value, true);
  217. }
  218. void LiquidCrystal::writeInt(uint16_t value, uint8_t digits) {
  219. uint16_t currentDigit;
  220. uint16_t nextDigit;
  221. switch (digits) {
  222. case 1: currentDigit = 10; break;
  223. case 2: currentDigit = 100; break;
  224. case 3: currentDigit = 1000; break;
  225. case 4: currentDigit = 10000; break;
  226. default: return;
  227. }
  228. for (uint8_t i = 0; i < digits; i++) {
  229. nextDigit = currentDigit/10;
  230. write((value%currentDigit)/nextDigit+'0');
  231. currentDigit = nextDigit;
  232. }
  233. }
  234. void LiquidCrystal::writeString(char message[]) {
  235. char* letter = message;
  236. while (*letter != 0) {
  237. write(*letter);
  238. letter++;
  239. }
  240. }
  241. void LiquidCrystal::writeFromPgmspace(const prog_uchar message[]) {
  242. char letter;
  243. while (letter = pgm_read_byte(message++)) {
  244. write(letter);
  245. }
  246. }
  247. /************ low level data pushing commands **********/
  248. // write either command or data, with automatic 4/8-bit selection
  249. void LiquidCrystal::send(uint8_t value, bool mode) {
  250. _rs_pin.setValue(mode);
  251. // if there is a RW pin indicated, set it low to Write
  252. if (!_rw_pin.isNull()) {
  253. _rw_pin.setValue(false);
  254. }
  255. if (_displayfunction & LCD_8BITMODE) {
  256. write8bits(value);
  257. } else {
  258. write4bits(value>>4);
  259. write4bits(value);
  260. }
  261. }
  262. void LiquidCrystal::pulseEnable(void) {
  263. _enable_pin.setValue(false);
  264. _delay_us(1);
  265. _enable_pin.setValue(true);
  266. _delay_us(1); // enable pulse must be >450ns
  267. _enable_pin.setValue(false);
  268. _delay_us(1); // commands need > 37us to settle [citation needed]
  269. }
  270. void LiquidCrystal::write4bits(uint8_t value) {
  271. for (int i = 0; i < 4; i++) {
  272. _data_pins[i].setDirection(true);
  273. _data_pins[i].setValue(((value >> i) & 0x01) != 0);
  274. }
  275. pulseEnable();
  276. }
  277. void LiquidCrystal::write8bits(uint8_t value) {
  278. for (int i = 0; i < 8; i++) {
  279. _data_pins[i].setDirection(true);
  280. _data_pins[i].setValue(((value >> i) & 0x01) != 0);
  281. }
  282. pulseEnable();
  283. }