Advertisement
baldengineer

Proper Larson Scanner with Software PWM

Oct 14th, 2015
1,471
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 6.47 KB | None | 0 0
  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
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement