Led pwm issue with this code

justindost1

New member
i have used a basic pwm dimming code to make sure the driver is working and hooked up correctly but when i use this code the leds wont come on till the pwm value is at full. and if i try to change the max value from anything other than 100 it wont come on at all.

Code:
 #define MAX_CHANNEL_PAIRS 4
_channelPair channels[MAX_CHANNEL_PAIRS] = {
  { 11, 7, 0 },
  { 10, 6, 0 },
  { 9, 5, 0 },
  { 8, 4, 0}
};
////////////////////////////////////////////////////////////

#define WHITE_MAX 100          // Maximum white level
#define BLUE_MAX 100          // Maximum blue level
#define DAWN_DUSK_OFFSET 45U   // How sooner should blue lights come up before white, and how later should they go off after white


this is the full code

Code:
  /**********************************************************************************
    Aquarium LED controller with weather simulation
    Copyright (C) 2010, 2011, Fabio Luis De Paoli

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License version 3 as published
    by the Free Software Foundation.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License v3
    along with this program.  If not, see 
    <http://www.gnu.org/licenses/gpl-3.0-standalone.html>.
 
// Definition of a light waypoint
struct _waypoint {
  unsigned int time;   // in 2 seconds, 1h=900 2secs, 24h = 43200 2secs
  byte         level;
};

// Definition of a segment
struct _segment {
  unsigned int strTime;  // Start
  byte         strLevel;  // Start
  unsigned int finTime;  // Finish
  byte         finLevel;  // Finish
};


/////////////////////////////////////////////////////////////
// Section where we define the white-blue channel pairs
struct _channelPair {
  byte wPin;
  byte bPin;
  unsigned int channelDelay;
};

#define MAX_CHANNEL_PAIRS 4
_channelPair channels[MAX_CHANNEL_PAIRS] = {
  { 11, 7, 0 },
  { 10, 6, 0 },
  { 9, 5, 0 },
  { 8, 4, 0}
};
////////////////////////////////////////////////////////////

#define WHITE_MAX 100          // Maximum white level
#define BLUE_MAX 100          // Maximum blue level
#define DAWN_DUSK_OFFSET 45U   // How sooner should blue lights come up before white, and how later should they go off after white


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

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

//////////////////////////////////////////////////////////////////

/******************************************************************************************
 * DO LIGHTNING
 *
 * Do lightning, flashing all the LEDs at full intensity in a lightning like pattern.
 *
 * Inspired by lightning code posted by Numlock10@ReefCentral
 * http://www.reefcentral.com/forums/showpost.php?p=17542851&postcount=206
 **/
void doLightning(byte aWhiteLevel, byte aBlueLevel) {
    byte numberOfFlashes = (byte) random(5) +1;
    byte maxLightLevel;

    if (aBlueLevel < 20) {
      maxLightLevel = (aBlueLevel * 2) + 3;
    } else {
      maxLightLevel = WHITE_MAX;
    }

    byte var = 0;
    while (var < numberOfFlashes) {
      // LEDs on for 50ms
      for (byte i=0; i<MAX_CHANNEL_PAIRS; i++) {
        setLedPWMOutputs(i, maxLightLevel, maxLightLevel);
      }
      delay(50);
      
      // LED off for 50ms
      for (byte i=0; i<MAX_CHANNEL_PAIRS; i++) {
        setLedPWMOutputs(i, 0, 0);
      }
      delay(50);
      
      // LED on for 50ms to 250ms
      for (byte i=0; i<MAX_CHANNEL_PAIRS; i++) {
        setLedPWMOutputs(i, maxLightLevel, maxLightLevel);
      }
      delay(random(50,250));           
      
      // set the LED back to normal levels for 50ms to 1sec
      for (byte i=0; i<MAX_CHANNEL_PAIRS; i++) {
        setLedPWMOutputs(i, aWhiteLevel, aBlueLevel);
      }
      delay(random(50,1000));            
      var++;
    }

    Serial.print("##LIGHTNING x");
    Serial.print(numberOfFlashes, DEC);
    Serial.print(" @");
    Serial.println(maxLightLevel,DEC);
}

///////////////////////////////////////////////////





/**************************************************************************
 * PLAN BASIC CURVE
 *
 * Plan the basic light curve for the day, before clouds and other
 * special effects are considered, just sunrise/sunset and the rest.
 **/
void planBasicCurve(byte aMonth, byte aDay) {

  unsigned int wSunriseStart, bSunriseStart;
  unsigned int wSunsetFinish, bSunsetFinish;
  unsigned int wFadeDuration, bFadeDuration;
  unsigned int wFadeStep, bFadeStep;
  
  //------------- BASIC CURVE ------------- 
  wFadeDuration = (unsigned int) map((unsigned int) aDay, 1U, (unsigned int) daysInMonth[aMonth-1], (unsigned int) minFadeDuration[aMonth-1], (unsigned int) maxFadeDuration[aMonth-1]);
  bFadeDuration = wFadeDuration + DAWN_DUSK_OFFSET/2U;
  wFadeDuration = wFadeDuration - DAWN_DUSK_OFFSET/2U;
  
  wSunriseStart = (unsigned int) map((unsigned int) aDay, 1U, (unsigned int) daysInMonth[aMonth-1], (unsigned int) minSunriseStart[aMonth-1], (unsigned int) maxSunriseStart[aMonth-1]);
  bSunriseStart = wSunriseStart - DAWN_DUSK_OFFSET/2U;
  wSunriseStart = wSunriseStart + DAWN_DUSK_OFFSET/2U;
  
  wSunsetFinish = (unsigned int) map((unsigned int) aDay, 1U, (unsigned int) daysInMonth[aMonth-1], (unsigned int) minSunsetFinish[aMonth-1], (unsigned int) maxSunsetFinish[aMonth-1]);
  bSunsetFinish = wSunsetFinish + DAWN_DUSK_OFFSET/2U;
  wSunsetFinish = wSunsetFinish - DAWN_DUSK_OFFSET/2U;
  
  // 30 transforms "1 min" in "2 secs":
  wFadeDuration = wFadeDuration * 30U;
  bFadeDuration = bFadeDuration * 30U;
  wSunriseStart = wSunriseStart * 30U;
  wSunsetFinish = wSunsetFinish * 30U;
  bSunriseStart = bSunriseStart * 30U;
  bSunsetFinish = bSunsetFinish * 30U;
  wFadeStep = wFadeDuration / 5U;
  bFadeStep = bFadeDuration / 5U;


  dcwWhiteCurve[0].time = 0;
  dcwWhiteCurve[0].level = 0;

  dcwWhiteCurve[1].time = wSunriseStart;  
  dcwWhiteCurve[1].level = 0;

  dcwWhiteCurve[2].time = wSunriseStart + wFadeStep;
  dcwWhiteCurve[2].level = (WHITE_MAX * 10) / 100;

  dcwWhiteCurve[3].time = wSunriseStart + 2U*wFadeStep;
  dcwWhiteCurve[3].level = (WHITE_MAX * 30) / 100;

  dcwWhiteCurve[4].time = wSunriseStart + 3U*wFadeStep;
  dcwWhiteCurve[4].level = (WHITE_MAX * 70) / 100;

  dcwWhiteCurve[5].time = wSunriseStart + 4U*wFadeStep;
  dcwWhiteCurve[5].level = (WHITE_MAX * 90) / 100;

  dcwWhiteCurve[6].time = wSunriseStart + 5U*wFadeStep;
  dcwWhiteCurve[6].level = WHITE_MAX;

  dcwWhiteCurve[7].time = wSunsetFinish - 5U*wFadeStep;
  dcwWhiteCurve[7].level = WHITE_MAX;

  dcwWhiteCurve[8].time = wSunsetFinish - 4U*wFadeStep;
  dcwWhiteCurve[8].level = (WHITE_MAX * 90) / 100;

  dcwWhiteCurve[9].time = wSunsetFinish - 3U*wFadeStep;
  dcwWhiteCurve[9].level = (WHITE_MAX * 70) / 100;

  dcwWhiteCurve[10].time = wSunsetFinish - 2U*wFadeStep;
  dcwWhiteCurve[10].level = (WHITE_MAX * 30) / 100;

  dcwWhiteCurve[11].time = wSunsetFinish - wFadeStep;
  dcwWhiteCurve[11].level = (WHITE_MAX * 10) / 100;

  dcwWhiteCurve[12].time = wSunsetFinish;
  dcwWhiteCurve[12].level = 0;

  dcwWhiteCurve[13].time = 1440U * 30U;
  dcwWhiteCurve[13].level = 0;


  dcwBlueCurve[0].time = 0;
  dcwBlueCurve[0].level = 0;

  dcwBlueCurve[1].time = bSunriseStart;  
  dcwBlueCurve[1].level = 0;

  dcwBlueCurve[2].time = bSunriseStart + bFadeStep;
  dcwBlueCurve[2].level = (BLUE_MAX * 10) / 100;

  dcwBlueCurve[3].time = bSunriseStart + 2U*bFadeStep;
  dcwBlueCurve[3].level = (BLUE_MAX * 30) / 100;

  dcwBlueCurve[4].time = bSunriseStart + 3U*bFadeStep;
  dcwBlueCurve[4].level = (BLUE_MAX * 70) / 100;

  dcwBlueCurve[5].time = bSunriseStart + 4U*bFadeStep;
  dcwBlueCurve[5].level = (BLUE_MAX * 90) / 100;

  dcwBlueCurve[6].time = bSunriseStart + 5U*bFadeStep;
  dcwBlueCurve[6].level = BLUE_MAX;

  dcwBlueCurve[7].time = bSunsetFinish - 5U*bFadeStep;
  dcwBlueCurve[7].level = BLUE_MAX;

  dcwBlueCurve[8].time = bSunsetFinish - 4U*bFadeStep;
  dcwBlueCurve[8].level = (BLUE_MAX * 90) / 100;

  dcwBlueCurve[9].time = bSunsetFinish - 3U*bFadeStep;
  dcwBlueCurve[9].level = (BLUE_MAX * 70) / 100;

  dcwBlueCurve[10].time = bSunsetFinish - 2U*bFadeStep;
  dcwBlueCurve[10].level = (BLUE_MAX * 30) / 100;

  dcwBlueCurve[11].time = bSunsetFinish - bFadeStep;
  dcwBlueCurve[11].level = (BLUE_MAX * 10) / 100;

  dcwBlueCurve[12].time = bSunsetFinish;
  dcwBlueCurve[12].level = 0;

  dcwBlueCurve[13].time = 1440U * 30U;
  dcwBlueCurve[13].level = 0;

}

/**************************************************************************
 * PLAN NEW DAY
 *
 * This is the function that is called when we enter a new day, it calls
 * planBasicCurve for the basic light with no clouds, then determines
 * the oktas number for the day, which will determine how many clouds
 * and at what spacing we will have 
 **/
void planNewDay(byte aMonth, byte aDay) {

  planBasicCurve(aMonth, aDay);

  if (!DEBUG_MODE) {
    //------------- OKTA DETERMINATION  ------------- 
    byte randNumber;
    randNumber = (byte) random(0,100);
  
    if (randNumber > cloudyDays[aMonth]) {
      // this is a mixed day, Okta 2 to 3
      okta = (byte) random(2,4);
    } else if (randNumber > clearDays[aMonth] ) {
      // this is a cloudy day, Okta 4 to 8
      okta = (byte) random(4,9);
    } else {
      // this is a clear day, Okta 0 to 1
      okta = (byte) random(0,2);
    }
  }

  Serial.print("Okta=");
  Serial.print(okta, DEC);

  setCloudSpacingAndTypes();

  Serial.print(", type1=");
  Serial.print(cloudType1, DEC);
  Serial.print(", type2=");
  Serial.print(cloudType2, DEC);
  Serial.print(", spacing=");
  Serial.println(cloudSpacing, DEC);

  currCloudCoverFinish = 0;
}



   


   



void serialCommands() 
{
  int command = 0;       // This is the command char, in ascii form, sent from the serial port     
  int i;
  byte test; 
  
  if (Serial.available()) {      // Look for char in serial que and process if found
    command = Serial.read();

    if (command == 73) {      // "I" = Info
      Serial.print("Okta: ");
      Serial.println(okta,DEC);
      dumpCurve();
    }
    
    if (command == 76) {      // "L" = doLigthning based off zero
      doLightning(prevWLevel, prevBLevel);
    }

    if (command == 79) {      // "O" = Set okta and recalculate day
      if (Serial.available()) {
        command = Serial.read();
        okta = command - 48;
        setCloudSpacingAndTypes();
        currCloudCoverFinish = 0;
        Serial.print("Okta reset to: ");
        Serial.println(okta,DEC);
      }
    }
    
    if (command == 82) {      //If command = "R" Read date and time
      getDateDs1307();
      printDateTime();
      Serial.println(" ");
    }
    if (command == 84) {      //If command = "T" Set Date
      setDateDs1307();
      getDateDs1307();
      printDateTime();
      Serial.println(" ");
    }
    else if (command == 81) {      //If command = "Q" RTC1307 Memory Functions
      delay(100);     
      if (Serial.available()) {
        command = Serial.read(); 
        if (command == 49) {      //If command = "1" RTC1307 Initialize Memory - All Data will be set to 255 (0xff).  Therefore 255 or 0 will be an invalid value.  
          Wire.beginTransmission(DS1307_I2C_ADDRESS); // 255 will be the init value and 0 will be considered an error that occurs when the RTC is in Battery mode.
          Wire.send(0x08); // Set the register pointer to be just past the date/time registers.
          for (i = 1; i <= 27; i++) {
            Wire.send(0xff);
            delay(100);
          }   
          Wire.endTransmission();
          getDateDs1307();
          printDateTime();
          Serial.println(": RTC1307 Initialized Memory");
        }
        else if (command == 50) {      //If command = "2" RTC1307 Memory Dump
          getDateDs1307();
          printDateTime();
          Serial.println(": RTC 1307 Dump Begin");
          Wire.beginTransmission(DS1307_I2C_ADDRESS);
          Wire.send(0x00);
          Wire.endTransmission();
          Wire.requestFrom(DS1307_I2C_ADDRESS, 64);
          for (i = 1; i <= 64; i++) {
             test = Wire.receive();
             Serial.print(i);
             Serial.print(":");
             Serial.println(test, DEC);
          }
          Serial.println(" RTC1307 Dump end");
        } 
      }  
    }
    Serial.print("Command: ");
    Serial.println(command);     // Echo command CHAR in ascii that was sent
  }
      
  command = 0;                 // reset command 
  delay(100);
}

/****************************************************************
 * SET LED PWM OUTPUTS
 *
 * Set all the LED channels we have connected to the Arduino
 * with the right PWM light value
 * 
 * For this function the bluePwmLevel and whitePwmLevel
 * are expressed in percentage 0-100
 *****************************************************************/
void setLedPWMOutputs(byte channel, byte whitePwmLevel, byte bluePwmLevel) {
  
  byte level = 0;
  
  level = (byte) ( ((unsigned int)whitePwmLevel *255U) /100U );
  analogWrite(channels[channel].wPin, level);

  level = (byte) ( ((unsigned int)bluePwmLevel *255U) /100U );
  analogWrite(channels[channel].bPin, level);
  
} 

/************************************************************
// 1) Sets the date and time on the ds1307
// 2) Starts the clock
// 3) Sets hour mode to 24 hour clock
// Assumes you're passing in valid numbers, Probably need to put in checks for valid numbers.
// Format: ssmmhhWDDMMYY  (W=Day of the week, Sunday = 0)
*/ 
void setDateDs1307()
{

   second = (byte) ((Serial.read() - 48) * 10 + (Serial.read() - 48)); // Use of (byte) type casting and ascii math to achieve result.  
   minute = (byte) ((Serial.read() - 48) *10 +  (Serial.read() - 48));
   hour  = (byte) ((Serial.read() - 48) *10 +  (Serial.read() - 48));
   dayOfWeek = (byte) (Serial.read() - 48);
   dayOfMonth = (byte) ((Serial.read() - 48) *10 +  (Serial.read() - 48));
   month = (byte) ((Serial.read() - 48) *10 +  (Serial.read() - 48));
   year= (byte) ((Serial.read() - 48) *10 +  (Serial.read() - 48));
   Wire.beginTransmission(DS1307_I2C_ADDRESS);
   Wire.send(0x00);
   Wire.send(decToBcd(second));    // 0 to bit 7 starts the clock
   Wire.send(decToBcd(minute));
   Wire.send(decToBcd(hour));      // If you want 12 hour am/pm you need to set
                                   // bit 6 (also need to change readDateDs1307)
   Wire.send(decToBcd(dayOfWeek));
   Wire.send(decToBcd(dayOfMonth));
   Wire.send(decToBcd(month));
   Wire.send(decToBcd(year));
   Wire.endTransmission();
}

/**************************************************************************
 * LOOP
 *
 **/
void loop() {
  
  unsigned int now;
  byte wLevel, bLevel;
  boolean inThunder;
  byte inCloud;
  boolean minuteChanged = false;

  serialCommands();

 
 
  getDateDs1307();
  if ((hour == 0) && (minute ==00) && (dayOfMonth == 0) && (year == 0)) {
    // Communication with RTC failed, get out of loop before something
    // bad happens
    Serial.print("#");
    heartbeat();
    delay(200);
    return;
  }
  //////////////IR REMOTE //////////////////
  /////////////////////////////////////////
   if (irrecv.decode(&results)) // have we received an IR signal?

  {

    translateIR();

    for (int z=0; z<2; z++) // ignore 2nd and 3rd signal repeat

    {

      irrecv.resume(); // receive the next value

    }

  }
  /////////////////////////////////////////////////////////////////////
  // If the day changed, plan the new day
  if (prevDayOfMonth != dayOfMonth) {
    Serial.println();
    Serial.println();

    printDateTime();
    Serial.println(" ");
  
    Serial.print("DofM:");
    Serial.print(prevDayOfMonth, DEC);
    Serial.print("->");
    Serial.println(dayOfMonth, DEC);
    prevDayOfMonth = dayOfMonth;
    planNewDay(month, dayOfMonth);
    dumpCurve();
  }

  if (!DEBUG_MODE) {
    now = (hour*1800U + minute*30U + second/2U);
  } else {
    now = debug_now;
    minute = now/60;
  }

  if (now != prevNow) {
    heartbeat();
    prevNow = now;
  }

  if (prevMinute != minute) {
    Serial.print("++");
    printDateTime();
    Serial.println(" ");
    prevMinute = minute;
    minuteChanged = true;
    dstemp(); 
}

  // Loop through the LED channel pairs getting their light levels
  for (byte i=0; i<MAX_CHANNEL_PAIRS; i++) {
    boolean channelInThunder;
    unsigned int chanDelay;
    
    // Protection against unsigned int roll backwards
    chanDelay = channels[i].channelDelay;
    if (chanDelay > now) {
      chanDelay = now;
    }    
    
    getLevel(now - chanDelay, &channelInThunder, &wLevel, &bLevel);
    setLedPWMOutputs(i, wLevel, bLevel);
    
    if (channels[i].channelDelay == 0) {
      inThunder = channelInThunder;
    }
  }

  // In the future change this to LCD output
  if ((prevWLevel != wLevel) || (prevBLevel != bLevel)) {
    inCloud = insideCloud(now);
    logLevel(now, wLevel, bLevel, inCloud, inThunder);
  }

  // If in Thunderstorm, 5% possible lighning every minute
  #define LIGHTNING_CHANCE 5
  if ((inThunder) && (minuteChanged)) {
      byte randNumber = (byte) random(0, 100);
      if (randNumber <= LIGHTNING_CHANCE) {  
          doLightning(wLevel, bLevel);
      }
  }

  prevWLevel = wLevel;
  prevBLevel = bLevel;
  prevMinute = minute;
  planNextCloudBatch(now);

}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**************************************************************************
 * SETUP
 //////////////////////////////////////////////////////////////////////////////////////////////////////////////
 **/
 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void setup() {

  Wire.begin();
  Serial.begin(9600);
  randomSeed(analogRead(0));
  heartbeatLevel = LOW;

  getDateDs1307();
  
  // Zero the key variables
  currCloudCoverStart  = 0;
  currCloudCoverFinish = 0;
  prevWLevel = 0;
  prevBLevel = 0;
  prevDayOfMonth = 0;
  dayOfMonth = 40;  // Invalid number to force planNewDay in first loop
  
  if (DEBUG_MODE) {
    
    okta=0;
    xTestRun();

    prevDayOfMonth = 0;    
    okta=1;
    xTestRun();

    prevDayOfMonth = 0;    
    okta=2;
    xTestRun();

    prevDayOfMonth = 0;    
    okta=3;
    xTestRun();

    prevDayOfMonth = 0;    
    okta=4;
    xTestRun();

    prevDayOfMonth = 0;    
    okta=5;
    xTestRun();

    prevDayOfMonth = 0;    
    okta=6;
    xTestRun();

    prevDayOfMonth = 0;    
    okta=7;
    xTestRun();

    prevDayOfMonth = 0;    
    okta=8;
    xTestRun();
  }
 
  //////////IR REMOTE//////////////////////
irrecv.enableIRIn(); // Start the receiver
}

/******************************************************************************
// 1) Sets the date and time on the ds1307
// 2) Starts the clock
// 3) Sets hour mode to 24 hour clock
// Assumes you're passing in valid numbers, Probably need to put in checks for valid numbers.
//
// Format: ssmmhhWDDMMYY  (W=Day of the week, Sunday = 0)
void setDateDs1307() {
   second = (byte) ((Serial.read() - 48) * 10 + (Serial.read() - 48)); // Use of (byte) type casting and ascii math to achieve result.  
   minute = (byte) ((Serial.read() - 48) *10 +  (Serial.read() - 48));
   hour  = (byte) ((Serial.read() - 48) *10 +  (Serial.read() - 48));
   dayOfWeek = (byte) (Serial.read() - 48);
   dayOfMonth = (byte) ((Serial.read() - 48) *10 +  (Serial.read() - 48));
   month = (byte) ((Serial.read() - 48) *10 +  (Serial.read() - 48));
   year= (byte) ((Serial.read() - 48) *10 +  (Serial.read() - 48));
   Wire.beginTransmission(DS1307_I2C_ADDRESS);
   Wire.send(0x00);
   Wire.send(decToBcd(second));    // 0 to bit 7 starts the clock
   Wire.send(decToBcd(minute));
   Wire.send(decToBcd(hour));      // If you want 12 hour am/pm you need to set
                                   // bit 6 (also need to change readDateDs1307)
   Wire.send(decToBcd(dayOfWeek));
   Wire.send(decToBcd(dayOfMonth));
   Wire.send(decToBcd(month));
   Wire.send(decToBcd(year));
   Wire.endTransmission();

  printDateTime();
}
*/

void logLevel(unsigned int tNow, byte wTLevel, byte bTLevel, byte tInCloud, boolean tInThunder) 
{
  Serial.print(tNow,DEC);
  Serial.print(",");
  Serial.print(wTLevel,DEC);
  Serial.print(",");
  Serial.print(bTLevel,DEC);
  Serial.print(",");
  Serial.print(tInCloud,DEC);
  Serial.print(",");
  Serial.print(tInThunder,DEC);
  Serial.println();
}
 
Back
Top