Calcolatrice di valori con errore (incertezza) fisico

Buongiorno a tutti e a tutte,
Mi sono scontrato contro un problema che credo sia alquanto comune alle scuole superiori e mi chiedevo come potessi risolverlo. In sostanza il problema è questo: "come si può calcolare più velocemente una misura con il suo errore (incertezza) assoluto (a)?". Mi sono allora risposto da solo pensando di usufruire delle infinite potenzialità di Arduino. Ho iniziato allora provando a scrivere un codice tale che inserendo i valori dalla porta seriale mi riuscisse a fare tutti i calcoli e restituendomi i valori tramite un display. Raggiunto tale traguardo mi sono posto un obiettivo più alto: evitare di usare la porta seriale in modo da potermi portare la "calcolatrice" in giro senza dover utilizzare il computer (in tal caso basterebbe una tabella excel). Per Natale il gentilissimo babbo Natale mi ha regalato un tastierino a matrice 4x4 (questo), ma non so come utilizzarlo perchè nelle "istruzioni" è presente solo una spiegazione su come estrarre un valore singolo alla volta, ma a me serve un sistema che mi possa permettere di scrivere un valore anche con cifre decimali. Ho allora tentato di adattare il codice che utilizzavo per leggere dalla porta seriale al tastierino, ma non ci sono riuscito. Il codice per leggere i dati dalla porta seriale è il seguente:

if(Serial.available()){               //inserisce i caratteri inviati sul monitor seriale dentro la variabile di tipo "char"
    stringa = "";
    do{
      if(Serial.available()){           
        c=Serial.read();
        if(c != '\n')
        stringa+=c;
      }
    }while(c != '\n');

Il problema sta nel fatto che non ho un Serial.available() per il tastierino...
Inoltre le variabili float tengono i valori decimali fino ai centesimi, ma nei calcoli scientifici si può arrivare ad avere anche più di 5-6 cifre decimali...

Riassumendo i problemi sono:

  • Permettere il funzionamento del tastierino 4x4 su Arduino;
  • Trovare una modalità che permetta di compiere calcoli e immagazzinare dati in variabili con numeri decimali oltre le 5-6 cifre decimali;
  • Ottimizzare lo sketch se possibile;
  • Eventualmente salvare i calcoli su una schedina microSD;

Il codice al momento è il seguente:

#include <Keypad.h>
#include <LiquidCrystal.h>
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);
#define COLS 4
#define ROWS 4

char KEYS[ROWS][COLS]={
{'1', '2', '3', 'A'},
{'4', '5', '6', 'B'},
{'7', '8', '9', 'C'},
{'*', '-', '#', 'D'}
};
byte colPIN[COLS] = { 31, 33, 35, 37 };
byte rowPIN[ROWS] = { 23, 25, 27, 29 };
char pressedTaster;
Keypad tastierino = Keypad(makeKeymap(KEYS), rowPIN, colPIN, ROWS, COLS);


char c;
String stringa;

struct incertezza{
  float x;
  float Dx;
  float y;
  float Dy;
  float G;
  float DG;
  byte operazione;
  byte stato;
  float elevato;
};
struct incertezza inc;
void setup() {
  lcd.begin(16,2);
  lcd.clear();
  lcd.setCursor(0, 0);
  Serial.begin(9600);
  inc.stato = 0;
}

void loop() {
  Serial.println(stringa);
  if(inc.stato == 0){
    lcd.setCursor(0,0);
    lcd.print("Calcolatrice");
    lcd.setCursor(0,1);
    lcd.print("con errore");
    delay(500);
    inc.stato = 1;
  }else if(inc.stato == 1){
    lcd.clear();
    lcd.setCursor(0,0);
    lcd.print("misura 1:");
    lcd.setCursor(10,0);
    lcd.print(stringa);
    if(Serial.available()){
    stringa = "";
    do{        
        c=tastierino.getKey();
        if(c != "A" || c != "B" || c != "C" || c != "D"){
          stringa+=c;
        }
    }while(c != "A" || c != "B" || c != "C" || c != "D");
  }
  inc.x = stringa.toFloat();
  if(inc.x != 0){
  inc.stato = 2;
  lcd.print(inc.x);
  stringa = "";
  delay(1500);
  }
  }else if(inc.stato == 2){
    lcd.clear();
    lcd.setCursor(0,0);
    lcd.print("errore misura 1:");
    lcd.setCursor(0,1);  
    stringa = "";
    do{        
        c=tastierino.getKey();
        if(c != "A" || c != "B" || c != "C" || c != "D"){
          stringa+=c;
        }
    }while(c != "A" || c != "B" || c != "C" || c != "D");
  inc.Dx = stringa.toFloat();
  if(inc.Dx != 0){
  inc.stato = 3;
  lcd.print(inc.Dx);
  stringa = "";
  delay(1500);
  }
  }else if(inc.stato == 3){
    lcd.clear();
    lcd.setCursor(0,0);
    lcd.print("misura 2 o ^x:");
    lcd.setCursor(10,0);
    lcd.print(stringa);
    if(Serial.available()){
    stringa = "";
    do{        
        c=tastierino.getKey();
        if(c != "A" || c != "B" || c != "C" || c != "D"){
          stringa+=c;
        }
    }while(c != "A" || c != "B" || c != "C" || c != "D");
  }
  inc.y = stringa.toFloat();
  if(inc.y != 0){
  inc.stato = 4;
  lcd.print(inc.y);
  stringa = "";
  delay(1500);
  }
  }else if(inc.stato == 4){
    lcd.clear();
    lcd.setCursor(0,0);
    lcd.print("errore misura 2:");
    lcd.setCursor(0,1);  
    if(Serial.available()){
    stringa = "";
  }
  inc.Dy = stringa.toFloat();
  if(inc.Dy != 0){
  inc.stato = 5;
  lcd.print(inc.Dy);
  stringa = "";
  delay(1500);
  }
  }else if(inc.stato == 5){
    lcd.clear();
    lcd.setCursor(0,0);
    lcd.print("operazione:");
    lcd.setCursor(0,1);  
    if(Serial.available()){
    stringa = "";
    do{        
        c=tastierino.getKey();
        if(c != "A" || c != "B" || c != "C" || c != "D"){
          stringa+=c;
        }
    }while(c != "A" || c != "B" || c != "C" || c != "D");
    }
if(stringa == "+"){
    inc.G = inc.x+inc.y;
    lcd.clear();
    lcd.setCursor(0,0);
    lcd.print("risultato:");
    delay(1000);
    lcd.clear();
    lcd.setCursor(0,0);
    lcd.print("G=");
    lcd.setCursor(4,0);
    lcd.print(inc.G);
    inc.DG = inc.Dx+inc.Dy;
    lcd.setCursor(0,1);
    lcd.print("DG=");
    lcd.setCursor(4,1);
    lcd.print(inc.DG);
    while(1);
}else if(stringa == "-"){
    inc.G = inc.x-inc.y;
    lcd.clear();
    lcd.setCursor(0,0);
    lcd.print("risultato:");
    delay(1000);
    lcd.clear();
    lcd.setCursor(0,0);
    lcd.print("G=");
    lcd.setCursor(4,0);
    lcd.print(inc.G);
    inc.DG = inc.Dx+inc.Dy;
    lcd.setCursor(0,1);
    lcd.print("DG=");
    lcd.setCursor(4,1);
    lcd.print(inc.DG);
        while(1);
}else if(stringa == "*"){
    inc.G = inc.x*inc.y;
    lcd.clear();
    lcd.setCursor(0,0);
    lcd.print("risultato:");
    delay(1000);
    lcd.clear();
    lcd.setCursor(0,0);
    lcd.print("G=");
    lcd.setCursor(4,0);
    lcd.print(inc.G);
    inc.DG = inc.G*((inc.Dx/inc.x)+(inc.Dy/inc.y));
    lcd.setCursor(0,1);
    lcd.print("DG=");
    lcd.setCursor(4,1);
    lcd.print(inc.DG);
      while(1);
}else if(stringa == "/"){
    inc.G = inc.x/inc.y;
    lcd.clear();
    lcd.setCursor(0,0);
    lcd.print("risultato:");
    delay(1000);
    lcd.clear();
    lcd.setCursor(0,0);
    lcd.print("G=");
    lcd.setCursor(4,0);
    lcd.print(inc.G);
    inc.DG = inc.G*((inc.Dx/inc.x)+(inc.Dy/inc.y));
    lcd.setCursor(0,1);
    lcd.print("DG=");
    lcd.setCursor(4,1);
    lcd.print(inc.DG);
        while(1);
}else if(stringa == "^"){
  for(int i; i=1; i++){
    inc.elevato = inc.elevato*inc.x;
  }
    inc.G = inc.x*inc.x;
    lcd.clear();
    lcd.setCursor(0,0);
    lcd.print("risultato:");
    delay(1000);
    lcd.clear();
    lcd.setCursor(0,0);
    lcd.print("G=");
    lcd.setCursor(4,0);
    lcd.print(inc.G);
    inc.DG = inc.y*(inc.Dx/inc.x)*inc.elevato;
    lcd.setCursor(0,1);
    lcd.print("DG=");
    lcd.setCursor(4,1);
    lcd.print(inc.DG);
        while(1);
}
  }
  delay(1000);
}

Hai provato questo sketch su wokwi:

Per avere più cifre modifica questa riga:

memory = String(calculate(operation, leftNum, rightNum), 6);

Penso possa essere un buon punti di partenza.

Ciao.

Io farei così:

  • Dichiara la variabile come float
  • Alla pressione di un tasto:
    • Se numero:
      • Moltiplica la variabile temporanea per 10 e somma il tasto premuto
    • Se premuto il punto:
      • Da ora in poi sommi il numero premuto diviso per 10^(numero di cifre premute dopo la virgola). Cosi il numero va dopo la virgola
      • Raggiunto il numero massimo di decimali interrompi

Es.
tempVar = 0
1° tasto: 1. tempVar = (tempVar * 10) + 1 = (0 * 10) + 1 = 1
2° tasto: 4. tempVar = (tempVar * 10) + 4 = (1 * 10) + 4 = 10 + 4 = 14
3° tasto: , numPremuto = 0 (tempVar = 14,)
4° tasto: 3. tempVar = tempVar + (3 / 10^1) = 14 + (3 / 10) = 14 + 0,3 = 14,3
5° tasto: 9. tempVar = tempVar + (9 / 10^2) = 14,3 + (9 / 100) = 14,3 + 0,09 = 14,39
E cosi via

Le variabili float non tengono fino ai centesimi, ma hanno precisione fino a 7 decimali. E' il Serial.print del float che di default "stampa" due decimali. Puoi risolvere il problema indicando quanti decimali mostrare: Serial.print(tempVar, 5) nel caso di esempio restituisce 14,39000.

Per salvare i dati su scheda sd ci sono molte opzioni disponibili. Puoi anche provare a ri-adattare il codice di un data logger.

1 Like

Grazie mille per il consiglio.
Proverò a metterlo in prova. Fino ad ora mi sono cimentato in valori salvati su una variabile char e poi string (string += char) e poi andavo a convertirlo in float. Sembrerebbe più semplice il tuo esmpio.
Grazie ancora :grin:

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