Hello, I built the attached schematic, but I have some problems in writing the code and understanding it, could you please help me with a check of the code ?
My questions are:
1. I don't know how to include the PID calculations and the lcd display code in the loop() function. Could you help me with some advice/code/comments ?
2. How to correctly write the zero() ISR function ?
#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)
*/
#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;
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;
double total_error, last_error;
int max_control = 0;
int min_control = 200;
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, 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() {
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;
}
else { //reading valid
duty = map(pidOut, max_control, min_control, 0, 25);
duty = constrain(duty, 0, 25); // ***keep duty between 0 and 25 (25 = 100%)
if (duty > 0) {
digitalWrite(triac, HIGH);
} else {
digitalWrite(triac, LOW);
}
}//if (tempError
} //if(counter >= 25
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);
}