Problem with interrupt and timer millis/micros

Hello everyone after searching the web I bother you with the following problem: I am putting together a device to melt wax. It consists of a 220 v / 1000 watt resistor, a ds18b20 temperature sensor and a 16x2 lcd display.

Basically the program what it does is to read the interruptions (of an optocoupler, zero crossing ) and then to fire a triac to handle the 220v of the resistance through a PID controller. The problem arises when I plug in the 220v: the interrupts are triggered and the screen runs very slowly. When I read millis or micros, I see that they do not run properly and everything is very slow.

#include <Wire.h>
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27, 16, 2);

#include <OneWire.h>
#include <DallasTemperature.h>
#define ONE_WIRE_BUS 11
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);
DeviceAddress Termometro;

float temp = 0.0;

const byte rojo = 7;
const byte verde = 8;
bool estadoledv = true;
bool estadoledr = true;

const byte buzzer = 12;
bool estadobuzzer = false;

const byte interruptPin = 2;
const byte dimmer = 6;
int valor = 0;

byte setpoint = 0;

unsigned long tiempoactual = 0;
unsigned long tiempoanterior = 0;
unsigned long tiempoanterior2 = 0;
unsigned long tiempoanterior3 = 0;
unsigned long tiempoanterior4 = 0;
unsigned long tiempoanterior5 = 0;

const byte boton =  9;
bool pressed_1 = false;
volatile bool encender = false;
byte a = 1;

byte n = 0;

float PID_error = 0.0;
float previous_error = 0.0;
volatile int PID_value = 0;
// ORIGINAL!!! : byte kp = 203;   byte ki = 7.2;   byte kd = 1.04;
int kp = 1000;   byte ki = 0;   byte kd = 25;
byte PID_p = 0;    byte PID_i = 0;   byte PID_d = 0;


void setup() {
  lcd.begin();
  Wire.setClock(100000L);
  lcd.backlight();
  pinMode(rojo, OUTPUT);
  pinMode(verde, OUTPUT);
  inicio();
  pinMode(interruptPin, INPUT_PULLUP);
  attachInterrupt(digitalPinToInterrupt(interruptPin), interrupcion, RISING);
  pinMode(dimmer, OUTPUT);
  digitalWrite(dimmer, LOW);
  pinMode (boton, INPUT_PULLUP);
  pinMode (buzzer, OUTPUT);

  PCIFR |= (1 << PCIF0);
  PCICR |= (1 << PCIE0);
  PCMSK0 |= (1 << PCINT1);

  //  Serial.begin(115200);

  sensors.begin();
  sensors.getAddress(Termometro, 0);
  sensors.setResolution(Termometro, 9);

}

void loop() {

  tiempoactual = millis();

  if (tiempoactual - tiempoanterior2 >= 800 && a == 0) {
    a = 1;
  }

  if (tiempoactual - tiempoanterior3 >= 3000) {
    tiempoanterior3 = tiempoactual;
    n++;
    lcd.clear();
    if (n == 2) {
      n = 0;
    }
  }

  switch (n) {
    case 0:
      estado();
      break;

    case 1:
      temperatura();
      break;
  }


  if (tiempoactual - tiempoanterior >= 500) {
    tiempoanterior = tiempoactual;
    sensors.requestTemperatures();
    temp = sensors.getTempC(Termometro);

    if (encender) {
      previous_error = PID_error;
      PID_error = setpoint - temp;

      if (PID_error > 30)                             //integral constant will only affect errors below 30ºC
      {
        PID_i = 0;
      }

      PID_p = kp * PID_error;                         //Calculate the P value
      PID_i = PID_i + (ki * PID_error);               //Calculate the I value
      PID_d = kd * ((PID_error - previous_error) / 0.5); //Calculate the D value
      PID_value = 9200.0 - (PID_p + PID_i + PID_d);                      //Calculate total PID value

      //We define firing delay range between 0 and 7400. Read above why 7400!!!!!!!
      if (PID_value < 0)      {
        PID_value = 0;
      }

      if (PID_value > 9200)      {
        PID_value = 9200;
      }

      PID_value = 7000;

      // LOW VERDE
      PORTB &= B11111110;

      if (!estadoledr) {
        PORTD |= B10000000;
        //ROJO HIGH
      }
      else {
        //LOW ROJO
        PORTD &= B01111111;
      }
      estadoledr = !estadoledr;

    }

    else {
      // triac LOW
      PORTD &= B10111111;

      //LOW ROJO
      PORTD &= B01111111;

      if (!estadoledv) {
        PORTB |= B11000001;
        //VERDE HIGH
      }
      else {
        // LOW VERDE
        PORTB &= B11111110;
      }
      estadoledv = !estadoledv;

    }

    if (temp >= 30) {
      if (!estadobuzzer) {

        PORTB |= B11010000;
        //BUZZER HIGH
      }
      else {
        //BUZZER LOW
        PORTB &= B11101111;
      }
    }
    else {
      //BUZZER LOW
      PORTB &= B11101111;
    }
    estadobuzzer = !estadobuzzer;

  }
}


void interrupcion() {

  resistencia();

}

void resistencia() {

  if (encender) {

    delayMicroseconds(PID_value);

    // triac high
    PORTD |= B01000000;
    delayMicroseconds(100);
    // triac LOW
    PORTD &= B10111111;
  }
}









ISR(PCINT0_vect) {
  if (PINB & B00000010) {
    if (a == 1)    {
      encender = !encender;
      //Serial.println(encender);
      tiempoanterior2 = tiempoactual;
      a = 0;
    }
  }
}

void estado() {

  if (tiempoactual - tiempoanterior4 >= 150) {
    tiempoanterior4 = tiempoactual;
    lcd.setCursor(4, 0);
    lcd.print("Estado:");

    if (!encender) {
      lcd.setCursor(3, 1);
      lcd.print(" Detenido ");
    }
    else {
      lcd.setCursor(3, 1);
      lcd.print("Calentando");
    }
  }
}

void temperatura() {

  if (tiempoactual - tiempoanterior4 >= 100) {
    tiempoanterior4 = tiempoactual;
    lcd.setCursor(0, 0);
    lcd.print("Temp.:");
    lcd.setCursor(7, 0);
    lcd.print(temp);
    lcd.setCursor(13, 0);
    lcd.print((char)223);
    lcd.setCursor(14, 0);
    lcd.print("C");

    lcd.setCursor(3, 1);
    lcd.print("Set:");
    lcd.setCursor(8, 1);
    lcd.print(valor);
    lcd.setCursor(11, 1);
    lcd.print((char)223);
    lcd.setCursor(12, 1);
    lcd.print("C");


    valor =  analogRead(A0);
    valor = map(valor, 0, 1023, 27 , 31);
  }
}


void inicio() {

  PORTD |= B10000000;
  //ROJO HIGH
  PORTB |= B11000001;
  //VERDE HIGH
  lcd.setCursor(4, 0);
  lcd.print("INTRONIC");
  delay(1000);
  lcd.setCursor(0, 1);
  lcd.print("Iniciando...");
  delay(2000);
  lcd.clear();

  //LOW ROJO
  PORTD &= B01111111;
  // LOW VERDE
  PORTB &= B11111110;

}

The start and stop of the system is with a push button. The truth is I do not realize where I screw up ...

Thank you!!! (sorry for my bad english)

Don't use a delaymicroseconds in interrupt. Arm some unused timer and use its interrupt to switch a triac.

Do you really need such a complex control technique to melt wax? Have you tried a simple bang-bang controller with a little bit of hysteresis?

I agree, thats why I add:

void interrupcion() {

  resistencia();

}

void resistencia() {

  if (encender) {

    delayMicroseconds(PID_value);

    // triac high
    PORTD |= B01000000;
    delayMicroseconds(100);
    // triac LOW
    PORTD &= B10111111;
  }
}

To fire the triac out of the interrupt, it runs better, but not accurately :frowning: .

gfvalvo:
Do you really need such a complex control technique to melt wax? Have you tried a simple bang-bang controller with a little bit of hysteresis?

Yes, because here in Argentina, we are poor!!!, I need to save energy... The PID is the best option.

Total energy usage would be the same. For approximately constant temperature, Energy In = Heat Lost to Environment.

gfvalvo:
Total energy usage would be the same. For approximately constant temperature, Energy In = Heat Lost to Environment.

The system consists of two containers, one inside the other, with insulation in between. Anyway, I would like to leave the system running with PID control.

alesam:
Arm some unused timer and use its interrupt to switch a triac.

How? I've tried:

#include <TimerOne.h>
const byte interruptPin = 2;
const byte dimmer = 6;
int PID_value = 7000;

void setup() {
  attachInterrupt(digitalPinToInterrupt(interruptPin), interrupcion, RISING);
  pinMode(dimmer, OUTPUT);
  digitalWrite(dimmer, LOW);
  Timer1.initialize(10000);
  Timer1.disablePwm(9);
  Timer1.disablePwm(10);
  Timer1.attachInterrupt(nowIsTheTime, PID_value);
}

void loop() {
  // put your main code here, to run repeatedly:

}


void interrupcion() {

  // triac LOW
  PORTD &= B10111111;

  Timer1.restart();
  Timer1.attachInterrupt(nowIsTheTime, 9200);

}


void nowIsTheTime() {

  if (PID_value <= 9200) {

    // triac high
    PORTD |= B01000000;

  }

  if (PID_value >= PID_value + 100 ) {
    // triac LOW
    PORTD &= B10111111;

  }

}

But doesn't work.