Прерывание 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;//сброс
  }
}  

, 👍0

Обсуждение

Похоже, часть вашего кода была обрезана; не могли бы вы добавить это? Кроме того, можете ли вы попытаться дать более подробное описание того, что вы хотите, чтобы код делал? что вы использовали, чтобы рассчитать время вашего кода?, @BrettAM

в основном мой алгоритм требует частоты дискретизации 100 Гц, и это то, что я использовал для его разработки в первую очередь. Прерывание, хотя и сконфигурированное с такой скоростью передачи данных, не работает должным образом, я предполагаю, что это проблема настройки прерывания., @user49395

Должны ли вы вручную запускать функцию прерывания в цикле или она должна запускаться только тогда, когда датчик вызывает прерывание?, @BrettAM

Я на самом деле только что заметил это. После удаления вызова прерывания из цикла прерывание просто никогда не сработает. Регистры включения и карты настроены правильно, может кто-нибудь подтвердить это, пожалуйста., @user49395

после некоторого устранения неполадок: установка pin2 в качестве входа ничего не меняет. тестирование, если выход ADXL INT1 переключается с выходной частотой 1 Гц, когда мультиметр дает 0 В, значит, проблема исходит от акселерометра, он почему-то ничего не генерирует. изменить: я изменил устройство на 0x53 вместо 0x1D, и теперь светодиод всегда горит, но не переключается жестко., @user49395


2 ответа


1

Согласно таблице данных:

Функции прерывания фиксируются и сбрасываются при чтении регистры данных (от адреса 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 из прерывания? сервисная программа?

,

0

Пробил себе голову этим. И искали решение в Интернете И часами пытались запрограммировать решение. Судя по моим тестам, проблема заключается в регистре 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.

,