1

我正在使用 I2C 从 arduino 以 25Hz 的采样率从 MPU-6050 惯性测量单元读取数据,并且工作正常。然后我添加了第二个 MPU-6050,我也以 25Hz 的采样频率读取它。它们有不同的地址,所以我可以在 I2C 中访问它们。但是,由于我添加了第二个,我的 arduino 停止似乎在 1000 到 5000 个 loop() 调用后冻结,冻结在循环中的某个地方(每次都不同,与我通过将字符发送到与 PC 的串行连接进行调试所观察到的情况不同)。在每个循环中,我从其中一个 MPU-6050 读取数据。我的代码使用 Jeff Rowberg 的库,灵感来自http://forum.arduino.cc/index.php?PHPSESSID=t6lmv7i431eqeaf05ui619q2h6&topic=118937.msg1368958#msg1368958中的代码,它提出了同样的问题:

// I2C device class (I2Cdev) demonstration Arduino sketch for MPU6050 class using DMP (MotionApps v2.0)
// 6/21/2012 by Jeff Rowberg <jeff@rowberg.net>
// Updates should (hopefully) always be available at https://github.com/jrowberg/i2cdevlib


// I2Cdev and MPU6050 must be installed as libraries, or else the .cpp/.h files
// for both classes must be in the include path of your project
#include "I2Cdev.h"

#include <SoftwareSerial.h>
#include "MPU6050_6Axis_MotionApps20.h"
//#include "MPU6050.h" // not necessary if using MotionApps include file

// Arduino Wire library is required if I2Cdev I2CDEV_ARDUINO_WIRE implementation
// is used in I2Cdev.h
#if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE
#include "Wire.h"
#endif

// class default I2C address is 0x68
// specific I2C addresses may be passed as a parameter here
// AD0 low = 0x68 (default for SparkFun breakout and InvenSense evaluation board)
// AD0 high = 0x69
MPU6050 mpu_1;
MPU6050 mpu_2(0x69);  // <-- use for AD0 high

#define LED_PIN 13 // (Arduino is 13, Teensy is 11, Teensy++ is 6)
bool blinkState = false;

// MPU control/status vars
bool dmpReady = false; // set true if DMP init was successful
uint8_t forceReadMPU = 1;

uint8_t mpuIntStatus_1; // holds actual interrupt status byte from MPU
uint8_t devStatus_1; // return status after each device operation (0 = success, !0 = error)
uint16_t packetSize_1; // expected DMP packet size (default is 42 bytes)
uint16_t fifoCount_1; // count of all bytes currently in FIFO
bool mpuNeedToBeRead_1;
uint8_t fifoBuffer_1[64]; // FIFO storage buffer

uint8_t mpuIntStatus_2;
uint8_t devStatus_2;
uint16_t packetSize_2;
uint16_t fifoCount_2;
bool mpuNeedToBeRead_2;
uint8_t fifoBuffer_2[64];

// orientation/motion vars
Quaternion q; // [w, x, y, z] quaternion container
VectorFloat gravity; // [x, y, z] gravity vector
float ypr[3]; // [yaw, pitch, roll] yaw/pitch/roll container and gravity vector

SoftwareSerial xbee = SoftwareSerial(4, 5);
float measures[3];
byte serialBuffer[2*2*sizeof(measures)+1]; //two gyroscopes, two bytes per digit, 4 digit per measure + '\0'

// ================================================================
// === INTERRUPT DETECTION ROUTINE ===
// ================================================================

volatile bool mpuInterrupt_1 = false;     // indicates whether MPU interrupt pin has gone high
volatile bool mpuInterrupt_2 = false;

void dmpDataReady_1() {
    mpuInterrupt_1 = true;
}
// Función que invoca cuando detecta una interrupción en el MPU 2
void dmpDataReady_2() {
    mpuInterrupt_2 = true;
}




// ================================================================
// === INITIAL SETUP ===
// ================================================================

void setup() {
  xbee.begin(19200);
  serialBuffer[2*2*sizeof(measures)] = 0x00; // set '\0' at the end of the array, for Serial.print

    // join I2C bus (I2Cdev library doesn't do this automatically)
#if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE
        Wire.begin();
        TWBR = 24; // 400kHz I2C clock (200kHz if CPU is 8MHz)
#elif I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_FASTWIRE
        Fastwire::setup(400, true);
#endif

    // initialize serial communication
    // (115200 chosen because it is required for Teapot Demo output, but it's
    // really up to you depending on your project)
    Serial.begin(19200);
    //while (!Serial); // wait for Leonardo enumeration, others continue immediately

    // NOTE: 8MHz or slower host processors, like the Teensy @ 3.3v or Ardunio
    // Pro Mini running at 3.3v, cannot handle the 115200 baud rate reliably due to
    // the baud timing being too misaligned with processor ticks. You must use
    // 38400 or slower in these cases, or use some kind of external separate
    // crystal solution for the UART timer.

    // initialize device
    Serial.println(F("Initializing I2C devices..."));
    mpu_1.initialize();
    mpu_2.initialize();

    // verify connection
    Serial.println(F("Testing device connections..."));
    Serial.println(mpu_1.testConnection() ? F("MPU6050_1 connection successful") : F("MPU6050_1 connection failed"));
    Serial.println(mpu_2.testConnection() ? F("MPU6050_2 connection successful") : F("MPU6050_2 connection failed"));

    // wait for ready
    /*
    Serial.println(F("\nSend any character to begin DMP programming and demo: "));
    while (Serial.available() && Serial.read()); // empty buffer
    while (!Serial.available()); // wait for data
    while (Serial.available() && Serial.read()); // empty buffer again
  */
    // load and configure the DMP
    Serial.println(F("Initializing DMP..."));
    devStatus_1 = mpu_1.dmpInitialize();
    devStatus_2 = mpu_2.dmpInitialize();    

    if (devStatus_1 == 0) {
        // turn on the DMP, now that it's ready
        Serial.println(F("Enabling DMP..."));
        mpu_1.setDMPEnabled(true);

        // enable Arduino interrupt detection
        Serial.println(F("Enabling interrupt detection (Arduino external interrupt 0)..."));
        attachInterrupt(0, dmpDataReady_1, RISING); // Utilizamos la primera interrupción externa (número 0) que está en el pin digital 2
                                                     // Cuando la interrupción tiene lugar invoca la función "dmp_1_DataReady"
                                                     // RISING dispara la interrupción cuando el pin pasa de valor alto (HIGH) a bajo (LOW)
        mpuIntStatus_1 = mpu_1.getIntStatus();

        // set our DMP Ready flag so the main loop() function knows it's okay to use it
        Serial.println(F("DMP ready! Waiting for first interrupt..."));

        // get expected DMP packet size for later comparison
        packetSize_1 = mpu_1.dmpGetFIFOPacketSize();

            // supply your own gyro offsets here, scaled for min sensitivity
        mpu_1.setXGyroOffset(17);
        mpu_1.setYGyroOffset(-22);
        mpu_1.setZGyroOffset(33);
        mpu_1.setXAccelOffset(2310);
        mpu_1.setYAccelOffset(1823);
        mpu_1.setZAccelOffset(1477);

    }else {
        // ERROR!
        // 1 = initial memory load failed
        // 2 = DMP configuration updates failed
        // (if it's going to break, usually the code will be 1)
        Serial.print(F("DMP 1 Initialization failed (code "));
        Serial.print(devStatus_1);
        Serial.println(F(")"));
    }

    if (devStatus_2 == 0) {
        // turn on the DMP, now that it's ready
        Serial.println(F("Enabling DMP..."));
        mpu_2.setDMPEnabled(true);

        // enable Arduino interrupt detection
        Serial.println(F("Enabling interrupt detection (Arduino external interrupt 0)..."));
        attachInterrupt(1, dmpDataReady_2, RISING); // Utilizamos la segunda interrupción externa (número 1) que está en el pin digital 3
                                                     // Cuando la interrupción tiene lugar invoca la función "dmp_1_DataReady"
                                                     // RISING dispara la interrupción cuando el pin pasa de valor alto (HIGH) a bajo (LOW)        
        mpuIntStatus_2 = mpu_2.getIntStatus();

        // set our DMP Ready flag so the main loop() function knows it's okay to use it
        Serial.println(F("DMP ready! Waiting for first interrupt..."));
        dmpReady = true;

        // get expected DMP packet size for later comparison
        packetSize_2 = mpu_2.dmpGetFIFOPacketSize();

        mpu_1.setXGyroOffset(-5);
        mpu_1.setYGyroOffset(-60);
        mpu_1.setZGyroOffset(69);
        mpu_1.setXAccelOffset(-1088);
        mpu_1.setYAccelOffset(580);
        mpu_1.setZAccelOffset(1936);

    }else {
        // ERROR!
        // 1 = initial memory load failed
        // 2 = DMP configuration updates failed
        // (if it's going to break, usually the code will be 1)
        Serial.print(F("DMP 2 Initialization failed (code "));
        Serial.print(devStatus_2);
        Serial.println(F(")"));
    }

    // configure LED for output
    pinMode(LED_PIN, OUTPUT);
}



// ================================================================
// === MAIN PROGRAM LOOP ===
// ================================================================

void loop() {

     // if programming failed, don't try to do anything
     if (!dmpReady) return;

     // wait for MPU interrupt or extra packet(s) available.
     while ( !mpuInterrupt_1 && fifoCount_1 < packetSize_1);

     mpuInterrupt_1 = false;
     mpuIntStatus_1 = mpu_1.getIntStatus();
     fifoCount_1 = mpu_1.getFIFOCount();

     // check for overflow (this should never happen unless our code is too inefficient)
     if ((mpuIntStatus_1 & 0x10) || fifoCount_1 == 1024) {
         // reset so we can continue cleanly
         mpu_1.resetFIFO();
         Serial.println(F("FIFO 1 overflow!"));

     // otherwise, check for DMP data ready interrupt (this should happen frequently)
     } else if (mpuIntStatus_1 & 0x02) {
         // wait for correct available data length, should be a VERY short wait
         while (fifoCount_1 < packetSize_1) fifoCount_1 = mpu_1.getFIFOCount();

         // read a packet from FIFO
         if (packetSize_1 >= 64) Serial.println("Packet size incoherence 1");
         mpu_1.getFIFOBytes(fifoBuffer_1, packetSize_1);

         // track FIFO count here in case there is > 1 packet available
         // (this lets us immediately read more without waiting for an interrupt)
         fifoCount_1 -= packetSize_1;
         //mpu_1.resetFIFO();// Parce que j'arrive pas à trouver une fonction setFIFOsize(). Juste espérer qu'elle ne se remplit pas pendant l'exécution de la ligne précédente...
     }

     while ( !mpuInterrupt_2 && fifoCount_1 < packetSize_2);

     // reset interrupt flag and get INT_STATUS byte
     mpuInterrupt_2 = false;
     mpuIntStatus_2 = mpu_2.getIntStatus();
     fifoCount_2 = mpu_2.getFIFOCount();

     // check for overflow (this should never happen unless our code is too inefficient)
     if ((mpuIntStatus_2 & 0x10) || fifoCount_2 == 1024) {
         // reset so we can continue cleanly
         mpu_2.resetFIFO();
         Serial.println(F("FIFO 2 overflow!"));

     // otherwise, check for DMP data ready interrupt (this should happen frequently)
     } else if (mpuIntStatus_2 & 0x02) {
         // wait for correct available data length, should be a VERY short wait

         while (fifoCount_2 < packetSize_2) fifoCount_2 = mpu_2.getFIFOCount();

         // read a packet from FIFO
         if (packetSize_2 >= 64) Serial.println("Packet size incoherence 2");
         mpu_2.getFIFOBytes(fifoBuffer_2, packetSize_2);

         // track FIFO count here in case there is > 1 packet available
         // (this lets us immediately read more without waiting for an interrupt)
         fifoCount_2 -= packetSize_2;
         //mpu_2.resetFIFO();// Parce que j'arrive pas à trouver une fonction setFIFOsize(). Juste espérer qu'elle ne se remplit pas pendant l'exécution de la ligne précédente...
    }
}

串行输出没有报告错误。当 Arduino 冻结时,闪烁的 LED(代码结束)仍然亮着。是冻结,还是崩溃?我该如何解决?

4

3 回答 3

4

我摆脱了冻结问题,避免使用中断。不要在代码中使用它们,也不要连接 MPU6050 的 INT 引脚。一旦我将该引脚连接到 Arduino 数字输入,问题就会再次出现。

于 2015-11-16T12:05:20.110 回答
1

我知道它是很久以前发布的。我仍然有类似的问题。在我的情况下Serial.flush()解决了这个问题。

于 2017-10-18T22:37:40.053 回答
0

从等待中断的while循环中删除以下内容,它对我有用

&& fifoCount_1 < packetSize_1
于 2015-07-09T21:34:38.560 回答