domenica 3 settembre 2017

Calcolatrice RPN

- Calcolatrice RPN con Arduino - 

-  RPN Calculator with Arduino-

- 28/08/2017-

   Progetto di calcolatrice con Arduino, questo esperimento è per tutti, non presenta difficoltà è facile reperire il materiale ed è un progetto economico.





Materiale occorrente:

Arduino UNO
LCD 16x2 I2C
Tastierino a matrice 4x4





Caratteristiche del progetto:
_ Costo del materiale molto contenuto.
_ Calcolatrice simil scientifica di tipo RPN.
_ La calcolatrice proposta non è programmabile ma è possibile preparare dei programmi
    o nuove funzioni da inserire nello sketch e successivamente richiamarli
    con la  funzione XEQ  nn.

Per realizzare questo progetto mi sono ispirato alla mia HP-41, è chiaro che non è possibile realizzare una calcolatrice con quelle caratteristiche, ma mi sono ispirato alla sua filosofia e alle sue funzioni.

Le funzioni che ho implementato sono solo una piccolissima parte di quelle della HP, ho escluso tutte quelle utili alla programmazione diretta e tutta la parte "ALFA" .

Queste limitazioni sono imposte dal numero dei tasti 4x4 cioè 16 tasti.
Ho quindi utilizzato molto i tasti seconda funzione, e da 16 si passa a 32 ma non bastava ancora, ho quindi implementato la funzione XEQ nn, (vagamente simile a quella della HP), con la quale si possono richiamare funzioni o programmi preimpostati nello sketch.

La realizzazione hardware è molto semplice ho usato un display 16x2 con la I2C quindi per il collegamento sono sufficienti 4 fili (SDA, SCL, VCC, GND).
Unica nota attenzione !! Io ho utilizzato " LiquidCrystal_I2C lcd(0x3F,16,2); " ma nel Vostro progetto anziché 0x3F potrebbe essere necessario altro indirizzo.

Per quanto riguarda il tastierino numerico i collegamenti sono semplici 4 pin servono per le colonne, e 4 pin per le righe, da collegare ad 8 pin digitali di arduino (nel mio caso 0-7).




Come si può vedere i collegamenti sono semplici.

Prima di procedere oltre vediamo la caratteristica principale di questa calcolatrice.

RPN (Notazione Polaccacca Inversa) reverse polish notation.

Nella RPN si introducono prima gli operandi e dopo gli operatori.
I valori vengono impilati nella "CATASTA" e gli operatori eseguono il calcolo facendo scendere la catasta.

Chi non conosce questa notazione seguendo questo post e costruendo questa calcolatrice scoprirà qualcosa di diverso dal solito, e molto interessante.

Dopo la descrizione dello sketch e delle varie funzioni, con la calcolatrice costruita potrete procedere al collaudo ed alla comprensione della notazione polacca inversa.

Per chi conosce la notazione polacca inversa la costruzione di questa calcolatrice servirà ad approfondire questo sistema di calcolo. Anzi troverà nella mia implementazione delle semplificazioni forse troppo spartane (soprattutto se raffrontate alle implementazioni di HP), e se vorrà potrà correggere e migliorare quanto fatto.


In questa calcolatrice gli operatori lavorano solo utilizzando gli operandi in catasta.

Quindi con questa calcolatrice si dovrà digitare 12 enter, poi 14 enter, adesso in y abbiamo il 12 in x il 14 la pressione dell'operando "+" eseguirà la somma ed il risultato sarà in x in y scende il contento di z, in z scende il contento di t. ( questo in modo del tutto analogo alla HP-41).

Queste le funzioni da tastiera:

Io ho inserito i codici ASCII che si vedono sopra, che rappresenteranno le funzioni dirette del tasto.
Per le "seconde funzioni"  al codice ascii (diretto) aggiungo 27.

così ho la seguente tabella:








codice
descrizione
codice
2 F DESCRIZIONE
49             1 1
76
sin seno di x
50             2 2
77
tan tangente x
51             3 3
78
cos coseno x
43               “ +”        SOMMA
70
“ x” MOLTIPLICAZIONE
52             4 4
79
SQRT radice quadrata
53             5 5
80
Y^x Y elavato alla x
54             6 6
81
CHS cambiosegno x
45             “-” SOTTRAZIONE
72
“ / “ DIVISIONE
55             7 7
82
STO sto nn memorizza x
56             8 8
83
RCL rcl nn richiama nn in x
57             9 9
84
FIX decimali visualizzati
62            
   F2 seconda fun
89
F2 ***********
61             “ = “       ENTER
88
LASTX recupera x
48             0 0
75
X;Y scambio x con y
46             “ . “   PUNTO
73
R! ruota in giu catasta
60             “del “ cancella VISORE
87
XEQ esegue funzione nn









Lo sketch esegue la funzione (diretta) per i codici che si formano con la pressione del tasto che vanno da 49 a 61; quando viene premuto il tasto F2 (codice 62) (nella foto sotto il tasto con la lampadina!!) lo sketch aggiunge 27 ai codici quindi si ha una seconda serie di codici da 76 a 87, questi codici eseguono le seconde funzioni.

Il codice 87 esegue la sub che legge il numero funzione/o programma da eseguire e lo attiva.

In questo modo si possono aggiungere moltissime funzioni senza ulteriori tasti, qui sotto le funzioni che ho introdotto.

Per eseguire queste funzioni occorre inserire in catasta i valori richiesti dalla funzione, poi inserire nel visore il numero della funzione ed infine premere 2F e XEQ.
La funzione o il programma vengono eseguiti ed i risultati si troveranno in catasta.






//******************************************************************************
// -------------------------------------------------------------------------------
// 1 -  arcoseno di x inserire in x il valore seno -- in x anglo alfa in RADIANTI
// 2 -  arcotangente di x inserire in x il valore tangente --- in x anglo alfa in RADIANTI
// 3 -  arcocoseno di x inserire in x il valore coseno --; in x anglo alfa in RADIANTI
// 4 - da SESSAGESIMALI A sessadecimali
// 5 - da sessadecimali a SESSAGESIMALI
// 6 - RESTITUISCE PI - GRECO IN X
// 7 - da radianti a SESSAGESIMALI
// 8 - DA SESSAGESIMALI a radianti
// 9 - CLR cancella catasta e visore
//-------------------
// 10 - R-P
// da rettangolari a polari insere in x la coordinata x ed in y la cooordinata y
// restituisce in y la distanza
// e restituisce in x l'angolo alfa in RADIANTI
//
//----------------
// 11 - P-;R
// da polari a rettangolari inserire in x l'angolo alfa
// in RADIANTI
// restituisce le cordinate in x e y
// --------------------------
// 12 - CLRM cancella memorie utente da 1 a 9
// 13 - notazione scientifica ON - OFF
// 14 - INPUT notazione scientifica in y il numero nella forma n.nnnnn (mantissa)
//      in x l'esponente in base 10 del numero
//   poi premere 14 in visore e quindi 2F ; XEQ
// ----------------------------------------------------
// 15 - LN logaritmo naturale in base e
// 16 - e^x Antilogaritmo naturale
// 17 - LOG10 logaritmo in base 10
// 18 - 10^x - potenza di 10 alla x
// 19 - Fattoriale max n = 30
// 20 - da RADIANTI a centesimali
// 21 - da centesimali a RADIANTI
//**********************************************

A titolo di esempio ho scritto alcuni piccoli programmi che si possono lanciare con questa procedura.

//**********************************************
//    programmi
//**********************************************
// 22 - Carnot soluzione triangolo 2 lati e angolo compreso
//       in x angolo in RADIANTI;  in output avremo il lato c
//       in y lato b                
//       in z lato a
//-------------------------------------------------------
// 23 - Superficie triangolo con tre lati Erone
// 24 - Partitore di tensione
// 25 - parallelo resistenze
// 26 - scorporo IVA
//
//

lo sketch 

*/
//***************************************
// librerie incluse
//---------------------------------------
// E' inclusa la -maht.h-
#include -Wire.h-
#include -LiquidCrystal_I2C.h-
#include -Keypad.h-


dopo aver incluso le librerie si dichiarano variabili e costanti


//********************************************************************
const byte righe = 4;   // per keypad
const byte colonne = 4;
//********************************************************************
char key; // contiene il codice tasto premuto
int codice =0; // codice operativo calcolato a partire da key (codice asccii)
int poscifra = 0;// tiene conto delle cifre
boolean stato = false; // questa per attivare o disattivare la seconda funzione tasti
boolean sciee = false; // true visualizza in notazione scientifica
//-----------------------------------------------------------------
float k1 = 10000000;// numero massimo visualizzabile poi si passa in visualizz scie
float k0 = 0.00001; // numero decimale piu piccolo visualizzabile
// per l'inserimento dei numeri decimali
int pdec = 0; // punto decimale
int ndec =0;  // conta decimali
int fix = 4; //decimali di default



Per il tastierino la libreria Keypad risolve con facilità il suo utilizzo.

//*************************************************************************
// codici tasierino   mappa dei tasti
//*************************************************************************
char chiave [colonne][righe] =
{
  {49,50,51,43},    // 1   2   3  +
  {52,53,54,45},    // 4   5   6  -
  {55,56,57,62},    // 7   8   9  2F
  {61,48,46,60}     // En  0   .  del

};
//---------------------------------------------------------------
//                   pin assegnati al tastierino
//---------------------------------------------------------------
byte pinrighe[righe] = {4,5,6,7};
byte pincolonne[colonne] = {0,1,2,3};

// inizializza keypad e lcd

Keypad keypad = Keypad (makeKeymap(chiave),pinrighe,pincolonne,righe,colonne);

LiquidCrystal_I2C lcd(0x3F,16,2);

 //**********************************************

qui sotto ho dichiarato alcune variabili globali:


 //**********************************************
 //*** registri catasta
 double regx = 0.0;
 double regy = 0.0;
 double regz = 0.0;
 double regt = 0.0;
 // ****registri speciali
 double regxs = 0.0; // per visualizzare la parte decimale della notazione sci
 int esponente = 0; // esponente nella scientifica
 double visore = 0.0; // accumula i valori immessi
 double lastx = 0.0; // recupero del registro x

 //***********************
 //   memorie utente
 //***********************
    double mem1 = 0.0;
    double mem2 = 0.0;
    double mem3 = 0.0;
    double mem4 = 0.0;
    double mem5 = 0.0;
    double mem6 = 0.0;
    double mem7 = 0.0;
    double mem8 = 0.0;
    double mem9 = 0.0;
 //***********************

 Le varie sub sono di tipo void ed aggiornano o cambiano le variabili di catasta.
Le mem1 - mem9 sono memorie a disposizione dell'utente per inserire dati intermedi o dati da richiamare con funzioni o programmi aggiuntivi. (volendo se ne possono aggiungere altre, modificando lo sketch.

I registri catasta sono utilizzati per tutti i calcoli e per input output delle varie funzioni
i registri speciali sono:
regxs  uso questo registro per visualizzare la mantissa dei numeri visualizzati in modalità SCI,
Il numero rimane comunque nel registro x ( regx) ed è quello che viene effettivamente utilizzato per i calcoli, int esponente  serve a visualizzare l'esponente della notazione SCI

Il registro visore serve per immettere i valori da utilizzare ma non viene coinvolto nelle funzioni di calcolo, serve inoltre per passare il dato alle funzioni FIX, STO, RCL, XEQ che hanno bisogno di un dato numerico.
In ogni caso descriverò ogni funzione in dettaglio.

Il setup serve a visualizzare la versione dello Sketch ( questo serve se si aggiungono funzioni o si sostituiscono o modificano quelle esistenti), a sapere con che versione si sta lavorando.
 Basterà aggiornare la riga evidenziata in blu nel vostro sketch.

void setup() {
 //INIZIALIZZAZIONE
 lcd.init();  // initialize the lcd
 lcd.clear();
  // Print a message to the LCD.
  lcd.backlight();
  lcd.setCursor(0,0);
  lcd.print("calcolatrice RPN");
  lcd.setCursor(0,1);
  lcd.print("v.300817-207");
  delay (3000);
  lcd.clear();
}

Il loop dello sketch è molto semplice:

Si aggiorna il display.

Poi si entra nel ciclo while in attesa della pressione del tasto.

Quindi si esegue le funzioni richieste (dirette o seconde funzioni), infine si torna al ciclo.



//**************************************************************
//**************************************************************
void loop()
{

aggiornadisplay(); // sub che aggiona il display

// se abbiamo un codice 61 ENTER si esegue
if (codice == 61)
   { enter();}

key = 0;  // azzera variabile tasto del tasterino e
//************* attende la pressione di un tasto sul tastierino
 while (key == 0)   // rimane qui fino alla pressione di un tasto
 {
  key = keypad.getKey();
  codice = key;
 }
//-------------------------------------------------------------

// ****si controlla lo stato della calcolatrice
//  che può essere  funzioni dirette o seconde funzioni

if (stato == true)
 { // siamo in 2F )
   funzioni_seconde();
 }
if (stato == false)
 {// siamo nelle funzioni dirette
   funzioni_dirette();
 
  }


}
//**** END LOOP *******************************************************
//*******************************************************************

Il restante sketch esegue le funzioni richiamate dai codici sopra indicati.

void aggiornadisplay()

Questa funzione aggiorna il display, si utilizzano 2 righe nella prima riga si visualizza il registro x (regx), viene fatto il controllo se siamo in notazione scientifica SCI (in questo caso si visualizza regxs e esponente) in modo da rappresentare numeri molto grandi o molto piccoli.

Nella seconda riga si visualizzano i dati inseriti da tastiera registro VISORE preceduto da 1: per le funzioni dirette e 2: quando è stato premuto il tasto 2F (seconda funzione).
//******************************************

void aggiornadisplay()
{
  //***************
  // mostra display
  //---------------
// si esegue il controllo se visualizzare in notazione sci o con fix
double testx = regx;
if (testx < 0) testx = testx*-1;

if (testx > k1) sciee = true;
if (testx < k0) sciee = true;
if (testx == 0) sciee = false;



lcd.clear();
lcd.setCursor(0,0);
lcd.print("X:");
lcd.setCursor(4,0);

if (sciee == true)
   {
     sci(); // sub per notazione scientifica
     lcd.print(regxs,5);
     lcd.setCursor(14,0);
     lcd.print (esponente);
   }
 
    else lcd.print(regx,fix); // visualizzazione normale
 
lcd.setCursor(0,1);
if (stato == false){lcd.print("1:");}
if (stato == true) {lcd.print("2:");}
lcd.setCursor(4,1);
lcd.print(visore,fix);
sciee = false;
//------------------
}


La sub qui sotto serve per la notazione scientifica



// questa sub prepara "regxs" ed "esponente" per visualizzare in notazione sci
// ATTENZIONE regxs serve solo per la visualizzazione di numeri in notazione
// scientifica in abbinamento al registro "esponente"
// non coinvolgere direttamente nei calcoli i due rappresentano comunque
// il contenuto di "regx" che deve essere utilizzato per il calcolo.

void sci()
{
    lastx = regx;
    double numero = regx;
    int segno = 1;
    int segnoe = 1;
    esponente = 0;
 
    // se il numero è negativo si trasforma in positivo
    // ma si mette a -1 la variabile segno, ci servirà
    // per ritornare a negativo dopo aver trovato
    // il valore dell'esponte con la log10(numero)
    if (numero < 0) {numero = numero *-1; segno = -1;}
 
    double numlog = log10(numero); // si ottiene il logaritmo del numero
                                   // N,xxxxx preleveremo la parte
                                   // intera che rappresenta l'esponente
     esponente = int( numlog);   // adesso abbiamo il numero intero esponente
     numero = numero*segno;  // si ripristina il giusto segno
   
   // si esegue il controllo se l'esponente è negativo e si
   //esegue la stessa  procedura fatta per il numero
   if (esponente <0 esponente="esponente" segnoe="-1;}</p">
 //-----------------------------------------------------------------------
         // se segnoe è negativo il numero è molto piccolo
     if (segnoe == -1){regxs = numero * pow(10,esponente);}
        else regxs = numero / pow(10,esponente); //altrimenti numero molto grande
 //------------------------------------------------------------------------
    esponente = esponente * segnoe; // si ripristina il giusto segno
                                    // all'esponente
}

//***************************


Adesso si selezionano le funzioni dirette, in questo caso ci sono da considerare  i codici relativi alle cifre da 48 a 57 in questo caso significa che si intende immettere una cifra e quindi si deve trattare con la funzione impostanumero che accumulerà le cifre fino a completare l'immissione con enter o per raggiunta dimensione visualizzabile. (stesso concetto per i numeri decimali, se è stato premuto il punto decimale)

I restanti codici sono commentati ed è facile capire la loro funzione.

//***************************
// FUNZIONI DIRETTE
// SELEZIONA LA FUNZIONE
//***************************
void funzioni_dirette()
{
      if (pdec == 0)   // si deve scegliere fra numeri e numeri decimali
          {
           if ((codice  >= 48) && (codice <= 57 ))
               {impostanumero();}
          }      
      if (pdec == 1)  // è stato premuto il punto decimali
          {
           if ((codice  >= 48) && (codice <= 57 ))
               {impostanumerodec();}
          }    

  // il codice è relativo ad una funzione oppure è stato attivato il tasto 2F
  // per attivare le seconde funzioni
  //seleziona la funzione la invia alla sub che la esegue e quindi ritorna
  //
        if (codice == 43)// somma
            {somma();}
           
         if (codice == 45) //sottrazione
             {sottrazione();}
           
         if (codice ==  46) // punto decimali
              {punto();}  // con questa si pone a 1 la pdec
           
         if (codice ==  60)//cancella carattere
               {del(); }
             
         if (codice ==  61)// ENTER
             {enter();}
             
         if (codice ==  62) //seconda funzione 2f
             { stato = true;} // cambia stato
           
  return;
}
//*********************************************

La scelta delle seconde funzioni è più lineare in quanto non ci sono le cifre immesse per i calcoli.
Sono tutte indicate esplicitamente, le varie funzioni come già detto agiscono sui registri della catasta.
Casi particolari sono 84 fix n decimali, 83 rcl n , 82 sto n. Per queste si inserisce la cifra nel visore e successivamente si attiva la funzione.
es : 5 in visore, premere 2f, poi il 9 (in questo modo si forma il codice 84 ) che attiverà 5 decimali dopo la virgola.
in ogni caso rivedremo questi passaggi per ogni funzione.

Anche per la funzione codice 87 XEQ nn si procede con lo stesso sistema ma prima si devono porre in catasta i valori che la funzione deve utilizzare, poi impostare in visore il numero della funzione e quindi premere 2f ed infine XEQ, la calcolatrice eseguirà la funzione o il programma inserendo in catasta i risultati.

//*************************************
// FUNZIONI SECONDE  SCELTA FUNZIONE
//*************************************
void funzioni_seconde()
{
  stato = false; // rimette false per tornare alle funzioni dirette
  int codiceF2 = codice + 27;    
   //esegue una della funzioni F2 seconde    
       
        if (codiceF2 == 89)// non fa nulla
            {}
     
        if (codiceF2 == 70)// moltiplicazione
            {moltiplicazione();}
           
         if (codiceF2 == 72) //divisione
             {divisione();}
                   
                         //-----------------------------------------
         if (codiceF2 ==  87) // Xeq esegue funzione da 1 a ...
              {Xeq_x();} // questa esegue una delle funzioni richiamabili
                         // con una o due cifre da 1 a 26 (attualmente)
                         // ma espandibile ...
                         // si possono scrivere piccoli programmi
                         // che si richiamano con il relativo numero
                         // ----------------------------------------
           
         if (codiceF2 ==  88)//Lastx ( recupera x )
               {last_x(); }
             
         if (codiceF2 ==  75)//  scambio x con y
             {scambio();}
             
         if (codiceF2 ==  73) // R! scorre catasta
              { ruota(); }
           
          if (codiceF2 == 81) //cambia segno (moltiplica x per -1)
             {cambiasegno();}
           
         if (codiceF2 ==  76) // seno di x angolo in RADIANTI
              {lastx = regx;  regx = sin (regx);}
           
         if (codiceF2 ==  77)//tangente  x  angolo in x in RADIANTI
             {  lastx = regx; regx = tan (regx);}
             
         if (codiceF2 ==  78)// coseno  x  angolo in x in RADIANTI
             {  lastx = regx; regx = cos (regx);}
             
         if (codiceF2 ==  79) //radice quadrata
              { lastx = regx; regx = sqrt (regx);}
           
           
         if (codiceF2 ==  80)
         // potenza eleva y alla x
         //pow(base, exponent)
         //base: numero (tipo float)
        //exponent: la potenza a cui è elevata la base (tipo float)
        // si utilizza x ed y della catasta
          { lastx = regx; regx = pow (regy, regx); }
           
           
         if (codiceF2 ==  84)//fix decimali
               {visfix(); }
             
         if (codiceF2 ==  82)// STO n
             {sto_n();}
             
         if (codiceF2 ==  83) //RCL n
              {rcl_n(); }  
          codice = 0;
          visore = 0;        
     return;          
}

Dopo questo rimangono da spiegare le varie funzioni richiamate.

Alcune sono semplicissime e già previste nella libreria maht.h di arduino si passa loro i valori dalla catasta ed in catasta ritroviamo i risultati. 
Altre sono piccole procedure eseguite utilizzando comunque la libreria matematica.

Particolare è la imposta numero che serve per avere un valore numerico dalla pressione di tasti cifra.
//*********************************************
// esegue le funzioni dirette
//*********************************************

// parte intera di un numero si scrive su visore
void impostanumero()
{
  poscifra = poscifra +1;
  if (poscifra <  9)
   {int cifra =  codice - 48;
    visore = visore * 10 + cifra;
   }
    else { codice = 61;}
}
//*********************************************
// si scrive su visore il numero decimale
void impostanumerodec()
{
   ndec = ndec+1;
  if (fix >= ndec)
  {
   float cifradec = (codice - 48.0);
      if (ndec == 1) {visore = visore  + (cifradec /10);}
      if (ndec == 2){visore = visore  +  (cifradec /100);}
      if (ndec == 3){visore = visore  +  (cifradec /1000);}
      if (ndec == 4){visore = visore  + (cifradec /10000);}
      if (ndec == 5){visore = visore  + (cifradec /100000);}    
 }
   else { codice = 61;}
     
}


//----------------------------------------------------------
Queste due funzioni trasformano le singole cifre nel valore numerico che si sta impostando.
es: vogliamo inserire il numero 123 ; si preme 1 codice 49 - 48 = 1 quindi in visore avremo visore*10 = 0+1 = 1 pressione successiva 2 codice 50-48 = 2 e quindi avremo visore = visore*10+2 = 1*10+2 = 12; pressione successiva 3 codice 51-48 = 3 e quindi avremo 12*10+3 = 123
 che appunto è il numero che volevamo inserire.
Per le cifre decimali si procede in modo simile ma dividendo per 10,100,1000 ecc la cifra da aggiungere.

Queste sono  due funzioni  particolari per il resto è molto semplice nello sketch sono tutte commentate .

Vediamo alcune funzioni.

Qui sotto le 4 operazioni ogni operando come prima cosa salva il contenuto di regx nel registro lastx
Successivamente esegue l'operazione ponendo  il risultato in x.
quindi scende la catasta in regy scende regz, ed in regz scende regt.
Io poi eseguo del che rimette a zero il visore (questo perché altrimenti avremmo due righe con la stessa cifra e la cosa può creare confusione)
Per la divisione si fa un controllo che non sia una divisione per 0.

//----------------------------------------------------------
// operandi
// somma
void somma()
{
  // somma il contenuto di x con y e lo pone in x scorre la catasta
  lastx = regx;
  regx = (regx + regy);
  regy = regz;
  regz = regt;
  del();
  }

// sottrazione
void  sottrazione()
{
 // sottrae x da y
  lastx = regx;
  regx = (regy - regx);
  regy = regz;
  regz = regt;
  del();
}

// moltiplicazione
       void moltiplicazione()
        {
          lastx = regx;       // prima salva in lastx il valore di x      
          regx = (regy * regx); // esegue la moltiplicazione
          regy = regz;        
          regz = regt;
          del();
        }

//divisione
         void divisione()
          {
            lastx = regx;            // prima salva in lastx il valore di x
            if (regx == 0) return;   //******* divisione per 0
            regx = (regy / regx);      // esegue la divisione
            regy = regz;              // abbassa la catasta
            regz = regt;
            del();    

        }   

//--------------------------------------------------

Queste funzioni agiscono sulla catasta operativa ed hanno molta utilità
La Enter fa salire la catasta copiando in t la z, in z la y, in y il regx, in regx il visore, viene conservato in lastx il regx.
Dopo questa fase di salita della catasta azzero il visore.

        // --  ENTER
       void enter()
       {
          regt = regz;
          regz = regy;
          regy = regx;
          regx = visore;
          lastx = regx;
       // prima sale la catasta
       // poi azzera
        del();
      }

Lastx recupera il registro x dopo che è stato cambiato da una funzione.
Prima si fa salire la catasta in t la z, in z la y, in y l'attuale x, e quindi si riporta in in x il precedente x che abbiamo conservato nel registro lastx.
Questa funzione è molto utile in caso di errori, ma anche per recuperare un valore da utilizzare.

         //Lastx
          void last_x()
          { regt = regz;
            regz = regy;
            regy = regx;
            regx = lastx;
          }

Queste due funzioni servono per cambiare l'ordine della catasta; la scambio x-y coinvolge solo i due registri scambiandone il contenuto. La Ruota (giù) fa scorrere in giù la catasta in x mette y, in y va z, in z va t, ed infine in t va regx. Ad ogni pressione si ripete fino a ritornare nella posizione originaria.
Nella HP-41 esiste anche la funzione Ruota (su) che non ho realizzato del tutto analoga ma con rotazione contraria.
       
         //  x<>y scambio
          void scambio()
          {
            double scambio = regx;
            regx = regy;
            regy = scambio;
        }  
         //ruota giu la catasta
           void ruota()
          {
            double ruota = regx;
            regx = regy;
            regy = regz;
            regz = regt;
            regt = ruota;
        }

La funzione 80 eleva y alla x 
         //pow(base, exponent)
         //base: numero (tipo float)
        //exponent: la potenza a cui è elevata la base (tipo float)
        // si utilizza x ed y della catasta
          { lastx = regx; regx = pow (regy, regx); }




Utilizzo delle memorie utente

Le sub STO n e RCL n sono utilizzabili per memorizzare dati intermedi o risultati o per calcoli con numeri che si ripetono spesso, possono essere utilizzate come input-output in funzioni o programmi scritti nel caso che i registri della catasta non siano sufficienti.

L'utilizzo è semplicissimo:
Si inserisce in x il valore da memorizzare con enter, poi si scrive in visore il registro (da 1 a 9) ma è possibile aumentarli.
Quindi si preme 2F e STO (tasto 7).

Per richiamare in x il contenuto di una memoria semplicemente in visore si scrive il numero della memoria poi si preme 2F e RCL (tasto 8), il contenuto della memoria viene posto in x.


//-------------------------------------------------------------------      
        // STO n  SUB PER MEMORIZZARE IL CONTENUTO DI X
         //NEL REGISTRO INDICATO IN VISORE  DA 1 A 9
         // MA SE OCCORRE SI PUO' AUMENTARE LE MEMORIE UTENTE
         // IN QUEL CASO OCCORRE VARIARE ANCHE LA SUB RCL n
         // E LA SUB CHE CANCELLA IL CONTENUTO MEMORIE UTENTE
         // CIOE LA 12 cancella_mem
       
             void sto_n()
           {
             int mem = visore;
             if (( mem < 1 )||(mem > 9)) return;
           
              switch (mem)
                       {
                         case 1:
                            mem1 = regx;
                            break;
                          case 2:
                             mem2 = regx;
                          break;
                          case 3:
                              mem3 = regx;
                          break;
                          case 4:
                             mem4 = regx;
                          break;
                          case 5:
                             mem5 = regx;
                          break;
                            case 6:
                            mem6 = regx;
                            break;
                          case 7:
                             mem7 = regx;
                          break;
                          case 8:
                              mem8 = regx;
                          break;
                          case 9:
                             mem9 = regx;
                          break;
                       }              
            } // fine void sto_n
      //-------------------------------------------------------------------------    

          // richiama la memoria utente indicata in visore e pone il contenuto in x      
          //RCL n
             void rcl_n()  
           {
             int mem = visore;
             if (( mem < 1 )||(mem > 9)) return;
           
             
                switch (mem)
                       {
                         case 1:
                           {lastx = regx; regx = mem1;}
                          break;
                          case 2:
                             {lastx = regx; regx = mem2;}
                          break;
                          case 3:
                              {lastx = regx; regx = mem3;}
                          break;
                          case 4:
                              {lastx = regx; regx = mem4;}
                          break;
                          case 5:
                              {lastx = regx; regx = mem5;}
                          break;
                       
                          case 6:
                           {lastx = regx; regx = mem6;}
                          break;
                          case 7:
                             {lastx = regx; regx = mem7;}
                          break;
                          case 8:
                              {lastx = regx; regx = mem8;}
                          break;
                          case 9:
                              {lastx = regx; regx = mem9;}
                          break;
                      }
        }


//*****************************************************

La funzione XEQ nn

Questa funzione è determinante per espandere e potenziare la calcolatrice.
In questa versione ho predisposto di chiamare 25 funzioni da 1 a 26 ma è 
possibile espandere questo numero.
Le funzioni predisposte sono da 1 a 21 ed alcune sono molto semplici non hanno
bisogno di commenti:

da 1 a 3 arco seno di x, arco tangente di x, arcoseno di x, restituiscono in x l'angolo
relativo al valore trovato in x l'angolo è espresso in RADIANTI, si utilizza semplicemente
le funzioni della libreria. In Lastx si conserva il valore di partenza.

4 e 5 converte angoli sesagesimali in sessadecimali e viceversa

6 richiama la costante PI (pigreco) anche questa nella libreria.

7 e 8 converte angoli da RADIANTI a sessagesimali e viceversa.

9   cancella i registri catasta e visore, cancella anche lastx.

Queste funzioni usano due registi per input e output ( x , y).

10   da rettangolari a polari inserire in x la coordinata x, ed in y la coordinata y.
           restituisce in y la distanza 
          restituisce in x angolo in RADIANTI

11   da polari a rettangolari inserire in x l'angolo alfa  in RADIANTI
             inserire in y la magnitudine o distanza.
             restituisce le coordinate in x e y.

12   cancella memorie utente (tutte) non ha bisogno di input.

13   attiva o disattiva la notazione scientifica (ma se un numero è troppo grande
       o troppo piccolo per essere visualizzato cambia automaticamente).

14   EEX entrata con l'esponente, per l'input di numeri con mantissa ed esponente
       introdurre la mantissa in y e l'esponente in x.

15 e 16 logaritmo naturale ed  e^x.

17 e 18 logaritmo in base 10 ed 10^x.

19     fattoriale di x ( x numero intero da 1 a 30 MAX), restituisce in x il fattoriale.

20 e 21  da RADIANTI a centesimali e viceversa.
-------------

In questo sketch ho aggiunto alcuni semplici programmi a titolo di esempio. (da 22 a 26)

I programmi si richiamano dopo aver impostato nei registri di catasta i valori in input, si richiama quindi il programma che restituirà in catasta i risultati.

Nei programmi qui sotto io ho utilizzato solo i registri di catasta ma per input e/o per output si possono utilizzare nella stessa modalità le memorie utente da 1 a 9.

22   Soluzione triangolo con il teorema di Carnot, si conoscono due lati e l'angolo compreso
       la soluzione trova la misura del lato opposto all'angolo.
        porre in regz  uno dei lati conosciuti
                  in regy  il secondo lato conosciuto
                  in  regx angolo compreso fra i due lati in radianti
       in uscita avremo: 
                                 in regx troviamo il lato cercato opposto all'anglo compreso
                                    regy = lato noto
                                    regz =  altro lato noto
                                   regt =  angolo noto  in radianti 

23   Soluzione triangolo con teorema di Erone.
        Si calcola la  superficie del triangolo  noti i tre lati  in x lato a, in y lato b, in z lato c
       restituisce in x la superficie, in y,z, t i lati a,b,c.

24     Partitore di tensione
        Si calcola la ripartizione delle tensioni ai capi delle resistenze
        si devono inserire almeno due valori di  resistenza r1, r2, se c'e un terzo valore inserire r3 altrimenti 0 zero, inserire la Vin. Per la soluzione si applica la formula Vn = Vin*(rn/(r1+r2+r3))
     inserire
            regy; // inserire valore R1 in omm
            regz; // inserire valore R2 in omm
            regt; // inserire valore R3 se non serve inserire 0
            regx;// inserire Vin in Volt
in uscita avremo:
          regx = v1;  // Volt in v1
         regy = v2;  // Volt in v2
         regz = v3;  // Volt in v3
         regt = 0;

25  PARALLELO RESISTORI   r1 -r2 - r3 - r4

     si inseriscono in x ed in y i valori di due resistori (MINIMO!!)
     se ci sono più resistori si inserisce in z il terzo ed in t il 4
    se il resistore non c'e inserire 0
    questo programma modifica tutta la catasta
    in uscita avremo in x la resistenza parallelo ed in y il numero delle 
   resistenze inserite

26   SCORPORO IVA
          impostare  in Y l'aliquota
         impostare  in X il totale compreso IVA

         in OUTPUT avremo:
          x = IVA, y = imponibile, z =il totale, t = aliquota.

        
//---------------------------------------------------------------------------------------
//
//
         // Xeq_n  --- esegue la funzione da 1 a 26
         //         --- è comunque possibile implementare funzioni o calcoli
         //         ---- e/o veri programmi che restituiscono valori in catasta
         //         ----  modificando questa sub e aggiungendo la sub da chiamare
         void Xeq_x()
         { int mem = visore;
            if (( mem < 1 )|| ( mem > 26)) return;
           
             switch (mem)
                {
                 case 1:
                        arcosen_x();
                        break;
                 case 2:
                         arcotan_x();
                        break;
                 case 3:
                        arcocos_x();
                        break;
                 case 4:
                        sess_sedec(); // converte da sessagesimali a sessadecimali
                        break;
                 case 5:
                        sedec_sessa(); // converte da sessadecimali a sessagesimali
                        break;
                 case 6:
                        { lastx = regx; regx = PI;}// richiama pigreco
                        break;
                 case 7:
                         {lastx = regx; regx = regx*180.0/PI; sedec_sessa();}
                                           // converte da radianti in sessagesimali
                        break;
                 case 8:
                         {lastx = regx; sess_sedec();regx = regx*PI/180.0;}
                                                // da gradi sessagesimali a radianti
                        break;
                 case 9:
                         cancella(); // cancella registri catasta e visore
                        break;
                 case 10:
                       R_P (); // da rettangolari a polari
                           
                        break;
                 case 11:
                        P_R(); // da polari a rettangolari p>=0 e alfa >=0 e <= pi/2
                        break;
                 case 12:
                        cancella_mem(); // cancella memerie utente
                        break;
                 case 13:
                        { if (sciee == false) sciee = true;
                            else sciee = false;}
                        break;
                 case 14:
                        inputsci();
                        break;
                 case 15:
                       // ln
                       {lastx = regx; regx = log(regx);}
                        break;
                     
                  case 16:
                       // exp
                       {lastx = regx; regx = exp(regx);}
                        break;
                     
                  case 17:
                        //Log10
                        {lastx = regx; regx = log10(regx);}
                        break;
                     
                   case 18:
                        //10alla x
                        {if (regx < 30)
                            {lastx = regx; regx = pow(10,regx);}
                         }
                        break;
                     
                     case 19:
                           // calcolo fattoriale di x max 30
                           fact();
                          break;
                    case 20:
                         // da radianti a centesimali
                         { lastx = regx; regx = regx*200.0/PI;}
                         break;
                     case 21:
                       //  da centesimali a radianti
                          { lastx = regx; regx = regx*PI/200.0;}
             
                         break;
                     case 22:
                          carnot(); //calcolo triangolo 2 lati angolo compreso
                          break;
                     case 23:
                          erone();  // superficie con tre lati
                          break;
                     case 24:
                          partitore(); //partitore di tensione
                         break;
                     case 25:
                          parallelo(); // resistenze in parallelo
                          break;
                     case 26:
                          sco_iva();   // corporo IVA
                          break;                  
                }  
         } // fine void XEQ
 //-------------------------------------------------------------------

Indice delle funzioni e loro uso:

----------------------------------------------------------------------
Funzioni dirette
----------------------------------------------------------------------
Somma, sottrazione, : Si introducono i due operandi in Y ed X quindi si preme il tasto relativo alla funzione, il risultato viene posto in X.

Enter: Introduce in x quanto è contenuto sul "visore" e fa salire il resto della catasta, quello che era in x sale in y, il contenuto di y sale in z, il contenuto di z sale in t.

Del  ( <-- b="">:  Cancella il contenuto del visore.

F2   Tasto seconda funzione abilita la seconda funzione.

----------------------------------------------------------------------------------
Funzioni seconde
----------------------------------------------------------------------------------
moltiplicazione, divisione: Si introducono i due operandi in Y ed X quindi si preme il tasto relativo alla funzione, il risultato viene posto in X

Sin, Tan, Cos : Restituiscono in X, il valore seno, tangente, coseno dell'angolo in Radianti contenuto                           in X.

Sqrt :  Esegue la radice quadrata del contenuto in X, pone il risultato in X.

Y^x :  Eleva a potenza , introdurre in Y il valore, in X l'esponente, il risultato è posto in X.

CHS :  Cambio segno, cambia il segno ad X.

STO:  Memorizza in un registro utente ( da 1 a 9) il contenuto di X, immettere in X il valore da memorizzare ( potrebbe anche essere il risultato di precedenti operazioni) poi nel visore scrivere il registro dove si vuole memorizzare (1-9) quindi premere il tasto funzione. Il contenuto di x rimane in x e viene duplicato nel registro indicato.

RCL: Richiama in X il contenuto del registro ( da 1 a 9), immettere nel visore il numero del registro e premere il tasto funzione, in X avremo il contenuto del registro richiesto, il registro rimane invariato, nel registro lastx viene prima salvato il contenuto precedente di X.

FIX:  Si possono impostare il numero dei decimali visualizzati ( da 0 a 5 ), scrivere in visore il numero da 0 a 5 e premere il tasto funzione. Di default ho posto a 4 i decimali.

lastx: Recupera in X il contenuto precedente ad una operazione, il contenuto di X viene spostato in Y.
Utile per recuperare in caso di operazioni errate.

X_Y: Scambio X con Y, Insieme alla rotazione della catasta si può cambiare l'ordine degli operandi in catasta.

R! :  Ruota giù, la catasta viene fatta ruotare y in x, z in y, t in z, x in t. Ad ogni pressione ruota fino a tornare nella situazione iniziale, utile per rivedere tutto il contenuto della catasta, ed eventualmente utilizzando lo scambio cambiarne la disposizione.

XEQ : Questa funzione richiama ed esegue funzioni o programmi, si scrive nel visore il numero della funzione e si preme il tasto XEQ, prima si dovrà immettere in catasta i valori richiesti dalla funzione e o programma rispettandone anche l'ordine. In uscita avremo la catasta aggiornata con i risulati.
Possono essere usati anche i registri utente che la funzione e/o programma possono utilizzare come input e/o come output.

------------------------------------------------------------------------------------------
Riporto qui per maggior chiarezza le funzioni richiamabili.

da 1 a 3 arco seno di x, arco tangente di x, arcoseno di x, restituiscono in x l'angolo
relativo al valore trovato in x l'angolo è espresso in RADIANTI, si utilizza semplicemente
le funzioni della libreria. In Lastx si conserva il valore di partenza.

4 e 5 converte angoli sesagesimali in sessadecimali e viceversa

richiama la costante PI (pigreco) anche questa nella libreria.

7 e 8 converte angoli da RADIANTI a sessagesimali e viceversa.

9   cancella i registri catasta e visore, cancella anche lastx.

Queste funzioni usano due registi per input e output ( x , y).

10   da rettangolari a polari inserire in x la coordinata x, ed in y la coordinata y.
           restituisce in y la distanza 
          restituisce in x angolo in RADIANTI

11   da polari a rettangolari inserire in x l'angolo alfa  in RADIANTI
             inserire in y la magnitudine o distanza.
             restituisce le coordinate in x e y.

12   cancella memorie utente (tutte) non ha bisogno di input.

13   attiva o disattiva la notazione scientifica (ma se un numero è troppo grande
       o troppo piccolo per essere visualizzato cambia automaticamente).

14   EEX entrata con l'esponente, per l'input di numeri con mantissa ed esponente
       introdurre la mantissa in y e l'esponente in x.

15 e 16 logaritmo naturale ed  e^x.

17 e 18 logaritmo in base 10 ed 10^x.

19     fattoriale di x ( x numero intero da 1 a 30 MAX), restituisce in x il fattoriale.

20 e 21  da RADIANTI a centesimali e viceversa.
-------------

In questo sketch ho aggiunto alcuni semplici programmi a titolo di esempio. (da 22 a 26)

I programmi si richiamano dopo aver impostato nei registri di catasta i valori in input, si richiama quindi il programma che restituirà in catasta i risultati.

Nei programmi qui sotto io ho utilizzato solo i registri di catasta ma per input e/o per output si possono utilizzare nella stessa modalità le memorie utente da 1 a 9.

22   Soluzione triangolo con il teorema di Carnot, si conoscono due lati e l'angolo compreso
       la soluzione trova la misura del lato opposto all'angolo.
        porre in regz  uno dei lati conosciuti
                  in regy  il secondo lato conosciuto
                  in  regx angolo compreso fra i due lati in radianti
       in uscita avremo: 
                                 in regx troviamo il lato cercato opposto all'anglo compreso
                                    regy = lato noto
                                    regz =  altro lato noto
                                   regt =  angolo noto  in radianti 

23   Soluzione triangolo con teorema di Erone.
        Si calcola la  superficie del triangolo  noti i tre lati  in x lato a, in y lato b, in z lato c
       restituisce in x la superficie, in y,z, t i lati a,b,c.

24     Partitore di tensione
        Si calcola la ripartizione delle tensioni ai capi delle resistenze
        si devono inserire almeno due valori di  resistenza r1, r2, se c'e un terzo valore inserire r3 altrimenti 0 zero, inserire la Vin. Per la soluzione si applica la formula Vn = Vin*(rn/(r1+r2+r3))
     inserire
            regy; // inserire valore R1 in omm
            regz; // inserire valore R2 in omm
            regt; // inserire valore R3 se non serve inserire 0
            regx;// inserire Vin in Volt
in uscita avremo:
          regx = v1;  // Volt in v1
         regy = v2;  // Volt in v2
         regz = v3;  // Volt in v3
         regt = 0;

25  PARALLELO RESISTORI   r1 -r2 - r3 - r4

     si inseriscono in x ed in y i valori di due resistori (MINIMO!!)
     se ci sono più resistori si inserisce in z il terzo ed in t il 4
    se il resistore non c'e inserire 0
    questo programma modifica tutta la catasta
    in uscita avremo in x la resistenza parallelo ed in y il numero delle 
   resistenze inserite

26   SCORPORO IVA
          impostare  in Y l'aliquota
         impostare  in X il totale compreso IVA

         in OUTPUT avremo:
          x = IVA, y = imponibile, z =il totale, t = aliquota.
----------------------------------------------------------------------------------------------------------

La calcolatrice proposta è praticamente programmabile in C++.

E' sufficiente preparare un piccolo programma e quindi inserirlo nello sketch con la normale USB di Arduino sovrascrivendo la precedente versione (ricordarsi di aggiornare la riga nel setup per sapere sempre che versione è presente sul micro)

I programmi sopra riportati sono solo un piccolo esempio ma la potenzialità e la memoria disponibile danno la possibilità di fare molto di più.

Per scrivere questi programmi o/e funzioni aggiuntive io uso questo metodo:

Ho predisposto su CodeBlocks uno schema tipo e provo il programma quando ho messo a punto la funzione / programma copio e con poche modifiche la inserisco come void "xxxxx"()

//***************************  LISTATO IN CODEBLOCKS   C++ *****************
using namespace std;
#include
#include
#include
#include
double regx = 0.0; // le quattro variabili della casta
double regy = 0.0;
double regz = 0.0;
double regt = 0.0;

// si potrebbero aggiungere se utili anche
 //***********************
 //   memorie utente
 //***********************
 //   double mem1 = 0.0;
 //   double mem2 = 0.0;
 //   double mem3 = 0.0;
 //   double mem4 = 0.0;
 //   double mem5 = 0.0;
 //   double mem6 = 0.0;
//    double mem7 = 0.0;
//    double mem8 = 0.0;
//    double mem9 = 0.0;
 //***********************
// utilizzando poi quelle che servono

int main()
{

    cout << "input valore in x" << endl;
    cin >> regx;
    cout << "input valore in y" << endl;
    cin >> regy;
    cout << "input valore in z" << endl;
    cin >> regz;
    cout << "input valore in t" << endl;
    cin >> regt;
//********************************************************************
//  calcolo superficie triangolo con ERONE
//********************************************************************
//     copiare da qui
//********************************************************************
if (regx >= (regy+regz)|| regy >= (regx+regz)|| regz >=(regx+regy))
        cout << " NON E' UN TRIANGOLO   " << endl;
    else {
            cout << "  E' UN TRIANGOLO   " << endl;
            double per = regx + regy + regz;
            double per2 = per/2;
            double super = sqrt(per2*((per2-regx)*(per2-regy)*(per2-regz)));

            regx = super;
            regy = per;
            regz = per2;
            regt = 1;

         }
//********************************************************************
//********************************************************************
//      fino a qui
//*********************************************************************

    cout << "output in x  " << endl;
    cout << regx << endl;
     cout << "output in y  " << endl;
    cout << regy << endl;
    cout << "output in z  " << endl;
    cout << regz << endl;
     cout << "output in t  " << endl;
    cout << regt << endl;

    return 0;
}

//***********************************************************************

In questo modo è possibile provare la funzione o programma fino al suo corretto funzionamento, dopo si sovrascrive lo sketch di Arduino una sola volta.

Logicamente si dovrà anche modificare la sub XEQ aggiungendo o sostituendo la funzione.

In ogni caso è possibile aggiungere e/o modificare funzioni, realizzando la propria calcolatrice su misura!

Nel video che ho pubblicato su YouTube descrivo vari passaggi per utilizzare la calcolatrice.




                 

 Scaricate lo sketch v. 207

Spero che questo lavoro sia piaciuto,

Sergio

  

Nessun commento:

Posta un commento

Vi ringrazio per la lettura e vi invito al prossimo post.
Se il post vi è stato utile, vi è piaciuto oppure no, scrivete un commento.

Un saluto a tutti.
Sergio

Copyright - Condizioni d’uso - Disclaimer
http://avventurarduino.blogspot.it/2012/10/inizia-lavventura-arduino-12-settembre.html