Speed determined Midi messages, Reed Switch and Arduino Uno Rev3

Hi Team,

I have taken on a project where I am attempting to use a Reed switch fitted to a bicycle wheel to send midi messages to QLab (Figure 53 show control software) to control the output of LED lights.

The Basic idea being that as a user pedals the bike faster, More lights will light up.

So far I have managed to find a tutorial that shows building a Bike speedometer, Which I have successfully done.
I am now attempting to add to the code so I can use the speed read out to generate Midi messages to send to the control computer Via Hairless MIDI.

My end goal is to get the Arduino spitting out a new MIDI Note on command as the bike passes a certain speed threshold, keeping that note on until the bike passes back below the speed threshold. I also want to have up to ten individual thresholds so I can have 10 channels of lights which come on as the bike gets faster and faster. Again all turning back off as the bike passes back below the threshold.

I am getting messages out of the Arduino but they seem not to be responsive to the speed.
I also get MIDI Messages on channels that I have not mentioned at all and at various velocities, Unsure of why this is.

Here is my code, It compiles and uploads but currently doesn't do what I am aiming for.
Am I going down the right path here?

//calculations
//tire radius ~ 13.5 inches
//circumference = pi*2*r =~85 inches
//max speed of 35mph =~ 616inches/second
//max rps =~7.25
#include <MIDI.h>
MIDI_CREATE_DEFAULT_INSTANCE();
#define reed A0//pin connected to read switch

//storage variables
int reedVal;
long timer;// time between one full rotation (in ms)
float mph;
float radius = 13.5;// tire radius (in inches)
float circumference;

int maxReedCounter = 100;//min time (in ms) of one rotation (for debouncing)
int reedCounter;


void setup(){
  
  reedCounter = maxReedCounter;
  circumference = 2*3.14*radius;
  pinMode(reed, INPUT);
  
  // TIMER SETUP- the timer interrupt allows precise timed measurements of the reed switch
  //for more info about configuration of arduino timers see http://arduino.cc/playground/Code/Timer1
  cli();//stop interrupts

  //set timer1 interrupt at 1kHz
  TCCR1A = 0;// set entire TCCR1A register to 0
  TCCR1B = 0;// same for TCCR1B
  TCNT1  = 0;
  // set timer count for 1khz increments
  OCR1A = 1999;// = (1/1000) / ((1/(16*10^6))*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
  //END TIMER SETUP
  
  Serial.begin(9600);
}


ISR(TIMER1_COMPA_vect) {//Interrupt at freq of 1kHz to measure reed switch
  reedVal = digitalRead(reed);//get val of A0
  if (reedVal){//if reed switch is closed
    if (reedCounter == 0){//min time between pulses has passed
      mph = (56.8*float(circumference))/float(timer);//calculate miles per hour
      timer = 0;//reset timer
      reedCounter = maxReedCounter;//reset reedCounter
    }
    else{
      if (reedCounter > 0){//don't let reedCounter go negative
        reedCounter -= 1;//decrement reedCounter
      }
    }
  }
  else{//if reed switch is open
    if (reedCounter > 0){//don't let reedCounter go negative
      reedCounter -= 1;//decrement reedCounter
    }
  }
  if (timer > 2000){
    mph = 0;//if no new pulses from reed switch- tire is still, set mph to 0
  }
  else{
    timer += 1;//increment timer
  } 
     if (mph > 25){                    // If we have received a message
        MIDI.sendNoteOn(42, 127, 1);    // Send a Note (pitch 42, velo 127 on channel 1)
        delay(1000);                // Wait for a second
        MIDI.sendNoteOff(42, 0, 1);     // Stop the note
    } 
    if (mph > 15){                    // If we have received a message
        MIDI.sendNoteOn(50, 127, 1);    // Send a Note (pitch 42, velo 127 on channel 1)
        delay(1000);                // Wait for a second
        MIDI.sendNoteOff(50, 0, 1);     // Stop the note
    } 
    if (mph = 0){
        MIDI.sendNoteOff(42, 0, 1);
        MIDI.sendNoteOff(50, 0, 1);
    
    }

        
  }

void displayMPH(){
 Serial.println(mph);
}

void loop(){

  //print mph once a second
  displayMPH();
  delay(1000);

}

I am super new to the Arduino world so forgive me if I have completely come at this from the wrong direction...
Any suggestions/ pointers about what I am trying to do would at this point be super apprciated,

Have a great day!

No, you are not on the right path. Your interrupt service routine (ISR) should not be using delay() since it won't work and should not be sending the midi notes.

ISR functions should be short and fast. Something like setting a flag or maybe reading an input or two.

In your loop() function is where you notice the flag has changed and react to it (like sending a note, etc.)

Also, how is your reed switch wired up? Does it have an external pull-up resistor attached? It will need one based on how your code is written.

Hi,

Thanks for your reply,

I see what you are saying, Although I'm not too sure I understand how to rectify it.

Is it a case of moving my midi commands to the loop() section of the code?
I'm not sure what you mean by setting flags?
Sorry that I'm still very new to this.

My board does have a 10K Ohm 1/4-Watt Carbon Film Resistor in it.

It is wired up between the reed switch, 5v and ground.

I have attached a photo and (Crude) schematic to the original post.

Thanks

Just copy the MIDI stuff into loop:

//calculations
//tire radius ~ 13.5 inches
//circumference = pi*2*r =~85 inches
//max speed of 35mph =~ 616inches/second
//max rps =~7.25
#include <MIDI.h>
MIDI_CREATE_DEFAULT_INSTANCE();
#define reed A0//pin connected to read switch

//storage variables
//int reedVal;
volatile long timer;// time between one full rotation (in ms)
volatile float mph;
const float radius = 13.5;// tire radius (in inches)
float circumference;

const int maxReedCounter = 100;//min time (in ms) of one rotation (for debouncing)
volatile int reedCounter;


void setup() {

  reedCounter = maxReedCounter;
  circumference = 2 * 3.14 * radius;
  pinMode(reed, INPUT);

  // TIMER SETUP- the timer interrupt allows precise timed measurements of the reed switch
  //for more info about configuration of arduino timers see http://arduino.cc/playground/Code/Timer1
  cli();//stop interrupts

  //set timer1 interrupt at 1kHz
  TCCR1A = 0;// set entire TCCR1A register to 0
  TCCR1B = 0;// same for TCCR1B
  TCNT1  = 0;
  // set timer count for 1khz increments
  OCR1A = 1999;// = (1/1000) / ((1/(16*10^6))*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
  //END TIMER SETUP

  Serial.begin(9600);
}


ISR(TIMER1_COMPA_vect) {//Interrupt at freq of 1kHz to measure reed switch
  int reedVal = digitalRead(reed);//get val of A0
  if (reedVal) { //if reed switch is closed
    if (reedCounter == 0) { //min time between pulses has passed
      mph = (56.8 * float(circumference)) / float(timer); //calculate miles per hour
      timer = 0;//reset timer
      reedCounter = maxReedCounter;//reset reedCounter
    }
    else {
      if (reedCounter > 0) { //don't let reedCounter go negative
        reedCounter -= 1;//decrement reedCounter
      }
    }
  }
  else { //if reed switch is open
    if (reedCounter > 0) { //don't let reedCounter go negative
      reedCounter -= 1;//decrement reedCounter
    }
  }
  if (timer > 2000) {
    mph = 0;//if no new pulses from reed switch- tire is still, set mph to 0
  }
  else {
    timer += 1;//increment timer
  }
}

void displayMPH() {
  Serial.println(mph);
}

void loop() {

  //print mph once a second
  displayMPH();

  if (mph > 25) {                   // If we have received a message
    MIDI.sendNoteOn(42, 127, 1);    // Send a Note (pitch 42, velo 127 on channel 1)
    delay(1000);                // Wait for a second
    MIDI.sendNoteOff(42, 0, 1);     // Stop the note
  }
  if (mph > 15) {                   // If we have received a message
    MIDI.sendNoteOn(50, 127, 1);    // Send a Note (pitch 42, velo 127 on channel 1)
    delay(1000);                // Wait for a second
    MIDI.sendNoteOff(50, 0, 1);     // Stop the note
  }
  if (mph = 0) {
    MIDI.sendNoteOff(42, 0, 1);
    MIDI.sendNoteOff(50, 0, 1);

  }



  delay(1000);

}

One thing to note about the current code is that the variable mph is always changing so those 3 if() statements could theoretically all be false. If you want a constant value through each iteration of loop(), then you need to make a local copy of the variable.