Reputation: 9701
I have connected an 1.3in OLED display that uses I2C to my Arduino Uno plus two buttons using pullup resistors to act as "Previous" and "Next" arrows that switch between different images. I use the u8g2 library to communicate with and draw stuff on the screen:
#include <U8g2lib.h>
#include <Wire.h>
#define MAX_STATES 9
U8G2_SH1106_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, U8X8_PIN_NONE);
const char COPYRIGHT_SYMBOL[] = {0xa9, '\0'};
void u8g2_prepare() {
u8g2.setFont(u8g2_font_6x10_tf);
u8g2.setFontRefHeightExtendedText();
u8g2.setDrawColor(1);
u8g2.setFontPosTop();
u8g2.setFontDirection(0);
}
void u8g2_box_frame() {
u8g2.drawStr(0, 0, "drawBox");
u8g2.drawBox(5, 10, 20, 10);
u8g2.drawStr(60, 0, "drawFrame");
u8g2.drawFrame(65, 10, 20, 10);
}
void u8g2_r_frame_box() {
u8g2.drawStr(0, 0, "drawRFrame");
u8g2.drawRFrame(5, 10, 40, 15, 3);
u8g2.drawStr(70, 0, "drawRBox");
u8g2.drawRBox(70, 10, 25, 15, 3);
}
void u8g2_disc_circle() {
u8g2.drawStr(0, 0, "drawDisc");
u8g2.drawDisc(10, 18, 9);
u8g2.drawStr(60, 0, "drawCircle");
u8g2.drawCircle(70, 18, 9);
}
void u8g2_string_orientation() {
u8g2.setFontDirection(0);
u8g2.drawStr(5, 15, "0");
u8g2.setFontDirection(3);
u8g2.drawStr(40, 25, "90");
u8g2.setFontDirection(2);
u8g2.drawStr(75, 15, "180");
u8g2.setFontDirection(1);
u8g2.drawStr(100, 10, "270");
}
void u8g2_line() {
u8g2.drawStr(0, 0, "drawLine");
u8g2.drawLine(7, 20, 77, 32);
}
void u8g2_triangle() {
u8g2.drawStr(0, 0, "drawTriangle");
u8g2.drawTriangle(14, 20, 45, 30, 10, 32);
}
void u8g2_unicode() {
u8g2.drawStr(0, 0, "Unicode");
u8g2.setFont(u8g2_font_unifont_t_symbols);
u8g2.setFontPosTop();
u8g2.setFontDirection(0);
u8g2.drawUTF8(10, 20, "☀");
u8g2.drawUTF8(30, 20, "☁");
u8g2.drawUTF8(50, 20, "☂");
u8g2.drawUTF8(70, 20, "☔");
u8g2.drawUTF8(95, 20, COPYRIGHT_SYMBOL); //COPYRIGHT SIMBOL
u8g2.drawUTF8(115, 15, "\xb0"); // DEGREE SYMBOL
}
#define image_width 128
#define image_height 21
static const unsigned char image_bits[] U8X8_PROGMEM = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x06, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x1f, 0x00, 0x00,
0xfc, 0x1f, 0x00, 0x00, 0x06, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xfe, 0x1f, 0x00, 0x00, 0xfc, 0x7f, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x07, 0x18, 0x00, 0x00, 0x0c, 0x60, 0x00, 0x00,
0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x18, 0x00, 0x00,
0x0c, 0xc0, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x03, 0x18, 0x00, 0x00, 0x0c, 0xc0, 0xf0, 0x1f, 0x06, 0x63, 0x80, 0xf1,
0x1f, 0xfc, 0x33, 0xc0, 0x03, 0x18, 0x00, 0x00, 0x0c, 0xc0, 0xf8, 0x3f,
0x06, 0x63, 0xc0, 0xf9, 0x3f, 0xfe, 0x33, 0xc0, 0x03, 0x18, 0x00, 0x00,
0x0c, 0xc0, 0x18, 0x30, 0x06, 0x63, 0xc0, 0x18, 0x30, 0x06, 0x30, 0xc0,
0xff, 0xff, 0xdf, 0xff, 0x0c, 0xc0, 0x18, 0x30, 0x06, 0x63, 0xe0, 0x18,
0x30, 0x06, 0x30, 0xc0, 0xff, 0xff, 0xdf, 0xff, 0x0c, 0xc0, 0x98, 0x3f,
0x06, 0x63, 0x60, 0x98, 0x3f, 0x06, 0x30, 0xc0, 0x03, 0x18, 0x0c, 0x00,
0x0c, 0xc0, 0x98, 0x1f, 0x06, 0x63, 0x70, 0x98, 0x1f, 0x06, 0x30, 0xc0,
0x03, 0x18, 0x06, 0x00, 0x0c, 0xc0, 0x18, 0x00, 0x06, 0x63, 0x38, 0x18,
0x00, 0x06, 0x30, 0xc0, 0x03, 0x18, 0x03, 0x00, 0x0c, 0xe0, 0x18, 0x00,
0x06, 0x63, 0x1c, 0x18, 0x00, 0x06, 0x30, 0xc0, 0x00, 0x80, 0x01, 0x00,
0xfc, 0x7f, 0xf8, 0x07, 0x1e, 0xe3, 0x0f, 0xf8, 0x07, 0x06, 0xf0, 0xcf,
0x00, 0xc0, 0x00, 0x00, 0xfc, 0x3f, 0xf0, 0x07, 0x1c, 0xe3, 0x07, 0xf0,
0x07, 0x06, 0xe0, 0xcf, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x30, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0xe0, 0x00, 0xfc, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x00, 0xfc, 0x1f, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f
};
void u8g2_bitmap() {
u8g2.drawXBMP(0, 5, image_width, image_height, image_bits);
}
void setup(void) {
pinMode(8, INPUT_PULLUP);
pinMode(7, INPUT_PULLUP);
Serial.begin(9600);
u8g2.begin();
u8g2_prepare();
}
float i = 0.0;
int state = 0;
typedef struct Button
{
char state_old;
char state_new;
bool pressed;
Button ()
{
state_old = LOW;
state_new = LOW;
pressed = false;
}
} Button;
Button prevButton;
Button nextButton;
void loop(void) {
prevButton.state_new = digitalRead(8);
nextButton.state_new = digitalRead(7);
if (prevButton.state_new != prevButton.state_old)
{
prevButton.pressed = prevButton.state_new == LOW;
if (prevButton.pressed)
{
Serial.println("Previous");
state = ((state - 1) + MAX_STATES) % MAX_STATES;
}
}
if (nextButton.state_new != nextButton.state_old)
{
nextButton.pressed = nextButton.state_new == LOW;
if (nextButton.pressed)
{
Serial.println("Next");
state = (state + 1) % MAX_STATES;
}
}
prevButton.state_old = prevButton.state_new;
nextButton.state_old = nextButton.state_new;
switch (state)
{
case 0:
u8g2.clearBuffer();
u8g2_prepare();
u8g2_box_frame();
u8g2.sendBuffer();
break;
case 1:
u8g2.clearBuffer();
u8g2_disc_circle();
u8g2.sendBuffer();
break;
case 2:
u8g2.clearBuffer();
u8g2_r_frame_box();
u8g2.sendBuffer();
break;
case 3:
u8g2.clearBuffer();
u8g2_prepare();
u8g2_string_orientation();
u8g2.sendBuffer();
break;
case 4:
u8g2.clearBuffer();
u8g2_line();
u8g2.sendBuffer();
break;
case 5:
u8g2.clearBuffer();
u8g2_triangle();
u8g2.sendBuffer();
break;
case 6:
u8g2.clearBuffer();
u8g2_prepare();
u8g2_unicode();
u8g2.sendBuffer();
break;
case 7:
u8g2.clearBuffer();
u8g2_bitmap();
u8g2.sendBuffer();
break;
case 8:
u8g2.clearBuffer();
u8g2.setCursor(0, 0);
u8g2.print(i);
i = i + 1.5;
u8g2.sendBuffer();
break;
}
Serial.print("Current state:");
Serial.println(state);
delay(100);
}
The issue doesn't (at least I think) come from the library itself. As you can see I have created a very simple sequence of states that I switch between using the buttons. The previous button decrements, while the next - increments the state. Of course since I want to have a wrap-around behaviour (going one state more after last state will change the state to the lowest one and vice versa) I use modulo.
It works...To some extent. When I reach state 0 (lowest state) and press the previous button I expect "Current state: 8" to be displayed in the serial monitor and the respective image data to be loaded in the buffer of the OLED. Instead I get the following behaviour:
I get output in the serial monitor:
Pre?
The OLED doesn't change it's buffer to the last state
With stop working I mean I can neither increment, nor decrement the state using the button and the continious output "Current state: ..." is not printed. I actually just checked and the same issue happens with the increment.
I have used such modulo many times so I am very perplexed as to why this is happening. I can understand to get (for some reason) the incorrect state but for the whole thing to freeze...
One thing I've noticed when flashing the microcontroller is a warning in the Arduino IDE:
Sketch uses 24852 bytes (77%) of program storage space. Maximum is 32256 bytes.
Global variables use 1945 bytes (94%) of dynamic memory, leaving 103 bytes for local variables. Maximum is 2048 bytes.
Low memory available, stability problems may occur.
Is it possible that this is what is happening? If so, how is it related to a simple decrement of an integer?
Upvotes: 0
Views: 343
Reputation: 1835
Modulo division is rather expensive, so let's do simply:
const byte STATECOUNT = 9;
static byte state; // 9 values (range 0 .. 8) circular
if (buttonup) {
state++;
if (state >= STATECOUNT) state = 0;
}
else if(buttondn){
if (state == 0) state = STATECOUNT;
state--;
}
Upvotes: 0