Здравствуйте, есть готовый проект пид регулятора температуры, с термопарой К типа и олет дисплей. Все устраивает кроме некоректной обработки сигналов энкодера, при вращении энкодера устанавливаемая темпереатура может увеличичтся или уменьшиться, или вовсе не меняется не зависмо от навправления вращения и способа подключения энкодера, пробовал разные энкодеры. обработка энкодера реализована в коде без сторонних бибилиотк, хотел добавить обработку на библиотеке GyverEncoder и потерпел фиаско. Если сможете подсказать, буду очень благодарен. enc1 исходный рабочий код, enc2 моя попытка встроить GyverEncoder.
Исходники брал здесь
Исходники брал здесь
enc1:
#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <PIDController.h>
#include "max6675.h"
// Define Rotary Encoder Pins (контакты энкодера)
#define CLK_PIN 3
#define DATA_PIN 4
#define SW_PIN 2
// MAX6675 Pins
#define thermoDO 8
#define thermoCS 9
#define thermoCLK 10
// Mosfet Pin (контакты Mosfet транзистора)
#define mosfet_pin 11
// Serial Enable
#define [B]DEBUG[/B]
#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels
#define OLED_RESET -1 // Reset pin # (or -1 if sharing Arduino reset pin)
/*In this section we have defined the gain values for the
* proportional, integral, and derivative controller I have set
* the gain values with the help of trial and error methods.
*/
#define __Kp 30 // Proportional constant
#define __Ki 0.7 // Integral Constant
#define __Kd 200 // Derivative Constant
int clockPin; // Placeholder por pin status used by the rotary encoder
int clockPinState; // Placeholder por pin status used by the rotary encoder
int set_temperature = 1; // This set_temperature value will increas or decreas if when the rotarty encoder is turned (значение температуры, будет изменяться при вращении ручки энкодера)
float temperature_value_c = 0.0; // stores temperature value (будет хранить значение температуры)
long debounce = 0; // Debounce delay (задержка для устранения эффекта дребезга контактов)
int encoder_btn_count = 0; // used to check encoder button press (счетчик нажатий кнопки энкодера)
MAX6675 thermocouple(thermoCLK, thermoCS, thermoDO); // Create an instance for the MAX6675 Sensor Called "thermocouple" (создаем объект для работы с термопарой)
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);// Create an instance for the SSD1306 128X64 OLED "display" (создаем объект для работы с дисплеем)
PIDController pid; // Create an instance of the PID controller class, called "pid" (создаем объект для работы с ПИД алгоритмом)
void setup() {
#ifdef [B]DEBUG[/B]
Serial.begin(9600);
#endif
pinMode(mosfet_pin, OUTPUT); // MOSFET output PIN
pinMode(CLK_PIN, INPUT); // Encoer Clock Pin
pinMode(DATA_PIN, INPUT); //Encoder Data Pin
pinMode(SW_PIN, INPUT_PULLUP);// Encoder SW Pin
pid.begin(); // initialize the PID instance (инициализируем ПИД алгоритм)
pid.setpoint(200); // The "goal" the PID controller tries to "reach" (задаем целевую точку для его работы)
pid.tune(__Kp, __Ki,__Kd); // Tune the PID, arguments: kP, kI, kD (производим начальную настройку ПИД алгоритма)
pid.limit(0, 255); // Limit the PID output between 0 and 255, this is important to get rid of integral windup! (задаем пределы работы ПИД алгоритма)
if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
#ifdef [B]DEBUG[/B]
Serial.println(F("SSD1306 allocation failed"));
#endif
for (;;); // Don't proceed, loop forever (бесконечный цикл)
}
//
display.setRotation(2); //Rotate the Display
display.display(); //Show initial display buffer contents on the screen -- the library initializes this with an Adafruit splash screen.
display.clearDisplay(); // Cleear the Display
display.setTextSize(2); // Set text Size
display.setTextColor(WHITE); // set LCD Colour
display.setCursor(48, 0); // Set Cursor Position
display.println("PID"); // Print the this Text
display.setCursor(0, 20); // Set Cursor Position
display.println("Temperatur"); // Print the this Text
display.setCursor(22, 40); // Set Cursor Position
display.println("Control"); // Print the this Text
display.display(); // Update the Display
delay(2000); // Delay of 200 ms
}
void set_temp()
{
if (encoder_btn_count == 2) // check if the button is pressed twice and its in temperature set mode. (если кнопка нажата дважды, то используем режим установки температуры)
{
display.clearDisplay(); // clear the display
display.setTextSize(2); // Set text Size
display.setCursor(16, 0); // set the diplay cursor
display.print("Set Temp."); // Print Set Temp. on the display
display.setCursor(45, 25); // set the cursor
display.print(set_temperature);// print the set temperature value on the display
display.display(); // Update the Display
}
}
void read_encoder() // In this function we read the encoder data and increment the counter if its rotaing clockwise and decrement the counter if its rotating counter clockwis
{
clockPin = digitalRead(CLK_PIN); // we read the clock pin of the rotary encoder
if (clockPin != clockPinState && clockPin == 1) { // if this condition is true then the encoder is rotaing counter clockwise and we decremetn the counter (энкодер вращается по часовой стрелке)
if (digitalRead(DATA_PIN) != clockPin) set_temperature = set_temperature - 1; // decrmetn the counter.
else set_temperature = set_temperature + 1; // Encoder is rotating CW so increment (энкодер вращается против часовой стрелке)
if (set_temperature < 1 )set_temperature = 1; // if the counter value is less than 1 the set it back to 1
if (set_temperature > 200 ) set_temperature = 200; //if the counter value is grater than 150 then set it back to 150
#ifdef [B]DEBUG[/B]
Serial.println(set_temperature); // print the set temperature value on the serial monitor window (выводим установленное значение температуры в окно монитора последовательной связи)
#endif
}
clockPinState = clockPin; // Remember last CLK_PIN state (запоминаем последнее состояние CLK_PIN)
if ( digitalRead(SW_PIN) == LOW) //If we detect LOW signal, button is pressed
{
if ( millis() - debounce > 80) { //debounce delay
encoder_btn_count++; // Increment the values
if (encoder_btn_count > 2) encoder_btn_count = 1;
#ifdef [B]DEBUG[/B]
Serial.println(encoder_btn_count);
#endif
}
debounce = millis(); // update the time variable
}
}
void loop()
{
read_encoder(); //Call The Read Encoder Function
set_temp(); // Call the Set Temperature Function
if (encoder_btn_count == 1) // check if the button is pressed and its in Free Running Mode -- in this mode the arduino continiously updates the screen and adjusts the PWM output according to the temperature.
{
temperature_value_c = thermocouple.readCelsius(); // Read the Temperature using the readCelsius methode from MAX6675 Library.
int output = pid.compute(temperature_value_c); // Let the PID compute the value, returns the optimal output (вычисляем оптимальное значение с помощью ПИД алгоритма)
analogWrite(mosfet_pin, output); // Write the output to the output pin
pid.setpoint(set_temperature); // Use the setpoint methode of the PID library to (устанавливаем целевую точку для ПИД алгоритма)
display.clearDisplay(); // Clear the display
display.setTextSize(2); // Set text Size
display.setCursor(16, 0); // Set the Display Cursor
display.print("Cur Temp."); //Print to the Display
display.setCursor(45, 25);// Set the Display Cursor
display.print(temperature_value_c); // Print the Temperature value to the display in celcius
display.display(); // Update the Display
#ifdef [B]DEBUG[/B]
Serial.print(temperature_value_c); // Print the Temperature value in *C on serial monitor (выводим значение температуры в окно монитора последовательной связи)
Serial.print(" "); // Print an Empty Space
Serial.println(output); // Print the Calculate Output value in the serial monitor.
#endif
delay(200); // Wait 200ms to update the OLED dispaly. (ждем 200 мс чтобы обновить OLED дисплей)
}
}
enc2:
#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <PIDController.h>
#include "max6675.h"
// Define Rotary Encoder Pins (контакты энкодера)
#define CLK 3
#define DT 4
#define SW 2
#include "GyverEncoder.h"
Encoder enc1(CLK, DT, SW);
// MAX6675 Pins
#define thermoDO 8
#define thermoCS 9
#define thermoCLK 10
// Mosfet Pin (контакты Mosfet транзистора)
#define mosfet_pin 11
// Serial Enable
#define [B]DEBUG[/B]
#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels
#define OLED_RESET -1 // Reset pin # (or -1 if sharing Arduino reset pin)
/*In this section we have defined the gain values for the
* proportional, integral, and derivative controller I have set
* the gain values with the help of trial and error methods.
*/
#define __Kp 30 // Proportional constant
#define __Ki 0.7 // Integral Constant
#define __Kd 200 // Derivative Constant
int set_temperature = 1; // This set_temperature value will increas or decreas if when the rotarty encoder is turned (значение температуры, будет изменяться при вращении ручки энкодера)
float temperature_value_c = 0.0; // stores temperature value (будет хранить значение температуры)
MAX6675 thermocouple(thermoCLK, thermoCS, thermoDO); // Create an instance for the MAX6675 Sensor Called "thermocouple" (создаем объект для работы с термопарой)
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);// Create an instance for the SSD1306 128X64 OLED "display" (создаем объект для работы с дисплеем)
PIDController pid; // Create an instance of the PID controller class, called "pid" (создаем объект для работы с ПИД алгоритмом)
void setup() {
#ifdef [B]DEBUG[/B]
Serial.begin(9600);
enc1.setType(TYPE2);
#endif
pinMode(mosfet_pin, OUTPUT); // MOSFET output PIN
pinMode(SW, INPUT_PULLUP);// Encoder SW Pin
pid.begin(); // initialize the PID instance (инициализируем ПИД алгоритм)
pid.setpoint(150); // The "goal" the PID controller tries to "reach" (задаем целевую точку для его работы)
pid.tune(__Kp, __Ki,__Kd); // Tune the PID, arguments: kP, kI, kD (производим начальную настройку ПИД алгоритма)
pid.limit(0, 255); // Limit the PID output between 0 and 255, this is important to get rid of integral windup! (задаем пределы работы ПИД алгоритма)
if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
#ifdef [B]DEBUG[/B]
Serial.println(F("SSD1306 allocation failed"));
#endif
for (;;); // Don't proceed, loop forever (бесконечный цикл)
}
//
display.setRotation(2); //Rotate the Display
display.display(); //Show initial display buffer contents on the screen -- the library initializes this with an Adafruit splash screen.
display.clearDisplay(); // Cleear the Display
display.setTextSize(2); // Set text Size
display.setTextColor(WHITE); // set LCD Colour
display.setCursor(48, 0); // Set Cursor Position
display.println("PID"); // Print the this Text
display.setCursor(0, 20); // Set Cursor Position
display.println("Temperatur"); // Print the this Text
display.setCursor(22, 40); // Set Cursor Position
display.println("Control"); // Print the this Text
display.display(); // Update the Display
delay(2000); // Delay of 200 ms
}
void set_temp()
{
if (enc1.isDouble()) // check if the button is pressed twice and its in temperature set mode. (если кнопка нажата дважды, то используем режим установки температуры)
{
display.clearDisplay(); // clear the display
display.setTextSize(2); // Set text Size
display.setCursor(16, 0); // set the diplay cursor
display.print("Set Temp."); // Print Set Temp. on the display
display.setCursor(45, 25); // set the cursor
display.print(set_temperature);// print the set temperature value on the display
display.display(); // Update the Display
}
}
void read_encoder() // In this function we read the encoder data and increment the counter if its rotaing clockwise and decrement the counter if its rotating counter clockwis
{
if (enc1.isLeft()) set_temperature = set_temperature - 1; // decrmetn the counter.
else set_temperature = set_temperature + 1; // Encoder is rotating CW so increment (энкодер вращается против часовой стрелке)
if (set_temperature < 1 )set_temperature = 1; // if the counter value is less than 1 the set it back to 1
if (set_temperature > 300 ) set_temperature = 300; //if the counter value is grater than 150 then set it back to 150
#ifdef [B]DEBUG[/B]
Serial.println(set_temperature); // print the set temperature value on the serial monitor window (выводим установленное значение температуры в окно монитора последовательной связи)
#endif
void loop()
{
enc1.tick();
set_temp(); // Call the Set Temperature Function
if (enc1.isClick()) // check if the button is pressed and its in Free Running Mode -- in this mode the arduino continiously updates the screen and adjusts the PWM output according to the temperature.
{
temperature_value_c = thermocouple.readCelsius(); // Read the Temperature using the readCelsius methode from MAX6675 Library.
int output = pid.compute(temperature_value_c); // Let the PID compute the value, returns the optimal output (вычисляем оптимальное значение с помощью ПИД алгоритма)
analogWrite(mosfet_pin, output); // Write the output to the output pin
pid.setpoint(set_temperature); // Use the setpoint methode of the PID library to (устанавливаем целевую точку для ПИД алгоритма)
display.clearDisplay(); // Clear the display
display.setTextSize(2); // Set text Size
display.setCursor(16, 0); // Set the Display Cursor
display.print("Cur Temp."); //Print to the Display
display.setCursor(45, 25);// Set the Display Cursor
display.print(temperature_value_c); // Print the Temperature value to the display in celcius
display.display(); // Update the Display
#ifdef [B]DEBUG[/B]
Serial.print(temperature_value_c); // Print the Temperature value in *C on serial monitor (выводим значение температуры в окно монитора последовательной связи)
Serial.print(" "); // Print an Empty Space
Serial.println(output); // Print the Calculate Output value in the serial monitor.
#endif
delay(200); // Wait 200ms to update the OLED dispaly. (ждем 200 мс чтобы обновить OLED дисплей)
}
}
Изменено: