Помощь в коде контроллер для управления электронного терморегулирующего вентиля

jan999
Offline
Зарегистрирован: 07.11.2017

Прошу помощи не работает скетч появляется ошибка: exit status 1 'printTemperature' was not declared in this scope




#include <LiquidCrystal.h>
#include <AccelStepper.h>
#include <OneWire.h>
#include <DallasTemperature.h>
#define ONE_WIRE_BUS 12  // Data wire is plugged into port 12 on the Arduino
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);
DeviceAddress Suction;
#define STEPS 480 // change this to the number of steps on your motor
AccelStepper stepper(AccelStepper::HALF4WIRE, 0, 1, 2, 3);
LiquidCrystal lcd(8, 9, 4, 5, 6, 7);
int sensorPin = A0;    // select the input pin for the key
int sensorValue = 1023;  // variable to store the value coming from the sensor
float PressureValue ;    // среднеарифм показания датчика давления ,флоат.
long intPressureValue ;    // Показания датчика давления ,бин, 10 разр,макс 2,147,483,647.
float UPressureValue ;    //  Показания датчика давления ,Вольт
int minst = 66;           // минимальное число шагов открытия ЭРВ.
int nulst = 100;          // среднестатистическое положение ЭРВ, относительно которого производится ввод поправки в плюс/минус. Если брать аналогию с ТРВ, то нужно вообще делать minst=nulst
int start_pos = 0;        //при простое компрессора это значение вычитается из nulst для закрытия эрв.
int st = minst;          //установка ЭРВ в минимально открытое состояние.
int pre_st = minst;      // предыдущее положение.
int m = 0;              // Защёлка входа-выхода в ручной режим.
int p = 0;       //Опред простоя компрессора
int p1 = 0;       //Опред запуска компрессора
int p2 = 0;       //Опред запуска компрессора
unsigned long k1 = 0;  // счётчик времени  интегратора 1
unsigned long k2 = 0;  // счётчик времени интегратора 2
unsigned long t_over = 550000; // время ,mс, по истечении которого интегр сост приравнивается к сумме интегр и пропорциональной составляющих при ошибке более 2 гр. Задано на минуту больше времени разогрева ТН. При изменении t_discr менять не нужно.
unsigned int s = 10000;  // количество усреднений с датч давл. 10000 это около 1.2 секунд. Это время не должно превышать t_discr (ms) и не должно быть равным нулю
int start = 0;  // обнул Kci и Kp после входа в главный цикл программы
float err = 0.0 ;       //   Константы и переменные для вычисления ошибки и необходимого положения ЭРВ (st)
float need_SH = 4.0;   // Заданное значение перегрева
float tempA1;   // Температура кипения (давление) для использования в основном цикле
float tempB1;   // Температура всаса  для использования в основном цикле
float pre_tempA1;
float pre_tempB1; // Предыдущая температура
float Kp = 0.2;             // Коэф пропорц.Kp*err*err*err Тогда ошибка при 480 шагах будет 7.6гр.
int Kp_on = 0;          // Включение-выключение проп сост. Изначально проп сост выключена и включается при определении включения компрессора.
float Ki;               // Коэф интегр для подстановки в формулу st=.... Расчитывается в теле программы как Ki=t_discr/Ti.   Ki не должен быть равен нулю.
int Ki_on = 1;          // Вкл-выкл интегральной сост. В программе не меняется, задаётся только здесь для вкл-выкл.
int Ti = 70;            //  Постоянная времени интегрирования в секундах, нормированная.  Не зависит от частоты расчёта ошибки. Для исключения интегральной сотавляющей, Ti сделать максимально большим. 32 767. Или выключить коэффициентом Ki_on. Ti  не должно быть равным нулю
int Kci = 0;           // Выключатель разрешения процесса накопления интегр состаляющей. Изначально запрещено до определения вкл компрессора.
float C = 0.0;            // Служебная переменная интегрирования (накопительная)
int Td = 0;            //  Постоянная времени дифференцирования в секундах, нормированная. Не зависит от частоты расчёта ошибки. Для исключения дифф составляющей сделать Td=0.
float Kd;              // Коэф дифф для подстановки в формулу st=.... Расчитывается в теле программы как Kd=Td/t_discr.
int Kd_on = 0;           // Вкл-выкл дифф сост. Включается- выключается в теле программы по условиям определения вкл или выкл компрессора.
float pre_err = 0.0;        // Предыдущая ошибка в общем цикле вычисления шагов
float SH = 0.0;
unsigned long t_discr = 3000;  //  Время дискретизации PID st=......... Обязательно должна быть того же типа что и millis . не должно быть равным нулю
unsigned long previousMillis = 0;  // Служебная переменная коррекция интегрирующей цепью
unsigned long previousMillis3 = 0;  // Служебная переменная3 для гашения подсветки через заданное время после последнего нажатия любой кнопки.
int led = 1; // переменная для гашения подсветки
int ledoff = 1; // плавн гашение


void setup() {
  Ki = (float)t_discr / ((float)Ti * 1000.0);     //  Коэф интегр для подстановки в формулу st=....
  Kd = (float)Td * 1000.0 / (float)t_discr;     //Коэф дифф для подстановки в формулу st=....
  pinMode(10, OUTPUT);   // для гашения дисплея
  analogWrite(10, 40); // При старте подсветка дисплея включена
  sensors.begin();
  if (!sensors.getAddress(Suction, 0)) lcd.print("no find 0");
  sensors.setResolution(Suction, 12);
  stepper.setAcceleration(100);
  stepper.setMaxSpeed(70);
  lcd.begin(16, 2);
  lcd.print("Set EEV to");
  lcd.setCursor(0, 1);
  lcd.print("start position");
  delay(1000);
  stepper.runToNewPosition(-STEPS - 40);
  stepper.setCurrentPosition(0);
  delay(2000);
  stepper.runToNewPosition(minst);
  delay(2000);
  lcd.clear();
}


void manual()       // Функция ручного управления ЭРВ
{
  analogWrite(10, 40); // В ручном режиме подсветка включена и не выключается.
  lcd.clear();
  lcd.print("Manual mode");
  delay (1000);
  while  (m == 1)

    sensors.requestTemperatures();
    printTemperature(Suction);
    lcd.setCursor(9, 0);
  lcd.print("Meev");
  lcd.print(st);
  {
    sensorValue = analogRead(sensorPin); // read the value from the sensor: LEFT
    while (sensorValue < 550 && sensorValue > 355)
    {
      if (st > 0)
      {
        st = st - 1;
        lcd.clear();
        lcd.setCursor(9, 0);
        lcd.print("Meev");
        lcd.print(st);
        stepper.runToNewPosition(st);
        delay(200);
      }
      sensorValue = analogRead(sensorPin); // read the value from the sensor:
    }
    while  (sensorValue < 30)
    {
      if  (st < STEPS)
      {
        st = st + 1;
        lcd.clear();
        lcd.setCursor(9, 0);
        lcd.print("Meev");
        lcd.print(st);
        stepper.runToNewPosition(st);
        delay(200);
      }
      sensorValue = analogRead(sensorPin); //  read the value from the sensor: 1023 none; 639 (720)SET; 408 (481) LEFT; 0 RIGHT; 98 (131)UP; 254 (307) DOWN
    }

    if (sensorValue < 780 && sensorValue > 600) // Выход из ручного режима
    {
      m = 0;
      lcd.clear();
      lcd.print("Auto mode");
      led = 1; // Для гашения подсветки экрана через x минут после входа в автоматический режим.
      delay (1000);
    }

    while (sensorValue < 350 && sensorValue > 200)  // По нажатию кнопки Down уменьшаем перегрев (need_SH) с дискретностью 0,1 градус.
    {
      need_SH = need_SH - 0.1;
      if (need_SH <= 0.5) {
        need_SH = 0.5;
      }
      lcd.clear();
      lcd.setCursor(0, 0);
      lcd.print("set SH=");
      lcd.print(need_SH);
      delay(400);
      sensorValue = analogRead(sensorPin);
    }
    while (sensorValue < 180 && sensorValue > 50)  // По нажатию кнопки UP увеличиваем перегрев (need_SH) с дискретностью 0,1 градус.
    {
      need_SH = need_SH + 0.1;
      if (need_SH >= 10.0) {
        need_SH = 10.0;
      }
      lcd.clear();
      lcd.setCursor(0, 0);
      lcd.print("set SH=");
      lcd.print(need_SH);
      delay(300);
      sensorValue = analogRead(sensorPin);
    }
    delay(200);
    stepper.disableOutputs();
  }
}

void printTemperature(DeviceAddress t)
{
  intPressureValue = 0;                                              // Усредняем значение считанного давления. 112 мкс на одно чтение. 1.12 c на 10000 циклов
  for (long i = 0; i < s; ++i) {
    intPressureValue = intPressureValue + analogRead(A2);
  }
  PressureValue = (float)intPressureValue / (float)s;                            // среднее знач давл, float 1023.0
  UPressureValue = PressureValue * 0.004875044 ;   //       5/*1023, но поскольку реальный на этом контроллере Uref=4,98717 --->(4,98717/1023). ( до этого выставлял 0.00489632 )
  float tempA = 0.00 - 0.23783374 * pow(UPressureValue, 6) + 5.49765589 * pow(UPressureValue, 5) - 52.43191395 * pow(UPressureValue, 4) + 264.81602585 * pow(UPressureValue, 3) - 752.10945958 * pow(UPressureValue, 2) + 1166.07930268 * UPressureValue - 803.62383077 ;   // Температура кипения   Полином 6 степени сделанный в экселе по таблице температура кипения-напряжение.

  float tempB = sensors.getTempC(Suction);   // считываем температуру всасывания
  if (tempB > -127.00) // защита от сбоя датчика.
  {
    tempB1 = tempB;
  }

  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("Ev:");
  lcd.print(tempA);  // Температура кипения
  tempA1 = tempA;
  lcd.setCursor(0, 1);
  lcd.print("Sc:");
  lcd.print(tempB);    //  Suction temperature
  lcd.setCursor(9, 1);
  lcd.print("SH=");
  SH = tempB1 - tempA1;
  lcd.print(SH);
  lcd.setCursor(10, 0);
  lcd.print("eev");
  lcd.print(st);
  delay(200);
}

void loop() {
  unsigned long currentMillis = millis();

  sensors.requestTemperatures();               // Запрос датчиков, расчёт SH и новой ошибки
  printTemperature(Suction);

  sensorValue = analogRead(sensorPin);           // read the value from the sensor: 1023 none; 639 (720)SET; 408 (481) LEFT; 0 RIGHT; 98 (131)UP; 254 (307) DOWN
  if (sensorValue < 780 && sensorValue > 600)    // По нажатию кнопки SET вход в меню ручного управления.
  {
    m = 1;
    manual();
  }

  if (sensorValue < 900)    // При нажатии любой кнопки зажигаем подсветку.
  {
    analogWrite(10, 40);
    led = 1;
  }
  if (led == 1)
  {
    previousMillis3 = currentMillis;
    led = 0;
    ledoff = 1;
  }
  if ((currentMillis - previousMillis3) >= 60000  &&  ledoff == 1) // Гасим подсветку дисплея по истечении x минут после последнего нажатия любой клавиши.
  {
    analogWrite(10, 40);
    delay(100);
    analogWrite(10, 20);
    delay(100);
    analogWrite(10, 10);
    delay(100);
    analogWrite(10, 5);
    delay(100);
    digitalWrite(10, LOW);
    ledoff = 0;
  }

  if ((currentMillis - previousMillis) >= t_discr) //  ПОСТОЯННАЯ ВРЕМЕНИ ДЛЯ ПРОПОРЦИОНАЛЬНОЙ, ИНТЕГРАЛЬНОЙ И ДИФФЕРЕНЦИАЛЬНОЙ СОСТАВЛЯЮЩИХ , мС.Проблема была в разном типе переменных и в операции в функции абс()
  {
    err = SH - need_SH;
    if (err > 50) {
      err = 50;
    }
    if (err < -50) {
      err = -50;
    }
    previousMillis = currentMillis;

    // ********************************************************************************************Определение начальных условий******************************************
    if (start == 0) //  Обнуление проп и интегр сост при включении
    {
      start = 1;
      C = 0.0;
      Kp_on = 0;
      Kci = 0;
      Kd_on = 0;
      start_pos = nulst - minst;
    }
    float deltaB1 = pre_tempB1 - tempB1;
    float temp_derr = err - pre_err;
    if (abs(deltaB1) < 0.1 && abs(err) > 3 && abs(temp_derr) < 0.1) {
      p = p + 1;
    }
    else {
      p = 0;
    }    // При ошибке более 2 гр и отсутствии реакции датчика температуры на всасе, ошибки и дельты ошибки на протяжении времени p*3 cек подряд, определяем простой компрессора, сбрасываем интегральную состовляющую "С", пропорц  и дифф в ноль.
    if (p >= 130)
    {
      C = 0.0;
      Kci = 0;
      Kp_on = 0;
      Kd_on = 0;
      start_pos = nulst - minst;
      p = 0;
    }

    if (tempA1 - pre_tempA1 < -0.1) // Вкл пропорц и накопительную и дифф сост  при вкл комрессора.
    {
      p1 = p1 + 1;
    }
    else {
      p1 = 0;
    }
    if (p1 > 3)
    {
      Kp_on = 1;
      Kci = 1;
      Kd_on = 1;
      start_pos = 0;
      p1 = 0;
    }

    if (tempA1 - pre_tempA1 < -4.0) // Вкл пропорц и накопительную и дифф сост  при вкл комрессора.
    {
      p2 = p2 + 1;
    }
    else {
      p2 = 0;
    }
    if (p2 > 1)
    {
      Kp_on = 1;
      Kci = 1;
      Kd_on = 1;
      start_pos = 0;
      p2 = 0;
    }

    if (SH > 20 && tempA1 < -20) // Вкл пропорц и накопительную и дифф сост  при вкл комрессора.
    {
      Kp_on = 1;
      Kci = 1;
      Kd_on = 1;
      start_pos = 0;
    }
    // ********************************************************************************************Конец определения начальных условий********************************

    //  ******************** Обработка интегальной составляющей

    if (abs(err) >= abs(pre_err) || err > 2.0 || err < -1.5)   //  изменяем интегратор "С" только при ошибке более 2 или менее -1 градуса или при условии что ошибка увеличивается или остаётся прежней. и только если определено включение компресора (Kci=1)
    {
      if (err <= 10.0 && err >= -4.0) {
        C = C + (float)Kci * err;                                      // При ошибке не более 4 градусов интеграл с вычисляется без ограничений
      }
      if (err < -4.0) {
        C = C - Kci * 4.0;                                      // при ошибке менее -4 градусов, считаем err=-4.
      }
      if (err > 10.0) {                                            // при ошибке более +10 градусов, считаем err=10.
        C = C + Kci * 10.0;
      }
      if (SH < 0.8) {                                           // при опасно низком перегреве - ещё раз
        C = C + Kci * err;
      }
    }

    if (Ki_on * Ki * C > 40)
    {
      if (abs(err) >= abs(pre_err) || err > 2.0 || err < -1.4)   // Повторяем расчёт С при предыдущем положении более 100 шагов.
      {
        if (err <= 10.0 && err >= -4.0) {
          C = C + (float)Kci * err;
        }
        if (err < -4.0) {
          C = C - Kci * 4.0;
        }
        if (err > 10.0) {
          C = C + Kci * 10.0;
        }
        if (SH < 0.9) {
          C = C + Kci * err;
        }
      }
    }

    if (Ki_on * Ki * C > 80)
    {
      if (abs(err) >= abs(pre_err) || err > 2.0 || err < -1.3)   // Повторяем расчёт С при предыдущем положении более 160 шагов.
      {
        if (err <= 10.0 && err >= -4.0) {
          C = C + (float)Kci * err;
        }
        if (err < -4.0) {
          C = C - Kci * 4.0;
        }
        if (err > 10.0) {
          C = C + Kci * 10.0;
        }
        if (SH < 1.0) {
          C = C + Kci * err;
        }
      }
    }

    if (Ki_on * Ki * C > 160)
    {
      if (abs(err) >= abs(pre_err) || err > 2.0 || err < -1.2)   // Повторяем расчёт С при предыдущем положении более 256 шагов.
      {
        if (err <= 10.0 && err >= -4.0) {
          C = C + (float)Kci * err;
        }
        if (err < -4.0) {
          C = C - Kci * 4.0;
        }
        if (err > 10.0) {
          C = C + Kci * 10.0;
        }
        if (SH < 1.1) {
          C = C + Kci * err;
        }
      }
    }

    if (Ki_on * Ki * C > 320)
    {
      if (abs(err) >= abs(pre_err) || err > 2.0 || err < -1.1)   // Повторяем расчёт С при предыдущем положении более 409 шагов.
      {
        if (err <= 10.0 && err >= -4.0) {
          C = C + (float)Kci * err;
        }
        if (err < -4.0) {
          C = C - Kci * 4.0;
        }
        if (err > 10.0) {
          C = C + Kci * 10.0;
        }
        if (SH < 1.2) {
          C = C + Kci * err;
        }
      }
    }

    if (err < -1.4) {
      k1 = k1 + 1;
    }
    else {
      k1 = 0;
    }
    if (k1 > t_over / t_discr) {                 // При  ошибке менее -2 градусов в течение 10 минут (600000 мсек) подряд,
      C = C + (Kp_on * Ki_on * Kp * err * err * err) / Ki; // "C" устанавливается такой, чтобы новый интеграл был равен предыдущим интегралу и пропорц сост. Необходимое количество шагов обеспечивается за счёт интегрирующей составляющей.
      k1 = 0;
    }

    if (err > 2.0) {
      k2 = k2 + 1;
    }
    else {
      k2 = 0;
    }
    if ((k2 > t_over / t_discr)) {               // При  ошибке более +2 градусов в течение 10 минут (600000 мсек) подряд,
      C = C + (Kp_on * Ki_on * Kp * err * err * err) / Ki; // "С" устанавливается такой, чтобы новый интеграл был равен предыдущим интегралу и пропорц сост. Необходимое количество шагов обеспечивается за счёт интегрирующей составляющей.
      k2 = 0;
    }

    if (Ki * C >= (STEPS - nulst)) {
      C = (STEPS - nulst) / Ki;
    }                                                                      // Ограничение выражения nulst+Ki*C пределами (0 шагов- STEPS шагов) относительно средней точки nulst
    if (Ki * C <= (minst - nulst)) {
      C = (minst - nulst) / Ki;
    }                                                                      // Ограничение произведения nulst+Ki*C пределами (0 шагов- STEPS шагов) относительно средней точки nulst
    // ******************* Конец обработки интегральной составляющей.*********************************

    if (err >= 0)
    {
      st = (float)nulst - (float)start_pos + (float)Kp_on * Kp * err * err * err + (float)Ki_on * Ki * C + (float)Kd_on * Kd * (err - pre_err);
    }
    else
    {
      st = (float)nulst - (float)start_pos + (float)Kp_on * Kp * err * err * err * 2.0 + (float)Ki_on * Ki * C + (float)Kd_on * Kd * (err - pre_err);
    }

    // Максимальная температура кипения не более 19.5 градусов. Это максимум для Резистора 390 Ом и датчика 4-20 ма, сигнал на А2=5В.

    if (st > pre_st + 50) { // Огранчиваем максимальное перемещение эрв за 1 шаг t_discr
      st = pre_st + 50;
    }
    if (st < pre_st - 50) {
      st = pre_st - 50;
    }

    if (st >= STEPS) { // Ограничиваем диапазон шагов
      st = STEPS;
    }
    if (st <= minst) {
      st = minst;
    }

    stepper.runToNewPosition(st);
    delay (400);
    stepper.disableOutputs();

    if (sensorValue < 350 && sensorValue > 200)  // По нажатию кнопки Down на 2 секунды выводятся сервисные параметры.
    {
      lcd.clear();
      lcd.setCursor(0, 0);
      lcd.print("nSH=");
      lcd.print(need_SH);
      lcd.setCursor(7, 0);
      lcd.print(" err=");
      lcd.print(err);
      lcd.setCursor(0, 1);
      lcd.print(nulst);
      lcd.setCursor(3, 1);
      if (Kp_on * Kp * err * err * err >= 0)
      {
        lcd.print("+");
        lcd.setCursor(4, 1);
        lcd.print(Kp_on * Kp * err * err * err);
      }
      else
      {
        lcd.print(2.0 * Kp_on * Kp * err * err * err);
      }
      lcd.setCursor(7, 1);
      if (Ki_on * Ki * C >= 0)
      {
        lcd.print("+");
        lcd.setCursor(8, 1);
      }
      lcd.print(Ki_on * Ki * C);
      lcd.setCursor(12, 1);
      if (Kd_on * Kd * (err - pre_err) >= 0)
      {
        lcd.print("+");
        lcd.setCursor(13, 1);
      }
      lcd.print(Kd_on * Kd * (err - pre_err));
      delay (2000);
    }

    pre_err = err;
    pre_tempA1 = tempA1;
    pre_tempB1 = tempB1;
    pre_st = st;
  }
}















 

 

DIYMan
DIYMan аватар
Offline
Зарегистрирован: 23.11.2015

Перенесите функцию printTemperature выше того места, где она вызывается.

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

и научись вставлять чужой авнокод правильно. 

Alexander
Offline
Зарегистрирован: 25.04.2010
jan999
Offline
Зарегистрирован: 07.11.2017
Конкретно этот кусок кода, если есть возможность укажите как правильно надо перенести

void manual()       // Функция ручного управления ЭРВ
{
  
  analogWrite(10, 40); // В ручном режиме подсветка включена и не выключается.
  lcd.clear();
  lcd.print("Manual mode");
  delay (1000);
  while  (m == 1)

   sensors.requestTemperatures();
    printTemperature(Suction);
    lcd.setCursor(9, 0);
  lcd.print("Meev");
  lcd.print(st);

 

sadman41
Offline
Зарегистрирован: 19.10.2016

Конкретно тут всё рассказано с примерами: http://cppstudio.com/post/5291/ -> "В языках C и C++, функции должны быть объявлены до момента их вызова"

b707
Offline
Зарегистрирован: 26.05.2017

jan999 пишет:

Конкретно этот кусок кода, если есть возможность укажите как правильно надо перенести

Конкретно этот кусок кода трогать не надо - прочитайте еще раз ВНИМАТЕЛЬНО сообщение №1