Arduino and Interrupts - trying to understand code and to add new function - Page 1
Forum section: electronics / beginners

author: mike_mike
author_rank: Super Contributor
timestamp: July 14, 2020, 05:06:50 pm
content: I am thinking about building the project from this web site:https://www.instructables.com/id/DIY-Arduino-Soldering-Station/I will use a Nokia 5110 display connected at the digital outputs of an Arduino Nano. You can find the schematic attached. The AC1 and AC2 is a 24Vac/100W transformer. The soldering iron will be a Gordak 24V/50W, with K Type Thermocouple.The relay is used to cut power when the thermocouple wire gets disconnected or when the temperature is above 432 C.I will also add a protection - which will cut the power to the iron - using the relay.I wrote a code modification, which will cut off the power to the iron and will display a error message on the lcd.Is the checkForErrors() function correct ?Where, in the code, should I call the above mentioned function ?Code:#include <PCD8544.h>#include <SPI.h>#include <Wire.h>#include <max6675.h>#define thermoDO 11#define thermoCS 12#define thermoCLK 13#define potentiometer A0#define zerocrossing 2#define triac 7#define relay 9float temperature, realTemperature;int pottemperature;int counter;MAX6675 thermocouple(thermoCLK, thermoCS, thermoDO);PCD8544 lcd(3, 4, 5, 6, 8);void setup() {lcd.begin(84, 48);pinMode(potentiometer, INPUT);pinMode(zerocrossing, INPUT_PULLUP);pinMode(triac, OUTPUT);digitalWrite(triac, LOW);counter = 0;realTemperature = thermocouple.readCelsius();temperature = 0.779828 * realTemperature - 10.3427;updatedisplay();attachInterrupt(0, zero, RISING);}void loop() {}void zero() {counter++;if (counter < 40) {if (temperature <= pottemperature) {digitalWrite(triac, HIGH);}else {digitalWrite(triac, LOW);}}if (counter == 40) {digitalWrite(triac, LOW);detachInterrupt(0);realTemperature = thermocouple.readCelsius();temperature = 0.779828 * realTemperature - 10.3427;updatedisplay();counter = 0;attachInterrupt(0, zero, RISING);}}void updatedisplay() {pottemperature = analogRead(potentiometer);pottemperature = map(pottemperature, 0, 1023, 0, 400);checkForErrors();lcd.setCursor(0, 0);lcd.print("SET= ");lcd.print(5, 0);lcd.print(pottemperature);lcd.setCursor(0, 1);lcd.print("READ= ");lcd.setCursor(7, 1);lcd.print((int)temperature);delay(200);}void checkForErrors() {realTemperature = thermocouple.readCelsius();if (isnan(realTemperature) or realTemperature >= 432) {while (true) {detachInterrupt(0);digitalWrite(triac, LOW);digitalWrite(relay, LOW); // the relay will disconnect the power to the soldering iron heating elementlcd.clear();lcd.setCursor(0, 0);lcd.print("Error !");delay(500);}}}

author: Manul
author_rank: Super Contributor
timestamp: July 14, 2020, 08:27:28 pm
content: I think you need in Setup()Code:pinMode(relay OUTPUT);digitalWrite(relay, HIGH);And here you already have temperature, so no need to check it again, just pass it to your function (more optimized):Code:void zero() {counter++;if (counter < 40) {if (temperature <= pottemperature) {digitalWrite(triac, HIGH);}else {digitalWrite(triac, LOW);}}if (counter == 40) {digitalWrite(triac, LOW);detachInterrupt(0);realTemperature = thermocouple.readCelsius();temperature = 0.779828 * realTemperature - 10.3427;checkForErrors(temperature); Pass temperature to your functionupdatedisplay();counter = 0;attachInterrupt(0, zero, RISING);}}Your function may be like that:Code:void checkForErrors(float Temp) {if (thermocouple.readError() || Temp >= 432) {digitalWrite(relay, LOW); // the relay will disconnect the power to the soldering iron heating elementlcd.clear();lcd.setCursor(0, 0);lcd.print("Error !");while(true); //Loop forever until reboot}}From looking at a library I think thermocouple.readError() is a proper way to see if some error happened, so I changed.P.S. I think "||" is correct logical operator, not "or". Code which I provided is not guaranteed. I'm not Arduino programmer.EDIT: I just saw that temperature is a global variable here, so no need to pass it as an argument. You should add some freewheeling diode on your relay.

author: mike_mike
author_rank: Super Contributor
timestamp: July 31, 2020, 07:43:30 am
content: 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 ?Code:#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 A1volatile float temperature, realTemperature; // I have declared those 2 variables as VOLATILE, because of using them inside and outside ISRint pottemperature;int counter;int duty = 0; // variable for duty cyclebyte thermometer = //icon for termometer{B00100,B01010,B01010,B01110,B01110,B11111,B11111,B01110};byte arrow = //icon for arrow{B11000,B01100,B00110,B00011,B00011,B00110,B01100,B11000};MAX6675 thermocouple(thermoCLK, thermoCS, thermoDO);/* The circuit:LCD RS pin to digital pin 12LCD Enable pin to digital pin 11LCD D4 pin to digital pin 5LCD D5 pin to digital pin 4LCD D6 pin to digital pin 3LCD D7 pin to digital pin 2LCD R/W pin to groundLCD VSS pin to groundLCD VCC pin to 5V10K resistor:ends to +5V and groundwiper to LCD VO pin (pin 3)*/#define PRINTRATE 100#define DISPLAYRATE 250char textbuf; //buffer for data to sendunsigned long serialTime = millis(); //sending interval for dataunsigned long displayTime = serialTime; //display interval for LCDint 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 gaindouble Ki; //integral gaindouble Kd; //derivative gainint 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 ISRunsigned long current_time = millis(); //returns the number of milliseconds passed since the Arduino started running the programint delta_time = current_time - last_time; //delta time intervalpottemperature = analogRead(potentiometer);pottemperature = map(pottemperature, 0, 1023, 150, 400);setpoint = pottemperature;realTemperature = thermocouple.readCelsius();temperature = int(0.779828 * realTemperature - 10.3427); // make temperature an integersensed_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 termif (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 termcontrol_signal = Kp * error + (Ki * T) * total_error + (Kd / T) * delta_error; //PID control computeif (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 belowif (counter > duty) { //reach duty cycle limit, unless duty was 25 in which case leave on until next duty calculated laterdigitalWrite(triac, LOW);}if (counter >= 25) {counter = 0;}else { //reading validduty = 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 >= 25void 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 signlcd.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 elementlcd.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);}