10. Output Devices¶
OLED¶

A 1.3-inch OLED display was used in this project and identified as using the SH1106 controller. It worked correctly with the Adafruit SH110X library, while the SSD1306 library produced incorrect output such as noise and distortion.
Library¶
A library in embedded programming is a collection of pre-written code that simplifies interaction with hardware components. Libraries reduce development time, minimize errors, and make code more readable.
I used the following libraries for the I2C OLED Display:
<Adafruit_GFX.h>: Provides basic drawing functions such as lines, rectangles, circles, triangles, and text rendering.<Adafruit_SH110X.h>: Simplifies controlling SH1106 or SH1107 OLED displays with Arduino.
Testing OLED Properties¶
// Include required libraries
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SH110X.h>
// Display configuration
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
// Create display object
Adafruit_SH1106G display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1);
void setup() {
Serial.begin(115200);
delay(2000); // Wait for Serial Monitor
Serial.println("=== SH1106 OLED Properties ===");
// Initialize I2C (SDA = 6, SCL = 7)
Wire.begin(6, 7);
// Initialize display
if (!display.begin(0x3C, true)) {
Serial.println("SH1106 OLED not found!");
while (1); // Halt execution
}
Serial.println("OLED detected successfully!");
// Test drawing on OLED
display.clearDisplay();
display.drawRect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, SH110X_WHITE); // border
display.drawLine(0, 0, SCREEN_WIDTH - 1, SCREEN_HEIGHT - 1, SH110X_WHITE); // diagonal
display.setTextSize(1);
display.setCursor(0, SCREEN_HEIGHT - 10);
display.println("Bottom Text Test");
display.display();
Serial.println("Check OLED for rectangle, diagonal line, and bottom text");
}
void loop() {
// Nothing to run continuously
}
Results Example:
=== SH1106 OLED Properties ===
OLED detected successfully!
Screen Width: 128
Screen Height: 64
I2C Address: 0x3C
Text color constant: 1
Max Cursor X: 127
Max Cursor Y: 63
=== Test drawing functions ===
Check OLED for rectangle, diagonal line, and bottom text

Display Properties on OLED¶
// Include required libraries
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SH110X.h>
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
Adafruit_SH1106G display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1);
void setup() {
Serial.begin(115200);
delay(2000);
Wire.begin(6, 7);
if (!display.begin(0x3C, true)) {
Serial.println("OLED not found!");
while (1);
}
Serial.println("OLED detected successfully!");
display.clearDisplay();
display.setTextColor(SH110X_WHITE);
display.setTextSize(1);
int y = 0;
display.setCursor(0, y); display.println("Screen Properties:"); y += 8;
display.setCursor(0, y); display.print("Width: "); display.println(SCREEN_WIDTH); y += 8;
display.setCursor(0, y); display.print("Height: "); display.println(SCREEN_HEIGHT); y += 8;
display.setCursor(0, y); display.print("I2C Addr: "); display.println("0x3C"); y += 8;
display.setCursor(0, y); display.print("Text Color: "); display.println(SH110X_WHITE); y += 8;
display.setCursor(0, y); display.print("Max Cursor X: "); display.println(SCREEN_WIDTH - 1); y += 8;
display.setCursor(0, y); display.print("Max Cursor Y: "); display.println(SCREEN_HEIGHT - 1); y += 8;
display.setCursor(0, y); display.println("End of Properties");
display.display();
}
void loop() {
// Nothing to run continuously
}

Simple Display Example¶
// Include required libraries
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SH110X.h>
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
Adafruit_SH1106G display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1);
// Example sensor values
float flowRate = 2.5; // L/min
int waterQuality = 78; // %
int systemHealth = 85; // %
void setup() {
Serial.begin(115200);
delay(2000);
Wire.begin(6, 7);
if (!display.begin(0x3C, true)) {
Serial.println("OLED not found!");
while (1);
}
}
void loop() {
display.clearDisplay();
display.setTextColor(SH110X_WHITE);
// Title
display.setTextSize(2);
display.setCursor(5, 0);
display.println("H2O");
display.drawLine(0, 20, SCREEN_WIDTH, 20, SH110X_WHITE);
// Water Quality
display.setTextSize(1);
display.setCursor(0, 34);
display.print("Qual:");
display.setCursor(65, 34);
display.print(waterQuality);
display.println("%");
// Footer
display.setCursor(15, 58);
display.println("System Active");
display.display();
delay(1000);
}
OLED Cheat Sheet¶

Output Turbidity readings

I used the code below
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SH110X.h>
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
Adafruit_SH1106G display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1);
// Turbidity sensor pin
#define TURBIDITY_PIN D1
int turbidityPercent = 0;
int waterQuality = 0;
// ===== Function to stabilize readings =====
int readTurbidity() {
long sum = 0;
for (int i = 0; i < 10; i++) {
sum += analogRead(TURBIDITY_PIN);
delay(5);
}
return sum / 10; // average value
}
void setup() {
Serial.begin(115200);
delay(2000);
Wire.begin(6, 7); // SDA, SCL
if (!display.begin(0x3C, true)) {
Serial.println("OLED not found!");
while (1);
}
display.clearDisplay();
display.setTextColor(SH110X_WHITE);
}
void loop() {
// ===== READ SENSOR (STABLE) =====
int rawValue = readTurbidity();
// ===== MAP VALUES (ADJUSTABLE) =====
turbidityPercent = map(rawValue, 1000, 3000, 100, 0);
turbidityPercent = constrain(turbidityPercent, 0, 100);
// Water quality = same as turbidity scale (clean = high)
waterQuality = turbidityPercent;
// ===== SERIAL DEBUG =====
Serial.print("Raw: "); Serial.print(rawValue);
Serial.print(" | Turbidity: "); Serial.print(turbidityPercent);
Serial.print("% | Quality: "); Serial.print(waterQuality);
Serial.println("%");
// ===== OLED DISPLAY =====
display.clearDisplay();
// Title
display.setTextSize(2);
display.setCursor(25, 0);
display.println("H2O");
display.drawLine(0, 20, SCREEN_WIDTH, 20, SH110X_WHITE);
// Data
display.setTextSize(1);
display.setCursor(0, 25);
display.print("Turb:");
display.setCursor(85, 25);
display.print(turbidityPercent);
display.print("%");
display.setCursor(0, 38);
display.print("Qual:");
display.setCursor(85, 38);
display.print(waterQuality);
display.print("%");
display.setCursor(0, 51);
display.print("Status:");
display.setCursor(85, 51);
if (waterQuality > 75) display.print("GOOD");
else if (waterQuality > 40) display.print("OK");
else display.print("BAD");
display.display();
delay(1000);
}