• Система автоматизации с открытым исходным кодом на базе esp8266/esp32 микроконтроллеров и приложения IoT Manager. Наша группа в Telegram

Нужна помощь магнитометр QRM3100 и ESP8266

pvvx

Активный участник сообщества
Круто. А энтузиасты за бугром такие поделки не делают? Неужели простыми средствами нельзя мониторить магнитное поле замли в метеостанции?
Делали, но только на одной бочке - "интузиастам" не интересует наведение на цели. Им о погоде больше :)
Да и подлодки давно не железные, а титановые... :p
 

post125

New member
Работать не будет.
а он и не работавет. Ваш нормально работает. Но, поскольку, задал вопрос, получил ответ, должен проверить и ответить.
А вы посмотрите схемы ММР-203 https://www.google.com/search?q=MMP-203+схема
Поставьте современную элементную базу, увеличьте катушки и разнесите, триангуляция...
Оцифруйте всю информацию, включая огибающие затухания, фазы и т.д. ESP не справится, но для Arduino есть не только ESP и на Arduino можно странслировать и СИ и C++ хоть мегабайтные :)
это сурово, я не потяну - не хватит ни времени, ни знаний. только чуть освоил ардуину, а тут почти с нуля прибор разрабатывать, да еще с математическими заморочками...
 

post125

New member
Работать не будет.
а он и не работавет. Ваш нормально работает. Но, поскольку, задал вопрос, получил ответ, должен проверить и ответить.
А вы посмотрите схемы ММР-203 https://www.google.com/search?q=MMP-203+схема
Поставьте современную элементную базу, увеличьте катушки и разнесите, триангуляция...
Оцифруйте всю информацию, включая огибающие затухания, фазы и т.д. ESP не справится, но для Arduino есть не только ESP и на Arduino можно странслировать и СИ и C++ хоть мегабайтные :)
это сурово, я не потяну - не хватит ни времени, ни знаний. только чуть освоил ардуину, а тут почти с нуля прибор разрабатывать, да еще с математическими заморочками...
 

post125

New member
Делали, но только на одной бочке - "интузиастам" не интересует наведение на цели. Им о погоде больше :)
Да и подлодки давно не железные, а титановые... :p
вот и мне цель не нужна, мне бы о погоде. а как у камрадов на одной бочке прибор может называться?
 

CodeNameHawk

Moderator
Команда форума
код такой:
  • #include <Wire.h>
  • //float x, y, z;
  • byte QRM3100_I2C_ADDRESS =0x23;
  • void setup() {
  • Serial.begin(9600);
  • Wire.begin();
  • writeRegister(0b0000001,0b01110001);
  • }
  • void loop() {
  • delay(500);
  • while ((readRegister(0x34) & 0x80) != 0x80) {}
  • int x =(int) ((uint32_t)readRegister(0x24))<<16+ ((uint32_t)readRegister(0x25))<<8+readRegister(0x26);
  • int y =(int) ((uint32_t)readRegister(0x27))<<16+ ((uint32_t)readRegister(0x28))<<8+readRegister(0x29);
  • int z =(int) ((uint32_t)readRegister(0x2A))<<16+ ((uint32_t)readRegister(0x2B))<<8+readRegister(0x2C);
Как этот код относится к моему совету?
Проблема возможно в
Создайте новые переменные типа int32_t, скопируйте в них mx, my, mz, а потом выполняйте вычисления.
 

pvvx

Активный участник сообщества
Как этот код относится к моему совету?
Там знак в 24-ом бите, а перевод младших 8-ми битных в числа со знаком всё исказит.
Исходное число состоит из одного знакового байта и двух без. Т.е. требуется непосредственный перевод одного со знаком и объединение с двумя без знаков.
 

post125

New member
Что то не так делаете, покажите код.
код (может не правильно понял ваши рекомендации, не работает):
Код:
#include <Wire.h>
float x, y, z;
byte QRM3100_I2C_ADDRESS =0x23;
uint32_t xx2 ;
uint32_t xx1 ;
uint32_t xx0 ;
uint32_t yy2 ;
uint32_t yy1 ;
uint32_t yy0 ;
uint32_t zz2 ;
uint32_t zz1 ;
uint32_t zz0 ;

void setup() {
  Serial.begin(9600);
  Wire.begin();
  writeRegister(0b0000001,0b01110001);
}

void loop() {

delay(500);

while ((readRegister(0x34) & 0x80) != 0x80) {}
  uint8_t mx2 = readRegister(0x24);
  uint8_t mx1 = readRegister(0x25);
  uint8_t mx0 = readRegister(0x26);
  uint8_t my2 = readRegister(0x27);
  uint8_t my1 = readRegister(0x28);
  uint8_t my0 = readRegister(0x29);
  uint8_t mz2 = readRegister(0x2A);
  uint8_t mz1 = readRegister(0x2B);
  uint8_t mz0 = readRegister(0x2C);

xx2 = mx2;
xx1 = mx1;
xx0 = mx0;
yy2 = my2;
yy1 = my1;
yy0 = my0;
zz2 = mz2;
zz1 = mz1;
zz0 = mz0;

  x = ((int32_t)(xx2 * 256 * 256) | (xx1 * 256) | xx0);
  y = ((int32_t)(yy2 * 256 * 256) | (yy1 * 256) | yy0);
  z = ((int32_t)(zz2 * 256 * 256) | (zz1 * 256) | zz0);

 

  Serial.print("M:  X\t");
  Serial.print(x);
  Serial.print("\t   Y\t");
  Serial.print(y);
  Serial.print("\t   Z\t");
  Serial.print(z);
  Serial.println("");
  delay(500); 
 
}

uint8_t readRegister(uint8_t address){  // функция чтения регистра
  uint8_t output;

  Wire.beginTransmission(QRM3100_I2C_ADDRESS);
  Wire.write(address);
  Wire.endTransmission();

  delayMicroseconds(2);

  Wire.requestFrom(QRM3100_I2C_ADDRESS, 1);
  while(Wire.available())
  {
  output = Wire.read();
  }
  return output;
}

void writeRegister(uint8_t address, uint8_t value){ // функция записи в регистр
  Wire.beginTransmission(QRM3100_I2C_ADDRESS);
  Wire.write(address);
  Wire.write(value);
  Wire.endTransmission();
}
 

CodeNameHawk

Moderator
Команда форума
post125, У вас проблема с приведением типов.(это делает компилятор)
Список команд Arduino

Код:
Arduino поддерживает работу с целыми числами в разных системах исчисления:
Базис     Префикс     Пример     Особенности
2 (двоичная)     B или 0b (ноль бэ)     B1101001     цифры 0 и 1
8 (восьмеричная)     0 (ноль)     0175     цифры 0 – 7
10 (десятичная)     нет     100500     цифры 0 – 9
16 (шестнадцатеричная)     0x (ноль икс)     0xFF21A     цифры 0-9, буквы A-F

ВАЖНО! Для арифметических вычислений по умолчанию используется ячейка long (4 байта), но при умножении и делении используется int (2 байта), что может привести к непредсказуемым результатам! Если при умножении чисел результат превышает 32’768, он будет посчитан некорректно. Для исправления ситуации нужно писать (тип данных) перед умножением, что заставит МК выделить дополнительную память для вычисления (например (long)35 * 1000). Также существую модификаторы, делающие примерно то же самое.

    u или U – перевод в формат unsigned int (от 0 до 65’535). Пример: 36000u
    l или L – перевод в формат long (-2 147 483 648… 2 147 483 647). Пример: 325646L
    ul или UL – перевод в формат unsigned long (от 0 до 4 294 967 295). Пример: 361341ul

Посмотрим, как это работает на практике:

    long val;
    val = 2000000000 + 6000000;         // посчитает корректно (т.к. сложение)
    val = 25 * 1000;                    // посчитает корректно (умножение, меньше 32'768)
    val = 35 * 1000;                    // посчитает НЕКОРРЕКТНО! (умножение, больше 32'768)
    val = (long)35 * 1000;              // посчитает корректно (выделяем память (long) )
    val = 35 * 1000L;                   // посчитает корректно (модификатор L)
    val = 35 * 1000u;                   // посчитает корректно (модификатор u)
    val = 70 * 1000u;                   // посчитает НЕКОРРЕКТНО (модификатор u, результат > 65535)
    val = 1000 + 35 * 10 * 100;         // посчитает НЕКОРРЕКТНО! (в умножении больше 32'768)
    val = 1000 + 35 * 10 * 100L;        // посчитает корректно! (модификатор L)
    val = (long)35 * 1000 + 35 * 1000;  // посчитает НЕКОРРЕКТНО! Второе умножение всё портит
    val = (long)35 * 1000 + (long)35 * 1000;  // посчитает корректно (выделяем память (long) )
    val = 35 * 1000L + 35 * 1000L;      // посчитает корректно (модификатор L)

Arduino поддерживает работу с числами с плавающей точкой (десятичные дроби). Этот тип данных не является для неё “родным”, поэтому вычисления с ним производятся в несколько раз дольше, чем с целочисленным типом (около 7 микросекунд на действие). Arduino поддерживает три типа ввода чисел с плавающей точкой:
Тип записи     Пример     Чему равно
Десятичная дробь     20.5     20.5
Научный     2.34E5     2.34*10^5 или 234000
Инженерный     67e-12     67*10^-12 или 0.000000000067

С вычислениями есть такая особенность: если в выражении нет float чисел, то вычисления будут иметь целый результат (дробная часть отсекается). Для получения правильного результата нужно писать (float) перед действием, или использовать float числа при записи. Смотрим:

    float val;
    val = 100 / 3;          // посчитает НЕПРАВИЛЬНО (результат 3.0)
    val = (float)100 / 3;   // посчитает правильно (указываем (float))
    val = 100.0 / 3;        // посчитает правильно (есть число float)
    val = 100 / 3.0;        // посчитает правильно (есть число float)
    float val2 = 100;
    val = val2 / 3;         // посчитает правильно (есть число float)

Ну и напоследок, при присваивании float числа целочисленному типу данных дробная часть отсекается. Если хотите математическое округление – его нужно использовать отдельно:

    int val;
    val = 3.25;         // val принимает 3
    val = 3.92;         // val принимает 3
    val = round(3.25);  // val принимает 3
    val = round(3.92);  // val принимает 4

Читай более подробный урок по математическим операциям.
 

pvvx

Активный участник сообщества
Полагаю Вы не правильно преобразуете
Во-первых это преобразование
(int32_t)(mx2 * 256 * 256)
означает что вы сначала умножили на 2^16 число, а потом преобразовали его в 32 битовое.
Всё тут пучком - итого будут правильные 16..31 биты в int32_t.
если mx2 - 8 бит то будет переполнение
надо делать так
((int32_t)mx2) * 256 * 256
а еще лучше сначала преобразуйте отдельным оператором в 32 бит все три числа а потом их складывайте
и формирование числа лучше записать так
X=(256*(256*Y|Z))|E вместо X=Y*256*256|256*Z|E
или так X=(((Y<<8)|Z)<<8)|E предварительно преобразовав Y Z к 32 битам
Так не будет работать :)
Если пошли таким начальным путем (int32_t)(mx2 * 256 * 256), то все последующие будут автоматом расширены на int32_t :p и or ('|') отработает неверно :p
Для однозначности вписывайте маски:
(int32_t)(mx2 * 256 * 256) | ((mx1 & 0xff)*256) | (mx1 & 0xff)
что увеличит код и кол-во действий, если оптимизатор не справиться...
 

pvvx

Активный участник сообщества
post125, У вас проблема с приведением типов.(это делает компилятор)
Список команд Arduino

Код:
Arduino поддерживает работу с целыми числами в разных системах исчисления:
Это полная лабуда. Arduino c ESP работает с GCC и там всё описано.
На синтаксис влияет только Using the GNU Compiler Collection (GCC): Standards
 

CodeNameHawk

Moderator
Команда форума
И если должны быть отрицательные значения то не uint32_t, а int32_t.
 

pvvx

Активный участник сообщества
@CodeNameHawk -
Можно начать с этого:
"ВАЖНО! Для арифметических вычислений по умолчанию используется ячейка long (4 байта), но при умножении и делении используется int (2 байта)"
С какого перепугу на 32-х битном CPU int стал 2 байта? :) :)
Ваше описание дано для 8-ми или 16-ти битного CPU?
 

CodeNameHawk

Moderator
Команда форума
"ВАЖНО! Для арифметических вычислений по умолчанию используется ячейка long (4 байта), но при умножении и делении используется int (2 байта)"
Указать явно никому не помешает, нп. если перенести код на ардуино плату.
 

pvvx

Активный участник сообщества
Указать явно никому не помешает, нп. если перенести код на ардуино плату.
На какую? Для Arduino есть CPU с int в 4, 8, 16, 32, 64 бит и со своими трансляторами, где всё по разному :)
В итоге выйдет путаница ещё хуже.
 

post125

New member
по идеи надо посмотреть, выдает ли датчик отрицательные значения, если выдает, тогда код надо писать по другому.
на ардуине про мини начальный код работает корректно и отрицательные значения выдает.
этот код от "pvvx" работает корректно и на ардуине и на есп8266:
Код:
union {
int32_t i;
int16_t w[2];
uint8_t ub[4];
} x;
int8_t a;
a = (int8_t) readRegister(0x24);
x.w[1] = (int16_t) a;
x.ub[1] = (uint8_t) readRegister(0x25);
x.ub[0] = (uint8_t) readRegister(0x26);
но не могу его пока вставить в метеостанцию - компиллятор ругается словами "... does not name a type"
 
Сверху Снизу