lunedì 30 gennaio 2023

Calcolatrice scientifica - Scientific calculator

 Calcolatrice RPN con 48 tasti



Si costruisce una calcolatrice migliorata rispetto a quella  realizzata nel 2017 che trovate su questo blog.







Calcolatrice RPN con Arduino - 
-  RPN Calculator with Arduino-
- 28/08/2017-


Questo progetto utilizza 48 tasti per l'input  ed un display a 4 righe x 20 in questo modo è più facile e divertente  utilizzare la calcolatrice.

Il prototipo da me realizzato è molto spartano ma ognuno di Voi potrà realizzare un contenitore migliore. E' possibile alimentazione con batteria.

Questo progetto è interessante per la sua possibilità di personalizzazione ed utilizzo di quasi tutte le schede della famiglia "Arduino".

Potrete personalizzare sia il contenitore che lo sketch aggiungendo funzioni e programmi . 


Materiale occorrente:

Arduino UNO  oppure altre schede come Mega 2560 ed altre.

3 tastierini da 16 tasti per formare una tastiera di 4 righe x 12 colonne

Display 4 righe 20 caratteri I2C 

Si può collegare anche un display 4x20 non I2C ( ma in questo caso bisogna usare il Mega perché su Arduino UNO non sarebbero sufficienti i pin)

Cambiando la scheda si dovranno fare poche modifiche allo schema ed allo sketch.



Caratteristiche di questa versione:

A _ Con la tastiera a 48 tasti molte funzioni sono eseguibili con la pressione di un tasto.

B _ Rimangono disponibili molti tasti con la possibilità di assegnare loro una                        SECONDA FUNZIONE.

C_ Il display con 4 righe permette di visualizzare i registri X, Y, Z e quindi                             maggior facilità dell'uso della catasta operativa.

D_ Lo sketch è predisposto per inserire nuove funzioni ed assegnarle ai tasti disponibili         come seconda funzione.

E_ Possibilità d'integrare funzioni o programmi da richiamare con XEQ nn, questi programmi o funzioni possono essere integrati e richiamabili come le funzioni della calcolatrice facendo uso della catasta o dei registri di memoria.

F_ Possibilità di alimentazione a batteria diventando portatile.



Questa versione NON supporta la programmazione (diretta).*

 Non supporta le funzioni rivolte ai pin di Arduino presenti nel progetto "ArduinoQuadro".

Ho quindi semplificato l'uso e reso semplice l'integrazione e l'aggiunta di programmi o funzioni per una personalizzazione completa.

Manca si la possibilità di programmarla direttamente ma vedremo come sia semplice preparare dei programmi da integrare nella calcolatrice, e richiamabili con XEQnn.



Qui sotto trovate due schemi di collegamento :

Schema con Arduino UNO



Schema con ATmega 2560





Come si vede lo schema di collegamento è molto semplice.

I tastierini hanno 8 pin ciascuno i 4 a sinistra identificano la colonna ed i 4 a destra identificano le righe.

Si collegano insieme le 4 righe di ogni tastierino e queste le mandiamo a 4 pin di Arduino

Nello schema righe (verde, blu, grigio, marrone).

Ogni colonna (12) invece la colleghiamo ad un pin di Arduino (colori rosa, porpora, arancione, giallo)

La pressione di un tasto individua la chiusura dell'incrocio RigaX, e ColonnaY, la libreria Keypad.h provvede a restituire nella variabile key il codice del tasto premuto.

Lo sketch è molto commentato e si possono comprendere i vari passaggi.

Si possono realizzare con altre schede della famiglia Arduino cambiando i collegamenti dei tastierini (righe e colonne), e cambiare nello sketch la sola parte che riguarda i pin a cui sono collegati i tastierini.

Qui sotto la porzione di sketch da modificare.



//-----------------------------------------------------------------------------
//           pin assegnati al tastierino per ARDUINO UNO
//-----------------------------------------------------------------------------
byte pinrighe[righe] = {14, 15, 16, 17};  // pin analogici A0, A1, A2, A3
byte pincolonne[colonne] = {13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2};

//------------------------------------------------------------------------------
//            pin assegnati al tastierino per ATMEGA 2560
//------------------------------------------------------------------------------
    byte pinrighe[righe] = {23, 25, 27, 29};
byte pincolonne[colonne] = {53, 51, 49, 47, 45, 43, 41, 39, 37, 35, 33, 31};
//------------------------------------------------------------------------------

Se utilizzate Arduino MEGA con lo schema sopra indicato sono valide le righe in rosso

e quindi potete commentare le altre.

Se utilizzate Arduino UNO  sono valide le righe blu e commentate le righe rosse.

In ogni caso per qualsiasi altra scheda utilizzata seguite questo metodo. 


ATTENZIONE il mio display ha questo indirizzo

LiquidCrystal_PCF8574 lcd(0x27);


Il Vostro LCD potrebbe avere altro indirizzo, controllate anche di includere la libreria del vostro lettore LCD, in qualche caso potrebbero essere necessarie delle modifiche nello sketch alle istruzioni che mostrano i dati.






Uso della calcolatrice.

Su questo stesso blog trovate  alcune prime indicazioni nel post 

Calcolatrice RPN con Arduino

Calcolatrice RPN

Sul Web trovate anche i manuali della HP41 a cui mi sono ispirato.


Qui trovate lo sketch ( riferito allo schema MEGA) ma contiene anche le righe per Arduino uno come indicato sopra da modificare.

Questo il risultato verifica con IDE 2 di Arduino per il Mega:

Lo sketch usa 22272 byte (8%) dello spazio disponibile per i programmi. Il massimo è 253952 byte.

Le variabili globali usano 962 byte (11%) di memoria dinamica, lasciando altri 7230 byte liberi per le variabili locali. Il massimo è 8192 byte.


Come potete vedere c'è spazio per modifiche ed aggiunte di funzioni.


Lo sketch si compone di più schede per poterlo leggere più agevolmente.

Scheda principale con il LOOP

 Qui ci sono le dichiarazioni, il setup, i pin utilizzati per il tastierino, le sub per l'inserimento dei dati e la chiamata alle funzioni. 

SCHEDA FUNZIONI DIRETTE E SECONDE
Qui trovate tutte le funzioni della calcolatrice dirette e con tasto 2F


SCHEDA XEQ-STO-RCL
 dedicata alle funzioni che vengono chiamate con indirizzo nn


SCHEDA PROG

Per i programmi da chiamare con XEQ (nn) numero programma, che potete integrare con i vostri programmi.


SCHEDA NOMI FUNZIONI


In questa trovate tutti i nomi funzioni che vengono visualizzati a destra sulla prima riga del LCD 
In questo sketch ho dato un tempo di 300 ms, potete cambiarlo o non visualizzare il nome funzione.





/* ****************************
   SERGIO PRENLELOUP
   08-05-2025
   versione v-101-48-080525

  --------------------------------------------------------------------------

#include <Vcc.h>


const float minVcc = 0.0;
const float maxVcc = 5.0;
const float fix = 1.0103; // 4.9/5.0

Vcc vcc(fix);

void setup() {
  Serial.begin(9600);

}

void loop() {
  float v = vcc.Read_Volts();
  Serial.print("V=");
  Serial.print(v);
  delay(1000);

  float p = vcc.Read_Perc(minVcc, maxVcc);
  Serial.print(" Perc=");
  Serial.println(p);
  delay(1000);
}





  Nuovo sketch calcolatrice RPN  NON programmabile.
 

  Modalita Diretta == si eseguono le funzioni assegnate ai tasti in modo diretto,
in modo simile all'uso della
                 HP-41  alcuni tasti hanno la seconda funzione.

      Si possono richiamare funzioni con XEQ nn  che si potranno aggiungere
con programmazione in C
      In questo modo anche questa calcolatrice è in pratica programmabile in "C"
     
  Questa calcolatrice utilizza 48 tasti che sono composti
da tre tastierini da 16 tasti.
  Si può realizzare anche con poche modifiche al listato una calcolatrice
a 32 tasti utilizzando 2 tastierini
 
  Il display ha 4 linee

                 Mostrano i registri di catasta X, Y , Z
                 la riga più in basso serve solo come
                 visualizzatore del dato introdotto.

  La calcolatrice si può utilizzare direttamente in modo simile alla HP-41
  Utilizzando catasta e registri di memoria.

         

  La catasta operativa.
  X, Y, Z, T, U,  lastX. ( in questa versione le lascio come variabili globali)

  Ci sono 19 registri di memoria utente possono essere usati direttamente o
  in programmi della funzione XEQnn (variabili globali).
  ********************************************************************************
****************************

  Si possono aggiungere funzioni o programmi che utilizzino sia la
 catasta e/o registri di memoria, questi programmi si possono
  aggiungere alle funzioni esistenti; per richiamarli basterà eseguire XEQ nn (01-99).

  //**********************************************************************************************************
  FUNZIONI PROGAMMABILI E RELATIVI CODICI.

  il codice è un byte ( quindi da 0 a 255)

  MEMORIE & INDICI = da 01 a 19   alla pressione delle istruzioni:

  STO; RCL; XEQ - si attiva una R nella sinistra del visore e si
introducono due cifre

  01 per memoria 1 ... fino a 19  ( funzioni STO e RCL )

  per la funzione XEQ da 01 fino a 40
  -----------------------------------------------------------------
-------------------------------------------
 CODICI TASTO FUNZIONI DIRETTE
 
  49-1, 50-2, 51-3,  52-4, 53-5, 54-6,  55-7, 56-8, 57-9,  48-0,
46-punto,   43 +,  45 -, 44-*, 47-/, 90 ENTER
  ----------------------------------------------------------------------
--------------------------------------
  58 SIN, 59 COS,  60 TAN,  61 ASIN ,  62 ACOS, 63 ATAN, 64 LOG,  65 (2F),
  66 STO, 67 PI,   68 SQRT, 69 FIX,    70 Y^x,  71 X^2,  72 LN,   73 R>P,
  74 RCL, 75 EEX,  76 CHS,  77 HMS,    78 RAD,  79 1/X,  80 e^X,  81 P>R,
  82 DEL, 83 X<>Y, 84 R\    85 LASTX,  86 DISP, 87 CLST, 88 10^x, 89 XEQ
 
 ****************************************************************************
************************************
  CON LA PRESSIONE DEL TASTO F2 (65) SI ATTIVANO LE SECONDE FUNZIONI
  A QUESTI CODICI SI AGGIUNGE +50 OTTENENDO COSI  CODICI DA 93 A 140 DISPONIBILI
  PER SECONDE FUNZIONI
  ATTIVATE  SOLO TRE SECONDE FUNZIONI IN QUESTA VERSIONE

 ***********************************************************************
*****************************************

  HARDWARE UTILIZZATO
 
  ARDUINO UNO
 
  una tastiera composta dall'assemblaggio di 3 tastierini 4x4, ottenendo
  così una tastiera 12 x 4 ( 48 tasti) 4 RIGHE X 12 COLONNE.
  Ai tasti verranno assegnate 2 o più funzioni.
 
  Display lcd 20x4 (I2C)
 
  Possibilità di alimentazione a batteria.
 *****************************************

 */
 //***************************************
 // librerie incluse

 //---------------------------------------
 // E' inclusa anche da sistema la <maht.h>
#include <Wire.h>
#include <LiquidCrystal_PCF8574.h>
#include <Keypad.h>
#include <Vcc.h>  // libreria controllo carica batteria


//***************************************************
 const byte righe = 4;   // per keypad
 const byte colonne = 12;
//***************************************************

//****************************************************
// codici tastierino  per 48 tasti
//***********************************************

byte chiave [righe][colonne] =
{ {49, 50, 51, 43, 58, 59, 60, 61, 62, 63, 64, 65}, //
  {52, 53, 54, 45, 66, 67, 68, 69, 70, 71, 72, 73}, //
  {55, 56, 57, 44, 74, 75, 76, 77, 78, 79, 80, 81}, //
  {90, 48, 46, 47, 82, 83, 84, 85, 86, 87, 88, 89}, //

};

//-----------------------------------------------------------------------------
//           pin assegnati al tastierino per ARDUINO UNO
//-----------------------------------------------------------------------------
//byte pinrighe[righe] = {14, 15, 16, 17};  // pin analogici A0, A1, A2, A3
//byte pincolonne[colonne] = {13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2};

//-----------------------------------------------------------------------
//            pin assegnati al tastierino per ATMEGA 2560
//--------------------------------------------------------------------------
byte pinrighe[righe] = {23, 25, 27, 29};
byte pincolonne[colonne] = {53, 51, 49, 47, 45, 43, 41, 39, 37, 35, 33, 31};
//------------------------------------------------------------------------------

// ------------------------------------------------------------------------
//  QUI SOTTO VARIABILI E COSTANTI
//
//*********************************************************************

const float minVcc = 0.0;
const float maxVcc = 5.0;
const float correzione =  4.8/5.0;  // 1.0103; // 4.9/5.0
Vcc vcc(correzione);

byte key; // contiene il codice tasto premuto
byte codice = 0; // codice operativo calcolato a partire da key (codice asccii)
int poscifra = 0;// tiene conto delle cifre
boolean sciee = false; // true visualizza in notazione scientifica
boolean stato = false; // per la calcolatrice ( seconda funzione dei tasti)
boolean dirette = true; //funzioni_dirette
boolean seconde = false; //funzioni_F2
boolean reg = false; // registri memoria (STOnn- RCLnn)

//------------------------------------------------------------------------
boolean se = true;  // per le funzion if
boolean xeq = true;  // per inserimento codice in Xeq_nn
boolean uscitacalc = true; // per uscire da caLCOLATRICE si mette a false
//-------------------------------------------------------------------------
float numero; // usata nella sci
float k1 = 10000000;// numero massimo visualizzabile poi si passa in 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
int numProg = 0; // indice numero programmi in XEQ

//*********************************************************************
// *******    V A R I A B I L I G L O B A L I  ************************
//*********************************************************************

//*** registri catasta
float lastx = 0.0; // recupero del registro x
float regx = 0.0;
float regy = 0.0;
float regz = 0.0;
float regt = 0.0;
float regu = 0.0;

// registri speciali
float regxs = 0.0; // per visualizzare la parte decimale della notazione sci
int esponente = 0; // esponente nella scientifica
float visore = 0.0; // accumula i valori immessi
//********************************************************************

//*******************************************************************
//          STRINGHE   caratteri custom
//********************************************************************


  String nomeProg = "";
 //********************************************************************
 // caratteri batteria carica - scarica
 //********************************************************************

  byte batteriaScarica[8] = {
  0b01110,
  0b10001,
  0b10001,
  0b10001,
  0b11001,
  0b11101,
  0b11111,
  0b11111
};

byte batteriaCarica[8] = {
  0b01110,
  0b11111,
  0b11111,
  0b11111,
  0b11111,
  0b11111,
  0b11111,
  0b11111
};
//----------------------------

//***********************
//   memorie utente
//***********************
//--------------------------

float mem1 = 0.0;
float mem2 = 0.0;
float mem3 = 0.0;
float mem4 = 0.0;
float mem5 = 0.0;
float mem6 = 0.0;
float mem7 = 0.0;
float mem8 = 0.0;
float mem9 = 0.0;
float mem10 = 0.0;
float mem11 = 0.0;
float mem12 = 0.0;
float mem13 = 0.0;
float mem14 = 0.0;
float mem15 = 0.0;
float mem16 = 0.0;
float mem17 = 0.0;
float mem18 = 0.0;
float mem19 = 0.0;
//***********************

// inizializza keypad e lcd
//--------------------------------------------------------------------------------
Keypad keypad = Keypad (makeKeymap(chiave), pinrighe, pincolonne, righe, colonne);

LiquidCrystal_PCF8574 lcd(0x27);
//--------------------------------------------------------------------------------


void setup()
{
  Wire.begin();
  Wire.beginTransmission(0x27);
  lcd.begin(20, 4); // initialize the lcd
  lcd.setBacklight(255);
   // creazione nuovi caratteri
  lcd.createChar(0, batteriaScarica);
  lcd.createChar(1, batteriaCarica);
  lcd.home();
  lcd.clear();
 
  lcd.setCursor(0, 1);
//lcd.print("1234567890123456");
  lcd.print("v-506-48-080525"); // VERSIONE
  lcd.setCursor(0, 2);
//lcd.print("1234567890123456");
  lcd.print("Calcolatrice RPN");
 
  delay (3000);

}


//-----------------------------------------------------------------------
//    LOOP PRINCIPALE
//---------------------------------------------------------------------


void loop()
{
   calcolatrice();
}

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

//*******************************************************************
//  **********    F U N Z I O N I     **********
//*******************************************************************

void calcolatrice() // questa è un loop per utilizzare come calcolatrice
{
  uscitacalc = false;
  dirette = true;
 
  while (uscitacalc == false)
  {
   

    aggiornadisplay(); // sub che aggiorna il display


    tasto(); // attende pressione tasto

    tastiFunzione(); // si controlla se funzioni dirette o seconde funzioni

 

    if (dirette == true)funzioni();//funzioni dirette

    if (seconde == true) //  seconde funzioni 2F
    {
      codice = codice + 50;
      seconde_Funzioni();
    }

   
   
   }
}
//***************** fine calcolatrice ******************************

// con questa si controlla la seconda funzione
//  (2F 65) se premuto attiva se già attive disattiva
void tastiFunzione()
{
  if ( codice == 65) // F2 seconde funzioni
  {
    if (seconde == true)
    { seconde = false;
      dirette = true;
    }
    else
    {
      seconde = true;
      dirette = false;  
    }
  }  
}
//-----------------------------------------------------------
// qui si controlla il codice
// del tasto premuto e si indirizza l'esecuzione
// della relativa funzione e quindi si ritorna.
// queste funzioni sono per l'uso diretto della calcolatrice
//------------------------------------------------------------

void funzioni()
{
  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();


    }
  }
 
  //------------------------------------------------------------------


 
  if (codice ==  90)// ENTER
  {
    nome_funzione(codice);
    enter();

  }
 
  if (codice == 43)// somma
  {
    nome_funzione(codice);
    if (visore != 0)enter();
    somma();
  }

  if (codice == 44)// moltiplicazione
  {
    nome_funzione(codice);
    if (visore != 0)enter();
    moltiplicazione();
  }

  if (codice == 45) //sottrazione
  {
    nome_funzione(codice);
    if (visore != 0)enter();
    sottrazione();
  }

  if (codice ==  46) // punto decimali
  {
    punto(); // con questa si pone a 1 la pdec
  }


  if (codice == 47) //divisione
  {
    nome_funzione(codice);
    if (visore != 0)enter();
    divisione();
  }
  //----------------------------------------
  // dal 48 al 57 ci sono le cifre da 0 a 9
  //----------------------------------------

  if (codice ==  58) // seno di x angolo in RADIANTI
  {
    nome_funzione(codice);
    if (visore != 0)enter();
    senox();
  }

  if (codice ==  59)// coseno  x  angolo in x in RADIANTI
  {
    nome_funzione(codice);
    if (visore != 0)enter();
    cosenx();
  }


  if (codice ==  60)//tangente  x  angolo in x in RADIANTI
  {
    nome_funzione(codice);
    if (visore != 0)enter();
    tangx();
  }


 if (codice ==  61)// arco seno di x
  {
    nome_funzione(codice);
    if (visore != 0)enter();
    arcosen_x();
  }
  if (codice ==  62)// arco coseno di x
  {
    nome_funzione(codice);
    if (visore != 0)enter();
    arcocos_x();
  }
  if (codice ==  63)// arco tangente di x
  {
    nome_funzione(codice);
    if (visore != 0)enter();
    arcotan_x();
  }
 

 if (codice ==  64)////Log10
  {
    nome_funzione(codice);
    if (visore != 0)enter();
    log10x();
  }


 //---------------------------------------
    // codice 65 2F seconde funzioni

    // al codice viene aggiunto +50
 //-----------------------------------------


 
  if (codice ==  66)// STO n
  {
    nome_funzione(codice);
   // impostareg();
    if ((visore > 0) && (visore <= 19))
    {
      sto_n();
      del();
    }
  }
  //-----------------------------------------
  if (codice ==  67)//  // PI GRECO
  {
    nome_funzione(codice);
    if (visore != 0)enter();
    pigreco();
  }

 
  if (codice ==  68) //radice quadrata
  {
    nome_funzione(codice);
    if (visore != 0)enter();
    sqrtx();
  }

 if (codice ==  69)//fix decimali
  {
    visfix();
  }

 
  if (codice ==  70)// potenza eleva y alla x
  {
    nome_funzione(codice);
    Ysux();
  }

 

  if (codice ==  71)// quadrato di x
  {
    nome_funzione(codice);
    if (visore != 0)enter();
    xquadro();
  }

 

 if (codice ==  72) // ln logaritmo naturale
  {
    nome_funzione(codice);
    if (visore != 0)enter();
    logN();
  }



 if (codice ==  73)// da rettangolari a polari
  {
    nome_funzione(codice);
    R_P ();
  }
 
 
 
  //-------------------------------------
  if (codice ==  74) //RCL n
  {
    nome_funzione(codice);
   // impostareg();
    if ((visore > 0) && (visore <= 19))
    {
      rcl_n();
      del();
    }
  }
  //--------------------------------------

  if (codice ==  75)//EEX
  {
    nome_funzione(codice);
    inputsci();
  }


  if (codice ==  76)// CHS cambio segno (moltiplica x per -1
  {
    nome_funzione(codice);
    cambiasegno();  //  CHS
  }

 if (codice ==  77)// converte da radianti in sessagesimali
  {
    nome_funzione(codice);
    if (visore != 0)enter();
    radHMS();
  }

 if (codice ==  78)// da gradi sessagesimali a radianti
  {
    nome_funzione(codice);
    if (visore != 0)enter();
    HMSrad();
  }

  if (codice == 79) // 1/x
  {
    nome_funzione(codice);
    if (visore != 0)enter();
    unosux();
  }


  if (codice == 80) // e alla x exp(x)
  {
    nome_funzione(codice);
    if (visore != 0)enter();
    expX ();
  }
 
 if (codice ==  81)
  {
    nome_funzione(codice);
    P_R(); // da polari a rettangolari p>=0 e alfa >=0 e <= pi/2
  }

  if (codice ==  82)//cancella carattere
  {
    del();
  }

  if (codice ==  83)//  x<>y scambio x con y
  {
    nome_funzione(codice);
    scambio();
  }

  if (codice ==  84) // R! scorre catasta giù
  {
    nome_funzione(codice);
    ruota();
  }

  if (codice ==  85)//Lastx ( recupera x )
  {
    nome_funzione(codice);
    last_x();
  }

  if (codice ==  86) // // 86  ruota SU catasta
  {
    nome_funzione(codice);
    ruotaSU();
  }
  // CLST  //
  if (codice == 87)
  {
    nome_funzione(codice);
    cancella(); //cancella catasta e visore
  }

  if (codice == 88) //10alla x
  {
    nome_funzione(codice);
    if (visore != 0)enter();
    po10x();
  }
 
  if (codice ==  89) // Xeq esegue funzione da 1 a ...
  {
   
    nome_funzione(codice);
    //impostareg();
    if ((visore > 0) && (visore <= 40))
    {
      Xeq_nn();
      del();
   
    }
  }
  return;
}

 //--------------------------------------------------
 //end funzioni_dirette
 //--------------------------------------------------

 //***************************
 //
 //     SECONDE FUNZIONI
 //
 //**************************-
 void seconde_Funzioni()
 {

if (codice == 112) //fact() // funzione fattoriale max 30
  {
    nome_funzione(codice);
    if (visore != 0)enter();
    fact();
     seconde = false;
    dirette = true;
  }

  if (codice == 113) //SQx_Y() radice x di Y
  {
    nome_funzione(codice);
    if (visore != 0)enter();
    SQx_Y();
     seconde = false;
    dirette = true;
   
  }

  if (codice == 114) // percento x%y
  {
    nome_funzione(codice);
    if (visore != 0)enter();
    percento();
 
    seconde = false;
    dirette = true;
  }
 
    //  codice 115 2F

  if (codice == 120) // FRC PARTE FRAZIONARIA DI X
  {
    nome_funzione(codice);
    if (visore != 0)enter();
    parteFRC();
     seconde = false;
    dirette = true;
  }

  if (codice == 121) // PARTE INTERA DI X
  {
    nome_funzione(codice);
    if (visore != 0)enter();
    parteINT();
     seconde = false;
    dirette = true;
  }

 
  if (codice == 122) // differenza percentuale
  {
    nome_funzione(codice);
    if (visore != 0)enter();
    percentoDi();
     seconde = false;
    dirette = true;
  }

  if (codice == 123) // MODULO PONE IN X IL RESTO DELLA DIVISIONE Y/X
  {
    nome_funzione(codice);
    if (visore != 0)enter();
    resto();
     seconde = false;
    dirette = true;
  }
 



  return;
  //------------------------------------------------
}

void visualizzaBatt()
{
   float p = vcc.Read_Perc(minVcc, maxVcc);
   int Percento = p;
   if (Percento <= 80){
      lcd.setCursor(19,0);
      lcd.write(byte(0));
   }
   else {
       lcd.setCursor(19,0);
      lcd.write(byte(1));
   }
}
   

void visualizzaNome(String nomeFunzione)
{
  lcd.setCursor(15, 3);
  lcd.print(nomeFunzione);
  delay(300);  // TEMPO DOVE SI MOSTRA A SINISTRA IL NOME DELLA FUNZIONE
}


//--------------------------------------------
//         ATTESA PRESSIONE TASTO
//****************************************************

void tasto()
{
  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;
  }
}
//*********************************************************************
//  AGGIORNA IL DISPLAY
//*********************************************************************
void aggiornadisplay()
{
  //***************
  // mostra display
  //---------------
  sciee = false;
  // si esegue il controllo se visualizzare in notazione sci o con fix
  float testx = regz;
  if (testx < 0) testx = testx * -1;
  if (testx > k1) sciee = true;
  if (testx < k0) sciee = true;
  if (testx == 0) sciee = false;
//**************************
  lcd.clear();
  visualizzaBatt();
  lcd.setCursor(0, 0);
  lcd.print("Z:");
  lcd.setCursor(4, 0);
  //---------------------------
if (sciee == true)
  { numero = regz;
    sci(); // sub per notazione scientifica
    lcd.print(regxs, 5);
    lcd.setCursor(14, 0);
    lcd.print (esponente);
  }
  else lcd.print(regz, fix);


//******************************
  sciee = false;
  testx = regy;
  if (testx < 0) testx = testx * -1;
  if (testx > k1) sciee = true;
  if (testx < k0) sciee = true;
  if (testx == 0) sciee = false;
//**************************

  lcd.setCursor(0, 1);
  lcd.print("Y:");
  lcd.setCursor(4, 1);
//-------------------------
if (sciee == true)
  { numero = regy;
    sci(); // sub per notazione scientifica
    lcd.print(regxs, 5);
    lcd.setCursor(14, 1);
    lcd.print (esponente);
  }
  else lcd.print(regy, fix);

 //******************************
  sciee = false;
  testx = regx;
  if (testx < 0) testx = testx * -1;
  if (testx > k1) sciee = true;
  if (testx < k0) sciee = true;
  if (testx == 0) sciee = false;
//**************************

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

  if (sciee == true)
  { numero = regx;
    lastx = regx;
    sci(); // sub per notazione scientifica
    lcd.print(regxs, 5);
    lcd.setCursor(14, 2);
    lcd.print (esponente);
  }

  else lcd.print(regx, fix); // visualizzazione normale
 
  lcd.setCursor(0, 3);
  if (dirette == true)
    {lcd.print("1:");}
     else {
      lcd.print("2:");
     }

 
  if (visore != 0)
  {
    lcd.setCursor(4, 3);
    lcd.print(visore, fix);
  }
  sciee = false;
}
//---------------------------------------------------------
// 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 viene utilizzato direttamente nei calcoli i due rappresentano comunque
// il contenuto di "regx" che deve essere utilizzato per il calcolo.

//**************************************************************
//       PER NOTAZIONE SCIENTIFICA SI CALCOLA ESPONENTE
//*************************************************************


void sci()
{
  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 * -1;
    segnoe = -1;
  }
  //-----------------------------------------------------------------------
  // 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
}

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

byte impostacodice() // imposta codice DEL TASTO BATTUTO
{
  byte cod = 0;
  tasto();   // inserisce nella variabile globale codice il
  // tasto battuto  ( da 43 a 90 )


  tastiFunzione(); // lavora sulle boolean delle funzioni

  //  controlla lo stato delle funzioni e crea il codice effettivo
  //  aggiungendo al codice creato da tasto() 50,150 il +100 è per le alfa

  // se il tasto premuto è un tasto funzione ritorna
   if (codice == 65 )return cod;
  // in questo modo ritorna cod = 0

  // con queste si crea il codice effettivo considerando il tasto funzione relativo

  if (dirette == true)cod = codice;//funzioni dirette

  if (seconde == true) //  deconde funzioni 2F
  { codice = codice + 50;
    cod = codice;
  }
  //if (alfa == true)funzioni_alfa(); // tastiera alfa

  // if (ardu == true)
  // { codice = codice + 150; //funzioni arduino 3F
  //  cod = codice;
  // }

  return cod;

}

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

void impostanumero()
{
 
  poscifra = poscifra + 1;
  if (poscifra <  9)
  { int cifra =  codice - 48;
    visore = visore * 10 + cifra;
   
  }
 else codice = 90;//enter
}


//****************************************************************
// questa variante migliora di poco la visualizzazione dei numeri decimali
// 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 * 0.1);
     
    }
    if (ndec == 2)
    {
       
      visore = visore  + (cifradec * 0.01);
     
    }
    if (ndec == 3)
    {
     
       visore = visore  + (cifradec * 0.001);
    }
     
     
    if (ndec == 4)
    {
     
      visore = visore  + (cifradec * 0.0001);

     
    }
    if (ndec == 5)
    {
     
       visore = visore  + (cifradec * 0.00001);
    }
  }
  else
  {
    codice = 90;
  }

}

// //**************************************************
//         FINE LISTATO
//**************************************************
//SCHEDA XEQ-STO-RCL PER LE FUNZIONI CON CHIAMTA nn
//---------------------------------------------------
//SCHEDA FUNZIONI DIRETTE E SECONDE
//---------------------------------------------------
//SCHEDA PROG PER I PROGRAMMI UTENTE CHIAMATI CON XEQnn
//------------------------------------------------------------------
// SCHEDA NOMI FUNZIONI CON STRINGHE VISUALIZZATE DEI NOMI FUNZIONI
//******************************************************************



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


/----------------------------------------------------------
//               FUNZIONI DIRETTE E SECONDE CON 2F
//----------------------------------------------------------

void senox()// SENO di x (con x in radianti)
{
  lastx = regx;
  regx = sin (regx);
}
void cosenx()// COSENO di x (con x in radianti)
{
  lastx = regx;
  regx = cos (regx);
}

void tangx() // TANGENTE di x (con x in radianti)
{
  lastx = regx;
  regx = tan (regx);
}
void unosux() // 1/X
{
  if (regx == 0)return;
  lastx = regx;
  regx = ( 1 / regx);
}
void sqrtx() // RADICE QUADRATA DI X
{
  lastx = regx;
  regx = sqrt (regx);
}

void xquadro() // X ELEVATO AL QUADRATO
{
  lastx = regx;
  regx = regx * regx;
}
void pigreco() // PIGRECO
{
  lastx = regx;
  regu = regt;
  regt = regz;
  regz = regy;
  regy = regx;
  regx = PI;
}
void clx() // AZZERA IL REG X
{
  lastx = regx;
  regx = 0.0;
}
void log10x() // LOGARITMO DI X IN BASE 10
{
  lastx = regx;
  regx = log10(regx);
}
void logN() // LOGARITMO DI X IN BASE e
{
  lastx = regx;
  regx = log(regx);
}

void po10x()//10alla x
{
  if (regx < 30)
  {
    lastx = regx;
    regx = pow(10, regx);
  }
}

void expX ()// exp e^x
{
  lastx = regx;
  regx = exp(regx);
}


void Ysux()// Y^x ( Y elevato alla X )
{
  lastx = regx;
  regx = pow (regy, regx);
}

void SQx_Y()// RADICE ENNESIMA DI Y  (radice x di Y)
{
  lastx = regx;
  regx = pow (regy,(1/regx));
}



void HMSrad() // da gradi sessagesimali H.ms a Radianti
{
  lastx = regx;
  sess_sedec();
  regx = regx * PI / 180.0;
}
void radHMS() //da radianti a gradi sessagesimali H.ms
{
  lastx = regx;
  regx = regx * 180.0 / PI;
  sedec_sessa();
}
void somma()//43
{
  lastx = regx;
  regx = (regx + regy);
  regy = regz;
  regz = regt;
  regt = regu;

  del();
}

void  sottrazione()//45
{
  lastx = regx;
  regx = (regy - regx);
  regy = regz;
  regz = regt;
  regt = regu;

  del();
}

// punto decimali
void punto()//46
{
  pdec = 1;
  ndec = 0;
  codice = 0;
}

//cancella carattere dal visore
void del() //82
{
  visore = 0;
  poscifra = 0;
  codice = 0;
  pdec = 0;
  ndec = 0;
}


void enter()//90 TASTO ENTER INTRODUCE  IL VISORE in X e fa scorrere su
{
  regu = regt;
  regt = regz;
  regz = regy;
  regy = regx;
  regx = visore;

  del();
}

// moltiplicazione  //44
void moltiplicazione()
{
  lastx = regx;
  regx = (regy * regx); // esegue la moltiplicazione
  regy = regz;
  regz = regt;
  regt = regu;
  del();
}

//divisione  //47
void divisione()
{

  if (regx == 0) return;  //******* divisione per 0

  lastx = regx;  // prima salva in lastx il valore di x
  regx = (regy / regx);      // esegue la divisione
  regy = regz;
  regz = regt;
  regt = regu;
  del();
}
// clr   // CLST  //
void cancella() //cancella catasta e visore
{
  regu = 0.0;
  regt = 0.0;
  regz = 0.0;
  regy = 0.0;
  regx = 0.0;
  lastx = 0.0;
  visore = 0.0;
  poscifra = 0;
  codice = 0;
  pdec = 0;
  ndec = 0;
}

void cancella_mem()// cancella memorie utente
{
  mem1 = 0.0;
  mem2 = 0.0;
  mem3 = 0.0;
  mem4 = 0.0;
  mem5 = 0.0;
  mem6 = 0.0;
  mem7 = 0.0;
  mem8 = 0.0;
  mem9 = 0.0;
  mem10 = 0.0;
  mem11 = 0.0;
  mem12 = 0.0;
  mem13 = 0.0;
  mem14 = 0.0;
  mem15 = 0.0;
  mem16 = 0.0;
  mem17 = 0.0;
  mem18 = 0.0;
  mem19 = 0.0;

}



//Lastx
void last_x()//85 RECUPERA IL CONTENUTO DI X
{
  regu = regt;
  regt = regz;
  regz = regy;
  regy = regx;
  regx = lastx;
}

//  x<>y scambio
void scambio()//83 SCAMBIA I REGITRI X Y NELLA CATASTA
{
  float scambio = regx;
  regx = regy;
  regy = scambio;
}
//ruota giu la catasta
void ruota()//84  RUOTA GIU' LA CATASTA
{
  float ruota = regx;
  regx = regy;
  regy = regz;
  regz = regt;
  regt = regu;
  regu = ruota;
}

 //  86 ruota SU la catasta
void ruotaSU()
{
  float ruota = regu;
  regu = regt;
  regt = regz;
  regz = regy;
  regy = regx;
  regx = ruota;
}
//cambiosegno
void cambiasegno()//86 CAMBIA SEGNO AL REGISTRO X
{
  lastx = regx; regx = regx * -1;
}

// FIX----- scelta numero decimali dopo il punto da 0 a 5
void visfix()//77
{ if (( visore < 0 ) || (visore > 5)) return;
  else fix = visore;
}

void arcosen_x()// 61 ASIN ritorna angolo in x in RADIANTI
{
  if ((regx < -1) || ( regx > 1)) return;
  {
    lastx = regx;
    regx = asin (regx);
  }
}

void arcocos_x()//62 ACOS ritorna angolo in x in RADIANTI
{
  if ((regx < -1) || ( regx > 1)) return;
  {
    lastx = regx;
    regx = acos (regx);
  }
}


void arcotan_x()//63 ATAN ritorna angolo in x in RADIANTI
{
  lastx = regx;
  regx = atan (regx);
}



// converte x da sessagesimale a sessadecimale
// solo il registro x della catasta viene utilizzato
void sess_sedec()  // FUNZIONE
{
  lastx = regx;
  float a = regx;
  int b = int(a);  // i gradi
  float c = (a - b) * 100;
  int d = int(c);
  float pri = d / 60.0; // primi
  float sec = (c - d) / 36.0; // i secondi
  regx = (b + pri + sec);
}

// converte x da sessadecimali a sessagesimali
// solo il registro x della catasta viene utilizzato
void sedec_sessa() // FUNZIONE
{
  lastx = regx;
  float a = regx;
  int b = int(a);  // i gradi
  float c = (a - b) * 60;
  int d = int(c);  // i primi
  float pri = d / 100.0;
  float sec = (c - d) * 6 / 1000.0; // i secondi
  regx = (b + pri + sec);
}

// da polari a rettangolari inserire in x l'angolo alfa
// in gradi RADIANTI
// inserire in y la magnitudine
// restituisce le cordinate in x e y
void P_R()
{

  double magni = regy;
  double alfa = (regx);
  if (magni < 0)return;
  if (alfa > (2 * PI))return;
  if (alfa < 0 )return;
  regx = magni * cos(alfa);
  regy = magni * sin(alfa);
}

// da rettangolari a polari inserire in x la coordinata Xp
ed in y la coordinata Yp
// restituisce in y la distanza
// e restituisce in x angolo in RADIANTI
//
void R_P()
{
  double alfa = 0;
  double magni = sqrt((regx * regx) + (regy * regy));
  alfa = atan2(regy, regx);
  regx = alfa;
  regy = magni;
}
// questa sub serve ad inserire un numero molto grande o molto piccolo
// in catasta inserendo in y il valore n.nnnnn ed in x l'esponente base 10
void inputsci()
{
  double numero = regy;
  double esp = regx;
  regx = numero * pow(10, esp);
  regxs = regx;
  esponente = esp;
  sciee = true;
}



void fact() // funzione fattoriale max 30
{
  int numero = regx;
  double fact = 1.0;
  regx = fact;

  if ((numero < 1) || (numero > 31)) return;

  else
  {
    for ( int i = numero; i > 1; i--)
    {
      fact = fact * i;
    }
    regx = fact;
  }
}
// end fact

void percento()
{
  lastx = regx;
  regx = (regx * regy / 100);
}

void percentoDi()
{
  if ( regy == 0) return;
 
  lastx = regx;
  regx = (( regx - regy)* 100)/ regy;
}

void parteFRC()
{
  lastx = regx;
  int parteint = (int) regx;
  regx = (regx - parteint);
}

void parteINT()
{
  lastx = regx;
  regx = (int) regx;
 
}

void resto()
{
  lastx = regx;
  int parteint = (int)(regy/regx);
  int re = regy - (parteint * regx);
  regx = re;
}



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

// -----------------------------------------------------------------
//              NOME FUNZIONE
// questa funzione ritorna una stringa con il nome della funzione
// relativa al codice passato, che sarà visualizzata
// a destra sul display per 300 ms.
//-------------------------------------------------------------------

String nome_funzione(byte codice)
{
  String nomeFunzione = "";


  if ((codice  >= 48) && (codice <= 57 ))return nomeFunzione;// numeri
  if ((codice  >= 0 ) && (codice <= 42 ))nomeFunzione = (codice);// registri
  if (codice == 46)return nomeFunzione;// punto decimale

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

 

  if (codice == 43)nomeFunzione = "SOMMA";
  if (codice == 44)nomeFunzione = "PER";
  if (codice == 45)nomeFunzione = "MENO";
  if (codice == 47)nomeFunzione = "DIV";
  if (codice == 58)nomeFunzione = "SIN";// SENO
  if (codice == 59)nomeFunzione = "COS";// COSENO
  if (codice == 60)nomeFunzione = "TAN";// TANGENTE
  if (codice == 61)nomeFunzione = "ASIN";// ARCOSENO DI X
  if (codice == 62)nomeFunzione = "ACOS";// ARCOCOSENO DI X
  if (codice == 63)nomeFunzione = "ATAN";// ARCOTANGENTE DI X
  if (codice == 64)nomeFunzione = "LOG";// LOGARITMO BASE 10
  if (codice == 65)return nomeFunzione;// seconda funzione
  if (codice == 66)nomeFunzione = "STO";// STOnn INSERIMENTO IN MEMORIA nn
  if (codice == 67)nomeFunzione = "PI";// PI GRECO
  if (codice == 68)nomeFunzione = "SQRT";// SQRT
  if (codice == 69)return nomeFunzione;// FIX  fissa i decimali visibili  
  if (codice == 70)nomeFunzione = "Y^x";// Y ELEVATO A X
  if (codice == 71)nomeFunzione = "X2";// X AL QUADRATO
  if (codice == 72)nomeFunzione = "LN";// LOG N
  if (codice == 73)nomeFunzione = "R>P";// DA RETTANGOLARI A POLARI
  if (codice == 74)nomeFunzione = "RCL";// RCLnn RICHIAMA LA MEMORIA nn
  if (codice == 75)nomeFunzione = "EEX";// EEX INSERIMENTO ESPONENTE
  if (codice == 76)nomeFunzione = "CHS";// CAMBIO SEGNO
  if (codice == 77)nomeFunzione = "HMS";// >HMS DA RADIANTI A GRADI/MINUTI/SECONDI
  if (codice == 78)nomeFunzione = "RAD";// >RAD DA DECIMALI A RADIANTI
  if (codice == 79)nomeFunzione = "1/X";// 1/X
  if (codice == 80)nomeFunzione = "e^X";// e ALLA X
  if (codice == 81)nomeFunzione = "P>R";// DA POLARI A RETTANGOLARI
  if (codice == 82)nomeFunzione = "DEL";// DEL CANCELLA VISORE
  if (codice == 83)nomeFunzione = "X<>Y";// X<>Y SCAMBIO X CON Y
  if (codice == 84)nomeFunzione = "RGIU";// RGIU SPOSTA GIù LA CATASTA
  if (codice == 85)nomeFunzione = "LASTX";// LASTX RICHIAMA IN IN X IL REGISTRO LASTX
  if (codice == 86)nomeFunzione = "R_SU"; // RUOTA SU LA CATASTA
  if (codice == 87)nomeFunzione = "CLST";// CANCELLA CATASTA E VISORE
  if (codice == 88)nomeFunzione = "10^x ";// 10 ^x
  if (codice == 89)nomeFunzione = "XEQ";// XEQ ESEGUE FUNZIONE O PROGRAMMA
  if (codice == 90)nomeFunzione = "ENTER";


  //*********************************************
  //  seconde funzioni + 50 da 93 a 140
  //*********************************************

 
  if (codice == 93)nomeFunzione = "093";// tasto piu
  if (codice == 94)nomeFunzione = "094";// tasto per
  if (codice == 95)nomeFunzione = "095";// tasto meno
  if (codice == 96)nomeFunzione = "097";// tasto diviso
  if (codice == 108)nomeFunzione = "108";//  
  if (codice == 109)nomeFunzione = "109";//
  if (codice == 110)nomeFunzione = "110";//
  if (codice == 111)nomeFunzione = "111";//
  if (codice == 112)nomeFunzione = "FACT";// FATTORIALE DI X
  if (codice == 113)nomeFunzione = "Rx-Y";// RADICE x DI Y
  if (codice == 114)nomeFunzione = " % ";// PERCENTUALE x DI Y
  if (codice == 115)nomeFunzione = "115";// 2F
  if (codice == 116)nomeFunzione = "116";//
  if (codice == 117)nomeFunzione = "117";//
  if (codice == 118)nomeFunzione = "118";//
  if (codice == 119)nomeFunzione = "119";//
  if (codice == 120)nomeFunzione = "FRC";// PARTE FRAZIONARIA DI X
  if (codice == 121)nomeFunzione = "INT";// PARTE INTERA DI X
  if (codice == 122)nomeFunzione = "% DI";// DIFFERENZA PERCENTUALE FRA X ED Y
  if (codice == 123)nomeFunzione = "MOD";// MODULO DIVISIONE Y MOD X IL RESTO è IN X
  if (codice == 124)nomeFunzione = "124";//
  if (codice == 125)nomeFunzione = "125";//
  if (codice == 126)nomeFunzione = "126";//
  if (codice == 127)nomeFunzione = "127";//  
  if (codice == 128)nomeFunzione = "128"; //
  if (codice == 129)nomeFunzione = "129";//
  if (codice == 130)nomeFunzione = "130";//
  if (codice == 131)nomeFunzione = "131";//
  if (codice == 132)nomeFunzione = "132";//
  if (codice == 133)nomeFunzione = "133";//
  if (codice == 134)nomeFunzione = "134";//
  if (codice == 135)nomeFunzione = "135";//
  if (codice == 136)nomeFunzione = "135";//
  if (codice == 137)nomeFunzione = "137";//
  if (codice == 138)nomeFunzione = "138";//
   
  visualizzaNome(nomeFunzione);

  return nomeFunzione;

}

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

//************************************************************
//
//  In questa scheda PROG-DI-XEQnn
//  ci sono i prorammi aggiuntivi
// che sono chiamati con XEQnn.
// Il primo è l'elenco dei programmi "catalog"
// fa una funzione simile alla catalog della HP dove mostra
// il numero da inserire nella XEQnn ed il nome del programma
// per eseguire questi programmi bisogna inserire
// nei registri e/o nelle memorie i valori richiesti.
// il programma viene eseguito ed nei registri si trovano i
// risultati nei registri della catasta e/o nelle memorie
//
// Se si vuole aggiungere un programma si
// dovrà  modificare queste parti:
// 1) aggiungere in questa scheda il programma con suo nome
// 2) modificare in questa scheda il prog catalog aggiungendolo
// 3) modificare la scheda XEQ-STO-RCL nella parte relativa
// alla chiamata XEQnn inserendo nel ciclo case
// il nome del nuovo programma
//************************************************************


void catalog()
{
 
  lcd.clear();
   // se si aggiungono programmi aggiornare la lista qui sotto
   

    for (int i = 1; i < 10; i++)
    {
    numProg = i;
   
    if (i == 1)nomeProg = "LISTA PROGRAMMI";
    if (i == 2)nomeProg = " TRI. CARNOT   ";
    if (i == 3)nomeProg = " PARALLELO RES ";
    if (i == 4)nomeProg = "Triangolo Erone";
    if (i == 5)nomeProg = " PARTITORE V   ";
    if (i == 6)nomeProg = " SCORPORO IVA  ";
    if (i == 7)nomeProg = "INPUT-OUT-PROG ";
    if (i == 8)nomeProg = "RAD -> CENTESI ";
    if (i == 9)nomeProg = "CENTES. -> RAD ";

    lcd.setCursor(0, 0);
    lcd.print(numProg);
    lcd.setCursor(4, 0);
    lcd.print(nomeProg);
    delay (1800);
    lcd.clear();
    }
      //lcd.clear();
}


//**********************************************************************************************
//
//  1° ESEMPIO PROGRAMMA CALCOLO TRIANGOLO CON CARNOT
//
 void carnot()  // funzione 02 ****
     {
         

      //  angolo in x in RADIANTI
     double latoa = regz; // uno dei lati conosciuti
     double latob = regy; // il secondo lato conosciuto
     double angolo = regx;// angolo compreso fra i due lati
     //  si cerca il terzo lato
     //  gli angoli INPUT sono inseriti in RADIANTI
     //  gli angoli in OUT saranno in RADIANTI

     //***********************************
     // due lati ed angolo compreso
     
     double latoc = sqrt(pow(latoa,2)+ pow(latob,2)-(2*latoa*latob)*cos(angolo));

     regx = latoc;  // in x troviamo il lato cercato opposto all'anglo compreso
     regy = latob;  // lato noto
     regz = latoa;  // lato noto
     regt = angolo; // angolo noto  in radianti
     //**************************************************
   

} // fine carnot




void parallelo() // prog 03
{
 //*************************************************************
 //       PARALLELO RESISTORI
 //
 //  //   r1 -r2
 //*************************************************************
 // si inseriscono in x ed in y i valori di due resistori.
 //
 // questo programma modifica tutto lo stak
 // in uscita avremo in x la resistenza parallelo
 //
   
      //*****************************
     double resp = 0;
   
        resp =  1/ ((1/regx)+ (1/regy));
       

      regx = resp;
      regy = 0;
      regz = 0;
      regt = 0;

}
// fine parallelo
//******************************************************************


//************************************************************
//              superficie triangolo con Erone
//    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.
//*************************************************************
//
void erone()  //  fuzione 04 ****
{


 double latoa = regx;
 double latob = regy;
 double latoc = regz;
 
if (latoa >= (latob+latoc)|| latob >= (latoc + latoa)|| latoc >=(latob+latoa)) return;
         
    else {
         
            double perimetro = latoa + latob + latoc;
            double per2 = perimetro/2;
            double super = sqrt(per2*((per2-latoa)*(per2-latob)*(per2-latoc)));

            regx = super;
            regy = latoa;
            regz = latob;
            regt = latoc;

         }
}// fine erone
 

//*******************************************************
// partitore di tensione
//*******************************************************
void partitore() // funzione 05
{
 

      //*****************************
  //Vn= VIN(Rn/(R1 + R2 + R3)

    double r1 = regy; // inserire valore R1 in omm
    double r2 = regz; // inserire valore R2 in omm
    double r3 = regt; // inserire valore R3 se non serve inserire 0
    double vin = regx;// inserire Vin in Volt

    double v1 = vin * ( r1 / ( r1+r2+r3));
    double v2 = vin * ( r2 / ( r1+r2+r3));
    double v3 = vin * ( r3 / ( r1+r2+r3));
   
    regx = v1;  // Volt in v1
    regy = v2;  // Volt in v2
    regz = v3;  // Volt in v3
    regt = 0;
} // fine partitore

//*****************************************************************
//       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.
// *****************************************************************
//          
void sco_iva()//   funzione 06 ****
{
     

      //****************************************
      double aliq = regy;
      double total = regx;
      double imponibile = (total*100)/(100+aliq);
      //*****************************************
      //output
      regx = (total - imponibile); // IVA
      regy =  imponibile;
      regz = total;
      regt = aliq;
 
     //*****************************************
} // fine scorporo iva
//----------------------------------------------------------------------------
 void input_out_prog()
 {
    lcd.clear();
 // lcd.print("01234567890123456789");
    lcd.setCursor(0, 0);
    lcd.print("Inserire i dati nei ");
    lcd.setCursor(0, 1);
    lcd.print("registri x,y,z,t   ");
    lcd.setCursor(0, 2);
    lcd.print("angoli in RAD      ");
    lcd.setCursor(0, 3);
    lcd.print("num poi tasto XEQ ");
    tasto();
    lcd.clear();

 }



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

//--------------------------------------------------------------------------
//   SCHEDA FUNZIONI CON INDICE ..  STO - RCL - XEQ
//-----------------------------------------------------------------------

// IN QUESTA SCHEDA CI SONO TRE VOID CON LA STRUTTURA SWITCH - CASE
// CHE MEMORIZZANO ( con STO nn) o richiamano delle memorie ( con RCL nn)

// in questa scheda si trova anche la strurrura switch-case
// per chiamare i programmi utente con XEQ nn

// STO nn  SUB PER MEMORIZZARE IL CONTENUTO DI X
//NEL REGISTRO INDICATO IN VISORE  DA 1 A 19
// MA SE OCCORRE SI PUO' AUMENTARE LE MEMORIE UTENTE
// IN QUEL CASO OCCORRE VARIARE ANCHE LA SUB RCL
// E LA SUB CHE CANCELLA IL CONTENUTO MEMORIE UTENTE
// CIOE LA cancella_mem

void sto_n()
{
  int mem = visore;
  if (( mem < 1 ) || (mem > 19)) 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;
    case 10:
      mem10 = regx;
      break;

    case 11:
      mem11 = regx;
      break;
    case 12:
      mem12 = regx;
      break;
    case 13:
      mem13 = regx;
      break;
    case 14:
      mem14 = regx;
      break;
    case 15:
      mem15 = regx;
      break;
    case 16:
      mem16 = regx;
      break;
    case 17:
      mem17 = regx;
      break;
    case 18:
      mem18 = regx;
      break;
    case 19:
      mem19 = regx;
      break;
  }
  visore = 0;
} // fine void sto_n
//----------------------------------------------------------------


//RCL  richiama in x uno dei registri
void rcl_n()
{
 // indirizzo = visore;
  int mem = visore;

  if (( mem < 1 ) || (mem > 19)) return;


  switch (mem)
  {
    case 1:
      {
        visore = mem1;
        enter();
      }
      break;
    case 2:
      {
        visore = mem2;
        enter();
      }
      break;
    case 3:
      {
        visore = mem3;
        enter();
      }
      break;
    case 4:
      {
        visore = mem4;
        enter();
      }
      break;
    case 5:
      {
        visore = mem5;
        enter();
      }
      break;

    case 6:
      {
        visore = mem6;
        enter();
      }
      break;
    case 7:
      {
        visore = mem7;
        enter();
      }
      break;
    case 8:
      {
        visore = mem8;
        enter();
      }
      break;
    case 9:
      {
        visore = mem9;
        enter();
      }
      break;

    case 10:
      {
        visore = mem10;
        enter();
      }
      break;

    case 11:
      {
        visore = mem11;
        enter();
      }
      break;

    case 12:
      {
        visore = mem12;
        enter();
      }
      break;
    case 13:
      {
        visore = mem13;
        enter();
      }
      break;
    case 14:
      {
        visore = mem14;
        enter();
      }
      break;
    case 15:
      {
        visore = mem15;
        enter();
      }
      break;

    case 16:
      {
        visore = mem16;
        enter();
      }
      break;
    case 17:
      {
        visore = mem17;
        enter();
      }
      break;
    case 18:
      {
        visore = mem18;
        enter();
      }
      break;
    case 19:
      {
        visore = mem19;
        enter();
      }
      break;

  }

  visore = 0;
}

//-----------------------------------------------------------
void Xeq_nn()
{
  //indirizzo = visore;
  int mem = visore;
  if (( mem < 1 ) || ( mem > 40)) return;

  switch (mem)
  {
    case 1:
      {
        //catalog(); // nomi dei programmi di XEQnn
        catalog();
      }
      break;
    case 2:
      {
        carnot(); // soluzione triangolo due lati angolo compreso
      }
      break;
    case 3:
      {
        parallelo(); // calcola la rt di due resistenze in parallelo
      }
      break;
    case 4:
        {
          erone(); // 04 calcola triangolo con erone
        }
      break;
    case 5:
        {
          partitore(); // 05 calcola partitore di tensione
        }
      break;

    case 6:
       {
         sco_iva(); // 06  scorporo iva
       }
      break;
    case 7:
       {
         input_out_prog();//07 indicazioni su input output per i programmi
       }

      break;
    case 8: // DA RADIANTI A CENTESIMALI
      {
        lastx = regx;
        regx = regx * 200.0 / PI;
      }

      break;
    case 9:
        //  da centesimali a radianti
      {
        lastx = regx;
        regx = regx * PI / 200.0;
      }
      break;
    case 10:
      //---
      break;
    case 11:
      //----

      break;
    case 12:
      //----
      break;
    case 13:
        //----

      break;

    case 14:
      //-----
      break;
    case 15:
      //-----
      break;

    case 16:
      //----
      break;

    case 17:
      //----
      break;

    case 18:
      // disponibile
      break;

    case 19:
      //----
      break;

    case 20:
      //****
     
      break;

    case 21:
     
      break;

    case 22:
      // disponibile
      break;


    case 23:
      // disponibile
      break;

    case 24:
      // disponibile
      break;

    case 25:
      //------------------
     
      break;



    case 26:
      // disponibile
      break;

    case 27:
      // disponibile
      break;

    case 28:
      // disponibile
      break;

    case 29:
      // disponibile
      break;

    case 30:
      // disponibile
      break;

    case 31:
      // disponibile
      break;

    case 32:
      // disponibile
      break;

    case 33:
      // disponibile
      break;

    case 34:
      // disponibile
      break;
    case 35:
      // disponibile
      break;

    case 36:
      // disponibile
      break;

    case 37:
      // disponibile
      break;

    case 38:
      // disponibile
      break;

    case 39:
      // disponibile
      break;

    case 40:
      // disponibile
      break;

  }
  visore = 0;
} // fine void XEQ

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




Indice delle funzioni e loro uso:

----------------------------------------------------------------------

Funzioni dirette

----------------------------------------------------------------------

Somma, sottrazione, moltiplicazione, divisione :

 Si introduce il primo operando, poi il secondo e si preme il tasto operatore 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 :   Cancella il contenuto del visore.


F2   Tasto seconda funzione abilita e disabilita la seconda funzione.


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 19) 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 (01-19) quindi premere il tasto funzione STO. Il contenuto di x rimane in x e viene duplicato nel registro indicato.


RCL: Richiama in X il contenuto del registro ( da 01 a 19), immettere nel visore il numero del registro e premere il tasto funzione RCL, 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 FIX. 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 risultati.

Possono essere usati anche i registri utente che la funzione e/o programma possono utilizzare come input e/o come output.



 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.

 In Lastx si conserva il valore di partenza.


 costante PI (pigreco)  in x.

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


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

R>P  : Da coordinate rettangolari a polari, x,y  inserire le due coorinate e premere il tasto R>P restituisce in y la distanza in x l'angolo in radianti.

P>R  : 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.

Log : logaritmo in base 10.

LN : logaritmo in base e.

R^ : Rsu ruota la catasta  regx sale in regy , regy sale in regz e così via.



Aggiornamento 18/02/23 lo sketch aggiornato è v506-48-v109 






Questa è la tabella di corrispondenza dei tasti e del codice.



Ho aggiunto alcune funzioni e programmi da chiamare con la XEQnn

--------------------------------------------------------------------------------

Funzioni seconde  ( prima premere il tasto 2F)

appare sulla linea del visore il 2, per togliere la 2F premere ancora il tasto, 
sul visore appare 1.

--------------------------------------------------------------------------------

FACT : calcola il fattoriale di x

xSQRy : calcola radice x del registro y

% : calcola la percentuale x del registro y

FRC : parte frazionaria di x ( elimina la parte intera di x)

INT : parte intera di un numero ( elimina la parte decimale senza arrotondamento).

%D : calcola pa differenza percentuale fra Y ed X 

MOD : resto della divisione Y / X 

Ho aggiunto solo 8 seconde funzioni dalla tabella sopra potete vedere che sono disponibili molti altri tasti da usare come seconda funzione (d nella tabella).

E' possibile aggiungere altre seconde funzioni per farlo occorre seguire questi passi:


1) nella sub void funzioni() - scheda principale-

aggiungere nello spazio dedicato alle seconde funzioni ( vedi qui sotto)


 //--------------------------------------------------
 //end funzioni_dirette
 //--------------------------------------------------

 //***************************
 //
 //     SECONDE FUNZIONI
 //
 //**************************-

 if (codice == 112) //fact() // funzione fattoriale max 30
  {
    nome_funzione(codice);
    if (visore != 0)enter();
    fact();
  }

una porzione di codice che richiami la nostra nuova funzione 

si può copiare questa cambiare il codice del tasto  e il nome della nuova funzione .


2) nella scheda :

 FUNZIONI DIRETTE E SECONDE CON 2F

scrivere una void con nome funzione che esegua il calcolo.


3)  aggiornare la scheda " NOMI FUNZIONI "

basterà indicare il nome scelto e sostituirlo al posto del codice 

 

  //*********************************************
  //  seconde funzioni + 50 da 93 a 140
  //*********************************************

 
  if (codice == 93)nomeFunzione = "093";// tasto piu
  if (codice == 94)nomeFunzione = "094";// tasto per
  if (codice == 95)nomeFunzione = "095";// tasto meno
  if (codice == 96)nomeFunzione = "097";// tasto diviso
  if (codice == 108)nomeFunzione = "108";//  
  if (codice == 109)nomeFunzione = "109";//
  if (codice == 110)nomeFunzione = "110";//
  if (codice == 111)nomeFunzione = "111";//
  if (codice == 112)nomeFunzione = "FACT";// FATTORIALE DI X
  if (codice == 113)nomeFunzione = "Rx-Y";// RADICE x DI Y
  if (codice == 114)nomeFunzione = " % ";// PERCENTUALE x DI Y
  if (codice == 115)nomeFunzione = "115";// 2F
  if (codice == 116)nomeFunzione = "116";//
  if (codice == 117)nomeFunzione = "117";//
  if (codice == 118)nomeFunzione = "118";//
  if (codice == 119)nomeFunzione = "119";//
  if (codice == 120)nomeFunzione = "FRC";// PARTE FRAZIONARIA DI X
  if (codice == 121)nomeFunzione = "INT";// PARTE INTERA DI X
  if (codice == 122)nomeFunzione = "% DI";// DIFFERENZA PERCENTUALE FRA X ED Y
  if (codice == 123)nomeFunzione = "MOD";// MODULO DIVISIONE Y MOD X IL RESTO è IN X
  if (codice == 124)nomeFunzione = "124";//


per esempio se abbiamo scelto il tasto relativo al codice 116 basterà inserire il nome della funzione abbreviato vedi esempi.
( questa operazione serve solo a visualizzare il nome della funzione eseguita ma non influisce sul calcolo )


------------------------------------

Programmi aggiuntivi

--------------------------------------
Con questo aggiornamento ho aggiunto anche alcuni programmi di esempio richiamabili con la XEQ nn 

Questi programmi sono realizzabili scrivendoli con l'IDE Arduino nella scheda PROG-DI-XEQnn

Se si vuole aggiungere un programma si
// dovrà  modificare queste parti:
// 1) aggiungere in questa scheda il programma con suo nome
// 2) modificare in questa scheda il prog catalog aggiungendolo
// 3) modificare la scheda XEQ-STO-RCL nella parte relativa
// alla chiamata XEQnn inserendo nel ciclo case
// il nome del nuovo programma


Ho aggiunto il programma (1)  void catalog() 

questo programma visualizza il numero ed il nome dei programmi contenuti nella scheda quindi se aggiungete programmi aggiornate anche il catalog con il nome del nuovo programma. 

 programma (2)   carnot() 

void carnot()  // funzione 02 ****
     {
      //  angolo in x in RADIANTI
     double latoa = regz; // uno dei lati conosciuti
     double latob = regy; // il secondo lato conosciuto
     double angolo = regx;// angolo compreso fra i due lati
     //  si cerca il terzo lato
     //  gli angoli sono inseriti in RADIANTI  INPUT
     //  gli angoli saranno in RADIANTI

     //***********************************
     // due lati ed angolo compreso
     
     double latoc = sqrt(pow(latoa,2)+ pow(latob,2)-(2*latoa*latob)*cos(angolo));

     regx = latoc;  // in x troviamo il lato cercato opposto all'anglo compreso
     regy = latob;  // lato noto
     regz = latoa;  // lato noto
     regt = angolo; // angolo noto  in radianti
     //**************************************************
} // fine carnot


Si calcola il terzo lato del triangolo, conoscendo i due lati e l'angolo compreso, angoli in radianti.


 programma (3)  parallelo() resistori inserire in x ed in y i valore di due resistenze.
( valori espressi nella stessa unità di misura ) in x ritroviamo il valore del parallelo. 

void parallelo() // prog 03
{
 //*************************************************************
 //       PARALLELO RESISTORI
 //
 //  //   r1 -r2
 //*************************************************************
 // si inseriscono in x ed in y i valori di due resistori.
 //
 // questo programma modifica tutto lo stak
 // in uscita avremo in x la resistenza parallelo
 //
   
     double resp = 0;
   
        resp =  1/ ((1/regx)+ (1/regy));
       

      regx = resp;
      regy = 0;
      regz = 0;
      regt = 0;

}
// fine parallelo
//******************************************************************

programma (4)  erone()  Calcolo superfice triangolo noti i tre lati.
si inseriscono i tre lati in x,y,z e si ottiene la superficie in x.


//************************************************************
//              superficie triangolo con Erone
//    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.
//*************************************************************
//
void erone()  //  fuzione 04 ****
{
 double latoa = regx;
 double latob = regy;
 double latoc = regz;
 
if (latoa >= (latob+latoc)|| latob >= (latoc + latoa)|| latoc >=(latob+latoa)) return;
         
    else {
         
            double perimetro = latoa + latob + latoc;
            double per2 = perimetro/2;
            double super = sqrt(per2*((per2-latoa)*(per2-latob)*(per2-latoc)));

            regx = super;
            regy = latoa;
            regz = latob;
            regt = latoc;

         }
}// fine erone

programma (5)   partitore()  Inserire Vin in x, e i valori delle resistenze in serie 

Vedi listato qui sotto 

//*******************************************************
// partitore di tensione
//*******************************************************
void partitore() // funzione 05
{
  //Vn= VIN(Rn/(R1 + R2 + R3)

    double r1 = regy; // inserire valore R1 in omm
    double r2 = regz; // inserire valore R2 in omm
    double r3 = regt; // inserire valore R3 se non serve inserire 0
    double vin = regx;// inserire Vin in Volt

    double v1 = vin * ( r1 / ( r1+r2+r3));
    double v2 = vin * ( r2 / ( r1+r2+r3));
    double v3 = vin * ( r3 / ( r1+r2+r3));

    regx = v1;  // Volt in v1
    regy = v2;  // Volt in v2
    regz = v3;  // Volt in v3
    regt = 0;
} // fine partitore

programma (6)  sco_iva()  Scorporo iva inserire in y l'aliquota, ed in x il totale con iva.

avremo in x iva, in y l'imponibile, in z il totale ed in t l'aliquota.


//*****************************************************************
//       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.
// *****************************************************************
//          
void sco_iva()//   funzione 06 ****
{
      //****************************************
      double aliq = regy;
      double total = regx;
      double imponibile = (total*100)/(100+aliq);
      //*****************************************
      //output
      regx = (total - imponibile); // IVA
      regy =  imponibile;
      regz = total;
      regt = aliq;
 
     //*****************************************
} // fine scorporo iva
//---------------------------------------------------------------------------------------

Si possono realizzare programmi richiamabili utilizzando la stessa struttura.

Lasciate un commento se avete domande o riscontrate errori.

Grazie!!




Qui sopra la foto con le funzioni 2F aggiunte ( vedi tasti sulla destra con due funzioni).
Per utilizzarle premere il tasto 2F, per uscire dalle seconde funzioni premere ancora il tasto 2F.

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