Problema con estación de soldar (Pistola de aire caliente)

Caería un rayo cerca que dañó el pin del micro 🤷‍♂️, como les pasa a los adaptadores de ethernet.

Hora de hacer un control analógico
 
¿Me equivoco o ese micro va con zócalo?
Nunca me gustó las memorias en zócalo, menos los microcontroladores..
Si, nunca estuvo soldado, los demás componentes sí los removí y pasé a bases para poder realizar las pruebas más fáciles, pero el MCU ya estaba así desde fábrica.
Si fuera posible levantaría el pin del microcontrolador del PCB y forzaría el estado alto mediante un PullUp externo y mediria a ver que pasa.
Cuando lo remuevo de la base el voltaje llega correctamente a 5V, como se puede observar en las fotos el LED enciende correctamente cuando lo inserto en los pines que corresponden a tierra y el interruptor. Lo que no me gusta del diseño es que no existe ninguna resistencia de protección al pin, sino que va directo, pero no entiendo cómo pudo dañarse.

¿De casualidad alguien tendrá el circuito? si no tendré que trazarlo por mi cuenta, hay un integrado de 8 pines que fue borrado (tiene lijada la nomenclatura) por lo que no sé qué podría ser.
 
Si, nunca estuvo soldado, los demás componentes sí los removí y pasé a bases para poder realizar las pruebas más fáciles, pero el MCU ya estaba así desde fábrica.

Cuando lo remuevo de la base el voltaje llega correctamente a 5V, como se puede observar en las fotos el LED enciende correctamente cuando lo inserto en los pines que corresponden a tierra y el interruptor. Lo que no me gusta del diseño es que no existe ninguna resistencia de protección al pin, sino que va directo, pero no entiendo cómo pudo dañarse.

¿De casualidad alguien tendrá el circuito? si no tendré que trazarlo por mi cuenta, hay un integrado de 8 pines que fue borrado (tiene lijada la nomenclatura) por lo que no sé qué podría ser.
Entonces no te quedan dudas de donde esta el problema. Por algo "gastaron" en poner zócalo, tal vez por eso que te paso.

Habría que averiguar si se consigue programado dicho microcontrolador y ponerle un Zener de 5.1V del pin a GND a ver si se quema este y no el pin la próxima vez.
 
Yo recuerdo que, allá en los principios de los tiempos, Philips impuso una modificación para los micros que comprendía una chapita adhesiva y un trocito de cable para conectarla a masa. En los chasis nuevos ya venía así. Adiós problemas.

Si soldados eran susceptibles de fallos por estática o capacidades parásitas.. No me imagino con zócalo.

El zócalo estará para facilitar el cambio si fallara o estará para facilitar el fallo y el cambio..de la estación completa... 🤔🤔¿?
 
El chip no es caro en AliExpress, pero dejando de lado el tema de la arquitectura porque tras programar en bare metal los PIC y MSP430, no creo que me dé problemas para aprender a usar el Samsung siempre que alguien dé el IDE para ello, no iré a comprar un programador solo para esto, creo que tendré que hacer mi propia estación con juegos de azar y. . . , digo, con USB para de una vez hasta controlar curvas de temperatura con la computadora y solo poner la pistola en un soporte para que se encargue de lo demás sola.
 
Aún intento realizar las reparaciones de la estación, pero tengo un componente rayado que no sé qué es, presumo podría ser algún amplificador.
Lo que encontré al intentar ver las conexiones del MCU hasta el momento va asíEstacion.png
La pistola como tal sirve, envíe la señal al pin del optoacoplador y se calienta correctamente, el pin 11 del socket tambien comienza a incrementar el voltaje por lo considero que es del termopar (tras el circuito de amplificación que aún no trazo), el 12 aún no descubro que es, lo que me llega a intrigar es una EEPROM culla función no sabría cual, la removí para leerla y parece que solo tiene almacenado 01 00, todos los demás bytes están en FF, un detalle es que solo tengo el pickit2 y la memoria es una Atmel al parecer AT24C02C ¿para qué creen que podría utilizarla?

Por ahora intentaré ver como se controla lo del ventilador ya que el potenciómetro parece ir analógicamente, el pin parece solo controlar entre si se enciende o no, el pin 12 aún tengo que descubrir a donde termina, lo malo es que el trazado pasa debajo del display y sin aire caliente no puedo removerla ya que la soldadura está debajo de la misma.

Intentaré trazar la última parte y luego conectarle el Arduino para probar ya que es el único MCU que tengo a 5V y al parecer el ventilador ocupa voltaje en H para no activarse.

En resumen, hasta el momento
Pin 4: Interruptor magnético en la pistola, pull-up 10k, High cuando se remueve de la base.
Pin 6: Optoacoplador, Activo Low
Pin 8: Botón temperatura + compartido con I2C
Pin 9: Botón temperatura - compartido con I2C
Pin 10: Ventilador, Activo Low
Pin 11: Posible señal termopar
pin 12: aún sin descubrir que es, tiene un voltaje relativamente bajo 0.7~0.8V pero no cambia cuando muevo los controles.
 
Bueno, después de revisar una y otra vez el circuito, ya tengo la parte de control del ventilador

Estacion-Ventilador.png

El problema es que se encendía a toda velocidad, el voltaje de salida es de 24V, hasta donde logro entender, se comportaría como una fuente lineal, pero por algún había regulación del voltaje al variar el potenciómetro. Decidí probar remover Q2 y reemplazarlo por Q1 ya que no tengo un 2N3904 y este último solo funciona como interruptor así que no es necesario para probar. Al parecer sí estaba dañado, ahora ya recuperé el control del ventilador.

Después de hacer eso encontré un MPS2222A en mis cosas y se lo instalé en lugar de Q1, lamentablemente aún presenta la falla del MCU, pero con esto ya tengo todas las conexiones mapeadas para entender cómo funciona y programarle algún otro controlador.

Por lo visto, esta estación realmente solo usa ese controlador para lo que es la regulación de la temperatura en la pistola, todo lo demás puede funcionar de forma independiente. Para encender la resistencia calefactora solo debo tratar con el LED del MOC3041 que usa. Como tiene disparo en cruce por cero no creo que haya alguna preocupación especial, pero ¿cómo recomendarían que trate el protocolo?
Para lo siguiente no se si es tan lineal el termopar y el que tengo para el multímetro solo me permite lecturas hasta 200ºC, creo que tendré que conseguir otro si quiero calibrar todo el rango.

PD: al parecer la memoria solo almacena la temperatura para conservarla cuando se apaga, el primer byte son las centenas al parecer y el segundo las decenas y unidades. Extraño formato para guardarlo.
 
Última edición:
Sigo progresando en reparar esta cosa compañeros, el avance ahora fue en algo del código para controlarla.
Descubrí que usar PWM es mala idea, si pudiera sincronizar la frecuencia con la onda de la red quizá podría aprovecharlo mejor, pero por ahora solo hacía que los focos titilen demasiado :,D
Estoy usando el Arduino Uno y la idea es ponerle un Arduino pro mini adentro.
2023-10-12_19-57-58.jpg
La regulación no es tan simple porque veo que al encender la resistencia esta se calienta bastante rápido, quizá cuando suba el muestreo lo regule mejor, pero por ahora tenemos el tema de la transferencia que de todas formas promediará, habrá que probar luego.
Este es el código que tengo hasta ahora
C++:
#define DISPLAY_1 6
#define DISPLAY_2 7
#define DISPLAY_3 A0
#define DISPLAY_A 8
#define DISPLAY_B 9
#define DISPLAY_C 10
#define DISPLAY_D 11
#define DISPLAY_E 12
#define DISPLAY_F 13
#define DISPLAY_G 4
#define DISPLAY_DP 5
#define PIN_FAN A3
#define SENSE_FAN A2
#define SENSE_TEMP A1
#define HEAT_ELEMENT 3
#define BUTTON_UP A5
#define BUTTON_DOWN A4
#define MAG_SW 2
#define USE_TIMER_1 true
#include "TimerInterrupt.h"
#define TIMER_INTERVAL_MS 5
struct {
  const uint8_t dp = 0x80;
  const uint8_t numbers[16] = { 0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7D, 0x07, 0x7F, 0x6F, 0x77, 0x7C, 0x39, 0x5E, 0x79, 0x71 };
} Display7Seg;
uint8_t displayBuffer[3] = { 0, 0, 0 };
int displayIndex = 0;
void TimerHandler(void) {
  switch (displayIndex) {
    case 0:
      digitalWrite(DISPLAY_3, LOW);
      digitalWrite(DISPLAY_1, HIGH);
      break;
    case 1:
      digitalWrite(DISPLAY_1, LOW);
      digitalWrite(DISPLAY_2, HIGH);
      break;
    case 2:
      digitalWrite(DISPLAY_2, LOW);
      digitalWrite(DISPLAY_3, HIGH);
      break;
  }
  if (0x01 & displayBuffer[displayIndex]) digitalWrite(DISPLAY_A, HIGH);
  else digitalWrite(DISPLAY_A, LOW);
  if (0x02 & displayBuffer[displayIndex]) digitalWrite(DISPLAY_B, HIGH);
  else digitalWrite(DISPLAY_B, LOW);
  if (0x04 & displayBuffer[displayIndex]) digitalWrite(DISPLAY_C, HIGH);
  else digitalWrite(DISPLAY_C, LOW);
  if (0x08 & displayBuffer[displayIndex]) digitalWrite(DISPLAY_D, HIGH);
  else digitalWrite(DISPLAY_D, LOW);
  if (0x10 & displayBuffer[displayIndex]) digitalWrite(DISPLAY_E, HIGH);
  else digitalWrite(DISPLAY_E, LOW);
  if (0x20 & displayBuffer[displayIndex]) digitalWrite(DISPLAY_F, HIGH);
  else digitalWrite(DISPLAY_F, LOW);
  if (0x40 & displayBuffer[displayIndex]) digitalWrite(DISPLAY_G, HIGH);
  else digitalWrite(DISPLAY_G, LOW);
  if (0x80 & displayBuffer[displayIndex]) digitalWrite(DISPLAY_DP, HIGH);
  else digitalWrite(DISPLAY_DP, LOW);
  if (displayIndex == 2) displayIndex = 0;
  else displayIndex++;
}
void displayNumber(uint16_t val) {
  int cents = val / 100;
  if (cents < 10) displayBuffer[0] = ~Display7Seg.numbers[cents];
  int x = val % 100;
  int dec = x / 10;
  if (dec < 10) displayBuffer[1] = ~Display7Seg.numbers[dec];
  int unit = x % 10;
  if (unit < 10) displayBuffer[2] = ~Display7Seg.numbers[unit];
}
volatile int temp = 0, speed = 0, heater = 0;
void setup() {
  // put your setup code here, to run once:
  pinMode(DISPLAY_A, OUTPUT);
  pinMode(DISPLAY_B, OUTPUT);
  pinMode(DISPLAY_C, OUTPUT);
  pinMode(DISPLAY_D, OUTPUT);
  pinMode(DISPLAY_E, OUTPUT);
  pinMode(DISPLAY_F, OUTPUT);
  pinMode(DISPLAY_G, OUTPUT);
  pinMode(DISPLAY_DP, OUTPUT);
  pinMode(DISPLAY_1, OUTPUT);
  pinMode(DISPLAY_2, OUTPUT);
  pinMode(DISPLAY_3, OUTPUT);
  pinMode(PIN_FAN, OUTPUT);
  pinMode(HEAT_ELEMENT, OUTPUT);
  digitalWrite(HEAT_ELEMENT, HIGH);
  pinMode(MAG_SW, INPUT_PULLUP);
  pinMode(BUTTON_UP, INPUT_PULLUP);
  pinMode(BUTTON_DOWN, INPUT_PULLUP);
  Serial.begin(115200);
  displayBuffer[0] = ~0x6D;
  displayBuffer[1] = ~0x79;
  displayBuffer[2] = ~0x50;
  heater = 50;
  ITimer1.init();
  if (ITimer1.attachInterruptInterval(TIMER_INTERVAL_MS, TimerHandler)) {
    Serial.println(F("Starting  ITimer1 OK"));
  } else
    Serial.println(F("Can't set ITimer1. Select another freq. or timer"));
}
void loop() {
  // put your main code here, to run repeatedly:
  temp = analogRead(SENSE_TEMP);
  speed = analogRead(SENSE_FAN);
  if (Serial.available() != 0) {
    int tvar = Serial.parseInt();
    heater = tvar;
    //analogWrite(HEAT_ELEMENT, heater);
  }
  if (digitalRead(MAG_SW)) {
    digitalWrite(PIN_FAN, LOW);
    if (temp > heater) {
      digitalWrite(HEAT_ELEMENT, HIGH);
      Serial.print("Inactive");
    } else {
      digitalWrite(HEAT_ELEMENT, LOW);
      Serial.print("Active");
    }
    
  } else {
    digitalWrite(HEAT_ELEMENT, HIGH);
    Serial.print("Inactive");
    if(temp < 20) digitalWrite(PIN_FAN, HIGH);
  }
  Serial.print(" T ");
  Serial.print(temp);
  Serial.print(" S ");
  Serial.print(speed);
  Serial.print(" P ");
  Serial.println(heater);
  displayNumber(temp);
  delay(100);
}
Me falta agregar código para el funcionamiento de los botones y asignar correctamente la pantalla, por ahora puede mostrar los números, para mantener el mux, opté por un simple buffer que almacena los valores y luego por interrupción del timer actualizarlo. Por ahora, el umbral de temperatura se establece desde el serial. Mañana quizá compre el Arduino que irá montado para armarlo y de ahí solo quedaría hacer más pruebas para calibrar todo. Por lo pronto ya la lógica permite encender y apagar la resistencia al removerlo de la base, también apagarlo cuando la temperatura supera el umbral y encenderlo cuando baja, el ventilador también se enciende al removerlo y se apaga cuando la temperatura alcanza un punto seguro mientras está en la base.

En general hay 2 cosas que estoy contemplando, dejarle el serial que podría ayudarme a automatizar curvas de temperatura, y lo otro quizá es, dado a que la versión SMD tiene 2 pines análogos extra, quizá dejarle una interfaz para una sonda de temperatura externa.
 
Intenté realizar algunas pruebas midiendo la temperatura con el multímetro y variando los parámetros, luego le pedí al programa calcular la regresión lineal
WP_20231002_23_00_54_Pro.jpg 1697223992518.png
Con esos datos hice algunas correcciones al código para agregar la temperatura como una tabla, eso ahorra tiempo en tener que procesar la conversión en el controlador, además de que sobra memoria, así que ¿por qué no?
C++:
#define DISPLAY_1 6
#define DISPLAY_2 7
#define DISPLAY_3 A0
#define DISPLAY_A 8
#define DISPLAY_B 9
#define DISPLAY_C 10
#define DISPLAY_D 11
#define DISPLAY_E 12
#define DISPLAY_F 13
#define DISPLAY_G 4
#define DISPLAY_DP 5

#define PIN_FAN A3
#define SENSE_FAN A2
#define SENSE_TEMP A1
#define HEAT_ELEMENT 3
#define BUTTON_UP A5
#define BUTTON_DOWN A4
#define MAG_SW 2

#define USE_TIMER_1 true
#include "TimerInterrupt.h"
#define TIMER_INTERVAL_MS 5
#define DEBOUNCING_INTERVAL_MS 200
#define LONG_PRESS_INTERVAL_MS 3000
#define SETTINGS_TIMEOUT 3000

//buttons
volatile bool Changing_Settings = false;
volatile int Changing_Settings_Timeout = SETTINGS_TIMEOUT / TIMER_INTERVAL_MS;

volatile bool Button_Up_Pressed = false;
volatile bool Button_Up_Release = false;
volatile bool Button_Up_Hold = false;
volatile int Button_Up_Cicles = 0;

volatile bool Button_Down_Pressed = false;
volatile bool Button_Down_Release = false;
volatile bool Button_Down_Hold = false;
volatile int Button_Down_Cicles = 0;

struct {
  const uint8_t dp = 0x80;
  const uint8_t numbers[16] = { 0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7D, 0x07, 0x7F, 0x6F, 0x77, 0x7C, 0x39, 0x5E, 0x79, 0x71 };
} Display7Seg;
const int calTable[] = { //Calibration table, temperature by value on ADC
32, 33, 35, 36, 37, 38, 39, 40,
42, 43, 44, 45, 46, 47, 49, 50,
51, 52, 53, 54, 56, 57, 58, 59,
60, 61, 63, 64, 65, 66, 67, 68,
70, 71, 72, 73, 74, 75, 77, 78,
79, 80, 81, 83, 84, 85, 86, 87,
88, 90, 91, 92, 93, 94, 95, 97,
98, 99, 100, 101, 102, 104, 105, 106,
107, 108, 109, 111, 112, 113, 114, 115,
116, 118, 119, 120, 121, 122, 123, 125,
126, 127, 128, 129, 131, 132, 133, 134,
135, 136, 138, 139, 140, 141, 142, 143,
145, 146, 147, 148, 149, 150, 152, 153,
154, 155, 156, 157, 159, 160, 161, 162,
163, 164, 166, 167, 168, 169, 170, 172,
173, 174, 175, 176, 177, 179, 180, 181,
182, 183, 184, 186, 187, 188, 189, 190,
191, 193, 194, 195, 196, 197, 198, 200,
201, 202, 203, 204, 205, 207, 208, 209,
210, 211, 212, 214, 215, 216, 217, 218,
220, 221, 222, 223, 224, 225, 227, 228,
229, 230, 231, 232, 234, 235, 236, 237,
238, 239, 241, 242, 243, 244, 245, 246,
248, 249, 250, 251, 252, 253, 255, 256,
257, 258, 259, 260, 262, 263, 264, 265,
266, 268, 269, 270, 271, 272, 273, 275,
276, 277, 278, 279, 280, 282, 283, 284,
285, 286, 287, 289, 290, 291, 292, 293,
294, 296, 297, 298, 299, 300, 301, 303,
304, 305, 306, 307, 308, 310, 311, 312,
313, 314, 316, 317, 318, 319, 320, 321,
323, 324, 325, 326, 327, 328, 330, 331
};

volatile int temp = 0, speed = 0, heater = 0;
uint8_t displayBuffer[3] = { 0, 0, 0 };
volatile int displayIndex = 0;

void TimerHandler(void) {
  switch (displayIndex) {
    case 0:
      digitalWrite(DISPLAY_3, LOW);
      digitalWrite(DISPLAY_1, HIGH);
      break;
    case 1:
      digitalWrite(DISPLAY_1, LOW);
      digitalWrite(DISPLAY_2, HIGH);
      break;
    case 2:
      digitalWrite(DISPLAY_2, LOW);
      digitalWrite(DISPLAY_3, HIGH);
      break;
  }
  if (0x01 & displayBuffer[displayIndex]) digitalWrite(DISPLAY_A, HIGH);
  else digitalWrite(DISPLAY_A, LOW);
  if (0x02 & displayBuffer[displayIndex]) digitalWrite(DISPLAY_B, HIGH);
  else digitalWrite(DISPLAY_B, LOW);
  if (0x04 & displayBuffer[displayIndex]) digitalWrite(DISPLAY_C, HIGH);
  else digitalWrite(DISPLAY_C, LOW);
  if (0x08 & displayBuffer[displayIndex]) digitalWrite(DISPLAY_D, HIGH);
  else digitalWrite(DISPLAY_D, LOW);
  if (0x10 & displayBuffer[displayIndex]) digitalWrite(DISPLAY_E, HIGH);
  else digitalWrite(DISPLAY_E, LOW);
  if (0x20 & displayBuffer[displayIndex]) digitalWrite(DISPLAY_F, HIGH);
  else digitalWrite(DISPLAY_F, LOW);
  if (0x40 & displayBuffer[displayIndex]) digitalWrite(DISPLAY_G, HIGH);
  else digitalWrite(DISPLAY_G, LOW);
  if (0x80 & displayBuffer[displayIndex]) digitalWrite(DISPLAY_DP, HIGH);
  else digitalWrite(DISPLAY_DP, LOW);

  if (displayIndex == 2) displayIndex = 0;
  else displayIndex++;

  if (Button_Up_Pressed) {  //actions at Up button
    //Button already pressed
    Button_Up_Cicles++;  //increase the counter
    if (Button_Up_Cicles >= (DEBOUNCING_INTERVAL_MS / TIMER_INTERVAL_MS)) {
      if (digitalRead(BUTTON_UP)) {  //at release
        //button press action
        if (heater < 229) heater++;
        Button_Up_Pressed = false;
        Changing_Settings_Timeout = SETTINGS_TIMEOUT / TIMER_INTERVAL_MS;
        Changing_Settings = false;
        Button_Up_Cicles = 0;
      }
    }
  } else {
    //Button not pressed
    if (digitalRead(BUTTON_UP) == false) {
      Button_Up_Pressed = true;
      Changing_Settings = true;
    }
  }

  if (Button_Down_Pressed) {  //actions at Down button
    //Button already pressed
    Button_Down_Cicles++;  //increase the counter
    if (Button_Down_Cicles >= (DEBOUNCING_INTERVAL_MS / TIMER_INTERVAL_MS)) {
      if (digitalRead(BUTTON_DOWN)) {  //at release
        //button press action
        if (heater > 0) heater--;
        Button_Down_Pressed = false;
        Changing_Settings_Timeout = SETTINGS_TIMEOUT / TIMER_INTERVAL_MS;
        Changing_Settings = false;
        Button_Down_Cicles = 0;
      }
    }
  } else {
    //Button not pressed
    if (digitalRead(BUTTON_DOWN) == false) {
      Button_Down_Pressed = true;
      Changing_Settings = true;
    }
  }
  if(Changing_Settings == false && Changing_Settings_Timeout) Changing_Settings_Timeout--;
}

void displayNumber(uint16_t val) {
  int cents = val / 100;
  if (cents < 10) displayBuffer[0] = ~Display7Seg.numbers[cents];
  int x = val % 100;
  int dec = x / 10;
  if (dec < 10) displayBuffer[1] = ~Display7Seg.numbers[dec];
  int unit = x % 10;
  if (unit < 10) displayBuffer[2] = ~Display7Seg.numbers[unit];
}
void displayShow(uint8_t symbol1, uint8_t symbol2, uint8_t symbol3) {
  displayBuffer[0] = ~symbol1;
  displayBuffer[1] = ~symbol2;
  displayBuffer[2] = ~symbol3;
}

void setup() {
  // put your setup code here, to run once:
  //Priority
  pinMode(PIN_FAN, OUTPUT);  //stop fan
  digitalWrite(PIN_FAN, HIGH);
  pinMode(HEAT_ELEMENT, OUTPUT);  //Set heater and disable
  digitalWrite(HEAT_ELEMENT, HIGH);
  heater = 0;

  //Config display pins
  pinMode(DISPLAY_A, OUTPUT);
  pinMode(DISPLAY_B, OUTPUT);
  pinMode(DISPLAY_C, OUTPUT);
  pinMode(DISPLAY_D, OUTPUT);
  pinMode(DISPLAY_E, OUTPUT);
  pinMode(DISPLAY_F, OUTPUT);
  pinMode(DISPLAY_G, OUTPUT);
  pinMode(DISPLAY_DP, OUTPUT);
  pinMode(DISPLAY_1, OUTPUT);
  pinMode(DISPLAY_2, OUTPUT);
  pinMode(DISPLAY_3, OUTPUT);

  //configure control inputs
  pinMode(MAG_SW, INPUT_PULLUP);
  pinMode(BUTTON_UP, INPUT_PULLUP);
  pinMode(BUTTON_DOWN, INPUT_PULLUP);

  Serial.begin(115200);

  /*
  displayBuffer[0] = ~0x6D;
  displayBuffer[1] = ~0x79;
  displayBuffer[2] = ~0x50;
  */

  ITimer1.init();
  if (ITimer1.attachInterruptInterval(TIMER_INTERVAL_MS, TimerHandler)) {
    Serial.println(F("Starting  ITimer1 OK"));
  } else
    Serial.println(F("Can't set ITimer1. Select another freq. or timer"));

  displayShow(0x50, 0x5E, 0x6E);  //Message rdY
  delay(1000);
}

void loop() {
  // put your main code here, to run repeatedly:
  temp = analogRead(SENSE_TEMP);
  speed = analogRead(SENSE_FAN);

  if (Serial.available() != 0) {
    int tvar = Serial.parseInt();
    heater = tvar;
    Changing_Settings_Timeout = SETTINGS_TIMEOUT / TIMER_INTERVAL_MS;
  }
  if (digitalRead(MAG_SW)) {
    digitalWrite(PIN_FAN, LOW);
    if (temp > heater) {
      digitalWrite(HEAT_ELEMENT, HIGH);
    } else {
      digitalWrite(HEAT_ELEMENT, LOW);
    }

  } else {
    digitalWrite(HEAT_ELEMENT, HIGH);
    if (temp < 20) digitalWrite(PIN_FAN, HIGH);
  }
  Serial.print(temp);
  Serial.print(" ");
  Serial.print(speed);
  Serial.print(" ");
  Serial.println(heater);
  if(Changing_Settings || Changing_Settings_Timeout){
    displayNumber(calTable[heater]);
  } else {
    displayNumber(calTable[temp]);
  }
  delay(25);
}
Aun debo probar que velocidad es más cómoda al momento de sostener el botón para cambiar los valores, pero en general está funcionando bien, falta agregar esa parte al código y quizá meter la tabla de calibración en la EEPROM para que se pueda actualizar en el futuro en caso de ser necesario, luego dejar de usar strings para la comunicación y eliminar ese delay para mejorar la respuesta del control, por ahora solo lo uso para las pruebas. Lo último será agregar códigos de error para casos como falla en la pistola. Quizá E-S para falla del sensor y E-H para cuando se mide temperatura, pero no parezca responder el incremento al encendido del calefactor.

Ya hice una prueba, les comparto el video.
 
Bueno, ya está todo adentro.
2023-10-14_17-56-39.jpg
1697324467939.png
Hasta le puse bluetooth

Les dejo el código en caso de que a alguien le sirva
C++:
//Pin DEF
#define DISPLAY_1 A3
#define DISPLAY_2 A2
#define DISPLAY_3 4
#define DISPLAY_A 8
#define DISPLAY_B 9
#define DISPLAY_C 10
#define DISPLAY_D 11
#define DISPLAY_E 12
#define DISPLAY_F 13
#define DISPLAY_G 6
#define DISPLAY_DP 7

#define PIN_FAN 5
#define SENSE_FAN A1
#define SENSE_TEMP A0
#define HEAT_ELEMENT 3
#define BUTTON_UP A5
#define BUTTON_DOWN A4
#define MAG_SW 2

#define USE_TIMER_1 true
#include "TimerInterrupt.h"
#define TIMER_INTERVAL_MS 5
#define DEBOUNCING_INTERVAL_MS 200
#define LONG_PRESS_INTERVAL_MS 1000
#define LONG_PRESS_INTERVAL_DIV 10
#define SETTINGS_TIMEOUT 3000

#define TEMP_LIMIT 500  
#define SAFE_TEMP 40
#define MIN_FAN_VALUE 60
#define SAFE_DISCHARGE_RATIO 0.75f
const int calTable[] = {  //Calibration table, temperature by value on ADC
  32, 33, 35, 36, 37, 38, 39, 40,
  42, 43, 44, 45, 46, 47, 49, 50,
  51, 52, 53, 54, 56, 57, 58, 59,
  60, 61, 63, 64, 65, 66, 67, 68,
  70, 71, 72, 73, 74, 75, 77, 78,
  79, 80, 81, 83, 84, 85, 86, 87,
  88, 90, 91, 92, 93, 94, 95, 97,
  98, 99, 100, 101, 102, 104, 105, 106,
  107, 108, 109, 111, 112, 113, 114, 115,
  116, 118, 119, 120, 121, 122, 123, 125,
  126, 127, 128, 129, 131, 132, 133, 134,
  135, 136, 138, 139, 140, 141, 142, 143,
  145, 146, 147, 148, 149, 150, 152, 153,
  154, 155, 156, 157, 159, 160, 161, 162,
  163, 164, 166, 167, 168, 169, 170, 172,
  173, 174, 175, 176, 177, 179, 180, 181,
  182, 183, 184, 186, 187, 188, 189, 190,
  191, 193, 194, 195, 196, 197, 198, 200,
  201, 202, 203, 204, 205, 207, 208, 209,
  210, 211, 212, 214, 215, 216, 217, 218,
  220, 221, 222, 223, 224, 225, 227, 228,
  229, 230, 231, 232, 234, 235, 236, 237,
  238, 239, 241, 242, 243, 244, 245, 246,
  248, 249, 250, 251, 252, 253, 255, 256,
  257, 258, 259, 260, 262, 263, 264, 265,
  266, 268, 269, 270, 271, 272, 273, 275,
  276, 277, 278, 279, 280, 282, 283, 284,
  285, 286, 287, 289, 290, 291, 292, 293,
  294, 296, 297, 298, 299, 300, 301, 303,
  304, 305, 306, 307, 308, 310, 311, 312,
  313, 314, 316, 317, 318, 319, 320, 321,
  323, 324, 325, 326, 327, 328, 330, 331
};

//buttons
volatile bool Changing_Settings = false;
volatile int Changing_Settings_Timeout = SETTINGS_TIMEOUT / TIMER_INTERVAL_MS;
volatile int Cycles_Div = LONG_PRESS_INTERVAL_DIV;

volatile bool Button_Up_Pressed = false;
volatile bool Button_Up_Release = false;
volatile bool Button_Up_Hold = false;
volatile int Button_Up_Cycles = 0;

volatile bool Button_Down_Pressed = false;
volatile bool Button_Down_Release = false;
volatile bool Button_Down_Hold = false;
volatile int Button_Down_Cycles = 0;


struct {
  const uint8_t dp = 0x80;  //  0     1     2     3     4     5     6     7     8     9     A     B     C     D     E     F
  const uint8_t numbers[16] = { 0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7D, 0x07, 0x7F, 0x6F, 0x77, 0x7C, 0x39, 0x5E, 0x79, 0x71 };
} Display7Seg;


volatile int temp = 0, speed = 0, heater = 0;
volatile uint8_t displayBuffer[3] = { 0, 0, 0 };
volatile int displayIndex = 0;

void TimerHandler(void) {
  /***********************************
          Display MUX Section
  ***********************************/
  switch (displayIndex) {
    case 0:
      digitalWrite(DISPLAY_3, LOW);
      digitalWrite(DISPLAY_1, HIGH);
      break;
    case 1:
      digitalWrite(DISPLAY_1, LOW);
      digitalWrite(DISPLAY_2, HIGH);
      break;
    case 2:
      digitalWrite(DISPLAY_2, LOW);
      digitalWrite(DISPLAY_3, HIGH);
      break;
  }
  if (0x01 & displayBuffer[displayIndex]) digitalWrite(DISPLAY_A, HIGH);
  else digitalWrite(DISPLAY_A, LOW);
  if (0x02 & displayBuffer[displayIndex]) digitalWrite(DISPLAY_B, HIGH);
  else digitalWrite(DISPLAY_B, LOW);
  if (0x04 & displayBuffer[displayIndex]) digitalWrite(DISPLAY_C, HIGH);
  else digitalWrite(DISPLAY_C, LOW);
  if (0x08 & displayBuffer[displayIndex]) digitalWrite(DISPLAY_D, HIGH);
  else digitalWrite(DISPLAY_D, LOW);
  if (0x10 & displayBuffer[displayIndex]) digitalWrite(DISPLAY_E, HIGH);
  else digitalWrite(DISPLAY_E, LOW);
  if (0x20 & displayBuffer[displayIndex]) digitalWrite(DISPLAY_F, HIGH);
  else digitalWrite(DISPLAY_F, LOW);
  if (0x40 & displayBuffer[displayIndex]) digitalWrite(DISPLAY_G, HIGH);
  else digitalWrite(DISPLAY_G, LOW);
  if (0x80 & displayBuffer[displayIndex]) digitalWrite(DISPLAY_DP, HIGH);
  else digitalWrite(DISPLAY_DP, LOW);

  if (displayIndex == 2) displayIndex = 0;
  else displayIndex++;

  /***********************************
          Button Scan Section
  ***********************************/

  if (Button_Up_Pressed) {  //actions at Up button
    //Button already pressed
    Button_Up_Cycles++;  //increase the counter
    if (Button_Up_Cycles >= (DEBOUNCING_INTERVAL_MS / TIMER_INTERVAL_MS)) {
      if (digitalRead(BUTTON_UP)) {  //at release
        //button press action
        if (heater < 229) heater++;
        Button_Up_Pressed = false;
        Changing_Settings_Timeout = SETTINGS_TIMEOUT / TIMER_INTERVAL_MS;
        Changing_Settings = false;
        Button_Up_Cycles = DEBOUNCING_INTERVAL_MS / TIMER_INTERVAL_MS;
      } else {
        if (Button_Up_Cycles > (LONG_PRESS_INTERVAL_MS / TIMER_INTERVAL_MS)) {
          if (Cycles_Div) {
            Cycles_Div--;
          } else {
            Cycles_Div = LONG_PRESS_INTERVAL_DIV;
            if (heater < 229) heater++;
          }
        }
      }
    }
  } else {
    //Button not pressed
    if (digitalRead(BUTTON_UP) == false) {
      Button_Up_Pressed = true;
      Changing_Settings = true;
    }
  }

  if (Button_Down_Pressed) {  //actions at Down button
    //Button already pressed
    Button_Down_Cycles++;  //increase the counter
    if (Button_Down_Cycles >= (DEBOUNCING_INTERVAL_MS / TIMER_INTERVAL_MS)) {
      if (digitalRead(BUTTON_DOWN)) {  //at release
        //button press action
        if (heater > 0) heater--;
        Button_Down_Pressed = false;
        Changing_Settings_Timeout = SETTINGS_TIMEOUT / TIMER_INTERVAL_MS;
        Changing_Settings = false;
        Button_Down_Cycles = 0;
      } else {
        if (Button_Down_Cycles > (LONG_PRESS_INTERVAL_MS / TIMER_INTERVAL_MS)) {
          if (Cycles_Div) {
            Cycles_Div--;
          } else {
            Cycles_Div = LONG_PRESS_INTERVAL_DIV;
            if (heater > 0) heater--;
          }
        }
      }
    }
  } else {
    //Button not pressed
    if (digitalRead(BUTTON_DOWN) == false) {
      Button_Down_Pressed = true;
      Changing_Settings = true;
    }
  }
  if (Changing_Settings == false && Changing_Settings_Timeout) Changing_Settings_Timeout--;
}

// Raw byte to display buffer
void displayShow(uint8_t symbol1, uint8_t symbol2, uint8_t symbol3) {
  displayBuffer[0] = ~symbol1;
  displayBuffer[1] = ~symbol2;
  displayBuffer[2] = ~symbol3;
}

// uint16_t to display, max value is 999
void displayNumber(uint16_t val) {
  int cents = val / 100;
  if (cents < 10) displayBuffer[0] = ~Display7Seg.numbers[cents];
  else displayShow(0x40, 0x40, 0x40);  //Show [---] in overflow 999
  int x = val % 100;
  int dec = x / 10;
  if (dec < 10) displayBuffer[1] = ~Display7Seg.numbers[dec];
  int unit = x % 10;
  if (unit < 10) displayBuffer[2] = ~Display7Seg.numbers[unit];
}

void criticalError() {
  digitalWrite(HEAT_ELEMENT, HIGH);  //turn off heat element
  digitalWrite(PIN_FAN, LOW);        //keep fan on for safety
  displayShow(0x79, 0x40, 0x39);     //Message [E-C]
  Serial.println("####  Critical Error!!  ####\r\nTurn off manually");
  while (1)
    ;  //stop
}
void setup() {
  // put your setup code here, to run once:
  //Priority
  pinMode(PIN_FAN, OUTPUT);  //stop fan
  digitalWrite(PIN_FAN, HIGH);
  pinMode(HEAT_ELEMENT, OUTPUT);     //Set heater and disable
  digitalWrite(HEAT_ELEMENT, HIGH);  //off
  heater = 58;

  //Config display pins
  pinMode(DISPLAY_A, OUTPUT);
  pinMode(DISPLAY_B, OUTPUT);
  pinMode(DISPLAY_C, OUTPUT);
  pinMode(DISPLAY_D, OUTPUT);
  pinMode(DISPLAY_E, OUTPUT);
  pinMode(DISPLAY_F, OUTPUT);
  pinMode(DISPLAY_G, OUTPUT);
  pinMode(DISPLAY_DP, OUTPUT);
  pinMode(DISPLAY_1, OUTPUT);
  pinMode(DISPLAY_2, OUTPUT);
  pinMode(DISPLAY_3, OUTPUT);
  //init value should show [8.8.8.] as lamp test
  //configure control inputs
  pinMode(MAG_SW, INPUT_PULLUP);
  pinMode(BUTTON_UP, INPUT_PULLUP);
  pinMode(BUTTON_DOWN, INPUT_PULLUP);

  Serial.begin(115200);

  ITimer1.init();
  if (ITimer1.attachInterruptInterval(TIMER_INTERVAL_MS, TimerHandler)) {
    Serial.println(F("Starting"));
  } else
    Serial.println(F("Can't set ITimer1. Select another freq. or timer"));

  //Startup checks
  displayShow(0x04, 0x54, 0x70);  //Message [int]
  delay(2000);                    //wait for stability

  //Fan test
  Serial.print("Fan Test ");
  int fan_voltage = analogRead(SENSE_FAN);
  Serial.print("Off: ");
  Serial.print(fan_voltage);
  digitalWrite(PIN_FAN, LOW);  // Fan On
  delay(2000);                 //wait for stability
  fan_voltage = analogRead(SENSE_FAN);
  Serial.print(" On: ");
  Serial.print(fan_voltage);
  digitalWrite(PIN_FAN, HIGH);  // Fan Off
  if (fan_voltage < MIN_FAN_VALUE) {
    displayShow(0x79, 0x40, 0x71);  //Message [E-F]
    Serial.println("ERROR: active minimum low");
    while (1)
      ;  //stop
  }
  delay(2);  //wait for decay
  int fan_hold = analogRead(SENSE_FAN);
  Serial.print(" Hold: ");
  Serial.print(fan_hold);
  float ratio = (float)fan_hold / (float)fan_voltage;
  Serial.print(" Ratio: ");
  Serial.println(ratio);
  if (ratio > SAFE_DISCHARGE_RATIO) {
    displayShow(0x79, 0x40, 0x71);  //Message [E-F]
    Serial.println("ERROR: Fan load low, check connection");
    while (1)
      ;  //stop
  }
  Serial.println("PASS");

  //Temp sensor check
  int temp_sensor = analogRead(SENSE_TEMP);
  Serial.print("Temp Sensor Test: ");
  Serial.println(temp_sensor);
  if (temp_sensor > 800) {  //900 is no sensor lecture
    Serial.println("ERROR: Temp Sensor");

    displayShow(0x79, 0x40, 0x6D);  //Message [E-S]
    delay(1000);
    while (1)
      ;  //stop
  } else Serial.println("PASS");

  // Hotair Gun mag switch presence
  if (digitalRead(MAG_SW)) {  // HIGH = gun not in place or fail switch
    Serial.println("Hot Air Gun magnetic switch is open\r\nCheck position in the base");
    displayShow(0x7D, 0x1C, 0x54);  //Message [Gun]
    while (digitalRead(MAG_SW))
      ;  //wait until is in place.
  }
  Serial.println("Gun detected in the base");

  //Heat element test
  digitalWrite(PIN_FAN, LOW);  //fan on
  if (temp_sensor > 40) Serial.println("Too hot to test, waiting. . . ");
  while (temp_sensor > 40) {  //wait if is hot
    temp_sensor = analogRead(SENSE_TEMP);
  }
  Serial.print("Heat Element Test Temp 1: ");
  temp_sensor = analogRead(SENSE_TEMP);
  Serial.print(temp_sensor);
  digitalWrite(HEAT_ELEMENT, LOW);   //heat on
  delay(2000);                       //delay to heat
  digitalWrite(HEAT_ELEMENT, HIGH);  //off
  Serial.print(" Temp 2: ");
  int new_temp_sensor = analogRead(SENSE_TEMP);
  Serial.println(new_temp_sensor);
  if ((new_temp_sensor - temp_sensor) > 15) {
    Serial.println("PASS");
    displayShow(0x50, 0x5E, 0x6E);  //Message [rdY]
    Serial.println("Ready");
    delay(1000);
  } else {
    displayShow(0x79, 0x40, 0x76);  //Message [E-H]
    Changing_Settings_Timeout = 10000 / TIMER_INTERVAL_MS;
     Serial.println("Verify heater element");
  }
}
#define SAMPLES_TO_AVERAGE 64
int SamplerIndex = 0;
int SamplerArray[SAMPLES_TO_AVERAGE] = { 0 };
void loop() {
  // put your main code here, to run repeatedly:
  temp = analogRead(SENSE_TEMP);
  speed = analogRead(SENSE_FAN);

  if (Serial.available() != 0) {
    int tvar = Serial.parseInt();
    heater = tvar;
    Changing_Settings_Timeout = SETTINGS_TIMEOUT / TIMER_INTERVAL_MS;
  }
  if (digitalRead(MAG_SW)) {
    digitalWrite(PIN_FAN, LOW);
    if (temp > heater) {
      digitalWrite(HEAT_ELEMENT, HIGH);
      if (temp > TEMP_LIMIT) criticalError();
    } else {
      digitalWrite(HEAT_ELEMENT, LOW);
    }

  } else {
    digitalWrite(HEAT_ELEMENT, HIGH);
    if (temp < SAFE_TEMP) digitalWrite(PIN_FAN, HIGH);
    //else digitalWrite(PIN_FAN, LOW);
  }
  Serial.print(temp);
  Serial.print(" ");
  Serial.print(speed);
  Serial.print(" ");
  Serial.println(heater);

  /* Average samples */
  SamplerArray[SamplerIndex] = temp;
  if (SamplerIndex < SAMPLES_TO_AVERAGE) SamplerIndex++;
  else SamplerIndex = 0;
  int sigmaTemp = 0;
  for (int i = 0; i < SAMPLES_TO_AVERAGE; i++) {
    sigmaTemp += SamplerArray[i];
  }
  //int tempAvg = sigmaTemp / SAMPLES_TO_AVERAGE;
  int tempAvg = sigmaTemp >> 6;  // DIV 64
  if (Changing_Settings || Changing_Settings_Timeout) {
    displayNumber(calTable[heater]);
  } else {
    if(tempAvg < SAFE_TEMP && digitalRead(MAG_SW)==LOW) displayShow(0x40, 0x40, 0x40);
    else displayNumber(calTable[tempAvg]);
  }
}

Durante el encendido hay una secuencia de revisión
1: Mide el voltaje en el ventilador, si es demasiado bajo (posible corto) o si la caída de voltaje es baja cuando lo enciende (posible circuito abierto) aparecerá el error [E-F] en la pantalla y se detiene.
2: Valida la lectura del sensor de temperatura, 900 es sin presencia, el margen está en 800 por ahora, si se excede muestra el código [E-S] y se detiene.
3: Verifica el interruptor magnético en la pistola, si esta no se encuentra en la base aparece el mensaje [Gun], entonces espera hasta que se coloque, si no lo detecta aún después entonces hay que revisar que le pasó al interruptor.
4: Hace una prueba de encendido, básicamente enciende el ventilador y toma una muestra de la temperatura, luego enciende la resistencia 2 segundos y vuelve a medir esperando detectar el incremento, si no ocurre aparecerá el mensaje en pantalla [E-H] durante 10 segundos, un detalle de este es que no sabría que tanto le afecta la temperatura ambiente al margen, así que este error no detiene el funcionamiento.

Durante el funcionamiento si por cualquier razón, se supera cierto límite de la temperatura, aparecerá [E-C], entonces se desactiva la resistencia y el ventilador queda encendido, esto también bloquea la estación así que requiere un reinicio, aquí queda a discreción si apagarla o permitirle enfriarla, generalmente no es buena idea apagarlas de inmediato por que se acumula el calor y puede ocurrir daños. Este caso es excepcional ya que el control tiene un margen superior en 229 en la rutina (en teoría 300ºC), por lo que no debería llegar a esa lectura, pero no está demás, por serial aún puedo establecer una temperatura mayor, aunque esta no se mostrará correctamente en pantalla cuando excede la tabla de calibración.

Realmente establecer esos valores necesita realizar algunas pruebas por ahora establecí estos, noten que los valores son los del ADC no en grados ya que hacer divisiones retrasaría la ejecución.
#define TEMP_LIMIT 500 //Limite de temperatura
#define SAFE_TEMP 40 //Temperatura segura en la cual se apaga el ventilador
#define MIN_FAN_VALUE 60 //Valor mínimo esperado en el ventilador, se toma el de velocidad mínima y se considera un umbral
#define SAFE_DISCHARGE_RATIO 0.75f // umbral de relación entre el voltaje encendido y el medido 2ms después de apagar el ventilador si la descarga se aproxima a 1 significa que el voltaje se retiene solo por el condensador del circuito, no se detecta el consumo esperado del ventilador. En mis pruebas conectado el mínimo rondaba 0.5, si desconectaba el ventilador era entre 0.82 y 0.9 dependiendo del valor en el potenciómetro.

Quizá luego mejoro la comunicación, por ahora solo sirve para que la estación reporte constantemente los valores y se pueda monitorear, al menos hasta que haga todas las pruebas y esté bien calibrado todo. Ocupo primero conseguir un termómetro que me permita lectura sobre los 200ºC para eso, pero no tengo intenciones de abrirla de nuevo hasta entonces.
 
Bueno, la ves pasada literal solo envolví el UNO y se lo lancé adentro con todos los cables XD
WP_20231004_15_39_40_Pro.jpg
Ya estuve soldando hoy el Pro Mini que iba a ocupar, lo hice en una placa que permitiría futuros complementos si alguna vez se me ocurre ponerle el sensor externo. También le puse resistencias de 330 a los pines de cátodo del display para evitar esa aberración del fabricante usando una al ánodo común, el brillo ahora es más uniforme comparado a como estaba cuando un dígito brillaba más que otro. También otra de 12k al que va hacía el interruptor magnético para evitar que vuelva a ocurrir la misma situación, como son 0805 quedaron todas debajo del Arduino.
vlcsnap-2023-10-21-05h06m47s257.png
En la nueva versión del firmware, agregué una opción para deshabilitarlo manualmente aun cuando no está en la base, aunque esa solo funciona cuando se controla por el serial, pero me permite ahora montarla en un soporte y justo tenía uno de micrófono que era demasiado grande para mis micrófonos, tanto que sujeta bien la pistola, cuenta con la misma función de solo apagar el ventilador en una temperatura segura.
DSC00267.JPG
También le hice una app con el GUI Composer de Texas Instruments por lo que el código agrega JSON para manejar los mensajes como lo requiere la app.
appControl.gif
La temperatura promedio es la calculada por el Arduino por lo que coincide con el valor en pantalla mientras envía el stream con la última lectura para revisarlo. El dial se actualiza con el valor objetivo del Arduino pro si lo mueves en la app, también se sincroniza y este actualiza el nuevo valor. Ahora las transferencias usan el valor de la tabla en lugar del ADC excepto para el caso del ventilador, pero es que ahí no tengo control, podría calcularlo con la relación de voltaje de ser necesario.
Lo único que necesito ver es como controlar la curva porque cuando incrementas la temperatura, esta sube considerablemente antes de establecerse, creo que el problema es la transferencia ya que esta no es inmediata por lo que el sensor tarda un poco y causa esto:
Video sin título ‐ Hecho con Clipchamp (2).gif
Fuera de esos cambios grandes es relativamente estable así que creo que no debería afectar mucho, ahora solo falta el script para que genere las curvas por sí solo.
Nuevo código del Arduino
C++:
//Pin DEF
#define DISPLAY_C 2
#define DISPLAY_D 3
#define DISPLAY_E 4
#define DISPLAY_F 5
#define DISPLAY_G 6
#define DISPLAY_DP 7
#define DISPLAY_A 8
#define DISPLAY_B 9
#define PIN_FAN 10  //PWM
#define DISPLAY_1 11
#define DISPLAY_2 12
#define DISPLAY_3 A1
#define HEAT_ELEMENT 13
#define FAN_ON LOW
#define FAN_OFF HIGH
#define HEAT_ON LOW
#define HEAT_OFF HIGH

#define SENSE_FAN A2    //Analog
#define SENSE_TEMP A3   //Analog
#define BUTTON_UP A5    //I2C
#define BUTTON_DOWN A4  //I2C
#define MAG_SW A0

#define USE_TIMER_1 true
#include "TimerInterrupt.h"
#define TIMER_INTERVAL_MS 5
#define DEBOUNCING_INTERVAL_MS 200
#define LONG_PRESS_INTERVAL_MS 1000
#define LONG_PRESS_INTERVAL_DIV 10
#define SETTINGS_TIMEOUT 3000

#define TEMP_LIMIT 500
#define SAFE_TEMP 40
#define MIN_FAN_VALUE 60
#define SAFE_DISCHARGE_RATIO 0.75f
const int calTable[] = {  //Calibration table, temperature by value on ADC
  32, 33, 35, 36, 37, 38, 39, 40,
  42, 43, 44, 45, 46, 47, 49, 50,
  51, 52, 53, 54, 56, 57, 58, 59,
  60, 61, 63, 64, 65, 66, 67, 68,
  70, 71, 72, 73, 74, 75, 77, 78,
  79, 80, 81, 83, 84, 85, 86, 87,
  88, 90, 91, 92, 93, 94, 95, 97,
  98, 99, 100, 101, 102, 104, 105, 106,
  107, 108, 109, 111, 112, 113, 114, 115,
  116, 118, 119, 120, 121, 122, 123, 125,
  126, 127, 128, 129, 131, 132, 133, 134,
  135, 136, 138, 139, 140, 141, 142, 143,
  145, 146, 147, 148, 149, 150, 152, 153,
  154, 155, 156, 157, 159, 160, 161, 162,
  163, 164, 166, 167, 168, 169, 170, 172,
  173, 174, 175, 176, 177, 179, 180, 181,
  182, 183, 184, 186, 187, 188, 189, 190,
  191, 193, 194, 195, 196, 197, 198, 200,
  201, 202, 203, 204, 205, 207, 208, 209,
  210, 211, 212, 214, 215, 216, 217, 218,
  220, 221, 222, 223, 224, 225, 227, 228,
  229, 230, 231, 232, 234, 235, 236, 237,
  238, 239, 241, 242, 243, 244, 245, 246,
  248, 249, 250, 251, 252, 253, 255, 256,
  257, 258, 259, 260, 262, 263, 264, 265,
  266, 268, 269, 270, 271, 272, 273, 275,
  276, 277, 278, 279, 280, 282, 283, 284,
  285, 286, 287, 289, 290, 291, 292, 293,
  294, 296, 297, 298, 299, 300, 301, 303,
  304, 305, 306, 307, 308, 310, 311, 312,
  313, 314, 316, 317, 318, 319, 320, 321,
  323, 324, 325, 326, 327, 328, 330, 331
};

//buttons
volatile bool Changing_Settings = false;
volatile int Changing_Settings_Timeout = SETTINGS_TIMEOUT / TIMER_INTERVAL_MS;
volatile int Cycles_Div = LONG_PRESS_INTERVAL_DIV;

volatile bool Button_Up_Pressed = false;
volatile bool Button_Up_Release = false;
volatile bool Button_Up_Hold = false;
volatile int Button_Up_Cycles = 0;

volatile bool Button_Down_Pressed = false;
volatile bool Button_Down_Release = false;
volatile bool Button_Down_Hold = false;
volatile int Button_Down_Cycles = 0;


struct {
  const uint8_t dp = 0x80;  //  0     1     2     3     4     5     6     7     8     9     A     B     C     D     E     F
  const uint8_t numbers[16] = { 0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7D, 0x07, 0x7F, 0x6F, 0x77, 0x7C, 0x39, 0x5E, 0x79, 0x71 };
} Display7Seg;

#include <ArduinoJson.h>

volatile int temp = 0, speed = 0, heater = 0, Target = 0;
volatile bool Enabled = true;
volatile uint8_t displayBuffer[3] = { 0, 0, 0 };
volatile int displayIndex = 0;

void TimerHandler(void) {
  /***********************************
          Display MUX Section
  ***********************************/
  switch (displayIndex) {
    case 0:
      digitalWrite(DISPLAY_3, LOW);
      digitalWrite(DISPLAY_1, HIGH);
      break;
    case 1:
      digitalWrite(DISPLAY_1, LOW);
      digitalWrite(DISPLAY_2, HIGH);
      break;
    case 2:
      digitalWrite(DISPLAY_2, LOW);
      digitalWrite(DISPLAY_3, HIGH);
      break;
  }
  if (0x01 & displayBuffer[displayIndex]) digitalWrite(DISPLAY_A, HIGH);
  else digitalWrite(DISPLAY_A, LOW);
  if (0x02 & displayBuffer[displayIndex]) digitalWrite(DISPLAY_B, HIGH);
  else digitalWrite(DISPLAY_B, LOW);
  if (0x04 & displayBuffer[displayIndex]) digitalWrite(DISPLAY_C, HIGH);
  else digitalWrite(DISPLAY_C, LOW);
  if (0x08 & displayBuffer[displayIndex]) digitalWrite(DISPLAY_D, HIGH);
  else digitalWrite(DISPLAY_D, LOW);
  if (0x10 & displayBuffer[displayIndex]) digitalWrite(DISPLAY_E, HIGH);
  else digitalWrite(DISPLAY_E, LOW);
  if (0x20 & displayBuffer[displayIndex]) digitalWrite(DISPLAY_F, HIGH);
  else digitalWrite(DISPLAY_F, LOW);
  if (0x40 & displayBuffer[displayIndex]) digitalWrite(DISPLAY_G, HIGH);
  else digitalWrite(DISPLAY_G, LOW);
  if (0x80 & displayBuffer[displayIndex]) digitalWrite(DISPLAY_DP, HIGH);
  else digitalWrite(DISPLAY_DP, LOW);

  if (displayIndex == 2) displayIndex = 0;
  else displayIndex++;

  /***********************************
          Button Scan Section
  ***********************************/

  if (Button_Up_Pressed) {  //actions at Up button
    //Button already pressed
    Button_Up_Cycles++;  //increase the counter
    if (Button_Up_Cycles >= (DEBOUNCING_INTERVAL_MS / TIMER_INTERVAL_MS)) {
      if (digitalRead(BUTTON_UP)) {  //at release
        //button press action
        if (heater < 229) heater++;
        Button_Up_Pressed = false;
        Changing_Settings_Timeout = SETTINGS_TIMEOUT / TIMER_INTERVAL_MS;
        Changing_Settings = false;
        Button_Up_Cycles = DEBOUNCING_INTERVAL_MS / TIMER_INTERVAL_MS;
      } else {
        if (Button_Up_Cycles > (LONG_PRESS_INTERVAL_MS / TIMER_INTERVAL_MS)) {
          if (Cycles_Div) {
            Cycles_Div--;
          } else {
            Cycles_Div = LONG_PRESS_INTERVAL_DIV;
            if (heater < 229) heater++;
          }
        }
      }
    }
  } else {
    //Button not pressed
    if (digitalRead(BUTTON_UP) == false) {
      Button_Up_Pressed = true;
      Changing_Settings = true;
    }
  }

  if (Button_Down_Pressed) {  //actions at Down button
    //Button already pressed
    Button_Down_Cycles++;  //increase the counter
    if (Button_Down_Cycles >= (DEBOUNCING_INTERVAL_MS / TIMER_INTERVAL_MS)) {
      if (digitalRead(BUTTON_DOWN)) {  //at release
        //button press action
        if (heater > 0) heater--;
        Button_Down_Pressed = false;
        Changing_Settings_Timeout = SETTINGS_TIMEOUT / TIMER_INTERVAL_MS;
        Changing_Settings = false;
        Button_Down_Cycles = 0;
      } else {
        if (Button_Down_Cycles > (LONG_PRESS_INTERVAL_MS / TIMER_INTERVAL_MS)) {
          if (Cycles_Div) {
            Cycles_Div--;
          } else {
            Cycles_Div = LONG_PRESS_INTERVAL_DIV;
            if (heater > 0) heater--;
          }
        }
      }
    }
  } else {
    //Button not pressed
    if (digitalRead(BUTTON_DOWN) == false) {
      Button_Down_Pressed = true;
      Changing_Settings = true;
    }
  }
  if (Changing_Settings == false && Changing_Settings_Timeout) Changing_Settings_Timeout--;
}

// Raw byte to display buffer
void displayShow(uint8_t symbol1, uint8_t symbol2, uint8_t symbol3) {
  displayBuffer[0] = ~symbol1;
  displayBuffer[1] = ~symbol2;
  displayBuffer[2] = ~symbol3;
}

// uint16_t to display, max value is 999
void displayNumber(uint16_t val) {
  int cents = val / 100;
  if (cents < 10) displayBuffer[0] = ~Display7Seg.numbers[cents];
  else displayShow(0x40, 0x40, 0x40);  //Show [---] in overflow 999
  int x = val % 100;
  int dec = x / 10;
  if (dec < 10) displayBuffer[1] = ~Display7Seg.numbers[dec];
  int unit = x % 10;
  if (unit < 10) displayBuffer[2] = ~Display7Seg.numbers[unit];
}

void criticalError() {
  digitalWrite(HEAT_ELEMENT, HIGH);  //turn off heat element
  digitalWrite(PIN_FAN, LOW);        //keep fan on for safety
  displayShow(0x79, 0x40, 0x39);     //Message [E-C]
  Serial.println("####  Critical Error!!  ####\r\nTurn off manually");
  while (1)
    ;  //stop
}

void SysTest() {
  //Fan test
  Serial.print("Fan Test ");
  int fan_voltage = analogRead(SENSE_FAN);
  Serial.print("Off: ");
  Serial.print(fan_voltage);
  digitalWrite(PIN_FAN, LOW);  // Fan On
  delay(2000);                 //wait for stability
  fan_voltage = analogRead(SENSE_FAN);
  Serial.print(" On: ");
  Serial.print(fan_voltage);
  digitalWrite(PIN_FAN, HIGH);  // Fan Off
  if (fan_voltage < MIN_FAN_VALUE) {
    displayShow(0x79, 0x40, 0x71);  //Message [E-F]
    Serial.println("ERROR: active minimum low");
    while (1)
      ;  //stop
  }
  delay(2);  //wait for decay
  int fan_hold = analogRead(SENSE_FAN);
  Serial.print(" Hold: ");
  Serial.print(fan_hold);
  float ratio = (float)fan_hold / (float)fan_voltage;
  Serial.print(" Ratio: ");
  Serial.println(ratio);
  if (ratio > SAFE_DISCHARGE_RATIO) {
    displayShow(0x79, 0x40, 0x71);  //Message [E-F]
    Serial.println("ERROR: Fan load low, check connection");
    while (1)
      ;  //stop
  }
  Serial.println("PASS");

  //Temp sensor check
  int temp_sensor = analogRead(SENSE_TEMP);
  Serial.print("Temp Sensor Test: ");
  Serial.println(temp_sensor);
  if (temp_sensor > 800) {  //900 is no sensor lecture
    Serial.println("ERROR: Temp Sensor");

    displayShow(0x79, 0x40, 0x6D);  //Message [E-S]
    delay(1000);
    while (1)
      ;  //stop
  } else Serial.println("PASS");

  // Hotair Gun mag switch presence
  if (digitalRead(MAG_SW)) {  // HIGH = gun not in place or fail switch
    Serial.println("Hot Air Gun magnetic switch is open\r\nCheck position in the base");
    displayShow(0x7D, 0x1C, 0x54);  //Message [Gun]
    while (digitalRead(MAG_SW))
      ;  //wait until is in place.
  }
  Serial.println("Gun detected in the base");

  //Heat element test
  digitalWrite(PIN_FAN, LOW);  //fan on
  if (temp_sensor > 40) {
    Serial.println("Too hot to test, waiting. . . ");
    displayShow(0x76, 0x5C, 0x70);  //Message [Hot]
  }
  while (temp_sensor > 40) {  //wait if is hot
    temp_sensor = analogRead(SENSE_TEMP);
  }
  Serial.print("Heat Element Test Temp 1: ");
  temp_sensor = analogRead(SENSE_TEMP);
  Serial.print(temp_sensor);
  digitalWrite(HEAT_ELEMENT, LOW);   //heat on
  delay(2000);                       //delay to heat
  digitalWrite(HEAT_ELEMENT, HIGH);  //off
  Serial.print(" Temp 2: ");
  int new_temp_sensor = analogRead(SENSE_TEMP);
  Serial.println(new_temp_sensor);
  if ((new_temp_sensor - temp_sensor) > 15) {
    Serial.println("PASS");
    displayShow(0x50, 0x5E, 0x6E);  //Message [rdY]
    Serial.println("Ready");
    delay(1000);
  } else {
    displayShow(0x79, 0x40, 0x76);  //Message [E-H]
    Changing_Settings_Timeout = 10000 / TIMER_INTERVAL_MS;
    Serial.println("Verify heater element");
    while (temp_sensor > 40) {  //wait if is hot
      temp_sensor = analogRead(SENSE_TEMP);
    }
    digitalWrite(PIN_FAN, HIGH);  // Fan Off
    delay(10000);
  }
}

String inputString = "";      // a String to hold incoming data
bool stringComplete = false;  // whether the string is complete
void setup() {
  // put your setup code here, to run once:
  //Priority
  pinMode(HEAT_ELEMENT, OUTPUT);     //Set heater and disable
  digitalWrite(HEAT_ELEMENT, HIGH);  //off
  pinMode(PIN_FAN, OUTPUT);          //Fan
  digitalWrite(PIN_FAN, HIGH);
  //configure control inputs
  pinMode(MAG_SW, INPUT_PULLUP);
  pinMode(BUTTON_UP, INPUT_PULLUP);
  pinMode(BUTTON_DOWN, INPUT_PULLUP);

  heater = 58;

  //Config display pins
  pinMode(DISPLAY_A, OUTPUT);
  pinMode(DISPLAY_B, OUTPUT);
  pinMode(DISPLAY_C, OUTPUT);
  pinMode(DISPLAY_D, OUTPUT);
  pinMode(DISPLAY_E, OUTPUT);
  pinMode(DISPLAY_F, OUTPUT);
  pinMode(DISPLAY_G, OUTPUT);
  pinMode(DISPLAY_DP, OUTPUT);
  pinMode(DISPLAY_1, OUTPUT);
  pinMode(DISPLAY_2, OUTPUT);
  pinMode(DISPLAY_3, OUTPUT);

  Serial.begin(115200);
  inputString.reserve(60);

  ITimer1.init();
  if (ITimer1.attachInterruptInterval(TIMER_INTERVAL_MS, TimerHandler)) {
    Serial.println(F("Starting"));
  } else
    Serial.println(F("Can't set ITimer1. Select another freq. or timer"));

  //Startup checks
  displayShow(0x04, 0x54, 0x70);  //Message [int]
  delay(2000);                    //wait for stability
  SysTest();
}

#define SAMPLES_TO_AVERAGE 64
int SamplerIndex = 0;
int SamplerArray[SAMPLES_TO_AVERAGE] = { 0 };
int tempAvg = 0;

void loop() {
  // put your main code here, to run repeatedly:
  temp = analogRead(SENSE_TEMP);
  speed = analogRead(SENSE_FAN);

  if (stringComplete) {
    //int tvar = Serial.parseInt();
    //heater = tvar;
    StaticJsonDocument<24> filter;
    filter["Target"] = true;
    filter["Enabled"] = true;

    StaticJsonDocument<60> doc;

    DeserializationError error = deserializeJson(doc, inputString, DeserializationOption::Filter(filter));

    if (error) {
      Serial.print(F("deserializeJson() failed: "));
      Serial.println(error.f_str());
      return;
    }
    if (inputString.indexOf("Target") > 0) {
      Target = doc["Target"];  // 999
      int indexSearch = 0;
      while (Target > (calTable[indexSearch])) indexSearch++;
      if (indexSearch == 0) {
        heater = 0;
      } else if (indexSearch < (sizeof(calTable) / sizeof(calTable[0]))) {
        heater = indexSearch - 1;
      } else {
        heater = (sizeof(calTable) / sizeof(calTable[0])) - 1;
      }
    }
    if (inputString.indexOf("Enabled") > 0)
      Enabled = doc["Enabled"];  // 1
    Changing_Settings_Timeout = SETTINGS_TIMEOUT / TIMER_INTERVAL_MS;
    inputString = "";
    stringComplete = false;
  }
  if (digitalRead(MAG_SW) && Enabled) {
    digitalWrite(PIN_FAN, LOW);
    if (temp > heater) {
      digitalWrite(HEAT_ELEMENT, HIGH);
      if (temp > TEMP_LIMIT) criticalError();
    } else {
      digitalWrite(HEAT_ELEMENT, LOW);
    }

  } else {
    digitalWrite(HEAT_ELEMENT, HIGH);
    if (temp < SAFE_TEMP) digitalWrite(PIN_FAN, HIGH);
    //else digitalWrite(PIN_FAN, LOW);
  }
  Serial.print("{\"Target\": ");
  Serial.print(calTable[heater]);
  Serial.print(", \"Fan\": ");
  Serial.print(speed);
  Serial.print(", \"Status\": ");
  Serial.print(digitalRead(MAG_SW) ? 1 : 0);  //Active HIGH
  Serial.print(", \"Enabled\": ");
  Serial.print(Enabled ? 1 : 0);  //Active HIGH
  Serial.print(", \"Sensor\": ");
  Serial.print(calTable[temp]);
  Serial.print(", \"Avg\": ");
  Serial.print(calTable[tempAvg]);
  Serial.print(", \"Heater\": ");
  Serial.print(bitRead(PORTB, 5) ? 0 : 1);  //Active LOW Lectura de estado de pin
  Serial.println("}");

  /* Average samples */
  SamplerArray[SamplerIndex] = temp;
  if (SamplerIndex < SAMPLES_TO_AVERAGE) SamplerIndex++;
  else SamplerIndex = 0;
  int sigmaTemp = 0;
  for (int i = 0; i < SAMPLES_TO_AVERAGE; i++) {
    sigmaTemp += SamplerArray[i];
  }
  //int tempAvg = sigmaTemp / SAMPLES_TO_AVERAGE;
  tempAvg = sigmaTemp >> 6;  // DIV 64
  if (Changing_Settings || Changing_Settings_Timeout) {
    displayNumber(calTable[heater]);
  } else {
    if (tempAvg < SAFE_TEMP && digitalRead(MAG_SW) == LOW) displayShow(0x40, 0x40, 0x40);
    else displayNumber(calTable[tempAvg]);
  }
}

void serialEvent() {
  while (Serial.available()) {
    // get the new byte:
    char inChar = (char)Serial.read();
    // add it to the inputString:
    inputString += inChar;
    // if the incoming character is a newline, set a flag so the main loop can
    // do something about it:
    if (inChar == '\n') {
      stringComplete = true;
    }
  }
}
Un detalle en el nuevo mapeo de pines es que usé el pin 13 para controlar la resistencia, por una parte, me ayuda ver visualmente si intenta activarlo con el led de la placa, sin embargo, el bootloader causa que se encienda cuando este "apaga" el LED por lo que tenía conflictos, lamentablemente me enteré después de soldar todo, para corregirlo usé el UNO como ISP para programar el Pro sin utilizar el bootloader, con eso carga más rápido y evita encender la resistencia, antes incluso en la prueba de inicio me aparecía el mensaje [Hot] cuando apenas la encendía.

Una pequeña nota, para poder reportar el estado del calefactor (el LED rojo en el gráfico), en lugar de usar una variable leo el registro de salida, por lo que hay que considerar que esa parte no usa el lenguaje de Arduino y en su lugar emplea bitRead(PORTB, 5), para que pueda analizar el comportamiento mientras la optimizo me era necesario poder ver cuando la apaga.

Bueno, supongo que ahora ya puedo decir que sí está listo, sin un Arduino UNO entero ahí adentro.
 
Hola, tengo una estación ZENY 898D+ y el fallo que me empe a dar es que cuando voy a usar la pistola de calor, ejemplo : pongo 200 grados de temperatura y empieza a calentar bien pero cuando llega a los 200 grados se apaga la resistencia y no calienta casi nada, espero me puedan ayudar, gracias.
 

Adjuntos

  • 20231112_204054.jpg
    20231112_204054.jpg
    253.6 KB · Visitas: 0
¿Ese comportamiento ocurre en cualquier temperatura que estableces o solo al pasar los 200ºC? me refiero a si ocurre si lo estableces a 150ºC, por ejemplo. Eso podría indicar también fallo en el firmware como le pasó a la mía, en mi caso la entrada que detectaba el interruptor en la pistola se estaba comportando como salida a tierra por lo que no se activaba al removerla de la base.
 
Si,ocurre en cualquier temperatura,empieza calentando bien,pero al llegar a la temperatura deseada se desconecta la resistencia.
¿Ese comportamiento ocurre en cualquier temperatura que estableces o solo al pasar los 200ºC? me refiero a si ocurre si lo estableces a 150ºC, por ejemplo. Eso podría indicar también fallo en el firmware como le pasó a la mía, en mi caso la entrada que detectaba el interruptor en la pistola se estaba comportando como salida a tierra por lo que no se activaba al removerla de la base.
Uieru
 
Atrás
Arriba