I'm having a really strange problem with my screen. It's connected in i2c to my Arduino Nano and I'm using a rotary encoder to navigate through a menu.
At startup everything is fine, but when I change menus a couple of times, there are flickering artifacts that start showing up in the bottom right corner. Did anyone ever get that kind of localized noise?
I thought maybe it would be my refresh rate that was a bit too high, I only had 10ms. But I cranked it up to 50 and it didn't change a thing.
EDIT: Thank you for your feedback! I tried a different approach, like you suggested, and got rid of all the calls to displayMenu() and the multiple while loops. The artifacts are smaller now, but they're still there...
They used to occur all the time and now they're just appearing during chooseValue() and action3() now. As if it was linked to the "value" variable. I don't get it...
Here's the updated code:
#include <Arduino.h>
#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <Adafruit_I2CDevice.h>
#include <math.h>
#include <RotaryEncoder.h>
#include <ButtonStates.h>
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET -1 // Reset pin # (or -1 if sharing Arduino reset pin)
#define SCREEN_ADDRESS 0x3C
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
RotaryEncoder encoder(A2, A3); // Rotary encoder connected to A2 and A3
ButtonSwitch button(2); // Rotary encoder button
int value = 0; // Value changed in one of the menus
int selection = 0; // Encoder position
struct menuItem { // Structure defining a menu item
const char *name; // Item name
void (*action)(); // Pointer pointing to the function handling the action
};
struct menu { // Structure defining a menu
char *name; // Menu name
int items; // Number of items in the menu
struct menuItem *collection; // Array containing all the menu items
};
struct menuItem menu1collection[5]; // Array for the menu
struct menuItem item1, item2, item3, item4, item5; // Items of the menu
struct menu menu1 = { "Today's menu", 5, menu1collection }; // Structure holding all the menu's info
struct menuItem menu2collection[4];
struct menuItem item6, item7, item8, item9;
struct menu menu2 = { "Tomorrow's menu", 4, menu2collection };
struct menu currentmenu = menu1;
enum screens { MENU, CHOOSEVAL };
enum screens screen = MENU;
void chooseValue(){
display.clearDisplay();
display.setTextSize(2);
display.setTextColor(SSD1306_WHITE);
display.setCursor(0, 20);
display.write( 17 );
display.setCursor(45, 20);
display.print(selection);
display.print("g");
display.setCursor(115, 20);
display.write( 16 );
display.display();
}
void displayMenu(){ // Function displaying the menu passed in argument
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(SSD1306_WHITE);
display.setCursor(0, 5);
display.println(currentmenu.name); // Display menu title
int div = floor((selection-0.5)/4); // Handle menus with more than 4 elements
for(int i=(4*div+1), j=0 ; i<=currentmenu.items && j<4 ; i++, j++){ // Cycle through 4 menu items
if(i==selection){ // Highlight selected item
display.fillRect(0, 18+10*j, 128, 10, SSD1306_WHITE);
display.setCursor(20, 20+10*j);
display.setTextColor(SSD1306_BLACK);
display.println(currentmenu.collection[i-1].name);
}
else{
display.setTextColor(SSD1306_WHITE);
display.setCursor(20, 20+10*j);
display.println(currentmenu.collection[i-1].name); // Display item
}
}
display.display();
}
ISR(PCINT1_vect) { // Interrupt routine for the rotary encoder
encoder.tick(); // Check the state of the encoder
}
// Functions handling the actions for each menu item ------------------------------------------------------------------
void action1(){
screen = CHOOSEVAL;
}
void action2(){
currentmenu = menu2;
encoder.setPosition(1);
}
void action3(){
display.clearDisplay();
display.setTextSize(2);
display.setTextColor(SSD1306_WHITE);
display.setCursor(45, 20);
display.print(value);
display.println("g");
display.display();
delay(1000);
}
void action4(){
display.clearDisplay();
display.setTextSize(2);
display.setTextColor(SSD1306_WHITE);
display.setCursor(0, 20);
display.println("Action 4!");
display.display();
delay(500);
}
void action5(){
display.clearDisplay();
display.setTextSize(2);
display.setTextColor(SSD1306_WHITE);
display.setCursor(0, 20);
display.println("Action 5!");
display.display();
delay(500);
}
void action6(){
display.clearDisplay();
display.setTextSize(2);
display.setTextColor(SSD1306_WHITE);
display.setCursor(0, 20);
display.println("Action 6!");
display.display();
delay(500);
}
void action7(){
display.clearDisplay();
display.setTextSize(2);
display.setTextColor(SSD1306_WHITE);
display.setCursor(0, 20);
display.println("Action 7!");
display.display();
delay(500);
}
void action8(){
display.clearDisplay();
display.setTextSize(2);
display.setTextColor(SSD1306_WHITE);
display.setCursor(0, 20);
display.println("Action 8!");
display.display();
delay(500);
}
void action9(){
currentmenu = menu1;
encoder.setPosition(1);
}
// -------------------------------------------------------------------------------------------------------------------
void handleMenu(){
}
void setup() {
Serial.begin(9600);
// Creating a menu requires the following ----------------------------------------------------------------------------
item1.name = "Choose a value";
item1.action = action1;
menu1collection[0] = item1;
item2.name = "Go to menu 2";
item2.action = action2;
menu1collection[1] = item2;
item3.name = "Display value";
item3.action = action3;
menu1collection[2] = item3;
item4.name = "Item 4";
item4.action = action4;
menu1collection[3] = item4;
item5.name = "Item 5";
item5.action = action5;
menu1collection[4] = item5;
item6.name = "Item 6";
item6.action = action6;
menu2collection[0] = item6;
item7.name = "Item 7";
item7.action = action7;
menu2collection[1] = item7;
item8.name = "Item 8";
item8.action = action8;
menu2collection[2] = item8;
item9.name = "< Back";
item9.action = action9;
menu2collection[3] = item9;
// -------------------------------------------------------------------------------------------------------------------
PCICR |= (1 << PCIE1); // This enables Pin Change Interrupt 1 that covers the Analog input pins or Port C.
PCMSK1 |= (1 << PCINT10) | (1 << PCINT11); // This enables the interrupt for pin 2 and 3 of Port C.
if(!display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS)) { // SSD1306_SWITCHCAPVCC = generate display voltage from 3.3V internally
Serial.println(F("SSD1306 allocation failed"));
for(;;); // Don't proceed, loop forever
}
// Init display
display.clearDisplay();
display.setTextSize(2);
display.setTextColor(SSD1306_WHITE);
display.setCursor(0, 20);
display.println("Loading...");
display.display();
delay(500);
}
void loop() {
switch(screen){
case MENU:
selection = encoder.getPosition(); // Get the encoder's position
if (selection < 1) { // Stop the encoder on the min position
encoder.setPosition(1);
selection = 1;
} else if (selection > currentmenu.items) { // Stop the encoder on the max position (number of items minus 1)
encoder.setPosition(currentmenu.items);
selection = currentmenu.items;
}
displayMenu();
if (button.triggerSingle()){
currentmenu.collection[selection-1].action(); // If a click is detected do the item's action
}
break;
case CHOOSEVAL:
selection = value + encoder.getPosition() * 10;
if (selection < 1) { // Stop the encoder on the min position
encoder.setPosition(1);
selection = 1;
}
chooseValue();
if (button.triggerSingle()){
value = selection;
encoder.setPosition(1);
screen = MENU;
}
break;
}
}