Arduino programmers

Reef Aquarium & Tank Building Forum

Help Support Reef Aquarium & Tank Building Forum:

trido

Fish Tank Freak
Joined
Sep 28, 2006
Messages
3,524
Location
Lynnwood
Is there anyone on the forums here that can answer some basic questions for me?
 
I found a bunch of information through Google and programming it, no help here that I know of though. :brick:
 
Ya, I didnt think there were any here. Katchupoy (Cesar) is a local and knows a lot about it but I'm ready to go and don't want to wait for potential days for a PM reply to get started.

Thanks for the google suggestion.
 
Oh, BTW eww (Eric and Becca) just bought one premade and preprogrammed for the same price as I bought my components . I wish I would have known that before I made my order a month ago. Would have save a ton of headaches.
 
Well, I have two different controllers that I built from the RC site, the Hydra and the Typhon. I also have several self-built from Arduino Unos and Megas. I've also built completely custom programs for them. So ... I may be able to help, and I'm in Woodinville.

Brian
 
That's the most exciting thing I've heard all weekend Brian!


PM sent.
 
Ya, I didnt think there were any here. Katchupoy (Cesar) is a local and knows a lot about it but I'm ready to go and don't want to wait for potential days for a PM reply to get started.

Thanks for the google suggestion.

Trido, I apologize for the delay. In and out of state limited access to computer. Can we start from scratch? Is your build similar to mine? Can you post here your sketch? So others can learn too?. Just want to let you know, I'm no expert. Just copied it from somewhere and try to change some.

hope this helps
 
Trido, I apologize for the delay. In and out of state limited access to computer. Can we start from scratch? Is your build similar to mine? Can you post here your sketch? So others can learn too?. Just want to let you know, I'm no expert. Just copied it from somewhere and try to change some.

hope this helps
I figured you were/are busy.
So far I don't have a workable sketch for my application.
Brian (BDinWA) came to my house yesterday and gave a arduino 101 tutorial to help me understand some of the basics as opposed to just loading a sketch (program) onto my set up leaving my blind. The first thing I learned was that most of the sketches I've been looking at automatically have code errors with the latest and greatest arduino 1.0 software. I downloaded the older version (.0022) and suddenly your two channel sketch works for me with only minor alterations. The second thing he taught me was that I have to have the Libraries (support programs) in the right location for my sketch's to access them.
Knowing these two basics has helped so much. He has offered to write me a four channel sketch with no buttons (no buttons on my LCD screen) and send it over to me. When I get it, I will know most of what I need to do to make it perfect for my four channel LED fixture. Yesterday the code was like a foreign language to me.
 
Would this be like the Reef Angel controller only totally diy?

Kind of, I looked at the RA and it looks more comparable to and AC Jr or RK lite. I'm building an LED dimming controller only for around $50.
I already have an AC Jr and don't feel like its necessary at this point to spend the extra hundreds to upgrade to a newer controller with a dimmer module.
 
this is weird. Im not receiving email notifications from RF.

Anyways, Yes my sketch have 2 controllable signals, and I have no idea how to make it 4 channels.
if Brian can help us here, then so much the better so that other people can learn too.

The way I understand it.... based on my sketch.

When channel 1 is on going "on ramp" channel 2 cannot start. Channel 1 needs to finish its program first then 2 will follow.
It would be nice if channel 2 can start while channel 1 is on going. If this is possible then 4, 5, or 6 channel will not be a problem.
And this is what i want to see.

also, i remember that not all pins are PWM so we need to save these for this purpose only.

btw, there is an extra 2 channel in there that controls power pump to act as a wave timer... a very cool feature that I have been using since Jan 2011.
 
Anyways, Yes my sketch have 2 controllable signals, and I have no idea how to make it 4 channels.
if Brian can help us here, then so much the better so that other people can learn too.

The way I understand it.... based on my sketch.

When channel 1 is on going "on ramp" channel 2 cannot start. Channel 1 needs to finish its program first then 2 will follow.
It would be nice if channel 2 can start while channel 1 is on going. If this is possible then 4, 5, or 6 channel will not be a problem.
And this is what i want to see.

also, i remember that not all pins are PWM so we need to save these for this purpose only.
Version 1 for trido will be done this weekend. 4 channels, concurrent dimming, easy to add more channels.

Version 2 will add a complete menu/control interface through the Serial connection, since he has no buttons.

I'm building these with the new Arduino 1.0 tools
 
Version 1 for trido will be done this weekend. 4 channels, concurrent dimming, easy to add more channels.

Version 2 will add a complete menu/control interface through the Serial connection, since he has no buttons.

I'm building these with the new Arduino 1.0 tools

That is very generous for you to take the time to build these. I'm sure they will be useful for ALOT of reefers in the future.
 
That is very generous for you to take the time to build these. I'm sure they will be useful for ALOT of reefers in the future.

Thanks for the kind words. Tons of credit really goes to the folks at RC who designed the Typhon project.

I made one of the boards, then modified the code with what I felt was a better menu system.

Then I went crazy, and built a system that uses a mix of Arduinos (Mega, Uno, and some bare bones systems) and XBEE modules to be able to manage 4 controllers from a single location.
Still a work in progress.

To me, this is just plain fun !!!
 
would it be possible for you to share your sketch specially the concurrent one. Just wanted to see how you did it.
 
Four channel sketch with no button support

I'll post it Cesar. This program is so much better than the older two channel. One obvious reason is that it has four channels instead of two.
The older one ramped up in ten percent increments (which was very noticeable) and this does one percent. This one also works better for the fading in and out. Right now I have channel one set to come on at 8:00 with a half hour ramp up, channel two at 8:30 with a one hour ramp up and channel three at 9:00 with a one hour ramp up. Channel four comes on at one-o-clock with a half hour ramp up to 100% for only three hours at full power. A full duration of four hours.

The one thing that had me confused about this program as opposed to the old one is that the max duration is the total light cycle including the ramp up and down phase. The old sketch kept the all three lighting cycles separate. Ramp up, max percentage, then ramp down.

Anyway, here is the new sketch. FWIW the values are set for my lights to be on from 8AM until 9PM with a max value of 70%


PHP:
/*
// Typhon firmware
// v0.2 alpha 2010-23-11
// N. Enders, R. Ensminger
// v0.9 alpha 2010-25-02
// Revised by B. Duthie
// This sketch provides firmware for the Typhon LED controller.
// It provides a structure to fade MAX_CHANNELS independent channels of LED lighting
// on and off each day, to simulate sunrise and sunset.
//
// Requires LiquidCrystal, Wire, EEPROM, EEPROMVar libraries.
// EEPROMVar is available here: http://www.arduino.cc/playground/uploads/Profiles/EEPROMVar_01.zip
//
// 02/12/12 to support leds, without use of buttons
*/

// include the libraries:
#include <LiquidCrystal.h>
#include <Wire.h>
#include <EEPROM.h>
#include <EEPROMVar.h>


/**** Define Variables & Constants ****/
/**************************************/
// printing to Serial if debugging
#define DEBUG_ON                       // General debugging
//#define DEBUG_LED                      // LED Fade

// ONLY INCLUDE THIS IF YOU ARE CHANGING VALUES STORED IN EEPROM
//#define RESET_EEPROM

// set the RTC's I2C address
#define DS1307_I2C_ADDRESS 0x68

// create the LCD
//LiquidCrystal lcd(8,  7, 5, 4, 16, 2); // Typhon
//int bkl         = 6;        // backlight pin
LiquidCrystal lcd(12, 8, 7, 6,  5, 4, 2); // Duanes
int bkl         = 13;        // backlight pin

//create manual override variables
int overSelect = 0; // allow the override menu to remember its current setting
                    // 0 = Timer, 1 = All On, 2 = All Off, 3 = % Value
int overPercent = 0;

// setting of 60, with internal delays, 0-100 percent takes about 15 seconds (per channel)
int rampDelayUp = 120; 
int rampDelayDn = 60;

// Variables making use of EEPROM memory:
EEPROMVar<int> oneStartMins = 480;     // minute to start this channel.
EEPROMVar<int> onePhotoPeriod = 780;   // photoperiod in minutes for this channel.
EEPROMVar<int> oneMin = 0;             // min intensity for this channel, as a percentage
EEPROMVar<int> oneMax = 70;           // max intensity for this channel, as a percentage
EEPROMVar<int> oneFadeDuration = 30;   // duration of the fade on and off for sunrise and sunset
                                       
EEPROMVar<int> twoStartMins = 510;
EEPROMVar<int> twoPhotoPeriod = 720;
EEPROMVar<int> twoMin = 0;             // min intensity for this channel, as a percentage
EEPROMVar<int> twoMax = 700;
EEPROMVar<int> twoFadeDuration = 60;

EEPROMVar<int> threeStartMins = 540;
EEPROMVar<int> threePhotoPeriod = 660;
EEPROMVar<int> threeMin = 0;             // min intensity for this channel, as a percentage
EEPROMVar<int> threeMax = 170;
EEPROMVar<int> threeFadeDuration = 60;
                            
EEPROMVar<int> fourStartMins = 720;
EEPROMVar<int> fourPhotoPeriod = 240;  
EEPROMVar<int> fourMin = 0;             // min intensity for this channel, as a percentage
EEPROMVar<int> fourMax = 100;          
EEPROMVar<int> fourFadeDuration = 60;  

// descriptions need to be 4 characters due to display area
char* oneDesc = "BR  ";
char* twoDesc = "RB  ";
char* threeDesc = "CW  ";
char* fourDesc = "NW";

#define MAX_CHANNELS 4

typedef struct {
  char* Desc;         // Channel Description
  int Led;            // channel pin
  int StartMins;      // minute to start this channel.
  int PhotoPeriod;    // photoperiod in minutes for this channel.
  int ledMin;            // min intensity for this channel, as a percentage
  int ledMax;            // max intensity for this channel, as a percentage
  int ledVal;            // current intensity for this channel, as a percentage
  int FadeDuration;   // duration of the fade on and off for sunrise and sunset for this channel.
  int RampDelay;
} channelVals_t;

channelVals_t channel[MAX_CHANNELS];
// freeMemory returns the amount of available memory for variables
extern unsigned int __bss_end;
extern unsigned int __heap_start;
extern void *__brkval;

int freeMemory() {
  int free_memory;

  if((int)__brkval == 0)
     free_memory = ((int)&free_memory) - ((int)&__bss_end);
  else
    free_memory = ((int)&free_memory) - ((int)__brkval);

  return free_memory;
}

/****** RTC Functions ******/
/***************************/

// Convert decimal numbers to binary coded decimal
uint8_t decToBcd(byte val)
{
  return ( (val/10*16) + (val%10) );
}

// Convert binary coded decimal to decimal numbers
uint8_t bcdToDec(byte val)
{
  return ( (val/16*10) + (val%16) );
}

// Sets date and time, starts the clock
void setDate(byte second,        // 0-59
             byte minute,        // 0-59
             byte hour,          // 1-23
             byte dayOfWeek,     // 1-7
             byte dayOfMonth,    // 1-31
             byte month,         // 1-12
             byte year)          // 0-99
{
   Wire.beginTransmission(DS1307_I2C_ADDRESS);
   Wire.send((uint8_t)0);
   Wire.send(decToBcd(second));
   Wire.send(decToBcd(minute));
   Wire.send(decToBcd(hour));
   Wire.send(decToBcd(dayOfWeek));
   Wire.send(decToBcd(dayOfMonth));
   Wire.send(decToBcd(month));
   Wire.send(decToBcd(year));
   Wire.endTransmission();
}

// Gets the date and time
void getDate(byte *second,
             byte *minute,
             byte *hour,
             byte *dayOfWeek,
             byte *dayOfMonth,
             byte *month,
             byte *year)
{
  Wire.beginTransmission(DS1307_I2C_ADDRESS);
  Wire.send((uint8_t)0);
  Wire.endTransmission();
  Wire.requestFrom(DS1307_I2C_ADDRESS, 7);
  *second     = bcdToDec(Wire.receive() & 0x7f);
  *minute     = bcdToDec(Wire.receive());
  *hour       = bcdToDec(Wire.receive() & 0x3f);
  *dayOfWeek  = bcdToDec(Wire.receive());
  *dayOfMonth = bcdToDec(Wire.receive());
  *month      = bcdToDec(Wire.receive());
  *year       = bcdToDec(Wire.receive());
}

/** Menu Control Functions **/
void showMainMenu () {
  Serial.println("");
  Serial.println("LED Control Actions");
  Serial.println("L+   All Max");
  Serial.println("L-   All Min");
  Serial.println("Lnnn All nnn%");
  Serial.println("LT   Timer Mode");
  Serial.println("");
}

int parseMenuCommand () {
    int command;
    int value = 0;
    int pct = 0;
    command = Serial.read();
    switch (command) {
      case 'l':
      case 'L':
        if (Serial.available() > 0) {
          value = Serial.read();
          if (value == 't' || value == 'T') {
            overSelect = 0;
            Serial.println("Setting Timer Mode");
          }
          if (value == '+') {
            overSelect = 1;
            Serial.println("All Max");
          } 
          if (value == '-') {
            overSelect = 2;
            Serial.println("All Min");
          }
          if (value >= '0' && value <= '9') {
            pct = value - '0';
            while (Serial.available() > 0) {
              value = Serial.read();
              if (value >= '0' && value <= '9') 
                pct = pct * 10 + value - '0';
              else
                break;
            }
            if (overPercent <= 100) {
              overSelect = 3;
              overPercent = pct;
              Serial.print("Setting ");
              Serial.print(overPercent);
              Serial.println("%");
            }
          }
        }
        else {  // unrecognized command
        }
    }
    Serial.flush(); // remove all incoming data 
    return (0);
}

/****** LED Functions ******/
/***************************/
//function to set LED brightness according to time of day
//function has three equal phases - ramp up, hold, and ramp down

int   setLed(int mins,    // current time in minutes
             int c        // current channel
            )  {
   // channel values, just to make code read a little easier
    int ledPin = channel[c].Led;           // pin for this channel of LEDs
    int start  = channel[c].StartMins;     // start time for this channel of LEDs
    int period = channel[c].PhotoPeriod;   // photoperiod for this channel of LEDs
    int fade   = channel[c].FadeDuration;  // fade duration for this channel of LEDs
    int ledMin = channel[c].ledMin;           // min value for this channel
    int ledMax = channel[c].ledMax;           // max value for this channel
    int ledVal = channel[c].ledVal;           // current value for this channel
    
    int val = ledMin;   // start with the assumption that this channel is off
    int pinVal;
    
      // adjust for midnite rollover
     if (mins < start && start + period > 1439 && mins <= (start + period) % 1440)
        mins += 1440;

      //fade up or currently on or currently off
      if (mins >= start)  {
        if (mins - start <= fade) { // fading up
          val = map(mins - start, 0, fade, ledMin, ledMax);
          }
        else if (mins < start + (period - fade)) { // on
          val = ledMax;
          }
        else if (mins > start + period) { // off - nothing to do, but print debug info
          }
      }
      //fade down
      if (mins >= start + period - fade && mins <= start + period)  {
        val = map(mins - (start + period - fade), 0, fade, ledMax, ledMin);
        }
     // if All On = use ledMax, All Off = use ledMin, otherwise use set percent
     switch(overSelect){
        case 1: // All On
          val = ledMax;
          break;
        case 2: // All Off
          val = ledMin;
          break;
        case 3: // specific percent
          val = overPercent;
          break;
     }

// Ramp Up/Down slowly -- do nothing if no change
// This will also impact setting of the override % value, and all on/off options
  if (channel[c].RampDelay > 0)  // avoid using delay() in loop()
     --channel[c].RampDelay;
  if (channel[c].RampDelay == 0 && val < ledVal) {
    --ledVal;
    channel[c].RampDelay = rampDelayDn;
  }
  if (channel[c].RampDelay == 0 && val > ledVal) {
    ++ledVal;
    channel[c].RampDelay = rampDelayUp;
  }
  if (ledVal != channel[c].ledVal) {
    // ledVal is the percentage (0-100) to set for this channel
    // pinVal is the value (0-255) to set for the Arduino PWM pin
    // comment out the line you don't want to use, or create your own
//    pinVal = map(ledVal, 0, 100, 0, 255);          // normal linear value for PWM
    pinVal = min(255, (pow(2, ledVal/10.0) + 2.99) / 4.0);  // value for Meanwell "D"
    analogWrite(ledPin, pinVal); 
  }
    
#ifdef DEBUG_LED
if (ledVal != channel[c].ledVal) {
      if (start + period > 1440) 
        Serial.println("Midnite rollover ");
      Serial.print("mins =");
      Serial.print(mins);
      Serial.print(", ");
      Serial.print(channel[c].Desc);
      Serial.print(", start = ");
      Serial.print(start);
      Serial.print(", period = ");
      Serial.print(period);
      Serial.print(", fade = ");
      Serial.print(fade);
      Serial.print(", min = ");
      Serial.print(ledMin);
      Serial.print(", max = ");
      Serial.print(ledMax);
     if(overSelect){
        Serial.print(", overSelect: ");
        Serial.print(val);
        }
  Serial.print(", ledVal = ");
  Serial.print(ledVal);
  Serial.print(", PWM = ");
  Serial.print(map(ledVal, 0, 100, 0, 255), DEC);
  Serial.print(", pin = ");
  Serial.println(pinVal, DEC);
}
#endif
    
  return ledVal;
}

/**** Display Functions ****/

void printMDY (byte mm, byte dd, byte yy)
{   if(mm<10){
      lcd.print(" ");
    }
    lcd.print(mm, DEC);
    lcd.print("/");
    if(dd<10){
      lcd.print(" ");
    }
    lcd.print(dd, DEC);
    lcd.print("/");
    if(yy<10){
      lcd.print("0");
    }
    lcd.print(2000 + yy, DEC);

}
void printDay (byte dday)
    {
      char* daynames[8] = {"???","Sun","Mon","Tue","Wed","Thu","Fri","Sat"};
      lcd.print(daynames[dday%8]);
    }

// format a number of minutes into a readable time (24 hr format)
void showMins(int mins,       //time in minutes to print
               boolean ampm = false   //print am/pm? - future implementation (or not)
              )  {
  int hr = (mins%1440)/60;
  int mn = mins%60;
    if(hr<10){
      lcd.print(" ");
    }
    lcd.print(hr);
    lcd.print(":");
    if(mn<10){
      lcd.print("0");
    }
    lcd.print(mn); 
}

// format hours, mins, secs into a readable time (24 hr format)
void showHMS (byte hr,
               byte mn,
               byte sec      //time to print
              )  
{
  
    if(hr<10){
      lcd.print(" ");
    }
    lcd.print(hr, DEC);
    lcd.print(":");
    if(mn<10){
      lcd.print("0");
    }
    lcd.print(mn, DEC);
    lcd.print(":");
    if(sec<10){
      lcd.print("0");
    }
    lcd.print(sec, DEC);
}

/**** Setup ****/
/***************/

void setup() {
#ifdef RESET_EEPROM
 oneStartMins = 480;     // minute to start this channel.
 onePhotoPeriod = 780;   // photoperiod in minutes for this channel.
 oneMin = 0;             // min intensity for this channel, as a percentage
 oneMax = 70;           // max intensity for this channel, as a percentage
 oneFadeDuration = 30;   // duration of the fade on and off for sunrise and sunset for
                                       //    this channel.
 twoStartMins = 510;
 twoPhotoPeriod = 720;
 twoMin = 0;             // min intensity for this channel, as a percentage
 twoMax = 70;
 twoFadeDuration = 60;

 threeStartMins = 540;
 threePhotoPeriod = 660;
 threeMin = 0;             // min intensity for this channel, as a percentage
 threeMax = 70;
 threeFadeDuration = 60;
                            
 fourStartMins = 720;
 fourPhotoPeriod = 600;  
 fourMin = 0;             // min intensity for this channel, as a percentage
 fourMax = 100;          
 fourFadeDuration = 30;  
 #endif
 
  // Initialize channel variables. Set LED channel pin and retrieve values from EEPROM
  channel[0].Desc = oneDesc;
  channel[0].Led = 11;
  channel[0].StartMins = oneStartMins;
  channel[0].PhotoPeriod = 780;   // onePhotoPeriod;
  channel[0].ledMin = oneMin;
  channel[0].ledMax = oneMax;
  channel[0].ledVal = 0;
  channel[0].FadeDuration = oneFadeDuration;

  channel[1].Desc = twoDesc;
  channel[1].Led = 10;
  channel[1].StartMins = twoStartMins;
  channel[1].PhotoPeriod = 720;   //twoPhotoPeriod;
  channel[1].ledMin = twoMin;
  channel[1].ledMax = twoMax;
  channel[1].ledVal = 0;
  channel[1].FadeDuration = twoFadeDuration;

  channel[2].Desc = threeDesc;
  channel[2].Led = 9;
  channel[2].StartMins = threeStartMins;
  channel[2].PhotoPeriod = 660;  //threePhotoPeriod;
  channel[2].ledMin = threeMin;
  channel[2].ledMax = threeMax;
  channel[2].ledVal = 0;
  channel[2].FadeDuration = threeFadeDuration;

  channel[3].Desc = fourDesc;
  channel[3].Led = 3;
  channel[3].StartMins = fourStartMins;
  channel[3].PhotoPeriod = fourPhotoPeriod;
  channel[3].ledMin = fourMin;
  channel[3].ledMax = fourMax;
  channel[3].ledVal = 0;
  channel[3].FadeDuration = fourFadeDuration;

  Serial.begin(57600);
  Serial.println("Duanes-Reef");

for (int i = 0; i < MAX_CHANNELS; ++i) {
  Serial.print(channel[i].Desc);
  Serial.print(", Start: ");  
  Serial.print(channel[i].StartMins);
  Serial.print(", Period: ");  
  Serial.print(channel[i].PhotoPeriod);
  Serial.print(", Min: ");  
  Serial.print(channel[i].ledMin, DEC);
  Serial.print(", Max: ");  
  Serial.print(channel[i].ledMax, DEC);
  Serial.print(", Fade: ");  
  Serial.print(channel[i].FadeDuration);
  Serial.println();
}

  Wire.begin();
  pinMode(bkl, OUTPUT);    // backlight control for the lcd display
  lcd.begin(16, 2);
  digitalWrite(bkl, HIGH);
  lcd.print("Duanes-Reef");

  byte second, minute, hour, dayOfWeek, dayOfMonth, month, year;
  getDate(&second, &minute, &hour, &dayOfWeek, &dayOfMonth, &month, &year);
  lcd.setCursor(0,1);
  printMDY(month, dayOfMonth, year);
  lcd.print(" - ");
  printDay(dayOfWeek);
  delay(5000);

  lcd.clear();
  
  updateEEPromVars();
  
  Serial.print("Free Memory = ");
  Serial.println(freeMemory());
  
  showMainMenu();
}

/***** Loop *****/
/****************/

void loop() {
  byte second, minute, hour, dayOfWeek, dayOfMonth, month, year;
  int minCounter;
  
  getDate(&second, &minute, &hour, &dayOfWeek, &dayOfMonth, &month, &year);
  minCounter = hour * 60 + minute;
  
  if (Serial.available() > 0) {
    parseMenuCommand();
    showMainMenu();
  }
  
  for (int i = 0; i < MAX_CHANNELS; i++) { //check & adjust fade durations
    if(channel[i].FadeDuration > channel[i].PhotoPeriod/2 && channel[i].PhotoPeriod >0) {
       channel[i].FadeDuration = channel[i].PhotoPeriod/2;
       }
    if(channel[i].FadeDuration < 1)
       channel[i].FadeDuration = 1;
    }
    
// set led outputs
      for (int i = 0; i < MAX_CHANNELS; i++)
        channel[i].ledVal = setLed(minCounter, i);
 
  
   doMainMenu(hour, minute, second);

}
    
void doMainMenu(byte hour,
                byte minute,
                byte second) {
  lcd.setCursor(0,0);
  showHMS(hour, minute, second);

  
// display the current intensity for each led channel
  showChannelValues();
  
//debugging function to use the select button to advance the timer by 1 minute
#ifdef DEBUG_ON
  if (0) {
    byte dayOfWeek, dayOfMonth, month, year;

    getDate(&second, &minute, &hour, &dayOfWeek, &dayOfMonth, &month, &year);
    ++minute;
    if (minute > 59) {
      minute = 0;
      ++hour;
      }
    if (hour > 23)
      hour = 0;
    setDate(second, minute+1, hour, dayOfWeek, dayOfMonth, month, year);
    delay(100);
    }
#endif DEBUG_ON
  }

void doOverride() {
  //Manual Override Menu
  lcd.setCursor(0,0);
  switch (overSelect){
    case 0:
      lcd.print("Control by Timer");
      break;
    case 1:
      lcd.print("LED: All Max ");
      break;
    case 2:
      lcd.print("LED: All Min ");
      break;
    case 3:
      lcd.print("All Set: ");
      if (overPercent < 10)
        lcd.print("  ");
      else if (overPercent < 100)
        lcd.print(" ");
      lcd.print(overPercent,DEC);
      lcd.print("%   ");
       break;
    default:
      overSelect = 0;
    }
//  showChannelValues(); // disabled so that changes only start after menu is selected again
} 

void showChannelValues() { // display the current intensity for each led channel
      lcd.setCursor(9,0);
      switch (overSelect) {
        case 0:
          lcd.print("Timer  ");
          break;
        case 1:
          lcd.print("All Max");
          break;
        case 2:
          lcd.print("All Min");
          break;
        case 3:
          lcd.print("All ");
          if (overPercent < 10)
            lcd.print(" ");
          lcd.print(overPercent);
          lcd.print("%");
          break;
        }
      
    lcd.setCursor(0,1);
    for (int i = 0; i < MAX_CHANNELS; i++) {
      lcd.print(" ");
      if (channel[i].ledVal < 10)
        lcd.print("  ");
      else if (channel[i].ledVal < 100)
        lcd.print(" ");
      lcd.print(channel[i].ledVal);
      }
}


// Actually needs to become a feature of the EEPromVar library -- later
// should just be a function of the assignment operators

void updateEEPromVars() {
  // Update EEProms with any values that may have changed
  // Only updates values that have changed
#ifdef DEBUG_ON
  Serial.println("Updating EEPromVars");
#endif
  if (channel[0].StartMins != oneStartMins) {
    oneStartMins = channel[0].StartMins;
  }
  if (channel[0].PhotoPeriod != onePhotoPeriod) {
    onePhotoPeriod = channel[0].PhotoPeriod;
  }
  if (channel[0].ledMin != oneMin) {
    oneMin = channel[0].ledMin;
  }
  if (channel[0].ledMax != oneMax) {
    oneMax = channel[0].ledMax;
  }
  if (channel[0].FadeDuration != oneFadeDuration) {
    oneFadeDuration = channel[0].FadeDuration;
  }

  if (channel[1].StartMins != twoStartMins) {
    twoStartMins = channel[1].StartMins;
  }
  if (channel[1].PhotoPeriod != twoPhotoPeriod) {
    twoPhotoPeriod = channel[1].PhotoPeriod;
  }
  if (channel[1].ledMin != twoMin) {
    twoMax = channel[1].ledMax;
  }
  if (channel[1].ledMax != twoMax) {
    twoMax = channel[1].ledMax;
  }
  if (channel[1].FadeDuration != twoFadeDuration) {
    twoFadeDuration = channel[1].FadeDuration;
  }
  
  if (channel[2].StartMins != threeStartMins) {
    threeStartMins = channel[2].StartMins;
  }
  if (channel[2].PhotoPeriod != threePhotoPeriod) {
    threePhotoPeriod = channel[2].PhotoPeriod;
  }
  if (channel[2].ledMin != threeMin) {
    threeMin = channel[2].ledMin;
  }
  if (channel[2].ledMax != threeMax) {
    threeMax = channel[2].ledMax;
  }
  if (channel[2].FadeDuration != threeFadeDuration) {
    threeFadeDuration = channel[2].FadeDuration;
  }
  
  if (channel[3].StartMins != fourStartMins) {
    fourStartMins = channel[3].StartMins;
  }
  if (channel[3].PhotoPeriod != fourPhotoPeriod) {
    fourPhotoPeriod = channel[3].PhotoPeriod;
  }
  if (channel[3].ledMin != fourMin) {
    fourMin = channel[3].ledMin;
  }
  if (channel[3].ledMax != fourMax) {
    fourMax = channel[3].ledMax;
  }
  if (channel[3].FadeDuration != fourFadeDuration) {
    fourFadeDuration = channel[3].FadeDuration;
  }
}
 
For anyone with no buttons on their LCD screen and wanting to show off their light fixture. Brian has added in this code so anyone can brighten or dim their lights with rewriting the code. I don't understand how to use it yet but I'm sure it will come in handy when I have company over. It is accessed through the serial monitor. Also, the way this version is written, it wont work on the new arduino 1.0 The older version of arduino .0022 is required for it to work.

PHP:
/** Menu Control Functions **/ 
void showMainMenu () { 
  Serial.println(""); 
  Serial.println("LED Control Actions"); 
  Serial.println("L+   All Max"); 
  Serial.println("L-   All Min"); 
  Serial.println("Lnnn All nnn%"); 
  Serial.println("LT   Timer Mode"); 
  Serial.println(""); 
} 

int parseMenuCommand () { 
    int command; 
    int value = 0; 
    int pct = 0; 
    command = Serial.read(); 
    switch (command) { 
      case 'l': 
      case 'L': 
        if (Serial.available() > 0) { 
          value = Serial.read(); 
          if (value == 't' || value == 'T') { 
            overSelect = 0; 
            Serial.println("Setting Timer Mode"); 
          } 
          if (value == '+') { 
            overSelect = 1; 
            Serial.println("All Max"); 
          }  
          if (value == '-') { 
            overSelect = 2; 
            Serial.println("All Min"); 
          } 
          if (value >= '0' && value <= '9') { 
            pct = value - '0'; 
            while (Serial.available() > 0) { 
              value = Serial.read(); 
              if (value >= '0' && value <= '9')  
                pct = pct * 10 + value - '0'; 
              else 
                break; 
            } 
            if (overPercent <= 100) { 
              overSelect = 3; 
              overPercent = pct; 
              Serial.print("Setting "); 
              Serial.print(overPercent); 
              Serial.println("%"); 
            } 
          } 
        } 
        else {  // unrecognized command 
        } 
    } 
    Serial.flush(); // remove all incoming data  
    return (0); 
}
 
Last edited:
Thank you Trido. I will try to relearn this code.

The only reason I created it in 10% increment is ... 1) My previous lighting was just one step. On and Off... I guess 10 steps is a big plus compared to my old one step process... 2) Im using MW-48D which is at first did not think that Im going to do arduino. So the 48D is not linear in terms of PWM unlike its sister "48P". But with 48D, I can start really low (dim) unlike 48P that starts around 20% brightness.

The way you describe your ramp up and down is not really different than mine???? I though while channel 1 is ongoing, channel 2 is simultaneously going too. But instead, you are saying, when channel 1 is done, then channel 2 will follow, then 3 then 4.
 
I can ramp them up simultaneously or separately. Also at pretty much any speed too. I found that with the old sketch, if I had a 1 hour ramp up with only 70% the sketch made it ramp up at a designated speed designed for 100%. Since I was only using 70% the loop would finish, the computer would get confused and then the ramp up would start over again at 10% until the one hour was finished. Maybe I didnt understand how to program it, the new sketch takes care of all this for me. I set the max percentage and the program automatically adjusts the ramp up speed for me depending on how long I want to stretch it out.

Don't get me wrong, I was very happy to get your old sketch to work for me. I also followed your build almost identically. Thank you for taking the time to put all of this information together (and post it on the web right here) for so many reefers that otherwise would be clueless.
 
Last edited:
I am checking the sketch right now, and that is a lot to digest... lol... it will take me weeks to dissect that...
About the ramp up at 70%, I never actually used that feature where you set it at a certain percentage. I have very limited knowledge with programming, thats why it ended up like that, unfinished. I got it from a fellow reefer and he is using pwm driver. And its not compatible with analog drivers. I ended up just turning my knob/potentiometer to a certain percentage and kept the program at 100%.

On a side note, are you understanding this sketch? it looks really cool but im still digesting it right now. its totally different than what I have.

Also, do you have a build page of your LED? show us some pics here so we all can see. Did you go with the PWM drivers? Did you notice that the light starts up bright already? and does not dim way down?

sorry for so many questions. just excited to see some people try the DIY build approach.
 

Latest posts

Back
Top