I'm using interrupts to handle several button inputs. I'm using this library: http://www.arduino.cc/playground/Main/PinChangeInt to implement it. Currently I'm testing just two buttons right now. When I start the Arduino up, everything seems fine, but when I click either button for the first time, via the Serial monitor, it thinks I'm clicking the other button first and then the button I actually clicked. It only does for the first button I click and it does it for both buttons. I can't seem to figure out what is going on and was wondering if anyone had any suggestions or similar problems. Thanks!
You will most likely have to post your code to get any specific help. Also be sure you are wiring buttons correctly using pull-up or pull-down resistor to prevent floating input problems. Also you probably have to be sure to disable all unused pins on that port to prevent spurious interrupts as floating inputs, by either wiring them with resistors or setting them as output pins.
Lefty
I figured I would have to post my code.. There's quite a bit though so I'll try to sift through it and only post the code that is getting used for this part of the program. I'm going to go eat some dinner quick though, so I'll post the code when I get back later. Also, if it helps at all (until I post the code later) I hooked up a third button to see what would happen and it looks like it fires each interrupt, in no particular order, but the same order each time for a given button, when I push a button for the first time. It's weird because it's only doing this when I push a button for the first time after start up.
I'll post code in an hour or two.
Well people always point out that by not posting all the code, you are bound to be not showing the part that is causing the problem(s). Your choice, as I probably won't be the one capable of figuring it out. However posting a wiring drawing of the switches or at least a detailed description of how you are wiring them up, I can help with. Floating inputs will definitely cause you grief and can cause illogical symptoms.
Ok here's the code (I took out some parts that were irrelevant. If you want to see that too just let me know):
/*
The main program that is excecuted. This program sets up the LEDs and manages the button interrupts. It loops over a simple switch case select which image to display.
Last Update: 8-24-2011
Created on: 8-24-2011
Created by: Brandon Hildreth
*/
#include "NEWLedControl.h"
#include "PinChangeInt.h"
#include "PinChangeIntConfig.h"
//#include "ImageData.h"
int pin0 = 2;
int pin1 = 3;
int pin2 = 4;
LedControl lc=LedControl(12,11,10,4);
volatile int ledState;
volatile boolean breakLoopFlag;
boolean powerState;
int button0Clicks;
int lastButtonPressed;
//***********************************************IMAGE DATA*************************************************************
const int sizeOfCurrentLED = 32;
byte CurrentLED[32];
const int sizeOfSmiley = 32;
byte Smiley[sizeOfSmiley] = {
B00000000,B00000000,B00000000,B00000000,B00111000,B00111000,B00111000,B00000000,
B00000000,B00111000,B00111000,B00111000,B00000000,B00000000,B00000000,B00000000,
B00000000,B00000000,B00000000,B00111000,B01111000,B11111000,B11111000,B11111000,
B11111000,B11111000,B11111000,B01111000,B00111000,B00000000,B00000000,B00000000};
;
const int sizeOfFrowny = 32;
byte Frowny[sizeOfFrowny] = {
B00000000,B00000000,B00000000,B00000000,B00111000,B00111000,B00111000,B00000000,
B00000000,B00111000,B00111000,B00111000,B00000000,B00000000,B00000000,B00000000,
B00000000,B00000000,B00000000,B11100000,B11110000,B11111000,B11111000,B11111000,
B11111000,B11111000,B11111000,B11110000,B11100000,B00000000,B00000000,B00000000};
const int sizeOfHearts = 32;
byte Heart1[sizeOfHearts] = {
B00000000,B00000000,B00000000,B11000000,B11100000,B11110000,B11110000,B11100000,
B11000000,B11100000,B11110000,B11110000,B11100000,B11000000,B00000000,B00000000,
B00000000,B00000000,B00000000,B00000000,B00001000,B00011000,B00111000,B01111000,
B11111000,B01111000,B00111000,B00011000,B00001000,B00000000,B00000000,B00000000};
;
byte Heart2[sizeOfHearts] = {
B00000000,B00000000,B11000000,B11100000,B11110000,B11111000,B11111000,B11110000,
B11100000,B11110000,B11111000,B11111000,B11110000,B11100000,B11000000,B00000000,
B00000000,B00000000,B00000000,B00001000,B00011000,B00111000,B01111000,B11111000,
B11111000,B11111000,B01111000,B00111000,B00011000,B00001000,B00000000,B00000000};
;
const int sizeOfError = 32;
byte Error[sizeOfError] = {
B11111000,B11111000,B11111000,B11111000,B11111000,B11111000,B11111000,B11111000,
B11111000,B11111000,B11111000,B11111000,B11111000,B11111000,B11111000,B11111000,
B11111000,B11111000,B11111000,B11111000,B11111000,B11111000,B11111000,B11111000,
B11111000,B11111000,B11111000,B11111000,B11111000,B11111000,B11111000,B11111000};
//************************************************SETUP()****************************************************************
void setup(){
Serial.begin(9600);
pinMode(pin0,INPUT);
pinMode(pin1,INPUT);
pinMode(pin2,INPUT);
digitalWrite(pin0,HIGH);
digitalWrite(pin1,HIGH);
digitalWrite(pin2,HIGH);
PCattachInterrupt(pin0,button0ISR,RISING);
PCattachInterrupt(pin1,button1ISR,RISING);
PCattachInterrupt(pin2,button2ISR,RISING);
//set brightness below
lc.setIntensity(0,15);
lc.clearDisplay(0);
lc.setIntensity(1,15);
lc.clearDisplay(1);
lc.setIntensity(2,15);
lc.clearDisplay(2);
lc.setIntensity(3,15);
lc.clearDisplay(3);
ledState = -1;
breakLoopFlag = false;
powerState = false;
button0Clicks = 0;
lastButtonPressed = -1;
}
//*****************************************************SUPPORT METHODS**********************************************************
/*
This method updates the CurrentLED global variable to reflect the current state of the LEDs.
It takes an array as a parameter.
*/
void updateCurrentLED(byte newLED[], int sizeOfArray){
for(int i=0; i<sizeOfArray; i++) {
CurrentLED[i]= newLED[i];
}
}
/*
This method will delay like the noraml delay() method but it adds a check every millisecond for the breakLoopFlag.
This method will need to be tested for efficiency and timing.
*/
boolean delayAndCheckInterrupt(double time) {
for(int i=0; i<time/100; i++){
if(breakLoopFlag){
return true;
}
delay(100);
}
return false;
}
/*
This method writes a single image to the LEDs
*/
void writeImage(byte image[], int sizeOfArray){
int addr = 0;
int row = 0;
for(int i=0; i<sizeOfArray; i++){
if(row==8){
row=0;
addr++;
}
lc.setRow(addr,row,image[i]);
row++;
}
updateCurrentLED(image,sizeOfArray);
}
/*
This method sets the on/off state of the MAX7219s. Data can still be sent to them while in shutdown mode. The MAZZX7219s are initiallized to be off with no data already sent to them.
*/
void setLEDsPowerState(boolean newState){
if(newState){
lc.shutdown(0,false);
lc.shutdown(1,false);
lc.shutdown(2,false);
lc.shutdown(3,false);
powerState = true;
}
else{
lc.shutdown(0,true);
lc.shutdown(1,true);
lc.shutdown(2,true);
lc.shutdown(3,true);
powerState = false;
}
}
//************************************************************IMAGE METHODS***************************************************
/*
This method makes an upright :D face. Static image. This is also the default image for the LEDs.
*/
void smiley() {
while(!breakLoopFlag){
writeImage(Smiley, sizeOfSmiley);
}
breakLoopFlag = false;
}
/*
This method makes an upright D: face. Static image.
*/
void frowny() {
while(!breakLoopFlag){
writeImage(Frowny, sizeOfFrowny);
}
breakLoopFlag = false;
}
/*
This method makes a heart. Static image.
*/
void heart() {
while(!breakLoopFlag){
writeImage(Heart1, sizeOfHearts);
if(delayAndCheckInterrupt(500)){
break;
}
writeImage(Heart2, sizeOfHearts);
if(delayAndCheckInterrupt(500)){
break;
}
}
breakLoopFlag = false;
}
/*
This method will turn the LEDs off if they are on, and vice versa.
Note: the device starts off.
*/
void powerChange(){
if(powerState){
setLEDsPowerState(false);
}
else{
setLEDsPowerState(true);
}
while(!breakLoopFlag){
}
breakLoopFlag = false;
}
/*
This method is used in the default section of the switch case. It should only appear if there is an actual error.
*/
void error(){
writeImage(Error, sizeOfError);
while(!breakLoopFlag){
setLEDsPowerState(false);
delay(1000);
setLEDsPowerState(true);
delay(1000);
}
}
//****************************************************ISR METHODS************************************************************
void button0ISR(){
Serial.println("button0ISR fired");
ledState=0;
breakLoopFlag = true;
}
void button1ISR(){
Serial.println("button1ISR fired");
ledState = 1;
breakLoopFlag = true;
}
void button2ISR(){
Serial.println("button2ISR fired");
ledState=2;
breakLoopFlag = true;
}
void button3ISR(){
ledState=3;
breakLoopFlag = true;
}
//This is the ISR to turn the LEDs on or off
void button4ISR(){
ledState = 4;
breakLoopFlag = true;
}
void button5ISR(){
ledState=5;
breakLoopFlag = true;
}
void button6ISR(){
ledState=6;
breakLoopFlag = true;
}
void button7ISR(){
ledState=7;
breakLoopFlag = true;
}
void button8ISR(){
ledState=8;
breakLoopFlag = true;
}
void button9ISR(){
ledState=9;
breakLoopFlag = true;
}
//*****************************************************LOOP()****************************************************************
//
void loop() {
Serial.print("ledState: ");
Serial.println(ledState);
Serial.print("button0Clicks: ");
Serial.println(button0Clicks);
switch(ledState) {
case 0:
if(lastButtonPressed != 0){
button0Clicks = 0;
}
button0Clicks++;
Serial.print("button0Clicks: ");
Serial.println(button0Clicks);
if(button0Clicks == 1){
smiley();
}
else if(button0Clicks == 2){
frowny();
}
else{
button0Clicks = 0;
}
lastButtonPressed = 0;
break;
case 1:
heart();
lastButtonPressed = 1;
break;
case 2:
powerChange();
lastButtonPressed = 2;
break;
case 3:
lastButtonPressed = 3;
break;
case 4:
powerChange();
lastButtonPressed = 4;
break;
case 5:
lastButtonPressed = 5;
break;
case 6:
lastButtonPressed = 6;
break;
case 7:
lastButtonPressed = 7;
break;
case 8:
lastButtonPressed = 8;
break;
case 9:
lastButtonPressed = 9;
break;
default:
//error();
lc.setRow(0,0,B00000000);
}
}
What processor (chip) are you using? Personally I wouldn't be doing Serial.println in an interrupt service routine. They are supposed to quickly deal with the interrupt, not slowly pump stuff out the serial port.
bthildreth:
... but when I click either button for the first time, via the Serial monitor, it thinks I'm clicking the other button first and then the button I actually clicked...
Which buttons do you click? You seem to have a lot of ISR functions (10 of them).
case 5:
lastButtonPressed = 5;
break;
case 6:
lastButtonPressed = 6;
break;
case 7:
lastButtonPressed = 7;
break;
case 8:
lastButtonPressed = 8;
break;
How about:
lastButtonPressed = ledState;
And avoid all that stuff?