chiarimenti su operatore di comparazione == [Risolto]

Salve a tutti

Sto cercando di realizzare un discriminatore con arduino IDE 1.0.1 scheda Mega 2560

In pratica leggo il valore di una tensione su porta analogica 0 e se il valore è uguale ad es. 3.21 accende un led " VERDE" lo stesso succede se raggiunge 3.22 V. accende " ROSSO" a 3.23 si accende il led “Giallo”
Questa variazione la simulo con un potenziometro posto con gli estremi tra + 5V e GND.
La tensione che viene instradata sulla porta 0 verificata con multimetro digitale è ad es. 3.21 ma il led "in questo caso verde " non ne vuol sapere di accendersi l’operatore di comparazione == non fa’ il suo dovere
qualcuno sa dirmi perche’ . Se invece uso l’operatore <= allora mi funziona ma il problema e’ che io voglio che solo se = alla tensione che voglio io devono accendersi il rispettivi led
Grazie allego lo sketch

#define inputPin1 0 //definisco i pin utilizzati di arduino pin analog 0

int valore1 = 0;


int numletture = 10;
float valorex= 0;// variabile di appoggio x comparazione 
float media1 = 0;// variabile x media 


float gradino = 0.00486;// fattore di conversione per gradino 0.0049 * 1023= 5V

void setup() {

  // put your setup code here, to run once:

  pinMode(11,OUTPUT);//inizializzo pin 11 come uscita digitale 
  pinMode(12,OUTPUT);
  pinMode(10,OUTPUT);
  Serial.begin(115200);// inizializzo la seriale software

}

void loop()  // put your main code here, to run repeatedly: 
{
  for (int k=0; k < 10; k++){  // Ciclo for per 10 letture

    valore1 = analogRead(inputPin1);//Leggo da analog input 0
    delay(10); 

    media1 = (valore1) + media1;// aggiungo lettura su variabile media1

  }

  media1 = (media1 / 10);// infine divido x 10 per la media letture 
  media1=(media1*gradino);//converto in volt
  valorex=media1;//valorex variabile di appoggio per discriminatore 

  if (valorex == 3.21 ) 
  {
    Led41();//se valore x = 3.21 V accendi led verde 
  }
  if (valorex == 3.22 ) 

  { 
    Led42();////se valore x = 3.22 V accendi led Rosso
  }

  if  (valorex == 3.23) { 
    Led43();// //se valore x = 3.2 V accendi led Giallo
  }


 
  Serial.print("PORTA ANALOGICA 0 =") ;// Stampo le medie lette da analog 0 
  Serial.print(media1);
  Serial.println();// aggiungo linefeed
  media1=0; //Azzero le medie per le prossime letture
 


}
void Led41(){
  digitalWrite(10,HIGH);
  delay(20);
  digitalWrite(10,LOW);
  }
void Led42(){
  digitalWrite(11,HIGH);
  delay(20);
  digitalWrite(11,LOW);
  }
void Led43(){
  digitalWrite(12,HIGH);
  delay(20);
  digitalWrite(12,LOW);
  }

mah,,, per accendere 3 led io metterei 3 if
visto che hai un multimetro porti la tensione a i valori che ti interessano con il voltmetro e leggi la lettura con analogRead e prendi nota dei tre valori

poi fai i tre if

se non hai un potenziometro lineare 10 giri la vedo dura trovare il valore preciso

Grazie per la risposta

Ho provato anche i tre if come da te consigliato ma non cambia la sostanza
per quanto riguarda il potenziometro nessun problema ho gia’ verificato con multimetro oscilloscopio Tektronics 213 DMM e’ uno strumento preciso e riesco ad trimmare abbastanza preciso ma non riesco ad accendere i led anche spostando da un estremo all’altro cioe’ da 0 a 4.99 Volt. Se utilizzo l’operatore <= tutto ok per me’ e’ un mistero .

proprio perchè ti va con il <= (sempre se non ci sono altri problemi che al momento non vedo) è sempre più probabile il fatto che non prendi il valore preciso…prova a fare una cosa con range tipo

if ((valorex >= 3.20 ) && (valorex <= 3.21))

invece di

if (valorex == 3.21 )

giusto per fare un esempio

poi io partirei da range abbastanza larghi così da vedere se il concetto in se funziona e piano piano lì restringi più che puoi (fino a che funziona praticamente)

Ok vado per tentativi e restringo il campo

grazie

Provo e faccio sapere

Perfetto funziona grazie per il suggerimento grandioso ale92 in effetti le finestre erano troppo strette nel mio skecth .
Scusa come faccio a mettere risolto sul mio Post .
Grazie

I valori possibili sono:
ADC= 658 valore calcolato= 3.19788002
ADC= 659 valore calcolato= 3.20274019
ADC= 660 valore calcolato= 3.20760011
ADC= 661 valore calcolato= 3.21246004
ADC= 662 valore calcolato= 3.21732020
ADC= 663 valore calcolato= 3.22218012
ADC= 664 valore calcolato= 3.22704005
ADC= 665 valore calcolato= 3.23190021
ADC= 666 valore calcolato= 3.23676013
ADC= 667 valore calcolato= 3.24162006
ADC= 668 valore calcolato= 3.24648022
ADC= 669 valore calcolato= 3.25134015

Spiegami dove trovi una corrispondenza ai valori 3.21 ; 3.22 o 3.23
Il == funziona correttamente, Il ragionamento su cui si basa il programma é sbagliato.

Suggerimenti:

  • non controllare le tensioni calcolate ma i valori ADC letti
  • la lettura non é mai cosí stabile che Ti legge i valori 661, 663 o 663 fissi.

Ciao Uwe

Grazie Uwe

Avevo provato anche a ragionare in termini dei numeri che mi riporta l'ADC ma non ne ero venuto a capo .
Potrebbe essere il mio ragionamento sbagliato ma bene o male con un potis dovrebbe primo o dopo lampeggiare qualcosa o no.Anche perche' l'oscillazione è di uno o due valori in piu' o in meno.
In definitiva se io misuro 3.21 e mi dopo la mia conversione vedo 3.21 perche' l'operatore di ccomparazione non funge?

latofra:
Grazie Uwe

Avevo provato anche a ragionare in termini dei numeri che mi riporta l’ADC ma non ne ero venuto a capo .
Potrebbe essere il mio ragionamento sbagliato ma bene o male con un potis dovrebbe primo o dopo lampeggiare qualcosa o no.Anche perche’ l’oscillazione è di uno o due valori in piu’ o in meno.
In definitiva se io misuro 3.21 e mi dopo la mia conversione vedo 3.21 perche’ l’operatore di ccomparazione non funge?

No, non avresti mai visto accendere un LED, perché se fai un confronto con 3,21 la tensione calcolata deve essere 3,210000 e non 3,21 e qualcosa.

Se usi dei Float non puoi usare il == ma devi sempre definire un valore sopre a uno sotto il quale la condizione é valida. Percui:

if ((valorex >=3,205) && (valorex <3,215))

Ti da un controllo se il valore é di 3,21 (arrotondato).

Ciao Uwe

latofra:
Grazie per la risposta

Ho provato anche i tre if come da te consigliato ma non cambia la sostanza
per quanto riguarda il potenziometro nessun problema ho gia’ verificato con multimetro oscilloscopio Tektronics 213 DMM e’ uno strumento preciso e riesco ad trimmare abbastanza preciso ma non riesco ad accendere i led anche spostando da un estremo all’altro cioe’ da 0 a 4.99 Volt. Se utilizzo l’operatore <= tutto ok per me’ e’ un mistero .

questo li fa accendere (mettere nel void loop e assicurarsi che i pin siano settato come output e messi LOW nel setup)

map(analogRead(A0), 0, 1023, 0, 500);

if (analogRead(A0) >= 321 && analogRead(A0) < 322) digitalWrite (10, HIGH);
if (analogRead(A0) >= 322 && analogRead(A0) < 323) digitalWrite (11, HIGH);
if (analogRead(A0) >= 323 && analogRead(A0) < 324) digitalWrite (12, HIGH);

e se metti anche queste righe si spengono se il potenziometro fa segnare una tensione diversa

if (analogRead(A0) < 321 && analogRead(A0) >=322) digitalWrite (10, LOW);
if (analogRead(A0) < 322 && analogRead(A0) >=323) digitalWrite (11, LOW);
if (analogRead(A0) < 323 && analogRead(A0) >=324) digitalWrite (12, LOW);

IMHO fare == su un analogRed è gia una specie di controsenso
ci va sempre l’accoppiata >= <

uwefed:
Se usi dei Float non puoi usare il == ma devi sempre definire un valore sopre a uno sotto il quale la condizione é valida.

Confermo, per via di come sono rappresentati i float è praticamente impossibile prevedere un valore esatto su cui eseguire un confronto "==", è sempre necessario prevedere una certa isteresi utilizzando una soglia minore e una superiore.
Aggiungo pure che su Arduino non è molto saggio utilizzare i float quando non è indispensabile (usa una mcu da solo 8 bit senza nessun supporto hardware per i float),meglio lavorare sempre con valori interi preventivamente moltiplicati x10,x100,x1000, etc, a seconda del numero di decimali desiderati.

latofra:
In definitiva se io misuro 3.21 e mi dopo la mia conversione vedo 3.21 perche’ l’operatore di ccomparazione non funge?

perchè la println “taglia” alla seconda cifra decimale, ma in realtà ce ne possono essere di più. Sul reference trovi quale println usare per visualizzare un numero arbitrario di valori dopo la virgola

Grazie a tutti per i preziosi consigli ho capito che beccare il giusto valore dopo la virgola e' un impresa titanica molto meglio prevedere delle finestre .I vostri consigli mi hanno spiegato in pratica come fare .
Per me il topic e' chiuso . Alla prossima

uwefed:
I valori possibili sono:
ADC= 658 valore calcolato= 3.19788002
ADC= 659 valore calcolato= 3.20274019
ADC= 660 valore calcolato= 3.20760011
ADC= 661 valore calcolato= 3.21246004
ADC= 662 valore calcolato= 3.21732020
ADC= 663 valore calcolato= 3.22218012
ADC= 664 valore calcolato= 3.22704005
ADC= 665 valore calcolato= 3.23190021
ADC= 666 valore calcolato= 3.23676013
ADC= 667 valore calcolato= 3.24162006
ADC= 668 valore calcolato= 3.24648022
ADC= 669 valore calcolato= 3.25134015

una precisazione; questi valori sono validi se calcolati con i float (vedi infinitesimale del calcolatore) e utilizzando la stessa logica che usa il chip.
Per fare un esempio, sempre con i float, avevo problemi che simulazioni fisiche su due sistemi differenti, nonostante gli stessi valori iniziali, avevano delle diversità dopo pochi step di esecuzione; per risolvere è bastato dare come direttiva al compilatore il parametro "strictfp" (questo in java, ma se ben ricordo c'è qualcosa di simile anche in C), in pratica disattivi tutte le ottimizzazioni non standard sul calcolo dei valori float, che sono diverse da CPU a CPU.

lesto:
che sono diverse da CPU a CPU.

Non da cpu a cpu, parliamo di micro senza fpu, ma da compilatore a compilatore e relative implementazioni su micro specifici dello stesso.
Di solito sul manuale del compilatore c'è sempre una sezione dedicata ai float dove viene descritta l'implementazione utilizzata, quella più diffusa è la IEEE 754, e le eventuali divergenze dallo standard utilizzato.

diciamo che esistono mille standard e non, strictfp forza l'uso dell'IEEE 754

lesto:
strictfp forza l'uso dell'IEEE 754

In C/C++ non esiste quel comando/funzione, è solo in Java perché nelle ultime release usano un formato divergente dal IEEE 754, serve a garantire la trasportabilità dei valori verso altri software, problema che in C/C++ non esiste, almeno parlando di compilatori per PC, se andiamo sulle mcu/micro il discorso è diverso e possono esserci dei problemi per trasferire float, in formato binario, tra programmi realizzati con compilatori diversi.

sì, principalmente nasce per il fatto che i sistemi 64bit usano (nelle JVM > 1.2) la rappresentazione 80bit..
ma ti assicuro che di diversità se ne riscontarno anche tra intel/amd entrambi a 64bit, e mi pare che i dati differissero anche sullo stesso PC ma con OS differente (win e linux)

se ho visto bene, il c/c++ può usare il IEEE745 o il IEEE754, oltre che varie ottimizzazioni di compilatore. Il determinismo dei float è una brutta bestia anche sui PC, ed ampiamente discussa perchè rendendo deterministici i clacoli si rende deterministica la fisica e quindi con una buona sincronizzazione dei delta (ovvero solo delle forze applicate e oggetti creati/eliminati) si possono avere le simulazioni remote completamente sincronizzate senza inviare gli stati di tutti gli oggetti nella fisica ogni tot, riducendo drasticamente l'uso di banda in base all'iterazione dei client. E spesso i client "passivi" sono tanti