Se connecter
Se connecter

ou
Créer un compte

ou
Agrandir
Les Mains dans le Cambouis
Bidouille & Développement Informatique

Sujet DIY Réalisation d'un Sugarcube MIDI Controller

  • 3 réponses
  • 2 participants
  • 431 vues
  • 5 followers
Sujet de la discussion DIY Réalisation d'un Sugarcube MIDI Controller
Bonjour a tous

J'essaye de réaliser un stepsequencer à base de matrice de led/button Sparkfun
https://www.sparkfun.com/products/7835

bidouille-developpement-informatique-2783068.jpg

Pour ce fait je me base sur la création d'un Sugarcube Afin premièrement d'apprendre le fonctionnement des registre à décalage et deuxièmement d'avoir une base de programme sur laquelle je peux m'appuyer
https://www.instructables.com/id/Multiplexing-with-Arduino-and-the-74HC595/
https://www.instructables.com/id/Sugarcube-MIDI-Controller/

Le montage est effectué et j'ai pu effectuer les programmes test
Un exemple ici

//BUTTON TEST w/ 74HC595 and 74HC165
//by Amanda Ghassaei 2012

//pin connections
int ledLatchPin = 6;
int ledClockPin = 5;
int ledDataPin = 7;
int buttonLatchPin = 4;
int buttonClockPin = 3;
int buttonDataPin = 2;

//looping variables
byte i;
byte j;
byte k;

//storage for led states, 4 bytes
byte ledData[] = {0, 0, 0, 0};
//storage for buttons, 4 bytes
byte buttonCurrent[] = {0,0,0,0};
byte buttonLast[] = {0,0,0,0};
byte buttonEvent[] = {0,0,0,0};
byte buttonState[] = {0,0,0,0};
//button debounce counter- 16 bytes
byte buttonDebounceCounter[4][4];


void setup() {
  DDRD = 0xFA;//set pins D7-D4 as output, D2 as input
}

// buttonCheck - checks the state of a given button.
//this buttoncheck function is largely copied from the monome 40h firmware by brian crabtree and joe lake
void buttonCheck(byte row, byte index)
{
  if (((buttonCurrent[row] ^ buttonLast[row]) & (1 << index)) &&   // if the current physical button state is different from the
  ((buttonCurrent[row] ^ buttonState[row]) & (1 << index))) {  // last physical button state AND the current debounced state

    if (buttonCurrent[row] & (1 << index)) {                      // if the current physical button state is depressed
      buttonEvent[row] = 1 << index;              // queue up a new button event immediately
      buttonState[row] |= (1 << index);                         // and set the debounced state to down.
  }
    else{
      buttonDebounceCounter[row][index] = 12;
    }  // otherwise the button was previously depressed and now
    // has been released so we set our debounce counter.
  }
  else if (((buttonCurrent[row] ^ buttonLast[row]) & (1 << index)) == 0 &&  // if the current physical button state is the same as
  (buttonCurrent[row] ^ buttonState[row]) & (1 << index)) {        // the last physical button state but the current physical
    // button state is different from the current debounce 
    // state...
    if (buttonDebounceCounter[row][index] > 0 && --buttonDebounceCounter[row][index] == 0) {  // if the the debounce counter has
      // been decremented to 0 (meaning the
      // the button has been up for 
      // kButtonUpDefaultDebounceCount 
      // iterations///

      buttonEvent[row] = 1 << index;    // queue up a button state change event

      if (buttonCurrent[row] & (1 << index)){          // and toggle the buttons debounce state.
        buttonState[row] |= (1 << index);
      }
      else{
        buttonState[row] &= ~(1 << index);
      }
    }
  }
}


void shift(){
  
  for (i=0;i<4;i++){
    
    buttonLast[i] = buttonCurrent[i];
    
    byte dataToSend = (1 << (i+4)) | (15 & ~ledData[i]);
      
    // set latch pin low so the LEDs don't change while sending in bits
    digitalWrite(ledLatchPin, LOW);
    // shift out the bits of dataToSend
    shiftOut(ledDataPin, ledClockPin, LSBFIRST, dataToSend);  
    //set latch pin high so the LEDs will receive new data
    digitalWrite(ledLatchPin, HIGH);
      
    //once one row has been set high, receive data from buttons
    //set latch pin high
    digitalWrite(buttonLatchPin, HIGH);
    //shift in data
    buttonCurrent[i] = shiftIn(buttonDataPin, buttonClockPin, LSBFIRST) >> 3;
    //latchpin low
    digitalWrite(buttonLatchPin, LOW);
    
    for (k=0;k<4;k++){
      buttonCheck(i,k);
    }
  }
}

void updateLEDs(){ //update the leds to reflect hte state of the buttons
  for (j=0;j<4;j++){
    ledData[j] = buttonState[j];
  }
}

void loop() {
  shift();
  updateLEDs();
}


avec ce programme j'ai 1 button = 1 led = 1 note Midi bref un clavier midi 16 note
C'est après que sa se gâte si je puis dire

Le programme complet compile
Le problème est que lorsque j'upload son programme complet c'est a dire son programme final il n'y a rien qui se passe
La programmatrice se sert d'un programme principal qui appelle plusieurs librairies
il n'y a pas de boucle principale ni de fonction delay car un timer est généré d’après ce que j'ai pu comprendre

J'ai checké toutes les soudures et les éventuelles faux contact ainsi que le schéma de câblage

Son programme est il erroné pour la version actuel de l’Arduino ? car le projet n'est pas récent

bidouille-developpement-informatique-2783084.jpg
bidouille-developpement-informatique-2783085.jpg
bidouille-developpement-informatique-2783086.jpg






[ Dernière édition du message le 02/11/2019 à 20:46:34 ]

2
Citation :
il n'y a pas de boucle principale


Or, tu as bien :

void loop() {
  shift();
  updateLEDs();
}


Ou alors, je ne comprends pas ce que tu veux dire.

Formateur en techniques sonores ; électronicien ; auteur @ sonelec-musique.com

[ Dernière édition du message le 31/10/2019 à 10:48:17 ]

3
Citation :
Or, tu as bien :
void loop() {
shift();
updateLEDs();
}


oui pour le programme de test des notes Midi

Pour le programme principal ;
https://github.com/amandaghassaei/Sugarcube-Arduino-Library

 #include "SugarCube.h"
  
  SugarCube sugarcube;

  void setup()
  {
//    default pin connections are given below:
//    Analog
//    0 - Gyroscope Y (Y4.5)
//    1 - Potentiometer 1
//    2 - Gyroscope X (X4.5)
//    3 - Accelerometer Y (YAcc)
//    4 - Accelerometer X (XAcc)
//    5 - Potentiometer 2
//    Digital
//    0 - serial in - this much remain unconnected
//    1 - serial out - this is hooked up to the MIDI output
//    2 - 74HC165 data pin (Q7)
//    3 - 74HC165 clock pin (CP)
//    4 - 74HC165 latch pin (PL)
//    5 - 74HC595 clock pin (SH_CP)
//    6 - 74HC595 latch pin (ST_CP)
//    7 - 74HC595 data pin (DS)
//    
//    set custom pin connections using the following commands, this must happen before sugarcube.init()
//    leave digital pins 0 and 1 (RX/TX Serial pins) empty
sugarcube.setLedLatchPin(6);
 sugarcube.setLedClockPin(5);
 sugarcube.setLedDataPin(7);
  sugarcube.setButtonLatchPin(4);
  sugarcube.setButtonClockPin(3);
 sugarcube.setButtonDataPin(2);
//  sugarcube.setXAccPin(A4);
//    sugarcube.setYAccPin(A3);
 sugarcube.setPot1Pin(A1);
  sugarcube.setPot2Pin(A5);
//    sugarcube.setXGyroPin(A2);
//    sugarcube.setYGyroPin(A0);
    
    byte patchNum = sugarcube.init();
    switch(patchNum) {
      case 0:
        {
          StepSequencer stepSequencer;
          sugarcube.setDelegate(&stepSequencer);
          for (;[img alt=";)"]https://static.audiofanzine.com/images/audiofanzine/interface/smileys/icon_wink.gif[/img] {}
        }
      case 1:
        {
          Flin flin;
          sugarcube.setDelegate(&flin);
          for (;[img alt=";)"]https://static.audiofanzine.com/images/audiofanzine/interface/smileys/icon_wink.gif[/img] {}
        }
      case 2:
        {
          Boiing boiing;
          sugarcube.setDelegate(&boiing);
          for (;[img alt=";)"]https://static.audiofanzine.com/images/audiofanzine/interface/smileys/icon_wink.gif[/img] {}
        }
      case 3:
        {
          Arp arp;
          sugarcube.setDelegate(&arp);
          for (;[img alt=";)"]https://static.audiofanzine.com/images/audiofanzine/interface/smileys/icon_wink.gif[/img] {}
        }
      case 4:
        {
          SimpleMIDIKeyboard simpleMIDIKeyboard;
          sugarcube.setDelegate(&simpleMIDIKeyboard);
          for (;[img alt=";)"]https://static.audiofanzine.com/images/audiofanzine/interface/smileys/icon_wink.gif[/img] {}
        }
      case 5:
        {
          PixelTilt pixelTilt;
          sugarcube.setDelegate(&pixelTilt);
          for (;[img alt=";)"]https://static.audiofanzine.com/images/audiofanzine/interface/smileys/icon_wink.gif[/img] {}
        }
      case 6:
      case 7:
      case 8:
      case 9:
      case 10:
      case 11:
      case 12:
      case 13:
      case 14:
      case 15:
        {
        SerialComm serialComm;
        sugarcube.setDelegate(&serialComm);
        for (;[img alt=";)"]https://static.audiofanzine.com/images/audiofanzine/interface/smileys/icon_wink.gif[/img] {}
        }
      break;
    }
  }
  
  void loop()
  {

  }
  
  //---------------------------------------------------------------------
  //--------------------INTERRUPT ROUTINES-------------------------------
  //---------------------------------------------------------------------
  
  ISR(TIMER1_COMPA_vect)
  {//time 1 interrupt, at freq of 1kHz
      sugarcube.timer1Routine();
  }

  ISR(TIMER2_COMPA_vect) 
  {//timer 2 interupt, every 128us
      sugarcube.timer2Routine();
  } 


bidouille-developpement-informatique-2783191.png

4
J'ai également pu tester ce programme qui intègre un timer et il fonctionne
C'est une fonction midi qui se trouve dans le Sugarcube
Une sorte de lecture de note va et vient sur chaque ligne et modifiable via un accéléromètre
Cela veut dire que mon montage est bon et que le programme principale sur Sugarcube ne marche pas c'est comme si je chargeais un programme vide.
Si Il y a quelque qui gère la programmation orienté objet afin de trouver une explication de se qui va pas de le code?



//accelerometer test- bounce
//by Amanda Ghassaei 2012
//[url]https://www.instructables.com/id/Send-and-Receive-MIDI-with-Arduino/[/url]

/*
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
*/

//pin connections
//#define ledLatchPin 6
//#define ledClockPin 5
//#define ledDataPin 7
//#define buttonLatchPin 4
//#define buttonClockPin 3
//#define buttonDataPin 2

//setup varibles for Gyroscope/Accelerometer
int xGyroRAW;
int yGyroRAW;
int xAccRAW;
int yAccRAW;
int zAccRAW;

byte xGyro;
byte yGyro;
byte xAcc;
byte yAcc;
byte zAcc;

//looping variables
byte i;
byte j;
byte k;

//storage for led states, 4 bytes
byte ledData[] = {0, 0, 0, 0};
//storage for buttons, 4 bytes
byte buttonCurrent[] = {0,0,0,0};
byte buttonLast[] = {0,0,0,0};
byte buttonEvent[] = {0,0,0,0};
byte buttonState[] = {0,0,0,0};
//button debounce counter- 16 bytes
byte buttonDebounceCounter[4][4];

//variables for accelerometer pixel movement
boolean firstPress[] = {0, 0, 0, 0};
byte movingPixel[] = {0, 0, 0, 0};
byte xPosition[4];
int timeX[] = {0, 0, 0, 0};
boolean dirX;
boolean dirY;
boolean prevDirX = 0;
boolean bounceDirection[]= {0, 0, 0, 0};
boolean toggle[] = {1, 1, 1, 1};
byte peakHeight[4];
byte lastX = 4;
byte lastY = 4;

//MIDI variables
int velocity = 100;
int noteON = 144;
int MIDIoffset = 60;
byte currentX;
byte note[] = {60, 64, 67, 72};


void setup() {
  
  DDRD = 0xFA;//set pins D7-D4 as output, D2 as input
  
  Serial.begin(31250);//MIDI baud rate 
  
  cli();//stop interrupts

  //set timer1 interrupt at 1kHz
  TCCR1A = 0;// set entire TCCR1A register to 0
  TCCR1B = 0;// same for TCCR1B
  TCNT1  = 0;//initialize counter value to 0;
  // set timer count for 1khz increments
  OCR1A = 1999;// = (16*10^6) / (1000*8) - 1
  // turn on CTC mode
  TCCR1B |= (1 << WGM12);
  // Set CS11 bit for 8 prescaler
  TCCR1B |= (1 << CS11);   
  // enable timer compare interrupt
  TIMSK1 |= (1 << OCIE1A);
  
  sei();//allow interrupts
  
}

ISR(TIMER1_COMPA_vect) {//Interrupt at freq of 1kHz
  for (byte a=0;a<4;a++){
    timeX[a]++;//increment each element of timeX
  }
  shift();
}

// buttonCheck - checks the state of a given button.
//this buttoncheck function is largely copied from the monome 40h firmware by brian crabtree and joe lake
void buttonCheck(byte row, byte index)
{
  if (((buttonCurrent[row] ^ buttonLast[row]) & (1 << index)) &&   // if the current physical button state is different from the
  ((buttonCurrent[row] ^ buttonState[row]) & (1 << index))) {  // last physical button state AND the current debounced state

    if (buttonCurrent[row] & (1 << index)) {                      // if the current physical button state is depressed
      buttonEvent[row] = 1 << index;              // queue up a new button event immediately
      buttonState[row] |= (1 << index);                         // and set the debounced state to down.
  }
    else{
      buttonDebounceCounter[row][index] = 12;
    }  // otherwise the button was previously depressed and now
    // has been released so we set our debounce counter.
  }
  else if (((buttonCurrent[row] ^ buttonLast[row]) & (1 << index)) == 0 &&  // if the current physical button state is the same as
  (buttonCurrent[row] ^ buttonState[row]) & (1 << index)) {        // the last physical button state but the current physical
    // button state is different from the current debounce 
    // state...
    if (buttonDebounceCounter[row][index] > 0 && --buttonDebounceCounter[row][index] == 0) {  // if the the debounce counter has
      // been decremented to 0 (meaning the
      // the button has been up for 
      // kButtonUpDefaultDebounceCount 
      // iterations///

      buttonEvent[row] = 1 << index;    // queue up a button state change event

      if (buttonCurrent[row] & (1 << index)){          // and toggle the buttons debounce state.
        buttonState[row] |= (1 << index);
      }
      else{
        buttonState[row] &= ~(1 << index);
      }
    }
  }
}


void shift(){
  
  for (i=0;i<4;i++){
    
    buttonLast[i] = buttonCurrent[i];
    
    byte dataToSend = (1 << (i+4)) | (15 & ~ledData[i]);
      
    // set latch pin low so the LEDs don't change while sending in bits
    PORTD&=B10111111;//digitalWrite(ledLatchPin, LOW);
    // shift out the bits of dataToSend 
    //shiftOut(ledDataPin, ledClockPin, LSBFIRST, dataToSend);  
    for (j=0;j<8;j++){
      PORTD&=B11011111;//digitalWrite(ledClockPin,LOW);
      //digitalWrite(ledDataPin,((dataToSend>>j)&1));
      if ((dataToSend>>j)&1){
        PORTD|=B10000000;
      }
      else{
        PORTD&=B01111111;
      }
      PORTD|=B00100000;//digitalWrite(ledClockPin,HIGH);
    }
    //set latch pin high so the LEDs will receive new data
    PORTD|=B01000000;//digitalWrite(ledLatchPin, HIGH);
    
    // SlowDown is put in here to waste a little time while we wait for the state of the output
    // pins to settle.  Without this time wasting loop, a single button press would show up as
    // two presses (the button and its neighbour)
    volatile int SlowDown = 0; 

    while (SlowDown < 15) 
    { 
      SlowDown++; 
    } 
      
    //once one row has been set high, receive data from buttons
    //set latch pin high
    PORTD|=B00010000;//digitalWrite(buttonLatchPin, HIGH);
    //shift in data
    //buttonCurrent[i] = shiftIn(buttonDataPin, buttonClockPin, LSBFIRST) >> 3;
    for (j=0;j<4;j++){
      PORTD&=B11110111;//digitalWrite(buttonClockPin,LOW);
      PORTD|=B00001000;//digitalWrite(buttonClockPin,HIGH);
    }
    for (j=0;j<4;j++){
      PORTD&=B11110111;//digitalWrite(buttonClockPin,LOW);
      if ((PIND>>2)&1){//digitalRead(buttonDataPin)
        buttonCurrent[i]|=1<<j;
      }
      else{
        buttonCurrent[i]&=~(1<<j); 
      }
      PORTD|=B00001000;//digitalWrite(buttonClockPin,HIGH);
    }
    //latchpin low
    PORTD&=B11101111;//digitalWrite(buttonLatchPin, LOW);
    
    for (k=0;k<4;k++){
      buttonCheck(i,k);
    }
  }
  
  //turn off leds- this way one row does not appear brighter than the rest
  
  // set latch pin low so the LEDs don't change while sending in bits
  PORTD&=B10111111;//digitalWrite(ledLatchPin, LOW);
  // shift out 0
  //shiftOut(ledDataPin, ledClockPin, LSBFIRST, 0);  
  for (j=0;j<8;j++){
    PORTD&=B11011111;//digitalWrite(ledClockPin,LOW);
    PORTD&=B01111111;
    PORTD|=B00100000;//digitalWrite(ledClockPin,HIGH);
  }
  //set latch pin high so the LEDs will receive new data
  PORTD|=B01000000;//digitalWrite(ledLatchPin, HIGH);
}

void checkPress(byte Y){
  if (buttonEvent[y]){
    for (byte b=0;b<4;b++){
      if (buttonState[y]&(1<<b)){
        //toggle firstPress variable
        firstPress[y] = 1;
        //display pressed pixel
        ledData[y] = (1<<b);
        //store current position
        xPosition[y] = (1<<b);
        //store peak height
        peakHeight[y] = (1<<b);
        //reset timers
        timeX[y] = 0;
        return;
      }
    }
  }
}

byte scaleAcc(int RAW){
  if (RAW<=10 && RAW>=-10){
    return 5;
  }
  else if (RAW<-10){
    if (RAW<-50){
      return 0;
    }
    else if (RAW<-40){
      return 1;
    }
    else if (RAW<-30){
      return 2;
    }
    else if (RAW<-20){
      return 3;
    }
    else{
      return 4;
    }
  }
  else if (RAW>10){
    if (RAW>50){
      return 10;
    }
    else if (RAW>40){
      return 9;
    }
    else if (RAW>30){
      return 8;
    }
    else if (RAW>20){
      return 7;
    }
    else{
      return 6;
    }
  }
}

void checkAccelerometerGyro(){
  //read values
  xGyroRAW = analogRead(A1);
  yGyroRAW = analogRead(A0);
  xAccRAW = analogRead(A4);
  yAccRAW = analogRead(A3);
  zAccRAW = analogRead(A2);
  
  //offset data
  xGyroRAW = 317-xGyroRAW;
  yGyroRAW = 183-yGyroRAW;
  xAccRAW = 282-xAccRAW;
  yAccRAW = 282-yAccRAW;
  zAccRAW = 282-zAccRAW;
  
  //convert to 0-10
  xAcc = scaleAcc(xAccRAW);
  yAcc = scaleAcc(yAccRAW);
  
  if (xAccRAW>5){
    dirX = 1;
  }
  else if (xAccRAW<5){
    dirX = 0;
  }
  if (yAccRAW>5){
    dirY = 1;
  }
  else if (yAccRAW>5){
    dirY = 0;
  }
  
}

int getTime(byte acceleration){
  switch (acceleration){
    case 0://max - acceleration
    return 100;
    break;
    case 1:
    return 100;
    break;
    case 2:
    return 150;
    break;
    case 3:
    return 200;
    break;
    case 4:
    return 250;
    break;
    case 5://lying flat
    return 0;
    break;
    case 6:
    return 250;
    break;
    case 7:
    return 200;
    break;
    case 8:
    return 150;
    break;
    case 9:
    return 100;
    break;
    case 10://max + acceleration
    return 100;
    break;
  }
}

void moveXPixel(byte Y, int timeComp){
  if (timeComp==0){
  }
  else{
    if (timeX[y]>timeComp){
      timeX[y] = 0;
      if (dirX){
        if (peakHeight[y]==8&&xPosition[y]==8){
          if(toggle[y]){
            MIDImessage(noteON,note[y],0);//send midi
            toggle[y]=0;
            ledData[y]=0;
          }
          else{
            MIDImessage(noteON,note[y],velocity);
            toggle[y]=1;
          }
        }
        else{
          toggle[y]=1;
          if (xPosition[y]==peakHeight[y]){//if at peak
            bounceDirection[y]=1;//falling
            MIDImessage(noteON,note[y],0);//turn note off
          }
          if (xPosition[y]==8){//if hitting bottom
            bounceDirection[y]=0;//rising
            MIDImessage(noteON,note[y],velocity);//turn note on
          }
          if (xPosition[y]==1){
            bounceDirection[y]=1;
          }
          if (bounceDirection[y]){
            xPosition[y] = xPosition[y]<<1;
          }
          else{
            xPosition[y] = xPosition[y]>>1;
          }
        }
      }
      else{
        if (peakHeight[y]==1&&xPosition[y]==1){
          if(toggle[y]){
            MIDImessage(noteON,note[y],0);//send midi
            toggle[y]=0;
            ledData[y]=0;
          }
          else{
            MIDImessage(noteON,note[y],velocity);
            toggle[y]=1;
          }
        }
        else{
          toggle[y]=1;
          if (xPosition[y]==peakHeight[y]){//if at peak
            bounceDirection[y]=0;//falling
            MIDImessage(noteON,note[y],0);//turn note off
          }
          if (xPosition[y]==8){
            bounceDirection[y]=0;
          }
          if (xPosition[y]==1){//if hitting bottom
            bounceDirection[y]=1;//rising
            MIDImessage(noteON,note[y],velocity);//turn note on
          }
          if (bounceDirection[y]){
            xPosition[y] = xPosition[y]<<1;
          }
          else{
            xPosition[y] = xPosition[y]>>1;
          }
        }
      }
    }
  }
}

void shake2Clear(){
  if (abs(xGyroRAW)>300){
    for (byte a=0;a<4;a++){
      firstPress[a]=0;
      ledData[a]=0;
    }
  }
}

void MIDImessage(int command, int MIDInote, int MIDIvelocity) {//send s a MIDI message
  Serial.write(command);//send note on or note off command 
  Serial.write(MIDInote);//send pitch data
  Serial.write(MIDIvelocity);//send velocity data
}

void loop() {
  checkAccelerometerGyro();
  shake2Clear();
  for (byte column=0;column<4;column++){
    checkPress(column);
    if (firstPress[column]){
    moveXPixel(column, getTime(xAcc));
    if (toggle[column]){
      ledData[column]= xPosition[column];
    } 
    }
  }
}