Forum Rule: Always post complete source code & details to reproduce any issue!
Results 1 to 11 of 11

Thread: Adding Adafruit LED Code to Teensy w/Controller

  1. #1
    Junior Member
    Join Date
    Nov 2019
    Posts
    15

    Adding Adafruit LED Code to Teensy w/Controller

    I've created a MIDI "Air Harp" instrument. Some prototype info:
    Video: https://youtu.be/VMS8y9XyK0A
    Images: https://imgur.com/5UsVyRW
    https://imgur.com/H30AUpI
    https://imgur.com/b1ulnFd
    https://imgur.com/zaTGVYp

    The current code:

    Code:
    int noteIsOn1;
    int noteIsOn2;
    int noteIsOn3;
    int noteIsOn4;
    int noteIsOn5;
    int noteIsOn6;
    int noteIsOn7;
    int noteIsOn8;
    int thresh;
    int vel;
    
    void setup() {
    
    thresh = 400;
    //thresh = constrain(thresh, 230, 232);
    vel = (random(90,120));
    
    }
    
    void loop() {
    
    /// Sensor 1
      if (noteIsOn1 == false) {
        if (analogRead(0) > thresh) {
          usbMIDI.sendNoteOn(60, random(90,120), 1);
          noteIsOn1 = true;
        }
      } else {
        if (analogRead(0) < thresh) {
          usbMIDI.sendNoteOff (60, 0, 1);
          noteIsOn1 = false;
        }
      }                 
    /// Sensor 2
      if (noteIsOn2 == false) {
       if (analogRead(1) > thresh) {
          usbMIDI.sendNoteOn(62, random(90,120), 1);
          noteIsOn2 = true;
        }
      } else {
        if (analogRead(1) < thresh) {
          usbMIDI.sendNoteOff (62, 0, 1);
          noteIsOn2 = false;
        }    
      }
    /// Sensor 3
      if (noteIsOn3 == false) {
        if (analogRead(2) > thresh) {
          usbMIDI.sendNoteOn(64, random(90,120), 1);
          noteIsOn3 = true;
        }
      } else {
        if (analogRead(2) < thresh) {
          usbMIDI.sendNoteOff (64, 0, 1);
          noteIsOn3 = false;
        }    
      }
      /// Sensor 4
      if (noteIsOn4 == false) {
        if (analogRead(3) > thresh) {
          usbMIDI.sendNoteOn(65, random(90,120), 1);
          noteIsOn4 = true;
        }
      } else {
        if (analogRead(3) < thresh) {
          usbMIDI.sendNoteOff (65, 0, 1);
          noteIsOn4 = false;
        }    
      }
        /// Sensor 5
      if (noteIsOn5 == false) {
        if (analogRead(4) > thresh) {
          usbMIDI.sendNoteOn(67, random(90,120), 1);
          noteIsOn5 = true;
        }
      } else {
        if (analogRead(4) < thresh) {
          usbMIDI.sendNoteOff (67, 0, 1);
          noteIsOn5 = false;
        }    
      }
      /// End Sensor
          /// Sensor 6
      if (noteIsOn6 == false) {
        if (analogRead(5) > thresh) {
          usbMIDI.sendNoteOn(69, random(90,120), 1);
          noteIsOn6 = true;
        }
      } else {
        if (analogRead(5) < thresh) {
          usbMIDI.sendNoteOff (69, 0, 1);
          noteIsOn6 = false;
        }    
      }
      /// End Sensor
            /// Sensor 7
      if (noteIsOn7 == false) {
        if (analogRead(6) > thresh) {
          usbMIDI.sendNoteOn(70, random(90,120), 1);
          noteIsOn7 = true;
        }
      } else {
        if (analogRead(6) < thresh) {
          usbMIDI.sendNoteOff (70, 0, 1);
          noteIsOn7 = false;
        }    
      }
      /// End Sensor
            /// Sensor 8
      if (noteIsOn8 == false) {
        if (analogRead(7) > thresh) {
          usbMIDI.sendNoteOn(72, random(90,120), 1);
          noteIsOn8 = true;
        }
      } else {
        if (analogRead(7) < thresh) {
          usbMIDI.sendNoteOff (72, 0, 1);
          noteIsOn8 = false;
        }    
      }
      /// End Sensor
      while (usbMIDI.read()) {}
      delay(5);
    
    }
    I'll try to make the code more elegant at some point.

    Next step that I need help on:

    I'm replacing the sticks in the prototype with clear tubes. Then I'm putting 3-9W LEDs at the bottom of the tubes. The idea is that the tubes will be one color when idle and another when activated.

    Here's a CAD image:
    Click image for larger version. 

Name:	yd82Lt3.png 
Views:	3 
Size:	104.3 KB 
ID:	18235

    I've bought this LED controller from adafruit:
    https://www.adafruit.com/product/1429

    As I understand it, I need to include the TLC5947 library in my above code. I think I can figure out the setup code. I'm not positive how to use the loop code. Here's a template of what each note/tube code would look like:

    Code:
    /// Sensor 1
      if (noteIsOn1 == false) {
        if (analogRead(0) > thresh) {
          usbMIDI.sendNoteOn(60, random(90,120), 1);
          ///INSERT CODE TO ACTIVATE LED COLOR FOR noteIsOn1=true
          noteIsOn1 = true;
        }
      } else {
        if (analogRead(0) < thresh) {
          usbMIDI.sendNoteOff (60, 0, 1);
          ///INSERT CODE TO ACTIVATE LED COLOR FOR noteIsOn1=false
          noteIsOn1 = false;
        }
      }
    I'm sure it's simple, but I'm not understanding what to use based on Adafruit's sample code.

    Thanks much for any help!

  2. #2
    Senior Member oddson's Avatar
    Join Date
    Feb 2013
    Location
    Isle in the Salish Sea
    Posts
    1,238
    You have a choice... you can figure out how to program that part for SPI control or you can figure out how to control LED load currents via transistor switches.

    No offence, but your programming skills appear a bit on the novice side. But if you go that way you need to learn how to use the library that supports SPI
    https://www.pjrc.com/teensy/td_libs_SPI.html




    If you have any electronics background (or are keen to learn) you might find it easier to use 9 digital pins to control each LED by driving the pin HIGH and LOW as needed (depending on if you are sourcing or sinking current and whether you are using a BJT or JFET/MOSFET to switch the circuit -- there are dozens of circuit variations that do this -- below is one).
    Click image for larger version. 

Name:	ZK60L.png 
Views:	2 
Size:	12.7 KB 
ID:	18237

    If you were going for two full octaves then the SPI would be a more compelling option as you can't afford 2 pins for every note.



    Regarding making your code more elegent… (when you are ready...)

    Your code could benefit from using arrays if you are doing the same thing with code on multiple objects.

    Since the pin is the only difference your code for each pin can be consolidated into a single 'for' loop.
    Code:
    for (int i = 0; i < 8; i++){
        if (noteIsOn[i] == false) {
            if (analogRead(i) > thresh) {
                usbMIDI.sendNoteOn(note[i], random(90,120), 1);
                noteIsOn[i] = true;
            }
        } else {
            if (analogRead(i) <= thresh){
                usbMIDI.sendNoteOff (note[i], 0, 1);
                noteIsOn[i] = false;
            }
        }
    }
    The local variable i is an index from zero to one less than the number of elements. Therefore the last element in note[] has an index of 7.

    The loop increments the index from 0 to 7 (last value "<8" - the number of elements in the array)

    You would need to declare the variables as arrays instead of as separate scalar values.

    So this:
    Code:
    int noteIsOn1;
    int noteIsOn2;
    int noteIsOn3;
    int noteIsOn4;
    int noteIsOn5;
    int noteIsOn6;
    int noteIsOn7;
    int noteIsOn8;
    Becomes this:
    Code:
    int noteIsOn[8];
    And you would need to configure a variable with all the note numbers you want to use
    Code:
    int note[8] = {60,62,64,65,67,69,71,72};
    Any you would likely do the same with pin numbers for the analog pins and LED pins.

    e.g.
    int ANALOG_PINS[A_PINS] = {A0,A1,A2,A3,A5,A6,A7,A8,A9};
    Note these don't have to be in order -- I've skipped A4 but as long as I've wired it that way it's fine. Very handy once you need specific pins for specific things.
    Your code actually relies a convention with analogRead that 1 = A1 but if you are explicitly listing pins it's best to call analog pins with the A# designation.

    With time you could figure out how to store the rate of change from values that didn't cross the threshold to generate a proportional velocity value when they do... (sample the values a regular intervals and use the difference to calculate a velocity value for the note on message).

    Interesting project... Nice to see modest early ambitions with plans for incremental improvement instead of trying to do everything at once.

    I'm happy to help with MIDI and basic programming stuff but I don't claim any expertise on SPI and really have only minimal electronics knowledge but there are lots of great people here that can help (provided you put in effort from your end).

  3. #3
    Senior Member
    Join Date
    Feb 2016
    Location
    Australia
    Posts
    231
    Copy example global variable stuff over to your program.
    Copy example setup stuff into your program setup()
    Wherever you want to light up your lights in your code just put:
    tlc.setLED(x, r, g, b);
    tlc.write();

    Where x is the led you want to light up and r,g,b are the red green blue values you want.
    x could be 1 to 8 I think and rgb probably 0-255. That’s my guess based on a look at example while I wait for my car to be serviced.

  4. #4
    Senior Member
    Join Date
    Feb 2016
    Location
    Australia
    Posts
    231
    Make sure their example works to start with so you know your hardware is hooked up correctly.

  5. #5
    Senior Member oddson's Avatar
    Join Date
    Feb 2013
    Location
    Isle in the Salish Sea
    Posts
    1,238
    D'oh… didn't notice the colour comments... kinda undermines my comments on direct control.

    Unless you really just want to alternate, in which case you can use the same signal and source one and sink the other to alternate the colour.

    If you want RGB LEDs on each you might consider smart pixel elements.

  6. #6
    Senior Member
    Join Date
    Feb 2016
    Location
    Australia
    Posts
    231
    Ooh. Oddson got me thinking. I don’t think that pwm controller can drive any significant power. I .09W maybe. Better check that. My apologies if you already have that covered.

  7. #7
    Junior Member
    Join Date
    Nov 2019
    Posts
    15
    Thanks for the coding tips on the 'for' loop @oddson! I should have prefaced that I haven't coded in about 10 years and should be considered a newbie. But I would consider myself a MIDI expert (lifelong synth player, since before MIDI) .

    My nephew, who is an engineer, is handling the electronics and building the frame. After I built the prototype I asked him for help to take it to the next level. He 3D printed the caps for the tubes and they look like they came from a legit manufacturer. Anyway, he picked out the controller for the LEDs. From what I read, "You can drive multiple LEDs in series, with a V+ anode supply of up to 30V." I think we're okay if I understand that right. We'll find out when the LEDs and the controller come in today.

    I mainly need help with the coding, which my nephew doesn't do very much. But this is really simple, so thanks @Gibbedy for this:

    tlc.setLED(x, r, g, b);
    tlc.write();
    Nice! I will see this all the way through, because we're using this instrument as our centerpiece for an epic Christmas song at my church. We were going to use a laser harp, but that's a huge animal to try to tackle this year. It morphed into this "Air Harp."

    Thanks again and any other input greatly appreciated.

  8. #8
    Senior Member oddson's Avatar
    Join Date
    Feb 2013
    Location
    Isle in the Salish Sea
    Posts
    1,238
    Apologies... yet again not reading carefully

    The controller should be fine and the library doesn't look difficult to use.

    Gibbedy's comments appear correct except the colour values are 12 bit values (stored as type uint16_t)

    Quote Originally Posted by Gibbedy View Post
    Ooh. Oddson got me thinking. I don’t think that pwm controller can drive any significant power. I .09W maybe. Better check that. My apologies if you already have that covered.
    That would be the spec 'Constant output sink current'? Says 30 mA. which is about 0.1W at 3.3 v.

    I have no clue it this will be sufficient for your project. I'm have very little LED display experience other than indicators.

    If you are interested I could help get you velocity control based on time between crossing two thresholds.

    Velocity could be mapped inversely proportional to the time between crossing lower to upper threshold.
    Last edited by oddson; 11-22-2019 at 12:08 AM.

  9. #9
    Junior Member
    Join Date
    Nov 2019
    Posts
    15
    Okay, we finally have the sensor harp very close to finished, but I can't get my head around the LED programming. The "harp" has 8 three-foot acrylic tubes on a frame positioned vertically. The tops of the tubes have the sensors that translate to a MIDI note when you put your hand over it. That part works fine. Inside each tube is an LED strip attached to the ADAFRUIT tlc5947 (https://www.adafruit.com/product/1429). By this evening everything will be hooked up and ready to program, but I'm still lost on the LED programming. I'm not understanding how each tube of LEDs can be addressed. We aren't using analog as I thought we were, so now I have to understand PWM.

    Here are the basic instructions: https://learn.adafruit.com/tlc5947-t...-reference-5-6. I need to think of each of the 8 tubes as a channel. If each tube is [i], then is a channel is the pin number some kind of factor of 3? "lednum = LED number (channel number of the "red" pin divided by 3)".

    I'm so lost. Any help greatly appreciated. Here is the current code:

    Code:
    // LED
    #include "Adafruit_TLC5947.h"
    #define NUM_TLC5974 1
    #define data   4
    #define clock   5
    #define latch   6
    #define oe  -1  // set to -1 to not use the enable pin (its optional)
    Adafruit_TLC5947 tlc = Adafruit_TLC5947(NUM_TLC5974, clock, data, latch);
    // END LED
    
    // HARP
    int noteIsOn[8]; 
    int note[8] = {60,62,64,65,67,69,71,72}; //MIDI Notes
    int thresh;
    int vel;
    int chan;
    // END HARP
     
    
    void setup() {
    
    // LED
      Serial.begin(9600);
      
      Serial.println("TLC5974 test");
      tlc.begin();
      if (oe >= 0) {
        pinMode(oe, OUTPUT);
        digitalWrite(oe, LOW);
      }
    // END LED
    
    // HARP
    thresh = 400; //Threshold of sensor
    vel = (random(100,127)); //MIDI velocity
    chan=1; //MIDI channel
    // END HARP
    
    }
    
    void loop() {   
    
       // SENSOR IS ON
    for (int i = 0; i < 8; i++){
        if (noteIsOn[i] == false) {
            if (analogRead(i) > thresh) {
                usbMIDI.sendNoteOn(note[i], vel, chan);
                noteIsOn[i] = true;
    
    // ADD LED NOTE ON COLOR CODE HERE     
     
            }
    
        } else {
    
       // SENSOR IS OFF  
            if (analogRead(i) <= thresh){
                usbMIDI.sendNoteOff (note[i], 0, chan);
                noteIsOn[i] = false;
    
    // ADD LED NOTE OFF COLOR CODE HERE
    
            }
        }
    }
    }

  10. #10
    Junior Member
    Join Date
    Nov 2019
    Posts
    15
    This is how the driver is wired. Each 3-pin connector is an LED strip:

    Click image for larger version. 

Name:	08wf5S7.jpg 
Views:	2 
Size:	52.6 KB 
ID:	18363

  11. #11
    Junior Member
    Join Date
    Nov 2019
    Posts
    15
    I'm going to give @Gibbedy's code a try when the hardware is ready (sometime tonight). In this code, a tubes should be blue when not activated and red when it is. Fingers crossed:

    Code:
    // LED
    #include "Adafruit_TLC5947.h"
    #define NUM_TLC5974 1
    #define data   4
    #define clock   5
    #define latch   6
    #define oe  -1  // set to -1 to not use the enable pin (its optional)
    Adafruit_TLC5947 tlc = Adafruit_TLC5947(NUM_TLC5974, clock, data, latch);
    // END LED
    
    // HARP
    int noteIsOn[8]; 
    int note[8] = {60,62,64,65,67,69,71,72}; //MIDI Notes
    int thresh;
    int vel;
    int chan;
    // END HARP
     
    
    void setup() {
    
    // LED
      Serial.begin(9600);
      
      Serial.println("TLC5974 test");
      tlc.begin();
      if (oe >= 0) {
        pinMode(oe, OUTPUT);
        digitalWrite(oe, LOW);
      }
    // END LED
    
    
    // HARP
    thresh = 400; //Threshold of sensor
    vel = (random(100,127)); //MIDI velocity
    chan=1; //MIDI channel
    // END HARP
    }
    
    void loop() {   
    
       // SENSOR IS ON
    for (int i = 0; i < 8; i++){
        if (noteIsOn[i] == false) {
            if (analogRead(i) > thresh) {
                usbMIDI.sendNoteOn(note[i], vel, chan);
                noteIsOn[i] = true;
    // LED RED   
          tlc.setLED(i, 4095, 0, 0);
          tlc.write();  
    // END LED
            }
        } else {
    
       // SENSOR IS OFF  
            if (analogRead(i) <= thresh){
                usbMIDI.sendNoteOff (note[i], 0, chan);
                noteIsOn[i] = false;
    // LED BLUE   
          tlc.setLED(i, 0, 0, 4095);
          tlc.write();  
    // END LED
            }
        }
    }
    }

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •