#include <Arduino.h>
#include <U8g2lib.h> // u8g2 library for OLED
#include <Wire.h> // IIC communication
#include <Adafruit_NeoPixel.h> // NeoPixel library
#define NUM_LEDS_PER_POT 30
#define NUM_POTS 4
#define PIN_NEO_PIXEL 6 // Arduino pin for NeoPixel
#define BRIGHTNESS 150 // Adjust brightness for NeoPixel
// Initialize the NeoPixel object
Adafruit_NeoPixel NeoPixel(NUM_LEDS_PER_POT * NUM_POTS, PIN_NEO_PIXEL, NEO_GRB + NEO_KHZ800);
// Initialize the OLED display
U8G2_SSD1306_128X32_UNIVISION_F_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE);
// two bubble images were drawn in Photopea and arrays were created using the image2cpp website
// 'img_bubble_fill', 26x13px
const unsigned char epd_bitmap_img_bubble_fill [] PROGMEM = {
0xfc, 0xff, 0xff, 0x00, 0xfe, 0xff, 0xff, 0x01, 0xfe, 0xff, 0xff, 0x01, 0xfe, 0xff, 0xff, 0x01,
0xfe, 0xff, 0xff, 0x01, 0xfe, 0xff, 0xff, 0x01, 0xfe, 0xff, 0xff, 0x01, 0xfe, 0xff, 0xff, 0x01,
0xfc, 0xff, 0xff, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00
};
// 'img_bubble_outline', 26x13px
const unsigned char epd_bitmap_img_bubble_outline [] PROGMEM = {
0xfe, 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0x03, 0xff, 0xff, 0xff, 0x03, 0xff, 0xff, 0xff, 0x03,
0xff, 0xff, 0xff, 0x03, 0xff, 0xff, 0xff, 0x03, 0xff, 0xff, 0xff, 0x03, 0xff, 0xff, 0xff, 0x03,
0xfe, 0xff, 0xff, 0x01, 0xfc, 0xff, 0xff, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00,
0x00, 0x30, 0x00, 0x00
};
// Potentiometer pins and previous values
int potentiometers[4] = {A0, A1, A2, A3};
int prevValues[4] = {0, 0, 0, 0};
int activePot = 0;
// Labels for potentiometers
const char* potLabels[4] = {"Pot 1", "Pot 2", "Pot 3", "Pot 4"};
int compass_degrees; // For compass value based on potentiometer reading
// Array for potentiometer values for NeoPixel control
int potValues[NUM_POTS]; // Stores potentiometer values as percentages
char buffer[20]; // helper buffer for displaying strings on the display
int xpos_offset; // x offset of all the tickmarks
int xpos_with_offset; // x position of the tickmark with applied offset
float xpos_final; // final x position for the tickmark
int str_width; // calculated width of the string
void setup() {
u8g2.begin(); // Initialize OLED display
NeoPixel.begin(); // Initialize NeoPixel strip
NeoPixel.setBrightness(BRIGHTNESS); // Set NeoPixel brightness
for (int i = 0; i < 4; i++) {
pinMode(potentiometers[i], INPUT); // Set potentiometer pins as input
}
}
void loop() {
int maxChange = 0;
// Read potentiometer values and update NeoPixel colors
for (int i = 0; i < 4; i++) {
int currentValue = analogRead(potentiometers[i]);
int change = abs(currentValue - prevValues[i]);
if (change > maxChange) {
maxChange = change;
activePot = i;
compass_degrees = map(currentValue, 0, 1023, 0, 100); // Map potentiometer to compass degrees (0-100)
xpos_offset = round((100 - compass_degrees) / 100.0 * 200.0); // calculate the X offset for all the tickmarks, max offset is 10(px)*24(tickmarks) = 240px
}
prevValues[i] = currentValue; // Update previous potentiometer value
potValues[i] = map(currentValue, 0, 1023, 0, 100); // Map potentiometer to 0-100 for NeoPixel control
}
// Update the OLED display with potentiometer values and tick marks
u8g2.clearBuffer();
u8g2.setDrawColor(1);
u8g2.setBitmapMode(1); // Transparent images
u8g2.setFont(u8g2_font_6x12_tf);
u8g2.setFontDirection(0);
u8g2.drawStr(7, 7, potLabels[activePot]);
for (int i = 0; i < 20; i++) { // go over all 24 tickmarks
xpos_with_offset = (64 + (i * 10) + xpos_offset) % 200; // calculate the x offset for all tickmarks, do not go over 240px
//xpos_with_offset = (64 + (i * 10) + xpos_offset1) % 200;
if (xpos_with_offset > 2 && xpos_with_offset < 128) { // only draw tickmarks that are inside the visible area (display width is 128px)
if (xpos_with_offset < 64) {
xpos_final = xpos_with_offset / 64.0; // convert 0-64 into 0-1 range to work nicely with the power function
xpos_final = pow(xpos_final, 2.5); // add easing by having the power function, tweak the exponent for different result
xpos_final = xpos_final * 64.0; // convert 0-1 back into 0-64 (left side of the screen)
} else {
xpos_final = (128 - xpos_with_offset) / 64.0; // convert 0-64 into 0-1 range to work nicely with the power function
xpos_final = pow(xpos_final, 2.5); // add easing by having the power function, tweak the exponent for different result
xpos_final = (64 - (xpos_final * 64.0)) + 64; // convert 1-0 back into 64-128 (right side of the screen)
}
xpos_final = round(xpos_final); // round the final x position to integer value
u8g2.drawLine(xpos_final, 7, xpos_final, 13); // draw tickmark
//u8g2.drawLine(0, 5, 127, 5); // draw horizontal line
u8g2.setFontDirection(0); // normal font direction
u8g2.setDrawColor(0); // black color
u8g2.drawXBMP(51, 0, 26, 13, epd_bitmap_img_bubble_outline); // bubble outline
u8g2.setDrawColor(1); // white color
u8g2.drawXBMP(50, 1, 26, 13, epd_bitmap_img_bubble_fill); // bubble fill
u8g2.setDrawColor(0); // black color
sprintf(buffer, "%d%%", compass_degrees); // convert compass degree integer to string, add the ' symbol that (somehow) looks like degree symbol (degree symbol is not present in the font)
//sprintf(buffer, "%d%", compass_degrees1);
str_width = u8g2.getStrWidth(buffer); // calculate the string width
u8g2.drawStr(64 - str_width / 2, 10, buffer); // draw centered string
}
u8g2.setDrawColor(1);
u8g2.setFontDirection(1);
u8g2.setFont(u8g2_font_6x13B_tf);
sprintf(buffer, "%d", i * 5); // convert compass degree integer to string, add the ' symbol that (somehow) looks like degree symbol (degree symbol is not present in the font)
str_width = u8g2.getStrWidth(buffer); // calculate the string width
//u8g2.drawStr(64 - str_width / 2, 8, buffer);
u8g2.drawStr(xpos_with_offset - 4, 16, buffer);// draw centered string
//u8g2.drawStr(0, 50, buffer);
// Update NeoPixel LEDs based on potentiometer values
NeoPixel.clear(); // Clear previous LED states
for (int pot = 0; pot < NUM_POTS; pot++) {
int startLED = pot * NUM_LEDS_PER_POT;
int numLitLEDs = map(potValues[pot], 0, 100, 0, NUM_LEDS_PER_POT); // Calculate LEDs to light up
for (int led = 0; led < NUM_LEDS_PER_POT; led++) {
if (led < numLitLEDs) {
NeoPixel.setPixelColor(startLED + led, NeoPixel.Color(255, 255, 255)); // Light LED white
} else {
NeoPixel.setPixelColor(startLED + led, NeoPixel.Color(0, 0, 0)); // Turn off LED
}
}
}
NeoPixel.show(); // Update the NeoPixel strip
delay(50); // Short delay for stability
}
u8g2.sendBuffer(); // Transfer the buffer to the display
}
Loading
ssd1306
ssd1306