pleasedontcode

# Thermal Desoldering rev_01

Feb 27th, 2026
44
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Arduino 19.13 KB | None | 0 0
  1. /********* Pleasedontcode.com **********
  2.  
  3.     Pleasedontcode thanks you for automatic code generation! Enjoy your code!
  4.  
  5.     - Terms and Conditions:
  6.     You have a non-exclusive, revocable, worldwide, royalty-free license
  7.     for personal and commercial use. Attribution is optional; modifications
  8.     are allowed, but you're responsible for code maintenance. We're not
  9.     liable for any loss or damage. For full terms,
  10.     please visit pleasedontcode.com/termsandconditions.
  11.  
  12.     - Project: # Thermal Desoldering
  13.     - Source Code NOT compiled for: Arduino Pro Mini 5V
  14.     - Source Code created on: 2026-02-27 12:39:41
  15.  
  16. ********* Pleasedontcode.com **********/
  17.  
  18. /****** SYSTEM REQUIREMENTS *****/
  19. /****** SYSTEM REQUIREMENT 1 *****/
  20.     /* Remova o debug serial a fim de reduzir memoria. */
  21. /****** END SYSTEM REQUIREMENTS *****/
  22.  
  23.  
  24. /* START CODE */
  25.  
  26. /*
  27.   ============================================
  28.   SOPRADOR TÉRMICO PARA DESSOLDAGEM v4.1 AC
  29.   ============================================
  30.   ✅ REFATORADO - SEM CONFLITOS DE PINOS
  31.   ✅ PIN D5 EXCLUSIVO PARA MAX6675 (CHIP SELECT)
  32.   ✅ PIN D12 PARA PUMP_GATE (PWM)
  33.   ✅ PROTEÇÃO: BOMBA SOLENOIDE COM LIMITE DE 40% MÍNIMO
  34.   ✅ SERIAL DEBUG REMOVIDO - OTIMIZADO PARA MEMORIA
  35.  
  36.   ⚡ SISTEMA AC COMPLETO:
  37.   - MOC3023 + BT136 (Triacs)
  38.   - Detecção zero-crossing
  39.   - Controle de resistência AC
  40.   - Controle de bomba solenoide AC
  41.   - Termopar MAX6675 Tipo K
  42.   - Display ST7735S 1.8"
  43.   - EEPROM para salvar setpoint
  44.   ============================================
  45. */
  46.  
  47. /****** DEFINITION OF LIBRARIES *****/
  48. #include <Adafruit_GFX.h>   //https://github.com/adafruit/Adafruit-GFX-Library
  49. #include <Adafruit_ST7735.h>
  50. #include <SPI.h>
  51. #include <max6675.h>
  52. #include <EEPROM.h>
  53.  
  54. // ======================================
  55. // CONFIGURAÇÃO DE PINOS (CORRIGIDO)
  56. // ======================================
  57.  
  58. // Display ST7735S (SPI)
  59. #define TFT_CS    10
  60. #define TFT_RST   9
  61. #define TFT_DC    8
  62.  
  63. // Termopar MAX6675 (SPI)
  64. #define THERMO_SCK  6   // Clock SPI
  65. #define THERMO_CS   5   // ✅ Chip Select (EXCLUSIVO)
  66. #define THERMO_SO   4   // MISO
  67.  
  68. // Potenciômetros analógicos
  69. #define POT_TEMP    A0
  70. #define POT_FAN     A1
  71.  
  72. // Botão
  73. #define POWER_BTN   7
  74.  
  75. // ⚡ PINOS AC - MOC3023 + BT136 (REMAPEADOS CORRETAMENTE)
  76. #define ZERO_CROSS_PIN  2   // INT0 - Detecção zero-crossing
  77. #define MOC_LED_PIN    11   // PWM - LED do MOC3023 (Resistência)
  78. #define HEATER_GATE    3    // PWM - Gate do BT136 (Resistência AC)
  79. #define PUMP_GATE      12   // ✅ NOVO PIN 12 - Gate do BT136 (Bomba AC)
  80.  
  81. // ======================================
  82. // CONSTANTES DO SISTEMA
  83. // ======================================
  84.  
  85. #define SAFE_TEMP           50
  86. #define AMBIENT_TEMP        25
  87. #define TEMP_MIN           100
  88. #define TEMP_MAX           500
  89. #define MAX_TEMP_ABSOLUTE  450
  90. #define MAX_HEATING_TIME   600000  // 10 minutos
  91.  
  92. // ⚠️ PROTEÇÃO BOMBA SOLENOIDE
  93. #define PUMP_MIN_POWER     40   // Mínimo 40% para não travar
  94. #define PUMP_MAX_POWER    100   // Máximo 100%
  95.  
  96. // PID Constants
  97. #define KP  6.0
  98. #define KI  0.15
  99. #define KD  1.5
  100.  
  101. // ✨ CORES DO DISPLAY (RGB565)
  102. #define COLOR_BG        0x0000  // Preto
  103. #define COLOR_TEXT      0xFFFF  // Branco
  104. #define COLOR_WHITE     0xFFFF  // Branco
  105. #define COLOR_CYAN      0x07FF  // Ciano
  106. #define COLOR_ORANGE    0xFE60  // Laranja
  107. #define COLOR_GREEN     0x0FE0  // Verde
  108. #define COLOR_RED       0xF800  // Vermelho
  109. #define COLOR_YELLOW    0xFFE0  // Amarelo
  110.  
  111. #define EEPROM_SETPOINT 0
  112.  
  113. // ======================================
  114. // INSTÂNCIAS
  115. // ======================================
  116.  
  117. Adafruit_ST7735 tft = Adafruit_ST7735(TFT_CS, TFT_DC, TFT_RST);
  118. MAX6675 thermocouple(THERMO_SCK, THERMO_CS, THERMO_SO);
  119.  
  120. // ======================================
  121. // VARIÁVEIS AC
  122. // ======================================
  123.  
  124. volatile unsigned long lastZeroCrossing = 0;
  125. volatile bool zeroCrossingDetected = false;
  126.  
  127. int heaterPowerLevel = 0;  // 0-255 (nível de potência da resistência)
  128. int pumpPowerLevel = 0;    // 0-255 (nível de potência da bomba)
  129.  
  130. bool systemOn = false;
  131. bool heatingMode = false;
  132. bool coolingDown = false;
  133. bool tempReached = false;
  134.  
  135. // ======================================
  136. // VARIÁVEIS DE TEMPERATURA E SETPOINT
  137. // ======================================
  138.  
  139. float currentTemp = AMBIENT_TEMP;
  140. float lastValidTemp = AMBIENT_TEMP;
  141. int setpointTemp = 350;
  142. int fanSpeed = 50;
  143.  
  144. // ======================================
  145. // CONTROLE PID
  146. // ======================================
  147.  
  148. float pidIntegral = 0;
  149. float pidLastError = 0;
  150.  
  151. // ======================================
  152. // TIMING
  153. // ======================================
  154.  
  155. unsigned long lastUpdate = 0;
  156. unsigned long lastPidTime = 0;
  157. unsigned long lastButtonCheck = 0;
  158. unsigned long lastThermoRead = 0;
  159. unsigned long heatingStartTime = 0;
  160.  
  161. // ======================================
  162. // CACHE DO DISPLAY (anti-flickering)
  163. // ======================================
  164.  
  165. struct DisplayCache {
  166.   int lastTemp;
  167.   int lastSetpoint;
  168.   int lastFanSpeed;
  169.   int lastHeaterPower;
  170.   int lastPumpPower;
  171.   bool lastCoolingDown;
  172.   uint16_t lastTempColor;
  173.   int lastStatus;
  174.   int lastTime;
  175. } cache;
  176.  
  177. /****** FUNCTION PROTOTYPES *****/
  178. void setup(void);
  179. void loop(void);
  180. void zeroCrossingInterrupt(void);
  181. void checkPowerButton(unsigned long currentMillis);
  182. void readPotentiometers(void);
  183. void controlSystemAC(unsigned long currentMillis);
  184. void checkSafetyLimits(unsigned long currentMillis);
  185. int calculatePID(float setpoint, float current);
  186. void togglePower(void);
  187. void loadSettingsFromEEPROM(void);
  188. void saveSettingsToEEPROM(void);
  189. void drawBootScreen(void);
  190. void drawInterface(void);
  191. void updateDisplay(unsigned long currentMillis);
  192. void drawStatus(void);
  193. uint16_t getTempColor(float temp);
  194. void drawProgressBar(uint16_t color);
  195. void drawReachedIndicator(void);
  196.  
  197. /****** DEFINITION OF LIBRARIES CLASS INSTANCES*****/
  198.  
  199. // ======================================
  200. // SETUP - INICIALIZAÇÃO
  201. // ======================================
  202.  
  203. void setup() {
  204.   // Configurar pinos DIGITAIS
  205.   pinMode(ZERO_CROSS_PIN, INPUT);
  206.   pinMode(MOC_LED_PIN, OUTPUT);
  207.   pinMode(HEATER_GATE, OUTPUT);
  208.   pinMode(PUMP_GATE, OUTPUT);      // ✅ PIN 12 como saída
  209.   pinMode(POWER_BTN, INPUT_PULLUP);
  210.   pinMode(POT_TEMP, INPUT);
  211.   pinMode(POT_FAN, INPUT);
  212.  
  213.   // Inicializar saídas em LOW (TRIACs desligados)
  214.   digitalWrite(HEATER_GATE, LOW);
  215.   digitalWrite(PUMP_GATE, LOW);    // ✅ Inicializar PIN 12
  216.   analogWrite(MOC_LED_PIN, 0);
  217.   analogWrite(PUMP_GATE, 0);       // ✅ PWM inicial = 0
  218.  
  219.   // Inicializar display
  220.   tft.initR(INITR_BLACKTAB);
  221.   tft.setRotation(1);
  222.   tft.fillScreen(COLOR_BG);
  223.  
  224.   drawBootScreen();
  225.   delay(2000);
  226.  
  227.   // Carregar setpoint da EEPROM
  228.   loadSettingsFromEEPROM();
  229.  
  230.   // Ler temperatura inicial
  231.   currentTemp = thermocouple.readCelsius();
  232.   if (!isnan(currentTemp)) {
  233.     lastValidTemp = currentTemp;
  234.   } else {
  235.     currentTemp = AMBIENT_TEMP;
  236.   }
  237.  
  238.   // ⚡ CONFIGURAR INTERRUPÇÃO ZERO-CROSSING
  239.   attachInterrupt(digitalPinToInterrupt(ZERO_CROSS_PIN), zeroCrossingInterrupt, RISING);
  240.  
  241.   drawInterface();
  242.   lastThermoRead = millis();
  243. }
  244.  
  245. // ======================================
  246. // LOOP PRINCIPAL
  247. // ======================================
  248.  
  249. void loop() {
  250.   unsigned long currentMillis = millis();
  251.  
  252.   checkPowerButton(currentMillis);
  253.   readPotentiometers();
  254.  
  255.   // Ler termopar
  256.   if (currentMillis - lastThermoRead >= 500) {
  257.     float temp = thermocouple.readCelsius();
  258.    
  259.     if (!isnan(temp) && temp > -10 && temp < 600) {
  260.       currentTemp = temp;
  261.       lastValidTemp = temp;
  262.     }
  263.    
  264.     lastThermoRead = currentMillis;
  265.   }
  266.  
  267.   controlSystemAC(currentMillis);
  268.   checkSafetyLimits(currentMillis);
  269.  
  270.   // Atualizar display com controle de flickering
  271.   if (currentMillis - lastUpdate >= 200) {
  272.     updateDisplay(currentMillis);
  273.     lastUpdate = currentMillis;
  274.   }
  275. }
  276.  
  277. // ======================================
  278. // ⚡ INTERRUPÇÃO ZERO-CROSSING
  279. // ======================================
  280.  
  281. void zeroCrossingInterrupt() {
  282.   lastZeroCrossing = micros();
  283.   zeroCrossingDetected = true;
  284.  
  285.   // ⚡ DISPARO DOS TRIACs COM DELAY PARA CONTROLE DE POTÊNCIA
  286.  
  287.   // Resistência (PIN 3)
  288.   if (heaterPowerLevel > 0) {
  289.     delayMicroseconds(map(255 - heaterPowerLevel, 0, 255, 0, 8000));
  290.     digitalWrite(HEATER_GATE, HIGH);
  291.     delayMicroseconds(10);
  292.     digitalWrite(HEATER_GATE, LOW);
  293.   }
  294.  
  295.   // Bomba (PIN 12) ✅ AGORA COM PINO DEDICADO
  296.   if (pumpPowerLevel > 0) {
  297.     delayMicroseconds(map(255 - pumpPowerLevel, 0, 255, 0, 8000));
  298.     digitalWrite(PUMP_GATE, HIGH);
  299.     delayMicroseconds(10);
  300.     digitalWrite(PUMP_GATE, LOW);
  301.   }
  302. }
  303.  
  304. // ======================================
  305. // VERIFICAR BOTÃO DE POTÊNCIA
  306. // ======================================
  307.  
  308. void checkPowerButton(unsigned long currentMillis) {
  309.   static bool buttonPressed = false;
  310.  
  311.   if (currentMillis - lastButtonCheck < 200) {
  312.     return;
  313.   }
  314.  
  315.   bool buttonState = digitalRead(POWER_BTN);
  316.  
  317.   if (buttonState == LOW && !buttonPressed) {
  318.     buttonPressed = true;
  319.     togglePower();
  320.   }
  321.   else if (buttonState == HIGH && buttonPressed) {
  322.     buttonPressed = false;
  323.   }
  324.  
  325.   lastButtonCheck = currentMillis;
  326. }
  327.  
  328. // ======================================
  329. // ⚠️ LEITURA DE POTENCIÔMETROS
  330. // ======================================
  331.  
  332. void readPotentiometers() {
  333.   // Temperatura
  334.   int tempRaw = analogRead(POT_TEMP);
  335.   int newSetpoint = map(tempRaw, 0, 1023, TEMP_MIN, TEMP_MAX);
  336.  
  337.   if (abs(newSetpoint - setpointTemp) > 5) {
  338.     setpointTemp = newSetpoint;
  339.     saveSettingsToEEPROM();
  340.     tempReached = false;
  341.   }
  342.  
  343.   // Ventoinha (Bomba)
  344.   int fanRaw = analogRead(POT_FAN);
  345.   int rawFanSpeed = map(fanRaw, 0, 1023, 0, 100);
  346.  
  347.   // ⚠️ PROTEÇÃO: Bomba solenoide não pode oscilar abaixo de 40%
  348.   // Se ficar abaixo, desliga completamente (0%) para não travar
  349.   if (rawFanSpeed > 0 && rawFanSpeed < PUMP_MIN_POWER) {
  350.     fanSpeed = 0;  // Desliga bomba
  351.   } else {
  352.     fanSpeed = rawFanSpeed;
  353.   }
  354. }
  355.  
  356. // ======================================
  357. // ⚡ CONTROLE DO SISTEMA AC
  358. // ======================================
  359.  
  360. void controlSystemAC(unsigned long currentMillis) {
  361.   if (systemOn && heatingMode) {
  362.     // Verificar tempo máximo de aquecimento
  363.     if (currentMillis - heatingStartTime > MAX_HEATING_TIME) {
  364.       togglePower();
  365.       return;
  366.     }
  367.    
  368.     // ⚡ PID para resistência AC
  369.     if (currentMillis - lastPidTime >= 100) {
  370.       heaterPowerLevel = calculatePID(setpointTemp, currentTemp);
  371.       analogWrite(MOC_LED_PIN, map(heaterPowerLevel, 0, 255, 0, 200));
  372.       lastPidTime = currentMillis;
  373.     }
  374.    
  375.     // Verificar se chegou no setpoint
  376.     if (abs(currentTemp - setpointTemp) < 3) {
  377.       if (!tempReached) {
  378.         tempReached = true;
  379.       }
  380.     }
  381.    
  382.     // ⚡ Controlar bomba AC (velocidade via potência) com proteção
  383.     if (fanSpeed == 0) {
  384.       pumpPowerLevel = 0;
  385.     } else if (fanSpeed < PUMP_MIN_POWER) {
  386.       pumpPowerLevel = 0;  // Proteção: desliga se < 40%
  387.     } else {
  388.       pumpPowerLevel = map(fanSpeed, 0, 100, 0, 255);
  389.     }
  390.    
  391.   } else if (coolingDown) {
  392.     heaterPowerLevel = 0;
  393.     analogWrite(MOC_LED_PIN, 0);
  394.    
  395.     if (currentTemp > SAFE_TEMP) {
  396.       // ⚡ Bomba em máxima potência para resfriar
  397.       pumpPowerLevel = 255;
  398.     } else {
  399.       pumpPowerLevel = 0;
  400.       coolingDown = false;
  401.       tempReached = false;
  402.     }
  403.   } else {
  404.     heaterPowerLevel = 0;
  405.     pumpPowerLevel = 0;
  406.     analogWrite(MOC_LED_PIN, 0);
  407.   }
  408. }
  409.  
  410. // ======================================
  411. // ⚠️ VERIFICAR LIMITES DE SEGURANÇA
  412. // ======================================
  413.  
  414. void checkSafetyLimits(unsigned long currentMillis) {
  415.   if (currentTemp > MAX_TEMP_ABSOLUTE) {
  416.     systemOn = false;
  417.     heatingMode = false;
  418.     coolingDown = true;
  419.     heaterPowerLevel = 0;
  420.     analogWrite(MOC_LED_PIN, 0);
  421.     pumpPowerLevel = 255;  // Máximo resfriamento
  422.     pidIntegral = 0;
  423.     pidLastError = 0;
  424.   }
  425. }
  426.  
  427. // ======================================
  428. // ⚡ CALCULA PID (RESISTÊNCIA AC)
  429. // ======================================
  430.  
  431. int calculatePID(float setpoint, float current) {
  432.   float error = setpoint - current;
  433.   float deltaTime = 0.1;
  434.  
  435.   // Proporcional
  436.   float P = KP * error;
  437.  
  438.   // Integral
  439.   pidIntegral += error * deltaTime;
  440.   pidIntegral = constrain(pidIntegral, 0, 255);
  441.   float I = KI * pidIntegral;
  442.  
  443.   // Derivativo
  444.   float derivative = (error - pidLastError) / deltaTime;
  445.   float D = KD * derivative;
  446.   pidLastError = error;
  447.  
  448.   // Output
  449.   float output = P + I + D;
  450.   output = constrain(output, 0, 255);
  451.  
  452.   // Anti-overshoot quando perto do setpoint
  453.   if (abs(error) < 10 && current > setpoint) {
  454.     output *= 0.5;
  455.   }
  456.  
  457.   return (int)output;
  458. }
  459.  
  460. // ======================================
  461. // LIGAR/DESLIGAR SISTEMA
  462. // ======================================
  463.  
  464. void togglePower() {
  465.   systemOn = !systemOn;
  466.   pidIntegral = 0;
  467.   pidLastError = 0;
  468.   tempReached = false;
  469.  
  470.   if (systemOn) {
  471.     heatingMode = true;
  472.     coolingDown = false;
  473.     heatingStartTime = millis();
  474.   } else {
  475.     heatingMode = false;
  476.     coolingDown = true;
  477.   }
  478.  
  479.   drawInterface();
  480. }
  481.  
  482. // ======================================
  483. // EEPROM - SALVAR/CARREGAR SETPOINT
  484. // ======================================
  485.  
  486. void loadSettingsFromEEPROM() {
  487.   int savedSetpoint = EEPROM.read(EEPROM_SETPOINT) * 256 + EEPROM.read(EEPROM_SETPOINT + 1);
  488.  
  489.   if (savedSetpoint >= TEMP_MIN && savedSetpoint <= TEMP_MAX) {
  490.     setpointTemp = savedSetpoint;
  491.   }
  492. }
  493.  
  494. void saveSettingsToEEPROM() {
  495.   EEPROM.write(EEPROM_SETPOINT, setpointTemp / 256);
  496.   EEPROM.write(EEPROM_SETPOINT + 1, setpointTemp % 256);
  497. }
  498.  
  499. // ======================================
  500. // DESENHAR TELA DE BOOT
  501. // ======================================
  502.  
  503. void drawBootScreen() {
  504.   tft.fillScreen(COLOR_BG);
  505.  
  506.   tft.setTextSize(2);
  507.   tft.setTextColor(COLOR_CYAN);
  508.   tft.setCursor(10, 30);
  509.   tft.println("SOPRADOR");
  510.   tft.setCursor(20, 50);
  511.   tft.println("TERMICO");
  512.  
  513.   tft.setTextSize(1);
  514.   tft.setTextColor(COLOR_WHITE);
  515.   tft.setCursor(15, 80);
  516.   tft.println("v4.1 AC MOC3023");
  517.   tft.setCursor(5, 95);
  518.   tft.println("PIN D12 PUMP_GATE");
  519.  
  520.   tft.drawRect(20, 110, 120, 8, COLOR_CYAN);
  521.   for (int i = 0; i < 120; i += 3) {
  522.     tft.fillRect(20, 110, i, 8, COLOR_CYAN);
  523.     delay(10);
  524.   }
  525. }
  526.  
  527. // ======================================
  528. // DESENHAR INTERFACE PRINCIPAL
  529. // ======================================
  530.  
  531. void drawInterface() {
  532.   tft.fillScreen(COLOR_BG);
  533.  
  534.   // Cabeçalho
  535.   tft.fillRect(0, 0, 160, 15, COLOR_CYAN);
  536.   tft.setTextSize(1);
  537.   tft.setTextColor(COLOR_BG);
  538.   tft.setCursor(10, 4);
  539.   tft.println("TERMOPAR K v4.1 AC");
  540.  
  541.   // Labels
  542.   tft.setTextColor(COLOR_WHITE);
  543.   tft.setTextSize(1);
  544.  
  545.   tft.setCursor(5, 25);
  546.   tft.println("TEMPERATURA:");
  547.  
  548.   tft.setCursor(5, 65);
  549.   tft.println("SETPOINT:");
  550.  
  551.   tft.setCursor(5, 85);
  552.   tft.println("BOMBA AC (40% min):");
  553.  
  554.   tft.setCursor(5, 105);
  555.   tft.print("Time: --:--");
  556.  
  557.   // Inicializar cache
  558.   cache.lastTemp = -999;
  559.   cache.lastSetpoint = -999;
  560.   cache.lastFanSpeed = -999;
  561.   cache.lastHeaterPower = -999;
  562.   cache.lastPumpPower = -999;
  563.   cache.lastCoolingDown = false;
  564.   cache.lastTempColor = COLOR_CYAN;
  565.   cache.lastStatus = -1;
  566.   cache.lastTime = -1;
  567. }
  568.  
  569. // ======================================
  570. // ATUALIZAR DISPLAY (COM ANTI-FLICKERING)
  571. // ======================================
  572.  
  573. void updateDisplay(unsigned long currentMillis) {
  574.   drawStatus();
  575.  
  576.   // Temperatura
  577.   int displayTemp = (int)currentTemp;
  578.   uint16_t tempColor = getTempColor(currentTemp);
  579.  
  580.   if (displayTemp != cache.lastTemp || tempColor != cache.lastTempColor) {
  581.     tft.fillRect(5, 38, 150, 20, COLOR_BG);
  582.     tft.setTextSize(3);
  583.     tft.setTextColor(tempColor);
  584.     tft.setCursor(10, 38);
  585.     tft.print(displayTemp);
  586.     tft.print("C");
  587.    
  588.     cache.lastTemp = displayTemp;
  589.     cache.lastTempColor = tempColor;
  590.   }
  591.  
  592.   // Setpoint
  593.   if (setpointTemp != cache.lastSetpoint) {
  594.     tft.fillRect(75, 65, 80, 15, COLOR_BG);
  595.     tft.setTextSize(2);
  596.     tft.setTextColor(COLOR_ORANGE);
  597.     tft.setCursor(80, 65);
  598.     tft.print(setpointTemp);
  599.     tft.print("C");
  600.    
  601.     cache.lastSetpoint = setpointTemp;
  602.   }
  603.  
  604.   // ⚡ BOMBA AC com proteção 40%
  605.   if (fanSpeed != cache.lastFanSpeed || coolingDown != cache.lastCoolingDown) {
  606.     tft.fillRect(5, 97, 150, 15, COLOR_BG);
  607.     tft.setTextSize(2);
  608.    
  609.     if (coolingDown && currentTemp > SAFE_TEMP) {
  610.       tft.setTextColor(COLOR_RED);
  611.       tft.setCursor(10, 97);
  612.       tft.print("MAX COOLING");
  613.     } else if (fanSpeed == 0) {
  614.       // ⚠️ Mostrar quando bomba está desligada por proteção
  615.       tft.setTextColor(COLOR_RED);
  616.       tft.setCursor(10, 97);
  617.       tft.print("OFF (< 40%)");
  618.     } else if (fanSpeed < PUMP_MIN_POWER) {
  619.       tft.setTextColor(COLOR_RED);
  620.       tft.setCursor(10, 97);
  621.       tft.print("PROT!");
  622.     } else {
  623.       tft.setTextColor(COLOR_GREEN);
  624.       tft.setCursor(10, 97);
  625.       tft.print(fanSpeed);
  626.       tft.print("% OK");
  627.     }
  628.    
  629.     cache.lastFanSpeed = fanSpeed;
  630.     cache.lastCoolingDown = coolingDown;
  631.   }
  632.  
  633.   // Timer
  634.   if (systemOn && heatingMode) {
  635.     int elapsedSeconds = (currentMillis - heatingStartTime) / 1000;
  636.     int minutes = elapsedSeconds / 60;
  637.     int seconds = elapsedSeconds % 60;
  638.    
  639.     if (elapsedSeconds != cache.lastTime) {
  640.       tft.fillRect(50, 105, 50, 10, COLOR_BG);
  641.       tft.setTextSize(1);
  642.       tft.setTextColor(COLOR_YELLOW);
  643.       tft.setCursor(55, 105);
  644.      
  645.       if (minutes < 10) tft.print("0");
  646.       tft.print(minutes);
  647.       tft.print(":");
  648.       if (seconds < 10) tft.print("0");
  649.       tft.print(seconds);
  650.      
  651.       cache.lastTime = elapsedSeconds;
  652.     }
  653.   }
  654.  
  655.   drawProgressBar(tempColor);
  656.  
  657.   // Indicador "TEMPERATURA ATINGIDA!"
  658.   if (tempReached && abs(currentTemp - setpointTemp) < 5) {
  659.     drawReachedIndicator();
  660.   }
  661. }
  662.  
  663. // ======================================
  664. // DESENHAR STATUS
  665. // ======================================
  666.  
  667. void drawStatus() {
  668.   tft.fillRect(115, 2, 42, 11, COLOR_CYAN);
  669.  
  670.   tft.setTextSize(1);
  671.   tft.setTextColor(COLOR_BG);
  672.   tft.setCursor(117, 4);
  673.  
  674.   if (coolingDown) {
  675.     tft.println("RESFR");
  676.   } else if (systemOn && heatingMode) {
  677.     if (tempReached) {
  678.       tft.println("OK!");
  679.     } else if (currentTemp < setpointTemp) {
  680.       tft.println("AQUEC");
  681.     } else {
  682.       tft.println("AJUST");
  683.     }
  684.   } else {
  685.     tft.println("DESLIG");
  686.   }
  687. }
  688.  
  689. // ======================================
  690. // OBTER COR BASEADA NA TEMPERATURA
  691. // ======================================
  692.  
  693. uint16_t getTempColor(float temp) {
  694.   if (temp > 400) {
  695.     return COLOR_RED;
  696.   } else if (temp > 200) {
  697.     return COLOR_ORANGE;
  698.   } else if (temp > 100) {
  699.     return COLOR_YELLOW;
  700.   } else {
  701.     return COLOR_CYAN;
  702.   }
  703. }
  704.  
  705. // ======================================
  706. // DESENHAR BARRA DE PROGRESSO TÉRMICA
  707. // ======================================
  708.  
  709. void drawProgressBar(uint16_t color) {
  710.   tft.drawRect(5, 120, 150, 8, COLOR_WHITE);
  711.  
  712.   int progress = map(constrain((int)currentTemp, AMBIENT_TEMP, setpointTemp), AMBIENT_TEMP, setpointTemp, 0, 148);
  713.  
  714.   if (progress > 0) {
  715.     tft.fillRect(6, 121, progress, 6, color);
  716.   }
  717.  
  718.   if (progress < 148) {
  719.     tft.fillRect(6 + progress, 121, 148 - progress, 6, COLOR_BG);
  720.   }
  721. }
  722.  
  723. // ======================================
  724. // INDICADOR "TEMPERATURA ATINGIDA!"
  725. // ======================================
  726.  
  727. void drawReachedIndicator() {
  728.   static unsigned long lastBlink = 0;
  729.   static bool blinkState = false;
  730.  
  731.   if (millis() - lastBlink > 500) {
  732.     blinkState = !blinkState;
  733.     lastBlink = millis();
  734.   }
  735.  
  736.   if (blinkState) {
  737.     tft.fillRect(120, 100, 35, 20, COLOR_GREEN);
  738.     tft.setTextSize(2);
  739.     tft.setTextColor(COLOR_BG);
  740.     tft.setCursor(122, 104);
  741.     tft.println("OK!");
  742.   }
  743. }
  744.  
  745. /* END CODE */
  746.  
Advertisement
Add Comment
Please, Sign In to add comment