Интеграция GyverEncoder в готовый скетч pid регулятора

anjei314

✩✩✩✩✩✩✩
16 Сен 2023
2
0
Здравствуйте, есть готовый проект пид регулятора температуры, с термопарой К типа и олет дисплей. Все устраивает кроме некоректной обработки сигналов энкодера, при вращении энкодера устанавливаемая темпереатура может увеличичтся или уменьшиться, или вовсе не меняется не зависмо от навправления вращения и способа подключения энкодера, пробовал разные энкодеры. обработка энкодера реализована в коде без сторонних бибилиотк, хотел добавить обработку на библиотеке 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 дисплей)
  }
}
 
Изменено:

VictorArx

★★✩✩✩✩✩
22 Мар 2021
525
86
Все устраивает кроме некоректной обработки сигналов энкодера, при вращении энкодера устанавливаемая темпереатура может увеличичтся или уменьшиться, или вовсе не меняется не зависмо
Энкодеры бывают бракованные. Посмотри видосы Гайвера про них. Можно проверить работу энкодера на мониторе порта.
 

anjei314

✩✩✩✩✩✩✩
16 Сен 2023
2
0
Пробовал разные энкодеры, проверял на мониторе с библиотекой Гайвера все работают четко
 

vortigont

★★★★★★✩
24 Апр 2020
1,022
542
Saint-Petersburg, Russia
@anjei314, какая-то чепуха в скетче написана. Бери примеры работы с гайвер-энкодером, делай по одному и учись как работает библиотека. Научись регулировать яркость светодиода энкодером, потом выводить данные на экран, по яркости этого же светодиода. Разберешься как это работает, тогда сможешь исправить исходный скетч.