Electronic – arduino – ADXL345 Arduino UNO data_ready interrupt

accelerometerarduinointerrupts

I would like the sensor values to be updated each 10ms(100Hz) and then run the algorithm and repeat the same process. However, after timing the algorithm it is taking only 2ms, I think the data_ready interrupt is not working as expected. Physical hardware connection is from INT1 of ADXL345 to pin2 of the UNO.

#include <Wire.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_ADXL345_U.h>
#include <avr/io.h>
#include <avr/power.h>

#define F_CPU 16000000UL 

volatile int sensor_update=0;

//Write to ADXL345 registers
void writeTo(int device, byte address, byte val) {
   Wire.beginTransmission(device); //start transmission to device 
   Wire.write(address);        // send register address
   Wire.write(val);        // send value to write
   Wire.endTransmission(); //end transmission
}

//ISR function

  void interrupt(void){
  sensor_update=1;
  }

void buzz(int targetPin, long frequency, long length) {
  long delayValue = 1000000/frequency/2; // calculate the delay value between transitions
  //// 1 second's worth of microseconds, divided by the frequency, then split in half since
  //// there are two phases to each cycle
  long numCycles = frequency * length/ 1000; // calculate the number of cycles for proper timing
  //// multiply frequency, which is really cycles per second, by the number of seconds to 
  //// get the total number of cycles to produce
  for (long i=0; i < numCycles; i++){ // for the calculated length of time...
    digitalWrite(targetPin,HIGH); // write the buzzer pin high to push out the diaphram
    delayMicroseconds(delayValue); // wait for the calculated delay value
    digitalWrite(targetPin,LOW); // write the buzzer pin low to pull back the diaphram
    delayMicroseconds(delayValue); // wait againf or the calculated delay value
  }
}

/* Assign a unique ID to this sensor at the same time */
Adafruit_ADXL345_Unified accel = Adafruit_ADXL345_Unified(12345);

void setup(void) 
{
  if (F_CPU == 16000000) clock_prescale_set(clock_div_1);
  Serial.begin(9600);
  //Serial.println("Accelerometer Test"); Serial.println("");

  pinMode(4, OUTPUT);// buzzer output pin

  /* Initialise the sensor */
  if(!accel.begin())
  {
    /* There was a problem detecting the ADXL345 ... check your connections */
    //Serial.println("Ooops, no ADXL345 detected ... Check your wiring!");
    while(1);
  }

  /* Set the range to whatever is appropriate for your project */
  accel.setRange(ADXL345_RANGE_16_G);
  accel.setDataRate(ADXL345_DATARATE_100_HZ);
  // displaySetRange(ADXL345_RANGE_8_G);
  // displaySetRange(ADXL345_RANGE_4_G);
  // displaySetRange(ADXL345_RANGE_2_G);

  //Create an interrupt that will trigger when a tap is detected.
  attachInterrupt(0, interrupt, RISING);

  writeTo(0x1D, 0x2E, 0);
  writeTo(0x1D, 0x2F, 0);
  writeTo(0x1D, 0x2E, 128);
  writeTo(0x1D, 0x2F, 127);
}

void loop(void) 
{


  if(sensor_update==1 ){
    //When sensor_update is set to 1 in the ISR,the algorithm process the data from the accelerometer being updated every 10ms(100Hz)
     sensor_update=0;//reset

  }
}

Update:

#include <Wire.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_ADXL345_U.h>
#include <avr/io.h>
#include <avr/power.h>


#define F_CPU 16000000UL 



int state=0; //0--active detecting; 1--sleeping
int state_count=0; //sleeping trigger between 2 states
double mag[40];
int i=0;
double acc_rate[39];
int hunt_sub=0;
int exit_marker=-10,trough_marker=-30,peak_marker=-10;
volatile int sensor_update=0;
byte buff[1] ;


volatile unsigned long time=0, time0=0,time_dis=0,time_array[40]={0};

//----------------------------------------------------------------------------------------------

//Read ADXL345 registers
void readFrom(int device, byte address, int num, byte buff[]) {
Wire.beginTransmission(device); //start transmission to device 
Wire.write(address);        //sends address to read from
Wire.endTransmission(); //end transmission

Wire.beginTransmission(device); //start transmission to device (initiate again)
Wire.requestFrom(device, num);    // request 1 byte from device

int i = 0;
while(Wire.available())    //device may send less than requested (abnormal)
{ 
buff[i] = Wire.read(); // receive a byte
i++;
}
Wire.endTransmission(); //end transmission
}

//Write to ADXL345 registers
void writeTo(int device, byte address, byte val) {
Wire.beginTransmission(device); //start transmission to device 
Wire.write(address);        // send register address
Wire.write(val);        // send value to write
Wire.endTransmission(); //end transmission
}



//----------------------------------------------------------------------------------------------

/////////////////////////////////////////////////////////////////////////////////////////////

//ISR function

void interrupt(void){
sensor_update=1;
//  time0 = time;
//   time= millis();
//        time_dis=time-time0;
//        if(i<40){
//          time_array[i]=time_dis;
//    }
 //readFrom(0x53, 0x30, 1, buff); //clear interrupt
}





/* Assign a unique ID to this sensor at the same time */
Adafruit_ADXL345_Unified accel = Adafruit_ADXL345_Unified(12345);





void setup(void) 
{
if (F_CPU == 16000000) clock_prescale_set(clock_div_1);
Serial.begin(9600);
//Serial.println("Accelerometer Test"); Serial.println("");

pinMode(4, OUTPUT);// buzzer output pin
//pinMode(2, INPUT);

/* Initialise the sensor */
if(!accel.begin())
{
/* There was a problem detecting the ADXL345 ... check your connections */
//Serial.println("Ooops, no ADXL345 detected ... Check your wiring!");
while(1);
}

/* Set the range to whatever is appropriate for your project */
accel.setRange(ADXL345_RANGE_16_G);
accel.setDataRate(ADXL345_DATARATE_1_56_HZ);
// displaySetRange(ADXL345_RANGE_8_G);
// displaySetRange(ADXL345_RANGE_4_G);
// displaySetRange(ADXL345_RANGE_2_G);

/* Display some basic information on this sensor */
//displaySensorDetails();

/* Display additional settings (outside the scope of sensor_t) */
//displayDataRate();
//displayRange();
//Serial.println("");

//Create an interrupt that will trigger when a tap is detected.

writeTo(0x1D, 0x2E, 0);// disable interrupt

attachInterrupt(0, interrupt, RISING);
writeTo(0x53, 0x2F, 0); //map data_ready to INT1
writeTo(0x53, 0x2E, 128); //enable data_ready




}

void loop(void) 
{


sensors_event_t event; 
readFrom(0x53, 0x30, 1, buff); //read the acceleration data from the ADXL345   (device,register to read from,number of bytes,array to store in)  
while(buff[0] & 0b10000000){
accel.getEvent(&event);
} 

 Serial.print("buff: "); Serial.print(buff[0], BIN); Serial.print("  ");
 delay(10);

 mag_calculation (event.acceleration.x, event.acceleration.y, event.acceleration.z);
 detachInterrupt(0);


 if(sensor_update==1 ){
 //When sensor_update is set to 1 in the ISR,the algorithm process the data from the accelerometer being updated every 10ms(100Hz)
 //rest of algorithm is here
 sensor_update=0;//reset
 attachInterrupt(0, interrupt, RISING);


 }


 }    

Best Answer

Remove this line from the loop:

/* Get a new sensor event */ 
  interrupt();

You don't need to call the interrupt routine. Interrupts work by interrupting the main program flow when ever an interrupt condition is met, then executing the interrupt service routine (in your case interrupt()) then back to where ever the program left off.

attachInterrupt(0, interrupt, RISING); is a function that enables an interrupt, in this case rising edge on INT0, and tells it what function to jump to (interrupt) when the interrupt condition is met.

The way you have it now, it is setting sensor_update=1; as fast as the loop can loop.

From comments:

void loop(void) 
{
    sensors_event_t event; 

The following will loop forever if the the flag is set as buff[0] is not updated:

    readFrom(0x53, 0x30, 1, buff);
    while(buff[0] & 0b10000000){
        accel.getEvent(&event);
    } 

Instead read the data then check the flag using a do loop:

    do {
        accel.getEvent(&event);
        readFrom(0x53, 0x30, 1, buff);
    } while(buff[0] & 0b10000000);

The rest of the code:

    Serial.print("buff: "); Serial.print(buff[0], BIN); Serial.print("  ");

    delay(10);
    mag_calculation (event.acceleration.x, 
                     event.acceleration.y, 
                     event.acceleration.z);

Remove the detach interrupt, it is not needed. The MCU will clear its interrupt flag when the code enters the ISR. By detaching here, the interrupt is disabled, and if sensor_update was 0 then it would never be enabled again by your following code.

    detachInterrupt(0);

    if(sensor_update==1 ) {
        sensor_update=0;//reset

Likewise remove the attach interrupt.

        attachInterrupt(0, interrupt, RISING);
    }
}