Eeprom ... help!

J'ai un arduino pro mini qui me génère une tension à la sortie d'une DAC selon la valeur de deux variables selectionnables par boutons-poussoirs .. ces valeurs sont stockées dans une eeprom aux adresses 0 et 1 de façon à ce qu'à la mise sous tension de l'arduino, la dernière tension sélectionnée revienne

Les valeurs par bouton-poussoirs :
BP1 => adresse0= 2.00 et adresse1 = 715.00
BP2 => adresse0= 1.50 et adresse1 = 715.00
BP3 => adresse0= 1.00 et adresse1 = 715.00
BP4 => adresse0= 1.00 et adresse1 = 204.00

Les tensions de sortie sont bonnes en fonctionnement normal
Mais à la remise sous tension, seule la valeur du BP4 revient correctement ... les autres produisent une tension differente

j'ai mis deux serial.print des valeurs relues dans l'eeprom à l'allumage et elles sont correctes mais mais la DAC ne donnent pas la bonne tension .. une idée?

capture 2023-10-29 à 17.05.34

Mon sketch :


#include "MCP_DAC.h"
#include <EEPROM.h>  // bibliotheque pour lire et ecrire dans Eeprom

MCP4921 MCP(11, 10);  //attribution entrées -> MCP4921 MCP(MOSI, SCK)

double tensionEYE3 = 0;            // tension mesurée en volt
double tensionEYE3max = 715;       // 715 = 3,55v
double valeurAenvoyer = 0;         // valeur numerique envoyée au DAC
double tensionVoulueEnSortie = 0;  // valeur en sortie de la formule

int adresse1 = 0;
int adresse2 = 1;
float Kchoisi;

//Choix des pines d'entrée
int boutonA = 6;  // the number of the RF output D0 => pine D3 
int boutonB = 5;  // the number of the RF output D1 => pine D4 
int boutonC = 4;  // the number of the RF output D2 => pine D5 
int boutonD = 3;  // the number of the RF output D3 => pine D6 
int LedChoix = 2; // led clignotante sur D2

// ========================
// Initialisation programme
// ========================
void setup() {

  // Initialise la liaison série (arduino nano -> PC)
  Serial.begin(115200);
  // initialise les pines boutton en mode entrée
  pinMode(boutonA, INPUT);
  pinMode(boutonB, INPUT);
  pinMode(boutonC, INPUT);
  pinMode(boutonD, INPUT);
  pinMode(10, OUTPUT); // CS de la DAC
  pinMode(12, OUTPUT); // MOSI(SDI) de la DAC
  pinMode(13, OUTPUT); // CLK de la DAC
  pinMode(LedChoix, OUTPUT);

// commande chip slect (CS) attribuée à la pine D12
  MCP.begin(12);

  //lecture de la dernière valeur de l'acceleration choisie
  Kchoisi = EEPROM.read(adresse1);
  tensionEYE3max = EEPROM.read(adresse2);


  delay(100);

  // si la case lue contient 255, la remplacer par Kchoisi 1.5
  if (Kchoisi == 255) {
    Kchoisi = 2;
  }
}
// =================
// Boucle principale
// =================
void loop() {
Serial.println(Kchoisi);
Serial.println(tensionEYE3max);
Serial.println(" ");
  // === CHOIX COURBES  ===================================
  // Pour acceleration très faible (kchoisi=2),presser le bouton A => RF haut
  // 1 clignotements

  if (digitalRead(3) == HIGH) { // Bouton A -> D3(Mini) -> D0(RF)
    Kchoisi = 2.0;                   // acceleration très faible
    tensionEYE3max = 715;
    EEPROM.write(adresse1, Kchoisi);  // ------------- ecrire Bchoisi dans EEPROM
    EEPROM.write(adresse2, tensionEYE3max);
    delay(100);
    ClignotementsLed(1, 500);        // 1 clignotements
  }

  // Pour aceleration faible (Kchoisi=1,5) ,presser le bouton B => RF haut
  // 2 clignotements

  if (digitalRead(4) == HIGH) { // Bouton B -> D4(Mini) -> D1(RF)
    Kchoisi = 1.5;                   // accelereration faible
     tensionEYE3max = 715;
    EEPROM.write(adresse1, Kchoisi);  // ------------- ecrire Bchoisi dans EEPROM
    EEPROM.write(adresse2, tensionEYE3max);
    delay(100);
      ClignotementsLed(2, 500);        // 2 clignotements
  }

  // Pour acceleration forte (Kchoisi= 1,2),presser le bouton C ==> RF haut
  // 3 clignotements

  if (digitalRead(5) == HIGH) {  // Bouton C -> D5(Mini) -> D2(RF)
    Kchoisi = 1;                   // acceleration forte
     tensionEYE3max = 715;
   
    EEPROM.write(adresse1, Kchoisi);  // ------------- ecrire Bchoisi dans
    EEPROM.write(adresse2, tensionEYE3max);
    delay(100);
     ClignotementsLed(3, 500);        // 3 clignotements
  }

  // Pour acceleration très forte (Kchoisi=1),presser le bouton D ==> RF haut
  // 4 clignotements

  if (digitalRead(6) == HIGH) {   // Bouton D rouge -> D6(Mini) -> D3(RF)
    Kchoisi = 1.0;                   //  acceleration très forte
    tensionEYE3max = 204;
    EEPROM.write(adresse1, Kchoisi);  // ------------- ecrire Bchoisi dans EEPROM
     EEPROM.write(adresse2, tensionEYE3max);
    delay(100);
     ClignotementsLed(4, 500);        // 4 clignotement
  }

  // === MESURE SIGNAL,TRAITEMENT ET ENVOI VERS DAC ===============

  // lecture signal sur la pine A3
  double tensionEYE3 = analogRead(A3);

  //La formule ne fonctionnera pas si tensionEYE3 > tensionEYE3max 
  if (tensionEYE3 > tensionEYE3max) {
    tensionEYE3 = tensionEYE3max;
  }

  // Formule de la courbe à sortir
  double tensionVoulueEnSortie = tensionEYE3max - pow(pow(tensionEYE3max, Kchoisi) - pow(tensionEYE3, Kchoisi), 1 / Kchoisi);

  // calcul de la valeur de la tension voulue en sortie du DAC et son envoi
  // * 4.0 pour convertir la sortie en 12bits et + 0,x si ajustement necessaire 
  double valeurAenvoyer = (tensionVoulueEnSortie * 4.0); 

  // envoi sur sortie DAC
  MCP.analogWrite(valeurAenvoyer);  // ecriture signal sur la pine 8 du MCP4921
}

// === SOUS-PROGRAMME CLIGNOTEMENTS ===============================
void ClignotementsLed(int C, unsigned long T) {
  for (int i = 1; i <= C; i++) {
    digitalWrite(LedChoix, HIGH);
    delay(T);
    digitalWrite(LedChoix, LOW);
    delay(T);
  }
}

Bonjour jo_6466

Tu sauves et lis:

	Kchoisi = EEPROM.read(adresse1);
	tensionEYE3max = EEPROM.read(adresse2);

Ce sont des variable de type float et double (4 bytes), or EEPROM read et write, ce n'est qu'un byte (8 bits de 0 à 255).

Pour faciliter le sauvegarde et la restitution de 2 variables double ou autres formats, il est préférable de les mettre dans une structure, et pour lire ces 2 variable, c'est EEPROM.get() et pour sauver, EEPROM.put().

Cordialement
jpbbricole

Pourquoi le Serial.print affiche-t-il la bonne valeur?

Bonjour jo_6466

Je ne puis te le dire, mais de sauver en EEPROM, avec read et write, quelque chose de plus grand qu'un byte (LSByte), fait que l'on ne sauve qu'un byte sur les 4 (float et double) donc on ne relit que ce byte.

J'ai adapté ton programme à la structure, essaies ça (ça compile mais pas essayé). Les variables à sauver sont dans la structure params

#include "MCP_DAC.h"
#include <EEPROM.h>  // bibliotheque pour lire et ecrire dans Eeprom

MCP4921 MCP(11, 10);  //attribution entrées -> MCP4921 MCP(MOSI, SCK)

struct parametresDef     // Structure avec les paramètres choisis
{
	float Kchoisi;
	double tensionEYE3max = 715;
};
parametresDef params;

double tensionEYE3 = 0;            // tension mesurée en volt
//double tensionEYE3max = 715;       // 715 = 3,55v
double valeurAenvoyer = 0;         // valeur numerique envoyée au DAC
double tensionVoulueEnSortie = 0;  // valeur en sortie de la formule

int adresse1 = 0;
//int adresse2 = 1;
//float Kchoisi;

//Choix des pines d'entrée
int boutonA = 6;  // the number of the RF output D0 => pine D3
int boutonB = 5;  // the number of the RF output D1 => pine D4
int boutonC = 4;  // the number of the RF output D2 => pine D5
int boutonD = 3;  // the number of the RF output D3 => pine D6
int LedChoix = 2; // led clignotante sur D2

// ========================
// Initialisation programme
// ========================
void setup() {

	// Initialise la liaison série (arduino nano -> PC)
	Serial.begin(115200);
	// initialise les pines boutton en mode entrée
	pinMode(boutonA, INPUT);
	pinMode(boutonB, INPUT);
	pinMode(boutonC, INPUT);
	pinMode(boutonD, INPUT);
	pinMode(10, OUTPUT); // CS de la DAC
	pinMode(12, OUTPUT); // MOSI(SDI) de la DAC
	pinMode(13, OUTPUT); // CLK de la DAC
	pinMode(LedChoix, OUTPUT);

	// commande chip slect (CS) attribuée à la pine D12
	MCP.begin(12);

	//lecture de la dernière valeur de l'acceleration choisie
	EEPROM.get(adresse1, params);     // Lecture des paramètres
	//Kchoisi = EEPROM.read(adresse1);
	//tensionEYE3max = EEPROM.read(adresse2);


	delay(100);

	// si la case lue contient 255, la remplacer par Kchoisi 1.5
	if (params, params.Kchoisi == 255) {
		params.Kchoisi = 2;
	}
}
// =================
// Boucle principale
// =================
void loop() {
	Serial.println(params.Kchoisi);
	Serial.println(params.tensionEYE3max);
	Serial.println(" ");
	// === CHOIX COURBES  ===================================
	// Pour acceleration très faible (kchoisi=2),presser le bouton A => RF haut
	// 1 clignotements

	if (digitalRead(3) == HIGH) { // Bouton A -> D3(Mini) -> D0(RF)
		params.Kchoisi = 2.0;                   // acceleration très faible
		params.tensionEYE3max = 715;
		EEPROM.put(adresse1, params);     // Sauvegarde des paramètres
		//EEPROM.write(adresse1, Kchoisi);  // ------------- ecrire Bchoisi dans EEPROM
		//EEPROM.write(adresse2, tensionEYE3max);
		delay(100);
		ClignotementsLed(1, 500);        // 1 clignotements
	}

	// Pour aceleration faible (Kchoisi=1,5) ,presser le bouton B => RF haut
	// 2 clignotements

	if (digitalRead(4) == HIGH) { // Bouton B -> D4(Mini) -> D1(RF)
		params.Kchoisi = 1.5;                   // accelereration faible
		params.tensionEYE3max = 715;
		EEPROM.put(adresse1, params);     // Sauvegarde des paramètres
		//EEPROM.write(adresse1, Kchoisi);  // ------------- ecrire Bchoisi dans EEPROM
		//EEPROM.write(adresse2, tensionEYE3max);
		delay(100);
		ClignotementsLed(2, 500);        // 2 clignotements
	}

	// Pour acceleration forte (Kchoisi= 1,2),presser le bouton C ==> RF haut
	// 3 clignotements

	if (digitalRead(5) == HIGH) {  // Bouton C -> D5(Mini) -> D2(RF)
		params.Kchoisi = 1;                   // acceleration forte
		params.tensionEYE3max = 715;
		
		EEPROM.put(adresse1, params);     // Sauvegarde des paramètres
		//EEPROM.write(adresse1, Kchoisi);  // ------------- ecrire Bchoisi dans
		//EEPROM.write(adresse2, tensionEYE3max);
		delay(100);
		ClignotementsLed(3, 500);        // 3 clignotements
	}

	// Pour acceleration très forte (Kchoisi=1),presser le bouton D ==> RF haut
	// 4 clignotements

	if (digitalRead(6) == HIGH) {   // Bouton D rouge -> D6(Mini) -> D3(RF)
		params.Kchoisi = 1.0;                   //  acceleration très forte
		params.tensionEYE3max = 204;
		EEPROM.put(adresse1, params);     // Sauvegarde des paramètres
		//EEPROM.write(adresse1, Kchoisi);  // ------------- ecrire Bchoisi dans EEPROM
		//EEPROM.write(adresse2, tensionEYE3max);
		delay(100);
		ClignotementsLed(4, 500);        // 4 clignotement
	}

	// === MESURE SIGNAL,TRAITEMENT ET ENVOI VERS DAC ===============

	// lecture signal sur la pine A3
	double tensionEYE3 = analogRead(A3);

	//La formule ne fonctionnera pas si tensionEYE3 > tensionEYE3max
	if (tensionEYE3 > params.tensionEYE3max) {
		tensionEYE3 = params.tensionEYE3max;
	}

	// Formule de la courbe à sortir
	double tensionVoulueEnSortie = params.tensionEYE3max - pow(pow(params.tensionEYE3max, params.Kchoisi) - pow(tensionEYE3, params.Kchoisi), 1 / params.Kchoisi);

	// calcul de la valeur de la tension voulue en sortie du DAC et son envoi
	// * 4.0 pour convertir la sortie en 12bits et + 0,x si ajustement necessaire
	double valeurAenvoyer = (tensionVoulueEnSortie * 4.0);

	// envoi sur sortie DAC
	MCP.analogWrite(valeurAenvoyer);  // ecriture signal sur la pine 8 du MCP4921
}

// === SOUS-PROGRAMME CLIGNOTEMENTS ===============================
void ClignotementsLed(int C, unsigned long T) {
	for (int i = 1; i <= C; i++) {
		digitalWrite(LedChoix, HIGH);
		delay(T);
		digitalWrite(LedChoix, LOW);
		delay(T);
	}
}

A+
jpbbricole

Parfait ... cela fonctionne .. merci!
A moi de chercher à comprendre ce que tu as modifié

Bonsoir jo_6466

Super !
J'ai laissé toutes les lignes devenues inutiles, en remarque.

Bonne continuation.
jpbbricole

J'ai l'impression d'être entré dans une boucle temporelle.
C'est un échange que l'on a déjà eu avec @jo_6466

Pourquoi as-tu effacé l'adresse2?.. les 2 valeurs de la structure peuvent être stockées à la même adresse1?

int adresse1 = 0;
//int adresse2 = 1;
//float Kchoisi;

Bonsoir jo_6466

Parce qu'elle ne sert plus, vu que la structure params est sauvée depuis l'adresse adresse1 et structure contient toutes les valeurs à sauver.

Si tu veux savoir quelle quantité d'EEPROM est utilisée par la sauvegarde de params, tu fais:
Serial.println(sizeof(params));

A+
jpbbricole

Merci pour les explications ... donc la variable float ou double peut prendre plusieurs adresses consécutives?

Autre question :
si on veut rendre le sketch plus rapide quel type de variables sont les préférables entre double et float sachant que c'est un arduino pro mini et qu'elles doivent être stockées en eeprom

Je n'ai à manipuler que des valeurs à deux décimales

Mes premiers essais en remplaçant double par floating m'ont donné des résultats erronnés

Bonsoir jo_6466

Oui, mais dans ton cas, on ne s'occupe plus de ce "détail", vu que tout est encapsulé dans une structure, qui, elle, prends plusieurs adresses consécutives.
L'énorme avantage d'opérer ainsi, avec nos variables en structure et de les sauver sous cette forme est que si tu veux ajouter une variable, par exemple boolean mesureOk = false

struct parametresDef     // Structure avec les paramètres choisis
{
	float Kchoisi;
	double tensionEYE3max = 715;
	boolean mesureOk = false;
};

C'est simple à faire, c'est automatiquement sauvé par:
EEPROM.put(adresse1, params); // Sauvegarde des paramètres
et restitué par:
EEPROM.get(adresse1, params); // Lecture des paramètres

Ca sort de mes compétences, je n'ai pas assez d'exoériences :woozy_face:

Cordialement
jpbbricole

C'est devenu clair pour moi ... l'utilisation de la structure est donc interessante si on veut sauvegarder plusieurs valeurs en eeprom sans ce préocuper de choisir une adresse pour chacunes d'elles et ainsi supprimer le risque de chevauchements de données

De même gérer le changement d'adresse dû au remplacement du type d'une des variables n'est plus un problème , c'est automatique ... c'est bien ça?

Bonsoir jo_6466

Super!

Oui.

En plus, une structure facilite grandement l'écriture du programme, pour autant que l'on a l'autocomplétion, comme dans l'IDE 2.0, il suffit de taper params. pour avoir les membres de la structure et d'en choisir un.

Bonne soirée.
jpbbricole

Question :
j'aurai besoin de vérifier de façon très précise la valeur d'une variable par le moniteur série
Mais il ne m'affiche que deux décimales ... y-a-t-il un moyen d'en afficher plus?

Bonjour,

Serial.print(val,6);
6 étant le nombre de décimales.

Merci!

Question 1:
je travaille avec un ESP-M3-DevKit dont je ne trouve pas le détail de son Pinout

J'ai juste ceci :

ESP_M3_DevKit

Je me demande si la pine ADC est bien une entrée analogique que je pourrai utiliser pour mesurer la tension batterie afin de me donner une alarme à un certain seuil de décharge?

Question 2:
Si ma batterie ne dépassera jamais 4,2v , puis-je mesurer directement sa tension sans passer par un pont diviseur?

Je ne suis pas un expert, mais si la sérigraphique la possibilité d'un ADC, je ne vois pas ce que ça pourrait être autre?

Question 2, normalement l'ADC mesure des tensions jusqu'à sa tension de référence. qui peut dépendre de l'alimentation ou une tension interne.
Après peut être qu'il est possible que l'ADC supporte les 1V de surtension, je ne connais pas le schéma de ta carte de développement.

Non puisque l'ESP est alimenté en 3,3V.
D'autant que si j'ai bien compris le 2AL3B-ESP-M utilise un ESP8285 et donc la réf interne doit être 1V

Bonsoir

Sur certaines cartes un pont diviseur de rapport 1/3 environ est inséré entre l'entrée ADC de la carte et l'entrée analogique du module contenant un ESP8266 ou un ESP8285

Si le schéma de la carte n'est pas disponible faire un essai : appliquer 1V sur l'entrée ADC de la carte et voir ce que donne la conversion analogique/numérique.