I am trying to create my own home automation using Arduino. I am using shift register for reading input(via push buttons) and writing output to led's. I am using SPI interface to communicate with shift registers.
Apart from SPI Arduino also deals with I2C devices. When push button is clicked Arduino ISR is invoked via pin 2, which then checks exact button that was pushed and takes action accordingly. The functionality currently works well with one small problem.
Sometimes when push button is clicked Arduino ignores the button press. After debugging for some time I observed that it happens when Arduino is busy with I2C communication with other devices.
I would like to know if it is possible to temporarily delay the push button input while Arduino busy with I2C communication? or is it possible to prioratize interrupt handling over I2C communication?
Below is the simplified code
#include <SPI.h>
#include <Wire.h>
byte Input=1;
volatile byte Check=1;
volatile byte Output=1;
int j;
//Pin connected to ST_CP of 74HC595
int latchPin = 8;
//Pin connected to SH_CP of 74HC595
int clockPin = 13;
////Pin connected to DS of 74HC595
int dataPin = 11;
int interruptPin=2;
int espPin=7;
char arduinoStatus[100]="0円";
void pin_read(){
for(j=0; j<50; j++)
delayMicroseconds(1000);
Check=1;
for(j=0; j<8; j++){
digitalWrite(latchPin, LOW);
delayMicroseconds(500);
SPI.transfer(Check);
SPI.transfer(Output);
digitalWrite(latchPin, HIGH);
delayMicroseconds(500);
if(digitalRead(interruptPin)==HIGH){
//Serial.println(Check);
if(bitRead(Output, j)==1)
bitWrite(Output, j, 0);
else
bitWrite(Output, j, 1);
}//dig check
Check = Check<<1;
}
digitalWrite(latchPin, LOW);
delayMicroseconds(500);
SPI.transfer(255); //to push buttons
SPI.transfer(Output); //to LEDs
digitalWrite(latchPin, HIGH);
delayMicroseconds(500);
}//pin_read
void setup() {
//set pins to output so you can control the shift register
pinMode(latchPin, OUTPUT);
pinMode(clockPin, OUTPUT);
pinMode(dataPin, OUTPUT);
pinMode(espPin, OUTPUT);
pinMode(interruptPin, INPUT);//Input from buttons
delay(1000);
// the LEDs don't change while you're sending in bits:
digitalWrite(latchPin, LOW);
SPI.setBitOrder(MSBFIRST);
SPI.setDataMode(SPI_MODE0);
SPI.setClockDivider(SPI_CLOCK_DIV2);
SPI.begin();
SPI.transfer(255);
SPI.transfer(255);
//take the latch pin high so the LEDs will light up:
digitalWrite(latchPin, HIGH);
Serial.begin(115200);
attachInterrupt(0, pin_read, RISING);
Wire.begin(8); // join i2c bus with address #8
Wire.onRequest(requestEvent); // register event
Wire.onReceive(receiveEvent);
Serial.println("Initialized...");
}
void loop() {
Serial.println("Interrupting...");
digitalWrite(espPin, HIGH);
while(digitalRead(interruptPin)==HIGH){}
delayMicroseconds(500);
digitalWrite(espPin, LOW);
delayMicroseconds(500);
Serial.println("Done...");
Serial.print("Output:");
Serial.println(Output);
delay(3000);
}
// function that executes whenever data is received from master
// this function is registered as an event, see setup()
void receiveEvent(int howMany) {
int i=0;
Serial.println("received::");
while (Wire.available()) { // loop through all
char c = Wire.read(); // receive byte as a character
arduinoStatus[i++]=c;
Serial.print(c); // print the character
}
arduinoStatus[i]='0円';
Serial.println("###");
}
// function that executes whenever data is requested by master
// this function is registered as an event, see setup()
void requestEvent() {
Serial.println("Sending...");
Wire.write("hello"); // respond with message of 6 bytes
Wire.write(Output);
Serial.println("Sent");
// as expected by master
}
-
1Sounds like you need to re-organize your software, in particular you probably need to use non-blocking I2C routines, at least if you have any peripherals that do clock-stretching. Most likely you could get away with only servicing the user inputs between i2c words, but if clock-stretching is possible, they could take longer.Chris Stratton– Chris Stratton2016年08月13日 16:22:21 +00:00Commented Aug 13, 2016 at 16:22
-
1Are you using delay() functions in your code?Transistor– Transistor2016年08月13日 16:24:03 +00:00Commented Aug 13, 2016 at 16:24
-
A question like this really needs to include your code.Chris Stratton– Chris Stratton2016年08月13日 16:24:59 +00:00Commented Aug 13, 2016 at 16:24
-
@ChrisStratton,@Transistor: have tried to search for non blocking I2C library for Arduino, but it looks like many people are looking for the same and not finding., I have posted the simplified code I am using.Xinus– Xinus2016年08月13日 17:21:11 +00:00Commented Aug 13, 2016 at 17:21
-
"When push button is clicked Arduino ISR is invoked via pin 2" - where is the ISR in your code?Bruce Abbott– Bruce Abbott2016年08月13日 17:25:54 +00:00Commented Aug 13, 2016 at 17:25
2 Answers 2
Without looking any further than the first delaymicroseconds()
command I would say that that's where the trouble lies. The delay()
functions are very handy for getting the beginner's first LED to blink and are a big problem after that. The problem is that the CPU is completely tied up during the delay and can't do anything else other than interrupts and you only have a limited supply of those. Your button press is missed.
You need to develop your own timers in the code and keep the main loop running constantly checking on each pass to see if the delay is complete.
What about polling the buttons periodically instead of using an interrupt? If you check them every 10 ms or so, you should still be able to detect a button press reliably. Connecting buttons to interrupt inputs is not necessarily the best idea due to contact bounce - this can cause a number of back-to-back interrupts. My guess is that interrupts are being disabled during some part of your code and when the interrupt pin level changes during that period, it gets ignored.
-
Close. I would use the interrupt to set a flag. Then, in the main loop, you process the button press whenever the loop comes back around.RubberDuck– RubberDuck2016年08月13日 19:56:25 +00:00Commented Aug 13, 2016 at 19:56
-
That won't solve the problem if the interrupt is getting missed while interrupts are disabled.alex.forencich– alex.forencich2016年08月13日 20:08:21 +00:00Commented Aug 13, 2016 at 20:08
-
True. I didn't notice anything disabling the interrupts though.RubberDuck– RubberDuck2016年08月13日 20:10:13 +00:00Commented Aug 13, 2016 at 20:10