Arduino (C ++) sketchc периодически зависает или сбрасывается: возможное переполнение - PullRequest
0 голосов
/ 28 сентября 2018

У меня проблемы с определением причины повторяющейся проблемы с некоторым кодом Arduino.Приведенный ниже код считывает два датчика температуры, отправляет результат в библиотеку PID и использует выходные данные для управления некоторыми реле в холодильнике (в основном, добавляя точный контроль температуры в холодильник).

Код зависает или Arduino периодически сбрасывается.Это происходит периодически, но период меняется - он останавливается каждые 30 минут, максимум около 30 часов.

Я подозреваю, что есть переполнение или что я пишу вне диапазона массива, но я не могу найти проблему.Маловероятно, что есть проблема с питанием - arduino подключен к источнику питания 10 В 12 В со специальным регулятором 5 В, поэтому я сомневаюсь в этом.

Я довольно новичок во всем этом и был бы очень признателен за любые указания или советы - даже некоторые советы о том, как устранить эту непредсказуемую ошибку, будут очень полезны!

Вот код:

Настройка и основной цикл, также проверяет аналоговый вход для заданной температуры:

// Call libraries for display, sensor, I2C, and memory. Library setup included as well.
#include <avr/pgmspace.h>
char buffer[20];

#include <Time.h>
#include <TimeLib.h>
#include <OneWire.h> 
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x3f,20,4); 
#include <DallasTemperature.h>
#include <PID_v1.h>

// Special Characters for the display and display animations
#if defined(ARDUINO) && ARDUINO >= 100
#define printByte(args)  write(args);
#else
#define printByte(args)  print(args,BYTE);
#endif
#define ONE_WIRE_BUS 5  //DS18S20 Signal pin on digital 2
uint8_t heart[8] = { 0x0,0xa,0x1f,0x1f,0xe,0x4,0x0};
uint8_t deg[8] = { 0x1c,0x14,0x1c,0x0,0x3,0x4,0x4,0x3};
uint8_t Pv[8] = { 0x1c,0x14,0x1c,0x10,0x10,0x5,0x5,0x2};
uint8_t Sv[8] = { 0xc,0x10,0x8,0x4,0x18,0x5,0x5,0x2};
// end special chars 


//************* Begin Variables Setup ***************//

//Sensors (ds18s20 needs additional chatter)

  byte addr1[8]= {0x28, 0x3F, 0xB5, 0x3C, 0x05, 0x00, 0x00, 0x25};
  byte addr2[8]= {0x28, 0xC7, 0xCD, 0x4C, 0x05, 0x00, 0x00, 0x0D};
  byte data1[12];
  byte data2[12];
  byte MSB = 0;
  byte LSB = 0; 
  float tempRead = 0;
  float TemperatureSum = 0;
  OneWire ds(ONE_WIRE_BUS);
  OneWire oneWire(ONE_WIRE_BUS); 
  DallasTemperature sensors(&oneWire);


//controller outputs
int ControlCpin = 6; // control to fridge
int ControlTpin = 8; // control to temperature/heater  (get aquarium heater)
int ControlLpin = 7; // control to light
int ControlApin = 9; // control to airflow

//operational vars (the button)
//int buttonPushCounter = 0;   // counter for the number of button presses DEPRACATED
int buttonState = 0;         // current state of the button
int lastButtonState = 0;     // previous state of the button
boolean buttonstate = false; // calculastate of the button (includes timer delay. use this in menus)
int buttontime = 0;          // press length measure 
int buttontimeon = 0;        // necessary for press length measure 

//operational vars (sensors and timing)
unsigned int sensorInterval = 20000;         // time between readings
unsigned long int sensorTime = 0;           // current time 
unsigned long int sensorTime2 = 0;          // time of last sensor reading

// fans, lights, and timers
unsigned long int fanONmillis = 0;
unsigned long int fanOFFmillis = 0;
byte fanON = 0;
byte fanOFF = 0;
boolean fanstate = false;
unsigned long int Time = 0;
unsigned long int TimeAdjust = 0;

unsigned long int LightON = 0;
unsigned long int LightOFF = 0;
unsigned int Hours = 0;
unsigned int Minutes = 0;
unsigned int Days = 0;
byte daysAdj = 0; //not implemented yet
float tempDiff = 0;

//key var storage
float PvH = 0; 
double PvT = 0;
float SvH = 0; 
double SvT = 12; 
float SvTdisplay = 5.5;
float SvTdisplayOld = 5.5;

float Temp1;                   //Current readings
float Temp2;                   //Current readings
float Temp3;                   //Current readings

// Fridge limits
unsigned int safetyRest = 5; // off this long every hour (minimum) to let the compressor rest in minutes
int minCool = 10; // minimum cooling period in minutes
int coolStart = 0;
byte coolON = 0;  // PID attached to this

// Heat limits
byte heatON = 0;  // PID attached to this

//cool
double Kp = 0.5;
double Ki = 0.5;
double Kd = 0.5;
double Output;
PID coolPID(&PvT, &Output, &SvT ,Kp,Ki,Kd, REVERSE);
unsigned coolWindowSize = 600;  // minutes*10
unsigned long coolWindowStartTime;
unsigned long coolOffElapsed = 0;
long unsigned PIDpos = 0; 

  unsigned long Outputx = 0;
  unsigned long PIDposx = 0;
  unsigned long safetyRestx = 0;

// ensure setpoint, input, and outpit are defined

//************* End Variables Setup ***************//


void setup(){

//Sensor start

  sensors.begin();


//Pin declarations  
  pinMode(ControlTpin, OUTPUT); //set outputs
  pinMode(ControlLpin, OUTPUT);
  pinMode(ControlApin, OUTPUT);
  pinMode(ControlCpin, OUTPUT);
  digitalWrite(ControlTpin, HIGH); // write outputs HIGH (off in this case) FIRST to prevent startup jitters.
  digitalWrite(ControlLpin, HIGH); 
  digitalWrite(ControlApin, HIGH); 
  digitalWrite(ControlCpin, HIGH); 

//LCD and special chars
  Serial.begin(9600);
  lcd.begin();                      
  lcd.backlight();
  lcd.createChar(0, heart);
  lcd.createChar(1, deg);
  lcd.createChar(2, Pv);
  lcd.createChar(3, Sv);
  lcd.clear();
  LoadScreen();
  HomeSetup();
  //PID setup
  coolPID.SetOutputLimits(0, coolWindowSize);
  coolPID.SetMode(AUTOMATIC);
  coolOffElapsed = millis();
}

void loop(){
  //if interval has passed, check the sensors, update the triggers, and update the screen
  if (millis() - sensorTime2 > sensorInterval){ 
     sensorTime2 = millis();
     SensorCheck();
     Triggers();
     HomeSetup ();
  }

  SvTdisplay = (float)analogRead(A0);
  SvTdisplay = SvTdisplay/40+5;
  if(abs(SvTdisplay-SvTdisplayOld) > 0.2){
    SvTdisplayOld = SvTdisplay;
    lcd.setCursor(2,0);
    lcd.print(SvTdisplayOld,1);     //svt
    lcd.printByte(1);
    lcd.print(" ");
    SvT = analogRead(A0)/4+50;
    }
  PIDpos = ((millis()/60000) % (coolWindowSize/10));
 }

Следующие коды экрана загрузки и обновляют экран с текущими значениями:

void LoadScreen (){
  lcd.clear();
  lcd.home();
  lcd.setCursor(0,0);
  lcd.print(" LaggerLogger "); 
  lcd.printByte(0);
  lcd.setCursor(0,1);
  lcd.print(" V2.0 Beepboop!"); 
  delay(3000);
  lcd.clear();
 }

//write the home screen to the LCD with current data 

void HomeSetup(){
  lcd.setCursor(0,0);
  lcd.printByte(3);
  lcd.print(" ");
  lcd.print(SvTdisplayOld,1);     //svt
  lcd.printByte(1);
  lcd.print(" ");
  lcd.setCursor(0,1);
  lcd.printByte(2);
  lcd.print(" "); 
  lcd.print(PvT/10,1);   //pvt
  lcd.printByte(1);
  lcd.print(" ");
  lcd.setCursor(8,1);
  lcd.print(day()-1);
  lcd.print("/");
  lcd.print(hour());
  lcd.print(":");
  lcd.print(minute());
  lcd.print(" ");
  lcd.setCursor(8,0);
  lcd.print(Output/10,1);
  lcd.print("m/h ");    
}

Следующее проверяет выходные значения и «запускает» реле, если это уместно:

void Triggers () {
  coolPID.Compute();

  // Check PID
  if ((Output/10) > (coolWindowSize/10-PIDpos) && PIDpos > safetyRest ) {  //
    coolON = 1;
    coolStart = millis();
  }
  else if ((millis() - coolStart) > (minCool * 60000)){
    coolON = 0;
  }
  else {}

  // Write to temp relay pins
  if (coolON == 1) {
    digitalWrite(ControlCpin, LOW);
  }
  else {
    digitalWrite(ControlCpin, HIGH);
  }

  // Control fans
  if (coolON == 1 || heatON == 1 || tempDiff > 1) {
    fanOFFmillis = millis();
    fanONmillis = millis();
    fanstate = true;
    digitalWrite(ControlApin, LOW);
  }
  else {
    fanstate = false;
    digitalWrite(ControlApin, HIGH);
  }
}

Следующее проверяет датчики температуры и выполняет некоторые вычисления часов:

void SensorCheck(){ 

     Temp1 = getTemp1();
     Temp2 = getTemp2();

    //average readings and note the difference
    if(Temp1 > 0 && Temp2 >0) { 
      PvT = (Temp1 + Temp2) / .2;
      tempDiff = abs(Temp1 - Temp2);
    }

    //... unless there's only one thermometer...
    else if (Temp1 > 0){  
      PvT = Temp1*10;
      tempDiff = 0;
    }
    else {
      PvT = 999;
      tempDiff = 0;
    }

    //clock update
    Time = millis() + TimeAdjust;
    Hours = hour();
    Minutes = minute();
    Days = day();  
}

float getTemp1(){
 sensors.requestTemperatures();
 float z = sensors.getTempCByIndex(0);
 return z;
 }

float getTemp2(){
 sensors.requestTemperatures();
 float z = sensors.getTempCByIndex(1);
 return z;
}

1 Ответ

0 голосов
/ 30 сентября 2018

Проблема заключалась в том, что целое число (объявленное как int coolStart) было позже обновлено для хранения значения millis ().

Millis () может быть намного больше, чем 16 бит, доступных для int, создаваяпереполнение.

Изменение объявления переменной на «unsigned long coolStart = 0;»Похоже, что проблема решена.

Спасибо всем за советы по устранению неполадок.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...