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: