Jump to content
Mihai3

Proiect statie de lipit cu Arduino Nano și control PID

Recommended Posts

Posted (edited)

Mi-am dorit de multă vreme să construiesc o stație de lipit care să folosească curentul alternativ ca și sursă de curent pentru alimentarea rezistenței letconului. Inițial am construit proiectul acesta: https://www.allaboutcircuits.com/projects/do-it-yourself-soldering-station-with-an-atmega8/?utm_source=eetech&utm_medium=eetech-social&utm_campaign=reposts-projects/ căruia i-am adăugat o protecție la supratemepratură.

Apoi am realizat proiectul acesta: https://www.instructables.com/id/DIY-Arduino-Soldering-Station/

Cu ajutor la scrierea programului, am realizat proiectul din această schemă: 

arduino_ss_schematic.thumb.png.7fb68eb16282600dc52523cfddc70b25.png

Explicațiile pentru schemă sunt: SV3 - avem conectați doar pinii A2 și A3 (veți vedea în program pentru că sunt folosiți la testare), SV1 - aici avem conectat un modul cu MAX6675 și SV2 - aici am conectat un LCD 1602, pe care se va afișa conform cu programul: temperatura setată din potențiometrul R7, temperatura aproximată a vârfului și [temperatura] citită de către MAX6675.

OK1 generează câte un impuls pentru fiecare trecere prin 0 a tensiunii alternative, K1 este un releu care oprește alimentarea rezistenței în momentul în care este depășită temperatura de 432 C sau atunci când este decuplat unul sau ambele fire de la termocuplu, partea de alimentare este formată din LM317 și L7805, iar elementul de forță este alcătuit din triacul BT138, care este controlat de pinul 7 al lui Arduino Nano V3. 

Pentru controlul temperaturii, am folosit un controller de tip PID, prin utilizarea în mediul Arduino IDE a librăriei <PID_v1.h>. La prima vedere, controlerul pare să funcționeze.

Programul implementat este: 

#include <PID_v1.h>
#include <LiquidCrystal.h>
#include <SPI.h>
#include <Wire.h>
#include <max6675.h>

#define thermoDO 12
#define thermoCS 10
#define thermoCLK 13
#define potentiometer A0
#define zerocrossing 2
#define triac 7
#define relay A1

#define test A2
#define test1 A3

int lowError = 0; //guessing for now.  The bigger these values the smaller the deadband either side of 0 error that constitues a 50% duty cycle
int highError = 220;

float temperature, realTemperature;
int pottemperature;
int counter;
int tempError = false;  // global error flag
int shownError = false; //flag to say error shown
int duty = 0; // variable for duty cycle

//PID constants
//double Kp = 5;
//double Ki = 0.25;
//double Kd = 0;

//Define the aggressive and conservative Tuning Parameters
double aggKp = 4, aggKi = 0.2, aggKd = 1;
double consKp = 1, consKi = 0.05, consKd = 0.25;


//PID variables
unsigned long currentTime, previousTime;
double elapsedTime;
double error;
double lastError;
double input, output, setPoint;
double cumError, rateError;

PID myPID(&input, &output, &setPoint, consKp, consKi, consKd, DIRECT);


byte thermometer[8] = //icon for termometer
{
  B00100,
  B01010,
  B01010,
  B01110,
  B01110,
  B11111,
  B11111,
  B01110
};

byte arrow[8] = //icon for arrow
{
  B11000,
  B01100,
  B00110,
  B00011,
  B00011,
  B00110,
  B01100,
  B11000
};

MAX6675 thermocouple(thermoCLK, thermoCS, thermoDO);

/*  The circuit:
   LCD RS pin to digital pin 12
   LCD Enable pin to digital pin 11
   LCD D4 pin to digital pin 5
   LCD D5 pin to digital pin 4
   LCD D6 pin to digital pin 3
   LCD D7 pin to digital pin 2
   LCD R/W pin to ground
   LCD VSS pin to ground
   LCD VCC pin to 5V
   10K resistor:
   ends to +5V and ground
   wiper to LCD VO pin (pin 3)
*/

LiquidCrystal lcd(3, 4, 5, 6, 8, 9);

// added stuff to log temperatures on serial monitor
// change loop time management from simple delay

#define PRINTRATE 100
#define DISPLAYRATE 250

char textbuf[100]; //buffer for data to send
unsigned long serialTime = millis(); //sending interval for data
unsigned long displayTime = serialTime;  //display interval for LCD
int pt; //local store for pot and iron temperatures;
int tmp;
double err, cErr, rErr, op;
int dty;

void setup() {
  myPID.SetMode(AUTOMATIC);
  myPID.SetOutputLimits(0, 220);
  Serial.begin(115200); // or faster if your Arduino/PC can handle it...
  pinMode(test, OUTPUT);
  pinMode(test1, OUTPUT);
  lcd.createChar(0, thermometer);
  lcd.createChar(1, arrow);
  lcd.begin(16, 2);
  lcd.setCursor(0, 0);
  lcd.print("STATIE DE LIPIT");
  output = 0;
  setPoint = 0;
  delay(1200);
  lcd.clear();
  pinMode(relay, OUTPUT);
  pinMode(potentiometer, INPUT);
  pinMode(zerocrossing, INPUT_PULLUP);
  pinMode(triac, OUTPUT);
  digitalWrite(triac, LOW);
  digitalWrite(relay, HIGH);
  realTemperature = thermocouple.readCelsius();
  temperature = 0.779828 * realTemperature - 10.3427;
  input = temperature;
  //updateDisplay();
  attachInterrupt(digitalPinToInterrupt(2), zero, RISING);
}



void loop() {
  if (millis() > serialTime + PRINTRATE) { //send serial data every PRINTRATE mS
    noInterrupts(); // make sure our local copies are not corrupted while copying them over from ISR
    tmp = temperature;
    pt = pottemperature;
    err = error;
    cErr = cumError;
    rErr = rateError;
    op = output;
    dty = duty;
    interrupts();
    sprintf(textbuf, "Time: %lu, Set: %4u, Temp: %4u", millis() / 100, pt, tmp); //format the print string
    Serial.print(textbuf);
    sprintf(textbuf, ", error: %.9g, cumErr: %.9g, rateErr: %.9g, output: %.9g, duty: %3u", err, cErr, rErr, op, dty);
    Serial.println(textbuf); //send to serial monitor, about 3mS @ 115200
    serialTime += PRINTRATE;
  }

  if (millis() > displayTime + DISPLAYRATE) { //update display every DISPLAYRATE mS
    if (!tempError) {  // if no error
      updateDisplay();
    } else // do something on error
    {
      // eg show the word error on the display
      if (!shownError) { // we've not shown error yet, so show it
        displayErrors();
        shownError = true; //set flag so don't show it again
      }
    }
    displayTime += DISPLAYRATE;
  }
}

void zero() {
  counter++;
  //*** change this line below
  if (counter > duty) { //reach duty cycle limit, unless duty was 25 in which case leave on until next duty calculated later
    digitalWrite(triac, LOW);
  }

  if (counter >= 25) {
    counter = 0;
    digitalWrite(test, HIGH); //this will generate a pulse on test pin (5) every 250mS to prove counter incrementing...
    pottemperature = analogRead(potentiometer);
    pottemperature = map(pottemperature, 0, 1023, 150, 400);
    setPoint = pottemperature;
    digitalWrite(test, LOW); // put test pin low
    realTemperature = thermocouple.readCelsius();
    temperature = int(0.779828 * realTemperature - 10.3427); // make temperature an integer
    input = temperature;
    if (tempError || isnan(realTemperature) || temperature >= 432) { // on error kill power & set global error flag
      digitalWrite(relay, LOW); // turn off power to iron
      //*** add this line below just in case
      digitalWrite(triac, LOW);
      tempError = true; //set error flag. can only be unset outside ISR. Once set no further action taken till unset in main loop.
    }
    else { //reading valid
      //***      if (temperature < pottemperature) { //*** remove this line and allow errors to be both + and -
      digitalWrite(test1, HIGH);  // *** changed, generate a pulse on test1 (D6) when reading valid
      //error = pottemperature - temperature;  // *** +ve error when low = increase duty cycle, -ve error when high = decrease it

      double gap = abs(setPoint - input); //distance away from setpoint

      if (gap < 10)
      { //we're close to setpoint, use conservative tuning parameters
        myPID.SetTunings(consKp, consKi, consKd);
      }
      else
      {
        //we're far from setpoint, use aggressive tuning parameters
        myPID.SetTunings(aggKp, aggKi, aggKd);
      }

      myPID.Compute();
      //      error = map(error, lowError, highError, 0, 24);
      //      cumError += error * 250.0; //
      //      rateError = (error - lastError) / 250.0; //
      //      output = Kp * error + Ki * cumError + Kd * rateError; //output error needs to be mapped to a number between 0 and 24
      duty = map(output, lowError, highError, 0, 25); // *** lowError is const for fully off, highError is const for fully on. zero error maps to 50%
      duty = constrain(duty, 0, 25); // ***keep duty between 0 and 25 (25 = 100%)
      //*** re-arrange & add 3 lines
      if (duty > 0) {
        digitalWrite(triac, HIGH);
      } else {
        digitalWrite(triac, LOW);
      }
      lastError = error;
      digitalWrite(test1, LOW);
      //*** remove 3 lines
      //      }
      //      else {
      //        duty = 0;
      //      }//if (temperature
    }//if (tempError
  } //if(counter >= 25
}// zero()

void updateDisplay() {
  pottemperature = analogRead(potentiometer);
  pottemperature = map(pottemperature, 0, 1023, 150, 400);
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.write((byte)0);
  lcd.setCursor(2, 0);
  lcd.print((int)pottemperature);
  lcd.setCursor(6, 0);
  lcd.print((char)223); //degree sign
  lcd.setCursor(7, 0);
  lcd.print("C");
  lcd.setCursor(0, 1);
  lcd.write((byte)1);
  if (temperature <= 45) {
    lcd.setCursor(2, 1);
    lcd.print("Lo");
  } else {
    lcd.setCursor(2, 1);
    lcd.print((int)temperature);
  }
  lcd.setCursor(6, 1);
  lcd.print("[");
  lcd.setCursor(7, 1);
  lcd.print((int)realTemperature);
  lcd.setCursor(10, 1);
  lcd.print("]");
  lcd.setCursor(12, 1);
  lcd.print((char)223);
  lcd.setCursor(13, 1);
  lcd.print("C");
}

void displayErrors() {
  digitalWrite(relay, LOW); // the relay will disconnect the power to the soldering iron heating element
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.write((byte)0);
  lcd.setCursor(1, 0);
  lcd.write((byte)0);
  lcd.setCursor(5, 0);
  lcd.print("ERROR!");
  lcd.setCursor(14, 0);
  lcd.write((byte)0);
  lcd.setCursor(15, 0);
  lcd.write((byte)0);
}

 

Am 2 întrebări în ceea ce privește programul (codul) implementat: 

1. Observ pe osciloscop că tranziția de la 0 logic la 1 logic (0V - 5V) de pe pinul 7 (albastru pe imagine) al lui Arduino, se face cu o întârziere de aproximativ 1 mS față de impulsul care il primește pe pinul 2 (galben pe imagine). În ce măsură afectează această întârziere funcționarea circuitului ? 

DS0110.jpg.72405a68acb7f4bc69c9d4017c4549d6.jpg

În timp ce tranziția de la 1 la 0 se face la momentul potrivit:

DS0111.jpg.15a3d986ea03ac86037d7a35e9c81144.jpg

Pe rezistența letconului:

DS0116.jpg.97aabe03cdbc8c8f6490b1b4db7f1717.jpg

2. Ce parere aveti despre cod ? Eu am adăugat numai partea cu implementarea PID-ului. 

Acesta este rezultatul (albastru = setpoint și roșu = temperatura letconului):

pid_aac.thumb.jpg.891fae2407d37a418fd3d50bff1fd1ab.jpg

Vă mulțumesc pentru eventualele sfaturi/observații/comentarii. 😀

Urmează și partea cu realizarea practică a stației, dar mai întâi aș dori să rezolv problemele prezentate.

Dacă există informații neclare sau incomplete, vă rog să îmi spuneți și voi încerca să clarific.

Edited by Mihai3
  • Like 2
  • Thanks 1

Share this post


Link to post
Share on other sites

Chiar imi place ceea ce vad. Un topic extraordinar. Si om mai mult ca sigur... asemenea topicului!

1. intarzierea prelucrarii informatiei o poate impune soft-ul - de regula in orice bucla main a oricarui program se introduce o intarziere din mai multe motive, inclusiv pentru a nu lua in calcul mai multe apasari consecutive pe un comutator switch in acelasi timp;

2. am obsevat ca nu ai adaugat bucla MAIN !! Deci, revino cu niste completari la COD. Codul e creeat de tine sau copy-paste de pe net, sau si-si ?

Share this post


Link to post
Share on other sites
Posted (edited)

Mulțumesc !

Codul e și-și. Eu știam numai de bucla loop() și setup() la Arduino. Acum am citit că defapt, folosește main(), dar e ascuns ... 

int main(void)
{
	init();

	setup();
    
	for (;;) {
		loop();
	}
        
	return 0;
}    

 

Edited by Mihai3

Share this post


Link to post
Share on other sites
Posted (edited)

Bun topicul si buna aplicatia (produsul final) felicitari.

1. Loop in lumea lui Arduino e "main" in lumea normala

2. Ai un potential dezastru pentru ca ai prea mult cod in rutina de intrerupere. Calculul PID nu is are locul acolo pentru ca nu trebuie facut la ficare trecere prin zero (adica la 10ms). Singurul lucru care trebuie facut sincron cu trecerile prin zero sunt pornirea si oprirea triac-ului. Intarzierea de 1 ms e de fapt durata calculul pid so ce mai faci tu pe acolo. Daca tot ce faci acolo e sub 10ms e ok, daca e mai mult e dezastru. (de exemplu daca editezi functia de citire a temperaturii si bagi un delay de 12ms in ea o sa-ti dea peste cap timing-ul la intreruperea de zero. (adica o sa faci debug la o functie dar bug-ul  o sa fie in alta functie) - astea sunt cele mai nasoale situatii de facut debug.

Atata timp cat executi intreruperea in mai putin de 10 ms esti ok.

RR

PS - Executa un test de stres - pune letconul pe o bucata de cupru cat mai mare - sa urmareste temperatura daca sta unde trebuie (si invers atinge letconul de ceva care e fierbinte) - adica regim tranzitoriu.

 

Edited by roadrunner

Share this post


Link to post
Share on other sites
Posted (edited)

Mulțumesc !

Am modificat codul, cu siguranță se mai poate îmbunătăți, dar vreau sa întreb cum pot să fac astfel încât bucla loop() să primească parametrii PID și apoi să calculeze valoarea PID iar apoi în aceeași buclă loop() să se și apeleze funcția de afișare ? A doua întrebare este cum pot să verific dacă am scris corect funcția zero() ?

#include <LiquidCrystal.h>
#include <SPI.h>
#include <Wire.h>
#include <max6675.h>

#define thermoDO 12
#define thermoCS 10
#define thermoCLK 13
#define potentiometer A0
#define zerocrossing 2
#define triac 7
#define relay A1

volatile float temperature, realTemperature;  // I have declared those 2 variables as VOLATILE, because of using them inside and outside ISR
int pottemperature;
int counter;
int duty = 0; // variable for duty cycle

byte thermometer[8] = //icon for termometer
{
  B00100,
  B01010,
  B01010,
  B01110,
  B01110,
  B11111,
  B11111,
  B01110
};

byte arrow[8] = //icon for arrow
{
  B11000,
  B01100,
  B00110,
  B00011,
  B00011,
  B00110,
  B01100,
  B11000
};

MAX6675 thermocouple(thermoCLK, thermoCS, thermoDO);

/*  The circuit:
   LCD RS pin to digital pin 12
   LCD Enable pin to digital pin 11
   LCD D4 pin to digital pin 5
   LCD D5 pin to digital pin 4
   LCD D6 pin to digital pin 3
   LCD D7 pin to digital pin 2
   LCD R/W pin to ground
   LCD VSS pin to ground
   LCD VCC pin to 5V
   10K resistor:
   ends to +5V and ground
   wiper to LCD VO pin (pin 3)
*/

volatile int pidOut = 0;

double sensed_output, control_signal;
double setPoint;
double Kp; //proportional gain
double Ki; //integral gain
double Kd; //derivative gain
int T = 100; //sample time in milliseconds (ms)
unsigned long last_time = 0;
double total_error, last_error;
int max_control = 0;
int min_control = 240;

LiquidCrystal lcd(3, 4, 5, 6, 8, 9);

void setup() {
  lcd.createChar(0, thermometer);
  lcd.createChar(1, arrow);
  lcd.begin(16, 2);
  lcd.setCursor(0, 0);
  lcd.print("STATIE DE LIPIT");
  delay(1200);
  lcd.clear();
  pinMode(relay, OUTPUT);
  pinMode(potentiometer, INPUT);
  pinMode(zerocrossing, INPUT_PULLUP);
  pinMode(triac, OUTPUT);
  digitalWrite(triac, LOW);
  digitalWrite(relay, HIGH);
  realTemperature = thermocouple.readCelsius();
  temperature = 0.779828 * realTemperature - 10.3427;
  //updateDisplay();
  attachInterrupt(digitalPinToInterrupt(2), zero_crosss_int, RISING);
}

void loop() {  //moved the PID computations outside the ISR
  unsigned long current_time = millis(); //returns the number of milliseconds passed since the Arduino started running the program
  int delta_time = current_time - last_time; //delta time interval
  pottemperature = analogRead(potentiometer);
  pottemperature = map(pottemperature, 0, 1023, 150, 400);
  setPoint = pottemperature;
  realTemperature = thermocouple.readCelsius();
  temperature = int(0.779828 * realTemperature - 10.3427); // make temperature an integer
  sensed_output = temperature;
  if (isnan(realTemperature) || sensed_output >= 432) {
    while (true) {
      digitalWrite(relay, LOW);
      displayErrors();
    }
  } else {
    updateDisplay();
  }
  if (delta_time >= T) {
    double error = setPoint - sensed_output;
    if (error <= 10) {
      Kp = 4, Ki = 0.2, Kd = 1;
    }
    if (error > 10) {
      Kp = 1, Ki = 0.05, Kd = 0.25;
    }
    total_error += error; //accumalates the error - integral term
    if (total_error >= max_control) total_error = max_control;
    else if (total_error <= min_control) total_error = min_control;

    double delta_error = error - last_error; //difference of error for derivative term

    control_signal = Kp * error + (Ki * T) * total_error + (Kd / T) * delta_error; //PID control compute
    if (control_signal >= max_control) control_signal = max_control;
    else if (control_signal <= min_control) control_signal = min_control;

    last_error = error;

  }
  noInterrupts();
  pidOut = int(control_signal);
  interrupts();
  last_time = current_time;
  delay(250);
}

void zero_crosss_int()
{
 
  int powertime = (39 * (256 - pidOut));
  
  delayMicroseconds(powertime);
 
  digitalWrite(triac, HIGH);

  delayMicroseconds(10);
 
  digitalWrite(triac, LOW);
}


void updateDisplay() {
  pottemperature = analogRead(potentiometer);
  pottemperature = map(pottemperature, 0, 1023, 150, 400);
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.write((byte)0);
  lcd.setCursor(2, 0);
  lcd.print((int)pottemperature);
  lcd.setCursor(6, 0);
  lcd.print((char)223); //degree sign
  lcd.setCursor(7, 0);
  lcd.print("C");
  lcd.setCursor(0, 1);
  lcd.write((byte)1);
  if (temperature <= 45) {
    lcd.setCursor(2, 1);
    lcd.print("Lo");
  } else {
    lcd.setCursor(2, 1);
    lcd.print((int)temperature);
  }
  lcd.setCursor(6, 1);
  lcd.print("[");
  lcd.setCursor(7, 1);
  lcd.print((int)realTemperature);
  lcd.setCursor(10, 1);
  lcd.print("]");
  lcd.setCursor(12, 1);
  lcd.print((char)223);
  lcd.setCursor(13, 1);
  lcd.print("C");
}

void displayErrors() {
  digitalWrite(relay, LOW); // the relay will disconnect the power to the soldering iron heating element
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.write((byte)0);
  lcd.setCursor(1, 0);
  lcd.write((byte)0);
  lcd.setCursor(5, 0);
  lcd.print("ERROR!");
  lcd.setCursor(14, 0);
  lcd.write((byte)0);
  lcd.setCursor(15, 0);
  lcd.write((byte)0);
  delay(500);
}

 

Edited by Mihai3

Share this post


Link to post
Share on other sites
Posted (edited)

Voi adăgura și un cod nou testat, și adaug pentru început câteva capturi de ecran de pe osciloscop.

Urmează și testul de stres propus de @roadrunner dar mai întâi vă aștept părerile legate de cod și capturi de ecran.

PS: Pe capturile pe care se vede numai trasa albastră este forma de undă de pe rezistența letconului, iar pe celelalte capturi de ecran, forma de undă galbenă este semnalul de pe pinul 2 al lui Arduino, iar forma de undă albastră este semnalul de pe pinul 7 (output) al lui Arduino.

PS2: Am făcut și testul de stres, temperatura a fost reglată la 320 C, am topit cositor de 1 mm grosime pe o bucată de PCB de 1.6 mm grosime, 55 mm lungime și 30 mm lățime  si cu grosimea stratului de cupru de 35 um, iar în acest timp de 1-2 minute, temperatura a scăzut la 315 C iar apoi a început să crească inapoi la 320 C.

 

 

 

DS0122.jpg

DS0123.jpg

DS0128.jpg

DS0129.jpg

DS0130.jpg

DS0131.jpg

Edited by Mihai3

Share this post


Link to post
Share on other sites
Posted (edited)

Acestea sunt codul și capturile de ecran de pe osciloscop:

DS0146 și DS0147 - pe rezistența letconului.

DS0134 și DS0138 - galben=semnalul de trecere prin zero, albastru=ieșirea (pin 7).

Aștept păreri/comentarii/sfaturi.

#include <TimerOne.h>          
#include <PID_v1.h>
#include <max6675.h>
#include <LiquidCrystal.h>
#include <SPI.h>
#include <Wire.h>

#define thermoDO 12
#define thermoCS 10
#define thermoCLK 13
#define potentiometer A0
#define zerocrossing 2
#define relay A1

float realTemperature;
int pottemperature;

LiquidCrystal lcd(3, 4, 5, 6, 8, 9);

byte thermometer[8] = //icon for termometer
{
  B00100,
  B01010,
  B01010,
  B01110,
  B01110,
  B11111,
  B11111,
  B01110
};

byte arrow[8] = //icon for arrow
{
  B11000,
  B01100,
  B00110,
  B00011,
  B00011,
  B00110,
  B01100,
  B11000
};

MAX6675 thermocouple(thermoCLK, thermoCS, thermoDO);

double Setpoint, Input, Output;
double aggKp = 4, aggKi = 0.2, aggKd = 1;
double consKp = 1, consKi = 0.05, consKd = 0.25;
PID myPID(&Input, &Output, &Setpoint, consKp, consKi, consKd, DIRECT);

volatile int i = 0;            //counter variable
volatile boolean zero_cross = 0; // Boolean to store a "switch" to tell us if we have crossed zero
int triac = 7;                // Output to Opto Triac
int dim = 0;                    // Dimming level (0-128)  0 = on, 128 = 0ff
int inc = 1;                    // counting up or down, 1=up, -1=down

int freqStep = 75;    // This is the delay-per-brightness step in microseconds.

void setup() {
  lcd.begin(16, 2);
  lcd.createChar(0, thermometer);
  lcd.createChar(1, arrow);
  lcd.setCursor(0, 0);
  lcd.print("STATIE DE LIPIT");
  myPID.SetMode(AUTOMATIC);
  myPID.SetOutputLimits(0, 128);
  pinMode(relay, OUTPUT);
  pinMode(potentiometer, INPUT);
  pinMode(zerocrossing, INPUT_PULLUP);
  pinMode(triac, OUTPUT); // Set the Triac pin as output
  delay(1200);
  lcd.clear();
  //  digitalWrite(triac, LOW);
  digitalWrite(relay, HIGH);
  attachInterrupt(digitalPinToInterrupt(2), zero_cross_detect, RISING);    // Attach an Interupt to Pin 2 (interupt 0) for Zero Cross Detection
  Timer1.initialize(freqStep);                      // Initialize TimerOne library for the freq we need
  Timer1.attachInterrupt(dim_check, freqStep);
}

void zero_cross_detect() {
  zero_cross = true;               // set the boolean to true to tell our dimming function that a zero cross has occured
  i = 0;
  digitalWrite(triac, LOW);       // turn off TRIAC (and AC)
}

// Turn on the TRIAC at the appropriate time
void dim_check() {
  if (zero_cross == true) {
    if (i >= dim) {
      digitalWrite(triac, HIGH); // turn on light
      i = 0; // reset time step counter
      zero_cross = false; //reset zero cross detection
    }
    else {
      i++; // increment time step counter
    }
  }
}

void loop() {
  //delay(18);
  pottemperature = analogRead(potentiometer);
  Setpoint = map(pottemperature, 0, 1023, 150, 400); //pottemperature is volatile
  realTemperature = thermocouple.readCelsius();
  Input = int(0.779828 * realTemperature - 10.3427); // make temperature an integer
  if (isnan(realTemperature) || Input >= 432) {
    while (true) {
      displayErrors();
    }
  } else {
    updateDisplay();
  }
  double gap = abs(Setpoint - Input); //distance away from setpoint
  if (gap < 10)
  { 
    myPID.SetTunings(consKp, consKi, consKd);
  }
  else
  {
    myPID.SetTunings(aggKp, aggKi, aggKd);
  }
  myPID.Compute();
  dim = map(Output, 0, 128, 128, 0);
  delay(300);
}

void updateDisplay() {
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.write((byte)0);
  lcd.setCursor(2, 0);
  lcd.print((int)Setpoint);
  lcd.setCursor(6, 0);
  lcd.print((char)223); //degree sign
  lcd.setCursor(7, 0);
  lcd.print("C");
  lcd.setCursor(0, 1);
  lcd.write((byte)1);
  if (Input <= 45) {
    lcd.setCursor(2, 1);
    lcd.print("Lo");
  } else {
    lcd.setCursor(2, 1);
    lcd.print((int)Input);
  }
  lcd.setCursor(6, 1);
  lcd.print("[");
  lcd.setCursor(7, 1);
  lcd.print((int)realTemperature);
  lcd.setCursor(10, 1);
  lcd.print("]");
  lcd.setCursor(12, 1);
  lcd.print((char)223);
  lcd.setCursor(13, 1);
  lcd.print("C");
}

void displayErrors() {
  digitalWrite(relay, LOW);
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.write((byte)0);
  lcd.setCursor(1, 0);
  lcd.write((byte)0);
  lcd.setCursor(5, 0);
  lcd.print("ERROR!");
  lcd.setCursor(14, 0);
  lcd.write((byte)0);
  lcd.setCursor(15, 0);
  lcd.write((byte)0);
  delay(300);
}

 

DS0146.jpg

DS0147.jpg

DS0134.jpg

DS0138.jpg

Edited by Mihai3

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

  • Recently Browsing   0 members

    No registered users viewing this page.

×
×
  • Create New...

Important Information

We use cookies and related technologies to improve your experience on this website to give you personalized content and ads, and to analyze the traffic and audience of your website. Before continuing to browse www.tehnium-azi.ro, please agree to: Terms of Use.