Прерывание ADXL345 Arduino UNO data_ready
Я бы хотел, чтобы значения датчика обновлялись каждые 10 мс (100 Гц), а затем запускался алгоритм и повторялся тот же процесс. Однако после синхронизации алгоритма он занимает всего 2 мс, я думаю, что прерывание data_ready не работает должным образом. Физическое аппаратное соединение — от INT1 ADXL345 к контакту 2 UNO.
изменить:
Я настроил акселерометр на скорость передачи данных 100 Гц. Я настроил прерывание с data_ready для запуска алгоритма, присутствующего в цикле, каждый раз, когда приходит новая выборка, то есть каждые 10 мс. Однако каждый образец поступает каждые 2 мс, что показывает, что прерывание не работает, и я хотел бы знать, почему. Я замерил время прерывания с помощью функции millis(); функция до и после вызова прерывания, также я сохранил выборки в массиве и распечатал их на последовательном интерфейсе, и выборки повторялись, поскольку они обновлялись каждые 2 мс вместо 10 мс. Алгоритм, который я разработал, требует частоты дискретизации 100 Гц.
#include <Wire.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_ADXL345_U.h>
#include <avr/io.h>
#include <avr/power.h>
#define F_CPU 16000000UL
volatile int sensor_update=0;
//------------------------------------------------ -------------------- -----------
//Запись в регистры ADXL345
void writeTo(int device, byte address, byte val) {
Wire.beginTransmission(device); // начинаем передачу на устройство
Wire.write(address); // отправляем адрес регистра
Wire.write(val); // отправляем значение для записи
Wire.endTransmission(); //завершить передачу
}
//------------------------------------------------ -------------------------------------------------------------
////////////////////////////////////////////////// ////////////////////////////////////////////
//функция ISR
void interrupt(void){
sensor_update=1;
}
////////////////////////////////////////////////// //////////////////////////////////////////////////
void buzz(int targetPin, long frequency, long length) {
long delayValue = 1000000/frequency/2; // вычисляем значение задержки между переходами
//// Количество микросекунд, равное 1 секунде, делим на частоту, затем делим пополам, так как
//// в каждом цикле две фазы
//// вычислить количество циклов для правильной синхронизации
long numCycles = frequency * length/ 1000;
//// умножить частоту, которая на самом деле составляет число циклов в секунду, на
//// количество секунд, чтобы получить общее количество циклов для производства
for (long i=0; i < numCycles; i++){ // для рассчитанного отрезка времени...
digitalWrite(targetPin,HIGH); // запишем зуммер в высокий уровень, чтобы вытолкнуть диафрагму
delayMicroseconds(delayValue); // ждем рассчитанного значения задержки
digitalWrite(targetPin,LOW); // пишем низкий уровень сигнала зуммера, чтобы оттянуть диафрагму
delayMicroseconds(delayValue); // ожидание снова или рассчитанное значение задержки
}
}
/* Assign a unique ID to this sensor at the same time */
Adafruit_ADXL345_Unified accel = Adafruit_ADXL345_Unified(12345);
void setup(void)
{
if (F_CPU == 16000000) clock_prescale_set(clock_div_1);
Serial.begin(9600);
//Serial.println("Тест акселерометра"); Серийный.println("");
pinMode(4, OUTPUT);// выходной контакт зуммера
/* Initialise the sensor */
if(!accel.begin())
{
/* There was a problem detecting the ADXL345 ... check your connections */
//Serial.println("Ой, ADXL345 не обнаружен... Проверьте проводку!");
while(1);
}
/* Set the range to whatever is appropriate for your project */
accel.setRange(ADXL345_RANGE_16_G);
accel.setDataRate(ADXL345_DATARATE_100_HZ);
// displaySetRange(ADXL345_RANGE_8_G);
// displaySetRange(ADXL345_RANGE_4_G);
// displaySetRange(ADXL345_RANGE_2_G);
//Создать прерывание, которое сработает при обнаружении касания.
attachInterrupt(0, interrupt, RISING);
writeTo(0x1D, 0x2E, 0);
writeTo(0x1D, 0x2F, 0);
writeTo(0x1D, 0x2E, 128);
writeTo(0x1D, 0x2F, 127);
}
void loop(void)
{
if(sensor_update==1 ){
// Когда в ISR для sensor_update установлено значение 1, алгоритм обрабатывает данные с акселерометра, которые обновляются каждые 10 мс (100 Гц)
sensor_update=0;//сброс
}
}
@user49395, 👍0
Обсуждение2 ответа
Согласно таблице данных:
Функции прерывания фиксируются и сбрасываются при чтении регистры данных (от адреса 0x32 до адреса 0x37) до прерывания. условие больше не действует для прерываний, связанных с данными, или чтение регистра INT_SOURCE (адрес 0x30) для остальные прерывания.
Поэтому ISR, который просто устанавливает флаг, не будет вызываться во второй раз. По крайней мере, вам нужно прочитать регистр INT_SOURCE. Если вы используете библиотеку SparkFun ADXL345, то это будет вызов вида:
ADXL345 adxl = ADXL345();
void setup() {
adxl.powerOn();
adxl.setInterruptBitLevel(true); // активный минимум
attachInterrupt(digitalPinToInterrupt(interruptPin), isr, LOW);
pinMode(interruptPin, INPUT);
adxl.singleTapINT(1);
...
}
void isr(void) {
detachInterrupt(digitalPinToInterrupt(interruptPin));
interrupts();
byte source = adxl.getInterruptSource();
...
attachInterrupt(digitalPinToInterrupt(interruptPin), isr, LOW);
}
Обратите внимание, что здесь я использую прерывание по уровню и повторно разрешаю прерывания перед вызовом adxl.getInterruptSource()
. Проблема в том, что этот вызов может занять некоторое время, чтобы поговорить по шине I2C. Чтобы гарантировать отсутствие повторных вызовов, я сначала отключаю прерывание. Без этого режим с запуском по уровню вызывает цикл прерывания.
Использование прерывания по уровню имеет смысл, поскольку ADXL не будет создавать другое прерывание, пока вы не прочитаете из INT_SOURCE
. Кроме того, это позволяет избежать проблемы с отсутствием обнаружения границ, что может привести к незаметным ошибкам, которые трудно найти.
Я не был уверен в правильности включения прерываний в ISR, поэтому задал вопрос по этому поводу: Как правильно запрашивать устройство I2C из прерывания? сервисная программа?
Пробил себе голову этим. И искали решение в Интернете И часами пытались запрограммировать решение. Судя по моим тестам, проблема заключается в регистре 0x30 — INT_SOURCE заполнен триггерами. Но контакт INT срабатывает только при чтении регистра 0x30 — INT_SOURCE. Это означает, что, во-первых, Arduino нельзя вывести из спящего режима с помощью контактов INT1 или INT2, потому что они не изменяются, если только Arduino уже не проснулся и не читает регистр 0x30 — INT_SOURCE. Вторая проблема заключается в том, чтобы инициировать вывод прерывания INT для перехода к процедуре обслуживания прерывания ISR, которую вы должны прочитать в регистре 0x30 — INT_SOURCE. И если вы собираетесь это сделать, вы можете забыть о прерывании и просто перейти в ISR() и проверить в нем регистры. Вот как пример в Sparkfun_ADXL345_Example для arduino закончился с ADXL_ISR(); вызов в основном цикле. Подводить итоги. Если кто-то не знает, как заставить ADXL345 изменить состояние своих выводов INT без необходимости чтения регистра 0x30 — INT_SOURCE, тогда устройство бесполезно для использования с выводами INT. Я отказался от этого и ищу другое устройство, чтобы вывести ESP32 из спящего режима. Например, BMI160 — Bosch, который выглядит как соперник и имеет для него библиотеку Arduino.
- Как сгенерировать аппаратное прерывание в mpu6050 для пробуждения Arduino из режима SLEEP_MODE_PWR_DOWN?
- Arduino непрерывно считывает значение АЦП с помощью прерывания
- Как правильно использовать volatile переменные в Arduino?
- Как прервать функцию цикла и перезапустить ее?
- 4-битный счетчик вверх и вниз
- Включить и отключить отдельные прерывания
- Управление функцией включения на драйвере микрошагового устройства
- Захват прерывания на обоих фронтах, когда он установлен на RISING или FALLING
Похоже, часть вашего кода была обрезана; не могли бы вы добавить это? Кроме того, можете ли вы попытаться дать более подробное описание того, что вы хотите, чтобы код делал? что вы использовали, чтобы рассчитать время вашего кода?, @BrettAM
в основном мой алгоритм требует частоты дискретизации 100 Гц, и это то, что я использовал для его разработки в первую очередь. Прерывание, хотя и сконфигурированное с такой скоростью передачи данных, не работает должным образом, я предполагаю, что это проблема настройки прерывания., @user49395
Должны ли вы вручную запускать функцию прерывания в цикле или она должна запускаться только тогда, когда датчик вызывает прерывание?, @BrettAM
Я на самом деле только что заметил это. После удаления вызова прерывания из цикла прерывание просто никогда не сработает. Регистры включения и карты настроены правильно, может кто-нибудь подтвердить это, пожалуйста., @user49395
после некоторого устранения неполадок: установка pin2 в качестве входа ничего не меняет. тестирование, если выход ADXL INT1 переключается с выходной частотой 1 Гц, когда мультиметр дает 0 В, значит, проблема исходит от акселерометра, он почему-то ничего не генерирует. изменить: я изменил устройство на 0x53 вместо 0x1D, и теперь светодиод всегда горит, но не переключается жестко., @user49395