Программирую модуль климат-контроля. Есть вопрос.

AndyE
Offline
Зарегистрирован: 30.04.2015

Здравствуйте. 

Затеял первый "серьезный" проект и столкнулся с некоторыми непонятками.

На данный момент код такой:

#include "Servo.h"
#include "DHT.h"
#include "PID_v1.h"
#include "PCD8544.h"
#include "EEPROM.h"

// Digital pins & PWM
#define POWER_RELAY        22       //реле поддержки питания
#define POWER_IN           23       //включение зажигания
#define INNER_SENSOR       24       //датчик температуры и влажности внутреннего воздуха цифровой (DHT11)
#define HEATER_MOTOR       2        //нога по которой управляется скорость вращения вентилятора отопителя
#define HEATER_VALVE       3        //сервопривод управления клапаном ОЖ
#define OUTER_AIR_SERVO    4        //сервопривод управления заслонкой воздуха
#define STATE_LED          13       //встроенный светодиод для индикации работы и имитации бурной деятельности

//Analog in pins
#define OUTER_TEMP         A0       //датчик температуры наружнего воздуха аналоговый
#define COOLANT_TEMP       A1       //датчик температуры теплоносителя

//настройки кнопочной станции
#define KEYTEMPUP          30       // |
#define KEYTEMPDOWN        31       // | регулировка температуры
#define KEYMODEAUTO        32       // режим автоматического регулирования скорости вентилятора
#define KEYONOFF           33       // включение\выключение модуля
#define KEYFANUP           34       // |
#define KEYFANDOWN         35       // | регулировка скорости вращения вентилятора
#define OUTER_AIRIN        36       // закрытие забора воздуха с улицы

//разметка EEPROM
#define FAN_SPEED          1        //
#define SETPOINT           2        // Адреса EEPROM для чтения значений при загрузке   
#define MODE_AUTO          3        // 

//тип датчика DHT
#define DHTTYPE DHT11               // у меня такой, если нужен другой тип - раскоментируй соответствующую строку
//#define DHTTYPE DHT21
//#define DHTTYPE DHT22

Servo heaterValve;
Servo outerAir;

static int heaterSpeed = 0;
static double outerTemp;
static double innerTemp;
static double innerHum;
static boolean modeAuto;

static double Setpoint, Input, Output;                       // создаем переменные для ПИД

//задаем коэффициенты ПИД
static double aggKp = 4, aggKi = 0.2, aggKd = 1;             // агрессивные
static double consKp = 1, consKi = 0.05, consKd = 0.25;      // консервативные

static double histeresis = 1;                                // коэффициент петли гистерезиса. пока не используется.
unsigned long beginTime;                                     // переменная начала работы таймера выключения

void setup()
{
  //первым делом взведем реле
  digitalWrite(POWER_RELAY, HIGH);

  // запуск порта отладки
  Serial.begin(9600);

  Serial.println("Climatic module v 0.1");    // Красивости...
  Serial.print("Initialising");
  delay(500);
  Serial.print(".");
  delay(500);
  Serial.print(".");
  delay(500);
  Serial.print(".");
  delay(500);
  Serial.print(".");
  delay(500);
  Serial.print(".");
  delay(500);                                 //В принципе не мешают, пусть будут. Время работы в данной части не критично

  // конфигурируем выходы
  pinMode(POWER_RELAY, OUTPUT);             // Выход "Реле "Камикадзе" (Поддерживает питание системы некоторое время после выключения зажигания, затем отключается)
  pinMode(HEATER_MOTOR, OUTPUT);            // Выход "Вентилятор"
  pinMode(HEATER_VALVE, OUTPUT);            // Выход "Клапан"
  pinMode(STATE_LED, OUTPUT);               // Встроенный светодиод
  Serial.println();
  Serial.println("Outputs configured");

  // конфигурируем входы
  pinMode(OUTER_TEMP, INPUT);               // Вход "Температура снаружи"
  pinMode(COOLANT_TEMP, INPUT);             // Вход "Температура теплоноситель"
  pinMode(KEYTEMPUP, INPUT);                // |
  pinMode(KEYTEMPDOWN, INPUT);              // |
  pinMode(KEYFANUP, INPUT);                 // |Входы кнопок
  pinMode(KEYFANDOWN, INPUT);               // |
  pinMode(KEYONOFF, INPUT);                 // |
  pinMode(KEYMODEAUTO, INPUT);              // |
  pinMode(OUTER_AIRIN, INPUT);              // |
  Serial.println();
  Serial.println("Inputs configured");

  //добавляем приводы
  heaterValve.attach(HEATER_VALVE);
  outerAir.attach(OUTER_AIR_SERVO);
  Serial.println();
  Serial.println("Servos attached");

  //создаем вызов внутреннего датчика температуры-влажности
  DHT inTemp(INNER_SENSOR, DHTTYPE);
  inTemp.begin();
  Serial.println();
  Serial.println("Inner temperature sensor is ready");

  //запускаем ПИД
  PID myPID(&Input, &Output, &Setpoint, consKp, consKi, consKd, DIRECT);
  Serial.println();
  Serial.println("PID started");

  //считываем значения предыдущего запуска
  heaterSpeed = EEPROM.read(FAN_SPEED);
  Setpoint = EEPROM.read(SETPOINT);
  modeAuto = EEPROM.read(MODE_AUTO);
  Serial.println();
  Serial.println("Previvous start data:");
  Serial.print("Fan speed: ");
  Serial.println(heaterSpeed);
  Serial.print("Temperature set: ");
  Serial.println(Setpoint);
  Serial.print("Fan mode: ");
  if (modeAuto == 0) {
    Serial.println("Manual");
  }
  else {
    Serial.println("Auto");
  }
  Serial.println(modeAuto);

  //приводим систему в стартовое состояние
  analogWrite(HEATER_MOTOR, heaterSpeed); //да, 0=0, но пусть пока будет для страховки
  outerTemp = analogRead(OUTER_TEMP);
  innerHum = inTemp.readHumidity();
  innerTemp = inTemp.readTemperature();
  Serial.println();
  if (innerTemp >= -50)
  {
    if (innerTemp <= 60) {
      Serial.print("Current temperature: ");
      Serial.print(innerTemp);
      Serial.println(" ᵒC");
    }
    else
    {
      Serial.println("It's too HOT here! Or temperature sensor fail.");
    }
  }
  else
  {
    Serial.println("It's too COLD here! Or temperature sensor fail.");
  }
  if (innerHum > 0 && innerHum < 100)
  {
    Serial.print("Current humidity: ");
    Serial.print(innerHum);
    Serial.println(" %");
  }
  else
  {
    Serial.println("Something wrong with humidity sensor!");
  }
  if (outerTemp > -50)
  {
    if (outerTemp < 50) {
      Serial.print("Current temperature: ");
      Serial.print(outerTemp);
      Serial.println(" ᵒC");
    }
    else
    {
      Serial.println("It's too HOT here! Or temperature sensor fail.");
    }
  }
  else
  {
    Serial.println("It's too COLD here! Or overboard temperature sensor fail.");
  }
  Serial.println("Thanks for flying our airline!");

}

void loop()
{
  Serial.println("Starting!");
  //код вызова завершающей функции
  if (digitalRead(POWER_IN) == LOW)
  {
    beginTime = millis();
    ending();
  }
  delay(1000);
}

void ending()
{
  /*эта часть нужна для задержки выключения питания платы при запитке через реле "Камикадзе" но она пока нихрена не работает как задумано.*/
  Serial.println("Ignition OFF");
  Serial.println(beginTime);
  Serial.println(millis());
  scanIgnition();
  Serial.println("Turning system OFF");
  digitalWrite(POWER_RELAY, LOW);
}

void scanIgnition ()
{
do {
    if (digitalRead(POWER_IN) == HIGH)
    {
      Serial.println("Ignition ON");
      loop();
    }
  }
  while (beginTime > (millis() - 100000));
}

Проблема заключается в следующем. в секции loop() пытался реализовать проверку наличия внешнего питания через проверку состояния цифрового входа. Проверка происходит (строки 192-196). При пропадании сигнала вызывается соответствующая (ending()) функция. А дальше начинаются странности.

Как я предполагал выполнение основной функции должно останавливаться и обработка передается в "дочернюю" функцию. Но почему-то loop() продолжает выполняться.

Воторой вопрос, с которым столкнулся - как остановить полностью выполнение программы? По идее после того, как будет отключено реле (строка 208), питание с платы пропадет. Но в случае работы "на столе" программа продолжает выполняться.

Программа расчитана на МЕГУ. 

vosara
vosara аватар
Offline
Зарегистрирован: 08.02.2014

Попробуйте функции в коде "void ending(), scanIgnition ()" перенести выше void loop() или обьявить до void loop()

AndyE
Offline
Зарегистрирован: 30.04.2015

К сожалению не помогло.

maksim
Offline
Зарегистрирован: 12.02.2012

Нет тут никаких станностей, что пишите, то и получаете. Что должно препятствовать продолжению выполнения основного цикла? Что вы пытаетесь сделать в строке 220? Попробуйте посчитать, что у вас получится в этой строке если например beginTime = 100, а millis() возвращает 101.

AndyE
Offline
Зарегистрирован: 30.04.2015

Я пытался задать интервал времени для того чтобы система ждала появления сигнала на входе POWER_RELAY.

Переписал скетч так, чтобы к переменной beginTime сразу же прибавлялся этот интервал и объеденил обе процедуры в одну. Этот кусок кода заработал как надо. Спасибо!

А что можете посоветовать для остановки выполнения кода программы? 

maksim
Offline
Зарегистрирован: 12.02.2012

Если ваша система не будет работать месяцами, то такое решение прокатит, если же нет, то примерно через 40 дней ждите глюка. http://arduino.ru/forum/programmirovanie/eshche-raz-migaem-svetodiodom-b...

while(1);

 

AndyE
Offline
Зарегистрирован: 30.04.2015

Спасибо! while(1) - то, что надо. Про переполнение значения я в курсе. Блок проектируется для авто. Аптайм 40 суток не реален.

Sloper
Sloper аватар
Offline
Зарегистрирован: 30.03.2015

Канонический таймер (например 3 сек):

unsigned long time;

void setup(){
}

void loop(){
if ((millis()-time) >3000){
   // команды по таймеру
  time = millis();
  }
}

А остановить скечь: for (;;){}