NEED NICK GAMMON's HELP! Using interrupt code with MPU9150 raw data

Hello,

I've posted similar questions in the "Sensor" section of the forum, but have had little response. I thought I might try posting my code here to see if anyone could be of assistance.

I am running this code with a piezo sensor connected to an Arduino Pro Mini on A1. I also have an MPU9150 connected to the same arduino with all of the correct connections, including the INT pin connected to digital pin 2 on the arduino. I am only wanting to retrieve the (mx) values, and ONLY when my piezo sensor has been tapped. So far all of the adjustments I have tried with the code still give me just a continuous stream of output from the MPU9150 sensor. I understand that the accelerometer can act as a 'tap detect', but I have found no functioning arduino code that works with the MPU9150 for the interrupts.

Thanks in advance for any help!


#include "Wire.h"

#include "I2Cdev.h"
#include "MPU6050.h"

MPU6050 accelgyro;

int16_t ax, ay, az;
int16_t gx, gy, gz;
int16_t mx, my, mz;

const byte TAP = A1;
const byte SENSE = 2;

#define LED_PIN 13
bool blinkState = false;

void switchPressed ()
{
if (analogRead (TAP) == LOW)
digitalWrite (SENSE, LOW);
else
digitalWrite (SENSE, HIGH);
}

void setup() {

Wire.begin();
Serial.begin(9600);

Serial.println("Initializing I2C devices...");
accelgyro.initialize();

Serial.println("Testing device connections...");
Serial.println(accelgyro.testConnection() ? "MPU6050 connection successful" : "MPU6050 connection failed");

pinMode (TAP, INPUT);
digitalWrite (SENSE, LOW);
attachInterrupt (0, switchPressed, RISING);

pinMode(LED_PIN, OUTPUT);
}

void loop() {
if (analogRead (TAP) == LOW)
accelgyro.getMotion9(&ax, &ay, &az, &gx, &gy, &gz, &mx, &my, &mz);

Serial.print(mx);

blinkState = !blinkState;
digitalWrite(LED_PIN, blinkState);
}

Since you seem to know who Nick is, try reading his two posts at the top of the forum that describe how to use this forum. Namely the part about using code tags when posting code so it is readable and copyable into an editor.

if (analogRead (TAP) == LOW)

analogRead will not always read exactly zero. Perhaps you meant to do a digitalRead here?

void loop() {
 if (analogRead (TAP) == LOW)
    accelgyro.getMotion9(&ax, &ay, &az, &gx, &gy, &gz, &mx, &my, &mz);

  
    
    Serial.print(mx); 
   
    
     
    blinkState = !blinkState;
    digitalWrite(LED_PIN, blinkState);
}

How many of those lines did you mean to be conditional? Only the reading from the accelgyro will be this way. The Serial print and everything else will run every time loop is called, sending data very rapidly to the screen and blinking the led so fast you won't be able to see it.

LOL.

Addressing your question to one person is like doing a PM.

Don't you think anyone else can help?

Please use code tags.

Read this before posting a programming question

How to use this forum

Sorry, here is the code I am running:

#include "Wire.h"


#include "I2Cdev.h"
#include "MPU6050.h"


MPU6050 accelgyro;

int16_t ax, ay, az;
int16_t gx, gy, gz;
int16_t mx, my, mz;

const byte TAP = A1;
const byte SENSE = 2;

#define LED_PIN 13
bool blinkState = false;

void switchPressed ()
{
  if (analogRead (TAP) == LOW)
    digitalWrite (SENSE, LOW);
    else
    digitalWrite (SENSE, HIGH);
}


void setup() {
    
    Wire.begin();
    Serial.begin(9600);

    
    Serial.println("Initializing I2C devices...");
    accelgyro.initialize();

    
    Serial.println("Testing device connections...");
    Serial.println(accelgyro.testConnection() ? "MPU6050 connection successful" : "MPU6050 connection failed");

    pinMode (TAP, INPUT);
    digitalWrite (SENSE, LOW);
    attachInterrupt (0, switchPressed, RISING);
    
    pinMode(LED_PIN, OUTPUT);   
}

void loop() {
 if (analogRead (TAP) == LOW)
    accelgyro.getMotion9(&ax, &ay, &az, &gx, &gy, &gz, &mx, &my, &mz);

  
    
    Serial.print(mx); 
   
    
     
    blinkState = !blinkState;
    digitalWrite(LED_PIN, blinkState);
}

I have analogRead because I have a piezo sensor connected to my arduino pro mini. I would like to only retrieve data from the MPU9150 when it has been tapped. I've tried implementing code from Nick Gammon's forum on Interrupts, but am lost at this point. If there is code for the MPU9150 that would allow me to engage it's tapping function, instead of using a piezo connected to A1, that would be preferred.

Also Nick, thank you for your reply. I do think many people could probably help, but I have looked at your work and seen your expertise and also how frequently you post on this forum. I'm on a deadline with this project, and really just need any help that anyone could offer.

I have analogRead because I have a piezo sensor connected to my arduino pro mini.

analogRead takes around 100us.
An interrupt service routine is not a great place for such a delay.

KAS12:
I have analogRead because I have a piezo sensor connected to my arduino pro mini. I would like to only retrieve data from the MPU9150 when it has been tapped. I've tried implementing code from Nick Gammon's forum on Interrupts, but am lost at this point. If there is code for the MPU9150 that would allow me to engage it's tapping function, instead of using a piezo connected to A1, that would be preferred.

Also Nick, thank you for your reply. I do think many people could probably help, but I have looked at your work and seen your expertise and also how frequently you post on this forum. I'm on a deadline with this project, and really just need any help that anyone could offer.

Presumably you want to read the MPU9150 at the moment the piezo is tapped. You have two obvious problems.

First you need to detect that the piezo has been tapped and this likely requires you to pre-condition the piezo signal so that it can trigger an interrupt. The pre-conditioning may need to be an amplifier but you might get away with just feeding the piezo output directly into one of the analog comparator inputs (maybe with some protective diodes) configured invoke an interrupt . You will only know for sure when you have examined the piezo waveform (an oscilloscope will help here). Once you can detect the piezo tap you can go on to dealing with the accelerometer.

Second, reading between the lines, you seem to be trying to measure the peek acceleration. If so, then by the time you have detected the tap it will probably be too late start a read on the accelerometer. It looks to me like you will need to read the accelerometer continuously storing values values that can be examined once the tap has been detected. A ring buffer would help here.

At this point I am struggling to see the point of the piezo since you can continuously process the accelerometer data looking for peeks which will indicate a tap.

Presumably you want to read the MPU9150 at the moment the piezo is tapped. You have two obvious problems.

How did you arrive at that presumption?

that would allow me to engage it's tapping function, instead of using a piezo

So the mpu6050 INT is connected to pin 2 (interrupt 0) but you never tell the 6050 what you want it to interrupt you for? So that will never fire.

An analog read in the ISR seems OK to me. (Typo fixed)

Then LOW is not an appropriate vale to use with analog comparisons. An analog pin will never be LOW.

Then there's the problem with the indenting making it look like you forgot to put braces on that last if(). Run the auto-format tool on your code. If it moves things you didn't expect then you have the wrong braces.

I'm not sure what you mean, exactly, AWOL?

Do you have any ideas on how I can use my piezo sensor connected to A1 on my arduino to trigger the raw data output from the MPU9150, which I have (INT connected to digital pin 2 on arduino board)? If not an interrupt service routine, then what? Any suggestions?

Thank you all for your replies.

Stowite:

Do you have example code, or know how to implement code so that the raw data will only print when the accelerometer hits peaks (i.e. taps)? I've only found code relating to the ADXL345 product, but none for the MPU6050 or MPU9150.

MorganS

I didn't realize about the analogRead function not responding on LOW, thank you. However, how do I correct as you said "you never tell the 6050 what you want it to interrupt you for? So that will never fire."

Anyone have any examples of how to use the peak acceleration or tap function?

Thank you

Actually, although the datasheet says it can be used for tap detection, it doesn't say any more about it. I would infer from that that it doesn't have a dedicated interrupt mode or simple digital output when a tap is detected.

The result is that you would have to sample the accelerometer some reasonable number of times per second and identify the tap from that data in your own code. The exact accelerations would depend highly on the mass of the object it's attached to and the strength of tap you are looking for.

So maybe the piezo is not silly as a tap detector. You basically have to do the same thing - take lots of samples and consider yourself tapped once the values go over a threshold. That threshold might be a constant programmed in your code or it might be dynamic, based on previous accelerations.

  if (analogRead (TAP) == LOW)

As others pointed out, this is wrong. analogRead() returns a number from 0 to 1023 with some jitter. Testing for exactly zero is not something I would do. Plus, that would take around 110 µs in the ISR.

You could take analogRead readings continuously, ignoring them until you get a tap (perhaps storing the last 100 or so in an array). You can read from the ADC asynchronously if that helps.

MorganS:
An analog read in the ISRAEL seems OK to me.

What about in Palestine?

If you meant "ISR", I'd have to disagree.

HELLO

I've been programming this.

-I've gotten the sensor motions and interrupts to work correctly.
-I put in your desired output of the (mx), however it only reads the (mx) of the first tap, and then repeats that data whenever it is tapped
-instead of printing the data from the location of the next tap.
-I hope this can help you, and I hope someone might have some advice on how to read (mx) from different locations continuously from each tap.

Moderator edit: misread subject, apologies.

I've attached my code and renamed the file to relate to your project. hope it helps

NOTE: you need to add 'utilities.h' file to the sketch for it to compile

testcodeforKAS12.ino (19.6 KB)

AWOL:
What about in Palestine?

If you meant "ISR", I'd have to disagree.

Oops. Autocorrect got me there. Original is fixed now.

Well, it's not like he's doing anything else that's time-critical. I don't see a problem with an ISR that takes a few hundred microseconds. How else are you going to do something like regular sampling of an analog input? (I'm thinking of a case where the main loop has other analog inputs, so you can't just put the analog system's timer to work.)

That sounds fraught with peril. You may be doing an analogRead in the main loop, and then you start another one in the ISR? In the middle of the first one? That is going to end badly.

Wow thanks! That might be the cause of a problem I had two years ago with interrupts. That's something I hadn't considered.

MorganS:
How else are you going to do something like regular sampling of an analog input?

By regular sampling of an analogue input.

OK, so imagine I need to sample an analog input on a regular schedule. Like 10 or 100 times per second. I am doing some math or PID with this, so I want it to be regular. Like, not having to wait for the current loop() to finish writing a long string to the LCD display. A timer interrupt can give me this regularity. How do I then do an analogRead() based on that timer?

And I still want to use analogRead() to display the battery voltage, but it doesn't have to be regular.