Arduino会在x秒后冻结



我正在读取来自MPU-6050惯性测量单元的数据,使用I2C,从arduino以25Hz的采样率读取,它工作得很好。然后我添加了第二个MPU-6050,我也以25Hz的采样频率读取。它们有不同的地址,所以我可以在I2C中访问它们。然而,自从我添加了第二个,我的arduino停止似乎在1000到5000循环()调用后冻结,在循环中的某个地方冻结(每次不同的地方,从我通过将字符发送到串行连接到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 + ''
// ================================================================
// === 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 '' 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...
    }
}

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

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

我知道这是很久以前发布的。我也有类似的问题。在我的案例中,Serial.flush()解决了这个问题。

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

&& fifoCount_1 < packetSize_1

相关内容

  • 没有找到相关文章

最新更新