SHARE
TWEET

Proper Larson Scanner with Software PWM

baldengineer Oct 14th, 2015 452 Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. //proper-larson.ino
  2.  
  3. // macros for LED state
  4. #define ON true
  5. #define OFF false
  6.  
  7. #define UP true
  8. #define DOWN false
  9.  
  10. // variables for larson pattern timing
  11. unsigned long currentMillis = millis();
  12. unsigned long previousMillis = 0;
  13. unsigned long millisInterval = 5;
  14.  
  15. // LED fading (recommended value)
  16. int fadeIncrement = 5;
  17.  
  18. // tells which LED is the brightest
  19. // start at the far "right" (or left?)
  20. int larsonStatus = 0x80;
  21.  
  22. // bit mask for maximum scan value
  23. // picture larsonMax in binary
  24. // 00001000 00000000
  25. // if you had 30 LEDs, you'd need an a long...
  26. int larsonMax = 0x80;
  27. // arbitrary starting direction
  28. bool direction = DOWN;
  29.  
  30. // variables for software PWM
  31. // really have to play with pwmMax
  32. // and microInterval to get a smooth
  33. // fade effect
  34. unsigned long currentMicros = micros();
  35. unsigned long previousMicros = 0;
  36. unsigned long microInterval = 10;
  37. // instead of HW PWM's "255" levels, we get 100
  38. const byte pwmMax = 100;
  39.  
  40. // typedef for properties of each sw pwm pin
  41. typedef struct pwmPins {
  42.   int pin;
  43.   int pwmValue;
  44.   bool pinState;
  45.   int pwmTickCount;
  46. } pwmPin;
  47.  
  48. // create the sw pwm pins
  49. // these can be any I/O pin
  50. // that can be set to output!
  51. const int pinCount = 8;
  52. //const byte pins[pinCount] = {2,3,5,6,9,10,11,12};
  53. const byte pins[pinCount] = {2,3,4,5,6,7,8,9};
  54.  
  55. // an array of Software PWM Pins
  56. pwmPin myPWMpins[pinCount];
  57.  
  58.  
  59. void setup() {
  60.         // sets each element of myPWMpins to something
  61.         setupPWMpins();
  62. }
  63.  
  64. void loop() {
  65.         // constantly ping handlePWM()
  66.         handlePWM();
  67.  
  68.         // typical millis timer code
  69.         // see what time it is.
  70.         currentMillis = millis();
  71.         if (currentMillis - previousMillis >= millisInterval) {
  72.                 if (direction == UP) {
  73.                         // going "left"
  74.                         // need a reference for which LED is the "bright" one
  75.                         int index = 0;
  76.                         for (index=pinCount; index >= 0; index--) {
  77.                                 if (bitRead(larsonStatus, index))
  78.                                         break;
  79.                         }
  80.                         // index is the bit set to "1"
  81.  
  82.                         // see if we're the last pin
  83.                         if (index < (pinCount)) {
  84.                                 // fade up the LED next to the "on" LED
  85.                                 myPWMpins[index+1].pwmValue += fadeIncrement;
  86.  
  87.                                 // check if the fading LED is fully on yet
  88.                                 if (myPWMpins[index+1].pwmValue >= pwmMax) {
  89.                                         // okay, time to move to the next one!
  90.                                         // "barrel shift" the "1", one bit over
  91.                                         larsonStatus = larsonStatus << 1;
  92.                                         // start fading the previous on
  93.                                         myPWMpins[index].pwmValue   = myPWMpins[index].pwmValue - fadeIncrement;
  94.                                         // did we hit the end yet?
  95.                                         if (larsonStatus == (larsonMax << 1)) {
  96.                                                 // okay, time to change direction
  97.                                                 larsonStatus = larsonMax;
  98.                                                 direction = DOWN;
  99.                                         }
  100.                                 }
  101.                         }
  102.                         // create the tails.
  103.                         createFadeTail((index-1),4,15);
  104.                         createFadeTail((index-2),2,5);
  105.                         createFadeTail((index-3),1,1);
  106.                 } else {
  107.                         // going right
  108.                         int index = 0;
  109.                         // need a reference for which LED is the "bright" one
  110.                         for (index=0; index < pinCount; index++) {
  111.                                 if (bitRead(larsonStatus, index))
  112.                                         break;
  113.                         }
  114.                         // index is the bit set to "1"
  115.  
  116.                         if (index > 0) {
  117.                                 // fade up the LED next to the "on" LED
  118.                                 myPWMpins[index-1].pwmValue += fadeIncrement;
  119.  
  120.                                 if (myPWMpins[index-1].pwmValue >= pwmMax) {
  121.                                         larsonStatus = larsonStatus >> 1;
  122.                                         // start fading the previous on
  123.                                         myPWMpins[index].pwmValue   = myPWMpins[index].pwmValue - fadeIncrement;
  124.                                         // didn't use a const here, because, it is probably 0
  125.                                         if ((larsonStatus == 0x01)) {
  126.                                                 direction = UP;
  127.                                         }
  128.                                 }      
  129.                                 // very similar to opposite direction
  130.                                 // except we are modifying pins "after" bright one
  131.                                 createFadeTail((index+1),4,15);
  132.                                 createFadeTail((index+2),2,5);
  133.                                 createFadeTail((index+3),1,1);
  134.                         }
  135.                 }
  136.                 // setup clock for next tick
  137.                 previousMillis = currentMillis;
  138.         }
  139. }
  140.  
  141. void createFadeTail(int pinIndex, int fadeMultiplier, int pwmLimit) {
  142.         // make sure we aren't modifying past the end of myPWMpins or pins array
  143.         if ((pinIndex) < pinCount) {
  144.                 // change pwmValue to make our fade effect
  145.                 myPWMpins[pinIndex].pwmValue = myPWMpins[pinIndex].pwmValue - fadeIncrement*fadeMultiplier;
  146.                 // make sure the number doesn't go negative
  147.                 if (myPWMpins[pinIndex].pwmValue <= fadeIncrement)
  148.                         // limit the lowest brightness
  149.                         // found this looks better with "1-5" instead of 0
  150.                         myPWMpins[pinIndex].pwmValue = pwmLimit;
  151.         }
  152.         handlePWM();
  153. }
  154.        
  155.  
  156. void handlePWM() {
  157.   currentMicros = micros();
  158.   // check to see if we need to increment our PWM counters yet
  159.     if (currentMicros - previousMicros >= microInterval) {
  160.     // Increment each pin's counter
  161.     for (int index=0; index < pinCount; index++) {
  162.     // each pin has its own tickCounter
  163.       myPWMpins[index].pwmTickCount++;
  164.  
  165.     // determine if we're counting on or off time
  166.       if (myPWMpins[index].pinState == ON) {
  167.         // see if we hit the desired on percentage
  168.         // not as precise as 255 or 1024, but easier to do math
  169.         if (myPWMpins[index].pwmTickCount >= myPWMpins[index].pwmValue) {
  170.           myPWMpins[index].pinState = OFF;
  171.         }
  172.       } else {
  173.         // if it isn't on, it is off
  174.         if (myPWMpins[index].pwmTickCount >= pwmMax) {
  175.           myPWMpins[index].pinState = ON;
  176.           myPWMpins[index].pwmTickCount = 0;
  177.         }
  178.       }
  179.  
  180.       // for the LEDs on or off, for min and max values
  181.       // similar to how Arduino library does PWM
  182.       if (myPWMpins[index].pwmValue == pwmMax)
  183.         myPWMpins[index].pinState = ON;
  184.       if (myPWMpins[index].pwmValue == 0)
  185.         myPWMpins[index].pinState = OFF;
  186.  
  187.           // could probably use some bitwise optimization here, digitalWrite()
  188.           // really slows things down after 10 pins.
  189.       digitalWrite(myPWMpins[index].pin, myPWMpins[index].pinState);
  190.     }
  191.     // reset the micros() tick counter.
  192.     previousMicros = currentMicros;
  193.   }
  194. }
  195.  
  196. // function to "setup" the sw pwm pin states
  197. // modify to suit your needs
  198. void setupPWMpins() {
  199.   for (int index=0; index < pinCount; index++) {
  200.         // connect a myPWMpin to an actual pin
  201.     myPWMpins[index].pin = pins[index];
  202.     // start with all LEDs off
  203.     myPWMpins[index].pwmValue = 0;
  204.     // doesn't matter ON or OFF
  205.     myPWMpins[index].pinState = ON;
  206.     // set the counter to 0
  207.     myPWMpins[index].pwmTickCount = 0;
  208.     // make sure pin is set correctly
  209.     pinMode(pins[index], OUTPUT);
  210.   }
  211.   // start with the "go-right" pattern, so
  212.   // turn on "last" LED full
  213.   myPWMpins[pinCount-1].pwmValue = 100;
  214. }
  215.  
  216. // Code from james@baldengineer.com
  217. // email | twitter | www
  218. // See more at: https://www.baldengineer.com/larson
RAW Paste Data
We use cookies for various purposes including analytics. By continuing to use Pastebin, you agree to our use of cookies as described in the Cookies Policy. OK, I Understand
 
Top