Как сгенерировать аппаратное прерывание в mpu6050 для пробуждения Arduino из режима SLEEP_MODE_PWR_DOWN?
Я использую Arduino UNO и сохраняю режим SLEEP_MODE_PWR_DOWN & хотите, чтобы он просыпался с помощью аппаратного контакта INT MPU6050 (который должен посылать сигнал, когда MPU находится в движении). Я использовал статью https://lukelectro. wordpress.com/2016/08/11/how-to-enable-motion-detection-interrupt-on-mpu6050/
#include <Wire.h>
//Аналоговый порт 4 (A4) = SDA (последовательные данные)
// Аналоговый порт 5 (A5) = SCL (последовательные часы)
#define SIGNAL_PATH_RESET 0x68
#define I2C_SLV0_ADDR 0x37
#define ACCEL_CONFIG 0x1C
#define MOT_THR 0x1F // Биты порога обнаружения движения [7:0]
#define MOT_DUR 0x20 // Порог счетчика длительности для генерации прерывания движения, частота 1 кГц, LSB = 1 мс
#define MOT_DETECT_CTRL 0x69
#define INT_ENABLE 0x38
#define WHO_AM_I_MPU6050 0x75 // Должен вернуть 0x68
#define INT_STATUS 0x3A
// когда ничего не подключено к AD0, чем адрес 0x68
#define ADO 0
#if ADO
#define MPU6050_ADDRESS 0x69 // Адрес устройства, когда ADO = 1
#else
#define MPU6050_ADDRESS 0x68 // Адрес устройства, когда ADO = 0
#endif
/* Example for using write byte
Configure the accelerometer for self-test
writeByte(MPU6050_ADDRESS, ACCEL_CONFIG, 0xF0); // Включить самотестирование по всем трем осям и установить диапазон акселерометра на +/- 8g */
void writeByte(uint8_t address, uint8_t subAddress, uint8_t data)
{
Wire.begin();
Wire.beginTransmission(address); // Инициализировать буфер Tx
Wire.write(subAddress); // Помещаем адрес подчиненного регистра в буфер Tx
Wire.write(data); // Помещаем данные в буфер Tx
Wire.endTransmission(); // Отправляем буфер Tx
// Serial.println("mnnj");
}
//пример использования readbytev ---- readByte(MPU6050_ADDRESS, GYRO_CONFIG);
uint8
_t readByte(uint8_t address, uint8_t subAddress)
{
uint8_t data; // `data` будет хранить данные регистра
Wire.beginTransmission(address); // Инициализировать буфер Tx
Wire.write(subAddress); // Помещаем адрес подчиненного регистра в буфер Tx
Wire.endTransmission(false); // Отправляем буфер Tx, но отправляем перезагрузку, чтобы поддерживать соединение
Wire.requestFrom(address, (uint8_t) 1); // Читаем один байт из адреса подчиненного регистра
data = Wire.read(); // Заполняем буфер Rx результатом
return data; // Возвращаем данные, считанные из ведомого регистра
}
void setup()
{
/*
* #define SIGNAL_PATH_RESET 0x68
#define I2C_SLV0_ADDR 0x37
#define ACCEL_CONFIG 0x1C
#define MOT_THR 0x1F // Биты порога обнаружения движения [7:0]
#define MOT_DUR 0x20 // Порог счетчика длительности для генерации прерывания движения, частота 1 кГц, LSB = 1 мс
#define MOT_DETECT_CTRL 0x69
#define INT_ENABLE 0x38
#define WHO_AM_I_MPU6050 0x75 // Должен вернуть 0x68
#define INT_STATUS 0x3A*/
Serial.begin(9600);
writeByte( MPU6050_ADDRESS, SIGNAL_PATH_RESET, 0x07);//Сбросьте все внутренние пути прохождения сигнала в MPU-6050, записав 0x07 в регистр 0x68;
writeByte( MPU6050_ADDRESS, I2C_SLV0_ADDR, 0x20);// запись в регистр 0x37 для выбора способа использования вывода прерывания. Для активного высокого уровня двухтактного сигнала, который сохраняется до тех пор, пока не будет прочитан регистр (десятичный) 58, запишите 0x20.
writeByte( MPU6050_ADDRESS, ACCEL_CONFIG, 0x01);//Запись регистра 28 (==0x1C) для установки цифрового фильтра верхних частот, биты 3:0. Например, установите его на 0x01 для 5 Гц. (Эти 3 бита выделены серым цветом в таблице данных, но они используются! Если оставить их равными 0, фильтр всегда выводит 0.)
writeByte( MPU6050_ADDRESS, MOT_THR, 0x14); // Запишите желаемый порог движения в регистр 0x1F (например, запишите десятичное число 20).
writeByte( MPU6050_ADDRESS, MOT_DUR, 0x01 ); // Установить длительность обнаружения движения на 1 мс; LSB составляет 1 мс при частоте 1 кГц.
writeByte( MPU6050_ADDRESS, MOT_DETECT_CTRL, 0x15); // чтобы зарегистрировать 0x69, запишите декремент обнаружения движения и несколько других настроек (например, напишите 0x15, чтобы установить декременты свободного падения и движения на 1 и задержку запуска акселерометра до 5 мс, добавив 1 мс. )
writeByte( MPU6050_ADDRESS, INT_ENABLE, 0x40 ); // запись в регистр 0x38, бит 6 (0x40), чтобы включить прерывание обнаружения движения. */
pinMode(13, OUTPUT); // устанавливает вывод 13 цифрового светодиода в качестве выхода
pinMode(7, INPUT); // устанавливает цифровой вывод 7 в качестве входа
}
uint16_t readdata;
void loop()
{
Serial.println("scdf");
if(digitalRead(7)==1)
{
while(1)
{
digitalWrite(13, 1);
delay(100);
}
}
// readdata = readByte(MPU6050_ADDRESS,WHO_AM_I_MPU6050);
// Serial.println(readdata);
}
@bandejiya, 👍8
Обсуждение1 ответ
Что ж, этот код сработал. В этом коде вывод INT MPU имеет активный низкий уровень, поэтому генерирует заземление при движении, которое затем подключается к контакту 2 INT0 или arduino UNO, который генерирует прерывание и пробуждает MCU
#include <avr/sleep.h>
#include <Wire.h>
//Аналоговый порт 4 (A4) = SDA (последовательные данные)
// Аналоговый порт 5 (A5) = SCL (последовательные часы)
#define SIGNAL_PATH_RESET 0x68
#define I2C_SLV0_ADDR 0x37
#define ACCEL_CONFIG 0x1C
#define MOT_THR 0x1F // Биты порога обнаружения движения [7:0]
#define MOT_DUR 0x20 // Порог счетчика длительности для генерации прерывания движения, частота 1 кГц, LSB = 1 мс
#define MOT_DETECT_CTRL 0x69
#define INT_ENABLE 0x38
#define WHO_AM_I_MPU6050 0x75 // Должен вернуть 0x68
#define INT_STATUS 0x3A
// когда ничего не подключено к AD0, чем адрес 0x68
#define ADO 0
#if ADO
#define MPU6050_ADDRESS 0x69 // Адрес устройства, когда ADO = 1
#else
#define MPU6050_ADDRESS 0x68 // Адрес устройства, когда ADO = 0
#endif
int wakePin = 2; // пин, используемый для пробуждения
int led = 13;
int flag = 0;
void wakeUpNow() { // ПРОГРАММА ПРОДОЛЖАЕТСЯ ПОСЛЕ ПРОБУЖДЕНИЯ (т.е. после получения прерывания)
// выполнить здесь код после пробуждения перед возвратом в функцию loop()
// таймеры и код с использованием таймеров (serial.print и т. д.) здесь не работают.
// нам действительно не нужно выполнять здесь какие-либо специальные функции, так как мы
// просто хотим, чтобы вещь проснулась
delay(500);
Serial.println("WOKEN UP !!!!!!!!!!");
delay(500);
int count = 10;
while (count != 0) {
delay(1000);
count--;
Serial.println(count);
delay(1000);
}
// в целях предосторожности, пока мы занимаемся другими делами
detachInterrupt(0);
}
/* Example for using write byte
Configure the accelerometer for self-test
writeByte(MPU6050_ADDRESS, ACCEL_CONFIG, 0xF0); // Включить самотестирование по всем трем осям и установить диапазон акселерометра на +/- 8g */
void writeByte(uint8_t address, uint8_t subAddress, uint8_t data) {
Wire.begin();
Wire.beginTransmission(address); // Инициализировать буфер Tx
Wire.write(subAddress); // Помещаем адрес подчиненного регистра в буфер Tx
Wire.write(data); // Помещаем данные в буфер Tx
Wire.endTransmission(); // Отправляем буфер Tx
// Serial.println("mnnj");
}
//пример использования readbytev ---- readByte(MPU6050_ADDRESS, GYRO_CONFIG);
uint8_t readByte(uint8_t address, uint8_t subAddress) {
uint8_t data; // `data` будет хранить данные регистра
Wire.beginTransmission(address); // Инициализировать буфер Tx
Wire.write(subAddress); // Помещаем адрес подчиненного регистра в буфер Tx
Wire.endTransmission(false); // Отправляем буфер Tx, но отправляем перезагрузку, чтобы поддерживать соединение
Wire.requestFrom(address, (uint8_t) 1); // Читаем один байт из адреса подчиненного регистра
data = Wire.read(); // Заполняем буфер Rx результатом
return data; // Возвращаем данные, считанные из ведомого регистра
}
void setup() {
/*
* #define SIGNAL_PATH_RESET 0x68
#define I2C_SLV0_ADDR 0x37
#define ACCEL_CONFIG 0x1C
#define MOT_THR 0x1F // Биты порога обнаружения движения [7:0]
#define MOT_DUR 0x20 // Порог счетчика длительности для генерации прерывания движения, частота 1 кГц, LSB = 1 мс
#define MOT_DETECT_CTRL 0x69
#define INT_ENABLE 0x38
#define WHO_AM_I_MPU6050 0x75 // Должен вернуть 0x68
#define INT_STATUS 0x3A*/
Serial.begin(9600);
writeByte(MPU6050_ADDRESS, 0x6B, 0x00);
writeByte(MPU6050_ADDRESS, SIGNAL_PATH_RESET, 0x07); // Сбросьте все внутренние пути прохождения сигнала в MPU-6050, записав 0x07 в регистр 0x68;
writeByte(MPU6050_ADDRESS, I2C_SLV0_ADDR, 0x20); // запись в регистр 0x37, чтобы выбрать, как использовать вывод прерывания. Для активного высокого уровня двухтактного сигнала, который сохраняется до тех пор, пока не будет прочитан регистр (десятичный) 58, запишите 0x20.
writeByte(MPU6050_ADDRESS, ACCEL_CONFIG, 0x01); //Запись регистра 28 (==0x1C), чтобы установить цифровой фильтр верхних частот, биты 3:0. Например, установите его на 0x01 для 5 Гц. (Эти 3 бита выделены серым цветом в таблице данных, но они используются! Если оставить их равными 0, фильтр всегда выводит 0.)
writeByte(MPU6050_ADDRESS, MOT_THR, 10); // Запишите желаемый порог движения в регистр 0x1F (например, запишите десятичное число 20).
writeByte(MPU6050_ADDRESS, MOT_DUR, 40); // Установить длительность обнаружения движения на 1 мс; LSB составляет 1 мс при частоте 1 кГц.
writeByte(MPU6050_ADDRESS, MOT_DETECT_CTRL, 0x15); // чтобы зарегистрировать 0x69, запишите декремент обнаружения движения и несколько других настроек (например, напишите 0x15, чтобы установить декременты свободного падения и движения на 1 и задержку запуска акселерометра до 5 мс, добавив 1 мс. )
writeByte(MPU6050_ADDRESS, INT_ENABLE, 0x40); // запись в регистр 0x38, бит 6 (0x40), чтобы включить прерывание обнаружения движения.
writeByte(MPU6050_ADDRESS, 0x37, 160); // теперь вывод INT активен низким уровнем
pinMode(2, INPUT); // устанавливает цифровой вывод 7 в качестве входа
pinMode(wakePin, INPUT_PULLUP); // wakePin — это номер контакта. 2
pinMode(led, OUTPUT); // светодиод - это номер контакта. 13
// attachInterrupt(0, wakeUpNow, LOW); // используем прерывание 0 (вывод 2) и запускаем функцию wakeUpNow, когда вывод 2 получает НИЗКИЙ уровень
}
void sleepNow() {
set_sleep_mode(SLEEP_MODE_PWR_DOWN); // здесь устанавливается спящий режим
sleep_enable(); // включает бит сна в регистре mcucr
delay(500);
Serial.println("About to sleep");
delay(500);
attachInterrupt(0, wakeUpNow, LOW); // используем прерывание 0 (вывод 2) и запускаем функцию
delay(500);
Serial.println("Interupt attached");
delay(500);
sleep_mode(); // здесь устройство фактически усыпляется...!!
// ПРОГРАММА ПРОДОЛЖАЕТСЯ С ЭТОГО МЕСТА ПОСЛЕ ЗАКРЫТИЯ ПРЕРЫВАНИЯ
delay(500);
Serial.println("Continuing main program after interupt");
delay(500);
sleep_disable(); // первое, что нужно сделать после пробуждения ото сна: отключить сон...
delay(500);
Serial.println("Sleep disabled");
delay(500);
}
uint16_t readdata;
void loop() {
if (digitalRead(2) == 0) {
{
digitalWrite(13, 1);
delay(100);
digitalWrite(13, 0);
delay(100);
}
}
sleepNow(); // здесь вызывается функция сна
readdata = readByte(MPU6050_ADDRESS, 0x3A);
Serial.print(readdata);
Serial.print(",");
readdata = readByte(MPU6050_ADDRESS, 0x37);
Serial.println(readdata);
}
Рад видеть, что у вас все получилось. Спасибо, что поделились своим решением., @Gerben
Мне нужно было поместить detachInterrupt() в функцию wakeUpNow(). В остальном отлично работает., @Patrick McGloin
+1 У меня отлично сработало. Нравится, что внешние библиотеки не нужны., @blak3r
У меня не работало, пока я не узнал, что MPU (дополнительно к MCU) должен очистить прерывание, прочитав: readByte (MPU6050_ADDRESS, 0x3A); И это не сработало в самом ISR, поэтому я установил логическое значение «прервано», и вне ISR отреагировал на это вызовом readByte. Также сделайте это после инициализации MPU., @user2081279
- Проблема прерывания библиотеки MPU6050 Arduino Jeff Rowberg
- Взаимодействие MPU6050 с Arduino uno
- Помощь с прерыванием режима ожидания Arduino и ватчдог таймера
- Как очистить буфер FIFO на MPU6050?
- Arduino непрерывно считывает значение АЦП с помощью прерывания
- Как правильно использовать volatile переменные в Arduino?
- Понимание того, почему следует избегать «String» и альтернативных решений
- Объяснение кода MPU6050
Используете ли вы библиотеку для настройки MPU6050 или взаимодействуете с ним вручную с помощью библиотеки Wire?, @Majenko
Привет @Majenko..! Я отредактировал вопрос и добавил код ..! в этом я просто использую библиотеку проводов, но в этом выводе INT mpu не генерируется триггер при движении, как это должно быть в соответствии со статьей., @bandejiya