2

I'd like to make a musical harp that utilizes break beam sensors.

I'd really appreciate guidance on these two questions:

  • How should I go about listening for multiple beam breaks at the same time? I'd like the box to be able to play cords, so I'd need to listen for the break beams while simultaneously taking the action do to other previous break beams. Are there any links to similar projects for guidance on handling multiple inputs (possibly multiple interrupts) at the same time, as well is multiple outputs?

  • Where is a good place to start to understand how to output non-buzzer sound with an Arduino? I bought a Adafruit Wave Shield to do the trick, but I'd appreciate advice on using this, or possibly taking an easier route.

My major concern is the first question however, and it makes me think I may need a Pi possibly? But I've never worked with those, so I'd like to avoid it if possible.

Thanks! :)

8
  • Why do you need to use interrupts? Will the MCU ever be doing anything other than waiting for beam breaks and playing notes? Commented Aug 16, 2017 at 22:17
  • You may be right, right off the bat, but it leads to another question that I don't have the knowledge to know quite yet.... after I sense the break beam and start a 'C note' for x seconds, will I be able to simultaneously sense another break beam while the 'C note' is playing and superpose another 'D note'?
    – GrantG
    Commented Aug 16, 2017 at 22:24
  • That depends on how you're handling notes. Commented Aug 16, 2017 at 22:27
  • Do you have an example where you send a command to run in the background of an arduino, while the void loop continues on it's way? I'll go look for example on the Google too.
    – GrantG
    Commented Aug 16, 2017 at 23:09
  • You still haven't explained how you're playing notes. Commented Aug 16, 2017 at 23:29

3 Answers 3

1

Most of the examples for that shield seem to suffer from what could be called delayitis. If you first convert the piano example to a more state-based approach then the loop you want becomes much simpler:

#define NUM_BEAMS 12
// a single octave

char filename[NUM_BEAMS+5]; //init the last 5 chars to ".wav\0"
int previousInputs; //flag variable where each bit is a single beam

void loop(){
    int inputs = readBeams();

    if(inputs != previousInputs){
      previousInputs = inputs;
      if (wave.isplaying) {// already playing something, so stop it!
        wave.stop(); // stop it
      }
      if(inputs == 0){
        return;
      }
      for(int i = 0; i< NUM_BEAMS; i++){
          filename[i] = inputs &(1<<i)?'1':'0';
      }

      if (!f.open(root, filename)) {
        putstring("Couldn't open file "); Serial.print(name); return;
      }
      if (!wave.create(f)) {
        putstring_nl("Not a valid WAV"); return;
      }
      // ok time to play!
      wave.play();
    }

}

The SD card in the shield will need 4095 files, each containing the chord that must be played.

No need for interrupts, no messy interrupt based IO. Just a simple loop() where you read the input and if different from last time start playing a new file.

If you have a shield that can actually do sound mixing then, instead of needing a file for every possible chord, you can start playing the note when the corresponding bit in started = inputs & ~previousInputs; is 1 and stop playing the note when the corresponding bit in ended = ~inputs & previousInputs; is 1.

1
  • This is a great solution to avoid interrupts. I'm realizing that my shield isn't going to be able to do the trick cleanly, and that I'm going to need to find a shield that can do some level of mixing so individual sounds can come and go more naturally.
    – GrantG
    Commented Aug 17, 2017 at 13:44
1

I quite like rachet freaks's idea, however whilst making an example for you his answer hadn't been posted. SO i'll chip in anyway!

In general it is possible to control and measure more than one input and output at the same time by the use of millis(). millis() is an arduino function that returns the number of milliseconds since the arduino fired up.

This probably doesnt sound overly useful to you straight away. But millis can be used in place of delay() if used correctly. Essentially you create a long variable to hold the beginning of an event and check the time since that event started with an if statement. If the difference in the current time and the start time is equal to the time you want the event to occur. Stop the event.

I appreciate my explanation might not be overly clear. So I wrote an example sketch. The sketch has two button inputs. And two button outputs. If one of the buttons is pressed one led will blink for 10 seconds, pressing the button mid blink will extend the time the led blinks by another 10 seconds. Whilst this is happening if you press the second button the other led will turn on, but only when the button is pressed. Using delay() to achieve this would not work nearly as well.

//Setup led and button pins
int ledPin1 = 3;
int ledPin2 = 4;
int butPin1 = 5;
int butPin2 = 6;

//Setup timers
unsigned long currentMillis = 0;
unsigned long blinkStartMillis = 0;
unsigned long ledOnMillis1 = 0;
unsigned long ledOffMillis1 =0;

//Setup variables to store input and output states.
int ledState1 = 0, ledState2 = 0; //State 1 for on, 0 for off;
int butState1 = 0, butState2 = 0; //State 1 for trigger, 0 for off;

//Setup trigger for event
int blinkTrigger = 0;

void setup() {
  pinMode(ledPin1, OUTPUT);
  pinMode(ledPin2, OUTPUT);
  pinMode(butPin1, INPUT);
  pinMode(butPin2, INPUT);

  delay(500);
}

void loop() {
    //Sets current millis for this loop
    currentMillis = millis();

    //Reads Button States
    butState1 = digitalRead(butPin1);
    butState2 = digitalRead(butPin2);

    //Setup to start blink if button 1 input is high
    if(butState1) {
      blinkTrigger = 1;
      blinkStartMillis = currentMillis;
    }

    //Handles Blinking
    if(blinkTrigger) {

      //If led1 off, and has been off for 500 milliseconds. led 1 on
      if(ledState1 == 0 && currentMillis - LedOffMillis >= 500) {
        digitalWrite(ledPin1, HIGH);
        ledState1 = 1;
        ledOnMillis = currentMillis;
      }

      //If led1 on, and has been on for 500 milliseconds. led 1 off
      if(ledState1 == 1 && currentMillis - LedOnMillis >= 500) {
        digitalWrite(ledPin1, LOW);
        ledState1 = 0;
        ledOffMillis = currentMillis;
      }

      //If led1 has been blinking for more than 10 seconds
      //Stop blinking
      if(currentMillis - blinkStartMillis > 10000) {
        digitalWrite(ledPin1, LOW);
        ledState1 = 0;
        blinkTrigger = 0;
      }
    }

    //While Button 2 pressed led 2 on
    if(butState2) digitalWrite(ledPin2, HIGH);
    if(!butState2) digitalWrite(ledPin2, LOW);

}

Note: The code style is a bit off because i rushed it, I would also usually use structs to hold the timers and event triggers.

Now for the Wave module rachet is bang on the money, you would need a file for every single note and every single chord.

I hope I helped, if not for your project maybe you may have learnt how to handle more than one event using event timings.

1
  • This is a great solution to the first problem. Thank you. I'm realizing that I'll hopefully be able to send the play command to the separate device, but my current choice for second device is questionable but functional.
    – GrantG
    Commented Aug 17, 2017 at 13:55
0

How should I go about listening for multiple beam breaks at the same time?

use interrupts. it can be done with external interrupts, pin change interrupts, comparator interrupts, analog interrupts, or even timer interrupts, depending on how you intend to approach it.

1
  • I think I like this approach, but can an Arduino complete the interupt commands in the background while the void loop continues in the foreground? For example, I'd like to continue playing the 'C-note' while the arduino looks to see if a 'D-note' is played, and if so, I'd like to superpose these two 'notes', while looking to see if the 'C-note' was played again.
    – GrantG
    Commented Aug 16, 2017 at 23:12

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.