Connection of the Heating Block Including PID Control and Menu - ARDUINO !
by InventionsLab in Circuits > Arduino
3049 Views, 4 Favorites, 0 Comments
Connection of the Heating Block Including PID Control and Menu - ARDUINO !
Today we will look at how to connect the heating element to the arduino, connect the rotary encoder and also set the PID control. How to Pid regulation? WHAT is PID control? What is PID control used for? How to set parameters Kp, Kd and Ki? How to make a menu in arduino UNO? Everything and more, including graphs where we can plot the course of temperature regulation.
Today we will look at how to connect the heating element to the arduino, connect the rotary encoder and also set the PID control. How to Pid regulation? WHAT is PID control? What is PID control used for? How to set parameters Kp, Kd and Ki? How to make a menu in arduino UNO? Everything and more, including graphs where we can plot the course of temperature regulation.
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <PID_v1.h>
//variables for the temperature sensor
int termPin = 0; // The analog pin the thermistor is connected to
int termNom = 100000; // Thermistor reference resistance
int refTep = 25; // Temperature for reference resistance
int beta = 3950; // Beta factor
int rezistor = 100000; // resistance value in series
double temp=0.0;
float voltage;
//button commands only for button and potentiometer
int pin3= 5; //Pin SW 4
const int pin1 = 2;
const int pin2 = 3;
volatile int statePin1 = 0; // Pin 1 status
volatile int statePin2 = 0; // Pin 2 status
volatile int laststatePin1 = 0;
volatile int laststatePin2 = 0;
volatile unsigned long timePin1 = 0; // Time for pin 1
volatile unsigned long timePin2 = 0; // Time for pin 2
volatile unsigned long lasttimePin1 = 0; // last Time for pin 1
volatile unsigned long lasttimePin2 = 0; // last Time for pin 2
int countererror2;
int countererror1;
//button
unsigned long lastButtonPress = 0;
bool buttonState = HIGH;
bool buttoncheck;
int buttonpressed=0;
// variables for the menu
int menu_activated=0;
int numberofmenu=4;
int checkmenu1=0;
unsigned long previousMillis = 0; // Variable to store previous time
const long interval = 500; // Interval for flashing text in menu
unsigned long currentMillismenu;
int checkemptyvalues=0;
unsigned long previousMillis2= 0;
//set to mosfet and temperature
int PWM_pin = 6; //Digital pin for PWM signal to the MOSFET driver
double set_temperature = 50.00; //The default temperature where you will tune the PID °C
float last_set_temperature = 0;
double PID_value = 0;
float last_kp = 0;
float last_ki = -100; // -100 remove error for display when value is 0
float last_kd = -100; // -100 remove error for display when value is 0
//PID constants double input, output;
double kp = 90, ki = 1.1, kd = 1; //set constant
PID pid(&temp, &PID_value, &set_temperature, kp, ki, kd, DIRECT);
LiquidCrystal_I2C lcd(0x27, 16, 2);
void setup() {
Serial.begin(9600);
analogReference(EXTERNAL);
lcd.init();
lcd.backlight();
lcd.setCursor(0, 0);
lcd.display();
// BUTTON set pin
pinMode(pin3, INPUT_PULLUP);
pinMode(pin1, INPUT);
pinMode(pin2, INPUT);
attachInterrupt(digitalPinToInterrupt(pin1), handlePin1Change, CHANGE);
attachInterrupt(digitalPinToInterrupt(pin2), handlePin2Change, CHANGE);
// Setting the output mode for PID
pid.SetMode(AUTOMATIC);
// Setting the sampling interval (time interval for PID calculation)
pid.SetSampleTime(50); // In this case 1000 ms (1 second)
}
void handlePin1Change() {
statePin1 = digitalRead(pin1);
timePin1 = millis(); // Record the change time on pin 1
//filtering annoying duplicates, both temporal and identical consecutive values, omitting zeros, lets only 1
if (timePin1 != lasttimePin1 && statePin1 != laststatePin1 ) {
if ( statePin1 == 1) {
countererror1++; }
compareStates();
lasttimePin1=timePin1;
laststatePin1=statePin1;
}
}
void handlePin2Change() {
statePin2 = digitalRead(pin2);
timePin2 = millis(); // Record the change time on pin 2
//filtering annoying duplicates, both temporal and identical consecutive values, omitting zeros, lets only 1
if (timePin2 != lasttimePin2 && statePin2 != laststatePin2 ) {
if ( statePin2 == 1) {
countererror2++; }
compareStates();
lasttimePin2=timePin2;
laststatePin2=statePin2;
}
}
void compareStates() {
//checking the last pin, which is always 1 + checking if the pins have changed at least 1x to check the wrong direction
if (statePin2 == 1 && statePin1 == 1 && countererror1 > 0 && countererror2 > 0 ) {
// checking if the button is not pressed, to check if the menu is preserved
if (buttonpressed == 0 ) {
//finding which direction it is facing
if (timePin2 > timePin1 ) {
//restriction to positive values only for menu
if (menu_activated > 0 ) {
menu_activated--;
}else
{
menu_activated=numberofmenu;
}
countererror1= 0;
countererror2= 0;
}else
{
// limitation the number of menus
if (numberofmenu > menu_activated ) {
menu_activated++;
}else {
menu_activated = 0;
}
countererror2=0;
countererror1=0;
}
}else {
if ( menu_activated == 1) {
if (timePin2 > timePin1 ) {
set_temperature = set_temperature-0.5 ;
}
else {
set_temperature = set_temperature+0.5;
}
countererror1= 0;
countererror2= 0;
}
if ( menu_activated == 2 ) {
if (timePin2 > timePin1 ) {
kp = kp-1 ;
}
else {
kp = kp+1 ;
}
countererror1= 0;
countererror2= 0;
}
if ( menu_activated == 3 ) {
if (timePin2 > timePin1 ) {
ki = ki-1 ;
}
else {
ki = ki+1 ;
}
countererror1= 0;
countererror2= 0;
}
if ( menu_activated == 4 ) {
if (timePin2 > timePin1 ) {
kd = kd-1 ;
}
else {
kd = kd+1 ;
}
countererror1= 0;
countererror2= 0;
}
}
}
}
//variables to calculate the highest and lowest values
unsigned long previousMillisa = 0;
double lowestdowntemp= set_temperature;
double higesttemp=set_temperature;
double maxhigesttemp=set_temperature;
double minlowestdowntemp= set_temperature;
double maxhigesttemp1=set_temperature;
double minlowestdowntemp1= set_temperature;
double result=0;
void loop() {
//graph display - this is for chart information only
if (millis()- previousMillisa >= 1000) {
// Find the highest value with a time interval to mitigate noise
if (temp > higesttemp ) {
//restart values
lowestdowntemp= set_temperature;
higesttemp = temp;
}
if (higesttemp >= temp && temp > set_temperature ) {
maxhigesttemp=higesttemp; }
if ( set_temperature > temp ) {
maxhigesttemp1=maxhigesttemp;
}
// Finding the lowest value
if (lowestdowntemp > temp ) {
//restart hodnot
higesttemp=set_temperature;
lowestdowntemp = temp;
}
if (temp >= lowestdowntemp && set_temperature > temp ) {
minlowestdowntemp=lowestdowntemp;
}
if ( temp > set_temperature) {
minlowestdowntemp1=minlowestdowntemp;
}
result=maxhigesttemp1-minlowestdowntemp1+50;
previousMillisa = millis();
Serial.print("PID_value:");
Serial.print(PID_value);
Serial.print(",");
Serial.print("temp:");
Serial.print(temp);
Serial.print(",");
Serial.print("ref.temp.:");
Serial.print(set_temperature);
Serial.print(",");
Serial.print("mintemp");
Serial.print(minlowestdowntemp1);
Serial.print(",");
Serial.print("maxtemp:");
Serial.print(maxhigesttemp1);
Serial.print(",");
Serial.print("deviation:");
Serial.print(result);
Serial.println("");
}
//measuring the voltage on the thermistor
voltage = analogRead(termPin);
// Convert the measured value to the thermistor resistance
voltage = 1023 / voltage - 1;
voltage = rezistor / voltage;
//Calculation of temperature according to the relation for the beta factor
temp = voltage / termNom; // (R/Ro)
temp = log(temp); // ln(R/Ro)
temp /= beta; // 1/B * ln(R/Ro)
temp += 1.0 / (refTep + 273.15); // + (1/To)
temp = 1.0 / temp; //The inverted value
temp -= 273.15; // Convert from Kelvin to degrees Celsius
// Calculation of PID control
pid.Compute();
analogWrite(PWM_pin,PID_value);
delay(50);
//menu 0
if(menu_activated == 0)
{
if (millis()- previousMillis2 >= 500) {
previousMillis2 = millis();
lcd.setCursor(0,0);
lcd.print("ACTUAL TEMP");
lcd.setCursor(0,1);
lcd.print("T:");
lcd.setCursor(2,1);
lcd.print(temp,1);
lcd.print("C ");
lcd.setCursor(9,1);
lcd.print("S:");
lcd.setCursor(11,1);
lcd.print(set_temperature,1);
lcd.print("C");
last_set_temperature=0;
last_kd=-100;
}
}//end of menu 0 (PID control)
//check button pressed for menu
buttoncheck = digitalRead(pin3);
if ((millis() - lastButtonPress) > 50) {
if (buttoncheck != buttonState) {
buttonState = buttoncheck;
if (buttonState == LOW) {
if (buttonpressed == 0) {
if (menu_activated != 0) {
buttonpressed=1;
}
}
else {
buttonpressed=0;
}
lastButtonPress = millis();
}
}
}
delay(1);
//end of button press
//Menu-page 1 (temperature setpoint)
if(menu_activated == 1)
{
if(buttonpressed == 1)
{
currentMillismenu = millis();
if (currentMillismenu - previousMillis >= interval) {
previousMillis = currentMillismenu;
//menu flashing when pressed, editing activation
if(checkmenu1 == 0){
lcd.setCursor(0,1);
lcd.print(" ");
checkmenu1=1;
checkemptyvalues=1;
}else {
lcd.setCursor(0,1);
lcd.print(set_temperature, 1);
lcd.print("C");
checkmenu1=0;
checkemptyvalues=0;
}}
}else{
// checking for an empty value after pressing the button
if(checkemptyvalues == 1)
{
lcd.setCursor(0,1);
lcd.print(set_temperature, 1);
lcd.print("C");
}}
if(set_temperature != last_set_temperature)
{
lcd.clear();
lcd.setCursor(0,0);
lcd.print("Set temperature:");
lcd.setCursor(0,1);
lcd.print(set_temperature, 1);
lcd.print("C");
}
last_set_temperature = set_temperature;
last_kp=0;
}
//end of menu 1
//Setting P - second menu
if(menu_activated == 2)
{
if(buttonpressed == 1)
{
currentMillismenu = millis();
if (currentMillismenu - previousMillis >= interval) {
previousMillis = currentMillismenu;
//menu flashing when pressed, editing activation
if(checkmenu1 == 0){
lcd.setCursor(0,1);
lcd.print("P: ");
lcd.print(" ");
checkmenu1=1;
checkemptyvalues=1;
}else {
lcd.setCursor(0,1);
lcd.print("P: ");
lcd.print(kp);
lcd.print(" ");
checkmenu1=0;
checkemptyvalues=0;
}}
}else{
// checking for an empty value after pressing the button
if(checkemptyvalues == 1)
{
lcd.setCursor(0,1);
lcd.print("P: ");
lcd.print(kp);
lcd.print(" ");
}}
if(kp != last_kp)
{
lcd.clear();
lcd.setCursor(0,0);
lcd.print("Set value ");
lcd.setCursor(0,1);
lcd.print("P: ");
lcd.print(kp);
lcd.print(" ");
}
last_kp = kp;
//it will be possible to display menu 0 again
last_set_temperature=0;
last_ki=-100;
}
//end - menu 2
//Setting I - 3 menu
if(menu_activated == 3)
{
if(buttonpressed == 1)
{
currentMillismenu = millis();
if (currentMillismenu - previousMillis >= interval) {
previousMillis = currentMillismenu;
//menu flashing when pressed, editing activation
if(checkmenu1 == 0){
lcd.setCursor(0,1);
lcd.print("I: ");
lcd.print(" ");
checkmenu1=1;
checkemptyvalues=1;
}else {
lcd.setCursor(0,1);
lcd.print("I: ");
lcd.print(ki);
lcd.print(" ");
checkmenu1=0;
checkemptyvalues=0;
}}
}else{
// checking for an empty value after pressing the button
if(checkemptyvalues == 1)
{
lcd.setCursor(0,1);
lcd.print("I: ");
lcd.print(ki);
lcd.print(" ");
}}
if(ki != last_ki )
{
lcd.clear();
lcd.setCursor(0,0);
lcd.print("Set value ");
lcd.setCursor(0,1);
lcd.print("I: ");
lcd.print(ki);
lcd.print(" ");
}
last_ki = ki;
last_set_temperature=0;
last_kp=0;
last_kd=-100;
}
//end - menu 3
//Setting D - 4 menu
if(menu_activated == 4)
{
if(buttonpressed == 1)
{
currentMillismenu = millis();
if (currentMillismenu - previousMillis >= interval) {
previousMillis = currentMillismenu;
//menu flashing when pressed, editing activation
if(checkmenu1 == 0){
lcd.setCursor(0,1);
lcd.print("D: ");
lcd.print(" ");
checkmenu1=1;
checkemptyvalues=1;
}else {
lcd.setCursor(0,1);
lcd.print("D: ");
lcd.print(kd);
lcd.print(" ");
checkmenu1=0;
checkemptyvalues=0;
}}
}else{
// checking for an empty value after pressing the button
if(checkemptyvalues == 1)
{
lcd.setCursor(0,1);
lcd.print("D: ");
lcd.print(kd);
lcd.print(" ");
}}
if(kd != last_kd)
{
lcd.clear();
lcd.setCursor(0,0);
lcd.print("Set value ");
lcd.setCursor(0,1);
lcd.print("D: ");
lcd.print(kd);
lcd.print(" ");
}
last_kd = kd;
last_ki=-100;
}
//end menu 4
}//Loop end