Hello,
as a musician I am building an MIDI breath controller (EWI) right now (I'm not an experienced programmer).
I have an bmp180 air pressure sensor and an MPR121 hooked up to i2c on an Arduino nano.
my problem:
different combinations of touch pins of the mpr121 touched, have to output a different note.
I use the Adafruit mpr121 library, and when running the example code the touch sensor works fine. Now I added a line to output "C#" (just for now) when touching a certain combination:
if ((cap.touched() & _BV(0)) && (cap.touched() & _BV(2))&& (cap.touched() & _BV(3))&& (cap.touched() & _BV(4))&& (cap.touched() & _BV(5))&& (cap.touched() & _BV(6))&& (cap.touched() & _BV(7))&& (cap.touched() & _BV(8))) { Serial.print("C#");
delay(100);}
When running this program, after pressing the combination it shows "C#" but then freezes and I get no new touch information in the serial monitor. Restarting the arduino helps but only until this combination is pressed again.
I read that one has to have external pull up resistors on i2c, but also that the arduino has built in pull up resistors, so one doesn't have to have external ones. Do I need external pull up resistors?
Does someone know what the problem is?
You need a bigger program than that to do anything useful. And you need to post it ALL if you want any help with it.
Steve
I added this line of code to the Adafruit MPR121 example sketch, to see if it works.
/*********************************************************
This is a library for the MPR121 12-channel Capacitive touch sensor
Designed specifically to work with the MPR121 Breakout in the Adafruit shop
----> https://www.adafruit.com/products/
These sensors use I2C communicate, at least 2 pins are required
to interface
Adafruit invests time and resources providing this open source code,
please support Adafruit and open-source hardware by purchasing
products from Adafruit!
Written by Limor Fried/Ladyada for Adafruit Industries.
BSD license, all text above must be included in any redistribution
**********************************************************/
#include <Wire.h>
#include <Adafruit_MPR121.h>
// You can have up to 4 on one i2c bus but one is enough for testing!
Adafruit_MPR121 cap = Adafruit_MPR121();
// Keeps track of the last pins touched
// so we know when buttons are 'released'
uint16_t lasttouched = 0;
uint16_t currtouched = 0;
void setup() {
Serial.begin(9600);
while (!Serial) { // needed to keep leonardo/micro from starting too fast!
delay(10);
}
Serial.println("Adafruit MPR121 Capacitive Touch sensor test");
// Default address is 0x5A, if tied to 3.3V its 0x5B
// If tied to SDA its 0x5C and if SCL then 0x5D
if (!cap.begin(0x5A)) {
Serial.println("MPR121 not found, check wiring?");
while (1);
}
Serial.println("MPR121 found!");
}
void loop() {
// Get the currently touched pads
currtouched = cap.touched();
if ((cap.touched() & _BV(0)) && (cap.touched() & _BV(2))&& (cap.touched() & _BV(3))&& (cap.touched() & _BV(4))&& (cap.touched() & _BV(5))&& (cap.touched() & _BV(6))&& (cap.touched() & _BV(7))&& (cap.touched() & _BV(8))) { Serial.print("C#");
delay(100);}
for (uint8_t i=0; i<12; i++) {
// it if *is* touched and *wasnt* touched before, alert!
if ((currtouched & _BV(i)) && !(lasttouched & _BV(i)) ) {
Serial.print(i); Serial.println(" touched");
}
// if it *was* touched and now *isnt*, alert!
if (!(currtouched & _BV(i)) && (lasttouched & _BV(i)) ) {
Serial.print(i); Serial.println(" released");
}
}
// reset our state
lasttouched = currtouched;
// comment out this line for detailed data from the sensor!
return;
// debugging info, what
Serial.print("\t\t\t\t\t\t\t\t\t\t\t\t\t 0x"); Serial.println(cap.touched(), HEX);
Serial.print("Filt: ");
for (uint8_t i=0; i<12; i++) {
Serial.print(cap.filteredData(i)); Serial.print("\t");
}
Serial.println();
Serial.print("Base: ");
for (uint8_t i=0; i<12; i++) {
Serial.print(cap.baselineData(i)); Serial.print("\t");
}
Serial.println();
// put a delay so it isn't overwhelming
delay(100);
}
This is my code to send Note On/Note Offs if a new combination is touched:
#include <Adafruit_MPR121.h>
#include <MIDI.h>
#include <SoftwareSerial.h>
#include <Wire.h>
#include <BMP180.h>
BMP180 barometer;
Adafruit_MPR121 cap = Adafruit_MPR121();
int note = 0;
int nextnote = 50;
int prenextnote = 0;
int velocity = 0;
int nextvelocity = 0;
int presecondnote = 0;
int lastnote;
int prenote = 0;
long lastvelocity;
long prevelocity;
long prevelocitytwo;
int octaveshift = 0;
int breath = 0;
boolean legato = 0;
long aftertouch;
long preaftertouch;
long preaftertouchtwo;
long pressure;
long lastpressure;
//joystick
const int X_pin = 0; // analog pin connected to X output
const int Y_pin = 1; // analog pin connected to Y output
MIDI_CREATE_DEFAULT_INSTANCE();
void setup() {
// put your setup code here, to run once:
Serial.begin(31250);
MIDI.begin(MIDI_CHANNEL_OMNI);
MIDI.sendNoteOn(50,100, 1);
delay(5000);
MIDI.sendNoteOff(50, 100, 1);
Wire.begin();
cap.begin(0x5A);
barometer = BMP180();
barometer.SoftReset();
barometer.Initialize();
}
void loop() {
// put your main code here, to run repeatedly:
if ((cap.touched() & _BV(0)) && (cap.touched() & _BV(2))&& (cap.touched() & _BV(3))&& (cap.touched() & _BV(4))&& (cap.touched() & _BV(5))&& (cap.touched() & _BV(6))&& (cap.touched() & _BV(7))&& (cap.touched() & _BV(8))) { prenote = 37; }
else if ((cap.touched() & _BV (0)) && (cap.touched() & _BV(2))&& (cap.touched() & _BV(3))&& (cap.touched() & _BV(4))&& (cap.touched() & _BV(6))&& (cap.touched() & _BV(7))&& (cap.touched() & _BV(8))) { prenote = 36; }
else if ((cap.touched() & _BV(1)) && (cap.touched() & _BV( 2))&& (cap.touched() & _BV(3))&& (cap.touched() & _BV( 4))&& (cap.touched() & _BV(6 ))&& (cap.touched() & _BV(7))&& (cap.touched() & _BV(8))) { prenote = 39; }
else if ((cap.touched() & _BV(2))&& (cap.touched() & _BV( 3))&& (cap.touched() & _BV(4))&& (cap.touched() & _BV( 6))&& (cap.touched() & _BV(7))&& (cap.touched() & _BV(8))) { prenote = 38; }
else if ((cap.touched() & _BV(3))&& (cap.touched() & _BV( 4))&& (cap.touched() & _BV(6))&& (cap.touched() & _BV(7))&& (cap.touched() & (8))) {prenote = 40; }
else if ((cap.touched() & _BV( 4))&& (cap.touched() & _BV( 6))&& (cap.touched() & _BV(7))&& (cap.touched() & _BV( 8))) { prenote = 41; }
else if ((cap.touched() & _BV( 3))&& (cap.touched() & _BV(6))&& (cap.touched() & _BV(7))&& (cap.touched() & _BV( 8))) {prenote = 42; }
else if ((cap.touched() & _BV(5))&& (cap.touched() & _BV( 6))&& (cap.touched() & _BV( 7))&& (cap.touched() & _BV(8))) {prenote = 44; }
else if ((cap.touched() & _BV(6))&& (cap.touched() & _BV(7))&& (cap.touched() & _BV( 8))) { prenote = 43; }
else if ((cap.touched() & _BV( 4))&& (cap.touched() & _BV(8))) { prenote = 46; }
else if ((cap.touched() & _BV(7))&& (cap.touched() & _BV( 8))) {prenote = 45; }
else if ((cap.touched() & _BV(7))) { prenote = 48; }
else if ((cap.touched() & _BV( 8))) {prenote = 47; }
else {prenote = 49; }
if(analogRead(X_pin) > 1000) { octaveshift = 12 ; }
else if(analogRead(Y_pin) > 1000) { octaveshift = 24 ; }
else if(analogRead(X_pin) < 30) { octaveshift = 36 ; }
else if(analogRead(Y_pin) < 30) { octaveshift = 48 ; }
else {octaveshift = 0;}
note = prenote + octaveshift;
nextnote = note;
MIDI.sendNoteOn(note, 100, 1);
while(nextnote==note){
if ((cap.touched() & _BV(0)) && (cap.touched() & _BV(2))&& (cap.touched() & _BV(3))&& (cap.touched() & _BV(4))&& (cap.touched() & _BV(5))&& (cap.touched() & _BV(6))&& (cap.touched() & _BV(7))&& (cap.touched() & _BV(8))) { prenextnote = 37; }
else if ((cap.touched() & _BV (0)) && (cap.touched() & _BV(2))&& (cap.touched() & _BV(3))&& (cap.touched() & _BV(4))&& (cap.touched() & _BV(6))&& (cap.touched() & _BV(7))&& (cap.touched() & _BV(8))) { prenextnote = 36; }
else if ((cap.touched() & _BV(1)) && (cap.touched() & _BV( 2))&& (cap.touched() & _BV(3))&& (cap.touched() & _BV( 4))&& (cap.touched() & _BV(6 ))&& (cap.touched() & _BV(7))&& (cap.touched() & _BV(8))) { prenextnote = 39; }
else if ((cap.touched() & _BV(2))&& (cap.touched() & _BV( 3))&& (cap.touched() & _BV(4))&& (cap.touched() & _BV( 6))&& (cap.touched() & _BV(7))&& (cap.touched() & _BV(8))) { prenextnote = 38; }
else if ((cap.touched() & _BV(3))&& (cap.touched() & _BV( 4))&& (cap.touched() & _BV(6))&& (cap.touched() & _BV(7))&& (cap.touched() & (8))) {prenextnote = 40; }
else if ((cap.touched() & _BV( 4))&& (cap.touched() & _BV( 6))&& (cap.touched() & _BV(7))&& (cap.touched() & _BV( 8))) { prenextnote = 41; }
else if ((cap.touched() & _BV( 3))&& (cap.touched() & _BV(6))&& (cap.touched() & _BV(7))&& (cap.touched() & _BV( 8))) {prenextnote = 42; }
else if ((cap.touched() & _BV(5))&& (cap.touched() & _BV( 6))&& (cap.touched() & _BV( 7))&& (cap.touched() & _BV(8))) {prenextnote = 44; }
else if ((cap.touched() & _BV(6))&& (cap.touched() & _BV(7))&& (cap.touched() & _BV( 8))) { prenextnote = 43; }
else if ((cap.touched() & _BV( 4))&& (cap.touched() & _BV(8))) { prenextnote = 46; }
else if ((cap.touched() & _BV(7))&& (cap.touched() & _BV( 8))) {prenextnote = 45; }
else if ((cap.touched() & _BV(7))) { prenextnote = 48; }
else if ((cap.touched() & _BV( 8))) {prenextnote = 47; }
else {prenextnote = 49; }
if(analogRead(X_pin) > 1000) { octaveshift = 12 ; }
else if(analogRead(Y_pin) > 1000) { octaveshift = 24 ; }
else if(analogRead(X_pin) < 30) { octaveshift = 36 ; }
else if(analogRead(Y_pin) < 30) { octaveshift = 48 ; }
else {octaveshift = 0;}
nextnote = prenextnote + octaveshift;
}
MIDI.sendNoteOff(note, 100, 1);
}
It didn't work, so I added a line of code to the example sketch to see if it registers the combinations. There I saw that it freezes when touching this combination.
What does the test program do if you use a simple version perhaps just looking for a single pad to be touched?
And if you're using this to set specific notes don't you also need to check that the other pads are NOT touched ? Just asking as this is way outside my experience.
Steve
Oh yeah, I need to check if the other pads are not checked. Thanks.
The example sketch works fine as long as my combination is not touched (in MPR example sketch).
It says : 1 touched / released etc on serial monitor.
But after I touched the combination, it freezes and I do get no data on serial monitor anymore.
though my line of code should do the same thing as the "touched / released" of the example sketch, I think.
I could save every keystate in a boolean, but wouln't that do the same as my if statement?
I will try this now..
Are you confident that the MPR121 can actually handle multiple electrodes being touched simultaneously? I don't know because I've never used one but I can't see anything in the specifications about multiple touches. I wonder if it may be that that's locking up rather than the Arduino.
Steve
In the example sketch it can say (1 touched, 2 touched, 3 touched, 1 released, 2 released), so it obviously can handle multiple electrodes being touched.
I changed the code to this:
/*********************************************************
This is a library for the MPR121 12-channel Capacitive touch sensor
Designed specifically to work with the MPR121 Breakout in the Adafruit shop
----> https://www.adafruit.com/products/
These sensors use I2C communicate, at least 2 pins are required
to interface
Adafruit invests time and resources providing this open source code,
please support Adafruit and open-source hardware by purchasing
products from Adafruit!
Written by Limor Fried/Ladyada for Adafruit Industries.
BSD license, all text above must be included in any redistribution
**********************************************************/
#include <Wire.h>
#include <Adafruit_MPR121.h>
// You can have up to 4 on one i2c bus but one is enough for testing!
Adafruit_MPR121 cap = Adafruit_MPR121();
// Keeps track of the last pins touched
// so we know when buttons are 'released'
uint16_t lasttouched = 0;
uint16_t currtouched = 0;
boolean keyzero;
boolean keyone;
boolean keytwo;
boolean keythree;
boolean keyfour;
boolean keyfive;
boolean keysix;
boolean keyseven;
boolean keyeight;
void setup() {
Serial.begin(9600);
while (!Serial) { // needed to keep leonardo/micro from starting too fast!
delay(10);
}
Serial.println("Adafruit MPR121 Capacitive Touch sensor test");
// Default address is 0x5A, if tied to 3.3V its 0x5B
// If tied to SDA its 0x5C and if SCL then 0x5D
if (!cap.begin(0x5A)) {
Serial.println("MPR121 not found, check wiring?");
while (1);
}
Serial.println("MPR121 found!");
}
void loop() {
// Get the currently touched pads
currtouched = cap.touched();
for (uint8_t i=0; i<12; i++) {
// it if *is* touched and *wasnt* touched before, alert!
if ((currtouched & _BV(i)) && !(lasttouched & _BV(i)) ) {
Serial.print(i); Serial.println(" touched");
if(i==0){keyzero = 1;}
if(i==1){keyone = 1;}
if(i==2){keytwo = 1;}
if(i==3){keythree = 1;}
if(i==4){keyfour = 1;}
if(i==5){keyfive = 1;}
if(i==6){keysix = 1;}
if(i==7){keyseven = 1;}
if(i==8){keyeight = 1;}
}
// if it *was* touched and now *isnt*, alert!
if (!(currtouched & _BV(i)) && (lasttouched & _BV(i)) ) {
Serial.print(i); Serial.println(" released");
if(i==0){keyzero = 0;}
if(i==1){keyone = 0;}
if(i==2){keytwo = 0;}
if(i==3){keythree = 0;}
if(i==4){keyfour = 0;}
if(i==5){keyfive = 0;}
if(i==6){keysix = 0;}
if(i==7){keyseven = 0;}
if(i==8){keyeight = 0;}
}
}
if (keytwo == 1 && keythree == 1 && keyfour == 1 && keyfive == 1 && keysix == 1 && keyseven ==1 && keyeight == 1) { Serial.print("C#");
delay(100);}
// reset our state
lasttouched = currtouched;
// comment out this line for detailed data from the sensor!
return;
// debugging info, what
Serial.print("\t\t\t\t\t\t\t\t\t\t\t\t\t 0x"); Serial.println(cap.touched(), HEX);
Serial.print("Filt: ");
for (uint8_t i=0; i<12; i++) {
Serial.print(cap.filteredData(i)); Serial.print("\t");
}
Serial.println();
Serial.print("Base: ");
for (uint8_t i=0; i<12; i++) {
Serial.print(cap.baselineData(i)); Serial.print("\t");
}
Serial.println();
// put a delay so it isn't overwhelming
delay(100);
}
I saved every key state in a boolean, but it still freezes. I don't understand why it can say x touched, y touched, z touched ... but freezes when my if sentence comes into action.
I attached a picture of the serial monitor: you can see that multiple electrodes were touched, but after "C#" it freezes.
Or is there a maximum number of conditions in an if sentence which I can use?
edit: ok, it also doesn't work with only one condition.
if (keyfive == 1) { Serial.println("C#");
delay(100);}