pleasedontcode

# Thermal Desoldering rev_03

Feb 27th, 2026
36
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Arduino 19.07 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 13:08:59
  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 D2 DETECÇÃO ZERO-CROSSING
  32.   ✅ PIN D3 PWM HEATER_GATE - MOC3023 LED (Resistência AC)
  33.   ✅ PIN D12 PWM PUMP_GATE - MOC3023 LED (Bomba AC)
  34.   ✅ PROTEÇÃO: BOMBA SOLENOIDE COM LIMITE DE 40% MÍNIMO
  35.   ✅ SERIAL DEBUG REMOVIDO - OTIMIZADO PARA MEMORIA
  36.  
  37.   ⚡ SISTEMA AC COMPLETO:
  38.   - MOC3023 + BT136 (Triacs)
  39.   - Detecção zero-crossing
  40.   - Controle de resistência AC via PWM HEATER_GATE (D3)
  41.   - Controle de bomba solenoide AC via PWM PUMP_GATE (D12)
  42.   - Termopar MAX6675 Tipo K
  43.   - Display ST7735S 1.8" (D8=DC, D9=RST, D10=CS)
  44.   - EEPROM para salvar setpoint
  45.   ============================================
  46. */
  47.  
  48. /****** DEFINITION OF LIBRARIES *****/
  49. #include <Adafruit_GFX.h>   //https://github.com/adafruit/Adafruit-GFX-Library
  50. #include <Adafruit_ST7735.h>
  51. #include <SPI.h>
  52. #include <max6675.h>
  53. #include <EEPROM.h>
  54.  
  55. // ======================================
  56. // CONFIGURAÇÃO DE PINOS (LIMPO)
  57. // ======================================
  58.  
  59. // Display ST7735S (SPI)
  60. #define TFT_CS    10
  61. #define TFT_RST   9
  62. #define TFT_DC    8
  63.  
  64. // Termopar MAX6675 (SPI)
  65. #define THERMO_SCK  11
  66. #define THERMO_CS   5
  67. #define THERMO_SO   4
  68.  
  69. // Potenciômetros analógicos
  70. #define POT_TEMP    A0
  71. #define POT_FAN     A1
  72.  
  73. // Botão
  74. #define POWER_BTN   7
  75.  
  76. // ⚡ PINOS AC - MOC3023 + BT136
  77. #define ZERO_CROSS_PIN  2   // INT0 - Detecção zero-crossing
  78. #define HEATER_GATE    3    // PWM - LED do MOC3023 (Resistência AC)
  79. #define PUMP_GATE      12   // PWM - LED do MOC3023 (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 via HEATER_GATE PWM)
  128. int pumpPowerLevel = 0;    // 0-255 (nível de potência da bomba via PUMP_GATE PWM)
  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(HEATER_GATE, OUTPUT);
  207.   pinMode(PUMP_GATE, OUTPUT);
  208.   pinMode(POWER_BTN, INPUT_PULLUP);
  209.   pinMode(POT_TEMP, INPUT);
  210.   pinMode(POT_FAN, INPUT);
  211.  
  212.   // Inicializar saídas em LOW (TRIACs desligados)
  213.   digitalWrite(HEATER_GATE, LOW);
  214.   digitalWrite(PUMP_GATE, LOW);
  215.   analogWrite(HEATER_GATE, 0);
  216.   analogWrite(PUMP_GATE, 0);
  217.  
  218.   // Inicializar display
  219.   tft.initR(INITR_BLACKTAB);
  220.   tft.setRotation(1);
  221.   tft.fillScreen(COLOR_BG);
  222.  
  223.   drawBootScreen();
  224.   delay(2000);
  225.  
  226.   // Carregar setpoint da EEPROM
  227.   loadSettingsFromEEPROM();
  228.  
  229.   // Ler temperatura inicial
  230.   currentTemp = thermocouple.readCelsius();
  231.   if (!isnan(currentTemp)) {
  232.     lastValidTemp = currentTemp;
  233.   } else {
  234.     currentTemp = AMBIENT_TEMP;
  235.   }
  236.  
  237.   // ⚡ CONFIGURAR INTERRUPÇÃO ZERO-CROSSING
  238.   attachInterrupt(digitalPinToInterrupt(ZERO_CROSS_PIN), zeroCrossingInterrupt, RISING);
  239.  
  240.   drawInterface();
  241.   lastThermoRead = millis();
  242. }
  243.  
  244. // ======================================
  245. // LOOP PRINCIPAL
  246. // ======================================
  247.  
  248. void loop() {
  249.   unsigned long currentMillis = millis();
  250.  
  251.   checkPowerButton(currentMillis);
  252.   readPotentiometers();
  253.  
  254.   // Ler termopar
  255.   if (currentMillis - lastThermoRead >= 500) {
  256.     float temp = thermocouple.readCelsius();
  257.    
  258.     if (!isnan(temp) && temp > -10 && temp < 600) {
  259.       currentTemp = temp;
  260.       lastValidTemp = temp;
  261.     }
  262.    
  263.     lastThermoRead = currentMillis;
  264.   }
  265.  
  266.   controlSystemAC(currentMillis);
  267.   checkSafetyLimits(currentMillis);
  268.  
  269.   // Atualizar display com controle de flickering
  270.   if (currentMillis - lastUpdate >= 200) {
  271.     updateDisplay(currentMillis);
  272.     lastUpdate = currentMillis;
  273.   }
  274. }
  275.  
  276. // ======================================
  277. // ⚡ INTERRUPÇÃO ZERO-CROSSING
  278. // ======================================
  279.  
  280. void zeroCrossingInterrupt() {
  281.   lastZeroCrossing = micros();
  282.   zeroCrossingDetected = true;
  283.  
  284.   // ⚡ DISPARO DOS TRIACs COM DELAY PARA CONTROLE DE POTÊNCIA
  285.  
  286.   // Resistência (PIN 3 - HEATER_GATE PWM)
  287.   if (heaterPowerLevel > 0) {
  288.     delayMicroseconds(map(255 - heaterPowerLevel, 0, 255, 0, 8000));
  289.     digitalWrite(HEATER_GATE, HIGH);
  290.     delayMicroseconds(10);
  291.     digitalWrite(HEATER_GATE, LOW);
  292.   }
  293.  
  294.   // Bomba (PIN 12 - PUMP_GATE PWM)
  295.   if (pumpPowerLevel > 0) {
  296.     delayMicroseconds(map(255 - pumpPowerLevel, 0, 255, 0, 8000));
  297.     digitalWrite(PUMP_GATE, HIGH);
  298.     delayMicroseconds(10);
  299.     digitalWrite(PUMP_GATE, LOW);
  300.   }
  301. }
  302.  
  303. // ======================================
  304. // VERIFICAR BOTÃO DE POTÊNCIA
  305. // ======================================
  306.  
  307. void checkPowerButton(unsigned long currentMillis) {
  308.   static bool buttonPressed = false;
  309.  
  310.   if (currentMillis - lastButtonCheck < 200) {
  311.     return;
  312.   }
  313.  
  314.   bool buttonState = digitalRead(POWER_BTN);
  315.  
  316.   if (buttonState == LOW && !buttonPressed) {
  317.     buttonPressed = true;
  318.     togglePower();
  319.   }
  320.   else if (buttonState == HIGH && buttonPressed) {
  321.     buttonPressed = false;
  322.   }
  323.  
  324.   lastButtonCheck = currentMillis;
  325. }
  326.  
  327. // ======================================
  328. // ⚠️ LEITURA DE POTENCIÔMETROS
  329. // ======================================
  330.  
  331. void readPotentiometers() {
  332.   // Temperatura
  333.   int tempRaw = analogRead(POT_TEMP);
  334.   int newSetpoint = map(tempRaw, 0, 1023, TEMP_MIN, TEMP_MAX);
  335.  
  336.   if (abs(newSetpoint - setpointTemp) > 5) {
  337.     setpointTemp = newSetpoint;
  338.     saveSettingsToEEPROM();
  339.     tempReached = false;
  340.   }
  341.  
  342.   // Ventoinha (Bomba)
  343.   int fanRaw = analogRead(POT_FAN);
  344.   int rawFanSpeed = map(fanRaw, 0, 1023, 0, 100);
  345.  
  346.   // ⚠️ PROTEÇÃO: Bomba solenoide não pode oscilar abaixo de 40%
  347.   // Se ficar abaixo, desliga completamente (0%) para não travar
  348.   if (rawFanSpeed > 0 && rawFanSpeed < PUMP_MIN_POWER) {
  349.     fanSpeed = 0;  // Desliga bomba
  350.   } else {
  351.     fanSpeed = rawFanSpeed;
  352.   }
  353. }
  354.  
  355. // ======================================
  356. // ⚡ CONTROLE DO SISTEMA AC
  357. // ======================================
  358.  
  359. void controlSystemAC(unsigned long currentMillis) {
  360.   if (systemOn && heatingMode) {
  361.     // Verificar tempo máximo de aquecimento
  362.     if (currentMillis - heatingStartTime > MAX_HEATING_TIME) {
  363.       togglePower();
  364.       return;
  365.     }
  366.    
  367.     // ⚡ PID para resistência AC (usando HEATER_GATE PWM = D3)
  368.     if (currentMillis - lastPidTime >= 100) {
  369.       heaterPowerLevel = calculatePID(setpointTemp, currentTemp);
  370.       analogWrite(HEATER_GATE, map(heaterPowerLevel, 0, 255, 0, 200));
  371.       lastPidTime = currentMillis;
  372.     }
  373.    
  374.     // Verificar se chegou no setpoint
  375.     if (abs(currentTemp - setpointTemp) < 3) {
  376.       if (!tempReached) {
  377.         tempReached = true;
  378.       }
  379.     }
  380.    
  381.     // ⚡ Controlar bomba AC (velocidade via potência) com proteção
  382.     if (fanSpeed == 0) {
  383.       pumpPowerLevel = 0;
  384.     } else if (fanSpeed < PUMP_MIN_POWER) {
  385.       pumpPowerLevel = 0;  // Proteção: desliga se < 40%
  386.     } else {
  387.       pumpPowerLevel = map(fanSpeed, 0, 100, 0, 255);
  388.     }
  389.    
  390.   } else if (coolingDown) {
  391.     heaterPowerLevel = 0;
  392.     analogWrite(HEATER_GATE, 0);
  393.    
  394.     if (currentTemp > SAFE_TEMP) {
  395.       // ⚡ Bomba em máxima potência para resfriar
  396.       pumpPowerLevel = 255;
  397.     } else {
  398.       pumpPowerLevel = 0;
  399.       coolingDown = false;
  400.       tempReached = false;
  401.     }
  402.   } else {
  403.     heaterPowerLevel = 0;
  404.     pumpPowerLevel = 0;
  405.     analogWrite(HEATER_GATE, 0);
  406.   }
  407. }
  408.  
  409. // ======================================
  410. // ⚠️ VERIFICAR LIMITES DE SEGURANÇA
  411. // ======================================
  412.  
  413. void checkSafetyLimits(unsigned long currentMillis) {
  414.   if (currentTemp > MAX_TEMP_ABSOLUTE) {
  415.     systemOn = false;
  416.     heatingMode = false;
  417.     coolingDown = true;
  418.     heaterPowerLevel = 0;
  419.     analogWrite(HEATER_GATE, 0);
  420.     pumpPowerLevel = 255;  // Máximo resfriamento
  421.     pidIntegral = 0;
  422.     pidLastError = 0;
  423.   }
  424. }
  425.  
  426. // ======================================
  427. // ⚡ CALCULA PID (RESISTÊNCIA AC)
  428. // ======================================
  429.  
  430. int calculatePID(float setpoint, float current) {
  431.   float error = setpoint - current;
  432.   float deltaTime = 0.1;
  433.  
  434.   // Proporcional
  435.   float P = KP * error;
  436.  
  437.   // Integral
  438.   pidIntegral += error * deltaTime;
  439.   pidIntegral = constrain(pidIntegral, 0, 255);
  440.   float I = KI * pidIntegral;
  441.  
  442.   // Derivativo
  443.   float derivative = (error - pidLastError) / deltaTime;
  444.   float D = KD * derivative;
  445.   pidLastError = error;
  446.  
  447.   // Output
  448.   float output = P + I + D;
  449.   output = constrain(output, 0, 255);
  450.  
  451.   // Anti-overshoot quando perto do setpoint
  452.   if (abs(error) < 10 && current > setpoint) {
  453.     output *= 0.5;
  454.   }
  455.  
  456.   return (int)output;
  457. }
  458.  
  459. // ======================================
  460. // LIGAR/DESLIGAR SISTEMA
  461. // ======================================
  462.  
  463. void togglePower() {
  464.   systemOn = !systemOn;
  465.   pidIntegral = 0;
  466.   pidLastError = 0;
  467.   tempReached = false;
  468.  
  469.   if (systemOn) {
  470.     heatingMode = true;
  471.     coolingDown = false;
  472.     heatingStartTime = millis();
  473.   } else {
  474.     heatingMode = false;
  475.     coolingDown = true;
  476.   }
  477.  
  478.   drawInterface();
  479. }
  480.  
  481. // ======================================
  482. // EEPROM - SALVAR/CARREGAR SETPOINT
  483. // ======================================
  484.  
  485. void loadSettingsFromEEPROM() {
  486.   int savedSetpoint = EEPROM.read(EEPROM_SETPOINT) * 256 + EEPROM.read(EEPROM_SETPOINT + 1);
  487.  
  488.   if (savedSetpoint >= TEMP_MIN && savedSetpoint <= TEMP_MAX) {
  489.     setpointTemp = savedSetpoint;
  490.   }
  491. }
  492.  
  493. void saveSettingsToEEPROM() {
  494.   EEPROM.write(EEPROM_SETPOINT, setpointTemp / 256);
  495.   EEPROM.write(EEPROM_SETPOINT + 1, setpointTemp % 256);
  496. }
  497.  
  498. // ======================================
  499. // DESENHAR TELA DE BOOT
  500. // ======================================
  501.  
  502. void drawBootScreen() {
  503.   tft.fillScreen(COLOR_BG);
  504.  
  505.   tft.setTextSize(2);
  506.   tft.setTextColor(COLOR_CYAN);
  507.   tft.setCursor(10, 30);
  508.   tft.println("SOPRADOR");
  509.   tft.setCursor(20, 50);
  510.   tft.println("TERMICO");
  511.  
  512.   tft.setTextSize(1);
  513.   tft.setTextColor(COLOR_WHITE);
  514.   tft.setCursor(15, 80);
  515.   tft.println("v4.1 AC MOC3023");
  516.   tft.setCursor(10, 95);
  517.   tft.println("D3: HEATER, D12: PUMP");
  518.  
  519.   tft.drawRect(20, 110, 120, 8, COLOR_CYAN);
  520.   for (int i = 0; i < 120; i += 3) {
  521.     tft.fillRect(20, 110, i, 8, COLOR_CYAN);
  522.     delay(10);
  523.   }
  524. }
  525.  
  526. // ======================================
  527. // DESENHAR INTERFACE PRINCIPAL
  528. // ======================================
  529.  
  530. void drawInterface() {
  531.   tft.fillScreen(COLOR_BG);
  532.  
  533.   // Cabeçalho
  534.   tft.fillRect(0, 0, 160, 15, COLOR_CYAN);
  535.   tft.setTextSize(1);
  536.   tft.setTextColor(COLOR_BG);
  537.   tft.setCursor(10, 4);
  538.   tft.println("TERMOPAR K v4.1 AC");
  539.  
  540.   // Labels
  541.   tft.setTextColor(COLOR_WHITE);
  542.   tft.setTextSize(1);
  543.  
  544.   tft.setCursor(5, 25);
  545.   tft.println("TEMPERATURA:");
  546.  
  547.   tft.setCursor(5, 65);
  548.   tft.println("SETPOINT:");
  549.  
  550.   tft.setCursor(5, 85);
  551.   tft.println("BOMBA AC (40% min):");
  552.  
  553.   tft.setCursor(5, 105);
  554.   tft.print("Time: --:--");
  555.  
  556.   // Inicializar cache
  557.   cache.lastTemp = -999;
  558.   cache.lastSetpoint = -999;
  559.   cache.lastFanSpeed = -999;
  560.   cache.lastHeaterPower = -999;
  561.   cache.lastPumpPower = -999;
  562.   cache.lastCoolingDown = false;
  563.   cache.lastTempColor = COLOR_CYAN;
  564.   cache.lastStatus = -1;
  565.   cache.lastTime = -1;
  566. }
  567.  
  568. // ======================================
  569. // ATUALIZAR DISPLAY (COM ANTI-FLICKERING)
  570. // ======================================
  571.  
  572. void updateDisplay(unsigned long currentMillis) {
  573.   drawStatus();
  574.  
  575.   // Temperatura
  576.   int displayTemp = (int)currentTemp;
  577.   uint16_t tempColor = getTempColor(currentTemp);
  578.  
  579.   if (displayTemp != cache.lastTemp || tempColor != cache.lastTempColor) {
  580.     tft.fillRect(5, 38, 150, 20, COLOR_BG);
  581.     tft.setTextSize(3);
  582.     tft.setTextColor(tempColor);
  583.     tft.setCursor(10, 38);
  584.     tft.print(displayTemp);
  585.     tft.print("C");
  586.    
  587.     cache.lastTemp = displayTemp;
  588.     cache.lastTempColor = tempColor;
  589.   }
  590.  
  591.   // Setpoint
  592.   if (setpointTemp != cache.lastSetpoint) {
  593.     tft.fillRect(75, 65, 80, 15, COLOR_BG);
  594.     tft.setTextSize(2);
  595.     tft.setTextColor(COLOR_ORANGE);
  596.     tft.setCursor(80, 65);
  597.     tft.print(setpointTemp);
  598.     tft.print("C");
  599.    
  600.     cache.lastSetpoint = setpointTemp;
  601.   }
  602.  
  603.   // ⚡ BOMBA AC com proteção 40%
  604.   if (fanSpeed != cache.lastFanSpeed || coolingDown != cache.lastCoolingDown) {
  605.     tft.fillRect(5, 97, 150, 15, COLOR_BG);
  606.     tft.setTextSize(2);
  607.    
  608.     if (coolingDown && currentTemp > SAFE_TEMP) {
  609.       tft.setTextColor(COLOR_RED);
  610.       tft.setCursor(10, 97);
  611.       tft.print("MAX COOLING");
  612.     } else if (fanSpeed == 0) {
  613.       // ⚠️ Mostrar quando bomba está desligada por proteção
  614.       tft.setTextColor(COLOR_RED);
  615.       tft.setCursor(10, 97);
  616.       tft.print("OFF (< 40%)");
  617.     } else if (fanSpeed < PUMP_MIN_POWER) {
  618.       tft.setTextColor(COLOR_RED);
  619.       tft.setCursor(10, 97);
  620.       tft.print("PROT!");
  621.     } else {
  622.       tft.setTextColor(COLOR_GREEN);
  623.       tft.setCursor(10, 97);
  624.       tft.print(fanSpeed);
  625.       tft.print("% OK");
  626.     }
  627.    
  628.     cache.lastFanSpeed = fanSpeed;
  629.     cache.lastCoolingDown = coolingDown;
  630.   }
  631.  
  632.   // Timer
  633.   if (systemOn && heatingMode) {
  634.     int elapsedSeconds = (currentMillis - heatingStartTime) / 1000;
  635.     int minutes = elapsedSeconds / 60;
  636.     int seconds = elapsedSeconds % 60;
  637.    
  638.     if (elapsedSeconds != cache.lastTime) {
  639.       tft.fillRect(50, 105, 50, 10, COLOR_BG);
  640.       tft.setTextSize(1);
  641.       tft.setTextColor(COLOR_YELLOW);
  642.       tft.setCursor(55, 105);
  643.      
  644.       if (minutes < 10) tft.print("0");
  645.       tft.print(minutes);
  646.       tft.print(":");
  647.       if (seconds < 10) tft.print("0");
  648.       tft.print(seconds);
  649.      
  650.       cache.lastTime = elapsedSeconds;
  651.     }
  652.   }
  653.  
  654.   drawProgressBar(tempColor);
  655.  
  656.   // Indicador "TEMPERATURA ATINGIDA!"
  657.   if (tempReached && abs(currentTemp - setpointTemp) < 5) {
  658.     drawReachedIndicator();
  659.   }
  660. }
  661.  
  662. // ======================================
  663. // DESENHAR STATUS
  664. // ======================================
  665.  
  666. void drawStatus() {
  667.   tft.fillRect(115, 2, 42, 11, COLOR_CYAN);
  668.  
  669.   tft.setTextSize(1);
  670.   tft.setTextColor(COLOR_BG);
  671.   tft.setCursor(117, 4);
  672.  
  673.   if (coolingDown) {
  674.     tft.println("RESFR");
  675.   } else if (systemOn && heatingMode) {
  676.     if (tempReached) {
  677.       tft.println("OK!");
  678.     } else if (currentTemp < setpointTemp) {
  679.       tft.println("AQUEC");
  680.     } else {
  681.       tft.println("AJUST");
  682.     }
  683.   } else {
  684.     tft.println("DESLIG");
  685.   }
  686. }
  687.  
  688. // ======================================
  689. // OBTER COR BASEADA NA TEMPERATURA
  690. // ======================================
  691.  
  692. uint16_t getTempColor(float temp) {
  693.   if (temp > 400) {
  694.     return COLOR_RED;
  695.   } else if (temp > 200) {
  696.     return COLOR_ORANGE;
  697.   } else if (temp > 100) {
  698.     return COLOR_YELLOW;
  699.   } else {
  700.     return COLOR_CYAN;
  701.   }
  702. }
  703.  
  704. // ======================================
  705. // DESENHAR BARRA DE PROGRESSO TÉRMICA
  706. // ======================================
  707.  
  708. void drawProgressBar(uint16_t color) {
  709.   tft.drawRect(5, 120, 150, 8, COLOR_WHITE);
  710.  
  711.   int progress = map(constrain((int)currentTemp, AMBIENT_TEMP, setpointTemp), AMBIENT_TEMP, setpointTemp, 0, 148);
  712.  
  713.   if (progress > 0) {
  714.     tft.fillRect(6, 121, progress, 6, color);
  715.   }
  716.  
  717.   if (progress < 148) {
  718.     tft.fillRect(6 + progress, 121, 148 - progress, 6, COLOR_BG);
  719.   }
  720. }
  721.  
  722. // ======================================
  723. // INDICADOR "TEMPERATURA ATINGIDA!"
  724. // ======================================
  725.  
  726. void drawReachedIndicator() {
  727.   static unsigned long lastBlink = 0;
  728.   static bool blinkState = false;
  729.  
  730.   if (millis() - lastBlink > 500) {
  731.     blinkState = !blinkState;
  732.     lastBlink = millis();
  733.   }
  734.  
  735.   if (blinkState) {
  736.     tft.fillRect(120, 100, 35, 20, COLOR_GREEN);
  737.     tft.setTextSize(2);
  738.     tft.setTextColor(COLOR_BG);
  739.     tft.setCursor(122, 104);
  740.     tft.println("OK!");
  741.   }
  742. }
  743.  
  744. /* END CODE */
  745.  
Advertisement
Add Comment
Please, Sign In to add comment