Ein Roboter mit bürstenlosem Antrieb, differenzial und NRF24L01 Funk. Großflächig gebaut um ein großes Solarpanel aufzunehmen. https://gitlab.informatik.hs-fulda.de/fdai5253/roboter
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

284 lines
8.5 KiB

  1. #include "PCD8544_SPI.h"
  2. #include <SPI.h>
  3. PCD8544_SPI_FB::PCD8544_SPI_FB()
  4. {
  5. }
  6. void PCD8544_SPI_FB::begin(bool invert)
  7. {
  8. this->begin(invert, 0xB0, 0x04, 0x12);
  9. }
  10. void PCD8544_SPI_FB::begin(bool invert, uint8_t vop, uint8_t tempCoef, uint8_t bias)
  11. {
  12. PCD8544_PORT |= (PIN_DC | PIN_RESET | PIN_CE);
  13. PCD8544_DDR |= (PIN_DC | PIN_RESET | PIN_CE);
  14. SPI.begin();
  15. // LCD init section:
  16. uint8_t invertSetting = invert ? 0x0D : 0x0C;
  17. // Must reset LCD first!
  18. PCD8544_PORT &= ~PIN_RESET;
  19. PCD8544_PORT |= PIN_RESET;
  20. this->writeLcd(PCD8544_COMMAND, 0x21); //Tell LCD that extended commands follow
  21. this->writeLcd(PCD8544_COMMAND, vop); //Set LCD Vop (Contrast): Try 0xB1(good @ 3.3V) or 0xBF if your display is too dark
  22. this->writeLcd(PCD8544_COMMAND, tempCoef); //Set Temp coefficent
  23. this->writeLcd(PCD8544_COMMAND, bias); //LCD bias mode 1:48: Try 0x13 or 0x14. Mine works best with 1:65/1:65
  24. this->writeLcd(PCD8544_COMMAND, 0x20); //We must send 0x20 before modifying the display control mode
  25. this->writeLcd(PCD8544_COMMAND, invertSetting); //Set display control, normal mode. 0x0D for inverse
  26. this->clear();
  27. }
  28. size_t PCD8544_SPI_FB::write(uint8_t data)
  29. {
  30. // Non-ASCII characters are not supported.
  31. if (data < 0x20 || data > 0x7F) return 0;
  32. if (this->m_Position + 5 >= BUF_LEN) this->m_Position -= (BUF_LEN - 6);
  33. memcpy_P(this->m_Buffer + this->m_Position, ASCII[data - 0x20], 5);
  34. this->m_Buffer[this->m_Position+5] = 0x00;
  35. this->m_Position += 6;
  36. if (this->m_Position >= BUF_LEN) this->m_Position -= BUF_LEN;
  37. //this->m_Position %= BUF_LEN;
  38. return 1;
  39. }
  40. void PCD8544_SPI_FB::clear(bool render)
  41. {
  42. memset(this->m_Buffer, 0x00, sizeof(this->m_Buffer));
  43. if (render)
  44. this->renderAll();
  45. this->gotoXY(0, 0);
  46. }
  47. uint8_t PCD8544_SPI_FB::gotoXY(uint8_t x, uint8_t y)
  48. {
  49. if (x >= PCD8544_X_PIXELS || y >= PCD8544_ROWS) return PCD8544_ERROR;
  50. this->writeLcd(PCD8544_COMMAND, 0x80 | x); // Column.
  51. this->writeLcd(PCD8544_COMMAND, 0x40 | y); // Row.
  52. this->m_Position = (PCD8544_X_PIXELS * y) + x;
  53. return PCD8544_SUCCESS;
  54. }
  55. uint8_t PCD8544_SPI_FB::writeBitmap(const uint8_t *bitmap, uint8_t x, uint8_t y, uint8_t width, uint8_t height)
  56. {
  57. //if (x >= PCD8544_X_PIXELS || y >= PCD8544_Y_PIXELS) return;
  58. //this->gotoXY(x, y);
  59. //uint16_t pos = this->m_Position;
  60. //for (uint8_t y = 0; y < height; y++)
  61. //{
  62. // memcpy(this->m_Buffer + pos, bitmap + (y*width), width);
  63. // pos += PCD8544_X_PIXELS;
  64. //}
  65. if (this->gotoXY(x, y) == PCD8544_ERROR) return PCD8544_ERROR;
  66. uint8_t *pos = this->m_Buffer + this->m_Position;
  67. const uint8_t *maxY = bitmap + height * width;
  68. for (const uint8_t *y = (uint8_t*) bitmap; y < maxY; y += width)
  69. {
  70. memcpy(pos, y, width);
  71. pos += PCD8544_X_PIXELS;
  72. }
  73. return PCD8544_SUCCESS;
  74. }
  75. //void PCD8544_SPI_FB::init(void)
  76. //{
  77. // // Must reset LCD first!
  78. // PCD8544_PORT &= ~PIN_RESET;
  79. // PCD8544_PORT |= PIN_RESET;
  80. //
  81. // this->writeLcd(PCD8544_COMMAND, 0x21); //Tell LCD that extended commands follow
  82. // this->writeLcd(PCD8544_COMMAND, 0xB0); //Set LCD Vop (Contrast): Try 0xB1(good @ 3.3V) or 0xBF if your display is too dark
  83. // this->writeLcd(PCD8544_COMMAND, 0x04); //Set Temp coefficent
  84. // this->writeLcd(PCD8544_COMMAND, 0x12); //LCD bias mode 1:48: Try 0x13 or 0x14. Mine works best with 1:65/1:65
  85. //
  86. // this->writeLcd(PCD8544_COMMAND, 0x20); //We must send 0x20 before modifying the display control mode
  87. // this->writeLcd(PCD8544_COMMAND, 0x0C); //Set display control, normal mode. 0x0D for inverse
  88. //}
  89. void PCD8544_SPI_FB::renderLine()
  90. {
  91. this->writeLcd(PCD8544_DATA, this->m_Buffer, BUF_LEN);
  92. }
  93. void PCD8544_SPI_FB::renderAll()
  94. {
  95. this->gotoXY(0, 0);
  96. this->writeLcd(PCD8544_DATA, this->m_Buffer, BUF_LEN);
  97. }
  98. uint8_t PCD8544_SPI_FB::renderString(uint8_t x, uint8_t y, uint16_t length)
  99. {
  100. if (this->gotoXY(x, y) == PCD8544_ERROR) return PCD8544_ERROR;
  101. length *= 6;
  102. this->writeLcd(PCD8544_DATA, this->m_Buffer + this->m_Position, length);
  103. this->m_Position += length;
  104. return PCD8544_SUCCESS;
  105. }
  106. void PCD8544_SPI_FB::setPixel(uint8_t x, uint8_t y, uint8_t value)
  107. {
  108. if (x >= PCD8544_X_PIXELS || y >= PCD8544_Y_PIXELS) return;
  109. uint8_t bank = y / 8;
  110. uint8_t bitMask = 1 << (y % 8);
  111. uint8_t &byte = this->m_Buffer[(PCD8544_X_PIXELS * bank) + x];
  112. if (value)
  113. byte |= bitMask;
  114. else
  115. byte &= ~bitMask;
  116. }
  117. bool PCD8544_SPI_FB::getPixel(uint8_t x, uint8_t y)
  118. {
  119. if (x >= PCD8544_X_PIXELS || y >= PCD8544_Y_PIXELS) return false;
  120. uint8_t bank = y / 8;
  121. uint8_t bitMask = 1 << (y % 8);
  122. uint8_t &byte = this->m_Buffer[(PCD8544_X_PIXELS * bank) + x];
  123. if((byte &= bitMask) > 0){
  124. return true;
  125. } else{
  126. return false;
  127. }
  128. }
  129. uint8_t PCD8544_SPI_FB::writeLine(uint8_t x1, uint8_t y1, uint8_t x2, uint8_t y2)
  130. {
  131. if (x1 == x2 || y1 == y2)
  132. {
  133. if (y1 > y2)
  134. swap(y1, y2);
  135. if (x1 > x2)
  136. swap(x1, x2);
  137. return this->writeRect(x1, y1, x2 - x1 + 1, y2 - y1 + 1);
  138. }
  139. else
  140. return PCD8544_ERROR;
  141. }
  142. void PCD8544_SPI_FB::swap(uint8_t &a, uint8_t &b)
  143. {
  144. uint8_t temp = a;
  145. a = b;
  146. b = temp;
  147. }
  148. //from top left to bottom right corner
  149. uint8_t PCD8544_SPI_FB::writeRect(uint8_t x, uint8_t y, uint8_t width, uint8_t height, bool fill)
  150. {
  151. if (x >= PCD8544_X_PIXELS || y >= PCD8544_Y_PIXELS || width == 0 || height == 0) return PCD8544_ERROR;
  152. // Calculate the bitmasks for the pixels.
  153. uint8_t bottom = y + height - 1;
  154. uint8_t bankTop = y / 8;
  155. uint8_t bankBottom = bottom / 8;
  156. uint8_t bitMaskTop = 0x01;
  157. uint8_t bitMaskBottom = 0x80;
  158. uint8_t bitMaskTopFill = 0xFF;
  159. uint8_t bitMaskBottomFill = 0xFF;
  160. bitMaskTop <<= (y % 8);
  161. bitMaskBottom >>= 7 - (bottom % 8);
  162. bitMaskTopFill <<= (y % 8);
  163. bitMaskBottomFill >>= 7 - (bottom % 8);
  164. // When fill is selected, we'll use the FillMask.
  165. if (fill)
  166. {
  167. bitMaskTop = bitMaskTopFill;
  168. bitMaskBottom = bitMaskBottomFill;
  169. }
  170. // When the rectangle fits in a single bank, we AND the top and bottom masks
  171. // So that we only fill the required area on the LCD.
  172. if (bankTop == bankBottom)
  173. {
  174. bitMaskTop = fill ? bitMaskTop & bitMaskBottom : bitMaskTop | bitMaskBottom;
  175. bitMaskTopFill &= bitMaskBottomFill;
  176. }
  177. this->gotoXY(x, bankTop);
  178. // Write the left 'side' of the rectangle on the top bank.
  179. this->m_Buffer[this->m_Position++] |= bitMaskTopFill;
  180. // Write a line or a fill.
  181. for (uint8_t i = 1; i < width-1; i++)
  182. this->m_Buffer[this->m_Position++] |= bitMaskTop;
  183. // Write the right 'side' of the rectangle on the top bank.
  184. if (width > 1)
  185. this->m_Buffer[this->m_Position++] |= bitMaskTopFill;
  186. this->m_Position += (PCD8544_X_PIXELS - width);
  187. // Write a fill across the middle banks or two sides of the rectangle.
  188. if (bankBottom - bankTop > 1)
  189. {
  190. for (uint8_t i = bankTop + 1; i < bankBottom; i++)
  191. {
  192. if (fill)
  193. memset(this->m_Buffer + this->m_Position, 0xFF, width);
  194. else
  195. {
  196. this->m_Buffer[this->m_Position] = 0xFF;
  197. this->m_Buffer[this->m_Position+width-1] = 0xFF;
  198. }
  199. this->m_Position += PCD8544_X_PIXELS;
  200. }
  201. }
  202. // If the rectangle spans across more than one bank,
  203. // apply the same logic for the bottom as the top.
  204. if (bankBottom > bankTop)
  205. {
  206. this->m_Buffer[this->m_Position++] |= bitMaskBottomFill;
  207. for (uint8_t i = 1; i < width-1; i++)
  208. this->m_Buffer[this->m_Position++] |= bitMaskBottom;
  209. if (width > 1)
  210. this->m_Buffer[this->m_Position++] |= bitMaskBottomFill;
  211. }
  212. return PCD8544_SUCCESS;
  213. }
  214. void PCD8544_SPI_FB::writeLcd(uint8_t dataOrCommand, const uint8_t *data, uint16_t count)
  215. {
  216. PCD8544_PORT = (PCD8544_PORT & ~PINS_CE_DC) | dataOrCommand;
  217. //for (uint16_t i = 0; i < count; i++)
  218. // SPI.transfer(data[i]);
  219. for (uint16_t i = count; i > 0; i--)
  220. SPI.transfer(data[count-i]);
  221. PCD8544_PORT |= PIN_CE;
  222. }
  223. void PCD8544_SPI_FB::writeLcd(uint8_t dataOrCommand, uint8_t data)
  224. {
  225. PCD8544_PORT = (PCD8544_PORT & ~PINS_CE_DC) | dataOrCommand;
  226. SPI.transfer(data);
  227. PCD8544_PORT |= PIN_CE;
  228. }
  229. // Valid values are 0x00 - 0x7F.
  230. void PCD8544_SPI_FB::contrast(uint8_t cnt)
  231. {
  232. this->writeLcd(PCD8544_COMMAND, 0x21); //Tell LCD that extended commands follow
  233. this->writeLcd(PCD8544_COMMAND, 0X80 | cnt); //Set LCD Vop (Contrast)
  234. }
  235. // printing just one line and cut the overhang
  236. void PCD8544_SPI_FB::printOut(String string, uint8_t line, uint8_t start)
  237. {
  238. line--;
  239. if(line > 5) {
  240. this->gotoXY(start,5);
  241. } else {
  242. this->gotoXY(start,line);
  243. }
  244. String subString;
  245. if(string.length() > 14) {
  246. subString += string.substring(0, 14);
  247. this->print(subString);
  248. } else {
  249. this->print(string);
  250. }
  251. }