1

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
}

migrated from electronics.stackexchange.com Aug 13 '16 at 19:35

This question came from our site for electronics and electrical engineering professionals, students, and enthusiasts.

  • 1
    Sounds 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 Aug 13 '16 at 16:22
  • 1
    Are you using delay() functions in your code? – Transistor Aug 13 '16 at 16:24
  • A question like this really needs to include your code. – Chris Stratton Aug 13 '16 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 Aug 13 '16 at 17:21
  • "When push button is clicked Arduino ISR is invoked via pin 2" - where is the ISR in your code? – Bruce Abbott Aug 13 '16 at 17:25
1

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.

0

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 Aug 13 '16 at 19:56
  • That won't solve the problem if the interrupt is getting missed while interrupts are disabled. – alex.forencich Aug 13 '16 at 20:08
  • True. I didn't notice anything disabling the interrupts though. – RubberDuck Aug 13 '16 at 20:10

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.