Distanz-/Tiefenmesser mit JSN-SR40T
Nelze vybrat více než 25 témat Téma musí začínat písmenem nebo číslem, může obsahovat pomlčky („-“) a může být dlouhé až 35 znaků.

Display.cpp 11KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369
  1. /*
  2. * Display.cpp
  3. *
  4. * Created on: 05.01.2026
  5. * Author: FSmilari
  6. */
  7. #include "Display.h"
  8. #include "Adafruit_ST7735.h"
  9. #include "images/SFToolsLogo.h"
  10. #include "fonts/titillium_web_regular16pt7b.h" // Add a custom font
  11. #include "fonts/titillium_web_regular10pt7b.h" // Add a custom font
  12. #include "fonts/titillium_web_semibold10pt7b.h" // Add a custom font
  13. #include "fonts/titillium_web_regular8pt7b.h" // Add a custom font
  14. #include "fonts/titillium_web_semibold8pt7b.h" // Add a custom font
  15. #include <Fonts/FreeSans9pt7b.h> // Add a custom font
  16. #include "images/stm32duino_logo.h"
  17. #include "images/thermometer_32.h"
  18. #include "images/gear.h"
  19. #include "images/zzz.h"
  20. #include "images/ruler.h"
  21. #include "images/air.h"
  22. #include "images/water.h"
  23. #include "images/water_s.h"
  24. //#define LED -1 // to +5v
  25. //#define SCK PA5
  26. //#define SDA PA7
  27. //#define MISO -1
  28. //#define MOSI SDA
  29. #define CS PA2
  30. #define DC PA1
  31. #define RST PA0
  32. #define ST7735_ARDUINOGREEN 0x04b3
  33. #define ST7735_STM32BLUE 0x03d6
  34. #define ST7735_DODGERBLUE 0x249f
  35. /*****************
  36. ** Constructors.
  37. ****************/
  38. Display::Display() : tft(Adafruit_ST7735(CS, DC, RST)) { // @suppress("Abstract class cannot be instantiated")
  39. starttime = 0;
  40. configUnit = "m/s";
  41. distance = 0;
  42. environment = 1;
  43. waterTemp = 20.0;
  44. airTemp = 20.0;
  45. refreshScreen = true;
  46. doMeasureAnimation = false;
  47. }
  48. void Display::init(void) {
  49. tft.initR(INITR_BLACKTAB);
  50. tft.fillScreen(ST7735_BLACK);
  51. tft.setRotation(1);
  52. tft.setTextWrap(false);
  53. tft.setTextColor(ST7735_WHITE);
  54. refreshScreen = true;
  55. }
  56. void Display::setRefreshScreen() {
  57. refreshScreen = true;
  58. }
  59. void Display::drawXCenteredText(String txt, const GFXfont *font, uint8_t size, uint16_t col, int16_t y) {
  60. int16_t x1, y1; // Top-left corner of text
  61. uint16_t w, h; // Width and height
  62. tft.setFont(font);
  63. tft.setTextSize(size); // Set text size. Goes from 0 (the smallest) to 20 (very big)
  64. tft.setTextColor(col);
  65. // Get bounds starting from (0, 0)
  66. tft.getTextBounds(txt, 0, 0, &x1, &y1, &w, &h);
  67. // Calculate centered position
  68. int16_t centered_x = (SCREEN_WIDTH - w) / 2 - 3;
  69. // Set cursor and print
  70. tft.setCursor(centered_x, y);
  71. tft.print(txt);
  72. }
  73. void Display::drawRightAlignedText(String txt, const GFXfont *font, uint8_t size, uint16_t col, int16_t xOffset, int16_t y) {
  74. int16_t x1, y1; // Top-left corner of text
  75. uint16_t w, h; // Width and height
  76. tft.setFont(font);
  77. tft.setTextSize(size); // Set text size. Goes from 0 (the smallest) to 20 (very big)
  78. tft.setTextColor(col);
  79. // Get bounds starting from (0, 0)
  80. tft.getTextBounds(txt, 0, 0, &x1, &y1, &w, &h);
  81. // Calculate position
  82. int16_t rightAligned_x = (SCREEN_WIDTH - xOffset) - w;
  83. // Set cursor and print
  84. tft.setCursor(rightAligned_x, y);
  85. tft.print(txt);
  86. }
  87. void Display::drawText(String txt, const GFXfont *font, uint8_t size, uint16_t col, int16_t x, int16_t y) {
  88. tft.setFont(font);
  89. tft.setTextSize(size); // Set text size. Goes from 0 (the smallest) to 20 (very big)
  90. tft.setTextColor(col);
  91. tft.setCursor(x, y);
  92. tft.print(txt);
  93. }
  94. void Display::drawCircle(int16_t x0, int16_t y0, int16_t r, uint16_t color) {
  95. tft.drawCircle(x0, y0, r, color);
  96. }
  97. void Display::clearDisplay(void) {
  98. tft.fillScreen(ST7735_BLACK);
  99. }
  100. void Display::showBrand(int16_t x, int16_t y) {
  101. drawBitmap(x, y, 128, 34, SFTools_Logo, ST7735_ORANGE);
  102. }
  103. void Display::showInitialization(void) {
  104. redrawFrame();
  105. drawXCenteredText("EchoLoT", &titillium_web_regular16pt7b, 1, ST7735_CYAN, 36);
  106. drawXCenteredText("designed by", &FreeSans9pt7b, 1, ST7735_WHITE, 64);
  107. showBrand(16, 84);
  108. delay(2000);
  109. redrawFrame();
  110. drawText("powered by", &FreeSans9pt7b, 1, ST7735_CYAN, 35, 30);
  111. tft.fillRoundRect(46, 42, 68, 68, 7, ST7735_STM32BLUE);
  112. drawBitmap(48, 44, 64, 64, epd_bitmap_stm32duino_logo_icon, ST7735_WHITE);
  113. delay(2000);
  114. }
  115. void Display::display(void) {
  116. if (!refreshScreen) {
  117. return;
  118. }
  119. refreshScreen = false;
  120. }
  121. void Display::showFrame(Status status) {
  122. switch (status) {
  123. case Status::INITIALIZATION:
  124. redrawFrame();
  125. break;
  126. case Status::IDLE:
  127. if (refreshScreen) {
  128. redrawIdleStatus();
  129. refreshScreen = false;
  130. }
  131. break;
  132. case Status::CONFIGURATION:
  133. if (refreshScreen) {
  134. redrawConfigStatus();
  135. refreshScreen = false;
  136. }
  137. break;
  138. default:
  139. break;
  140. }
  141. }
  142. void Display::setStatusValues(float airTemp, float waterTemp, float sonicSpeedAir, uint8_t saltPromilleWater) {
  143. this->airTemp = airTemp;
  144. this->waterTemp = waterTemp;
  145. this->sonicSpeedAir = sonicSpeedAir;
  146. this->saltPromilleWater = saltPromilleWater;
  147. }
  148. void Display::setEnvironment(int environment) {
  149. if (this->environment != environment) {
  150. this->environment = environment;
  151. redrawEnvIcon();
  152. redrawTempIcon();
  153. }
  154. }
  155. void Display::setDistance(uint32_t distance) {
  156. if (this->distance != distance) {
  157. this->distance = distance;
  158. redrawDistance();
  159. }
  160. }
  161. void Display::setConfigOption(String configOption) {
  162. if (!this->configOption.equals(configOption)) {
  163. this->configOption = configOption;
  164. redrawConfigOption();
  165. }
  166. }
  167. void Display::setConfigText(String configText) {
  168. if (!this->configValue.equals(configText)) {
  169. this->configValue = configText;
  170. redrawConfigValue();
  171. }
  172. }
  173. void Display::setConfigUnit(String configUnit) {
  174. if (!this->configUnit.equals(configUnit)) {
  175. this->configUnit = configUnit;
  176. redrawConfigUnit();
  177. }
  178. }
  179. /* ===== Private methods ===== */
  180. void Display::drawBitmap(int x, int y, int w, int h, const uint8_t bitmap[], uint16_t col) {
  181. tft.drawBitmap(x, y, bitmap, w, h, col);
  182. }
  183. void Display::drawRGBBitmap(int x, int y, int w, int h, const uint16_t bitmap[]) {
  184. tft.drawRGBBitmap(x, y, bitmap, w, h);
  185. }
  186. void Display::redrawFrame() {
  187. clearDisplay();
  188. tft.drawRoundRect(0, 0, 160, 128, 9, ST7735_CYAN);
  189. tft.drawRoundRect(1, 1, 158, 126, 8, ST7735_CYAN);
  190. }
  191. void Display::redrawGrid(bool cfg) {
  192. redrawFrame();
  193. tft.drawLine(0, 31, 160, 31, ST7735_CYAN);
  194. tft.drawLine(0, 32, 160, 32, ST7735_CYAN);
  195. tft.drawLine(0, 89, 160, 89, ST7735_CYAN);
  196. tft.drawLine(0, 90, 160, 90, ST7735_CYAN);
  197. tft.drawLine(cfg ? 120 : 80, 90, cfg ? 120 : 80, 128, ST7735_CYAN);
  198. tft.drawLine(cfg ? 121 : 81, 90, cfg ? 121 : 81, 128, ST7735_CYAN);
  199. }
  200. void Display::redrawIdleStatus() {
  201. redrawGrid();
  202. tft.drawBitmap(25, 4, epd_bitmap_Zzz_24, 24, 24, ST7735_CYAN);
  203. drawText("OPERATIV", &titillium_web_semibold8pt7b, 1, ST7735_WHITE, 55, 21);
  204. // float temp = environment == 1 ? airTemp : waterTemp;
  205. // uint16_t col = temp <= 17.0 ? ST7735_WHITE : temp <= 24.0 ? ST7735_GREEN : ST7735_ORANGE;
  206. // uint16_t thH = temp <= 17.0 ? 0 : temp <= 24.0 ? 5 : 9;
  207. // tft.drawBitmap(0, 92, thermometer_icon_32, 32, 32, col);
  208. // tft.drawRect(15, 107 - thH, 2, thH, col);
  209. // drawRightAlignedText(String(temp, 1), &titillium_web_semibold8pt7b, 1, col, 96, 114);
  210. // drawCircle(72, 104, 2, col);
  211. redrawTempIcon();
  212. redrawEnvIcon();
  213. redrawDistance();
  214. }
  215. void Display::redrawConfigStatus() {
  216. redrawGrid(true);
  217. tft.drawBitmap(35, 4, epd_bitmap_gear, 24, 24, ST7735_YELLOW);
  218. drawText("KONFIG.", &titillium_web_semibold8pt7b, 1, ST7735_YELLOW, 65, 21);
  219. redrawConfigValue();
  220. redrawConfigOption();
  221. redrawConfigUnit();
  222. }
  223. void Display::redrawEnvIcon() {
  224. const uint8_t *environmentIcon = environment == 1 ? epd_bitmap_air : environment == 2 ? epd_bitmap_water : epd_bitmap_water_s;
  225. uint16_t col = environment == 1 ? ST7735_WHITE : ST7735_DODGERBLUE;
  226. tft.fillRect(83, 92, 72, 33, ST7735_BLACK);
  227. tft.drawBitmap(108, 97, environmentIcon, 24, 24, col);
  228. }
  229. void Display::redrawTempIcon() {
  230. float temp = environment == 1 ? airTemp : waterTemp;
  231. uint16_t col = temp <= 17.0 ? ST7735_WHITE : temp <= 24.0 ? ST7735_GREEN : ST7735_ORANGE;
  232. uint16_t thH = temp <= 17.0 ? 0 : temp <= 24.0 ? 5 : 9;
  233. tft.fillRect(4, 92, 75, 30, ST7735_BLACK);
  234. tft.drawBitmap(0, 92, thermometer_icon_32, 32, 32, col);
  235. tft.drawRect(15, 107 - thH, 2, thH, col);
  236. drawRightAlignedText(String(temp, 1), &titillium_web_semibold8pt7b, 1, col, 96, 114);
  237. drawCircle(72, 104, 2, col);
  238. }
  239. void Display::runMeasureAnimation(bool run) {
  240. if (!this->doMeasureAnimation && run) {
  241. this->starttime = millis();
  242. this->doMeasureAnimation = run;
  243. } else if (this->doMeasureAnimation && !run) {
  244. this->starttime = 0;
  245. this->doMeasureAnimation = run;
  246. }
  247. tft.fillRect(24, 3, 28, 28, ST7735_BLACK);
  248. if (this->doMeasureAnimation && starttime != 0) {
  249. uint8_t lvl = ((millis() - starttime) / 1000) % 4;
  250. tft.drawBitmap(25, 4, epd_bitmap_Measure_25, 25, 25, ST7735_RED);
  251. switch (lvl) {
  252. case 0:
  253. tft.fillTriangle(25, 4, 30, 9, 25, 13, ST7735_RED);
  254. tft.fillTriangle(32, 4, 37, 9, 32, 13, ST7735_BLACK);
  255. tft.fillTriangle(39, 4, 44, 9, 39, 13, ST7735_BLACK);
  256. tft.fillTriangle(46, 4, 51, 9, 46, 13, ST7735_BLACK);
  257. break;
  258. case 1:
  259. tft.fillTriangle(25, 4, 30, 9, 25, 13, ST7735_BLACK);
  260. tft.fillTriangle(32, 4, 37, 9, 32, 13, ST7735_RED);
  261. tft.fillTriangle(39, 4, 44, 9, 39, 13, ST7735_BLACK);
  262. tft.fillTriangle(46, 4, 51, 9, 46, 13, ST7735_BLACK);
  263. break;
  264. case 2:
  265. tft.fillTriangle(25, 4, 30, 9, 25, 13, ST7735_BLACK);
  266. tft.fillTriangle(32, 4, 37, 9, 32, 13, ST7735_BLACK);
  267. tft.fillTriangle(39, 4, 44, 9, 39, 13, ST7735_RED);
  268. tft.fillTriangle(46, 4, 51, 9, 46, 13, ST7735_BLACK);
  269. break;
  270. case 3:
  271. tft.fillTriangle(25, 4, 30, 9, 25, 13, ST7735_BLACK);
  272. tft.fillTriangle(32, 4, 37, 9, 32, 13, ST7735_BLACK);
  273. tft.fillTriangle(39, 4, 44, 9, 39, 13, ST7735_BLACK);
  274. tft.fillTriangle(46, 4, 51, 9, 46, 13, ST7735_RED);
  275. break;
  276. default:
  277. break;
  278. }
  279. } else {
  280. tft.drawBitmap(25, 4, epd_bitmap_Zzz_24, 24, 24, ST7735_CYAN);
  281. }
  282. }
  283. void Display::redrawDistance() {
  284. tft.fillRect(4, 34, 152, 54, ST7735_BLACK);
  285. if (distance == 0) {
  286. drawXCenteredText("- - -", &titillium_web_regular16pt7b, 1, ST7735_WHITE, 69);
  287. } else {
  288. if (environment == 1) {
  289. uint16_t dist_CM = distance / 10;
  290. drawXCenteredText(String(dist_CM) + " cm", &titillium_web_regular16pt7b, 1, ST7735_WHITE, 69);
  291. } else {
  292. float dist_M = float(distance) / 1000;
  293. drawXCenteredText(String(dist_M, 1) + " m", &titillium_web_regular16pt7b, 1, ST7735_WHITE, 69);
  294. }
  295. }
  296. }
  297. void Display::redrawConfigValue() {
  298. tft.fillRect(4, 34, 152, 54, ST7735_BLACK);
  299. drawXCenteredText(configValue, &titillium_web_regular16pt7b, 1, ST7735_ORANGE, 69);
  300. }
  301. void Display::redrawConfigOption() {
  302. tft.fillRect(4, 92, 116, 30, ST7735_BLACK);
  303. drawText(configOption, &titillium_web_semibold8pt7b, 1, ST7735_WHITE, 6, 113);
  304. }
  305. void Display::redrawConfigUnit() {
  306. int16_t x1, y1; // Top-left corner of text
  307. uint16_t w, h; // Width and height
  308. tft.getTextBounds(configUnit, 0, 0, &x1, &y1, &w, &h);
  309. tft.fillRect(123, 92, 35, 30, ST7735_BLACK);
  310. drawRightAlignedText(configUnit, &titillium_web_semibold8pt7b, 1, ST7735_WHITE, (37 - w) / 2 + 2, 113);
  311. if (configUnit.equals(" C")) {
  312. drawCircle(121 + ((37 - w) / 2), 105, 2, ST7735_WHITE);
  313. } else if (configUnit.equals(" / ")) {
  314. drawCircle(124 + ((37 - w) / 2), 105, 2, ST7735_WHITE);
  315. drawCircle(124 + ((37 - w) / 2) + 10, 110, 2, ST7735_WHITE);
  316. drawCircle(124 + ((37 - w) / 2) + 15, 110, 2, ST7735_WHITE);
  317. }
  318. }