Mosfet IRL520 siempre conduciendo

Buenas a todos, estoy intentando construirme un secador de filamento. Para hacere pruebas con el PID tengo preparado este código:

//Control temperatura con PID


#include <PID_v1.h>
#include <Wire.h>
#include "ClosedCube_HDC1080.h"
#define PIN_OUT 5    //pin de salida pwm
//Hardware connections for Arduino Uno:
//VDD to 3.3V DC
//SCL to A5
//SDA to A4
//GND to common ground

// Instancia a la clase
ClosedCube_HDC1080 hdc1080;

double Setpoint, Input, Output;


//Iniciar parametros
double Kp=7.0, Ki=0.1, Kd=0.00;

PID myPID(&Input, &Output, &Setpoint, Kp, Ki, Kd, DIRECT);

unsigned long previousMillis = 0;   
const long interval = 2000;   //Gr?fica cada 2 sergundos"

void setup(){
  
  Serial.begin(9600);
  
  hdc1080.begin(0x40);
 // Por defecto la precisión es de 14-bit para temperatura y humedad
 // Cambiar resolución
   hdc1080.setResolution(HDC1080_RESOLUTION_8BIT, HDC1080_RESOLUTION_11BIT);

  Setpoint = 35;//La temperatura que queremos mantener
  myPID.SetMode(AUTOMATIC);
}

void loop(){
  unsigned long currentMillis = millis();
  
 delay(2000);
 
 // La lectura de la temperatura o la humedad tarda unos 250 milisegundos

 // Leer temperatura y humedad del sensor
  double Input = hdc1080.readTemperature();
  double humedad = hdc1080.readHumidity();
  
	if (isnan(humedad) || isnan(Input)) {
	Serial.println("Fallo al leer hdc1080 sensor!");
	return;
	}
 
  myPID.Compute();
                    //Se hace el calculo por el PID
                    
  
  analogWrite(PIN_OUT, Output);

  if (currentMillis - previousMillis >= interval) {
   previousMillis = currentMillis;
   Serial.print(Input);// Línea temperatura
   Serial.print(",");
   Serial.print(36);   //linea referencia +1 grado
   Serial.print(",");   
   Serial.print(35);   //linea SetPoint
   Serial.print(","); 
   Serial.print(34);   //linea referencia -1 grado
   Serial.print(",");  
   Serial.println(Output/5);  //PWM/10 para mejor gráfica
   Serial.print(",");
  
   
  }  
}

El esquema que estoy utilizando es este.

Mis conocimientos de electrónica son muy básicos. El esquema esta basado en cosas que he ido viendo en internet.En una primerar versión no puse el 6N136, pero me llegaba la señal invertida y cuando quería que calentara, enfriaba y viceversa. por eso pense en poner el optoacoplador.

Seguro que esta todo muy mal pero hoy por hoy el principal problema es que el mosfet conduce ( le da corriente al calentador) aunque el arduino este desconectado. A ver si me podeís ayudar con todo un poco. Ah¡ el calentador consume 6A.

Hola,
¿El GND de la fuente de 12V está conectado al mismo "Bus" del GND del U1?
Para ayudar a "depurar" su circuito,
Con Arduino desconectado, indícanos los voltajes en los siguientes puntos:

  1. Colector Q1;
  2. Pin 6 de U1.
1 Like

Hay muchas formas de hacer que eso funcione sin usar el transitor 2n2222.
La mas simple es que en lugar que invierta el optoacoplador pues puedes conectarlo asi.
El pin 6 o colector del 6n136 a 5V.
El pin 5 o Emisor a la R de 2k2 y el otro extremo a GND.
Evista el transitor Q1 y conecta directamente R3 al pin 5.
Ahora veo que tienes un divisor con R3 de 1k y R2 de 100k. Yo quitaría ambos o al menos quitaría R3 de 1K, pero al hacerlo nos queda R2 en paralelo con 2k2 lo que esta de mas de nuevo asi que retiralo.
Entonces el circuito se simplifica asi

Salvando los cambios es lo mismo usando tus valores.

2 Likes

Si ruilviana, es una fuente ATX. Las medidas de voltajes hasta el lunes no las podre tomar.
Muchas gracias por tu atención

Muchas gracias Surbyte, además se que tengo algun PC817. El lunes lo pruebo.

No puse el esquema para que cambies de Optoacoplador. Da lo mismo uno u otro siempre que trabajen adecuadamente.
El esquema te lo mostré para que veas como se logra que en el caso de ese esquema si tu pones un 0 el led del PC817 conduce y el fototransitor satura, entonces tienes tensión Vgs para que el IRL540 conduzca.
En el caso anterior el arduino envia un HIGH pero lo hace en el ánodo y el cátodo esta a GND.
Asi que es lo mismo.

Perdonad la tardanza y gracias por vuestros consejos.
Bueno, creo que ya lo tengo, al menos el simulador de proteus no me da errores.
Ha caido un opto y algún mosfet por el camino. No conocia el simulador de proteus¡¡

Os pongo el esquema a ver si veís algo raro.
Tambien he cambiado el código...

Con el circuito en off

la versión sin transistor:

Con la señal invertida, claro.

La R3 es de 1K8 (que no se ve).

El código lo utilicé usando el irl520 directamente al arduino así:

El código para el Autotune:

// ************************************************************************************
// **                                BASADO EN:                                      **
// ************************************************************************************
// ** https://github.com/br3ttb/Arduino-PID-Library                                  **
// ** https://github.com/br3ttb/Arduino-PID-AutoTune-Library                         **
// ** De Brett Beauregard                                                            **
// ** y en los ejemplos                                                              **
// ** https://www.megunolink.com/articles/malt-kiln/                                 **
// ** de Richard Oliver                                                              **
// ** y                                                                              **
// ** https://www.homebrewtalk.com/threads/pid-settings-on-arduino-based-hlt.328239/ **
// ** Post 11 del usuario chuckjaxfl                                                 **
//*************************************************************************************

#include <PID_v1.h>
#include <PID_AutoTune_v0.h>
#include <Wire.h>
#include "ClosedCube_HDC1080.h"
#include <max6675.h>

// digital pin connections
#define heaterPin 5
#define motorPin 8

const uint8_t thermoDO = 12;
const uint8_t thermoCS = 10;
const uint8_t thermoCLK = 13;


// Instancia a la clase
ClosedCube_HDC1080 hdc1080;
MAX6675 thermocouple(thermoCLK, thermoCS, thermoDO);

//Initialize PID

byte ATuneModeRemember=2;
double input=20, output=  2500, setpoint=65;
double kp=5000,ki=4.64,kd=0;
double input1;

double aTuneStep=500, aTuneNoise=1, aTuneStartValue=500;
unsigned int aTuneLookBack=20;

//boolean tuning = false;
boolean tuning = true;
unsigned long  modelTime, serialTime;

PID myPID(&input, &output, &setpoint,kp,ki,kd, DIRECT);
PID_ATune aTune(&input, &output);
int pidWindowSize = 3000;
unsigned long pidWindowStartTime;
double pidWindowOutput;

void setup()
{
  
  pinMode(heaterPin,OUTPUT);
  pinMode(motorPin,OUTPUT);
  //pinMode(PIN_INPUT,INPUT);
 digitalWrite(motorPin, LOW);

  //Setup the pid 
  myPID.SetMode(AUTOMATIC);
  myPID.SetOutputLimits(0, pidWindowSize);
  pidWindowStartTime = millis();

  if(tuning)
  {
    tuning=false;
    changeAutoTune();
    tuning=true;
  }

  serialTime = 0;
  Serial.begin(9600);
  hdc1080.begin(0x40);
  hdc1080.setResolution(HDC1080_RESOLUTION_8BIT, HDC1080_RESOLUTION_11BIT);
}

void loop()
{
  digitalWrite(motorPin,LOW);
  unsigned long now = millis();

  input = thermocouple.readCelsius();
  input1 =  hdc1080.readTemperature(); //Para comparar temperaturas
  if (isnan(input)) 
 {
 Serial.println("Fallo al leer MAX6675 sensor!");
  return;
 }
    

  if(tuning)
  {
    byte val = (aTune.Runtime());
    
    if (val!=0)
    {
      tuning = false;
      //tuning = true;
    }

    
    if(!tuning)
    { 
      ki = aTune.GetKi();
      kd = aTune.GetKd();
      myPID.SetTunings(kp,ki,kd);
      AutoTuneHelper(false);
    }
  }
  else myPID.Compute();

  setRelayState(heaterPin); 

  //send-receive with processing if it's time
  if(millis() > serialTime)
  {
    SerialReceive();
    SerialSend();
    serialTime+=500;
  }
}

void changeAutoTune()
{
 if(!tuning)
  {
    //Set the output to the desired starting frequency.
    output=aTuneStartValue;
    aTune.SetNoiseBand(aTuneNoise);
    aTune.SetOutputStep(aTuneStep);
    aTune.SetLookbackSec((int)aTuneLookBack);
    AutoTuneHelper(true);
    tuning = true;
  }
  else
  { //cancel autotune
    aTune.Cancel();
    tuning = false;
    AutoTuneHelper(false);
  }
}

void AutoTuneHelper(boolean start)
{
  if(start)
    ATuneModeRemember = myPID.GetMode();
  else
    myPID.SetMode(ATuneModeRemember);
}

void SerialSend()
{
  Serial.print("setpoint: ");Serial.print(setpoint); Serial.print(" ");
  Serial.print("input: ");Serial.print(input); Serial.print(" ");Serial.print("inputhdc: ");Serial.print(input1);
  Serial.print("output: ");Serial.print(output/1000); Serial.print(" ");
  if(tuning){
    Serial.println("tuning mode");
  } else {
    Serial.print("kp: ");Serial.print(myPID.GetKp()/1000);Serial.print(" ");
    Serial.print("ki: ");Serial.print(myPID.GetKi());Serial.print(" ");
    Serial.print("kd: ");Serial.print(myPID.GetKd());Serial.println();
  }
  delay(500);
}


void SerialReceive()
{
  if(Serial.available())
  
  {
   char b = Serial.read();
   
    Serial.flush(); // Serial.flush()lo que hace es esperar a que el envío de salida de los datos serie se complete. 

    if((b=='1' && !tuning) || (b!='1' && tuning))changeAutoTune();
  }
}

void setRelayState(int Pin)
  {
     if(millis() - pidWindowStartTime > pidWindowSize)
      { //time to shift the Relay Window
        pidWindowStartTime += pidWindowSize;
        pidWindowOutput = output;

      }

    if(pidWindowOutput > millis() - pidWindowStartTime) 
      {
        digitalWrite(Pin,HIGH);
      }
    else 
      {
        digitalWrite(Pin,LOW);
        
      }
  }

El codigo de funcionamiento:

// ************************************************************************************
// **                                BASADO EN:                                      **
// ************************************************************************************
// ** https://github.com/br3ttb/Arduino-PID-Library                                  **
// ** https://github.com/br3ttb/Arduino-PID-AutoTune-Library                         **
// ** De Brett Beauregard                                                            **
// ** y en los ejemplos                                                              **
// ** https://www.megunolink.com/articles/malt-kiln/                                 **
// ** de Richard Oliver                                                              **
// ** y                                                                              **
// ** https://www.homebrewtalk.com/threads/pid-settings-on-arduino-based-hlt.328239/ **
// ** Post 11 del usuario chuckjaxfl                                                 **
//*************************************************************************************

#include <PID_v1.h>
#include <Wire.h>
#include "ClosedCube_HDC1080.h"
#include <max6675.h>
 
// digital pin connections

#define heaterPin 5

const uint8_t thermoDO = 12;
const uint8_t thermoCS = 10;
const uint8_t thermoCLK = 13;
 
//declare functions

void setRelayState(int Pin);

// Instancia a las clases
ClosedCube_HDC1080 hdc1080;
MAX6675 thermocouple(thermoCLK, thermoCS, thermoDO);


 
//Initialize PID
double pidSetpoint, pidInput, pidOutput, pidWindowOutput;
PID heaterPID(&pidInput, &pidOutput, &pidSetpoint, 5000, 4.24, 65, DIRECT);
int pidWindowSize = 3000;
unsigned long pidWindowStartTime;
double TempHDC, HumHDC;

 
void setup() 
  {
    Serial.begin(9600);
	
    pinMode(heaterPin,OUTPUT);
 
    delay(2000);
 
    heaterPID.SetMode(AUTOMATIC);
    heaterPID.SetOutputLimits(0, pidWindowSize);
    pidWindowStartTime = millis();
    
 
    
   //serialTime = 0;
   Serial.begin(9600);
   hdc1080.begin(0x40);
   hdc1080.setResolution(HDC1080_RESOLUTION_8BIT, HDC1080_RESOLUTION_11BIT);
       
		  }
 
void loop() 
  {
     pidInput = thermocouple.readCelsius();
     pidSetpoint = 65;
     TempHDC = hdc1080.readTemperature();
	   HumHDC= hdc1080.readHumidity();
 
    //pidInput = onTemp;
    heaterPID.Compute();
    setRelayState(heaterPin);
     
  }
 

 
void setRelayState(int Pin)
  {
    if(millis() - pidWindowStartTime > pidWindowSize)
      { //time to shift the Relay Window
        pidWindowStartTime += pidWindowSize;
        pidWindowOutput = pidOutput;
 
      }
 
    if(pidWindowOutput > millis() - pidWindowStartTime) 
      {
        digitalWrite(Pin,HIGH);
        //digitalWrite(Pin,LOW); para OPTO
      }
    else 
      {
        digitalWrite(Pin,LOW);
        //digitalWrite(Pin,HIGH); para OPTO
      }
	  
	Serial.print("Input:");Serial.print(pidInput);Serial.print(",");// Línea temperatura HDC1080
   Serial.print("TempHDC: ");Serial.print(TempHDC); Serial.print(" ");
   Serial.print("HumHDC: ");Serial.print(HumHDC); Serial.print(" ");
   Serial.print(66);Serial.print(",");//linea referencia +1 grado   
   Serial.print("SetPoint:");Serial.print(pidSetpoint);Serial.print(",");//linea SetPoint
   Serial.print(64);Serial.print(",");   //linea referencia -1 grado 
   Serial.print("Output:");Serial.print(pidOutput/1000);Serial.println(",");//PWM/1000 para mejor gráfica
   delay(500);

  }
 

Seguro que me dejo alguna cosilla pero en un recipiente de 7,5 litros y con un elemento calefactor de 100W me tarda aproximadamente 1 hora en estabilizar la temperatura a 65ºC. Ya he probado con una bobina de filamento PETG húmeda de hace un año y el resultado ha sido satisfactorio.

Espero mejores tiempos cambiando el elemento calefactor por uno de más potencia además de implementar el código para un encoder y un lcd.

Muchas gracias Surbyte y ruilviana¡¡¡

Es un placer contar con gente así.

Yo creo que la resistencia serie de 1K al Gate del MOSFET es demasiada alta. Pero dejala si ha funcionado.
En todo caso no tiene mucho sentido el divisor 1k y 10k en el Gate.
La R de 1K o mejor dicho la R serie se pone para evitar situaciones en las que el MOSFET se dañe y no circuile por Gate mas corriente del microcontrolador que la necesaria. Dudo que pase aquí. Suele ocurrir en conmutaciones de circuitos con inductores (bobinas).
Esa es mi única observación.
Los IRL se usan para alimentaciones de micros con 3.3 o 5V. Cuando tienes fuente de 12V un IRF520 funciona igual y es o debiera ser mas barato.
Son comentarios sutiles, no afectan al funcionamiento.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.