Передача ссылки на оборудование между методами в пользовательском классе
Я новичок в C++/Arduino и впервые пытаюсь создать пользовательскую библиотеку. Я создал модуль с именем CDSensors.cpp
, который имеет два метода: SetupSensor
и ReadSensors
. Датчик представляет собой акселерометр/магнитометр SparkFun.
При наличии ошибок в настройках датчик возвращает все нули для компаса и акселерометра. Если между методами SetupSensor
и ReadSensor
нет указателя или другой связи, датчик возвращает все нули, как если бы он не был настроен.
Поэтому я пытаюсь передать ссылку на библиотеку датчиков между методами, как показано с объектом Limu в приведенном ниже коде. Теперь я получаю магнитные данные, но акселерометр возвращает все нули, поэтому что-то в моих ссылках на объекты мешает настройке датчика? (акселерометр нормально работает в демонстрационном коде SparkFun, на котором основан мой код).
Main.ino
#include <CDSensors.h>
#include <Wire.h>
#include <SPI.h>
#include <SparkFunMPU9250-DMP.h>
CDSensors* LSensors = &CDSensors (0);
CDSerialPrint* LSerialPrint = &CDSerialPrint (0);
MPU9250_DMP Limu = MPU9250_DMP ();
unsigned long LTimeNow = 0;
struct meas {
int BUx;
int acc_x
};
struct meas r;
void setup() {
LSensors->SetupSensors (Limu);
}
void loop() {
LSensors->ReadSensors (Limu, LTimeNow, r.BUx, r.acc_x);
Serial.print((int) (r.BUx) );
Serial.print((int) (r.acc_x) );
}
CDSensors.h
#ifndef CDSensors_h_h
#define CDSensors_h
#include <Wire.h>
#include <SPI.h>
#include <SparkFunMPU9250-DMP.h>
class CDSensors {
public:
CDSensors(int);
static void SetupSensors(MPU9250_DMP *imu);
void ReadSensors (MPU9250_DMP *imu, unsigned long& TimeNow, int& BUx,int& BUy,int& BUz,int& acc_x,int& acc_y,int& acc_z,int& a0,int& a1,int& a2,int& a3 );
private:
int value;
};
#endif
CDSensors.cpp
#include <Wire.h>
#include <SPI.h>
#include <SparkFunMPU9250-DMP.h>
#include "CDSensors.h"
//MPU9250_DMP imu;
boolean MPU9250_found = false;
unsigned long TimeNow = 0;
CDSensors::CDSensors(int givenValue) {
value = givenValue;
}
static void CDSensors::SetupSensors(MPU9250_DMP imu) {
if (imu.begin() != INV_SUCCESS) {
while (1) {
Serial.println("No MPU-9250 found, Check connections");
delay(5000);
}
}
imu.setSensors(INV_XYZ_ACCEL | INV_XYZ_GYRO | INV_XYZ_COMPASS);
imu.setGyroFSR(2000);
imu.setAccelFSR(2);
imu.setLPF(188);
imu.setSampleRate(100);
imu.setCompassSampleRate(100);
}
void CDSensors::ReadSensors(MPU9250_DMP imu, unsigned long& TimeNow, int& BUx, int& acc_x) {
TimeNow = millis();
if (imu.dataReady()) {
imu.update(UPDATE_ACCEL | UPDATE_GYRO | UPDATE_COMPASS);
}
BUx = imu.calcMag(imu.mx);
acc_x = imu.calcAccel(imu.ax);
}
@Hamish_Fernsby, 👍0
Обсуждение1 ответ
Я не думаю, что вы правильно создаете экземпляры этих классов. Вместо:
CDSensors* LSensors = &CDSensors (0);
CDSerialPrint* LSerialPrint = &CDSerialPrint (0);
MPU9250_DMP Limu = MPU9250_DMP ();
Как насчет:
CDSensors LSensors (0);
CDSerialPrint LSerialPrint (0);
MPU9250_DMP Limu;
Я не могу заставить ваш код скомпилироваться, но то, что я предлагаю, выглядит намного проще.
Ваше намерение здесь:
if (imu.begin() != INV_SUCCESS)
imu.setSensors(INV_XYZ_ACCEL | INV_XYZ_GYRO | INV_XYZ_COMPASS);
imu.setGyroFSR(2000);
imu.setAccelFSR(2);
imu.setLPF(188);
imu.setSampleRate(100);
imu.setCompassSampleRate(100);
.. быть на самом деле:
if (imu.begin() != INV_SUCCESS)
{
imu.setSensors(INV_XYZ_ACCEL | INV_XYZ_GYRO | INV_XYZ_COMPASS);
imu.setGyroFSR(2000);
imu.setAccelFSR(2);
imu.setLPF(188);
imu.setSampleRate(100);
imu.setCompassSampleRate(100);
}
На это указывает отступ.
если я правильно понял, класс создается при запуске с помощью
CDSensors* LSensors = &CDSensors (0);
и затем сохраняется.
LSensors
— это постоянный указатель, а CDSensors (0)
— это временный объект, созданный для выполнения присваивания. Например:
int foo = 2 + 3;
Теперь компилятор вычисляет 2 + 3 (давая 5), присваивает это значение foo, а затем отбрасывает временно вычисленное 5, используемое для выполнения присваивания.
В вашем случае CDSensors (0)
вызывает конструктор для CDSensors, создавая временный объект. Затем "&" оператор берет свой адрес (где-то в стеке, я думаю). Этот адрес копируется в LSensors. Затем объект уничтожается, потому что его время жизни закончилось. Компилятор даже предупреждает вас об этом:
CDSensors* LSensors = &CDSensors (0);
^
sketch_may07a:5: error: taking address of temporary [-fpermissive]
Это означает, что указатель теперь недействителен, поскольку базовый объект (на который он указывает) теперь отброшен.
Я даже видел, как люди довольно часто делают что-то подобное:
CDSensors LSensors = CDSensors (0);
Это не так уж плохо, потому что указатели не задействованы, но все равно нужно создать временный экземпляр класса, затем копировать его в LSensors и отбросить исходный экземпляр.
Вот как создать новый экземпляр класса:
CDSensors LSensors (0); // фактический класс, а не указатель
Или, если вам нужен указатель:
CDSensors * pLSensors; // указатель на класс (изначально NULL)
Затем в setup
вы создаете экземпляр:
pLSensors = new CDSensors (0);
Спасибо, Ник, я попробовал этот вариант, он также компилируется нормально, но все еще имеет ту же проблему с вспомогательным датчиком accl, возвращающим нули., @Hamish_Fernsby
Добавьте несколько отладочных отпечатков, не мучайтесь добавлением указателей в надежде, что это исправит ситуацию., @Nick Gammon
Также см. мой измененный ответ., @Nick Gammon
Re if (imu.begin() != INV_SUCCESS) извините опечатка в коде вверху, которая теперь исправлена., @Hamish_Fernsby
Я задавался вопросом, может ли это быть связано с конструкторами, но, если я правильно понял, класс создается при запуске с помощью CDSensors* LSensors = &CDSensors (0); а потом настойчиво. (в отличие от того, к чему я привык в Delphi, где вы можете везде набирать create/destroy)., @Hamish_Fernsby
Указатели - правильно - я полагаю, что добавление указателей экономит ресурсы, но вряд ли исправит ошибку времени выполнения., @Hamish_Fernsby
Смотрите измененный ответ., @Nick Gammon
Третья часть вводит в заблуждение. Говорить о "недопустимом указателе" нет смысла, так как сам код просто недействителен: язык не позволяет применять встроенный &
к временному. Это не компилируется. Я не знаю, почему ОП продолжает угадывать, является ли объект постоянным или нет. Нет смысла в том, что когда код просто не компилируется., @AnT
Четвертая часть также вводит в заблуждение. Даже в старом «классическом» C++ синтаксис инициализации копированием немедленно интерпретируется как прямая инициализация, когда типы в левой и правой частях совпадают. Временный объект не создается, копирование не выполняется. Аргументы конструктора немедленно передаются объекту LHS. Синтаксис инициализации копирования в этом случае является повторяющимся, громоздким и ненужным, но он не страдает от неэффективности, которую вы описываете в своем ответе. Он полностью эквивалентен «короткой» версии., @AnT
Я бы добавил к комментарию AnT таким образом, зачем передавать Limu в качестве параметра обеим функциям, когда сконструированный объект уже является глобальным. Просто используйте Limu
и удалите параметр в обоих методах. Если бы вы действительно хотели быть "OO", вы бы передали "Limu" конструктору. Так как вы передаете int
, который выглядит так, как будто никогда не используется, чего я не понимаю, если код отсутствует или не планируется на потом., @Kelly S. French
- Ошибка: "недопустимое использование нестатической функции-члена" при вызове функции из моего собственного класса-метода
- В чем разница между акселерометром, гироскопом и датчиком магнитометра?
- Как прочитать необработанные данные с модуля GY-85?
- Компас с компенсацией наклона Adafruit_LSM303
- Как правильно поместить дескриптор u8g2 в класс
- Используйте ISR внутри библиотеки более элегантно
- Компас с компенсацией наклона Использование HMC5983 дает непоследовательный вывод
- Как объявить указатель на библиотеку arduino neopixels, чтобы настроить его в функции настройки с помощью динамических переменных?
Есть ли причина, по которой вы определяете
MPU9250_DMP
вне вашего класса и в вашем основном скетче? Если вы объявите его внутри класса как переменную-член, вы можете отказаться от обработки ссылок, @chrislПопробуйте передать параметр imu по ссылке (вместо копирования), т. е.
MPU9250_DMP& imu
, в функции-члены SetupSensors и ReadSensors., @Mikael Patel@ChrisL Когда он был определен только в классе CDSensors, датчик возвращал все нули. Проверил локальным сериалпринтом, полагаю как-то теряется связь между настройками и чтением данных., @Hamish_Fernsby
@Nisse извините, исправил отступы и опечатки, я думаю, ваш комментарий решен., @Hamish_Fernsby
Как вы определяете это в классе? Вы выполнили его конструктор? Если нет, то проблема могла быть в нем, @chrisl
Можете ли вы опубликовать CDSensors.h? Я не могу понять
CDSensors* LSensors = &CDSensors (0); CDSerialPrint* LSerialPrint = &CDSerialPrint (0);
Как говорится в предупреждении, вы берете адрес временного объекта, который перестает существовать в конце этой строки., @Nick GammonПочему вы вообще используете классы? Датчиков будет много? Если это так, то делать функцию-член статической не имеет смысла., @Nick Gammon
@Mikael, новичок в указателях, я попробовал MPU9250_DMP * imu и MPU9250_DMP * imu В любом случае я получаю эту ошибку - неизвестное преобразование для аргумента 1 из «MPU9250_DMP» в «MPU9250_DMP & imu дает ту же проблему с возвратом нулей вспомогательного датчика., @Hamish_Fernsby
@Nick, почему классы - причина для перемещения этого фрагмента кода в отдельный блок .cpp заключается в том, что программа собирается стать намного сложнее, много математики и GPRS-связи, поэтому настройка / чтение датчика казались логичным куском чтобы выйти из main.ino Я предполагаю, что отдельный блок .cpp требует определения класса?, @Hamish_Fernsby
Нет, совсем нет., @Nick Gammon
И если вы изменили код, пожалуйста, опубликуйте измененный код. Мы не можем отлаживать код, который не видим., @Nick Gammon
Измените «static void SetupSensors (MPU9250_DMP * imu)» на «static void SetupSensors (MPU9250_DMP & imu)» как в исходном, так и в заголовочном файле. Внесите те же изменения в «ReadSensors». BW, почему вы используете
static
дляSetupSensors
., @Mikael Patel