Distanz-/Tiefenmesser mit JSN-SR40T
Ви не можете вибрати більше 25 тем Теми мають розпочинатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370
  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(String version) {
  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, 20);
  111. tft.fillRoundRect(46, 32, 68, 68, 7, ST7735_STM32BLUE);
  112. drawBitmap(48, 34, 64, 64, epd_bitmap_stm32duino_logo_icon, ST7735_WHITE);
  113. drawXCenteredText("Ver: " + version, &titillium_web_regular8pt7b, 1, ST7735_CYAN, 118);
  114. delay(5000);
  115. }
  116. void Display::display(void) {
  117. if (!refreshScreen) {
  118. return;
  119. }
  120. refreshScreen = false;
  121. }
  122. void Display::showFrame(Status status) {
  123. switch (status) {
  124. case Status::INITIALIZATION:
  125. redrawFrame();
  126. break;
  127. case Status::IDLE:
  128. if (refreshScreen) {
  129. redrawIdleStatus();
  130. refreshScreen = false;
  131. }
  132. break;
  133. case Status::CONFIGURATION:
  134. if (refreshScreen) {
  135. redrawConfigStatus();
  136. refreshScreen = false;
  137. }
  138. break;
  139. default:
  140. break;
  141. }
  142. }
  143. void Display::setStatusValues(float airTemp, float waterTemp, float sonicSpeedAir, uint8_t saltPromilleWater) {
  144. this->airTemp = airTemp;
  145. this->waterTemp = waterTemp;
  146. this->sonicSpeedAir = sonicSpeedAir;
  147. this->saltPromilleWater = saltPromilleWater;
  148. }
  149. void Display::setEnvironment(int environment) {
  150. if (this->environment != environment) {
  151. this->environment = environment;
  152. redrawEnvIcon();
  153. redrawTempIcon();
  154. }
  155. }
  156. void Display::setDistance(uint32_t distance) {
  157. if (this->distance != distance) {
  158. this->distance = distance;
  159. redrawDistance();
  160. }
  161. }
  162. void Display::setConfigOption(String configOption) {
  163. if (!this->configOption.equals(configOption)) {
  164. this->configOption = configOption;
  165. redrawConfigOption();
  166. }
  167. }
  168. void Display::setConfigText(String configText) {
  169. if (!this->configValue.equals(configText)) {
  170. this->configValue = configText;
  171. redrawConfigValue();
  172. }
  173. }
  174. void Display::setConfigUnit(String configUnit) {
  175. if (!this->configUnit.equals(configUnit)) {
  176. this->configUnit = configUnit;
  177. redrawConfigUnit();
  178. }
  179. }
  180. /* ===== Private methods ===== */
  181. void Display::drawBitmap(int x, int y, int w, int h, const uint8_t bitmap[], uint16_t col) {
  182. tft.drawBitmap(x, y, bitmap, w, h, col);
  183. }
  184. void Display::drawRGBBitmap(int x, int y, int w, int h, const uint16_t bitmap[]) {
  185. tft.drawRGBBitmap(x, y, bitmap, w, h);
  186. }
  187. void Display::redrawFrame() {
  188. clearDisplay();
  189. tft.drawRoundRect(0, 0, 160, 128, 9, ST7735_CYAN);
  190. tft.drawRoundRect(1, 1, 158, 126, 8, ST7735_CYAN);
  191. }
  192. void Display::redrawGrid(bool cfg) {
  193. redrawFrame();
  194. tft.drawLine(0, 31, 160, 31, ST7735_CYAN);
  195. tft.drawLine(0, 32, 160, 32, ST7735_CYAN);
  196. tft.drawLine(0, 89, 160, 89, ST7735_CYAN);
  197. tft.drawLine(0, 90, 160, 90, ST7735_CYAN);
  198. tft.drawLine(cfg ? 120 : 80, 90, cfg ? 120 : 80, 128, ST7735_CYAN);
  199. tft.drawLine(cfg ? 121 : 81, 90, cfg ? 121 : 81, 128, ST7735_CYAN);
  200. }
  201. void Display::redrawIdleStatus() {
  202. redrawGrid();
  203. tft.drawBitmap(25, 4, epd_bitmap_Zzz_24, 24, 24, ST7735_CYAN);
  204. drawText("OPERATIV", &titillium_web_semibold8pt7b, 1, ST7735_WHITE, 55, 21);
  205. // float temp = environment == 1 ? airTemp : waterTemp;
  206. // uint16_t col = temp <= 17.0 ? ST7735_WHITE : temp <= 24.0 ? ST7735_GREEN : ST7735_ORANGE;
  207. // uint16_t thH = temp <= 17.0 ? 0 : temp <= 24.0 ? 5 : 9;
  208. // tft.drawBitmap(0, 92, thermometer_icon_32, 32, 32, col);
  209. // tft.drawRect(15, 107 - thH, 2, thH, col);
  210. // drawRightAlignedText(String(temp, 1), &titillium_web_semibold8pt7b, 1, col, 96, 114);
  211. // drawCircle(72, 104, 2, col);
  212. redrawTempIcon();
  213. redrawEnvIcon();
  214. redrawDistance();
  215. }
  216. void Display::redrawConfigStatus() {
  217. redrawGrid(true);
  218. tft.drawBitmap(35, 4, epd_bitmap_gear, 24, 24, ST7735_YELLOW);
  219. drawText("KONFIG.", &titillium_web_semibold8pt7b, 1, ST7735_YELLOW, 65, 21);
  220. redrawConfigValue();
  221. redrawConfigOption();
  222. redrawConfigUnit();
  223. }
  224. void Display::redrawEnvIcon() {
  225. const uint8_t *environmentIcon = environment == 1 ? epd_bitmap_air : environment == 2 ? epd_bitmap_water : epd_bitmap_water_s;
  226. uint16_t col = environment == 1 ? ST7735_WHITE : ST7735_DODGERBLUE;
  227. tft.fillRect(83, 92, 72, 33, ST7735_BLACK);
  228. tft.drawBitmap(108, 97, environmentIcon, 24, 24, col);
  229. }
  230. void Display::redrawTempIcon() {
  231. float temp = environment == 1 ? airTemp : waterTemp;
  232. uint16_t col = temp <= 17.0 ? ST7735_WHITE : temp <= 24.0 ? ST7735_GREEN : ST7735_ORANGE;
  233. uint16_t thH = temp <= 17.0 ? 0 : temp <= 24.0 ? 5 : 9;
  234. tft.fillRect(4, 92, 75, 30, ST7735_BLACK);
  235. tft.drawBitmap(0, 92, thermometer_icon_32, 32, 32, col);
  236. tft.drawRect(15, 107 - thH, 2, thH, col);
  237. drawRightAlignedText(String(temp, 1), &titillium_web_semibold8pt7b, 1, col, 96, 114);
  238. drawCircle(72, 104, 2, col);
  239. }
  240. void Display::runMeasureAnimation(bool run) {
  241. if (!this->doMeasureAnimation && run) {
  242. this->starttime = millis();
  243. this->doMeasureAnimation = run;
  244. } else if (this->doMeasureAnimation && !run) {
  245. this->starttime = 0;
  246. this->doMeasureAnimation = run;
  247. }
  248. tft.fillRect(24, 3, 28, 28, ST7735_BLACK);
  249. if (this->doMeasureAnimation && starttime != 0) {
  250. uint8_t lvl = ((millis() - starttime) / 1000) % 4;
  251. tft.drawBitmap(25, 4, epd_bitmap_Measure_25, 25, 25, ST7735_RED);
  252. switch (lvl) {
  253. case 0:
  254. tft.fillTriangle(25, 4, 30, 9, 25, 13, ST7735_RED);
  255. tft.fillTriangle(32, 4, 37, 9, 32, 13, ST7735_BLACK);
  256. tft.fillTriangle(39, 4, 44, 9, 39, 13, ST7735_BLACK);
  257. tft.fillTriangle(46, 4, 51, 9, 46, 13, ST7735_BLACK);
  258. break;
  259. case 1:
  260. tft.fillTriangle(25, 4, 30, 9, 25, 13, ST7735_BLACK);
  261. tft.fillTriangle(32, 4, 37, 9, 32, 13, ST7735_RED);
  262. tft.fillTriangle(39, 4, 44, 9, 39, 13, ST7735_BLACK);
  263. tft.fillTriangle(46, 4, 51, 9, 46, 13, ST7735_BLACK);
  264. break;
  265. case 2:
  266. tft.fillTriangle(25, 4, 30, 9, 25, 13, ST7735_BLACK);
  267. tft.fillTriangle(32, 4, 37, 9, 32, 13, ST7735_BLACK);
  268. tft.fillTriangle(39, 4, 44, 9, 39, 13, ST7735_RED);
  269. tft.fillTriangle(46, 4, 51, 9, 46, 13, ST7735_BLACK);
  270. break;
  271. case 3:
  272. tft.fillTriangle(25, 4, 30, 9, 25, 13, ST7735_BLACK);
  273. tft.fillTriangle(32, 4, 37, 9, 32, 13, ST7735_BLACK);
  274. tft.fillTriangle(39, 4, 44, 9, 39, 13, ST7735_BLACK);
  275. tft.fillTriangle(46, 4, 51, 9, 46, 13, ST7735_RED);
  276. break;
  277. default:
  278. break;
  279. }
  280. } else {
  281. tft.drawBitmap(25, 4, epd_bitmap_Zzz_24, 24, 24, ST7735_CYAN);
  282. }
  283. }
  284. void Display::redrawDistance() {
  285. tft.fillRect(4, 34, 152, 54, ST7735_BLACK);
  286. if (distance == 0) {
  287. drawXCenteredText("- - -", &titillium_web_regular16pt7b, 1, ST7735_WHITE, 69);
  288. } else {
  289. if (environment == 1) {
  290. uint16_t dist_CM = distance / 10;
  291. drawXCenteredText(String(dist_CM) + " cm", &titillium_web_regular16pt7b, 1, ST7735_WHITE, 69);
  292. } else {
  293. float dist_M = float(distance) / 1000;
  294. drawXCenteredText(String(dist_M, 1) + " m", &titillium_web_regular16pt7b, 1, ST7735_WHITE, 69);
  295. }
  296. }
  297. }
  298. void Display::redrawConfigValue() {
  299. tft.fillRect(4, 34, 152, 54, ST7735_BLACK);
  300. drawXCenteredText(configValue, &titillium_web_regular16pt7b, 1, ST7735_ORANGE, 69);
  301. }
  302. void Display::redrawConfigOption() {
  303. tft.fillRect(4, 92, 116, 30, ST7735_BLACK);
  304. drawText(configOption, &titillium_web_semibold8pt7b, 1, ST7735_WHITE, 6, 113);
  305. }
  306. void Display::redrawConfigUnit() {
  307. int16_t x1, y1; // Top-left corner of text
  308. uint16_t w, h; // Width and height
  309. tft.getTextBounds(configUnit, 0, 0, &x1, &y1, &w, &h);
  310. tft.fillRect(123, 92, 35, 30, ST7735_BLACK);
  311. drawRightAlignedText(configUnit, &titillium_web_semibold8pt7b, 1, ST7735_WHITE, (37 - w) / 2 + 2, 113);
  312. if (configUnit.equals(" C")) {
  313. drawCircle(121 + ((37 - w) / 2), 105, 2, ST7735_WHITE);
  314. } else if (configUnit.equals(" / ")) {
  315. drawCircle(124 + ((37 - w) / 2), 105, 2, ST7735_WHITE);
  316. drawCircle(124 + ((37 - w) / 2) + 10, 110, 2, ST7735_WHITE);
  317. drawCircle(124 + ((37 - w) / 2) + 15, 110, 2, ST7735_WHITE);
  318. }
  319. }