LCD meni

programski jeziki in programiranje

Moderator: tilz0R

LCD meni

OdgovorNapisal/-a Lovro7 » 03 Mar 2025, 23:19

Tukaj je zanimiv način za izdelavo menijev na LCD zaslonih. Potrebuješ 4 tipke:
-naprej,
-nazaj,
-gor (poveča vrednost),
-dol (zmanjša vrednost)

Koda ni moja, sem pa dodal samodejno višanje vrednosti če držim gumb več kot 500ms.

Koda: Izberi vse
#include <LiquidCrystal.h>
LiquidCrystal lcd(6, 7, 5, 4, 3, 2);

//Input & Button Logic
const int numOfInputs = 4;
const int inputPins[numOfInputs] = {8,9,10,11};
int inputState[numOfInputs];
int lastInputState[numOfInputs] = {LOW,LOW,LOW,LOW};
bool inputFlags[numOfInputs] = {LOW,LOW,LOW,LOW};
long lastDebounceTime[numOfInputs] = {0,0,0,0};
long debounceDelay = 5;
unsigned long pressStartTime[numOfInputs] = {0};

//LCD Menu Logic
const int numOfScreens = 9;
int currentScreen = 0;
String screens[numOfScreens][2] = {{"Dolzina enote","ms"}, {"Ustavi po znaku",""}, {"St. ponovitev 1", " "},
{"St. ponovitev 2",""}, {"Gumb 1:", ""}, {"Gumb 2:", ""},
{"Gumb 3:", ""},{"Gumb 4:", ""}, {"Gumb 5:", ""}};
int parameters[numOfScreens];

void setup() {
  for(int i = 0; i < numOfInputs; i++) {
    pinMode(inputPins[i], INPUT);
    digitalWrite(inputPins[i], HIGH); // pull-up 20k
  }
  //Serial.begin(9600);
  lcd.begin(16, 2);
}

void loop() {
  setInputFlags();
  resolveInputFlags();
}

void setInputFlags() {
  for(int i = 0; i < numOfInputs; i++) {
    int reading = digitalRead(inputPins[i]);
    if (reading != lastInputState[i]) {
      lastDebounceTime[i] = millis();
    }
    if ((millis() - lastDebounceTime[i]) > debounceDelay) {
      if (reading != inputState[i]) {
        inputState[i] = reading;
        if (inputState[i] == LOW) {
          inputFlags[i] = HIGH;
          pressStartTime[i] = millis();
        }
      }
    }
    if (inputState[i] == LOW && (millis() - pressStartTime[i]) > 500) {
      static unsigned long lastIncrementTime[numOfInputs] = {0};
      if (millis() - lastIncrementTime[i] > 100) {
        inputFlags[i] = HIGH;
        lastIncrementTime[i] = millis();
      }
    }
    lastInputState[i] = reading;
  }
}


void resolveInputFlags() {
  for(int i = 0; i < numOfInputs; i++) {
    if(inputFlags[i] == HIGH) {
      inputAction(i);
      inputFlags[i] = LOW;
      printScreen();
    }
  }
}

void inputAction(int input) {
  if(input == 0) {
    if (currentScreen == 0) {
      currentScreen = numOfScreens-1;
    }else{
      currentScreen--;
    }
  }else if(input == 1) {
    if (currentScreen == numOfScreens-1) {
      currentScreen = 0;
    }else{
      currentScreen++;
    }
  }else if(input == 2) {
    parameterChange(0);
  }else if(input == 3) {
    parameterChange(1);
  }
}

void parameterChange(int key) {
  if(key == 0) {
    parameters[currentScreen]++;
  }else if(key == 1) {
    parameters[currentScreen]--;
  }
}

void printScreen() {
  lcd.clear();
  lcd.print(screens[currentScreen][0]);
  lcd.setCursor(0,1);
  lcd.print(parameters[currentScreen]);
  lcd.print(" ");
  lcd.print(screens[currentScreen][1]);
}
Vse je lahko žarnica, če je dovolj toka. http://lovro7.eu/index.html
Uporabniški avatar
Lovro7
 
Prispevkov: 352
Pridružen: 11 Feb 2024, 20:19
Kraj: Velenje (Šmartno ob Paki)
Zahvalil se je: 133 krat
Prejel zahvalo: 109 krat
Uporabnika povabil: DusanK
Število neizkoriščenih povabil: 8

Re: LCD meni

OdgovorNapisal/-a reber » 04 Mar 2025, 09:23

Lepo da se trudiš, ampak to je le del posameznega menija. Za izdelavo menija je v ozadju veliko več.
Komentarjev, vsaj uporabnih, ni. Če si naštudiral kodo od nekoga, jo dobil brez komentarjev, bi lahko ti dodal komentarje, za nepoznavalce zelo uporabno.
Kaj pa tipka za potrditev? kaj pa vpis parametra v eeprom? ali je to vse skupaj samo za sproti, brez shranjevanja v eeprom in brez potrditve, sprememba stopi v veljavo takoj? z izhodom iz menija?
Sporočila sprejemam na e-mail objavljen na www.reber.si
Uporabniški avatar
reber
 
Prispevkov: 2204
Pridružen: 17 Mar 2015, 20:30
Kraj: Bled
Zahvalil se je: 248 krat
Prejel zahvalo: 834 krat
Uporabnika povabil: s54mtb
Število neizkoriščenih povabil: 255

Re: LCD meni

OdgovorNapisal/-a Lovro7 » 04 Mar 2025, 10:11

Bom dodal komentarje.

Tipke za potrditev ni ker je meni narejen tako, da se vrednost posodobi z tipkama za gor in dol in nato prestavi zaslon.

Funkcije za pisanje v eeprom pa nisme dodal zato, da je koda bolj univerzalna. Enkrat bo zadostoval array vrednosti, enkrat bo zunanji EEPROM… Drugače pa se array parameters[] pretvori v konstanto in vpiše lokacije v EEPROMu. Potem pa se zamnja pisanje v parameters[] z EEPROM.update(parameters[currentSchreen], val)

Ker ima EEPROM omejeno število ciklov pisanja in branja je boljša opcija, da narediš tipko, ki potrdi vrednosti in jih shrani v EEPROM.

To je meni za nastavljanje parametrov. Prave menije z izbiro opciji… pa ponavadi delam z PREVEČ while zankami, if stavki… To verjetno ni pravi način.
Vse je lahko žarnica, če je dovolj toka. http://lovro7.eu/index.html
Uporabniški avatar
Lovro7
 
Prispevkov: 352
Pridružen: 11 Feb 2024, 20:19
Kraj: Velenje (Šmartno ob Paki)
Zahvalil se je: 133 krat
Prejel zahvalo: 109 krat
Uporabnika povabil: DusanK
Število neizkoriščenih povabil: 8

Re: LCD meni

OdgovorNapisal/-a s5ti » 06 Mar 2025, 15:19

AI naredi lepe komentarje
####


Code Anaysis
1. Language & Platform

The code is written in C++ for an Arduino microcontroller.
Uses the LiquidCrystal library to interface with an LCD display.
Uses digital inputs for button handling.
Implements debouncing logic and long-press detection.
Implements a menu system on a 16x2 LCD screen.

2. Purpose of the Code

The program:

Reads button presses from four buttons (connected to pins 8, 9, 10, 11).
Implements debouncing to ensure stable button reads.
Handles both short and long presses for different actions.
Manages an LCD menu system that allows navigation and parameter adjustment.
Updates LCD display to show current menu options and values.

3. Code Functionality Breakdown
3.1. LCD Initialization

LiquidCrystal lcd(6, 7, 5, 4, 3, 2);

Initializes the LCD using specific pins for RS, E, D4, D5, D6, and D7.

3.2. Input Button Setup

const int numOfInputs = 4;
const int inputPins[numOfInputs] = {8,9,10,11};
int inputState[numOfInputs];
int lastInputState[numOfInputs] = {LOW,LOW,LOW,LOW};
bool inputFlags[numOfInputs] = {LOW,LOW,LOW,LOW};
long lastDebounceTime[numOfInputs] = {0,0,0,0};
long debounceDelay = 5;
unsigned long pressStartTime[numOfInputs] = {0};

Manages button states and debounce timing.
Stores last button states and press durations.

3.3. Menu System Setup

const int numOfScreens = 9;
int currentScreen = 0;
String screens[numOfScreens][2] = {{"Dolzina enote","ms"}, {"Ustavi po znaku",""}, {"St. ponovitev 1", " "},
{"St. ponovitev 2",""}, {"Gumb 1:", ""}, {"Gumb 2:", ""},
{"Gumb 3:", ""},{"Gumb 4:", ""}, {"Gumb 5:", ""}};
int parameters[numOfScreens];

numOfScreens defines the number of menu screens.
screens contains screen titles and units for display.
parameters stores values associated with each menu option.

3.4. setup() - Initial Configuration

void setup() {
for(int i = 0; i < numOfInputs; i++) {
pinMode(inputPins[i], INPUT);
digitalWrite(inputPins[i], HIGH); // pull-up 20k
}
lcd.begin(16, 2);
}

Sets button pins as INPUT and enables internal pull-up resistors (active-low logic).
Initializes the 16x2 LCD display.

3.5. loop() - Main Execution Loop

void loop() {
setInputFlags();
resolveInputFlags();
}

Calls functions to handle button presses and actions.

3.6. setInputFlags() - Button Debouncing and Long-Press Handling

void setInputFlags() {
for(int i = 0; i < numOfInputs; i++) {
int reading = digitalRead(inputPins[i]);
if (reading != lastInputState[i]) {
lastDebounceTime[i] = millis();
}
if ((millis() - lastDebounceTime[i]) > debounceDelay) {
if (reading != inputState[i]) {
inputState[i] = reading;
if (inputState[i] == LOW) {
inputFlags[i] = HIGH;
pressStartTime[i] = millis();
}
}
}
if (inputState[i] == LOW && (millis() - pressStartTime[i]) > 500) {
static unsigned long lastIncrementTime[numOfInputs] = {0};
if (millis() - lastIncrementTime[i] > 100) {
inputFlags[i] = HIGH;
lastIncrementTime[i] = millis();
}
}
lastInputState[i] = reading;
}
}

Detects button press and release events.
Implements debouncing using debounceDelay.
Detects long-press events (holding for >500ms).

3.7. resolveInputFlags() - Processing Button Actions

void resolveInputFlags() {
for(int i = 0; i < numOfInputs; i++) {
if(inputFlags[i] == HIGH) {
inputAction(i);
inputFlags[i] = LOW;
printScreen();
}
}
}

Calls inputAction() when a button is pressed.
Refreshes the LCD screen after processing.

3.8. inputAction() - Defining Actions for Each Button

void inputAction(int input) {
if(input == 0) { // Left button
if (currentScreen == 0) {
currentScreen = numOfScreens - 1;
} else {
currentScreen--;
}
} else if(input == 1) { // Right button
if (currentScreen == numOfScreens - 1) {
currentScreen = 0;
} else {
currentScreen++;
}
} else if(input == 2) { // Increment parameter
parameterChange(0);
} else if(input == 3) { // Decrement parameter
parameterChange(1);
}
}

Button 0 (left): Moves to the previous menu item.
Button 1 (right): Moves to the next menu item.
Button 2: Increments the selected parameter.
Button 3: Decrements the selected parameter.

3.9. parameterChange() - Adjusting Parameter Values

void parameterChange(int key) {
if(key == 0) {
parameters[currentScreen]++;
} else if(key == 1) {
parameters[currentScreen]--;
}
}

Increments or decrements the parameter of the current screen.

3.10. printScreen() - Updating LCD Display

void printScreen() {
lcd.clear();
lcd.print(screens[currentScreen][0]);
lcd.setCursor(0,1);
lcd.print(parameters[currentScreen]);
lcd.print(" ");
lcd.print(screens[currentScreen][1]);
}

Clears the LCD screen.
Displays the menu title on the first line.
Displays the parameter value and unit on the second line.

4. Suggested Improvements
4.1. Improve Button Handling

Instead of using LOW and HIGH states manually, use bool for clarity.
bool inputFlags[numOfInputs] = {}; // Zero-initialized

4.2. Improve Debounce Logic

lastDebounceTime should be unsigned long instead of long (to match millis()).
debounceDelay should be constexpr for optimization.

constexpr unsigned long debounceDelay = 5;
unsigned long lastDebounceTime[numOfInputs] = {};

4.3. Use constexpr for Constants

constexpr int numOfInputs = 4;
constexpr int numOfScreens = 9;

4.4. Prevent Negative Parameter Values

void parameterChange(int key) {
if (key == 0) {
parameters[currentScreen]++;
} else if (key == 1 && parameters[currentScreen] > 0) {
parameters[currentScreen]--;
}
}

Prevents decrementing below zero.

4.5. Optimize LCD Refreshing

void resolveInputFlags() {
bool shouldRefresh = false;
for(int i = 0; i < numOfInputs; i++) {
if(inputFlags[i]) {
inputAction(i);
inputFlags[i] = false;
shouldRefresh = true;
}
}
if (shouldRefresh) printScreen();
}

Avoids unnecessary LCD updates.

Final Thoughts

The code is well-structured and efficiently handles an LCD menu system.
Improvements can optimize memory usage and enhance readability.
These optimizations will make the code more robust and maintainable.
Več glav - več zelja
s5ti
 
Prispevkov: 316
Pridružen: 22 Jan 2015, 11:03
Kraj: Logatec, Ljubljana
Zahvalil se je: 7 krat
Prejel zahvalo: 27 krat
Uporabnika povabil: s54mtb
Število neizkoriščenih povabil: 8


Vrni se na Software

Kdo je na strani

Po forumu brska: 0 registriranih uporabnikov in 1 gost