Помощь в коде контроллер для управления электронного терморегулирующего вентиля
- Войдите на сайт для отправки комментариев
Втр, 07/11/2017 - 02:35
Прошу помощи не работает скетч появляется ошибка: 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; } }
Перенесите функцию printTemperature выше того места, где она вызывается.
и научись вставлять чужой авнокод правильно.
http://arduino.ru/forum/obshchii/vstavka-programmnogo-koda-v-temukomment...
Конкретно тут всё рассказано с примерами: http://cppstudio.com/post/5291/ -> "В языках C и C++, функции должны быть объявлены до момента их вызова"
Конкретно этот кусок кода, если есть возможность укажите как правильно надо перенести
Конкретно этот кусок кода трогать не надо - прочитайте еще раз ВНИМАТЕЛЬНО сообщение №1