Skip to content

DevLog #1: Programming OLED & Rotary Encoder

OLED 12C

For this exercise, I’m using OLED SSD3016 0.96”

How to find I2C address

Run this code below

/* I2C Address Finder
 *  for " Arduino LCD I2C Tutorial| How to Program LCD Display"
 *  subscribe for more arduino Tuorials and Projects

https://www.youtube.com/channel/UCM6rbuieQBBLFsxs...
 */

#include <Wire.h>

void setup()

{
  Serial.begin (115200);
   while (!Serial)
    {
    }

  Serial.println ();
  Serial.println ("I2C scanner. Scanning ...");
  byte count = 0;
  pinMode(13,OUTPUT); 
  digitalWrite(13,HIGH);
  Wire.begin();
  for (byte i = 1; i < 120; i++)
  {
    Wire.beginTransmission (i);
    if (Wire.endTransmission () == 0)
      {
      Serial.print ("Found address: ");
      Serial.print (i, DEC);
      Serial.print (" (0x");
      Serial.print (i, HEX);
      Serial.println (")");
      count++;
      delay (1); 
      } 
  } 
  Serial.println ("Done.");
  Serial.print ("Found ");
  Serial.print (count, DEC);
  Serial.println (" device(s).");
} 

void loop() {}
It should show this in the serial monitor:

i2c-address-finder

Copy the address and paste it here:

i2c-address-finder-2

Basic Hello World

#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 32 // OLED display height, in pixels
#define OLED_RESET 4
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

void setup()   {  
  Serial.begin(9600);
  // by default, we'll generate the high voltage from the 3.3v line internally! (neat!)
  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);  // initialize with the I2C addr 0x3C (for the 128x32
  display.clearDisplay();
  display.display(); // this command will display all the data which is in buffer
}
void loop() { 
  display.clearDisplay();
  display.setTextSize(2);
  display.setTextColor(WHITE);
  display.setCursor(0,0);
  display.println("Hello World!");
  display.display();
  delay(3000);
}

Rotary Encoder

HW-040 Rotary Encoder Module

HW-040 rotary encoder is a device that generates an electrical signal based on how much the rotary input device (knob) is rotated and the direction it is rotating.

It generates a pulse train output with the number of pulses depending on the number of detents on the encoder. The number of pulses per revolution can vary depending on the specific encoder, but it is usually between 20 and 24 pulses per revolution. This allows for precise position sensing and control of the shaft’s rotation.

Specification:

  • Model: HW-040
  • Working voltage: 5V
  • Material: PCB + Brass
  • Mechanical angle: 360 Degrees
  • Output: 2-bit gray code
  • Positions per revolution: 30
  • Weight: 10g
  • Size: 32 x 19 x 30mm

Pin Configuration

5 output pins

  • CLK : Encoder Pin A (Digital Pin)
  • DT : Encoder Pin B (Digital Pin)
  • SW : No push-button switch
  • VCC(+): Voltage input(+5V)
  • GND : Ground

Tutorial: Controlling LEDs with Rotary Encoder and LCD Display

Test 1: Display through Serial Monitor

RE-led-exercise-circuit-diagram

Wokwi Simulation: here

// Rotary Encoder Inputs
#define CLK 2
#define DT 4
#define SW 3

int currentStateCLK;
int lastStateCLK;
unsigned long lastButtonPress = 0;

int leds [] = {27, 28};

unsigned int menu = 0;
int ledStatus[27] = {0};
int timer = 500;

void setup() {
  Serial1.begin(9600);

  // Set encoder pins as input
  pinMode(CLK, INPUT);
  pinMode(DT, INPUT);
  pinMode(SW, INPUT_PULLUP);

  for (int i = 0; i < 2; i++) {
    pinMode(leds[i], OUTPUT);
  }

  menu = 0;
  updateMenu();
}

void loop() {
  currentStateCLK = digitalRead(CLK);

  if (currentStateCLK != lastStateCLK  && currentStateCLK == 1) {
    if (digitalRead(DT) != currentStateCLK) {
      menu --;
      updateMenu();
    } else {
      menu ++;
      updateMenu();
    }
  }
  lastStateCLK = currentStateCLK;

  int btnState = digitalRead(SW);
  if (btnState == LOW) {
    if (millis() - lastButtonPress > 50) {
      executeAction();
      updateMenu();
    }
    lastButtonPress = millis();
  }
  delay(1);
}

void printlcd(){
  Serial1.println("LED Controller");
  }

void updateMenu() {

  switch (menu) {
    case 0:
      menu = 1;
      break;
    case 1:
      printlcd();
      Serial1.println("<LED 1>");
      break;
    case 2:
      printlcd();
      Serial1.println("<LED 2>");
      break;
    case 3:
      menu = 4;
      break;
  }
}
void executeAction() {
  switch (menu) {
    case 1:
      action1();
      break;
    case 2:
      action2();
      break;
  }
}

void action1() {
  if (ledStatus[menu] != 0) {
    ledStatus[menu] = 0;
    Serial1.println("> LED 1 OFF...");
    digitalWrite(leds[menu - 1], ledStatus[menu]);
    delay(timer);
  } else {
    ledStatus[menu] = 1;
    // display.clearDisplay();
    // display.println("> LED 1 ON...");
    Serial1.println("> LED 1 ON...");
    digitalWrite(leds[menu - 1], ledStatus[menu]);
    delay(timer);
  }
}
void action2() {
  if (ledStatus[menu] != 0) {
    ledStatus[menu] = 0;
    Serial1.println("> LED 2 OFF...");
    digitalWrite(leds[menu - 1], ledStatus[menu]);
    delay(timer);
  } else {
    ledStatus[menu] = 1;
    Serial1.println("> LED 2 ON...");
    digitalWrite(leds[menu - 1], ledStatus[menu]);
    delay(timer);
  }
}

Works in my Wokwi simulation, as well as in the physical circuit when I upload the code to the board. However, the result is not consistent, sometimes it works, sometimes not.. Apparently there’s a debouncing and inconsistency issue with Rotary Encoder, which needs further customized codes.