Hello everyone,
Im working on a schoolproject with some Bare Conductive Touch boards.
Bare Conductive has some codes available where you can daisy up to 6 Touchboards.
Now is the code written to use it as Midi output (codes more explained github link):
[Code to daisy 2 or more Touch boards and use them as Midi]
(GitHub - BareConductive/multi-board-touch-midi: Multi Board Bare Conductive Touch MIDI Demo Code)
Primary board code:
// compiler error handling
#include "Compiler_Errors.h"
// touch includes
#include <MPR121.h>
#include <Wire.h>
#define MPR121_ADDR 0x5C
#define MPR121_INT 4
#include <SoftwareSerial.h>
SoftwareSerial mySerial(12, 10); // Soft TX on 10, we don't use RX in this code
// number of boards config
// you can reduce this to improve response time, but the code will work fine with it
// left at 6 - do not try to increase this beyond 6!
// don't forget to edit the notes variable below if you change this
const uint8_t numSecondaryBoards = 6;
const uint8_t totalNumElectrodes = (numSecondaryBoards+1)*12;
// serial comms
const uint8_t serialPacketSize = 13;
uint8_t incomingPacket[serialPacketSize];
// secondary board touch variables
bool thisExternalTouchStatus[numSecondaryBoards][12];
bool lastExternalTouchStatus[numSecondaryBoards][12];
// compound touch variables
bool touchStatusChanged = false;
bool isNewTouch[totalNumElectrodes];
bool isNewRelease[totalNumElectrodes];
// MIDI config
uint8_t note = 0; // The MIDI note value to be played
const uint8_t resetMIDI = 8; // Tied to VS1053 Reset line
uint8_t instrument = 0;
// these are the MIDI notes you want to map to each electrode
// starting with E0 thru E11 on the primary board
// then E0 thru E11 on the first secondary board and so on
// note - the number of note values below MUST equal the total number of electrodes
const uint8_t notes[totalNumElectrodes] = {24,25,26,27,28,29,30,31,32,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};
void setup(){
Serial.begin(57600);
pinMode(LED_BUILTIN, OUTPUT);
//while (!Serial) {}; //uncomment when using the serial monitor
Serial.println("Bare Conductive Multi Board MIDI Piano");
if(!MPR121.begin(MPR121_ADDR)) Serial.println("error setting up MPR121");
MPR121.setInterruptPin(MPR121_INT);
// Reset the VS1053
pinMode(resetMIDI, OUTPUT);
digitalWrite(resetMIDI, LOW);
delay(100);
digitalWrite(resetMIDI, HIGH);
delay(100);
mySerial.begin(31250);
// initialise MIDI
setupMidi();
for(int i=0; i<numSecondaryBoards; i++){
for(int j=0; j<12; j++){
thisExternalTouchStatus[i][j] = false;
lastExternalTouchStatus[i][j] = false;
}
}
for(int i=0; i<totalNumElectrodes; i++){
isNewTouch[i] = false;
isNewRelease[i] = false;
}
for(int a=A0; a<=A5; a++){
pinMode(a, OUTPUT);
digitalWrite(a, LOW);
}
Serial1.begin(57600);
Serial1.setTimeout(3); // 3ms is more than enough time for a packet to be transferred (should take 2.26ms)
delay(100);
}
void loop(){
// reset everything that we combine from the two boards
resetCompoundVariables();
readLocalTouchInputs();
readRemoteTouchInputs();
processTouchInputs();
}
void readLocalTouchInputs(){
// update our compound data on the local touch status
if(MPR121.touchStatusChanged()){
MPR121.updateTouchData();
touchStatusChanged = true;
for(int i=0; i<12; i++){
isNewTouch[i] = MPR121.isNewTouch(i);
isNewRelease[i] = MPR121.isNewRelease(i);
}
}
}
void readRemoteTouchInputs(){
uint8_t numBytesRead;
for(int a=A0; a<A0+numSecondaryBoards; a++){
digitalWrite(a, HIGH);
// try to read a full packet
numBytesRead = Serial1.readBytesUntil(0x00, incomingPacket, serialPacketSize);
// only process a complete packet
if(numBytesRead==serialPacketSize){
// save last status to detect touch / release edges
for(int i=0; i<12; i++){
lastExternalTouchStatus[a-A0][i] = thisExternalTouchStatus[a-A0][i];
}
if(incomingPacket[0] == 'T'){ // ensure we are synced with the packet 'header'
for(int i=0; i<12; i++){
if(incomingPacket[i+1]=='1'){
thisExternalTouchStatus[a-A0][i] = true;
} else {
thisExternalTouchStatus[a-A0][i] = false;
}
}
}
// now that we have read the remote touch data, merge it with the local data
for(int i=0; i<12; i++){
if(lastExternalTouchStatus[a-A0][i] != thisExternalTouchStatus[a-A0][i]){
touchStatusChanged = true;
if(thisExternalTouchStatus[a-A0][i]){
// shift remote data up the array by 12 so as not to overwrite local data
isNewTouch[i+(12*((a-A0)+1))] = true;
} else {
isNewRelease[i+(12*((a-A0)+1))] = true;
}
}
}
} else {
Serial.print("incomplete packet from secondary board ");
Serial.println(a-A0, DEC);
Serial.print("number of bytes read was ");
Serial.println(numBytesRead);
}
digitalWrite(a, LOW);
}
}
void processTouchInputs(){
// only make an action if we have one or fewer pins touched
// ignore multiple touches
for (int i=0; i < totalNumElectrodes; i++){ // Check which electrodes were pressed
if(isNewTouch[i]){
//pin i was just touched
Serial.print("pin ");
Serial.print(i);
Serial.println(" was just touched");
noteOn(0, notes[i], 0x60);
digitalWrite(LED_BUILTIN, HIGH);
} else if(isNewRelease[i]){
//pin i was just released
// Serial.print("pin ");
// Serial.print(i);
// Serial.println(" is no longer being touched");
noteOff(0, notes[i], 0x60);
digitalWrite(LED_BUILTIN, LOW);
}
}
}
void resetCompoundVariables(){
// simple reset for all coumpound variables
touchStatusChanged = false;
for(int i=0; i<totalNumElectrodes; i++){
isNewTouch[i] = false;
isNewRelease[i] = false;
}
}
// functions below are little helpers based on using the SoftwareSerial
// as a MIDI stream input to the VS1053 - all based on stuff from Nathan Seidle
// Send a MIDI note-on message. Like pressing a piano key.
// channel ranges from 0-15
void noteOn(byte channel, byte note, byte attack_velocity) {
talkMIDI( (0x90 | channel), note, attack_velocity);
}
// Send a MIDI note-off message. Like releasing a piano key.
void noteOff(byte channel, byte note, byte release_velocity) {
talkMIDI( (0x80 | channel), note, release_velocity);
}
// Sends a generic MIDI message. Doesn't check to see that cmd is greater than 127,
// or that data values are less than 127.
void talkMIDI(byte cmd, byte data1, byte data2) {
mySerial.write(cmd);
mySerial.write(data1);
// Some commands only have one data byte. All cmds less than 0xBn have 2 data bytes
// (sort of: http://253.ccarh.org/handout/midiprotocol/)
if( (cmd & 0xF0) <= 0xB0)
mySerial.write(data2);
}
// SETTING UP THE INSTRUMENT:
// The below function "setupMidi()" is where the instrument bank is defined. Use the VS1053 instrument library
// below to aid you in selecting your desire instrument from within the respective instrument bank
void setupMidi(){
// Volume - don't comment out this code!
talkMIDI(0xB0, 0x07, 127); //0xB0 is channel message, set channel volume to max (127)
// ---------------------------------------------------------------------------------------------------------
// Melodic Instruments GM1
// ---------------------------------------------------------------------------------------------------------
// To Play "Electric Piano" (5):
talkMIDI(0xB0, 0, 0x00); // Default bank GM1
// We change the instrument by changing the middle number in the brackets
// talkMIDI(0xC0, number, 0); "number" can be any number from the melodic table below
talkMIDI(0xC0, 5, 0); // Set instrument number. 0xC0 is a 1 data byte command(55,0)
// ---------------------------------------------------------------------------------------------------------
// Percussion Instruments (Drums, GM1 + GM2)
// ---------------------------------------------------------------------------------------------------------
// uncomment the two lines of code below to use - you will also need to comment out the two "talkMIDI" lines
// of code in the Melodic Instruments section above
// talkMIDI(0xB0, 0, 0x78); // Bank select: drums
// talkMIDI(0xC0, 0, 0); // Set a dummy instrument number
// ---------------------------------------------------------------------------------------------------------
}
Secondary board code:
// compiler error handling
#include "Compiler_Errors.h"
// touch includes
#include <MPR121.h>
#include <Wire.h>
#define MPR121_ADDR 0x5C
#define MPR121_INT 4
const int triggerPin = A0;
boolean thisTriggerValue = false;
boolean lastTriggerValue = false;
char touchStatus[12] = {'0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'};
void setup(){
MPR121.begin(MPR121_ADDR);
MPR121.setInterruptPin(MPR121_INT);
pinMode(LED_BUILTIN, OUTPUT);
digitalWrite(LED_BUILTIN, LOW);
pinMode(triggerPin, INPUT);
digitalWrite(triggerPin, LOW); // ensure internal pullup is disabled
pinMode(1, INPUT); // ensure that TX goes out of circuit when the UART is disabled
for(int i=0; i<12; i++){
MPR121.setTouchThreshold(i, 40);
MPR121.setTouchThreshold(i, 20);
}
}
void loop(){
processInputs();
thisTriggerValue = digitalRead(triggerPin);
if(thisTriggerValue && !lastTriggerValue){ // rising edge triggered
sendSerialStatus();
}
lastTriggerValue = thisTriggerValue;
}
void processInputs() {
if(MPR121.touchStatusChanged()){
MPR121.updateTouchData();
for(int i=0; i<12; i++){
if(MPR121.isNewTouch(i)){
touchStatus[i] = '1';
} else if(MPR121.isNewRelease(i)){
touchStatus[i] = '0';
}
}
}
}
void sendSerialStatus(){
Serial1.begin(57600);
Serial1.write('T');
Serial1.write(touchStatus, 12);
Serial1.end();
}
Now they also have a code to use a Touchboard as HID keyboard.
https://www.instructables.com/The-Touch-Board-As-an-HID-Keyboard/
// compiler error handling
#include "Compiler_Errors.h"
// touch includes
#include <MPR121.h>
#include <MPR121_Datastream.h>
#include <Wire.h>
// keyboard includes
#include <Keyboard.h>
// keyboard variables
char key;
// keyboard behaviour constants
const bool HOLD_KEY = true; // set this to false if you want to have a single quick keystroke, true means the key is pressed and released when you press and release the electrode respectively
const char KEY_MAP[12] = {'J', 'U', 'H', 'Y', 'G', 'T', 'F', 'D', 'E', 'S', 'W', 'A'};
// const char KEY_MAP[12] = {KEY_LEFT_ARROW, KEY_RIGHT_ARROW, KEY_UP_ARROW, KEY_DOWN_ARROW, ' ', KEY_ESC, KEY_F1, KEY_F2, KEY_F3, KEY_F4, KEY_PAGE_UP, KEY_PAGE_DOWN}; // more keys at http://arduino.cc/en/Reference/KeyboardModifiers
// const char KEY_MAP[12] = {'8', '3', '0', '1', '2', '4', '7', '6', '5', '9', '9', '9'}; // for memory game
// touch constants
const uint32_t BAUD_RATE = 115200;
const uint8_t MPR121_ADDR = 0x5C;
const uint8_t MPR121_INT = 4;
// MPR121 datastream behaviour constants
const bool MPR121_DATASTREAM_ENABLE = false;
void setup() {
Serial.begin(BAUD_RATE);
pinMode(LED_BUILTIN, OUTPUT);
if (!MPR121.begin(MPR121_ADDR)) {
Serial.println("error setting up MPR121");
switch (MPR121.getError()) {
case NO_ERROR:
Serial.println("no error");
break;
case ADDRESS_UNKNOWN:
Serial.println("incorrect address");
break;
case READBACK_FAIL:
Serial.println("readback failure");
break;
case OVERCURRENT_FLAG:
Serial.println("overcurrent on REXT pin");
break;
case OUT_OF_RANGE:
Serial.println("electrode out of range");
break;
case NOT_INITED:
Serial.println("not initialised");
break;
default:
Serial.println("unknown error");
break;
}
while (1);
}
MPR121.setInterruptPin(MPR121_INT);
if (MPR121_DATASTREAM_ENABLE) {
MPR121.restoreSavedThresholds();
MPR121_Datastream.begin(&Serial);
} else {
MPR121.setTouchThreshold(40);
MPR121.setReleaseThreshold(20);
}
MPR121.setFFI(FFI_10);
MPR121.setSFI(SFI_10);
MPR121.setGlobalCDT(CDT_4US); // reasonable for larger capacitances
digitalWrite(LED_BUILTIN, HIGH); // switch on user LED while auto calibrating electrodes
delay(1000);
MPR121.autoSetElectrodes(); // autoset all electrode settings
digitalWrite(LED_BUILTIN, LOW);
Keyboard.begin();
}
void loop() {
MPR121.updateAll();
for (int i=0; i < 12; i++) { // check which electrodes were pressed
key = KEY_MAP[i];
if (MPR121.isNewTouch(i)) {
digitalWrite(LED_BUILTIN, HIGH);
Keyboard.press(key); // press the appropriate key on the "keyboard" output
if (!HOLD_KEY) {
Keyboard.release(key); // if we don't want to hold the key, immediately release it
}
} else {
if (MPR121.isNewRelease(i)) {
digitalWrite(LED_BUILTIN, LOW);
if (HOLD_KEY) {
Keyboard.release(key); // if we have a new release and we were holding a key, release it
}
}
}
}
if (MPR121_DATASTREAM_ENABLE) {
MPR121_Datastream.update();
}
}
The thing I want:
Daisy 2 Touch boards and instead of Midi output I want HID output, so not midi mp3 sounds but keyboard input.
Can somebody please help me? I have tried to combine the codes but they are so different I cant Figure it out...
If Somebody could help me, you would be my hero.
I think it should be hard if you have knowledge of coding so anyone?
Kind Regards,
Jelle