PWMAllPins


/******************************************************************************************************
*   Title: PWMallPins.pde
*   Author: Paul Badger 2007
*   Formating: Seth Wolf 2015
*  
*   Action:
*   This program fades LED's on Arduino digital pins 2 through 13 in a sine-wave pattern.
*   A program to illustrate one way to implement a manual PWM loop.
*
*   It could be modified to also modulate pins 0 & 1 and the analog pins.
*   I didn't modulate pins 0 & 1 just because of the hassle of disconnecting
*   the LEDs on the RX and TX pins (0 & 1).
*  
*   The PWM loop, as written, operates at about 175 HZ and is flicker-free.
*   The trick to this is to reduce the computation process time in between the PWM loop cycles.
*   Long delays between the loops are going to show up as flicker. This is true especially of
*   "Serial.print" debug statements which seem to hog the processor during
*   transmission. Shorter (time-wise) statements will just dim the maximum brightness of
*   the LED's. There are a couple of lines of code (commented out) that implement a
*   potentiometer as a speed control for the dimming.
*  
*   How it works:
*   The PWM loop turns on all LED's whose values are greater than 0 at the start of the PWM loop.
*   value. It then turns off the LED's as the loop variable is equal to the channel's PWM modulation
*   Because the values are limited to 255 (just by the table), all LED's are turned
*   off at the end of the PWM loop. This has the side effect of making any extra math,
*   sensor reading and will increase the "off" period of the LED's duty cycle. Consequently
*   the brightest LED value (255), which is supposed to represent a "100%" duty cycle
*   (on all the time), doesn't really do that. More math and sensor reading will increase  
*   the "off time", dimming the LED's max brightness. You can make up for  
*   this dimming with smaller series resistors, since LED's can be overrated if they aren't
*   on all of the time.The up side of this arrangement is that the LED's stay flicker free.

*  
*   Note:
*   This program could easily be used to modulate motor speeds with the addition of driver transistors or MOSFET's.
*  
*************************************************************************************************************/


int LEDCount = 12;                        // Number of LEDs used in this project
int topValue = 14;                        // Largest Arduino pin number of the LED pin set (+1)
int pinNumber;                            // variable for pinNumber
int fractionRemainder;                    // variable for fraction Remainder
int channelCounter;                       // variable for channel Counter
int brightValue;                          // variable for LED brightness Value
int setCounter;                           // variable for loop set Counter
int potValue;                             // Variable read from the potentiometer
int pwmVal[14];                           // PWM values for the LEDs (0&1 included but not used) (change this value if topValue is modified)
long time;                                // variable for speed debuging
float pwmSpeed[14] = {                    // These constants set the rate of dimming (change this value if topValue is modified)
 0, 0, 1.2, 1.3, 1.4, 1.9, .9, .8, .5, 1.2, 1.37, 1.47, .3, 3.2}; // 12 values (one for each of the LEDs in the set)
float pwmFloats[14];                      // Brightness values for each LED (change this value if topValue is modified)
unsigned char sinewave[] =                // Preset 256 values of a binary conversions of a sine wave
{
0x80,0x83,0x86,0x89,0x8c,0x8f,0x92,0x95,0x98,0x9c,0x9f,0xa2,0xa5,0xa8,0xab,0xae,
0xb0,0xb3,0xb6,0xb9,0xbc,0xbf,0xc1,0xc4,0xc7,0xc9,0xcc,0xce,0xd1,0xd3,0xd5,0xd8,
0xda,0xdc,0xde,0xe0,0xe2,0xe4,0xe6,0xe8,0xea,0xec,0xed,0xef,0xf0,0xf2,0xf3,0xf5,
0xf6,0xf7,0xf8,0xf9,0xfa,0xfb,0xfc,0xfc,0xfd,0xfe,0xfe,0xff,0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xfe,0xfd,0xfc,0xfc,0xfb,0xfa,0xf9,0xf8,0xf7,
0xf6,0xf5,0xf3,0xf2,0xf0,0xef,0xed,0xec,0xea,0xe8,0xe6,0xe4,0xe2,0xe0,0xde,0xdc,
0xda,0xd8,0xd5,0xd3,0xd1,0xce,0xcc,0xc9,0xc7,0xc4,0xc1,0xbf,0xbc,0xb9,0xb6,0xb3,
0xb0,0xae,0xab,0xa8,0xa5,0xa2,0x9f,0x9c,0x98,0x95,0x92,0x8f,0x8c,0x89,0x86,0x83,
0x80,0x7c,0x79,0x76,0x73,0x70,0x6d,0x6a,0x67,0x63,0x60,0x5d,0x5a,0x57,0x54,0x51,
0x4f,0x4c,0x49,0x46,0x43,0x40,0x3e,0x3b,0x38,0x36,0x33,0x31,0x2e,0x2c,0x2a,0x27,
0x25,0x23,0x21,0x1f,0x1d,0x1b,0x19,0x17,0x15,0x13,0x12,0x10,0x0f,0x0d,0x0c,0x0a,
0x09,0x08,0x07,0x06,0x05,0x04,0x03,0x03,0x02,0x01,0x01,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x01,0x02,0x03,0x03,0x04,0x05,0x06,0x07,0x08,
0x09,0x0a,0x0c,0x0d,0x0f,0x10,0x12,0x13,0x15,0x17,0x19,0x1b,0x1d,0x1f,0x21,0x23,
0x25,0x27,0x2a,0x2c,0x2e,0x31,0x33,0x36,0x38,0x3b,0x3e,0x40,0x43,0x46,0x49,0x4c,
0x4f,0x51,0x54,0x57,0x5a,0x5d,0x60,0x63,0x67,0x6a,0x6d,0x70,0x73,0x76,0x79,0x7c
};
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
void setup(){
  Serial.begin(9600);
  DDRD=0xFC; // Arduino digital pins 0 to 7 - Configure all pins as read/write and output except for the serial pins, 0 & 1
  DDRB=0xFF; // Arduino digital pins 8 to 13 - Configure all pins as read/write and output
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////
void loop()
{
/** Time = millis(); */                                     // This is for testing the loop speed (remove commented bracket)
/** For (setCounter=0; setCounter<1000; setCounter++){ */   // This is for testing the loop speed (remove commented bracket)
/** potValue = analogread(0);  */                           // Sets potValue control to manually change speed of fading (remove line below)
  for (pinNumber=0; pinNumber<topValue; pinNumber++){       // Calculate a new PWM value every time through the loop (Cycle back to 0 after 11)
    fractionRemainder = (fractionRemainder + 1) % LEDCount; // Calculate a new fraction Remainder every time - modulo operator makes it
    channelCounter = fractionRemainder + 2;                 // Add 2 to the result for cycling the selected channel(pin) numbers
    pwmFloats[channelCounter] = (pwmFloats[channelCounter] + pwmSpeed[channelCounter]);
/** pwmFloats[channelCounter] = (pwmFloats[channelCounter] + ((pwmSpeed[channelCounter]*15*(float)potValue)/1023)); */  // implements potentiometer control
      if (pwmFloats[channelCounter] >= 256){                            // Wrap around sine table values that are larger than 256
      pwmFloats[channelCounter] = pwmFloats[channelCounter] - 256;      //
    }                                                                   //
    else if  (pwmFloats[channelCounter] < 0){                           //
      pwmFloats[channelCounter] = pwmFloats[channelCounter] + 256;      // Wrap around sinewave table index values that are less than 0
    }                                                                   //
    pwmVal[channelCounter] = sinewave[(int)pwmFloats[channelCounter]];  // Convert the float value to an integer and get the value out of the sinewave index
  }                                                                     //
  PORTD = 0xFC;                                                         // Reset all outputs except serial pins 0 & 1
  PORTB = 0xFF;                                                         // Reset and turn on all pins of ports D & B
  for (setCounter=0; setCounter<3; setCounter++){                       // This adds more repetitions of the loop below to reduce the processing time of the loop above
  // Increase this value until you start to perceive any flicker in the LEDs
  // then back off and reduce the value
  // Decreasing value configures for a more responsive sensor input read process

    for (brightValue=0; brightValue<256; brightValue++){    // Cycle through the 256  values to find a match
      for( pinNumber=2; pinNumber<topValue; pinNumber++){   // start with 2 to avoid serial pins
        if (brightValue == pwmVal[pinNumber]){              // If it found a standard value matching one of the pins
          if (pinNumber < 8){                               // Corresponds to PORTD pin group
          // bit-shift a one into the proper bit then reverse the whole byte
          // equivalent to the line below but around 4 times faster
          // digitalWrite(pinNumber, LOW);
            PORTD = PORTD & (~(1 << pinNumber));            // Arduino digital pins 0 to 7
          }                                                 //
          else{                                             //
            PORTB = PORTB & (~(1 << (pinNumber-8)));        // Corresponds to PORTB (same as digitalWrite(pin, LOW);) on Port B pins
          }                                                 //
        }
      }
    }
  }
/**  } */                                                   // This is for the testing loop speed (remove the commented bracket)
/**  Serial.println((millis() - time), DEC);    */          // speed test code
}

 

Sketch Library

Share