First project, random freezing + any general advice is welcome!

Hi all!

Wall of text incoming, sorry in advance!

First let me say thanks for having such a great community! This system is pretty amazing, and the level of support for it is outstanding!

Intro: I am not a programmer. I wouldn't even call myself a dabbler, I might be willing to say I'm a corrupter of good code though :blush: This is my very first Arduino project and my first foray into programming, unless you count if statements in excel?

I have a project that I'm working on for personal use, so none of that secretive partial code posting here! I'll just post up the entire thing and feel free to tear it up.

My project is basically a thermostat, I have most everything working correctly. There are still a couple of features that I would like to add, like a hysteresis on the temp adjustment so I don't have 15-20 amps kicking on and off multiple times a second. Finishing the debounce for the set point adjustment (I had it written, it compiled, happy day!, then the buttons did nothing :confused: ).

The Arduino is currently powered off of USB and the eventual plan is to power it off of the 5v input line from a PSU from a computer. (Or I can put a drop down resistor in there and use the 12v line if you guys think that the 5v won't be enough)

I did the bad thing and found other examples of code from probably 10 or 15 sources, copied what I needed, tweaked it until it was what I wanted and then added to it.

Some of it is probably not very efficient, but again, I am not even a fledgling programmer, this is my very first time dealing with this type of project, so constructive criticism is welcome!

Also, I am basically using the serial output as a button debounce.... :blush: When I disable the serial one push of the button registers 10-20 times. When I enable the serial the button acts like a normal button should (I'm assuming that it's just dragging the Arduino down that much?). My plan is to figure out the button debounce I've seen and get it working. As I mentioned before I had it all coded and it compiled, but then the buttons did nothing, still not sure where I went wrong, but I'll eventually figure it out!

Here is the problem I am having (this time): As the project sits right now the code I am posting works. It does exactly what I want, but occasionally freezes. It usually takes a couple of hours, and it doesn't happen every time, sometimes it runs for 12 hours just fine, others, about 30 minutes. All I have to do to unfreeze the system is open the serial monitor and suddenly everything is running again. I know that the system was frozen and not just the LCD because I can hit the adjust temperature up 10 or 15 times, and as soon as it unfreezes it is still at the same point it was prior to the lock up.

Code in next post due to character limitations.

Thanks for any advice or help!

//All credit goes to the *ahem* borrowed codes original authors
//I just hacked it together and tweaked it for my use

/*-----( Import needed libraries )-----*/
#include <dht.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>

/*-----( Declare objects )-----*/
//I2C LCD
// Set the pins on the I2C chip used for LCD connections:
// addr, en,rw,rs,d4,d5,d6,d7,bl,blpol
#define I2C_ADDR    0x27   //LCD
#define BACKLIGHT_PIN 3    
#define En_pin  2
#define Rw_pin  1
#define Rs_pin  0
#define D4_pin  4
#define D5_pin  5
#define D6_pin  6
#define D7_pin  7

#define DHT22PIN 2          //DHT22 sensor

//Thermosistor
#define THERMISTORPIN A0    //Thermosistor
#define NUMSAMPLES 5
#define SERIESRESISTOR 10000
#define THERMISTORNOMINAL 10000  // resistance at 25 degrees C
#define TEMPERATURENOMINAL 25    // temp. for nominal resistance (almost always 25 C)
#define BCOEFFICIENT 3950        // The beta coefficient of the thermistor (usually 3000-4000)

int samples[NUMSAMPLES];

//switch for offset adjustment
const int SW1pin = 3;       // Pushbutton switch, raise setpoint
const int SW2pin = 4;       // Pushbutton switch, lower setpoint
int SW1state = 0;           // Current reading of SW1
int SW2state = 0;           // Current reading of SW2
double offset = 2.0;        //setPoint adjustment

int TEC1on = 7;            //TEC 1 output
int TEC2on = 8;            //TEC 2 output

LiquidCrystal_I2C lcd(I2C_ADDR,En_pin,Rw_pin,Rs_pin,D4_pin,D5_pin,D6_pin,D7_pin);

dht DHT22;

void setup()
{
  Serial.begin(9600);
  lcd.begin(16,2);         // initialize the lcd for 16 chars 2 lines
  // Switch on the backlight
  lcd.setBacklightPin(BACKLIGHT_PIN,POSITIVE);
  lcd.setBacklight(HIGH);
  lcd.home ();                   
 
  //switch for offset adjustment
  pinMode(SW1pin, INPUT_PULLUP);  // Enable pull-ups on switches
  pinMode(SW2pin, INPUT_PULLUP);

  //Thermosistor
  // connect AREF to 3.3V and use that as VCC, less noisy!
  analogReference(EXTERNAL);  
  
  //TEC enable pins
  pinMode(TEC1on, OUTPUT);
  pinMode(TEC2on, OUTPUT);
  
}


void loop()
{
  int chk = DHT22.read(DHT22PIN);
 
 //Thermosistor Instructions for A/D temp 
     uint8_t i;
  float average;

  // take N samples in a row, with a slight delay
  for (i=0; i< NUMSAMPLES; i++) 
  {
   samples[i] = analogRead(THERMISTORPIN);
   delay(10);
  }
 
  // average all the samples out
  average = 0;
  for (i=0; i< NUMSAMPLES; i++) 
  {
     average += samples[i];
  }
  
  average /= NUMSAMPLES;
 
  Serial.print("Average analog reading "); 
  Serial.println(average);
 
  // convert the value to resistance
  average = 1023 / average - 1;
  average = SERIESRESISTOR / average;
  Serial.print("Thermistor resistance "); 
  Serial.println(average);
 
  float steinhart;
  steinhart = average / THERMISTORNOMINAL;     // (R/Ro)
  steinhart = log(steinhart);                  // ln(R/Ro)
  steinhart /= BCOEFFICIENT;                   // 1/B * ln(R/Ro)
  steinhart += 1.0 / (TEMPERATURENOMINAL + 273.15); // + (1/To)
  steinhart = 1.0 / steinhart;                 // Invert
  steinhart -= 273.15;                         // convert to C
  
  //TEC instructions
  if (steinhart > (setPoint(DHT22.temperature, DHT22.humidity))) 
  {
    digitalWrite(TEC1on, HIGH);
  } 
  else 
  {
    digitalWrite(TEC1on, LOW); 
  }
  
  if ((steinhart - 2) > (setPoint(DHT22.temperature, DHT22.humidity))) 
  {
    digitalWrite(TEC2on, HIGH);
  } 
  else 
  {
    digitalWrite(TEC2on, LOW); 
  }
  
  //Offest switch instructions
  // Check states of pushbuttons, if pressed change setpoint up or down    
  SW1state = digitalRead(SW1pin);
    if (SW1state == 0) 
      offset++;
  SW2state = digitalRead(SW2pin);  
    if (SW2state == 0) 
      offset--; 
  
  Serial.print("Read sensor: ");
  switch (chk)
  {
    case 0: Serial.println("OK"); break;
    case -1: Serial.println("Checksum error"); break;
    case -2: Serial.println("Time out error"); break;
    default: Serial.println("Unknown error"); break;
  }
  
  lcd.setCursor(0, 0);

  lcd.print("C=");
  if ((float)DHT22.temperature < 9.5) lcd.print(" ");
  lcd.print((float)DHT22.temperature, 0);
  Serial.print("Temperature (C): ");
  Serial.println((float)DHT22.temperature, 2);

  lcd.print(" H=");
  if ((float)DHT22.humidity < 9.5) lcd.print(" ");
  lcd.print((float)DHT22.humidity, 0);
  lcd.print("%");
  Serial.print("Humidity (%): ");
  Serial.println((float)DHT22.humidity, 2);

  lcd.print(" R=");
  if (steinhart < 9.5) lcd.print(" ");
  lcd.print(steinhart, 0);
  Serial.print("Reservoir (C): ");
  Serial.println(steinhart, 2);  
  
  lcd.setCursor(0, 1);
  
  lcd.print("DP=");                                                                                         
  if (dewPointFast(DHT22.temperature, DHT22.humidity) < 9.5) lcd.print(" "); 
  lcd.print (dewPointFast(DHT22.temperature, DHT22.humidity), 0);
  Serial.print("Dew PointFast (C): ");
  Serial.println(dewPointFast(DHT22.temperature, DHT22.humidity));
  
  lcd.setCursor(8, 1);
  
  lcd.print(" SP=");
  if (setPoint(DHT22.temperature, DHT22.humidity) < 9.5) lcd.print(" ");
  lcd.print (setPoint(DHT22.temperature, DHT22.humidity), 0);
  Serial.print("Set Point (C): ");
  Serial.println(setPoint(DHT22.temperature, DHT22.humidity));
 
 if (dewPointFast(DHT22.temperature, DHT22.humidity) > 0 && dewPointFast(DHT22.temperature, DHT22.humidity) < 0.2) lcd.clear(); 
 
}

/*-----( Declare User-written Functions )-----*/

double dewPointFast(double celsius, double humidity)
{
        double a = 17.271;
        double b = 237.7;
        double temp = (a * celsius) / (b + celsius) + log(humidity/100);
        double Td = (b * temp) / (a - temp);
        return Td;
}

//Set Point for Reservoir, minimum offset temp = 2c
double setPoint(double celsius, double humidity)
{
        offset = constrain(offset, 1, 60);      
        double a = 17.271;
        double b = 237.7;
        double temp = (a * celsius) / (b + celsius) + log(humidity/100);
        double Td = (b * temp) / (a - temp);
        double Sp = Td + offset;
        if (Sp < 2) {return 2;}
        //else if (Sp <= Td) {return Td + 1;}
        else {return Sp;}
        
}
 
 //End

It restarts on the Serial monitor because that resets the board.

Usually the random freeze is a memory problem. Try using the F macro on all your prints of constant strings and see if freeing up some RAM helps.

Serial.println("This string consumes a lot of RAM");
Serial.println(F("And this string consumes none so it's much better"));

Thanks Delta_G,

I wasn't aware that opening the serial monitor reset the entire board.

I was just reading about the memory problem in the sticky. Guess I'm off to find a tutorial on the F macro so I actually understand what I'm putting in!

I'll give it a shot!

So reading it over, it appears that the F() macro tells the compiler to keep the ‚Äúconstants‚ÄĚ in flash memory instead of SRAM, is that correct?

So for say this line:

serial.print("A Constant String ");
serial.println(variable1);

I would put it in as:

serial.print(F("A Constant String ");
serial.println(variable1);

and this would free up the SRAM for the important task of actually calculating variables.

That makes sense.

So, in the same vein, the F() macro is basically something just written into the arduino.h Wstring.h library? Which is included by default into all Arduino sketches?

So when I put

serial.print(F("Constant"));

The F macro code is

WString.h:#define F(string_literal) (reinterpret_cast<const __FlashStringHelper *>(PSTR(string_literal)))

Which is gibberish to me… I understand what it is doing (from smart peoples explanations!) mostly…

It only works for strings, won’t work for bit-patterns for characters (would this be for like a LED display?)

BUT! You can (and apparently should!) use this for lcd.print also! Thanks again!

Most any print method can use the F macro. You can use it with LCD.print or client.print as well as long as the string is constant