Как правильно поместить дескриптор u8g2 в класс
Я пытаюсь создать небольшой будильник с батарейным питанием, используя Arduino MKRZero и универсальный OLED-дисплей с разрешением 128x64 пикселей, управляемый SH1106.
Я начал просто сбрасывать весь код в один файл с именем Clock.ino
. По мере того как код становился больше, я начал разбивать функциональность на отдельные классы. Это прекрасно подходило для хронометража и сигнализации, но когда я попытался сделать то же самое для функциональности дисплея, я столкнулся с проблемой.
Теперь я хотел разделить свой код отображения на отдельный класс. Рабочий код перед рефакторингом выглядит примерно так:
Clock.ino
//Display stuff
#include <U8x8lib.h>
#ifdef U8X8_HAVE_HW_SPI
#include <SPI.h>
#endif
U8X8_SH1106_128X64_NONAME_HW_I2C u8x8(/* reset=*/ U8X8_PIN_NONE);
void setup(void) {
u8x8.begin();
}
void print_clock([...]) {
[...]
u8x8.setCursor(0,3);
u8x8.print("23:59:59");
[...]
}
void loop(void) {
[...]
// Main clock
print_clock(clk.datetime);
[...]
}
Я попытался разделить его следующим образом:
Clock.ino
#include "Display.h"
Display disp;
void setup(void) {}
void loop(void) {
[...]
// Main clock
disp.print_clock([...]);
[...]
}
Display.cpp
#include "Display.h"
Display::Display() {
this->u8x8.begin();
}
void Display::print_clock([...]) {
[...]
this->u8x8.setCursor(0,3);
this->u8x8.print("23:59:59");
[...]
}
Дисплей.h
//Display stuff
#include <U8x8lib.h>
#ifdef U8X8_HAVE_HW_SPI
#include <SPI.h>
#endif
class Display {
public:
Display();
void print_clock([...]);
private:
U8X8_SH1106_128X64_NONAME_HW_I2C u8x8(/* reset=*/ U8X8_PIN_NONE);
}
Это не сработало, выдало мне целый список ошибок, все похожие на эти:
5 In file included from /home/simon/Arduino/libraries/U8g2/src/U8x8lib.h:45:0,
6 from sketch/Display.h:9,
7 from sketch/Display.cpp:1:
8 /home/simon/Arduino/libraries/U8g2/src/clib/u8x8.h:323:23: error: expected identifier before numeric c \>onstant
9 #define U8X8_PIN_NONE 255
10 ^
11 sketch/Display.h:26:55: note: in expansion of macro 'U8X8_PIN_NONE'
12 U8X8_SH1106_128X64_NONAME_HW_I2C u8x8(/* reset=*/ U8X8_PIN_NONE);
13 ^~~~~~~~~~~~~
14 /home/simon/Arduino/libraries/U8g2/src/clib/u8x8.h:323:23: error: expected ',' or '...' before numeric \> constant
15 #define U8X8_PIN_NONE 255
16 ^
17 sketch/Display.h:26:55: note: in expansion of macro 'U8X8_PIN_NONE'
18 U8X8_SH1106_128X64_NONAME_HW_I2C u8x8(/* reset=*/ U8X8_PIN_NONE);
19 ^~~~~~~~~~~~~
20 sketch/Display.cpp: In constructor 'Display::Display()':
21 Display.cpp:8:9: error: invalid use of member function 'U8X8_SH1106_128X64_NONAME_HW_I2C Display::u8x8 \>(int)' (did you forget the '()' ?)
22 this->u8x8.begin();
23 ~~~~~~^~~~
Поэтому я попытался переписать его таким образом, чтобы u8xu
var был глобальным, как это было раньше, определив его в Display.cpp
и избавляюсь от этого->>
до того, как u8x8.
вызовет метод на дисплее::
методы. Это тоже не сработало. Он компилируется, но мой дисплей остается пустым, и arduino застревает (больше не взаимодействует с последовательным интерфейсом, пока я его не сброшу).
В какой-то момент я переписал код таким образом, что передал переменную Конструктору для отображения
, но я думаю, что полностью ошибся, так как не смог заставить ее скомпилироваться.
итак, главный вопрос: как создать экземпляр объекта внутри моего класса, чтобы он стал доступным в качестве частной переменной?
Если кто-то хочет ознакомиться с полным кодом, он находится прямо здесь: https://github.com/ffective/wake-up/tree/master/Clock
Последняя фиксация-это способ разделения, который я описал последним: использование глобальной переменной. Предыдущая фиксация-это рабочий код со всеми методами отображения только в глобальном масштабе в Clock.ino
. К сожалению, я не сохранил свои попытки поместить его в качестве частной переменной.
@Simon, 👍-1
Обсуждение2 ответа
Вам нужно создать "пустой" объект в своем классе, а затем создать его экземпляр в списке инициализаторов конструктора:
class Display {
private:
U8X8_SH1106_128X64_NONAME_HW_I2C u8x8;
public:
Display() : u8x8(U8X8_PIN_NONE) {}
void print_clock([...]);
};
Частный объект не создается до тех пор, пока конструктор не будет вызван вызовом конструктора
Display ()
.
С этого момента вы можете использовать u8x8.whatever ()
, как обычно.
Также можно использовать U8X8_SH1106_128X64_NONAME_HW_I2C u8x8 { U8X8_PIN_NONE };
и ему не нужно использовать список инициализаторов в конструкторе по умолчанию. Здесь важно использовать {} вместо ()., @KIIV
Первые ошибки не очень полезны, но последняя, касающаяся функции-члена, объясняет все это. Вы не создаете переменную-член этого типа, вы пытаетесь создать функцию-член (со списком недопустимых параметров), которая возвращает значение U8X8_SH1106_128X64_NONAME_HW_I2C.
Этот код совершенно действителен:
class Display {
public:
Display() { u8x8.begin(); }
// вы также можете использовать другой инициализатор для объекта u8x8 (по умолчанию в этом случае он никогда не выполняется):
Display(uint8_t resetPin) : u8x8{resetPin} { u8x8.begin(); }
private:
U8X8_SH1106_128X64_NONAME_HW_I2C u8x8 { U8X8_PIN_NONE };
};
и в скетче:
// создание экземпляра:
Display disp{ 5 };
// или с конструктором по умолчанию и сбросом значения вывода
Display disp2;
- Какие накладные расходы и другие соображения существуют при использовании структуры по сравнению с классом?
- Поддерживает ли Arduino C++ динамические массивы объектов ?
- Прерывания внутри класса, связанные с функцией класса
- Наследование не работает должным образом
- Сообщение об ошибке при попытке настроить библиотеку U8g2
- Печать доступна с помощью U8GLib
- SSD1306 показывает статику, когда я пытаюсь отобразить изображение XBM
- Эффективный рабочий процесс/инструменты для преобразования цветных изображений в шестнадцатеричные массивы
То, что вы получили, - это объявление метода, а не определение переменной-члена. u8x8-это частный метод, возвращающий U8X8_SH1106_128X64_NONAME_HW_I2C. И он терпит неудачу на этой константе в списке параметров., @KIIV