0

I wrote a tiny C++ programm, that cross-compiles and runs on an Arduino Uno (atmega328p). It is a basic MIDI patch changer, which allows stepping through 32 slots, that contain program numbers (organized in arrays). After selecting a slot a timer runs, and when it reaches 400 ms, the program changes will be sent via serial midi protocol to the attached synthesizers. But this is not important in this case.

There are two buttons for increasing and decreasing the current program. The current program is displayed in binary with 5 LEDS. There are 32 programs to step through, 00000 representing 1 and 11111 representing 32.

So far everything works, I have made a tiny class, that represents a button and handles debouncing. So I don't think that noise is the cause of the error.

The error / bug is as follows: After some time (I could not reproduce the moment when the bug occures) the buttons trigger the action to change program twice - first when pressing, and second when releasing. Also if I press the button, wait some seconds and then release it... That is unwanted, but I cannot see where I made a mistake.

midipatcher.cpp - The entry point

#include <Arduino.h>
#include "Button.h"

int timer = 0;
int deltaTime = 0;
int currentSlot = 0;
bool waiting;
int actionDelay = 400;

Button* buttonUp;
Button* buttonDown;

int leds[] = { 9, 10, 11, 12, 13 };

byte nordLeadSlots[32] = {
  0, 1, 3, 2,
  5, 6, 9, 10,
  24, 50, 11, 12,
  25, 26, 25, 25
};

byte ms2000Slots[32] = {
  5, 6, 9, 10,
  24, 50, 11, 12,
  25, 26, 25, 25,
  0, 1, 3, 2
};

void sendSlotData() {
  Serial.write(0xC0);
  Serial.write(nordLeadSlots[currentSlot]);

  Serial.write(0xC1);
  Serial.write(ms2000Slots[currentSlot]);
}
void updateLeds() {
  for (int i = 0; i < 5; i++) {
    if (bitRead(currentSlot, i) == 1) {
        digitalWrite(leds[i], HIGH);
    } else {
        digitalWrite(leds[i], LOW);
    }
  }
}

void changeSlot(int slot) {
  if (slot > 31) {
    currentSlot = 0;
  } else if (slot < 0) {
    currentSlot = 31;
  } else {
    currentSlot = slot;
  }

  waiting = true;
  updateLeds();

  timer = millis();
}

void setup() {
  buttonUp = new Button(2);
  buttonDown = new Button(3);

  for (int i = 0; i < 5; i++) {
    pinMode(leds[i], OUTPUT);
  }

  Serial.begin(31250);
}

void loop() {
  if (buttonUp->isPressed()) {
    changeSlot(currentSlot + 1);
  }

  if (buttonDown->isPressed()) {
    changeSlot(currentSlot - 1);
  }

  deltaTime = millis() - timer;

  if (waiting == true && deltaTime > actionDelay) {
    sendSlotData();
    waiting = false;
  }
}

int main(void) {
  init();
  setup();
  while (true) {
    loop();
  }
}

Button.cpp - The code, that cares about debouncing buttons:

#include <Arduino.h>
#include "Button.h"

Button::Button(int pin) {
  debounceDelay_ = 10;

  pin_ = pin;
  state_ = LOW;
  lastDebounceTime_ = 0;

  pinMode(pin_, INPUT);
}

bool Button::isPressed() {
  if (millis() - debounceDelay_ < lastDebounceTime_) return false;

  int currentState = digitalRead(pin_);

  if (currentState != state_) {
    state_ = currentState;
    if (currentState == HIGH) {
      return true;
    }
  }
  lastDebounceTime_ = millis();
  return false;
}

I don't think that the time handling in the main class is the problem, it cares just about the 400 ms that have to pass before a program change will be sent, after selecting the slot. I have commented out that functionality, but the problem resisted.

EDIT:

This is a screenshot of the circuit, made with fritzing, sorry not the real circuit layout.

EDIT again: not.

Because my reputation is not high enough, I cannot post screenshots. The Picture is available here:

enter image description here

adricadar
  • 9,971
  • 5
  • 33
  • 46
ILCAI
  • 1,164
  • 2
  • 15
  • 35
  • When you don't press, is the pin linked to the ground or just not linked ? – Ôrel Apr 27 '15 at 07:20
  • Yes, it is linked with a pull down resistor. (Is this the right word?). I edited the original post and attached a screenshot of the sketch. – ILCAI Apr 27 '15 at 09:09
  • Did you figure out what the issue was? – RussDunn May 03 '15 at 01:58
  • No... I just built the damn thing, and after 30 - 40 button actions the problem occures. But no problem, it just takes more attention and I have to go back and forth some times until I got the desired slot. Ouch. I tried it out on a gig last saturday, and it worked out. Fun. – ILCAI May 06 '15 at 20:10

2 Answers2

0

Hi you can solve that problem using low pass filter.

Noise is a high frequency signal that comes from the surroundings, in could be an electrical noise generated when there a re reactive load in ac line.

What you can do is put a bypassed capacitor in each input pin to gnd.

or

Create a low pass filter program that only allows long state press.. a concept of a longpress button.

quickbrown
  • 93
  • 5
-1

You don't want pulldown resistors, you want to ground the switch and enable the internal pullups on the input pin. You can look at the photo of a little demo system I put together here:

https://kentindell.files.wordpress.com/2015/02/2015-02-18-15-02-16.jpg

The demo is discussed here:

https://kentindell.wordpress.com/2015/02/18/micrcontroller-interconnect-network-min-version-1-0/

The C to initialise the I/O port is here:

https://github.com/min-protocol/min/blob/master/firmware/main.c#L64

And the C code to read the input is here:

https://github.com/min-protocol/min/blob/master/firmware/main.c#L85

Ken Tindell
  • 343
  • 4
  • 7