I'm trying to create a small battery powered alarm clock using an Arduino MKRZero and a generic SH1106-controlled, 128x64 pixel oled.
I started out just dumping all code into a single file named Clock.ino
. As the code got bigger, I started to split out functionality into separate classes. This went fine for timekeeping and alarms, but when I tried to do the same for the display functionality, I ran into an issue.
Now I wanted to split out my display code into a separate class. The working code before the refactor looks a bit like this:
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);
[...]
}
I tried to split it out like this:
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");
[...]
}
Display.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);
}
That didn't work, gave me a whole list of errors, all similar to these:
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 ~~~~~~^~~~
So I tried rewriting it in such a way that the u8xu
var is global like it was before, defining it in Display.cpp
and getting rid of the this->
before the u8x8.
method calls in the Display::
methods. That didn't work either. It compiles, but my display stays blank and the arduino gets stuck (does not interface with serial anymore until I hard-reset it).
At some point I rewrote the code such that I passes on the variable to the Constructur for Display
, but I think I completely botched that as I couldn't get it to compile.
so, main question: how do I instantiate an object inside my class, so it becomes available as a private variable?
If anyone wants to look at the full code, it's right here: https://github.com/ffective/wake-up/tree/master/Clock
The latest commit is the way of splitting up I described last: using a global variable. The previous commit is the working code with all Display methods just globally in Clock.ino
. Unfortunately I didn't save my attempts for putting it as a private variable.