Проблема прерывания библиотеки MPU6050 Arduino Jeff Rowberg

Я пытался получить данные из MPU6050, используя библиотеку Arduino, упомянутую здесь.

Следующий код-это отредактированная версия примера кода, приведенного в папке библиотеки, который, кажется, работает нормально.

#define printfloatx(Name,Variable,Spaces,Precision,EndTxt) { Serial.print(F(Name)); {char S[(Spaces + Precision + 3)];Serial.print(F(" ")); Serial.print(dtostrf((float)Variable,Spaces,Precision ,S));}Serial.print(F(EndTxt)); }//Имя,Переменная,Spaces,Precision,EndTxt

#include "I2Cdev.h"
#include "MPU6050_6Axis_MotionApps_V6_12.h"

#include "Wire.h"

MPU6050 accelgyro;
MPU6050 mpu;


I2Cdev a;

/*
    IMU Нулевые переменные
*/

int16_t data_acc[3];
int16_t data_Gyro[3];

/*
   IMU Переменные инициализации
*/
uint8_t devStatus;      // возвращает состояние после каждой операции устройства (0 = успех, !0 = ошибка)
uint8_t mpuIntStatus;   // содержит фактический байт состояния прерывания из MPU
bool dmpReady = false;  // установить true, если инициализация DMP прошла успешно
uint16_t packetSize;    // ожидаемый размер пакета DMP (по умолчанию 42 байта)

/*
   Переменные нахождения угла ИДУ
*/
uint16_t fifoCount;     // количество всех байтов, находящихся в данный момент в FIFO
uint8_t fifoBuffer[64]; // Буфер хранения FIFO

Quaternion q;           // [w, x, y, z] кватернионный контейнер
VectorFloat gravity;    // [x, y, z] gravity vector
float ypr[3];           // [yaw, pitch, roll] yaw/pitch/roll контейнер и вектор силы тяжести



void Initialize()
{
  // инициализировать устройство
  Serial.println("Initializing I2C devices...");
  accelgyro.initialize();

  // проверить соединение
  Serial.println("Testing device connections...");
  Serial.println(accelgyro.testConnection() ? "MPU6050 connection successful" : "MPU6050 connection failed");
  Serial.println("tuning Each Dot = 100 readings");
  accelgyro.CalibrateAccel(10);
  accelgyro.CalibrateGyro(10);

  a.readWords(0x68, 0x06, 3, (uint16_t *)data_acc);
  a.readWords(0x68, 0x13, 3, (uint16_t *)data_Gyro);
} // Инициализация




void setup() {
  Wire.begin();
  Serial.begin(115200);
  Initialize();
  Wire.setClock(400000);
  while (!Serial);
  Serial.println(F("Инициализация устройств I2C..."));
  mpu.initialize();
  Serial.println(F("Соединения испытательного устройства..."));
  Serial.println(mpu.testConnection() ? F("соединение MPU6050 успешно") : F("соединение MPU6050 не удалось"));

  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()); // снова пустой буфер

  // загрузка и настройка DMP
  Serial.println(F("Инициализация DMP..."));
  devStatus = mpu.dmpInitialize();

  // поставьте здесь свои собственные смещения гироскопа, масштабированные для минимальной чувствительности
  mpu.setXGyroOffset(data_Gyro[0]);
  mpu.setYGyroOffset(data_Gyro[1]);
  mpu.setZGyroOffset(data_Gyro[2]);
  mpu.setXAccelOffset(data_acc[0]);
  mpu.setYAccelOffset(data_acc[1]);
  mpu.setZAccelOffset(data_acc[2]);

  if (devStatus == 0) {
    // Время калибровки: генерируйте смещения и калибруйте наш MPU6050
    mpu.CalibrateAccel(6);
    mpu.CalibrateGyro(6);
    Serial.println();
    mpu.PrintActiveOffsets();
    // включите DMP, теперь, когда он готов
    Serial.println(F("Включение DMP..."));
    mpu.setDMPEnabled(true);

    // включить обнаружение прерываний Arduino
    Serial.print(F("Включение обнаружения прерываний (внешнее прерывание Arduino "));
    mpuIntStatus = mpu.getIntStatus();
    Serial.println(F("DMP готов! Жду первого прерывания..."));
    dmpReady = true;
    packetSize = mpu.dmpGetFIFOPacketSize();
  } else {
    Serial.print(F("DMP Initialization failed (code "));
    Serial.print(devStatus);
    Serial.println(F(")"));
  }

  Serial.println("-------------- done --------------");
} // настройка

void loop()
{
  if (!dmpReady) return;
  if (mpu.dmpGetCurrentFIFOPacket(fifoBuffer)) {
    mpu.dmpGetQuaternion(&q, fifoBuffer);
    mpu.dmpGetGravity(&gravity, &q);
    mpu.dmpGetYawPitchRoll(ypr, &q, &gravity);
    Serial.print("ypr\t");
    Serial.print(ypr[0] * 180 / M_PI);
    Serial.print("\t");
    Serial.print(ypr[1] * 180 / M_PI);
    Serial.print("\t");
    Serial.print(ypr[2] * 180 / M_PI);
    Serial.println();
  }

}

Затем я активировал PIN захвата ввода для использования с прерыванием, и код выглядит следующим образом

#define printfloatx(Name,Variable,Spaces,Precision,EndTxt) { Serial.print(F(Name)); {char S[(Spaces + Precision + 3)];Serial.print(F(" ")); Serial.print(dtostrf((float)Variable,Spaces,Precision ,S));}Serial.print(F(EndTxt)); }//Имя,Переменная,Spaces,Precision,EndTxt

#include "I2Cdev.h"
#include "MPU6050_6Axis_MotionApps_V6_12.h"

#include "Wire.h"

MPU6050 accelgyro;
volatile MPU6050 mpu;


I2Cdev a;

/*
    IMU Zero variables
*/

int16_t data_acc[3];
int16_t data_Gyro[3];

/*
   IMU initialization variables
*/
uint8_t devStatus;      // возвращает состояние после каждой операции устройства (0 = успех, !0 = ошибка)
uint8_t mpuIntStatus;   // содержит фактический байт состояния прерывания из MPU
bool dmpReady = false;  // установить true, если инициализация DMP прошла успешно
uint16_t packetSize;    // ожидаемый размер пакета DMP (по умолчанию 42 байта)

/*
   IMU angle finding variables
*/
uint16_t fifoCount;     // количество всех байтов, находящихся в данный момент в FIFO
uint8_t fifoBuffer[64]; // Буфер хранения FIFO

Quaternion q;           // [w, x, y, z] кватернионный контейнер
VectorFloat gravity;    // [x, y, z] gravity vector
volatile float ypr[3];           // [yaw, pitch, roll] yaw/pitch/roll контейнер и вектор силы тяжести



void Initialize()
{
  // инициализировать устройство
  Serial.println("Initializing I2C devices...");
  accelgyro.initialize();

  // проверить соединение
  Serial.println("Testing device connections...");
  Serial.println(accelgyro.testConnection() ? "MPU6050 connection successful" : "MPU6050 connection failed");
  Serial.println("tuning Each Dot = 100 readings");
  accelgyro.CalibrateAccel(10);
  accelgyro.CalibrateGyro(10);

  a.readWords(0x68, 0x06, 3, (uint16_t *)data_acc);
  a.readWords(0x68, 0x13, 3, (uint16_t *)data_Gyro);
} // Инициализация

void timer4_initialization() {
  pinMode(49, INPUT);
  TCCR4A = 0; TCCR4B = 0; TCCR4C = 0;
  TCCR4B = B11000000;
  TIFR4 = _BV(ICF4);
  TIMSK4 = B00100000;
}

ISR(TIMER4_CAPT_vect) {
  if (!dmpReady) return;
  if (mpu.dmpGetCurrentFIFOPacket(fifoBuffer)) {
    mpu.dmpGetQuaternion(&q, fifoBuffer);
    mpu.dmpGetGravity(&gravity, &q);
    mpu.dmpGetYawPitchRoll(ypr, &q, &gravity);
  }
}



void setup() {
  Wire.begin();
  Serial.begin(115200);
  Initialize();
  Wire.setClock(400000);
  while (!Serial);
  Serial.println(F("Initializing I2C devices..."));
  mpu.initialize();
  Serial.println(F("Testing device connections..."));
  Serial.println(mpu.testConnection() ? F("MPU6050 connection successful") : F("MPU6050 connection failed"));

  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()); // снова пустой буфер

  // загрузка и настройка DMP
  Serial.println(F("Initializing DMP..."));
  devStatus = mpu.dmpInitialize();

  // поставьте здесь свои собственные смещения гироскопа, масштабированные для минимальной чувствительности
  mpu.setXGyroOffset(data_Gyro[0]);
  mpu.setYGyroOffset(data_Gyro[1]);
  mpu.setZGyroOffset(data_Gyro[2]);
  mpu.setXAccelOffset(data_acc[0]);
  mpu.setYAccelOffset(data_acc[1]);
  mpu.setZAccelOffset(data_acc[2]);

  if (devStatus == 0) {
    // Время калибровки: генерируйте смещения и калибруйте наш MPU6050
    mpu.CalibrateAccel(6);
    mpu.CalibrateGyro(6);
    Serial.println();
    mpu.PrintActiveOffsets();
    // включите DMP, теперь, когда он готов
    Serial.println(F("Enabling DMP..."));
    mpu.setDMPEnabled(true);

    // включить обнаружение прерываний Arduino
    Serial.print(F("Enabling interrupt detection (Arduino external interrupt "));
    mpuIntStatus = mpu.getIntStatus();
    Serial.println(F("DMP ready! Waiting for first interrupt..."));
    dmpReady = true;
    packetSize = mpu.dmpGetFIFOPacketSize();
  } else {
    Serial.print(F("DMP Initialization failed (code "));
    Serial.print(devStatus);
    Serial.println(F(")"));
  }

  Serial.println("-------------- done --------------");

  delay(2000);

  timer4_initialization();

} // настройка

void loop()
{
  Serial.print("ypr\t");
  Serial.print(ypr[0] * 180 / M_PI);
  Serial.print("\t");
  Serial.print(ypr[1] * 180 / M_PI);
  Serial.print("\t");
  Serial.print(ypr[2] * 180 / M_PI);
  Serial.println();
}


Здесь, когда я использую прерывание, я ничего не печатаю, кажется, что программа заморожена где-то в вызове функции interrupt ->.

В чем же заключается ошибка, которую я здесь совершаю?

Как выполнить измерение с MPU6050 с помощью процедур ISR.

, 👍3

Обсуждение

вы хотите сказать, что он даже не печатает " Инициализация устройств I2C...`?, @jsotola


2 ответа


4

Функции mpu.dmpGetCurrentFIFOPacket(fifoBuffer)и т. Д. Используют I2C для получения данных. Интерфейс I2C на Uno и Mega (которым вы пометили свой вопрос) реализован аппаратно и нуждается в прерываниях для обработки байтов данных (извлечения принятого байта из регистра или записи данных в регистр для отправки).

По умолчанию прерывания отключены внутри ISR. Таким образом, упомянутые функции не могут выполняться корректно. Они ждут прерывания, которое никогда не произойдет, так как функции выполняются, а прерывания отключены.

Можно повторно активировать прерывания в ISR, но это то, что вы должны делать только в нескольких ситуациях и только тогда, когда вы точно знаете, что делаете.

Вместо этого вы должны просто установить переменную volatile flag внутри ISR. В основном коде (в loop()) вы можете проверить наличие этого флага, выполнить код I2C, когда он установлен, и сбросить флаг после этого. И тогда вы также можете просто печатать, когда вместо каждой итерации цикла появляются новые данные. Так что примерно так:

volatile byte timer_flag = 0;

ISR(TIMER4_CAPT_vect) {
  timer_flag = 1;
}

void loop(){
    if(timer_flag){
        if (!dmpReady) return;
        if (mpu.dmpGetCurrentFIFOPacket(fifoBuffer)) {
            mpu.dmpGetQuaternion(&q, fifoBuffer);
            mpu.dmpGetGravity(&gravity, &q);
            mpu.dmpGetYawPitchRoll(ypr, &q, &gravity);
            // затем выведите значения здесь, так как мы получили новые данные из MPU
        }
        timer_flag = 0; // Сброс флага для следующего прерывания таймера
    }
}
,

0

Я изменил ответ Крисла, чтобы показать, как скопировать данные ISR и сбросить флаг ISR атомарным способом.

volatile bool isr_timer_flag = false;
volatile uint32_t isr_counter = 0;  // Добавлено для демонстрации атомарного копирования многобайтного типа данных.

ISR(TIMER4_CAPT_vect)
{
    isr_timer_flag = true;
    isr_counter++;
}

void loop()
{
    //
    // Получить копию данных и сбросить флаг атомарно, временно отключив прерывания.
    //

    // Отключите прерывания, сняв флаг глобального прерывания.
    cli();

    // Скопируйте данные.
    bool timer_flag = isr_timer_flag;
    uint32_t counter = isr_counter;

    // Сбросить флаг ISR для следующего прерывания таймера.
    // Сброс его здесь позволяет избежать снятия любого повторного флага во время следующих операторов if.
    isr_timer_flag = false;

    // Включить прерывания, установив флаг глобального прерывания.
    sei();

    // Теперь используйте локальную копию флага ISR.
    // Флаг ISR может быть повторно помечен в любое время в течение оставшейся части цикла,
    // but a fresh copy will be obtained on the next iteration of the loop.

    if (timer_flag)
    {
        if (!dmpReady) return;
        if (mpu.dmpGetCurrentFIFOPacket(fifoBuffer))
        {
            mpu.dmpGetQuaternion(&q, fifoBuffer);
            mpu.dmpGetGravity(&gravity, &q);
            mpu.dmpGetYawPitchRoll(ypr, &q, &gravity);
            // затем выведите значения здесь, так как мы получили новые данные из MPU
        }
    }
}
,