#include <Wire.h>
#include <LiquidCrystal_I2C.h>
// Ustawienia LCD
constexpr uint8_t I2C_ADDR = 0x27; // zmień na 0x3F jeśli Twój LCD ma inny adres
LiquidCrystal_I2C lcd(I2C_ADDR, 16, 2);
// Piny potencjometrów (ADC1: 32..39; 34 i 35 są tylko wejściowe – idealne)
constexpr int PIN_POT_G = 34; // G - pierwszy
constexpr int PIN_POT_S = 35; // S - drugi
// Ustawienia paska postępu
constexpr int LCD_COLS = 16;
constexpr int LCD_ROWS = 2;
constexpr int PREFIX_COLS = 2; // "G_" lub "S_"
constexpr int BAR_COLS = LCD_COLS - PREFIX_COLS; // 14 kolumn na pasek
constexpr int SEG_PER_CELL = 5; // 5 “pikseli” poziomych na znak
// Wygładzanie i odświeżanie
constexpr float ALPHA = 0.2f; // 0..1 (większe = szybsza reakcja)
constexpr uint32_t REFRESH_MS = 50;
byte bar1[8] = {0b10000,0b10000,0b10000,0b10000,0b10000,0b10000,0b10000,0b10000}; // 1/5
byte bar2[8] = {0b11000,0b11000,0b11000,0b11000,0b11000,0b11000,0b11000,0b11000}; // 2/5
byte bar3[8] = {0b11100,0b11100,0b11100,0b11100,0b11100,0b11100,0b11100,0b11100}; // 3/5
byte bar4[8] = {0b11110,0b11110,0b11110,0b11110,0b11110,0b11110,0b11110,0b11110}; // 4/5
byte bar5[8] = {0b11111,0b11111,0b11111,0b11111,0b11111,0b11111,0b11111,0b11111}; // 5/5
float filteredG = 0.0f;
float filteredS = 0.0f;
uint32_t lastUpdate = 0;
void drawBarAt(uint8_t colStart, uint8_t row, uint8_t cols, int steps) {
const int maxSteps = cols * SEG_PER_CELL; // np. 14 * 5 = 70
if (steps < 0) steps = 0;
if (steps > maxSteps) steps = maxSteps;
lcd.setCursor(colStart, row);
for (int i = 0; i < cols; i++) {
int seg = steps - i * SEG_PER_CELL; // ile “pikseli” w tej komórce
if (seg <= 0) {
lcd.write(' '); // pusto
} else if (seg >= SEG_PER_CELL) {
lcd.write(byte(4)); // pełny (bar5)
} else {
lcd.write(byte(seg - 1)); // częściowo wypełniony (bar1..bar4)
}
}
}
void setup() {
Wire.begin(21, 22); // ESP32: SDA=21, SCL=22
lcd.init();
lcd.backlight();
lcd.clear();
// Rejestracja własnych znaków (sloty 0..4)
lcd.createChar(0, bar1);
lcd.createChar(1, bar2);
lcd.createChar(2, bar3);
lcd.createChar(3, bar4);
lcd.createChar(4, bar5);
// Opcjonalnie: dopasowanie ADC do zakresu ~0..3.3V
// analogReadResolution(12); // (domyślnie 12-bit)
// analogSetPinAttenuation(PIN_POT_G, ADC_11db);
// analogSetPinAttenuation(PIN_POT_S, ADC_11db);
// Inicjalne wypełnienie filtra
filteredG = analogRead(PIN_POT_G);
filteredS = analogRead(PIN_POT_S);
// Stałe etykiety
lcd.setCursor(0, 0); lcd.print("G_");
lcd.setCursor(0, 1); lcd.print("S_");
}
void loop() {
uint32_t now = millis();
if (now - lastUpdate >= REFRESH_MS) {
// Odczyty
int rawG = analogRead(PIN_POT_G); // 0..4095
int rawS = analogRead(PIN_POT_S);
// Wygładzanie (EMA)
filteredG = ALPHA * rawG + (1.0f - ALPHA) * filteredG;
filteredS = ALPHA * rawS + (1.0f - ALPHA) * filteredS;
// Mapowanie do kroków paska
const int maxSteps = BAR_COLS * SEG_PER_CELL; // 14*5 = 70
int stepsG = map((int)filteredG, 0, 4095, 0, maxSteps);
int stepsS = map((int)filteredS, 0, 4095, 0, maxSteps);
// Rysowanie pasków
drawBarAt(PREFIX_COLS, 0, BAR_COLS, stepsG); // linia 1 po "G_"
drawBarAt(PREFIX_COLS, 1, BAR_COLS, stepsS); // linia 2 po "S_"
lastUpdate = now;
}
}