Why does this script not work correctly?

#include <frequencyToNote.h>
#include <MIDIUSB.h>
#include <pitchToFrequency.h>
#include <pitchToNote.h>

#define INPUT_PIN_7 7
#define SELECT_PIN_8 8
#define SELECT_PIN_9 9
#define SELECT_PIN_10 10
#define SELECT_PIN_11 11

unsigned long debounce;


void controlChange(byte channel, byte control, byte value) {
  midiEventPacket_t event = {0x0B, 0xB0 | channel, control, value};
  MidiUSB.sendMIDI(event);
}

void setup() {
  // put your setup code here, to run once:
    Serial.begin(9600);

    pinMode(SELECT_PIN_8, OUTPUT); //setting multiplexer selector pins to output
    pinMode(SELECT_PIN_9, OUTPUT);
    pinMode(SELECT_PIN_10, OUTPUT);
    pinMode(SELECT_PIN_11, OUTPUT);

    pinMode(INPUT_PIN_7, INPUT); //setting multiplexer input to pin 7 input
}

void loop() {
    digitalWrite(SELECT_PIN_8, LOW); //selecting Y0 input on the multiplexer
    digitalWrite(SELECT_PIN_9, LOW);  //selecting Y0 input on the multiplexer
    digitalWrite(SELECT_PIN_10, LOW);  //selecting Y0 input on the multiplexer
    digitalWrite(SELECT_PIN_11, LOW);  //selecting Y0 input on the multiplexer

    if (digitalRead(INPUT_PIN_7) == HIGH && millis() - debounce > 100){
      controlChange(0,1,1);
      debounce = millis();
    }
}

controlChange is from the MIDIUSB library. I am using some software to monitor midi inputs and when I click the button once it writes like 200 lines of inputs or something, then stops. "debounce" is an unsigned long variable.

The way I expect this to work is that when the button is pressed (HIGH) and the current millis-debounce is greater than 100ms it will send the control change, then update debounce to be the current time so as to stop multi triggering. But all it seems to do is spam the output a bunch then stop.

The code you posted looks like it probably does exactly as it's supposed to. The code you didn't post is causing the problem.

But all it seems to do is spam the output a bunch then stop.

Might it not be better to act when the input becomes HIGH rather than when it is HIGH ? See the StateChangeDetection example in the IDE.

How is the input wired ?
Do you have a pulldown resistor in place to keep the input LOW until the pin is taken HIGH or is the pin floating at an unknown voltage most of the time ?

The code you posted looks like it probably does exactly as it's supposed to.

To be certain, you'd need to research operator precedence. Me, I'm too lazy to do that, so I use parentheses to force the operators to be evaluated in the order I want.

DKWatson:
The code you posted looks like it probably does exactly as it's supposed to. The code you didn't post is causing the problem.

This is the only code in the void loop. The only other thing I could think of is maybe the function I got from the MIDIUSB library is causing it?

I will post the entirety when I get home.

UKHeliBob:
Might it not be better to act when the input becomes HIGH rather than when it is HIGH ? See the StateChangeDetection example in the IDE.

How is the input wired ?
Do you have a pulldown resistor in place to keep the input LOW until the pin is taken HIGH or is the pin floating at an unknown voltage most of the time ?

I am trying out a multiplexer. Basically all that is going on that you don't see here is:

digitalWrite(multiplexer pins, LOW)... I set all my multiplexer selector pins to LOW while I just test this single input, and digitalRead(7) -- the input pin, Z out on the multiplexer. The single button hooked up is going into Y0 on the multiplexer. 5V only flows through when the button is pressed, it is a momentary switch. So I don't believe the multiplexer would ever read any 'unknown voltage', its 5V or nothing.

I am afraid I am not familiar with pulldown resistors. I figured since its a momentary switch is it definitely only high/low depending on whether its being pressed or not.

thanks

I figured since its a momentary switch is it definitely only high/low depending on whether its being pressed or not.

Interesting. How do you figure that?

I figured since its a momentary switch is it definitely only high/low depending on whether its being pressed or not.

What makes its states HIGH and LOW ? How is it wired ?

It sounds like when your button is OPEN the input to the multiplexer is left floating. If it floats to HIGH your output will happen every 100 milliseconds.

To do state change detection you have to save the previous state.

void loop()
{
  unsigned long currentTime = millis();
  static boolean buttonAlreadyPressed = false;
  static unsigned long buttonStateChangeTime = 0;


 boolean buttonPressed = digitalRead(INPUT_PIN_7) == HIGH;  // Active HIGH

  // Check for button change and do debounce
  if (buttonPressed != buttonAlreadyPressed &&
      currentTime -  buttonStateChangeTime > 100)
  {
    // Button state has changed
    buttonStateChangeTime = currentTime;
    buttonAlreadyPressed = buttonPressed;


    if (buttonPressed)
    {
      // Button was just pressed
[color=#222222]   controlChange(0,1,1);[/color]
    }
  }
}

AWOL:
Interesting. How do you figure that?

pretty simple, i don't know what i'm doing! Well, since 5V is ONLY passing through when the button is pressed (how I have it wired), I don't see how it could be anything BUT high/low. If the button is pressed, the 5V leads connect and 5v is sent to the multiplexer... if its not pressed, there is no voltage going through at all. Unless I am vastly misunderstanding how high/low works, I thought this made sense.

UKHeliBob:
What makes its states HIGH and LOW ? How is it wired ?

5V goes into the button, the 'output' pin of the button is connected to the multiplexer. Therefore, I figured the multiplexer will always be reading no voltage from that input unless the button is currently making contact (passing through voltage). However, I have been wrong before. :slight_smile:

johnwasser:
It sounds like when your button is OPEN the input to the multiplexer is left floating. If it floats to HIGH your output will happen every 100 milliseconds.

To do state change detection you have to save the previous state.

void loop()

{
  unsigned long currentTime = millis();
  static boolean buttonAlreadyPressed = false;
  static unsigned long buttonStateChangeTime = 0;

boolean buttonPressed = digitalRead(INPUT_PIN_7) == HIGH;  // Active HIGH

// Check for button change and do debounce
  if (buttonPressed != buttonAlreadyPressed &&
      currentTime -  buttonStateChangeTime > 100)
  {
    // Button state has changed
    buttonStateChangeTime = currentTime;
    buttonAlreadyPressed = buttonPressed;

if (buttonPressed)
    {
      // Button was just pressed
  controlChange(0,1,1);
    }
  }
}

Thanks John. Perhaps I am misunderstanding how Arduino reads button states. The button I am using is momentary, there is either voltage passing through, or there's not. It is my understanding that if I am passing 5V through the button the Arduino should recognize that as a "HIGH" input, and if there is no voltage, "LOW".

Your example makes sense to me if I were to hold the button down for more than 100ms. I understand that it would basically cycle ever 100ms. However, a single fast click of the button causes it to trigger many more times than I would expect it to... even if I change the delay to 1000ms. This code, currently, is really the first thing i've ever written from scratch in C, or any language for that matter, so I am just going rudimentary with it as far as the debounce is concerned. I just want to get it to work first, then I will fine tune.

Also, as I mentioned elsewhere, this may just have something to do with the MIDIUSB library.

Google "arduino floating pin".

Here's what a quick look turned up on StackExchange:

What you have is called a Floating pin. Digital Input pins are very sensitive to change, and unless positively driven to one state or another (High or Low), will pick up stray capacitance from nearby sources, like breadboards, human fingers, or even the air. Any wire connected to it will act like a little antenna and cause the input state to change. And I mean any wire, the trace on the board, the wire to the breadboard, the breadboard pin, even the metal pin of the IC itself.

This is refereed to in the Arduino reference page:

If the pin isn't connected to anything, digitalRead() can return either HIGH or LOW (and this can change randomly).

If you look at the Arduino Digital Pin Tutorial:

This also means however, that input pins with nothing connected to them, or with wires connected to them that are not connected to other circuits, will report seemingly random changes in pin state, picking up electrical noise from the environment, or capacitively coupling the state of a nearby pin.

Often it is useful to steer an input pin to a known state if no input is present. This can be done by adding a pullup resistor (to +5V), or a pulldown resistor (resistor to ground) on the input, with 10K being a common value. There are also convenient 20K pullup resistors built into the Atmega chip that can be accessed from software. These built-in pullup resistors are accessed in the following manner.

pinMode(pin, INPUT); // set pin to input
digitalWrite(pin, HIGH); // turn on pullup resistors
These weak pull resistors force the input pin state into a known state, and are easily overwritten by stronger input voltages, like a direct connection to ground or +5v.

evanmars:
Google "arduino floating pin".

Here's what a quick look turned up on StackExchange:

Thanks for this. Isn't there a pinMode for PULLUP? Or is that something different

johnwasser:
It sounds like when your button is OPEN the input to the multiplexer is left floating. If it floats to HIGH your output will happen every 100 milliseconds

John, I tried using your code verbatim in my void loop. I threw in some Serial.println to check if the "if" statements were executing, it appears they are... however, the controlChange function appears to do nothing. I have checked that all the #INCLUDE statements are present, and the function is above the void setup. Oddly enough, if I re-load my original code, the controlChange function works, albeit, with the poor button triggering.

I thought I was confused before, but now it's worse! :slight_smile:

This is the updated code with yours in the void loop.

#include <frequencyToNote.h>
#include <MIDIUSB.h>
#include <pitchToFrequency.h>
#include <pitchToNote.h>

#define INPUT_PIN_7 7
#define SELECT_PIN_8 8
#define SELECT_PIN_9 9
#define SELECT_PIN_10 10
#define SELECT_PIN_11 11

void controlChange(byte channel, byte control, byte value) {
  midiEventPacket_t event = {0x0B, 0xB0 | channel, control, value};
  MidiUSB.sendMIDI(event);
}

void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);
  pinMode(SELECT_PIN_8, OUTPUT); //setting multiplexer selectors to output
  pinMode(SELECT_PIN_9, OUTPUT);
  pinMode(SELECT_PIN_10, OUTPUT);
  pinMode(SELECT_PIN_11, OUTPUT);

  digitalWrite(SELECT_PIN_8, LOW); //hard code to select input Y0 on multiplexer
  digitalWrite(SELECT_PIN_9, LOW);
  digitalWrite(SELECT_PIN_10, LOW);
  digitalWrite(SELECT_PIN_11, LOW);

  pinMode(INPUT_PIN_7, INPUT);
}

void loop() {
  unsigned long currentTime = millis();
  static boolean buttonAlreadyPressed = false;
  static unsigned long buttonStateChangeTime = 0;


 boolean buttonPressed = digitalRead(INPUT_PIN_7) == HIGH;  // Active HIGH

  // Check for button change and do debounce
  if (buttonPressed != buttonAlreadyPressed &&
      currentTime -  buttonStateChangeTime > 10)
  {
    // Button state has changed
    buttonStateChangeTime = currentTime;
    buttonAlreadyPressed = buttonPressed;
    Serial.println("first if");

    if (buttonPressed)
    {
      // Button was just pressed
      controlChange(0,1,1);
      Serial.println("Second if");
    }
  }

}

pressing the button prints this to the serial monitor

first if
second if
** a few seconds later**
first if

I'm not sure why there is a long delay between the loop reading again. However, my MIDI monitor shows no midi activity, whereas on my original code, it does seem to work, but I don't see why this would be any different.

Thanks in advance for any help.

Hi Aimbit,

Yes, you are indeed misunderstanding how a button and Arduino work electronically. Plus you are using a lot of code all at the same time. The key to getting an Arduino project working, is to do things one step at a time. As the momentary button is giving you problems, and changing and reading the pin states is fundamental to way Arduino (in fact any microcontroller) works.

So start with just the button code. Set all the library, MIDI, etc. stuff aside, concentrate on the button. Take an Arduino, any Arduino will do, but I'm gonna assume you have a Uno for the purposes of this exercise. Wire a momentary push button between a digital pin, say pin 2, and the other side of the switch to ground. So far there is no voltage anywhere. When the button is pressed, the pin closes, and is in contact with the ground. When you release the button, it opens and the switch is not connected to anything.

When it's closed, the pin is LOW. When it's open, the pin is not HIGH, nor is it LOW. But since, as you said, there is only HIGH and LOW, the pin will sometimes read HIGH, and sometimes LOW. Almost at random (in fact this phenominon is often used to seed a pseudo-random number generator.)

To make it HIGH, the pin needs to be deliberately "pulled up", that means that it is connected to the operating voltage through a resistor. You can put a physical resistor (10K ohms works well) between the switch pin, and the 5V pin. The pin is now pulled up to 5 volts when it is open, and the pin reads HIGH when the button is not pushed (the switch is open.)

When you press the button now, the current from the applied voltage can run right to ground, and the pin "sees" the ground, not the 5 volts, because the ground is in direct contact with the pin, but the 5 volts is ten thousand ohms away. Release the button, and it's now only in contact with 5 volts, even though the resistor is still there, there is no direct connection to the ground to compete with it.

As you also mentioned, INPUT_PULLUP is indeed a parameter to pinMode(). Using that parameter, you don't need to use an external resistor. It activates a resistor that is inside the Arduino's IC chip, that connects the pin to 5 volts through a very small resistor that is 20K-50K ohms. This performs exactly the same function as the external resistor, but there is one less thing you need in the circuit.

The following code illustrates this:

const byte inputPin = 2;  // pin --> ground

boolean inputState = false;
boolean lastInputState = false;

void setup() {
  pinMode(inputPin, INPUT_PULLUP);
  Serial.begin(115200);
}

void loop() {
  inputState = !digitalRead(inputPin);  // check the state of the pin
  if (inputState != lastInputState) {     // if it has changed since last time ...
    Serial.println(inputState);              //   and show the pin's state on the serial monitor
    lastInputState = inputState;          //   and update 'lastInputState' for next time
  }
}

This code also shows why you need to "debounce" the switch.

ChrisTenone:
Hi Aimbit,

Yes, you are indeed misunderstanding how a button and Arduino work electronically. Plus you are using a lot of code all at the same time. The key to getting an Arduino project working, is to do things one step at a time. As the momentary button is giving you problems, and changing and reading the pin states is fundamental to way Arduino (in fact any microcontroller) works.

Thanks, Chris. I was not aware that the voltage just 'floats', figured it was an all or none situation. I am assuming the way I have the button wired will affect how it is reading... I currently have 5V going in, and when it closes, the output is right to the multiplexer. I have nothing going to ground directly. Is this an issue?

I will try this whole setup sans multiplexer and see how it works. So in INPUT_PULLUP state, the default digitalRead will be HIGH, correct?

and just for clarity, what does this line return? inputState = !digitalRead(inputPin);
Meaning, is HIGH equal to true or false?

thanks

Aimbit:
I currently have 5V going in, and when it closes, the output is right to the multiplexer. I have nothing going to ground directly. Is this an issue?

What exactly do you mean by this? Perhaps a quick sketch? Is this an issue, maybe. Depends on many things, not the least of which is whether you know, or are prepared to learn, enough about basic electronic circuit design to have it explained to you. If not, just ignore it and follow advice.

DKWatson:
What exactly do you mean by this? Perhaps a quick sketch? Is this an issue, maybe. Depends on many things, not the least of which is whether you know, or are prepared to learn, enough about basic electronic circuit design to have it explained to you. If not, just ignore it and follow advice.

I have been reading a small electronics textbook actually. I have a decent amount of knowledge, but no practical experience/know how.

Basically, my button has 4 pins, 3 of them are connected to each other internally, 1 is not. Pressing the button bridges the gap between all the pins. I ran the Arduino 5V out to one of the three pins, and then the 4th non-connected pin is wired to my multiplexer's Y0 input.

Aimbit:
... just for clarity, what does this line return? inputState = !digitalRead(inputPin);
Meaning, is HIGH equal to true or false?

As you surmised, for the 'switch open' state (button is not pressed), digitalRead(inputPin) returns HIGH.

An exclamation point means not. Placed in front of digitalRead(), inverts the result of the following operation. So if a function returns true (or HIGH, or any value other than zero), then ! will return false (or LOW, or zero.)