2
\$\begingroup\$

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);


 }


 }    
\$\endgroup\$
  • \$\begingroup\$ Might be more at home in the Arduino stackexchange \$\endgroup\$ – I. Wolfe Feb 17 '15 at 23:04
  • \$\begingroup\$ I don't see where buzz() function is called in your code. Also, why are you using delay in microseconds? Doesn't arduino library provide _delay_ms() or something similar? \$\endgroup\$ – Ashton H. Feb 17 '15 at 23:07
  • 1
    \$\begingroup\$ I posted the code related to the interrupt problem I am having, others things are irrelevant \$\endgroup\$ – user49395 Feb 17 '15 at 23:10
3
\$\begingroup\$

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);
    }
} 
\$\endgroup\$
  • \$\begingroup\$ You probably have to read some register, e.g. data, to clear the interrupt flag on the ADXL and thus generate further interrupts. \$\endgroup\$ – geometrikal Feb 18 '15 at 2:05
  • \$\begingroup\$ I am using a library to obtain the data from the ADXL that's why I am not explicitly reading any register in my code. Is there any other way of clearing the flag? \$\endgroup\$ – user49395 Feb 18 '15 at 2:41
  • \$\begingroup\$ Looking at the ADXL data sheet you have to read a register to clear the interrupt pin on the device. Otherwise the pin will just stay outputting active low. There is no other way. If I understand correctly, for the DATA_READY interrupt, which you are using, this is the data registers, so using the library function that reads the data out should clear the ADXL interrupt pin. \$\endgroup\$ – geometrikal Feb 18 '15 at 2:48
  • \$\begingroup\$ Yeah since I am reading the samples using the library the interrupt pin should be cleared. Not sure what's causing this.writeTo(0x1D, 0x2E, 128); //enabling DATA_READY interrupt writeTo(0x1D, 0x2F, 127); //MAP DATA_READY to INT1 INT_SOURCE register is not used \$\endgroup\$ – user49395 Feb 18 '15 at 2:54
  • \$\begingroup\$ You have to explicitly read the data after if(sensor_update==1 ){, is that what you are doing? If so, please update your code. \$\endgroup\$ – geometrikal Feb 18 '15 at 4:47

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.