Pages: [1]   Go Down
Author Topic: Greenhouse controller v0.4  (Read 1058 times)
0 Members and 1 Guest are viewing this topic.
0
Offline Offline
Newbie
*
Karma: 0
Posts: 14
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

This is my first project with the arduino, and I know, I jumped right in.  This is a pretty big project for a first.  I feel like each small part is a hundred sub projects.  It's not nearly complete, but I have a working partial version right now, and I figured I might as well put it out there, see if I get any feedback.  My documentation is pretty sloppy, but I do put effort into documenting it, so you should be able to see what's going on pretty well.  Again, very much a work in progress.  At the moment it's fairly limited in capability, here's some stats:

3 outputs (ULN2003 to 12v relay to 110v relay): a water pump, artificial sunlight and a green LED worklight.  (Green light does not interrupt the darkness requirement flowering photosensitive plants have)

2 analog inputs: temperature sensors, LM34DZ

2 digital inputs : regular momentary NO pushbuttons

http://mulletsoda.seedtheplanet.com/marvin.jpg

http://code.google.com/p/atmega328growcontroller/    <~~ More detailed info

Quote
#include "OutletTimer.h"
#include "DigitalInputter.h"
#include "PrintPJRClcd.h"

/*Initialize outlets, OutletTimer(pinNumber, InitialMode, InitialTimeSec) */
OutletTimer MainLightOutletTimer(10,0,300);// Main light
OutletTimer MainVegPumpOutletTimer(9,1,60);//Water pumps
OutletTimer GreenWorkLightOutletTimer(8,4,0);//work lights

/* Initialize digital inputs DigitalInputter(int pinNumber) */
DigitalInputter WorkLightButton(7);
DigitalInputter PumpToggleButton(6);


/* Open LCD library on serial port */
PrintPJRClcd LCD = PrintPJRClcd(); 

/* Initialize analog inputs */
int AnalogRezTemp = 0;
int AnalogAirTemp = 0;
#define AnalogRezTempPin 0
#define AnalogAirTempPin 1

/* Variables for time watching */
unsigned long previousMillis = 0;        // will store last time millis
unsigned long curMillis = 0;
int timeSinceLast = 0;

/* floats for calculating time */
float MainLightTimeFloat;
unsigned char LoopsAround = 0;
void setup()
{

  /*   Set outlet on and off times  */
  MainLightOutletTimer.OnDuration = 64800; //main lights, 64800 = 18 hours
  MainLightOutletTimer.OffDuration = 21600; // 21600 = 6 hours
  MainVegPumpOutletTimer.OnDuration = 60;//veg pump
  MainVegPumpOutletTimer.OffDuration = 600;
  GreenWorkLightOutletTimer.OnDuration = 0;
  GreenWorkLightOutletTimer.OffDuration = 0;
  Serial.begin(19200);
  delay(1000);
  LCD.RedrawScreen();

}

void loop()
{

  /* Check inputs */
  if (WorkLightButton.CheckPin())   // if work light button has been pushed
  { 
    if (GreenWorkLightOutletTimer.CurrentMode==4) GreenWorkLightOutletTimer.ChangeMode(5); // if current mode is perm off, turn it perm on
    else if (GreenWorkLightOutletTimer.CurrentMode==5) GreenWorkLightOutletTimer.ChangeMode(4);
  };      
  if (PumpToggleButton.CheckPin()) //if pump button has been pushed
  {
    switch(MainVegPumpOutletTimer.CurrentMode) //what's the veg pump at now?
    {
    case 0: //off, normal operation
      MainVegPumpOutletTimer.ChangeMode(1);
      break;
    case 1: //on, normal operation
      MainVegPumpOutletTimer.ChangeMode(4);
      break;
    case 4: // perm off
      MainVegPumpOutletTimer.ChangeMode(5);
      break;
    case 5: // perm on
      MainVegPumpOutletTimer.ChangeMode(0);                  
      break;
    };
  };



  /*measure time past since last loop and increment down */
  curMillis = millis();
  if (curMillis < previousMillis) previousMillis = 0.0; //roll over check
  timeSinceLast = curMillis- previousMillis;
  previousMillis = curMillis;

  /* Analog inputs */
  AnalogRezTemp = analogRead(AnalogRezTempPin);
  AnalogAirTemp = analogRead(AnalogAirTempPin);

  /* Print info to screen */
  //LCD.RedrawScreen();
  LCD.PrintData(0,int(AnalogAirTemp/2.1));
  LCD.PrintData(1,int(AnalogRezTemp/2.1));
  LCD.PrintData(2,MainVegPumpOutletTimer.CurrentMode);
  LCD.PrintData(3,(MainVegPumpOutletTimer.TimeLeft/1000));
  LCD.PrintData(4, MainLightOutletTimer.CurrentMode);
  MainLightTimeFloat = ((long(MainLightOutletTimer.TimeLeft)/1000)/60);
  LCD.PrintData(5, int(MainLightTimeFloat));
  LCD.PrintData(6, GreenWorkLightOutletTimer.CurrentMode);
  /* Pass Time Since Last loop to each outlet */

  MainLightOutletTimer.ElapseTime(timeSinceLast);
  MainVegPumpOutletTimer.ElapseTime(timeSinceLast);
  GreenWorkLightOutletTimer.ElapseTime(timeSinceLast);


  LoopsAround++;
  if(LoopsAround==42) LCD.RedrawScreen();
}


Quote
/*
 *  A library for dealing with digital inputs *  Created by MulletSoda, 2010
 *  With love!
 */

#ifndef DigitalInputter_h
#define DigitalInputter_h

#include "WProgram.h"

class DigitalInputter
{
public:
  //public variables:
  int PinNumber;
  int _PinNumber;
  unsigned long _currentTime;
  unsigned long _deBounceTimeDone;
  boolean _deBounce;
  void DeBouncer();

  //public functions:
  DigitalInputter(int _PinNumber);
  boolean CheckPin();
private:
  //private variables
  //private functions
};

#endif



Quote
#include "WProgram.h"
#include "DigitalInputter.h"


DigitalInputter::DigitalInputter(int PinNumber)
{
  //initialize
  _PinNumber = PinNumber;
  pinMode(_PinNumber, INPUT);
  //digitalWrite(_PinNumber, HIGH);//turn on pull up resistor
  _deBounceTimeDone = 0;
}

boolean DigitalInputter::CheckPin()
{
  _currentTime = millis(); //what is the current time?

  //debounce and check
  if (!_deBounce)  //if deBounce has not been activated
    if (digitalRead(_PinNumber)==1){//read pin, if it returns activated then
      {
        _deBounce = true;
        _deBounceTimeDone =500 + _currentTime; // <*******************************************  Will this bypass the rollover problem????
        //turn on debounce, set time over, return true
        return true;
      };
    };
  if (_deBounce)  //if deBounce has been activated
  {
    if (_deBounceTimeDone <= _currentTime) _deBounce = false; //if enough time has passed
  };
  return false;
}

void DigitalInputter::DeBouncer()
{
}

« Last Edit: February 12, 2010, 02:39:37 pm by Mulletsoda » Logged

0
Offline Offline
Newbie
*
Karma: 0
Posts: 14
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
/*
 *  A timer for controlling outlets
 *  Created by MulletSoda, 2010
 *  With love!
 */

#ifndef OutletTimer_h
#define OutletTimer_h

#include "WProgram.h"

class OutletTimer
{
public: //publicly accessable variables and functions

  int pinNumber; //0 - 255, pin number of outlet
  unsigned long MaintTime; //   Maintainence mode time, turns on/off for a set period of time then returns to normal functioning
  int CurrentMode; //the current mode of this outlet
  unsigned long TimeLeft; //milliseconds until mode change
  unsigned long OffDuration; //Time outlet remains off
  unsigned long OnDuration; //Time outlet remains on

  /*  Functions available to the public */

  OutletTimer(int _pinNumber, int _InitialMode, unsigned int _InitialTimeSec);
  void ElapseTime(int TimeSinceLast); //De-increment time remaining
  void ChangeMode(int NewMode); //force a mode change
private: //private, localized variables and functions
  int _pinNumber;
  int _InitialMode;
  int _InitialTimeSec;

};

#endif




Quote
#include "WProgram.h"
#include "OutletTimer.h"

OutletTimer::OutletTimer(int _pinNumber, int _InitialMode, unsigned int _InitialTimeSec)
{
  /*  This should do everything needed when the controller first starts up
   *  Initialize pin, set pin to whatever, set on time, set off time, set timeleft, set mode,
   *  
   */
  pinNumber=_pinNumber;
  pinMode(pinNumber, OUTPUT);
  digitalWrite(pinNumber, _InitialMode);
  TimeLeft = _InitialTimeSec * 1000.0;          //set TimeLeft
  CurrentMode = int(_InitialMode);
}

void OutletTimer::ElapseTime(int TimeSinceLast)
{
  //increment time down, this includes check for 0 time and TimeIsUp

  if (TimeLeft > 1000.0) TimeLeft-=TimeSinceLast;  //time slips away yet again
  if (TimeLeft <= 1000.0 && TimeLeft != 0.0) //if TimeIsUp but not disabled
  {
    switch (CurrentMode) //what's the current mode we're switching from?
    {
      case (0): //outlet off, normal op: turn mode to on, time to OnTime, turn pin high
      ChangeMode(1);
      break;
      case (1): //outlet on, normal op : mode off, time to OffTime, pin low
      ChangeMode(0);
      break; 
      case (2): //maint off time up, return to normal operation: turn mode to on, time to OnTime, turn pin high
      ChangeMode(1);
      break;
      case (3): //maint on time up, return normal op : turn mode off, time to OffTime, pin low
      ChangeMode(0);
      break; 
      case (4): //perm off, should NEVER get here
      break;
      case (5): //perm on, should NEVER get here
      break; 

    }
    //for some reason I needed a delay here before, if there are errors, try adding 2ms
  }
}

void OutletTimer::ChangeMode(int NewMode)
{
  //mode change, newMode can be used to pass button presses, too, by using higher NewMode values
  switch (NewMode)
  {
  case 0: //off
    digitalWrite(pinNumber, LOW);
    CurrentMode = 0;
    TimeLeft = OffDuration * 1000.0;
    break;
  case 1: //on
    digitalWrite(pinNumber, HIGH);
    CurrentMode = 1;
    TimeLeft = OnDuration * 1000.0;
    break;
  case 2://off maint
    digitalWrite(pinNumber, LOW);
    CurrentMode = 2;
    TimeLeft=MaintTime * 1000.0;
    break;
  case 3://on maint
    CurrentMode = 3;
    digitalWrite(pinNumber, HIGH);
    TimeLeft = MaintTime * 1000.0;
    break;
  case 4://perm off
    digitalWrite(pinNumber, LOW);
    CurrentMode = 4;
    TimeLeft = 0.0;
    break;
  case 5://perm on
    digitalWrite(pinNumber, HIGH);
    CurrentMode = 5;
    TimeLeft = 0.0;
    break;
  default: //other
    digitalWrite(pinNumber, LOW);
    /*
            *  This will be used to deal with button presses later.  Example :
                  * Button0 gets pressed, can be sent as NewMode==50, then a switch (CurrentMode)
                  * {case 0: //toggle mode to on; case 1: //toggle mode to off}
                  */
    break;

  }
}
Logged

0
Offline Offline
Newbie
*
Karma: 0
Posts: 14
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
/*
 *  A library for printing to a 8x20 LCD, obtained from PJRC
 *  Created by MulletSoda, 2010
 *  With love!
 */

#ifndef PrintPJRClcd_h
#define PrintPJRClcd_h

#include "WProgram.h"

class PrintPJRClcd
{

public:
  /* Variables */
  int blank;
  /* Functions */
  PrintPJRClcd(); //initialize, clear screen, set up all descriptive info
  void PrintData(int type,unsigned long datas);//type is set to location, datas is info to be printed
  void RedrawScreen();
private:
  /* Variables */
  int _row; //Cursor row position, 1 - 8
  int _column; //Cursor column position, 1 - 20
  /* Functions */
  void PositionCursor(int _row, int _cursor); //position cursor
};


#endif


Quote
#include "WProgram.h"
#include "PrintPJRClcd.h"

PrintPJRClcd::PrintPJRClcd()
{

};

void PrintPJRClcd::RedrawScreen()
{
  PositionCursor(1,1);
  Serial.print("Air T:   F      My Robot");
  PositionCursor(2,1);
  Serial.print("Rez1 T:   F       Friend");
  PositionCursor(4,1);
  Serial.print("Pump1:    :      seconds");
  PositionCursor(3,1);
  Serial.print("                        ");
  PositionCursor(5,1);
  Serial.print("                        ");
  PositionCursor(6,1);
  Serial.print("Worklight:               ");
  PositionCursor(7,1);
  Serial.print("            Min left     ");
  PositionCursor(8,1);
  Serial.print("                   ");

};

void PrintPJRClcd::PositionCursor(int _row, int _column)
{
  Serial.write(0x5C);
  Serial.write(0x42);
  Serial.write(byte(_column+31));
  Serial.write(byte(_row+31));
};

void PrintPJRClcd::PrintData(int type, unsigned long datas)
{

  switch (type) //where does this data go?
  {
  case 0: //Air temp
    PositionCursor(1,8);
    Serial.print(datas);
    break;
  case 1: //Rez temp
    PositionCursor(2,9);
    Serial.print(datas);
    break;
  case 2: //Pump1 on or off
    PositionCursor(4,8);
    if(datas==0) Serial.print("Off");
    else if(datas==1) Serial.print("On ");
  case 3: // Minutes left on Pump1
    PositionCursor(4,13);
    Serial.print(datas);
    break;
  case 4: //Day or Night
    PositionCursor(7,1);
    if(datas==0) Serial.print("Night");
    else if(datas==1) Serial.print(" Day ");
    break;
  case 5: // Min left till change
    PositionCursor(7,7);
    Serial.print(datas);
    break;
  case 6: //worklight status
    PositionCursor(6,12);
    if(datas==4) Serial.print("Off  ");
    if(datas==5) Serial.print("On   ");
    break;
  case 7: //debug
    PositionCursor(5,2);
    Serial.print(datas);
    break;
  };
};

Logged

0
Offline Offline
Newbie
*
Karma: 0
Posts: 2
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Are you growing in soil?

If you're interested I can post the homebrewed moisture sensor I built.
Logged

0
Offline Offline
Newbie
*
Karma: 0
Posts: 14
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Nope, hydroponic, but post it anyway.  Maybe somebody else can use it.

I'm interested in what people think of the code.  
Logged

0
Offline Offline
Newbie
*
Karma: 0
Posts: 3
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Looks pretty good!  

I am doing a similar project soon.   I may use your code for a little bit of reference... I am new to Arduino.
Logged

Pages: [1]   Go Up
Jump to: