Cd4067 y botones

Buenas a todos
Llevo un par de semanas trasteando con Arduino y los controladores midi , tenia un proyecto casi terminado , programado de 0 por mi , pero a ultima hora e decidido hacer una modificación y añadir 4 botones mas..¿el problema? Hay que añadir un multiplexor y lo único que encuentro son librerías y copiar y pegar el código , lo que hace que funcione , pero no entiendo lo que estoy haciendo y mi objetivo con esto es aprender , no tener el controlador funcionando lo antes posible
Mis únicos avances en el campo de los multiplexers a sido , leer los valores que arroja , pero no tengo ni idea de como manejarlos como en el ejemplo del codigo en el que el valor "Pinbotones" es un const int que hace referencia a las entradas digitales de Arduino , en este caso "2 , 3 y 4"
Este ejemplo es algo sintetizado de mi código , ya que esta programado con 12 botones , 5 encoders y otros botones para manejar el DAW
Entonces ¿como puedo hacer un código parecido a este metiendo las entradas del multiplexor?¿o soy yo que estoy tan verde que no lo entiendo y lo estoy enfocando de la manera equivocada?
Un saludo
Pd:Adjunto un esquema de como seria con el multiplexer y el código de ejemplo que tengo ahora con las funciones que me interesan


Procesando: 4067.jpg...

#include <MIDI.h>
 
 
const int Nbotones = 3;
const int PinBotones[Nbotones] = {2, 3, 4};
 
int vb[Nbotones] = {0};
int pvb[Nbotones] = {0};
 
unsigned long lastdebouncetime[Nbotones] = {0};
unsigned long debouncedelay = 20;
 
 
 //31500 MIDI 115200 HAIRLESS
 
void setup()
{
  Serial.begin(31500);
  for (int i = 0; i<Nbotones; i++) {
    pinMode(PinBotones[i] , INPUT_PULLUP);
  }
 
}
 
void loop()
{
  for (int i = 0; i<Nbotones; i++) {
 
    vb[i] = digitalRead(PinBotones[i]);
 
 
    if ((millis() - lastdebouncetime[i]) > debouncedelay)
    {
 
      if (pvb[i] != vb[i])
      {
 
 
        lastdebouncetime[i] = millis();
 
 
        if (vb[i] == LOW)
        {
          MIDI.sendNoteOn(36+i , 127 ,1);
        }
 
        else {
          MIDI.sendNoteOff(36+i , 127 ,1);
        }
        
      }
    pvb[i] = vb[i];
    }
    }
}```

Un multimplexor es una llave digital que pone en contactor en tu caso un boton con una entrada del Arduino. Para ello debe seleccionar que quiere leer.
La selección se hace con 4 salidas escribiendo valores que van e 0000 a 1111 o sea 16 posibles selecciones.
Escribes que conexión leerás y la lees porque ese boton queda conectado via el multiplexor a tu entrada del Arduino. Lo demas es como leer un pulsador.
O sea es leer un pulsador seleccionado cual entrada del multiplexor vas a usar.
Viendo tu codigo no me queda claro que lo hagas bien.
En el setup solo veo que lees 3 botones y me pregunto para qué? Solo debes leer uno y debes elegir cual leer para lo cual hay que seleccionar 4 salidas digitales como OUTPUT. Y eso no lo veo.
NO se que multiplexor es pero luce como un74HC4067

Veo que tiene una salida SO que tu has conectado al pin 2 aparentemente. Digo esto porque el esquema de Frizzing es de pobre resolucion. No me gusta el Fritzing salvo para los PCB que los hace bastante bien.
En tu código tienes 2,3,4 como supuestas entradas pull-up. Deberían ser 3,4,5,6 salidas digitales y 2 una entrada pull-up si es el caso.

Lo primero muchas gracias por responder
El código es lo que tengo ahora sin el multiplexor , que efectivamente , es un 4067
Entiendo lo de los valores , seria algo así no?

0 0 0 0 0 Canal 0
1 0 0 0 0 Canal 1
0 1 0 0 0 Canal 2
1 1 0 0 0 Canal 3
0 0 1 0 0 4. Canal 4...etc

Pero ¿como lo integro en el código? , solo veo ejemplos de librerías preparadas para hacer superficies de control midi y me lio todavía mas

Entiendo que entonces S0 , S1 , S2 y S3 trabajan como salidas , y SIG trabaja como entrada en Arduino (entrada digital por ser botones) , algo así:

const int muxS0 = 2;
const int muxS1 = 3;
const int muxS2 = 4;
const int muxS3 = 5;
const int muxSig = 8;


int valormplex = 0;

void setup() {
Serial.begin(9600);
pinMode(muxS0 , OUTPUT);
pinMode(muxS1 , OUTPUT);
pinMode(muxS2 , OUTPUT);
pinMode(muxS3 , OUTPUT);
pinMode(muxSig , INPUT_PULLUP);

}

void loop() {

valormplex = digitalRead(muxSig);
Serial.println(valormplex);
}

Pero no se como integrar aquí los valores del multiplexor(con el código de este post solo detecto la pulsación del botón que hay en el canal 1) para ya programarlos como un pulsador normal como en mi primer post
Mil gracias Surbyte

No.
Son 4 lineas de control o sea 0000 a 1111 totalizando 2^4 =16 contorles
No 5 como has puesto
Si lees en 2, entonces actua en 3,4,5 y 6 como salidas.
S0 , S1 , S2 y S3 trabajan como el direccionador del 4067.
Si le pones
s0 s1 s2 s3
0 0 0 0 la entrada 0
1 0 0 0 la entrada 1
0 1 0 0 la entrada 2
1 1 0 0 la entrada 3
todo en binario. Si no sabes binario busca código binario.
Solo admite 0 y 1. Cuando se llena con 1 desborda el siguiente.
Tal vez los haya puesto al reves, debes verificar la hoja de datos del 4067

Para situarme porque te aseguro que no veo tu esquema Fritzing

El direccionamiento ya lo expliqué y veo que esta bien.
La lectura esta conectada al pin 8, de modo que tmb luce como que has comprendido.

Voy a tomar una idea de Prometec

Para no complicarse la vida seria interesante usar un int (en este caso k que va de 0 a 15) que represente el número de puerta que queremos seleccionar, pero eso significa que tenemos que tomar los bits de ese número y escribirlos en los S0, S1, S2, S3.

Para ello la idea es tomar el último bit de esa variable k, y podemos hacerlo así:

S0 = k & B00000001;  digitalWrite ( 8 , S0); //Solo quiero el ultimo bit

muxS0 = k & B00000001; digitalWrite ( muxS0 , S0); // Solo quiero el ultimo bit
Tomamos el numero k y le hacemos un and con el binario 1, de modo que solo se mantiene el ultimo bit en 1 o 0 y lo escribimos en S0, que es el bit de menos peso.

muxS1 = ( k >> 1 ) & B00000001 ; digitalWrite ( muxS1 , S1) ;
muxS2 = ( k >> 1 ) & B00000001 ; digitalWrite (muxS2 , S2) ;
muxS3 = ( k >> 1 ) & B00000001 ; digitalWrite (muxS3 , S3) ;

Te quedaría de este modo la seleccion de puerta o canal del multiplexor

for (int k= 0 ; k<16 ; k++) {  // Selecciona la puerta a leer
      muxS0 = k & B00000001;  digitalWrite (muxS0 , S0); // Solo quiero el ultimo bit
      muxS1 = ( k >> 1 ) & B00000001 ; digitalWrite ( muxS1 , S1) ;
      muxS2 = ( k >> 1 ) & B00000001 ; digitalWrite (muxS2 , S2) ;
      muxS3 = ( k >> 1 ) & B00000001 ; digitalWrite (muxS3 , S3) ;
      Serial.print (k); Serial.print(‘\t’) ;
      Serial.println(analogRead(A1)) ;
      valormplex = digitalRead(muxSig);
      Serial.println("Estado pulsador["+String(k)+"] =" + String(valormplex));
}

Gracias de nuevo Surbyte , de verdad que me estoy esforzando por entenderlo , no se si es que me viene grande , pero ya que estoy aquí me gustaría terminarlo
Tengo esto , en el monitor serie lee en orden todos los pines , pero solo lee el primer botón y cambia el estado de todos

unsigned int S0, S1, S2, S3, k, p ; 

int muxS0 = 2;
int muxS1 = 3;
int muxS2 = 4;
int muxS3 = 5;
int valormplex = 0;
int muxSig = 8;


void setup() {
Serial.begin(9600);
        for (int i = 2 ; i < 8 ; i++)
             pinMode(i , OUTPUT);
             
pinMode(muxSig , INPUT_PULLUP);
}

void loop() {

for (int k= 0 ; k<16 ; k++) {  // Selecciona la puerta a leer
      muxS0 = ( k >> 1 ) & B00000001;  digitalWrite (muxS0 , S0); // Solo quiero el ultimo bit
      muxS1 = ( k >> 1 ) & B00000001 ; digitalWrite (muxS1 , S1) ;
      muxS2 = ( k >> 1 ) & B00000001 ; digitalWrite (muxS2 , S2) ;
      muxS3 = ( k >> 1 ) & B00000001 ; digitalWrite (muxS3 , S3) ;
      Serial.print (k); Serial.print("\t") ;
      Serial.println(analogRead(A1)) ;
      valormplex = digitalRead(muxSig);
      Serial.println("Estado pulsador["+String(k)+"] =" + String(valormplex));
}
}

Acabo de obtener un gran avance , de esta forma lo e entendido mejor , esta programado con dos botones para probar si funcionan todas las entradas , y va perfecto , esta noche me pongo a terminar el código y lo subo a ver que os parece

const int muxSIG = A5;
const int muxS0 = 3;
const int muxS1 = 4;
const int muxS2 = 5;
const int muxS3 = 6;

int mux1 = 0;
int vpmux1 = 0;
int mux2 = 0;
int vpmux2 = 0;

int SetMuxChannel(byte channel)
{
  digitalWrite(muxS0, bitRead(channel, 0));
  digitalWrite(muxS1, bitRead(channel, 1));
  digitalWrite(muxS2, bitRead(channel, 2));
  digitalWrite(muxS3, bitRead(channel, 3));
}


void setup()
{
  pinMode(muxSIG, INPUT_PULLUP);
  pinMode(muxS0, OUTPUT);
  pinMode(muxS1, OUTPUT);
  pinMode(muxS2, OUTPUT);
  pinMode(muxS3, OUTPUT); 
  
  Serial.begin(9600);
}

void loop()
{
    
     SetMuxChannel(1);
   
     mux1 = digitalRead(muxSIG);
      if(vpmux1 != mux1){
      
      if(mux1 == LOW){
        Serial.println("boton1 ON");
      }
      else{
        Serial.println("boton1 OFF");
        }
      vpmux1 = mux1;
      }

        SetMuxChannel(2);
    mux2 = digitalRead(muxSIG);
      if(vpmux2 != mux2){
      
      if(mux2 == LOW){
        Serial.println("boton2 ON");
      }
      else{
        Serial.println("boton2 OFF");
        }
      vpmux2 = mux2;
      }
   

La idea es meter los 16 botones como en el código anterior en un bucle for , para no tener 500 lineas de codigo ya hoy no me da tiempo a seguir pero mas o menos esta es la idea

void loop()
{
  for (int i = 0; i <= 16; i++) {
    SetMuxChannel(i) = digitalRead(muxSIG);
    if ((millis() - lastdebouncetime[i]) > debouncedelay)
    {
      if (vpmux[i] != mux[i])
      {

        if (mux[i] == LOW)
        {
          Serial.println("boton[i] ON");
        }
        else {
          Serial.println("boton[i] OFF");
        }
        vpmux[i] = mux[i];
      }
    }
  }
}

Obviamente no funciona :expressionless:
mañana le seguire dando vueltas , supongo que cuando sabes es algo obvio que se hace en 5 minutos

Fijate así

void loop()
{
  for (int i = 0; i <= 16; i++) {
    SetMuxChannel(i);
    mux[i] = digitalRead(muxSIG);
    if ((millis() - lastdebouncetime[i]) > debouncedelay)
    {
      if (vpmux[i] != mux[i])
      {

        if (mux[i] == LOW)
        {
          Serial.println("boton[i] ON");
        }
        else {
          Serial.println("boton[i] OFF");
        }
        vpmux[i] = mux[i];
      }
    }
  }
}

El error estaba en

SetMuxChannel(i) = digitalRead(muxSIG);

Y tambien, tienes que corregir la definición de SetMuxChannel(), no devuelve ningún resultado, entonces tiene que ser void

void SetMuxChannel(byte channel)

Saludos

Mil gracias gatul , no lo había planteado tan mal entonces :sweat_smile:
Luego cuando llegue a casa modifico el código y os cuento
Un saludo

vale , copiando y pegando el código y cambiando el int por un void , me da este error (nvalid types 'int[int]' for array subscript) , creo que debería modificar los:

int mux = 0
int vpmux = 0

por

int mux[     ] = {0}
int vpmux[     ] = {0}

pero así no responde nada , lo compila sin errores pero no recibo nada por el monitor serial , e probado a crear un const int entradasmux = 16; , para meterlo entre los corchetes como hice en otro proyecto , y funciona pero...

cuando pulso el botón 0 , el monitor serie me devuelve un 0 ON 1 OFF , en vez de 0 ON 0 OFF y lo lee en bucle hasta que suelto el botón

monitor serial

llevo unas 3 horas y es lo mas lejos que e llegado

A ver como va esto, usando parte de lo que tu usas, tu SetMuxChannel(byte chanel) y lo demas

const int muxSIG  = A5;
const int muxS0   = 3;
const int muxS1   = 4;
const int muxS2   = 5;
const int muxS3   = 6;

int mux1    = 0;
int vpmux1  = 0;
int mux2    = 0;
int vpmux2  = 0;

int SetMuxChannel(byte channel) {
  digitalWrite(muxS0, bitRead(channel, 0));
  digitalWrite(muxS1, bitRead(channel, 1));
  digitalWrite(muxS2, bitRead(channel, 2));
  digitalWrite(muxS3, bitRead(channel, 3));
}


void setup() {
  pinMode(muxSIG, INPUT_PULLUP);
  pinMode(muxS0, OUTPUT);
  pinMode(muxS1, OUTPUT);
  pinMode(muxS2, OUTPUT);
  pinMode(muxS3, OUTPUT);

  Serial.begin(9600);
}

void loop() {
  for (int k= 0 ; k<16 ; k++) {  // Selecciona la puerta a leer
      SetMuxChannel(k);
      // agrega el debounce pero por lo que vi esta mal hecho y no funciona
      Serial.println("Boton["+String(k)+"] =" + analogRead(muxSIG)?"OFF":"ON");
  }
}

utilizando ese código el monitor serie solo me devuelve un "OFF" agregue o no el debounce , voy a subir el código completo que tengo

EDITO
Acabo de dar con la tecla y no se muy bien como , porque estaba convencido de haber hecho esto como puse en el post anterior porque me parecía lo mas lógico y no entendía porque no funcionaba , e vuelto a probar y debe ser que algo no había hecho bien
Ahora mismo , reconoce todos los canales del mux y manda correctamente las funciones ON/OFF

#include <MIDI.h>
const int muxSIG = A5;
const int muxS0 = 3;
const int muxS1 = 4;
const int muxS2 = 5;
const int muxS3 = 6;

const int entradasmplex = 16;
int mux[entradasmplex] = {0};
int vpmux[entradasmplex] = {0};


unsigned long lastdebouncetime[entradasmplex] = {0};
unsigned long debouncedelay = 20;


void SetMuxChannel(byte channel)
{
  digitalWrite(muxS0, bitRead(channel, 0));
  digitalWrite(muxS1, bitRead(channel, 1));
  digitalWrite(muxS2, bitRead(channel, 2));
  digitalWrite(muxS3, bitRead(channel, 3));
}


void setup()
{
  pinMode(muxSIG, INPUT_PULLUP);
  pinMode(muxS0, OUTPUT);
  pinMode(muxS1, OUTPUT);
  pinMode(muxS2, OUTPUT);
  pinMode(muxS3, OUTPUT);

  Serial.begin(9600);
}

  void loop()
{
  for (int i = 0; i <= 15; i++) {
    
    SetMuxChannel(i);
    
    mux[i] = digitalRead(muxSIG);
    if ((millis() - lastdebouncetime[i]) > debouncedelay)
    {
      if (vpmux[i] != mux[i])
      {
      lastdebouncetime[i] = millis();

        if (mux[i] == LOW)
        {
         //MIDI.sendNoteOn(36 + i , 127 , 1);
          Serial.print(i);
          Serial.println("....ON");
        }
        else {
          //MIDI.sendNoteOff(36 + i , 127 , 1);
           Serial.print(i);
           Serial.println(" .   OFF");

        }
        vpmux[i] = mux[i];

      }
    }
  }
}

Te repito, esto no funciona porque nunca jamás ledices a

lastdebouncetime[i]) = millis();

para que efectivamente tengas un debounce de 20 mseg.
Al final debes ponerlo dentro de tu condición debounce

Cierto , venia a corregir el código , pensaba que ya lo había subido con el debounce , dejo el código editado mas arriba , revisado por si a alguien le sirve

Es importante que sigas las reglas, si alguien te dice que no se esta actualizando algo y tu vas y editas el código anterior, mi comentario o nuestros comentarios quedan fuera de lugar. No lo hagas!!