Помогите со считыванием данных с акселерометра ADXL373 (I2C)

Я использую < a href="https://eu.mouser.com/ProductDetail/Analog-Devices/EVAL-ADXL373Z?qs=QNEnbhJQKva6ENie%252BWXLsQ%3D%3D">ADXL373Z акселерометр с Arduino Uno для проекта.

Когда я запускаю код, я получаю неверные значения, которые, вероятно, даже не являются данными ускорения. Я думаю, что это может быть проблема с проводкой, я прикрепил схему ниже. Это мой первый проект Arduino, и я не смог найти других приложений с датчиком, который использую, поэтому любая помощь будет очень признательна. Заранее спасибо .

Техническое описание датчика: https://www.analog.com/media /en/technical-documentation/data-sheets/adxl373.pdf

Код (только для данных по оси X):

// Тест акселерометра ADXL373

#include <Wire.h>

/* -------- REGISTERS -------- */
#define ADDRESS_ADXL373 0x53 // адрес датчика (предполагается высокий уровень на выводе MISO)
#define ADDRESS_POWER_CTL 0x3F // управление питанием
#define ADDRESS_MEASURE 0x0E // управление измерениями
#define ADDRESS_TIMING 0x3D // выходная скорость передачи данных и внешние триггеры синхронизации
#define ADDRESS_XDATA_H 0x08 // данные ускорения по оси x [11:4]
#define ADDRESS_XDATA_L 0x09 // данные ускорения по оси x [3:0]
#define ADDRESS_YDATA_H 0x0A // данные ускорения по оси Y [11:4]
#define ADDRESS_YDATA_L 0x0B // данные ускорения по оси Y [3:0]
#define ADDRESS_ZDATA_H 0x0C // данные ускорения по оси Z [11:4]
#define ADDRESS_ZDATA_L 0x0D // данные ускорения по оси Z [3:0]
/* -------- REGISTERS -------- */

#define SCALE_FACTOR 0.2f // 200 мг на коэффициент масштабирования LSB
#define GRAVITY_EARTH 9.80665f // гравитация земли в м/с^2

void setup() {
  Serial.begin(115200);
  while(!Serial);
  Serial.println("ADXL373 Accelerometer Test");
  Wire.begin();
  Wire.beginTransmission(ADDRESS_ADXL373);
  Wire.write(ADDRESS_POWER_CTL);
  Wire.write(0x03); // активируем полнополосный режим измерения
  Wire.endTransmission(true);
  delay(50);
  Wire.beginTransmission(ADDRESS_ADXL373);
  Wire.write(ADDRESS_MEASURE);
  Wire.write(0x04); // установить полосу пропускания выходного сигнала на 2560 Гц
  Wire.endTransmission(true);
  delay(50);
  Wire.beginTransmission(ADDRESS_ADXL373);
  Wire.write(ADDRESS_TIMING);
  Wire.write(0x80); // установить частоту выходных данных на 5120 Гц
  Wire.endTransmission(true);
  delay(50);
}

void loop() {
  byte xAxisH, xAxisL;
  Wire.beginTransmission(ADDRESS_ADXL373);
  Wire.write(ADDRESS_XDATA_H);
  Wire.endTransmission(false);
  Wire.requestFrom(ADDRESS_ADXL373, 1, true);
  xAxisH = Wire.read();
  Wire.beginTransmission(ADDRESS_ADXL373);
  Wire.write(ADDRESS_XDATA_L);
  Wire.endTransmission(false);
  Wire.requestFrom(ADDRESS_ADXL373, 1, true);
  xAxisL = Wire.read();
  int16_t xAxisFinal;
  xAxisFinal = (uint16_t) xAxisH << 8 | xAxisL; // битовый сдвиг и объединение двух компонентов
  xAxisFinal = xAxisFinal >> 4; // 12-битное разрешение
  float xAccel;
  xAccel = xAxisFinal * SCALE_FACTOR * GRAVITY_EARTH;
  Serial.print("Xa = "); Serial.println(xAccel);
  delay(200);
}

Схема цепи:

Схема цепи

Результаты последовательного монитора (в м/с^2):

Последовательный монитор

, 👍3

Обсуждение

xAxisFinal = xAxisH << 4 | xAxisL; Я думаю, вы имели в виду << 8., @timemage


1 ответ


5

Согласно техническому описанию, 12 бит ускорения Х хранятся в регистры XDATA_H и XDATA_L следующим образом:

XDATA_H:   b₁₁b₁₀b₉ b₈ b₇ b₆ b₅ b₄
XDATA_L:   b₃ b₂ b₁ b₀ x  x  x  x

где x означает «зарезервировано».

Теперь есть две проблемы с этим кодом:

xAxisFinal = xAxisH << 4 | xAxisL; // bit shift 12-bit output data

Первая проблема заключается в том, что при смещении xAxisH на четыре позиции биты b₇–b₄ оказываются в тех же позициях, что и биты b₃–b₀ в xAxisL. Затем, когда эти значения объединяются с |, бит b₇ смешивается с b₃, b₆ с b₂ и т. д. Если вы действительно хотите сдвинуть xAxisH влево на четыре места, вы также должны сдвинуть xAxisL вправо на четыре места.

Вторая проблема заключается в том, что данные x представляют собой число со знаком, представленное в виде дополнение до двух, и бит знака (b₁₁) оказывается не в том месте. За например, если измеренное значение равно −16 (XDATA_H:XDATA_L = 0xff:0x00), вы в конечном итоге читаете 4980 (0x0ff0). Чтобы избежать этой проблемы, вы можете знак расширяет 12-битное число до 16-битного.

Однако я бы предложил совершенно другой подход. Номер слева в регистрах датчика, так что просто оставьте это так:

xAxisFinal = (uint16_t) xAxisH << 8 | xAxisL;

Промежуточное приведение к uint16_t здесь, чтобы избежать неопределенного поведения, окончательный результат подписывается. Если есть риск того, что зарезервированные биты отличны от нуля (даташит не очень понятен в этом уважение), вы могли бы

xAxisFinal &= 0xfff0;  // очищаем последние 4 бита

Обратите внимание, что теперь единицей измерения ускорения является 1/16 разрешения датчик, и все значения, которые вы получаете, кратны 16. Я не ожидаю это будет проблемой. Если вы действительно хотите использовать разрешение сенсора как вашего устройства, теперь вы можете сместить xAxisFinal на четыре позиции вправо, который автоматически выполнит расширение знака.


Обновление: обращение к отредактированному коду из OP:

Я изменил код в соответствии с вашими предложениями. Но я все еще получение неверных значений от последовательного монитора.

В вашем сообщении я вижу очень маленькие значения, около ±3 младших разрядов от датчик. Это вполне может быть шум датчика. Но тогда есть иногда большее значение. Интересно, что эти большие значения кажутся очень близко к ±16 младших разрядов, намекая на какую-то связь проблема.

Думаю, ответ содержится в этом предупреждении из технического описания датчика:

Всегда считывайте данные ускорения, используя многобайтовые передачи, чтобы убедиться, что одновременный и полный набор данных ускорения x, y и z читать.

Представьте, что датчик выдает только шум, а шум колеблется. между -1 и +1 LSB. Что вы ожидаете, так это:

value  XDATA_H   XDATA_L
  −1   11111111  11110000
  +1   00000000  00010000

Если вы читаете XDATA_H и XDATA_L в двух разных транзакциях, вы вполне может прочитать 0b11111111 для XDATA_H (поскольку датчик читает -1), затем прочитайте 00010000 для XDATA_L (поскольку он получает +1). Когда ты объедините эти два показания вместе, и вы получите

value  XDATA_H   XDATA_L
 −15   11111111  00010000

Я предлагаю вам следовать рекомендациям из таблицы данных и прочитать оба регистрируется за один раз:

Wire.beginTransmission(ADDRESS_ADXL373);
Wire.write(ADDRESS_XDATA_H);
Wire.endTransmission(false);
Wire.requestFrom(ADDRESS_ADXL373, 2, true);
xAxisH = Wire.read();
xAxisL = Wire.read();
,

Хе. Ваш ответ пришел примерно тогда же, когда и мой комментарий., @timemage

Спасибо, я изменил код в соответствии с вашими предложениями. Но я все еще получаю неверные значения от последовательного монитора. Я отредактировал код и результаты в своем посте. Если у вас есть другие предложения, я был бы признателен., @Maxxie

@Maxxie: см. расширенный ответ., @Edgar Bonet