Как получить и интерпретировать данные цифрового акселерометра?

Я пытаюсь подключить Arduino к цифровому акселерометру . Arduino получает команды от мобильного приложения и передает их через Bluetooth через последовательный порт оборудования. Я также разместил этот вопрос здесь.

Код:

 #include < SPI.h >

const int X8 = 0x06;
const int Y8 = 0x07;
const int Z8 = 0x08;

/*
bits
1 0  mode 00: standby, 01: measurement
5     1: spi 3 wire, 0: 4 wire
4      self test
3     2 glevel: 01 2g
1 0  mode, 00 standby, 01 measurement 
*/
const int MODE = 0x16;

const int STATUS = 0x09;

//7 полоса пропускания цифрового фильтра, 0 62,5 Гц, 1 125 Гц
const int CONTROL = 0x18;

bool isTesting = false;

const int chipSelectPin = 7;

void setup() {
    Serial.begin(9600);
    SPI.begin();
    pinMode(chipSelectPin, OUTPUT);

    //настраиваем режим ожидания, 4-проводной разъем, диапазон 2G,
    writeRegister(MODE, 0x04);

    //настраиваем скорость
    writeRegister(CONTROL, 0x00);

    delay(100);
}
void loop() {
    if (getSerial() == 't') {
        isTesting = true;
        writeRegister(MODE, 0x05); // 0000 0101- 0001 0101 0x15
        testing();

    }

}
void testing() {
    while (isTesting) {
        if ((readRegister(STATUS) & 1) == 1) {
            Serial.print((char) readRegister(X8), DEC);
            Serial.print("x");
            Serial.print((char) readRegister(Y8), DEC);
            Serial.print("y");
            Serial.print((char) readRegisterChar(Z8), DEC);
            Serial.print("z");
        }

        if (getSerial() == 'u') {
            isTesting = false;
            writeRegister(MODE, 0x04);
        }
    }
}
char getSerial() {
    if (Serial.available()) {
        char c = Serial.read();
        return c;
    }
    return 'x';
}
byte readRegister(byte thisRegister) {
    byte inByte = 0;
    SPI.beginTransaction(SPISettings(500000, MSBFIRST, SPI_MODE0)); // часы 500 кГц
    digitalWrite(chipSelectPin, LOW);
    SPI.transfer(thisRegister << 1);
    inByte = SPI.transfer(0x00);
    digitalWrite(chipSelectPin, HIGH);
    return inByte;
}
char readRegisterChar(byte thisRegister) {
    char inChar = 0;
    SPI.beginTransaction(SPISettings(500000, MSBFIRST, SPI_MODE0)); // часы 500 кГц
    digitalWrite(chipSelectPin, LOW);
    SPI.transfer(thisRegister << 1);
    inChar = SPI.transfer(0x00);
    digitalWrite(chipSelectPin, HIGH);
    return inChar;
}
void writeRegister(byte thisRegister, byte value) {
    SPI.beginTransaction(SPISettings(500000, MSBFIRST, SPI_MODE0)); // часы 500 кГц
    digitalWrite(chipSelectPin, LOW);
    SPI.transfer(128 | thisRegister << 1);
    SPI.transfer(value);
    digitalWrite(chipSelectPin, HIGH);
}

Датчик допускает 10-битные значения данных, но для простоты я получаю только 8-битные данные. Данные, полученные, когда датчик находится на плоской поверхности:

xy z

5–11 74

4–19 74

2 -9 69

0 -8 68

7–16 68

7–11 73

Результаты самотестирования:

-5 -20 122

-4 -22 122

-1 -20 123

-4 -20 123

-5 -21 121

-3 -18 123

-8 -22 127

Из таблицы данных: «Когда функция самотестирования инициируется через регистр управления режимом ($16), доступ к «самотестированию» ; К каждой оси прикладывается электростатическая сила, вызывающая ее отклонение. Ось Z обрезана для отклонения 1г.";

Правильны ли данные? Как это интерпретируется? Если данные z во время самотестирования составляют 1 г, не должны ли они иметь ту же величину, что и на плоской поверхности?

Я приспособился к кодированию, чтобы получить 10 бит данных:

const int X10_LSB = 0x00;
const int X10_MSB = 0x01;
const int Y10_LSB = 0x02;
const int Y10_MSB = 0x03;
const int Z10_LSB = 0x04;
const int Z10_MSB = 0x05;

//[...]

void testing() {
        while (isTesting) {
            if ((readRegister(STATUS) & 1) == 1) {

                int xData = (readRegister(X10_MSB) << 8) | readRegister(X10_LSB);

                // проверяет, равен ли бит 9 1 и расширяется ли знак
                if ((xData & 512) == 512)
                    xData = (0b1111110000000000 | xData);
                int yData = (readRegister(Y10_MSB) << 8) | readRegister(Y10_LSB);
                if ((yData & 512) == 512)
                    yData = (0b1111110000000000 | yData);
                int zData = (readRegister(Z10_MSB) << 8) | readRegister(Z10_LSB);
                if ((zData & 512) == 512)
                    zData = (0b1111110000000000 | zData);

                Serial.print(xData);
                Serial.print("x");
                Serial.print(yData);
                Serial.print("y");
                Serial.print(zData);
                Serial.print("z");

            }

Выходные данные для измерения 2G:

4 246 -183

5 245 -183

5 245 -182

6 245 -181

Для самопроверки:

252 -20 -134

253 -21 -133

253 -21 -135

253 -20 -135

Значения для 8 и 10 бит данных не совпадают. Что я делаю не так?

Обновление: я переписал код, чтобы сначала получить 10 бит данных с младшими битами, как указано в комментарии:

Код:

     int xData =(readRegister (X10_LSB));
        xData = xData | (readRegister (X10_MSB)<<8);
        xData = xData << 6;
        int yData =(readRegister (Y10_LSB));
        yData = yData | (readRegister (Y10_MSB)<<8);
        yData = yData << 6;
        int zData = (readRegister (Z10_LSB));
        zData = zData | (readRegister (Z10_MSB)<<8);
        zData = zData << 6;

        xData /= 64;
        yData /= 64;
        zData /= 64;

Результаты работы датчика на плоской поверхности:

0–4 71

4–11 70

5–13 70

2–12 70

Результаты применения самотестирования:

-2 -19 123

-2 -19 122

-4 -20 122

-3 -21 122

Почему 8-битные и 10-битные результаты во время самотестирования возвращают одинаковые значения (около 128)? Должно ли 10-битное значение быть в 4 раза больше?

, 👍3

Обсуждение

Почему вы не сказали нам, что речь идет о датчике MMA7455L и что вы также задаете вопрос здесь: http://forum.arduino.cc/index.php?topic=465471.0 Пробовали ли вы библиотеку, которая, как известно, работает хорошо? Вы можете попытаться сдвинуть 10 бит на 6 бит влево для 16-битного целого числа с дополнением до 2. Сначала вы читаете MSB, но согласно таблице данных: «XOUTH следует читать непосредственно после чтения XOUTL»., @Jot

Вы пробовали этот [ссылка](https://playground.arduino.cc/Main/MMA7455) скетч с игровой площадки Arduino?, @chrisl


1 ответ


Лучший ответ:

2

Датчик допускает значения данных длиной 10 бит, но для простоты я получаю только 8-битные данные

Вы используете его в режиме 2g, поэтому у вас есть только 8 бит данных.

Данные, полученные при расположении датчика на плоской поверхности:

Это правильно. У вас есть 8-битный диапазон (256 значений, от -128 до +128), который отображает диапазон от +2g до -2g. Итак, у нас есть 256lsb/4g = 64lsb/g.
Неподвижно, длина вектора силы тяжести (sqrt(xx+yy+z*z)) должна быть близка к 64. Конечно, вам понадобится некоторое смещение и калибровка нелинейности, но данные кажутся хорошими.
Кроме того, если вы посмотрите на часть таблицы данных, которую вы разместили в таблице «Чувствительность», вы увидите, что они называют LSB «счетчиком», и они находятся в диапазоне, который мы рассчитали!

При запуске самотестирования результаты следующие:

И снова это верно , если ваш датчик плоский в том направлении, в котором гравитация применяется к Z; то, что вы видите, — это нормальная гравитация (64), суммирующаяся со смещением самотестирования (64), что дает вам хорошее значение ~128

Я адаптировал код для получения 10 бит данных:

Почему 8-битные и 10-битные результаты возвращают одинаковые значения во время самотестирования (около 128)? Должно ли 10-битное значение быть в 4 раза больше?

Чтобы использовать 10 бит, необходимо установить полный диапазон шкалы на +-8 г. Если вы посмотрите на часть таблицы данных, которую вы опубликовали, таблицу «Выходной сигнал», вы увидите, сколько бит доступно для каждого диапазона.
Если задуматься, как датчик узнает, хотите ли вы считать 8 или 10 бит? (помните, DS говорит, что вы должны считать младший регистр ПЕРЕД старшим!) если вы читаете только 8 бит, вы теряете 2 старших бита, один из которых представляет знак, а другой — самый важный бит, который может изменить ваш результат на 2^9=512 Кстати, ваше первое 10-битное преобразование также неверно, поскольку вы переворачиваете бит для дополнения до 2, но ничего не делаете с битом значения.
Решение с битовым смещением 6 и последующим делением работает, но выглядит немного странно. Я бы выбрал что-то более «стандартное», например

int xData = readRegister (X10_LSB) | (readRegister (X10_MSB) << 8);
if (xData | 0b0000 0010 0000 0000){ //if negative
    //keep 9 bit raspresenting the value and multiply by -1 to keep the sign
    xData = (xData & 0b0000 0001 1111 1111) * -1;
}
,