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

Thread: Bounce & Bounce2 Objects with Multiplexer 74HCT4051 / 4051

  1. #1
    Junior Member
    Join Date
    Jan 2016
    Location
    Ohio, USA
    Posts
    14

    Bounce & Bounce2 Objects with Multiplexer 74HCT4051 / 4051

    I have a MIDI project using switches, potentiometers and piezo-electrics paired with Teensy-LC. Things are going well.
    I am using 74HCT4051 multiplexers to read these components, and I have had great results.

    Previously, using Teensy 2.0, switches and piezos, I was generating MIDI Control Change values of 0 or 1 using the Bounce library.
    I need to understand how to use the Bounce/Bounce2 library with the 74HCT4051.

    Here's my example code, it does not work. The idea is to generate "1" when the buttons are pressed or the piezos generate a rising voltage, and a "0" when the voltage is falling. But I am getting neither 0 or 1.
    I also realize that I need more practice working with arrays in Arduino.

    Code:
    #include <Bounce2.h>
    # define BOUNCE_LOCK_OUT
    
    
    // variable definition for 4051
    int r0 = 0;  // setting initial value of 4051 pin (s0)
    int r1 = 0;  // setting initial value of 4051 pin (s1)
    int r2 = 0;  // setting initial value of 4051 pin (s2)
    int count = 0;  // which pin we are selecting while reading 4051 inputs
    int old_time = 0; // time since powered on
    
    // asssign Input pin
    int digitalPin = 3;
    
    // initiate Bounce
    Bounce debouncer_piezos[8] = Bounce();
    
    // define the s0, s1, s2 pins on Teensy
    int s0 = 0;
    int s1 = 1;
    int s2 = 2;
    
    // setup arduino pins
    void setup() {
      
      pinMode(s0, OUTPUT);  // s0
      pinMode(s1, OUTPUT);  // s1
      pinMode(s2, OUTPUT);  // s2
    
      pinMode(digitalPin, INPUT);  // set digitalPin to INPUT
      debouncer_piezos[8].attach(digitalPin);
      debouncer_piezos[8].interval(5);
    }
    
    
    void loop() {
      for(count = 0; count <= 7; count++) {  // "count = 0" initializes for loop,
                                             // "count <= 7" tests,
                                             // "count++" increments / decrements 
    
        debouncer_piezos[count].update();
        
        // SELECT THE BIT
        // reads bit of a number, in this case "count", 
        // it reads the binary equivalent of count (count = 1 --> r2r1r0 = 001)
        // "0" tells bitRead to read the right most bit
        // "1" tells bitRead to read the first bit form the right
        // "2" tells bitRead to read the second bit form the right
        r0 = bitRead(count, 0);
        r1 = bitRead(count, 1);
        r2 = bitRead(count, 2);
        
        // WRITE TO DIGITAL PINS
        digitalWrite(s0, r0);  // teensy pin 0, s0 on 4051
        digitalWrite(s1, r1);  // teensy pin 1, s1 on 4051
        digitalWrite(s2, r2);  // teensy pin 2, s2 on 4051
        
        delayMicroseconds(75);  // once the pin is selected, allow some time
                                // for the signal to stabalize
    
    
        // READ MULTIPLEXED PIN
        if ( debouncer_piezos[count].rose() ) {
        usbMIDI.sendControlChange(count+1, 1, 1);
        }
        if ( debouncer_piezos[count].fell() ) {
        usbMIDI.sendControlChange(count+1, 0, 1);
        }
        
        // simple counter that confirms teensy is communicating with Pure Data
        int new_time = millis();
        if ( new_time - old_time >= 1000 ) {
          usbMIDI.sendControlChange(100, new_time/1000, 1);
        }
    
    
      }
    }

  2. #2
    Junior Member
    Join Date
    Jan 2016
    Location
    Ohio, USA
    Posts
    14
    bump, still curious

  3. #3
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    21,279
    Quote Originally Posted by dr_d_nice View Post
    Bounce debouncer_piezos[8] = Bounce();
    Does this create 8 or only 1 actual Bounce object?

  4. #4
    Junior Member
    Join Date
    Jan 2016
    Location
    Ohio, USA
    Posts
    14
    I'm not actually sure.
    My intention is to monitor each of the 8 multiplexer pins. Maybe I do need a separate Bounce object per pin.

  5. #5
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    21,279
    Quote Originally Posted by dr_d_nice View Post
    Maybe I do need a separate Bounce object per pin.
    Yes, you definitely need 1 per pin.

    If each pin doesn't have its own pullup resistor, you'll also need many microseconds delay from the moment you change the mux before you update the Bounce object, to allow time for the weak pullup to slowly make the line high.

  6. #6
    Junior Member
    Join Date
    Jan 2016
    Location
    Ohio, USA
    Posts
    14
    Thanks Paul! I've give it a shot.

  7. #7
    3 year bump.

    Paul are you saying that each pin of each mux needs its own Bounce object? Seems like the same Bounce object could be used repeatedly on the same teensy input pin to which the mux is attached??

    I am currently working on something with a LOT of knobs and buttons, and while my code is functioning......it is long because I am struggling with how to efficiently setup Bounce objects such that a large number of them can be accessed from within a nested loop.

  8. #8
    and, does this create 8 or only 1 bounce() object

    Code:
    Bounce debouncer_piezos[8] = Bounce();

  9. #9
    Senior Member oddson's Avatar
    Join Date
    Feb 2013
    Location
    Isle in the Salish Sea
    Posts
    1,286
    You need separate bounce items because you will get different readings between each switch and you would mistake those for a bouncing switch....

    So you need multiple objects with the same pin input from the MUX but different indexes based on the selector settings at the mux to apply the correct data from the actual switch.

    I think that code only generates one bounce object. And I'm not sure bounce is the way to deal with piezo readings (implied by the name).

    If you are trying to extract a triggering event from the signal of a piezo you normally would convert it to an envelop and test when the envelop passes some threshold value.


    For how to initialize an array of bounce objects see the first post from this tread (notice the keyword 'new' in the setup lines on this and ResponsiveAnalogRead).
    https://forum.pjrc.com/threads/52552...ing-this-right

  10. #10
    Quote Originally Posted by oddson View Post

    For how to initialize an array of bounce objects see the first post from this tread (notice the keyword 'new' in the setup lines on this and ResponsiveAnalogRead).
    https://forum.pjrc.com/threads/52552...ing-this-right
    That link is very informative. Still trying to digest it. My experience with pointers and arrays is limited. LEARNING!

    Luckily my project does not use any piezos. Just pushbuttons and knobs.

    Currently I am reluctant to post my code because it --in my inexperienced style -- is super messy.

  11. #11
    Senior Member oddson's Avatar
    Join Date
    Feb 2013
    Location
    Isle in the Salish Sea
    Posts
    1,286
    That post covers how to initialize the bounce and ResponsiveAnalogRead object. It's multiplex code uses a delay immediately after setting the mux controls to give the signal time to stabilize after switching, which would be fine in some circumstances but I believe having it on the inner loop means it's firing between every reading meaning you would be less and less responsive the more mux you have.

    I have yet to write code for all the issues that arrise with lots of mux as I don't ever use up the pins on the T3.0s I usually use for my MIDI projects.

    So my mux experience has been purely 'experimental' and so I can't truly comment on usability in the real world of MIDI.

    This post is a decent index of what I do know on the subject: https://forum.pjrc.com/threads/52856...l=1#post181888

  12. #12
    Quote Originally Posted by oddson View Post
    That post covers how to initialize the bounce and ResponsiveAnalogRead object. It's multiplex code uses a delay immediately after setting the mux controls to give the signal time to stabilize after switching, which would be fine in some circumstances but I believe having it on the inner loop means it's firing between every reading meaning you would be less and less responsive the more mux you have.

    I have yet to write code for all the issues that arrise with lots of mux as I don't ever use up the pins on the T3.0s I usually use for my MIDI projects.

    So my mux experience has been purely 'experimental' and so I can't truly comment on usability in the real world of MIDI.

    This post is a decent index of what I do know on the subject: https://forum.pjrc.com/threads/52856...l=1#post181888
    Awesome! Thanks again. Here is what I have been able to get working with the Teensy 3.5. This is a bare bones version of the code which does not include all the other stuff I have going on: display, encoder, interface buttons, and some other functionality that is in development.

    The trick was setting up the large array of an array of Bounce and ResponsiveAnalogRead objects.

    Not entirely relevant to this post, no piezos.

    Code:
    // I am sure there are more efficient ways to do some of the things here, but this is working fine for me
    // this code is written for Teensy 3.5
    // the pin numbers used here are how My circuit is wired. it will vary for your design
    // I have pullup resistors on every single button, so I do not need any delay while reading through the mux pins
    
    
    #include "Type4051Mux.h"    //calls a 4051 mux library
    #include "Type4067Mux.h"    //calls a 4067 mux library
    #include <ResponsiveAnalogRead.h> // include the ResponsiveAnalogRead library for analog smoothing
    #include <Bounce.h>   // include the Bounce library for 'de-bouncing' switches -- removing electrical chatter as contacts settle
    //usbMIDI.h library is added automatically when code is compiled as a MIDI device
    #include <MIDI.h>                //include the midi library as I am also using  5pin Dins for MIDI in and out,
    MIDI_CREATE_DEFAULT_INSTANCE();  // instantiate MIDI
    
    
    //***************** define 4051 Selector pins
    
    const int B4051_S[3] = {26,27,28};   // sets up 4053 S pins as an array
    
    //***************** DEFINE MUX 4051 INPUT PINS
    
    const int B4051_[8] = {29,30,31,32,33,34,35,36};   // sets up the digital pins used for the 8 4051s as an array
    
    // creates 8 global 8ch mux  objects
    // parameters: (input pin, type, digi/analog, s0, s1, s2)
    // Need one of these for each 4051 on the board (8 total). they all share s0, s1, s2
    
    Type4051Mux buttonMux_[8] = {Type4051Mux(B4051_[0], INPUT, DIGITAL, B4051_S[0], B4051_S[1], B4051_S[2]),     //sets up the 4051 mux's as an array
                                 Type4051Mux(B4051_[1], INPUT, DIGITAL, B4051_S[0], B4051_S[1], B4051_S[2]),
                                 Type4051Mux(B4051_[2], INPUT, DIGITAL, B4051_S[0], B4051_S[1], B4051_S[2]),
                                 Type4051Mux(B4051_[3], INPUT, DIGITAL, B4051_S[0], B4051_S[1], B4051_S[2]),
                                 Type4051Mux(B4051_[4], INPUT, DIGITAL, B4051_S[0], B4051_S[1], B4051_S[2]),
                                 Type4051Mux(B4051_[5], INPUT, DIGITAL, B4051_S[0], B4051_S[1], B4051_S[2]),
                                 Type4051Mux(B4051_[6], INPUT, DIGITAL, B4051_S[0], B4051_S[1], B4051_S[2]),
                                 Type4051Mux(B4051_[7], INPUT, DIGITAL, B4051_S[0], B4051_S[1], B4051_S[2])};
    
    // Create Bounce objects for each button.  The Bounce object
    // automatically deals with contact chatter or "bounce", and
    // it makes detecting changes very simple.   
    // We need a Bounce object for every single PIN of every single mux
    const int BOUNCE_TIME = 7;              // the bounce time. I have 4.7kohm pull-up resistors on each of my buttons, and so am not using INPUT_PULLUP
    const int D_PINS = 8;                   //the number of digital pins used on the teensy for the 8 4051 Muxs
    const int D_MUX_PINS = 8;               //the number of  pins on each 4051 
    
    //Declares and sets pointer to an 8x8 array of bounce objects --> set this up in setup()
    
    //**************this part is super important!******************//
    Bounce *buttons[D_PINS][D_MUX_PINS];                    //this totally works     
    
      
    int noteOnVelocity = 99;  //--edit this later via the input buttons and encoder
    
    //define 4067 Selector pins
    
    const int K4067_S[4] = {2, 3, 4, 5};
    
    //DEFINE 4067 INPUT pins
    
    const int K4067_[7] = {16, 17, 18, 19, 20, 21, 22};
    
    const int A_PINS = 7;                         //the number of digital pins used on the teensy for the 7 4067 Muxs
    const int A_MUX_PINS = 16;                    // number of Multiplexer Analog PINS
    
    //creates 7 global instances of the 4067 mux 36ch (input pin, type, digital/analog, s0, s3, s2, s3)
    //I will need one of these for each 4067 on the board (7 total)
    Type4067Mux knobMux_[A_PINS] = {Type4067Mux(K4067_[0], INPUT, ANALOG, K4067_S[0], K4067_S[1], K4067_S[2], K4067_S[3]),    
                                    Type4067Mux(K4067_[1], INPUT, ANALOG, K4067_S[0], K4067_S[1], K4067_S[2], K4067_S[3]),
                                    Type4067Mux(K4067_[2], INPUT, ANALOG, K4067_S[0], K4067_S[1], K4067_S[2], K4067_S[3]),
                                    Type4067Mux(K4067_[3], INPUT, ANALOG, K4067_S[0], K4067_S[1], K4067_S[2], K4067_S[3]),
                                    Type4067Mux(K4067_[4], INPUT, ANALOG, K4067_S[0], K4067_S[1], K4067_S[2], K4067_S[3]),
                                    Type4067Mux(K4067_[5], INPUT, ANALOG, K4067_S[0], K4067_S[1], K4067_S[2], K4067_S[3]),
                                    Type4067Mux(K4067_[6], INPUT, ANALOG, K4067_S[0], K4067_S[1], K4067_S[2], K4067_S[3])};
    
                           
    
    // This creates a pointer to a declared array of responsiveAnalogRead objects
    
    //******************this part is super important**************//
    ResponsiveAnalogRead *knobMux[A_PINS][A_MUX_PINS];               //holy shit this totally works
    
    
    
    // set sup midi I/O pin definitions
    #define MIDI_In   0       //rx0
    #define MIDI_Out  1       //tx0
    
    int noteMap[8][8] = {{36,37,38,39,40,41,42,43},           //this array will be useful later when using the interface encoder and buttons to assign cutom mappings
                         {44,45,46,47,48,49,50,51},
                         {52,53,54,55,56,57,58,59},
                         {60,61,62,63,64,65,66,67},
                         {68,69,70,71,72,73,74,75},
                         {76,77,78,79,80,81,82,83},
                         {84,85,86,87,88,89,90,91},
                         {92,93,94,95,96,97,98,99}};
    
    int buttonChannelMap[8][8] = {{1,1,1,1,1,1,1,1},         //this array will be useful later when using the interface encoder and buttons to assign cutom mappings
                                  {1,1,1,1,1,1,1,1},
                                  {1,1,1,1,1,1,1,1},
                                  {1,1,1,1,1,1,1,1},
                                  {1,1,1,1,1,1,1,1},
                                  {1,1,1,1,1,1,1,1},
                                  {1,1,1,1,1,1,1,1},
                                  {1,1,1,1,1,1,1,1}};
     
    int knobCcMap[7][16] = {{1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16},
                            {17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32},                      //this array will be useful later when using the interface encoder and buttons to assign cutom mappings
                            {33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48},
                            {49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64},
                            {65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80},
                            {81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96},
                            {97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112}};
    
    int knobChannelMap[7][16] = {{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},            //this array will be useful later when using the interface encoder and buttons to assign cutom mappings
                                 {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},
                                 {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},
                                 {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},
                                 {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},
                                 {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},
                                 {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}};
               
    // a data array and a lagged copy to tell when MIDI Knob changes are required
    byte data[A_PINS][A_MUX_PINS];
    
    byte dataLag[A_PINS][A_MUX_PINS];
    
    
    
    void setup() { 
      //setup all the pins. might be redundant for 4067, 4051,but whatevs
    //pins will vary based on YOUR design and wiring
      pinMode(MIDI_In, INPUT);
      pinMode(MIDI_Out, OUTPUT);
      
      pinMode(K4067_S[0], OUTPUT);
      pinMode(K4067_S[1], OUTPUT);
      pinMode(K4067_S[2], OUTPUT);
      pinMode(K4067_S[3], OUTPUT);
    
      pinMode(B4051_S[0], OUTPUT);
      pinMode(B4051_S[1], OUTPUT);
      pinMode(B4051_S[2], OUTPUT);
      
      pinMode(B4051_[0], INPUT);
      pinMode(B4051_[1], INPUT);
      pinMode(B4051_[2], INPUT);
      pinMode(B4051_[3], INPUT);
      pinMode(B4051_[4], INPUT);
      pinMode(B4051_[5], INPUT);
      pinMode(B4051_[6], INPUT);
      pinMode(B4051_[7], INPUT);
    
      pinMode(K4067_[0], INPUT);
      pinMode(K4067_[1], INPUT);
      pinMode(K4067_[2], INPUT);
      pinMode(K4067_[3], INPUT);
      pinMode(K4067_[4], INPUT);
      pinMode(K4067_[5], INPUT);
      pinMode(K4067_[6], INPUT);
      
      pinMode(23, OUTPUT);    // this pin is not used in the controller and is free for scoping slash debugging
    
    
      //this sets up the analog responsive read object array
    //******************this part is super important**************//
    // it populates the RAR array with the correct stuff
      for (int j = 0; j < A_PINS; j++){
        for (int i = 0; i < A_MUX_PINS; i++){
          knobMux[j][i] = new ResponsiveAnalogRead(K4067_[j], true); // initialize
        }
      }
    
    
      //this sets up the buttons bounce object array
    //******************this part is super important**************//
    // it populates the Bounce array with the correct stuff
      for(int j = 0; j < D_PINS; j++){
        for (int i = 0; i < D_MUX_PINS; i++){
          buttons[j][i] = new Bounce(B4051_[j], BOUNCE_TIME);
        }
      }
    
      //start an instance of MIDI I/O
      MIDI.begin();
    
      //starts serial monitor, use for debug, 
      //Serial.begin(115200);    
      //higher speed than 31250 (MIDI), 57600 will also work
      
    }
    
    
    void loop(){
    
      //******************** call the readKnobs() function***************//
      digitalWrite(23, HIGH);         //this pin is for debugging with a scope to test timing
      readKnobs();
    
      //******************** call the readButtons() function***************//
      digitalWrite(23, LOW);          //this pin is for debugging with a scope to test timing
      readButtons();  
    
      // MIDI Controllers should discard incoming MIDI messages.
      // http://forum.pjrc.com/threads/24179-Teensy-3-Ableton-Analog-CC-causes-midi-crash
      while (usbMIDI.read()) {
        // ignore incoming messages
      }
    }
    
    
    
                          
    void readKnobs(){
      //************this section reads the knob values through the 4067*****************//
      //************reads and smooths knob input****************//
       for(int j = 0; j < A_PINS; j++){ 
        for (int i= 0; i < A_MUX_PINS; i++){
          knobMux_[j].setChannel(i);                       //THIS Totally WORKS
          knobMux[j][i]->update();
          if(knobMux[j][i]->hasChanged()){
            data[j][i] = knobMux[j][i]->getValue()>>3;
            if (data[j][i] != dataLag[j][i]){
              dataLag[j][i] = data[j][i];
              usbMIDI.sendControlChange(knobCcMap[j][i], data[j][i], knobChannelMap[j][i]);
              //MIDI.sendControlChange(knobCcMap[j][i], data[j][i], knobChannelMap[j][i]);
            }
          }
         }
       } 
      // ****************************ends loop for reading knobs **************// 
    }
    
    
    void readButtons(){
        for(int j = 0; j < D_PINS; j++){
          for(int i = 0; i < D_MUX_PINS; i++){
            buttonMux_[j].setChannel(i);
            buttons[j][i]->update();
            if (buttons[j][i]->fallingEdge()) {
              usbMIDI.sendNoteOn(noteMap[j][i], noteOnVelocity, buttonChannelMap[j][i]);   //************IT WORKS!!************//
              //MIDI.sendNoteOn(noteMap[j][i], noteOnVelocity, buttonChannelMap[j][i]);    // Send a Note (pitch , velo , on channel)
            } 
            if (buttons[j][i]->risingEdge()) {
              usbMIDI.sendNoteOff(noteMap[j][i], 0, buttonChannelMap[j][i]); 
             // MIDI.sendNoteOff(noteMap[j][i], 0, buttonChannelMap[j][i]);
            }
          }
        }
    }

Posting Permissions

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