Aiuto lettura / scrittura EEPROM

Ciao a tutti,
sto lavorando ad un progetto e sono a buon punto...
Vorrei aggiungere la "ciliegina sulla torta", ovvero tenere in memoria l'ultimo valore ottenuto.

Spiegando meglio, questo è il codice che ho scritto:

#include <ItemSubMenu.h>
#include <LcdMenu.h>
#include <MenuScreen.h>
#include <SimpleRotary.h>
#include <input/SimpleRotaryAdapter.h>
#include <display/LiquidCrystal_I2CAdapter.h>
#include <renderer/CharacterDisplayRenderer.h>
#include <ItemBack.h>
#include <ItemWidget.h>
#include <widget/WidgetRange.h>
#include <Wire.h>

// LCD Configuration
#define LCD_ROWS 4
#define LCD_COLS 20

// Encoder Pins
#define ENCODER_PIN_A 2
#define ENCODER_PIN_B 3
#define ENCODER_PIN_SW 4

// Motor Pins
#define MOTOR_1_STEP_PIN 5
#define MOTOR_1_DIR_PIN 6
#define MOTOR_1_ENABLE_PIN 7


// Motor and movement parameters
const int steps_per_mm = 200;
const int motor_steps_per_encoder = 20;
float mm_per_encoder_step = (float)motor_steps_per_encoder / steps_per_mm;

// Global Variables
float current_value_fence = 0.0;  // Current fence value
float previous_value_fence = 0.0; // Previous fence value
float mm_position_1 = 0.0;          // Position in mm motor 1

// Callback function declarations
void callback_mm_Fence(float value_fence);

// External declarations for submenus
extern MenuScreen* ZeroCalibrationScreen;
extern MenuScreen* Fence_ToolScreen;
extern MenuScreen* Fence_AdjustmentScreen;
extern MenuScreen* Tool_AdjustmentScreen;
extern MenuScreen* AppsScreen;

// Define the main menu
// clang-format off

// MAIN MENU
MENU_SCREEN(mainScreen, mainItems,
    ITEM_SUBMENU("Zero Calibration", ZeroCalibrationScreen),
    ITEM_SUBMENU("Fence & Tool", Fence_ToolScreen),
    ITEM_SUBMENU("Apps", AppsScreen));

// MENU ZERO CALIBRATION
MENU_SCREEN(ZeroCalibrationScreen, ZeroCalibrationItems,
    ITEM_BACK("Back to Main Menu"));

// MENU FENCE & TOOL
MENU_SCREEN(Fence_ToolScreen, Fence_ToolItems,
    ITEM_SUBMENU("Move Tool", Tool_AdjustmentScreen),
    ITEM_SUBMENU("Move Fence", Fence_AdjustmentScreen),
    ITEM_BACK("Back to Main Menu"));

// MENU FENCE ADJUSTMENT
MENU_SCREEN(Fence_AdjustmentScreen, Fence_AdjustmentItems,
    ITEM_WIDGET(
        "Set cm:",
        callback_mm_Fence,
        WIDGET_RANGE(0.0f, 0.1f, 0.0f, 1000.0f, "%.2fcm", 2)),
    ITEM_BACK("Back"));

// MENU TOOL ADJUSTMENT
MENU_SCREEN(Tool_AdjustmentScreen, Tool_AdjustmentItems,
    ITEM_BACK("Back"));

// MENU APPS
MENU_SCREEN(AppsScreen, AppsItems,

    ITEM_BACK("Back to Main Menu"));

// Initialize LCD and Renderer
LiquidCrystal_I2C lcd(0x27, LCD_COLS, LCD_ROWS);
CharacterDisplayRenderer renderer(new LiquidCrystal_I2CAdapter(&lcd), LCD_COLS, LCD_ROWS);
LcdMenu menu(renderer);

// Rotary Encoder and Adapter
SimpleRotary encoder(ENCODER_PIN_A, ENCODER_PIN_B, ENCODER_PIN_SW);
SimpleRotaryAdapter encoderA(&menu, &encoder);

// SETUP FUNCTION
void setup() {
    // Display Setup
    renderer.begin();
    pinMode(ENCODER_PIN_SW, INPUT_PULLUP);
    lcd.clear();
    lcd.setCursor(0, 0);
    lcd.print("Welcome!");
    delay(1000);
    lcd.setCursor(0, 1);
    lcd.print("Loading...");
    delay(2000);
    menu.setScreen(mainScreen); // Start with the main menu

    // Serial Setup
    Serial.begin(9600);
    Serial.println("System Running!");

    // Motor Setup
    pinMode(MOTOR_1_STEP_PIN, OUTPUT);
    pinMode(MOTOR_1_DIR_PIN, OUTPUT);
    pinMode(MOTOR_1_ENABLE_PIN, OUTPUT);
    digitalWrite(MOTOR_1_ENABLE_PIN, LOW); // Enable motor driver
    Serial.println("Motor Ready!");
}

// MOVE MOTOR FUNCTION
void moveMotor_1(float delta_mm) { 
    // Moves Motor
    int steps = abs(delta_mm) * steps_per_mm;
    digitalWrite(MOTOR_1_DIR_PIN, delta_mm > 0 ? HIGH : LOW);
    for (int i = 0; i < steps; i++) {
        digitalWrite(MOTOR_1_STEP_PIN, HIGH);
        delayMicroseconds(1000);
        digitalWrite(MOTOR_1_STEP_PIN, LOW);
        delayMicroseconds(1000);
    }
}

// FENCE CALLBACK FUNCTION
void callback_mm_Fence(float value_fence) {
    current_value_fence = value_fence; // Store the new value
    Serial.print("Fence position: "); 
    Serial.println(value_fence);
}

// MAIN LOOP
void loop() {
    encoderA.observe();

    // Handle Fence Position Update
    if (current_value_fence != previous_value_fence) {
        float delta = current_value_fence - previous_value_fence; // Calculate change
        mm_position_1 += delta * mm_per_encoder_step; // Update motor position

        // Prevent going below 0 mm
        if (mm_position_1 < 0) {
            mm_position_1 = 0;
        }
        moveMotor_1(delta); 
        Serial.print("Delta Value: ");
        Serial.println(delta);// Move motor according to delta
        Serial.print("Steps done by the Fence motor: ");
        Serial.println(abs(delta) * steps_per_mm);// Move motor according to delta
        previous_value_fence = current_value_fence; // Update previous value
    }
}

Vorrei salvare il "current_value_fence" ottenuto dopo il movimento del motore sulla EEPROM, in modo da sapere in che posizione si trova l'utensile al momento dell'accensione.

Ho letto sull'argomento ma non sono riuscito a venirne fuori...
Attualmente l'output che ottengo con questo codice sul monitor seriale (a fini di diagnostica) è il seguente:

System Running!
Motor Ready!

Vorrei avere anche il valore relativo alla posizione dell'utensile, qualcosa tipo:

System Running!
Motor Ready!
Current Fence position: XXX

Qualcuno saprebbe darmi una mano?
Grazie mille! :pray:

PS: @gpb01 devo aver fatto del casino creando una bozza, pubblicata per errore. Ho provveduto ad eliminarla ma la vedo ancora sul forum, ha lo stesso titolo di questo Argomento. Riusciresti a cancellarlo? Grazie!

Ma quale problema hai nello specifico ? C'e' una libreria apposita, EEPROM
Dovresti salvare nella loop() il valore di "current_value_fence" (occhio che è un float)
EEPROM.put(0, current_value_fence);
e poi nella setup leggerlo
EEPROM.get(0, current_value_fence);

Però... la eeprom non ha scritture infinite. Se scrivi troppe volte stesse celle (10.000 mi pare su Arduino Uno R3) poi si congelano.

1 Like

... poi si degradano ed il valore NON è più attendibile.

Guglielmo

1 Like

Come ha già scritto @nid69ita, il problema dell'EEPROM é proprio il fatto che é pensato per pochi cicli di scrittura e quindi lo si usa per salvare dei parametri o delle configurazioni, non per cambiare valore di continuo. Parti dal fatto che può aggiornare il valore per 10.000 volte e guarda ogni quanti secondi salvi il valore, a quel punto sai dopo quanto tempo l'EEPROM non sarà più utilizzabile.

Soluzioni?
1- Usa un condensatore da 1F e non appena "scopri" che non hai più corrente, salvi il valore nell'EEPROM.
2- Usa un encoder in cui puoi scoprire la posizione iniziale, tipo AS5600.
3- Usa una memoria esterna tipo FRAM

Il costo tra le varie soluzioni é simile (~5€).

1 Like

In realtà, dato che il limite è per singolo byte, esistono delle tecniche per la memorizzazione "a rotazione" nei vari bytes di memoria ... si allunga solo il tempo e, in casi come questi, non sono certo la "soluzione" ma un procrastinare il problema :wink:

La soluzione più semplice, come indicato, è usare memorie di tipo RAM (quindi con scritture praticamente illimitate) ma che, con tecniche varie, conservino il valore in memoria anche in assenza di alimentazione ... FRAM, EERAM o NVSRAM (di queste ultime abbiamo più volte parlato e c'è anche una mia libreria bella e pronta per il loro utilizzo).

Guglielmo

1 Like

Grazie a tutti per il vostro aiuto!
@gpb01 mi potresti indicare la tua libreria? :slight_smile:
Cercando on-line ho trovato mille mila modelli diversi, avete dei suggerimenti per una memoria?
Grazie ancora!

Prova a vedere questa discussione

Modulini già fatti x Arduino con nvsram non ne ho trovati.
In alternativa potresti usare un modulino x scrivere su SD (ti basta una 512kb se si trova)

Avevo già messo tutto per farseli ... QUI :wink: ... e, sempre in quella discussione, la versione aggiornata della libreria (1.0.1).

Guglielmo

... ho fatto un aggiornamento, lo trovate alla fine di quella discussione.

Guglielmo

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.