venerdì 15 dicembre 2017

ArduinoQuadro

- ArduinoQuadro - 

- 15/12/2017-

   Il progetto di calcolatrice con Arduino, si trasforma in ArduinoQuadro!! 

Progetto evoluzione del precedente post "Calcolatrice RPN "

Ho pubblicato un nuovo progetto con 48 tasti modificato e semplificato.



Materiale occorrente:

Arduino UNO
LCD 16x2 I2C
Tastierino a matrice 4x4.

Consultare il precedente post per schema collegamenti, e spiegazioni iniziali.


Rimane invariato lo schema e l'hardware.
_ Costo del materiale molto contenuto.
_ Calcolatrice  scientifica di tipo RPN.

Le novità in questo post!!



Ora la calcolatrice è programmabile!


Si possono programmare funzioni matematiche e trigonometriche disponibili anche in modo diretto.
E sono disponibili alcune funzionalità di Arduino.
Si potranno realizzare piccoli "sketch" senza dover utilizzare un PC.


Sono disponibili PIN DIGITALI  e  PIN ANALOGICI che possono essere utilizzati
per input output.

Si potrà scrivere un piccolo programma che potrà essere conservato nella EEPROM.

Una volta lanciata l'esecuzione il programma viene eseguito in modalità "interpetre".
 Non si esegue una compilazione quindi l'utilizzo come microcontrollore è limitato,
( sono limitati anche i pin disponibili ( da 0 a 7 sono utilizzati per il tastierino.)

Si potranno visualizzare risultati sul display LCD, immettere dati
dalla tastiera, e/o utilizzare i rimanenti pin disponibili  di Arduino, compresi gli analogici.

 ArduinoQuadro.

Queste alcune caratteristiche:

Programmazione diretta con la scrittura di piccoli programmi nel linguaggio
"Codice99".
Questo linguaggio appositamente preparato si basa su 99 codici che possono essere
scritti in ram e che successivamente l'interpetre utilizzerà per eseguire la relativa funzione.
Ad ogni codice corrisponde una funzione.
(Alcune funzioni avranno bisogno di più codici)
Ho lasciato disponibili alcuni codici per future versioni.
L'immissione del programma in ram avviene con un micro editor che consente
di scrivere il programma e rivederlo scorrendo le istruzioni ed eventualmente correggere errori.

Una volta scritto il programma potrà essere eseguito e/o salvato nella EEPROM
(salvandolo nella EEPROM rimane permanente fino alla cancellazione).

Questo arduino avrà alcuni registri speciali (catasta operativa)
X, Y, Z, T, U,  lastX.
Ci saranno alcuni registri di memoria che i programmi utente potranno utilizzare.



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

MEMORIE & INDICI = da 00 a 19 (questi codici vengono immessi prima della istruzione che li
                   utilizza. prima si imposta il numero e poi l'istruzione.
                   Es.  prima 01 poi 67 (STOnn) in questo caso il contenuto di x viene
                   memorizzato nel regisro mem1
                   Le istruzioni qui sotto con (*) DEVONO ESSERE PRECEDUTE DALL'INDICE
------------------------------------------------------------------------------------------------------------
I/O     = 20 PRINT    21 INPUT     da 22 a 29 disp
------------------------------------------------------------------------------------------------------------
ARDUINO  = 30 *PINPUT  31 *PIOUT  32 *DWHIGH  33 *DWLOW  34 *DREAD
                        35 *AREAD 36 *AWRITE 37 *DELAYn  38 *TONE    39 *NOTONE   
------------------------------------------------------------------------------------------------------------
CONTROLLO = 40 XmaggioreY? 41 XminoreY?  42 X = Y  43 X maggiore 0? 44 Xminore 0?
                            45 *INCn     46 END     47 LOOP   48  RTN      49 NOP
-------------------------------------------------------------------------------------------------------
MATEMATICHE = 50 (-) 51 (X) 52 (/) 53 (+)  54 CHS  55 Y^x  56 1/X  57  disp
                                 58 SQRT  59 disp
------------------------------------------------------------------------------------------------------
CATASTA e VARIE = 60 DEL  61 ENTER  62 CLST (clr) 63 LASTX  64 XscambioY
 65 RUOTA GIU'  66 CLX    67 *STOnn  68 *RCLnn   69 RUOTA SU R^
------------------------------------------------------------------------------------------------------
TRIGONOM e VARIE = 70 PI  71 SIN  72 COS  73 TAN  74 ASIN  75 ACOS
                                         76 ATAN         77 disp    78 disp      79 disp
--------------------------------------------------------------------------------------------------------------
ESEGUI e VARIE  =  80 SUB0 81 SUB1  82 SUB2    83 SUB3  84 SUB4  85 SUB5
                                    86 disp   87 disp     88 *XEQnn 89 disp
--------------------------------------------------------------------------------------------------------------
LABEL e VARIE  =  90 LBL0  91 LBL1  92 LBL2  93 LBL3  94 LBL4  95 LBL5
                                    96 disp   97 disp     98 disp     99 ENDEND
--------------------------------------------------------------------------------------------------------------

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

I programmi si scrivono semplicemente digitando il codice relativo alla funzione,
si dovranno immettere sempre 2 caratteri per digitare uno si scrive "01".


L'EDITOR visualizza un numero progressivo (linea programma).

Una volta scritto il programma si potrà controllare scorrendo (tasto 1 avanti)  - (tasto 3 indietro) le linee di programma.

E' possibile correggere gli errori.

Finito il controllo è possibile salvare il programma in memoria.
(in questo modo ad una successiva accensione si potrà utilizzare il programma)



Qui sotto il loop principale del programma.


//**************************************************************
void loop()
{
  inizializzazione(); // inizializzazione
  iniarduino();


// scelte iniziali calcolatrice o arduQuadro menu
arduino();


 while(arduQuadro == true)
 {
   nuovoprog();    // scelta se NEW (scrivere nuovo programma )
                            //oppure OLD programma in RAM
   // finito la registrazione
   // del programma o il caricamento da RAM
 
   controllo(); // Si esegue il controllo e correzione
 
   costanti();   // Possiamo inserire dati nei registri

   stringhe();  // per inserimento stringhe

   // pronto e si mette in attesa pressione tasto
   pronto();
   tasto();


   // Esegue il programma utente
    progUtente();

  // uscita dal programma utente
   fineprog();

 }
// esegue come calcolatrice diretta
 if (calcRPN == true) {uscitacalc = false;calcolatrice();}

}

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

dopo l'inizializzazione apparirà sul display questo menù, che ci chiede di scegliere fra
CALC (calcolatrice manuale) oppure arduQ ( uso in programmazione )

void arduino()
{
//stringaMenu0 = String("1234567890123456");
  stringaMenu0 = String("arduinoQuadro-13");
  stringaMenu1 = String("1=CALC 3= arduQ ");
sceltemenu();
if (old == true){arduQuadro = true; calcRPN = false;} // si programma come arduQuadro
  else {arduQuadro = false; calcRPN = true;}/// si usa come calcolatrice
}


Se si sceglie 3 (arduQ) si trova una ulteriore richiesta, se utilizzare il programma in memoria o scrivere un nuovo programma.




// con questa si esegue un programma esistente
// si corregge un programma esistente
// oppure si sceglie di scriverne uno nuovo
void nuovoprog()
{
stringaMenu0 = String("Menu programma  ");
stringaMenu1 = String("1=NEW  - 3=OLD");    **A
sceltemenu();
if (old == true){leggiprog();} // con old a true si legge il programma dalla EPROM
if (old == false) {scritturaprog();} // con old false si scrive nuovo programma
}


Se si sceglie NEW si scriverà un nuovo programma con l'editor.
(si scrivono i codici delle istruzioni ogni codice 2 cifre )
in questo caso si vedrà sul display
 lcd.print("C.. ");

ed ad ogni codice inserito il numero linea ed il codice
Per finire premere 2 volte il tasto (2F)


Secelta **A
OLD  il programma prosegue richiamando il programma esistente e riprende dal controllo e correzione.

Alla richiesta di controllo  possiamo scegliere se effettuare un controllo del programma in memoria oppure no.

Con l'editor possiamo scorrere le istruzioni avanti tasto (1) indietro tasto (3)
Possiamo correggere un'istruzione errata, ed è possibile inserire istruzioni.
( vedi più avanti spiegazioni uso editor )

Alla fine del controllo possiamo salvare il programma corretto
appare il messaggio " Salva in RAM"


Dopo questa fase possiamo inserire dati.
Per inserire dati nella catasta si opera in modo consueto come con la calcolatrice in modo diretto

Per inserire i dati nelle memorie utente occorre inserire il dato in X e nella linea visore il numero da 1 a 19 del registro che vogliamo utilizzare.




void costanti()
{
stringaMenu0 = String("Ins.  Dati ? ");
stringaMenu1 = String("1= SI - 3= NO");
sceltemenu();
 if (old == true){return;} // salta inserimento dati

// inseimento dati valori
dati = true;
while ( dati == true)
{
aggiornadisplay(); // sub che aggiona il display
tasto();
insertdati();

if (codice == 62){dati = false;}
}
lcd.clear();
lcd.setCursor(0,0);
lcd.print("OK dati inseriti");
delay (1000);
}

Una volta risposto SI  (1) alla richiesta di inserire dati viene visualizzato la riga X e sotto la riga visore come nell'uso come calcolatrice.
Si può inserire le cifre e con Enter si passano nella catasta operativa ( si possono usare per l'inserimento i registri della catasta  ( x,y,z,t,u) .... logicamente il programma dovrà essere scritto per utilizzarli tenendo conto delle operazioni in catasta.

E' possibile anche inserire dati nei registri dedicati all'utente da 1 a 19 ( sono float).

Per inserire un dato in questi registri si procede così:
  _ Prima si inserisce nel registro  X con Enter.

 _ Poi si inserisce nella riga visore  il numero del registro da 1 a 19 senza premere Enter

 _ Quindi premere il tasto (+) più ( apparirà  " OK " )

continuare così per tutti i dati da inserire

_  alla fine premere il tasto 2F  con il quale si esce da inserimento dati, appare il messaggio

" OK dati inseriti"



Il programma chiederà se inserire stringhe.... ( per ora Una stringa )
Questa funzione è molto limitata si possono introdurre i codici ASCII ( solo minori di 99)
per formare una stringa MAX 16 caratteri che utilizzeremo nella PRINT

Questa funzione non è molto funzionale (ma la tastiera disponibile è limitata) penso di realizzare una versione con una tastiera più dotata e quindi semplificando l'immissione dei programmi e delle stringhe.

dopo questa fase il programma attende la pressione di un tasto e si avvia.
(si può lanciare in esecuzione anche un loop continuo che si ferma solo togliendo alimentazione o premendo il reset di arduino)


Al termine del programma UTENTE si potrà scegliere se continuare in programmazione o passare alla calcolatrice in uso manuale (STOP)

void fineprog()
{
stringaMenu0 = String("Fine programma");
stringaMenu1 = String("1=STOP  3=CONT"); // si stop
sceltemenu();
if (si == true) {calcRPN = true; arduQuadro = false;}

}

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

Qui descrivo l'uso diretto della calcolatrice 

Uso diretto si usano le funzioni dirette e seconde ( 2F)

In modo del tutto analogo al precedente post.
Per uscire dall'uso diretto premere 2 volte il tasto 2F.

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     Cancella il contenuto del visore.


F2   Tasto seconda funzione abilita la seconda funzione.
Questo tasto è utilizzato anche per altre funzioni nel programma (vedi note per F2)


----------------------------------------------------------------------------------
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 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 (1 a 19) quindi premere il tasto funzione. Il contenuto di x rimane in x e viene duplicato nel registro indicato.
La stessa modalità si può utilizzare in programmazione:
1 inserire indice es : 01
2 inserire il codice  : 67 
queste due righe di programma memorizzano il contenuto di x nel registro utente 01.

RCL: Richiama in X il contenuto del registro ( da 1 a 19), 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.
La stessa modalità si può utilizzare in programmazione:
1 inserire indice es : 02
2 inserire il codice  : 68 
queste due righe di programma richiamano in x il valore contenuto nel registro indice 02.

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.
Non programmabile

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.
La stessa modalità si può utilizzare in programmazione:

------------------------------------------------------------------------------------------
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.
In programmazione queste si possono chiamare più semplicemente con il codice relativo:


4 e 5 converte angoli sesagesimali in sessadecimali e viceversa

richiama la costante PI (pigreco) anche questa nella libreria.
In programmazione si può digitare il codice 71:

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.
-------------

****   P R O G R A M M A Z I O N E  ****


Descrizione delle funzioni programmabili e relativi codici:

Codici da 1 a 19 --- INDICI  si inseriscono nel programma prima della funzione che ne farà uso.

20 ---  PRINT  scrive sul display nella prima riga X= ......   e sotto la stringaUTENTE  (che può anche essere vuota) 

21 --- INPUT    si possono inserire dati nei registri e nella catasta.

-----------------------------------------------------------------------------------------------------
Istruzioni funzioni "Arduino"

30 --- PINPUT   deve essere preceduta dal numero del pin da porre come Input.

31 --- PIOUT   deve essere preceduta dal numero del pin da porre come Output.

32 --- DWHIGH   deve essere preceduta dal numero del pin da porre ALTO (1).

33 --- DWLOW   deve essere preceduta dal numero del pin da porre BASSO (0).

34 --- DREAD   legge il valore 0/1 del pin indicato nell'istruzione che la precede.

35 -- AREAD  legge il valore analogico del pin indicato nell'istruzione che la precede.

36 -- AWRITE   scrive sul pin indicato il valore (0 -255) contenuto in x.

37 -- DELAY n  scrivere prima uno dei seguenti indici :
                         1 = 5 mms, 2= 10, 3= 50, 4= 250, 5=500, 6 = 1000 mms
                         poi il codice 37 ed avremo un Delay del tempo indicato
                         per tempi diversi ripetere l'istruzione

38 -- TONE      TONE (PIN,FREQUENZA,DURATA)
                                / indirizzo per pin 
                                  nel regx la frequenza (intero)
                                // in regy se zero ( per fermare occorre la NOTONE)
                                // oppure inserire in y la durata in mms.

39 -- NOTONE    per fermare la TONE indicare il pin da fermare. 
                             (prima di attivare un pin occorre fermare il pin che esegue TONE)

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

Istruzioni di controllo  ( IF )
Queste istruzioni eseguono il controllo,
 il programma salta l'istruzione successiva  SE VERA la condizione.

I controlli sono: 40  XmaY , 41  XmiY , 42  X=Y , 43  Xma0 ,  44  Xmi0 .

45 -- INCn      per simulare il for.   Inserire un codice da 1 a 6 seguito dalla istruzione INCn (45).
                                Questa istruzione mette a disposizione 6 variabili di tipo intero,
                        inc1, inc2 ecc.. In fase di inserimento dati del programma queste
                        variabili si inizializzano con un valore da raggiungere ( target).
                        Nello stesso momento si pone a 0 le corrispondenti variabili
                         cont1, cont2 ecc.. che serviranno per il conteggio.
 
                       Tasto (  - )   durante la fase di Inserimento Dati
                        ( vedi spiegazione tasti funzione più sotto)

                       Nella fase di elaborazione la variabile cont(n) viene incrementata di 1 ad ogni
                       ciclo, nel registro regx viene posto il cont attuale, ed in regy viene posto inc(n).
                       Ora si può fare un controllo X con Y per verificare se il target è stato raggiunto.     
                   
46  --  END    con questa si indica la fine del programma. Quando il programma trova questa                                      istruzione esce dall'esecuzione ed è disponibile per l'uso diretto.

47 --  LOOP   questa istruzione se inserita crea un loop continuo il programma non termina.

La prima esecuzione del programma parte sempre dall'istruzione 0, se la loop è inserita come prima istruzione il programma riparte sempre da 0, altrimenti dopo la     prima esecuzione le successive ripartono dalla riga loop.
Questo rende possibile eseguire un loop successivo ad una fase simile ad un setup.

48 --  RTN     istruzione di fine subroutine.

Il programma torna alla riga successiva alla chiamata della  corrispondente label.
Se questa istruzione non viene inserita il programma prosegue fino all'ultima istruzione.


49 -- NOP       non operazioni

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

Matematiche
                       50 (-),   51 ( * ),   52 ( / ),   53  ( + ) 

54 --  CHS   cambia segno al registro regx.

55 --  Y^x     eleva il contenuto di regy  alla potenza indicata in regx il risultato in regx.

56 --  1/X      uno su X  ( esegue l'operazione 1/x  il risultato nel regx)

57 --   disp

58 --  SQRT   salva X in lastx  e poi calcola la  radice quadrata di X risultato in regx .

59 --  disp

-------------------------------------------------------------------------------------------------------------------------
Operazioni catasta.

60 --  DEL     cancella  "Visore"  ( linea per inserimento dati ).

61 --  ENTER      fa salire la catasta operativa ed introduce il contenuto del "Visore" nel registro
                             regx  poi azzera il visore.

62 -- CLST       cancella la catasta compreso lastx ed il visore.

63 --  LASTX     nel registro regx ritorna il valore di lastx e sale tutta la catasta.

64 -- X_Y         scambio fra regx e regy.

65 -- R!              ruota la catasta GIU'

66 -- CLX         azzera il registro x  (prima salva il contenuto nel registro lastx)

67 -- STOnn    introduce nel registro nn (indicato da indice ) il contenuto del regx.

68 -- RCLnn    richiama dal registro nn (indicato da indice ) e pone il contenuto nel registro regx                                 facendo salire la catasta.

69 --  R^          ruota la catasta SU

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

Trigonometriche

70 --  PI      costante PI (pigreco) viene richiamate nel regx. (prima salva il contenuto di x in lastx)

71 -- SIN      prima salva in lastx il registro x e poi calcola la funzione.

72 -- COS    prima salva in lastx il registro x e poi calcola la funzione.

73 -- TAN    prima salva in lastx il registro x e poi calcola la funzione.

74 -- ASIN   prima salva in lastx il registro x e poi calcola la funzione.

75 -- ACOS   prima salva in lastx il registro x e poi calcola la funzione.

76 -- ATAN   prima salva in lastx il registro x e poi calcola la funzione.

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

Chiamata a SUB

da codice 80 a 85   SUB0, SUB1, SUB2, SUB3, SUB4, SUB5.

Questi codici indirizzano il programma sulla linea della relativa label.

Label da 90 a 95  LBL0, LBL1, LBL2,LBL3, LBL4, LBL5.

Quando il programma si sposta sulla label chiamata esegue le funzioni fino a trovare RTN
quando trova RTN torna all'istruzione successiva che ha chiamato la SUB, altrimenti prosegue fino alla fine del programma.

All'interno di una SUB è possibile chiamare altre sub fino ad un massimo di 6 nidificazioni.

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

88 --  XEQnn      con questa si può chiamare una funzione od un programma.
                             Impostare nel visore il numero della funzione e/o programma e chiamare il
                             codice 88 (nella catasta o nei registri dovranno esserci già impostati i relativi dati                                 per il calcolo.
                             Per esempio (funzione R-P  da rettangolari a polari), posso impostare la coordinata                               X e la coordinata Y nei rispettivi registri poi nel programma indicherò
                            10 (numero di questa funzione) seguito da 88 ed avrò come risultato
                             in regy il vettore distanza, ed in regx l'angolo in radianti.
         
                              Questo codice XEQnn in pratica aggiunge molte altre possibili funzioni,
                               io ne ho preparate alcune ma altre possono essere fatte dall'utente per sua
                               comodità o per scopi specifici.


99 -- ENDEND    fine del listato di programma (ultima istruzione).

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

Tasti con funzioni multiple:

F2  ( tasto seconda funzione )

Se la calcolatrice è in uso diretto con la pressione del tasto si passa alle funzione secondarie dei tasti
( * ) , ( / ),  SIN, COS ecc.... 
Premendo mentre siamo in 2F ( si vede dal visore con il 2 a sinistra) si esce dalla calcolatrice manuale e si riparte dal menù iniziale con la richiesta di scegliere fra arduQ o CALC.

Quando siamo in programmazione nell'EDITOR premendo F2 si indica la fine di scrittura del programma e si passa alla fase successiva.

Quando siamo in "Controllo" serve per uscire.

In fase di inserimento dati o stringhe serve per uscire.

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

Tasto  ( - )   durante la fase controllo.

Si può correggere la linea di programma.
_ posizionarsi sulla riga da correggere
_   premere il tasto - (meno) e poi inserire il codice corretto,  apparirà correzione OK.
_  Questo serve solo a sostituire una istruzione errata, il resto del programma rimane invariato.
_  Se serve cancellare la riga è sufficiente inserire una NOP ( 49) che non altera il programma.

Tasto ( + )   durante la fase di controllo.

Con questo tasto si può inserire una nuova linea di programma. Tutto il programma si sposta dalla riga inserita in poi fino all'ultima.

_ posizionarsi con i tasti 1-3 sulla riga dove vogliamo inserire nuovo codice
_  si preme (+ )
_  ci chiede d'impostare il nuovo codice da inserire, inseriamo il codice
_   quindi sposta tutte le linee aggiungendo una riga al programma.
_  segnala con messaggio "correzione ok"

Per vedere la correzione spostarsi con i tasti 1-3.
        
In fase di controllo i tasti  ( 1 )  e  ( 3) servono per scorrere le istruzioni avanti e indietro.

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

Tasto ( + )   durante la fase di Inserimento Dati  ( STOnn ) 

Dopo aver inserito in X il dato da memorizzare inserire in visore il registro desiderato e quindi
premere  ( + ),  nel registro nn viene inserito il valore.

Tasto (  - )   durante la fase di Inserimento Dati  ( INCn)

Si può inserire il valore target del FOR in X ed nel visore il numero da 1 a 6 dei cicli possibili
poi premere il tasto ( - ).
Usare valori interi in ogni caso i registri utilizzati sono interi.

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

Programmi UTENTE

La programmazione con i codici qui proposta non è il massimo di semplicità ed immediatezza,
ma ho cercato di rendere disponibili le opzioni più comuni in un linguaggio di programmazione.

Le linee di programma attualmente previste sono 100. 

Le label sono 6 ( possono essere chiamate più volte)



Le label LBL sono solo 6 e non possono essere inserite più volte nel programma.

Da una SUB  si può chiamare altra SUB ma non se stessa.

Le IF di controllo possono essere fatte solo fra X e Y oppure fra X e 0.

Se il risultato del controllo è VERO salta l'istruzione successiva.

Il ciclo FOR è semplificato dalla INCn che mette a disposizione 6+6 variabili di tipo intero per il conteggio dei cicli. 
Le variabili intere inc1, inc2, ...., inc6 contengono il valore da raggiungere, le variabili corrispondenti
con1, cont2, ... cont6  conterranno i valori incrementati, l'incremento è fisso di 1.

Per questi programmi occorre scrivere le varie istruzioni, poi scriversi i relativi codici, e poi inserirli.

Ho preparato alcuni esempi per meglio spiegare l'uso di questa calcolatrice.

Esempi di programmi in "codice99"

Considero che già utilizzate la calcolatrice in modo manuale ed abbiate ben chiaro come utilizzare la catasta operativa  RPN.
In caso contrario date una lettura al precedente post

SKETCH – lampeggio di due led e beep con buzzer.  ( PRIMO)
Riga
istruzione codice
note
0
9 9
pin digitale 9 collegato al Buzzer
1
PIOUT 31
il pin 9 in OUTPUT
2
8 8
pin digitale 8 collegato al led
3
PIOUT 31
il pin 8 in OUTPUT
4
10 10
pin digitale 10 collegato al led
5
PIOUT 31
il pin 10 in OUTPUT
6
LBL0 90
Label 0
7
8 8

8
DWHIGH 32
il pin 8 si porta alto HIGH
9
9 9

10
TONE 38
si esegue TONE (in x 800 freq, in y 600 durata)
11
5 5
valore per delay ( 500 mms)
12
DELAY 37
esegue DELAY
12
8 8

14
DWLOW 33
il pin 8 si porta basso LOW
15
10 10

16
DWHIGH 32
il pin 10 si potra alto HIGH
17
9 9

18
TONE 38
esegue TONE sul pin 9
19
5 5

20
DELAY 37
esegue DELAY
21
10 10

22
DWLOW 33
il pin 10 si porta basso LOW
23
SUB0 80
SUB 0 ( va alla riga 6 codice 90 )
24
END 46
END programma
25









Questo esempio fa lampeggiare due led ed attiva il buzzer.
Si utilizzano i pin 8, e 10 per il led ed il pin 9 per il buzzer.

Prima si mettono in output i pin ( righe da 0 a 5 ) si indica il numero del pin seguito dall'istruzione PIOUT.

alla riga 6 si trova la label 0 LBL0 (codice 90)

Poi si accende un led si esegue un TONE ( in fase di inserimento dati ho introdotto 600 in Y ( durata del Tone, e 800 in X frequenza.

L'istruzione 12 esegue un Delay di 500mms

Quindi l'istruzione 14 spenge il led.

Poi si fanno le stesse cose con il secondo led.

Quindi all'istruzione 23 si trova la SUB0 che indirizza il programma sulla LBL0 riga 6
si entra così in LOOP che ripete le stesse istruzioni fino al reset della calcolatrice.

Allego un piccolo video dimostrativo.

Esempio di uso delle sub.

SKETCH – lampeggio di due led utilizzando due sub  (SECONDO)
Riga
istruzione codice
note
0
8 8
pin digitale 8 collegato al led
1
PIOUT 31
il pin 8 in OUTPUT
2
10 10
pin digitale 10 collegato al led
3
PIOUT 31
il pin 10 in OUTPUT
4
LBL0 90
Label 0
5
SUB1 81
SUB 1 SI ESEGUE LA Sub va alla LBL1
6
NOP 49
inserite per indicare possibili altre istruzioni
7
NOP 49

8
SUB0 80
SUB 0 ( va alla riga 4 codice 90 ) LOOP
9
END 46
END programma
10
LBL1 91
inizio SUB1
11
8 8

12
DWHIGH 32
il pin 8 si porta alto HIGH
12
5 5
valore per delay ( 500 mms)
14
DELAY 37
esegue DELAY
15
8 8

16
DWLOW 33
il pin 8 si porta basso LOW
17
SUB2 82
SUB2 esegue la sub va alla LBL2
18
NOP 49
inserite per indicare possibili altre istruzioni
19
NOP 49

20
RTN 48
Torna a riga seguente la SUB1 (6)
21
LBL2 92

22
10 10

23
DWHIGH 32
il pin 10 si potra alto HIGH
24
5 5

25
DELAY 37
esegue DELAY
26
10 10

27
DWLOW 33
il pin 10 si porta basso LOW
28
RTN 48
Torna a riga seguente la SUB2 (18)







Uso i due led collegati ai pin 8 e 10.
Il programma del tutto simile al precedente serve solo a dimostrare l'uso delle sub.
La sub1 (LBL1 riga 10) fa accendere e spengere il led collegato al pin 8.
All'interno della sub1 viene chiamata la sub2 (LBL2 riga 21), questa sub fa accendere e spengere il led collegato al pin 10.
La sub2  quando trova RTN ritorna alla sub1 e a sua volta quando la sub1 trova RTN torna al programma principale.
IL programma principale continua eseguendo il loop fra la riga ( 4 LBL0 e la riga 8 SUB0).

In questi due sketch ho utilizzato un loop continuo ( per uscire occorre il reset della calcolatrice.)



Nel prossimo sketch faremo eseguire un numero determinato di cicli.
Qui si utilizza la funzione INCn che simula il FOR .
Il programma aggiunge rispetto al precedente 3 istruzioni

6  01        01   Questa indica quale INCn useremo
7  INCn   45  ad ogni passaggio la variabile cont1 viene incrementata
8  X=Y?  42  controlla se abbiamo raggiunto il target immesso nella fase ins dati.

con queste istruzioni si esegue il programma per un numero di volte da noi voluto
(nel campo int )

Arrivati al numero scelto il programma termina.

Se si esegue una seconda volta il programma occorre reinserire il valore target nella fase Inserimento dati.

SKETCH – lampeggio di due led utilizzando due sub ( TERZO)
Riga
istruzione codice
note
0
8 8
pin digitale 8 collegato al led
1
PIOUT 31
il pin 8 in OUTPUT
2
10 10
pin digitale 10 collegato al led
3
PIOUT 31
il pin 10 in OUTPUT
4
LBL0 90
Label 0
5
SUB1 81
SUB 1 SI ESEGUE LA Sub va alla LBL1
6
1 1
si usa la INC 1
7
INCn 45
ad ogni passaggio incrementa il contatore
8
X=Y? 42
controlla se abbiamo raggiunto il target
9
SUB0 80
SUB 0 ( va alla riga 4 codice 90 ) LOOP
10
END 46
END programma
11
LBL1 91
inizio SUB1
12
8 8

13
DWHIGH 32
il pin 8 si porta alto HIGH
14
5 5
valore per delay ( 500 mms)
15
DELAY 37
esegue DELAY
16
8 8

17
DWLOW 33
il pin 8 si porta basso LOW
18
SUB2 82
SUB2 esegue la sub va alla LBL2
19
NOP 49
inserite per indicare possibili altre istruzioni
20
NOP 49

21
RTN 48
Torna a riga seguente la SUB1 (6)
22
LBL2 92

23
10 10

24
DWHIGH 32
il pin 10 si potra alto HIGH
25
5 5

26
DELAY 37
esegue DELAY
27
10 10

28
DWLOW 33
il pin 10 si porta basso LOW
29
RTN 48
Torna a riga seguente la SUB2 (18)







La funzione INCn vista sopra può essere fatta anche con istruzioni in codice99 con qualche istruzione in più.

Prova di funzionamento:

Utilizzate il pin digitale 09 per il LED ed il pin analogico A1 per collegare la fotoresistenza.
(nell'immagine qui sotto il filo verde è erroneamente posizionato sul pin A0 ) .

Dovrete inserire un valore in Y che corrisponda alla soglia di luce alla quale si deve accendere il led.








Vediamo il diagramma di flusso.


In questo sketch si legge un pin analogico  A0 il valore  letto va in X viene confrontato con il valore che abbiamo in Y (inserito nella fase "Inserimento dati" ) e se maggiore esegue l'istruzione successiva quindi torna a leggere un nuovo valore, questa fase si ripete fino a quando il valore X non risulta minore di Y ( loop corto).

Quando la luce diminuisce e X risulta minore del valore immesso in Y  salta l'istruzione e prosegue accendendo il led e tornando alla partenza e così rimane fino a quando non cambia ulteriormente la luce ambiente ed il valore di X risulta MAGGIORE di Y.

Lo sketch ripete il loop fino al reset della calcolatrice.

Se avete salvato il programma nella EEPROM potrete richiamarlo e magari provare ad inserire in Y un valore diverso come soglia di luce.

SKETCH – simil WHILE  (QUARTO)
Riga
istruzione codice
note
0
9 9
pin digitale 9 collegato al led
1
PIOUT 31
il pin 8 in OUTPUT
2
LBL0 90
Label 0
3
1 1
PIN A1
4
AREAD 35
legge il valore analogico sul pin A1
5
X 42
in Y avremo impostato un valore (ES= 90)
6
SUB0 80
SUB 0 ( va alla riga 2 codice 90 ) LOOP
7
9 9
pin digitale 9 collegato al led
8
DWHIGH 32
il pin 9 si porta alto HIGH
9
5 5
valore per delay ( 500 mms)
10
DELAY 37
esegue DELAY
11
9 9
pin digitale 9 collegato al led
12
DWLOW 33
il pin 9 si porta basso LOW
13
SUB0 80
SUB 0 ( va alla riga 2 codice 90 ) LOOP
14
END 46
FINE PROGRAMMA
15








Credo che con gli esempi fatti si possa capire come utilizzare questa calcolatrice.

Sul mio canale YouTube trovate un video su questa calcolatrice.



                                                           


Il listato per Arduino che allego è funzionante ma non ho testato tutte le possibilità.
La gestione degli errori nei programmi utente non è stata implementata.
In caso di errori o loop infiniti rimane solo la possibilità di reset.

Questo il messaggio dell' IDE dopo la compilazione.
Lo sketch usa 26.478 byte (82%) dello spazio disponibile per i programmi. Il massimo è 32.256 byte.
Le variabili globali usano 1.200 byte (58%) di memoria dinamica, lasciando altri 848 byte liberi per le variabili locali. Il massimo è 2.048 byte.

Come si vede c'è ancora spazio per aggiunte e o modifiche allo sketch, sono graditi commenti o segnalazioni di errori.





Sergio.


Il listato dello sketch


/* ****************************
   SERGIO & ADRIANO PRENLELOUP
   23/12/2017
   file= arduinoQuadro-14
   
--------------------------------------------------------------------------
Con questo sketch si realizza una calcolatrice programmabile, che potrà 
fare calcoli diretti, programmi utente con funzioni matematiche e trigonometriche,
sono disponibili PIN DIGITALI E PIN ANALOGICI che possono essere utilizzati
per input output.
Si potrà scrivere un piccolo programma che potrà essere conservato in ram.
Una volta lanciata l'esecuzione il programma viene eseguito dall'interpetre.
E si potranno visualizzare risultati sul display LCD, immettere dati
dalla tastiera, e/o utilizzare i pin disponibili  di Arduino.
In questo modo si realizza un "Arduino-arduino".
Queste le caratteristiche:
Programmazione diretta con la scrittura di piccoli programmi nel linguaggio
"Codice99".
Questo linguaggio appositamente preparato si basa su 99 codici che possono essere
scritti in ram e che successivamente l'interpetre utilizzerà per eseguire la relativa funzione.
Ad ogni codice corrisponde una funzione. 
(Alcune funzioni avranno bisogno di più codici)
L'immissione del programma in ram avviene con un micro editor che consente 
di scrivere il programma.
Rivederlo scorrendo le istruzioni e correggere errori.
Una volta scritto il programma potrà essere eseguito e/o salvato nella EEPROM
(salvandolo nella EEPROM rimane permanente fino alla cancellazione).
Questo arduino avrà alcuni registri speciali (catasta operativa)
X, Y, Z, T, U,  lastX.
Ci saranno alcuni registri di memoria che i programmi utente potranno utilizzare.

//**********************************************************************************************************
FUNZIONI PROGAMMABILI E RELATIVI CODICI.
MEMORIE & INDICI = da 00 a 19 (questi codici vengono immessi prima della istruzione che li
                   utilizza. prima si imposta il numero e poi l'istruzione.
                   Es.  prima 01 poi 67 (STOnn) in questo caso il contenuto di x viene
                   memorizzato nel regisro mem1
                   Le istruzioni qui sotto con (*) DEVONO ESSERE PRECEDUTE DALL'INDICE
------------------------------------------------------------------------------------------------------------
I/O     =  20  PRINT  21 INPUT  da 22 a 29 disponibili
------------------------------------------------------------------------------------------------------------
ARDUINO  = 30 *PINPUT  31 *PIOUT  32 *DWHIGH  33 *DWLOW  34 *DREAD  35 *AREAD 36 *AWRITE
           37 *DELAYn  38 *TONE    39 *NOTONE     
------------------------------------------------------------------------------------------------------------
CONTROLLO = 40 X>Y? 41 X<Y?  42 X=Y?  43 X>0?  44 X<0?  45 *INCn  46 END  47 LOOP 48 RTN 49 NOP
------------------------------------------------------------------------------------------------------------
MATEMATICHE = 50 (-) 51 (X) 52 (/) 53 (+)  54 CHS  55 Y^x  56 1/X  57  disp  58 SQRT  59 disp
-------------------------------------------------------------------------------------------------------------
CATASTA & VARIE = 60 DEL  61 ENTER  62 CLST (clr) 63 LASTX  64 X<>Y  65 RUOTA GIU' R!  
                  66 CLX  67 *STOnn  68 *RCLnn      69 RUOTA SU R^
--------------------------------------------------------------------------------------------------------------
TRIGONOM & VARIE = 70 PI  71 SIN  72 COS  73 TAN  74 ASIN  75 ACOS  76 ATAN  77 disp 78 disp 79 disp
--------------------------------------------------------------------------------------------------------------
ESEGUI & VARIE  =  80 SUB0 81 SUB1  82 SUB2  83 SUB3  84 SUB4  85 SUB5  86 disp 87 disp 88 *XEQnn 89 disp
--------------------------------------------------------------------------------------------------------------
LABEL & VARIE  =  90 LBL0  91 LBL1  92 LBL2  93 LBL3  94 LBL4  95 LBL5  96 disp 97 disp 98 disp  99 ENDEND
--------------------------------------------------------------------------------------------------------------
*********************************************************************************************                                        
HARDWARE
Si utilizza Arduino UNO, tastierino 16 tasti, display lcd 16x2 (I2C)
Possibilità di alimentazione a batteria.
*********************************************************************************************
*/
//***************************************
// librerie incluse
//---------------------------------------
// E' inclusa anche da sistema la <maht.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <Keypad.h>
#include <EEPROM.h>
//******************************************************************************************
//   E D I T O R dei programmi
//------------------------------------------------------------------------------------------
/*
I programmi si scrivono semplicemente digitando il codice relativo alla funzione, 
si dovranno immettere sempre 2 caratteri per digitare uno si scrive "01".
L'EDITOR visualizza un numero progressivo (linea programma).
L'eventuale inizializzazione di variabili o di costanti si utilizzerà la
funzione RCL con la quale si richiama il registro da 1 a 19.
Nella fase inserimento dati potremmo immettere questi valori.
Nell'inserimento dati possiamo utilizzare anche i registri della catasta, 
tenendo conto delle operazioni che svolgerà il programma
*/
//********************************************************************
const byte righe = 4;   // per keypad
const byte colonne = 4;
//********************************************************************
byte key; // contiene il codice tasto premuto
byte codice =0; // codice operativo calcolato a partire da key (codice asccii)
byte codProg = 0; // codici programma
byte indirizzo = 0; // per indirizzare le memorie, i pin, le sub.
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 looProg = false; // se true esegue loop
boolean se = true;  // per le funzion if
boolean xeq = true;  // per inserimento codice in Xeq_nn
boolean dati = true; // si inseriscono i dati in costanti
boolean prog = true; // si predispone per la programmazione
boolean sub = true; // per eseguire le subroutin
boolean endProg = false; // fine sub o programma
boolean stopProg = false; // per fermare il loop
boolean old = false; // per segnalare programma già in memoria risposta no
boolean si = true;  // risposta si nelle scelte
boolean gira = false; // per sapere se sta elaborando il programma false non elabora
boolean uscitacalc = false; // per uscire da caLCOLATRICE
boolean arduQuadro = false; // si lavora con arduino quadro se true
boolean calcRPN = false; // si lavora in calcolatrice se true
//-----------------------------------------------------------------
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
//*************************************************************************
// codici tastierino
//*************************************************************************
byte chiave [colonne][righe] = 
{
  {49,50,51,43},    // 1   2   3  +, *,  sto, ins-linea
  {52,53,54,45},    // 4   5   6  -, /,  inc, corr-linea
  {55,56,57,62},    // 7   8   9  2F , end-prog, esc, esc
  {61,48,46,60}     // En  0   .  del, Xeq
  
};
//---------------------------------------------------------------
//                   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); 
 //**********************************************
 //   ARRAY DEL PROGRAMMA
 //**********************************************
 byte programma[100];
 int riga = 0;
 int ultimariga = 100;
 
 int riga90 = 0;// qui si memorizza la riga inizio LBL
 int riga91 = 0;
 int riga92 = 0;
 int riga93 = 0;
 int riga94 = 0;
 int riga95 = 0;
 //----------------------------------------------------
 //  -----   variabili stak sub
  int rigasubA =  0;
   int rigasubB = 0;
   int rigasubC = 0;
   int rigasubD = 0;
   int rigasubE = 0;
   int rigasubF = 0;
   int rigasubG = 0;
   
   int rigasub = 0;
   int  rigaturn = 0;
 //----------------------------------------------------
 
 int rigaloop = 0; // punto di partenza dopo eventuale setup
 //------------------------
 //*** registri catasta
 float regx = 0.0;
 float regy = 0.0;
 float regz = 0.0;
 float regt = 0.0;
 float lastx = 0.0; // recupero del registro x
 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
 //****************************************************************************
  String stringaMenu0 =  String('              ');
  String stringaMenu1 =  String('              ');
  String stringaUtente = String('              ');
 //***********************
 //   memorie utente 
 //***********************
// registri per cicli for
 int inc1 = 0; int cont1 = 0; 
 int inc2 = 0; int cont2 = 0;
 int inc3 = 0; int cont3 = 0;
 int inc4 = 0; int cont4 = 0;
 int inc5 = 0; int cont5 = 0;
 int inc6 = 0; int cont6 = 0;
 //----------------------------
 //--------------------------
 
    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;
        
    
 //***********************
 
 
void setup()
{
  
  lcd.init();  // initialize the lcd 
  lcd.clear();
  lcd.backlight();
  lcd.setCursor(0,0);
  //lcd.print("1234567890123456");
    lcd.print("ArduinoQuadro 13");
  lcd.setCursor(0,1);
//lcd.print("1234567890123456");
  lcd.print("Dicembre 2017   ");
  
  delay (2000);  
}


//**************************************************************
//**************************************************************
void loop() 
{  
  inizializzazione(); // inizializzazione
  iniarduino();
 
// scelte iniziali calcolatrice o arduQuadro menu
arduino();
 
 
 while(arduQuadro == true) 
 {
   nuovoprog(); // scelta se NEW (scrivere nuovo programma ) 
   //oppure OLD programma in RAM
   // finito la registrazione 
   // del programma o il caricamento da RAM
   
   controllo(); // Si esegue il controllo e correzione
   
   costanti();// Possiamo inserire dati nei registri
   stringhe(); // per inseimento stringhe (da fare)
   // pronto e si mette in attesa pressione tasto
   pronto();
   tasto();
   // Esegue il programma utente 
   progUtente();
  // uscita dal programma utente
   fineprog();
 }
// esegue come calcolatrice diretta
 if (calcRPN == true) {uscitacalc = false;calcolatrice();}
 
}
//**** END LOOP ******************************************************
//********************************************************************
//******************************************
//******************************************
//**          F U N Z I O N I             **
//******************************************
//********************************************************************
void calcolatrice() // questa è un loop per utilizzare come calcolatrice
                    // manuale.  Per uscire (uscitacalc = true;)
{
while (uscitacalc == false)
{
aggiornadisplay(); // sub che aggiona il display

tasto(); // attende pressione tasto
//-------------------------------------------------------------
// ****** si controlla lo stato della calcolatrice 
//  che può essere  funzioni dirette o seconde funzioni 2F
if (stato == true)
 { // siamo in 2F )
   funzioni_seconde();
 }
if (stato == false)
 {// siamo nelle funzioni dirette
   funzioni_dirette();
   
  }
}
calcRPN = false;  // uscita da calcolatrice manuale
}
//***************** fine calcolatrice ******************************
// con queste si eseguono i comandi diretti da tastiera
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;
}
// ----  queste attivano le funzioni seconde della tastiera 2F (shift)
// vengono eseguite con la pressione del tasto 2F (shift) seguito dalla
// pressione del tasto relativo
//*********  SE VIENE PREMUTO 2F (SHIFT) SI ESCE DA CALCOLATRICE MANUALE
//**********  IN QUESTO CASO SI PASSA AL MENU' INIZIALE ARDU-QUADRO
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)
            {uscitacalc = true;}// uscita calcolatrice MANUALE
        
        if (codiceF2 == 70)// moltiplicazione
            {moltiplicazione();}
              
         if (codiceF2 == 72) //divisione
             {divisione();}
                      
                         
         if (codiceF2 ==  87) // Xeq esegue funzione da 1 a ...
           
        {Xeq_nn();} // questa esegue una delle funzioni richiamabili
                         
              
         if (codiceF2 ==  88)//Lastx ( recupera x )
               {last_x(); }
               
         if (codiceF2 ==  75)//  x<>y 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;            
}
//*********************************************************************
//******** ARDUINO QUADRO *********************************************
//*********************************************************************

 void inizializzazione()
  {
 
  lcd.clear();
  lcd.setCursor(0,0);
  lcd.print("Inizializzazione");
  delay (500); 
 //*******************************************************
  stringaMenu0 =  String("                ");
  stringaMenu1 =  String("                ");  
 //*******************************************************
 old = false; // per segnalare programma già in memoria risposta no
 si = true;  // risposta si nelle scelte
 gira = false; // se gira il programma va a true
 arduQuadro = false;
 calcRPN = false;
}
//****************************************************************
void iniarduino()
{
  stringaMenu0 =  String("                ");
  stringaMenu1 =  String("                ");
  // registri per cicli for
  inc1 = 0;  cont1 = 0;
  inc2 = 0;  cont2 = 0;
  inc3 = 0;  cont3 = 0;
  inc4 = 0;  cont4 = 0;
  inc5 = 0;  cont5 = 0;
  inc6 = 0;  cont6 = 0;
 
 //-------------------------------
       rigasubA =  0;
       rigasubB = 0;
       rigasubC = 0;
       rigasubD = 0;
       rigasubE = 0;
       rigasubF = 0;
       rigasubG = 0;
   
       rigasub = 0;
       rigaturn = 0;
  //------------------------------
 
 riga = 0;
 ultimariga = 100;
 
 riga90 = 0;// qui si memorizza la riga inizio LBL
 riga91 = 0;
 riga92 = 0;
 riga93 = 0;
 riga94 = 0;
 riga95 = 0;
 //-------------------
 //---------------------------------------------------
 rigaloop = 0;
 //----------------------------------------------------
 looProg = false; // se true esegue loop
 se = true;  // per le funzion if
 xeq = true;  // per inserimento codice
 dati = true; // si inseriscono i dati in costanti
 prog = true; // si predispone per la programmazione
 sub = true; // per eseguire le subroutin
 endProg = false; // fine sub o programma
 stopProg = false; // per fermare il loop
//-------------------------------------------------------------------- 
 old = false; // per segnalare programma già in memoria risposta no
 si = true;  // risposta si nelle scelte
 gira = false; // se gira il programma va a true
 
//-------------------------------------------------------------------- 
 
 
}
// con questa si sceglie se usare come
// calcolatrice RPN oppure come arduinoQuadro
// 
void arduino()
{
//stringaMenu0 = String("1234567890123456");
  stringaMenu0 = String("arduinoQuadro-13");
  stringaMenu1 = String("1=CALC 3= arduQ ");
sceltemenu();
if (old == true){arduQuadro = true; calcRPN = false;} // si programma come arduQuadro
  else {arduQuadro = false; calcRPN = true;}/// si usa come calcolatrice
}
void fineprog()
{
stringaMenu0 = String("Fine programma");
stringaMenu1 = String("1=STOP  3=CONT"); // si stop
sceltemenu();
if (si == true) {calcRPN = true; arduQuadro = false;}
}
// con questa si esegue un programma esistente
// si corregge un programma esistente
// oppure si sceglie di scriverne uno nuovo
void nuovoprog()
{
stringaMenu0 = String("Menu programma  ");
stringaMenu1 = String("1=NEW  - 3=OLD");
sceltemenu();
if (old == true){leggiprog();} // con old a true si legge il programma dalla EPROM
if (old == false) {scritturaprog();} // con old false si scrive nuovo programma
}

void sceltemenu()
{
lcd.clear(); 
lcd.setCursor(0,0);
lcd.print(stringaMenu0);
lcd.setCursor(0,1);
lcd.print(stringaMenu1);  
 boolean menu = true;
 old = false; // tasto 3 risposta no
 si = false; // tasto 1 risposta si
while (menu == true)
{
tasto();
if (codice == 49){si = true; menu = false;}   //  SI 
if (codice == 51){old = true; menu = false; } // NO
}
}
//-------------------------------------------------------
void pronto()
{lcd.clear(); 
lcd.setCursor(0,1);
lcd.print("Premi un 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;
 }
}
//*********************************************************************
void stringhe()// per inseimento stringhe (da fare)
{
  stringaMenu0 = String("Stringhe  ?  ");
  stringaMenu1 = String("1= SI - 3= NO");
sceltemenu(); 
 if (old == true){return;} // non si inseriscono stringhe
 
 // qui da fare inserimento stringhe
 
 inseralfa();
  }
//******************* EDITOR SCRITTURA PROGRAMMI UTENTE ******************
void scritturaprog()
// questa scrive e memorizza il programma UTENTE
{  
// cancellazione programma in memoria
for (int i = 0; i < 100; i++)
    {codProg = 0;
    EEPROM.write(i, codProg);
    }
//-------------------------------------
while ( prog == true)
   {
     inidisplay();  // editor scrittura codici
     editor();           
     prog = false;
   }

//********************************************************************
void inidisplay()
{
 //INIZIALIZZAZIONE EDITOR  
 lcd.init(); 
 lcd.clear();
  lcd.backlight();
  lcd.setCursor(0,0);
  lcd.print("ARDUINO EDITOR");
  lcd.setCursor(0,1);
  lcd.print("Inserire codice");
  delay (2000);
  lcd.clear();
  lcd.setCursor(0,0);
  lcd.print("C>: ");  
}
//********************************************************************

void editor() // QUI SI SCRIVONO I CODICI PROGRAMMA UTENTE
{
 riga = 0;
 int i=0;
 while ( i<100)
{
 
 impostacodice();
      
  programma[i] = codProg;
  
  riga = i;
  
  i = i+1;
  
  if (codice == 62) 
  {
    ultimariga = i;
   // programma[i] = 99;//ultimariga
    i = 100; 
  }
  editordisplay();
}
}
//***************************************************************************
//         F I N E SCRITTURA PROGRAMMA
//***************************************************************************

// CON QUESTA SI RIVEDE IL PROGRAMMA
//e consente la correzione di passi di programma
void controllo()
{
prelabora();  
stringaMenu0 = String("Controllo ?  ");
stringaMenu1 = String("1= SI - 3= NO");
sceltemenu(); 
 if (old == true){return;} // non esegue il controllo
// esegue il controllo 
lcd.clear(); 
lcd.setCursor(0,0);
//ultimariga = riga;
int c = 0;
while (c<ultimariga)
   {
      codProg = programma[c];
      riga = c;
      editordisplay();
      lcd.setCursor(0,1);
   // lcd.print("1234567890123456");
      lcd.print("cont> end> corr>");
      
      tasto();
        if (codice == 45) // correzione linea TASTO (-)
          {
            // scrivere la correzione
            // questo tipo di correzione sostituisce
            // la riga errata con altra corretta
            // lasciando invatiato il resto del programma
            //**  PER CANCELLARE INTRODURRE UNA NOP **** codice 49
            // la NOP non farà nulla e non altera il programma
            // ma occorre tener conto delle istruzioni precedenti o
            // seguenti che potrebbero utilizzare le informazioni
            // della riga cancellata (if, rcl, sto, pin ...)
             impostacodice();
             programma[c] = codProg;
             c = c-1; // per rivedere la correzione effettuata
                lcd.setCursor(0,1);
             // lcd.print("1234567890123456");
                lcd.print("correzione OK   ");
                delay (300);
          }
          
          if (codice == 43) // inserimento linea TASTO (+)
          {
                // si preme + (43) sul numero riga che si vuole inserire
                //  ci chiede d'impostare il nuovo codice da inserire
                //  quindi sposta tutte le linee aggiungento una riga
        
                int ins = c; // numero linea da inserire
                lcd.setCursor(0,1);
             // lcd.print("1234567890123456");
                lcd.print("ins new codice ");
                delay (300); 
                 impostacodice();
                int newCodice = codProg; 
             // aggiunge un posto all'array    
               ultimariga = ultimariga +1;
               int i = ultimariga;         
             // ciclo che parte dal fondo e sposta tutte le linee
             // fino alla riga da inserire  
               while (  ins < i )
                    {
                      programma[i] = programma[ i -1]; 
                      i = i-1;     
                     }
              // ora inserisce il nuovo codice al suo posto       
                 programma[ins] = newCodice;
              
              // conferma correzione    
                c = ins-1; 
                lcd.setCursor(0,1);
                lcd.print("correzione OK   ");
                delay (300);  
              }        
      
    //  tasti funzione 
          
        if (codice == 62){ c = ultimariga;} // esce dal controllo
        if (codice == 49) { c = c+1;}// avanti  (1)
        if (codice == 51) {c = c-1;} // indietro (3)
          
     
   }
salvaprog();
 // se vogliamo possiamo salvarlo nella EEPROM
}
//***************************************************************
 void salvaprog()     // si scrive il programma in memoria 
   {
    stringaMenu0 = String("Salva in RAM ");
    stringaMenu1 = String("1= SI - 3= NO");    
     sceltemenu();   
 if (old == true){return;}    
 if (old == false)
 { 
  for (int i = 0; i < ultimariga; i++)
    {codProg = programma[i];
    EEPROM.write(i, codProg);
    }
    lcd.setCursor(0,1);
 // lcd.print("1234567890123456");
    lcd.print("Salvataggio OK  ");
    delay (300);
    
  }
}
void leggiprog() // qui il codice per leggere il programma in memoria
{
lcd.clear(); 
lcd.setCursor(0,0);
lcd.print("Legge prog da RAM");  
    
for (int i = 0; i < 100; i++)
     { codProg = EEPROM.read(i);
       programma[i] = codProg;
     }
prelabora();  // predispone il programma letto da ram
}
//****************************************************************
void editordisplay()
{
lcd.clear(); 
lcd.setCursor(0,0);
lcd.print("n: ");
lcd.setCursor(4,0);
 lcd.print (riga);
 lcd.setCursor(10,0);
 lcd.print (codProg);
 if (codice == 62)
 {
 lcd.setCursor(0,1);
 lcd.print("fine programma");
 delay (3000);
 }
}
//*********************************************
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;

}
// 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 *-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
}

//*********************************************************
// con questa si inseriscono dati nei registri
//*********************************************************
void insertdati()
{
      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 == 43)// sto-n memorizza x nel reg indicato da visore
        
            {indirizzo = visore; sto_n();  lcd.print("  ok  "); delay (300);}
              
         if (codice == 45) // inserire in X numero da raggiungere, 
         // attenzione si usano interi 32767 -32768  
                       
                {gira = false; indirizzo = visore; inc_n();lcd.print("  ok  "); delay (300);}           
                  
             
         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) //fine dati
             { } 
  return;
}
void inseralfa()
{
      lcd.clear(); 
      lcd.setCursor(0,0);
      stringaUtente = ("");
    
   while (codice != 62)
    {
      impostacodice();
      char codAlfa = codProg;
      String stringa0 = String(codAlfa);
      stringaUtente =  String(stringaUtente + stringa0);
      lcd.clear(); 
      lcd.setCursor(0,0);
      lcd.print(stringaUtente);
     }
    alfadisplay(); 
      
  }

void alfadisplay()
{
lcd.clear(); 
lcd.setCursor(0,0);
lcd.print(stringaUtente);
 
 if (codice == 62)
 {
 lcd.setCursor(0,1);
 lcd.print("string  ok   ");
 delay (2000);
 }
}



void costanti()
{
stringaMenu0 = String("Ins.  Dati ? ");
stringaMenu1 = String("1= SI - 3= NO");
sceltemenu(); 
 if (old == true){return;} // salta inserimento dati
// inseimento dati valori 
dati = true;
while ( dati == true)
{
aggiornadisplay(); // sub che aggiona il display
tasto();
insertdati();
if (codice == 62){dati = false;}
}
lcd.clear(); 
lcd.setCursor(0,0);
lcd.print("OK dati inseriti");
delay (1000);
}
//***********************************************************************
//                 INTERPETRA ED ELABORA IL PROGRAMMA UTENTE
//***********************************************************************

void prelabora()
{
  //*********** PRE ELABORAZIONE *************************************
  // questa parte legge tutto il programma e cerca le LBL (90,91,92,93,94,95) 
  // cerca anche se esiste l'istruzione loop (47) in questo caso
  // pone a true la looProg ed il programma UTENTE continurà a girare
  // fino ad un reset esterno.
looProg = false;
rigaloop = 0;
for (int c = 0; c<ultimariga; c++) // prepara programma
     {codProg = programma[c];
      if ( codProg == 90){riga90 = c;} // memorizza inizio LBL
      if ( codProg == 91){riga91 = c;} 
      if ( codProg == 92){riga92 = c;}
      if ( codProg == 93){riga93 = c;} 
      if ( codProg == 94){riga94 = c;} 
      if ( codProg == 95){riga95 = c;}
      if ( codProg == 47){looProg = true; rigaloop = c;}// quando trova end riparte da rigaloop
      //if ( codProg == 99){ultimariga = c;}// memorizza l'ultima riga
     }
     
}
//**************************************************************************
void progUtente()
{
  gira = true;
  prelabora();
 //*************************************************************************
 //*************************** elaborazione programma **********************  
 //*************************************************************************
    if (looProg == true)
    { 
      int cloop = rigaloop;
        rigaloop = 0;
        cicloprogramma(); // esegue la prima volta il programma da zero
        rigaloop = cloop;
     }
     
     
      if (looProg == true)
        {  
          while (looProg == true)
          cicloprogramma(); // ora il programma gira sempre
         // interrupt
         // con pulsante
         // che ferma il loop 
         // mettendo looProg a false
         }
         else {cicloprogramma();}
         
  gira = false; // fine programma
  while(codice == 62)
 { 
   aggiornadisplay(); // sub che aggiona il display
   tasto();
   
  } 
}
//**************************************************************************
void cicloprogramma()
{
  int c = rigaloop;
   rigasub = 0; 
  
  codProg = 0;
 while (codProg != 46) // quando END esce
   {
     
      codProg = programma[c];
      riga = c;
      se = false;
 
 //----------------------------------------------------
 
       if ( codProg == 80){ rigasub = c; staksub(); c = riga90;}
       if ( codProg == 81){ rigasub = c; staksub(); c = riga91;}
       if ( codProg == 82){ rigasub = c; staksub(); c = riga92;}     
       if ( codProg == 83){ rigasub = c; staksub(); c = riga93;}
       if ( codProg == 84){ rigasub = c; staksub(); c = riga94;}
       if ( codProg == 85){ rigasub = c; staksub(); c = riga95;}
 //-----------------------------------------  
       
       
       
       if (codProg == 48){ stak(); c = rigaturn;}
                             
      eseguiprog();
      
      if (se == true) { c = c+1;} 
                     // se una if è vera torna true 
                       // e quindi si salta la riga successiva   
                       // altrimenti il prog continua normale
      
      c = c+1;
    }
   } 
 
 //*********************************************************
 //  ----   pila per le sub ----------
 
 void staksub() // fa salire in catasta stak delle sub il valore in rigasub
 { 
   rigasubG = rigasubF;
   rigasubF = rigasubE;
   rigasubE = rigasubD;
   rigasubD = rigasubC;
   rigasubC = rigasubB;
   rigasubB = rigasubA;
   rigasubA = rigasub;
 
 }
 void stak ()  // FA SCENDERE LO STAK E RESTITUISCE LA RIGA SUB
 {
   rigaturn = rigasubA;
   rigasubA = rigasubB;
   rigasubB = rigasubC;
   rigasubC = rigasubD;
   rigasubD = rigasubE;
   rigasubE = rigasubF;
   rigasubF = rigasubG;
 
 }
 
 
//******************************************
void eseguiprog()
{
  // esegue le funzioni
  funzioni();
  aggiornadisplay();
  
}
// ************************************************************************
//*************************************************************************
//************************************************
// queste sono FUNZIONI chiamate dal programma 
//***********************************************
// si distinguono dal "codice" che in questo caso diventa "codProg"
void funzioni() // ESEGUIBILI DA PROGRAMMA UTENTE
{
  // ------------------------------------------------
      if (( codProg >= 0) && ( codProg < 20))
          { indirizzo = codProg; visore = codProg;}
         // i numeri compresi da 0 a 19
         // sono indirizzi per le funzioni che li
         // richiedono stoxnn, rclxnn, pin ....
  //-------------------------------------------------
  
//  ****   per la PRINT da programma  
  if ( codProg == 20) // pulisce il display e scrive la stringa utente
                      //  attende la pressione di un tasto per continuare
                      // visualizza registro x 
          { 
lcd.clear(); 
lcd.setCursor(0,0);
lcd.print("X:");
lcd.setCursor(4,0);
lcd.print(regx);           
lcd.setCursor(0,1);            
lcd.print(stringaUtente);            
            
tasto();
           } 
           
//  ***  per effettuare input da programma           
           
if (codProg == 21) { costanti(); }  // inserimento dati
  //-------------------------------------------------
  //   *** ARDUINO  *****
  
         if (codProg == 30) //  pin nn input
             { pinMode ( indirizzo, INPUT);}
             
         if (codProg ==  31) // pin nn output
              { pinMode ( indirizzo, OUTPUT);}
           
               
         if (codProg ==  32) //--pin nn HIGH
             { digitalWrite( indirizzo, HIGH); }   
                             
          if (codProg == 33) //--pin nn LOW
             { digitalWrite( indirizzo, LOW); }
             
           if (codProg == 34)//-- legge il pin e inserisce il valore in x
            {regx = digitalRead (indirizzo );}
             
         if (codProg ==  35) //-- legge il pin ed inserisce il valore in x
            {
              int pin = 0;
               if (indirizzo == 0) {pin = A0;}
               if (indirizzo == 1) {pin = A1;}
               if (indirizzo == 2) {pin = A2;}
               if (indirizzo == 3) {pin = A3;}
            
            regx = analogRead(pin);}
            
          if (codProg == 36) // disponibile  
            { analogWrite (indirizzo, regx);  }
            
          if (codProg == 37) // delay 
            { delay_mm(); }  // in visore codice da 01 a 06 
            //1 = 5 mms, 2= 10, 3= 50, 4= 250, 5=500, 6 = 1000 mms
            
            if (codProg ==  38) //  TONE (PIN,FREQUENZA,DURATA)
                                // in indirizzo il pin nel regx la frequenza
                                // in y porre zero ( per fermare occorre la NOTONE)
                                // oppure inserire in y la durata 
             { if (regy == 0){ tone(indirizzo, regx);}
                   else {tone(indirizzo,regx, regy);}
             }      
                             
          if (codProg == 39) //
             { noTone( indirizzo); }
            
            
           
 //-----------------------------------------------------              
 //  **** CONTROLLO   ******
  
         if (codProg ==  40) //---controlla se x > di y
             {if ( regx > regy ){se = true;}}   
                             
          if (codProg == 41) //--- controlla se x < di y
              {if (regx < regy) {se = true;}} 
            
             if (codProg == 42) //---controlla se x =  y
                 {if (regx == regy){se = true;}}
             
         if (codProg ==  43) //----controlla se x è > di 0
             { if ( regx > 0){se = true;}}
           
               
         if (codProg ==  44)//--- controlla se x è < di 0
              { if ( regx < 0){se = true;}}   
                             
         if (codProg == 45)// 
             {inc_n(); } 
             
  //  ----    codici particolari ---------------------------------------
         
          if (codProg == 46) // END  FINE PROGRAMMA UTENTE
             {}// da inserire prima di eventuali sub
                              // esegue uscita dal programma
                              // se esiste l'istruzione loop
                              // rimanda alla rigaloop
                           
         if (codProg ==  47)// LOOP programma
            {} // memorizza la riga inizio loop
                              // del programma che puo essere diversa 
                              // dalla 0
               
         if (codProg ==  48)// RTN ritorno dalle sub
             {}   
                             
          if (codProg == 49)//
                {} // NOP  non fa nulla
             
        
 //--------------------------------------------------------------------             
 //   ******  MATEMATICHE   *****      
         
         
         if (codProg == 50) //sottrazione
             {sottrazione();}
             
         if (codProg ==  51) // moltiplicazione
            {moltiplicazione();}
           
               
         if (codProg ==  52) // divisione 
             {divisione();}   
                             
          if (codProg == 53)// somma
              {somma();}
                 
           
           if (codProg== 54) //cambia segno (moltiplica x per -1)
             {cambiasegno();}
            
             if (codProg == 55)  // potenza eleva y alla x  
              { lastx = regx; regx = pow (regy, regx); }      
           //pow(base, exponent)
          //base: numero (tipo float) 
          //exponent: la potenza a cui è elevata la base (tipo float)
          // si utilizza x ed y della catasta
        
        
            if (codProg == 56) // 1/x 
            {unosux();}
             
              if (codProg == 57) // intero di x
                 {}// {interox();}// da fare
             
              if (codProg == 58) // radice di x
             { lastx = regx; regx = sqrt (regx);}
             
             
              if (codProg == 59)// disponibile 
             { }
        
        
  //----------------------------------------------------------           
  //  *****   CATASTA OPERATIVA  *****
  
             
               if (codProg ==  60)// cancella 
                  {del();}
             
               if (codProg ==  61)// ENTER
                  {enter();} 
             
               if (codProg ==  62)// cancella registri e catasta
                    { cancella();}      //CLST
            
               if (codProg == 63) //Lastx ( recupera x )
                    {last_x(); }
               
               if (codProg ==  64)//  x<>y scambio x con y
                    {scambio();}
         
               if (codProg ==  65) // abbassa catasta R!
                  { ruota();}
            
               if (codProg ==  66)// cancella registo x
                  {lastx = regx; regx = 0.0;}
                   
               if (codProg ==  67)// memorizza x nel nn indicato nel precedente codice
                  {sto_n();}
                   
               if (codProg ==  68)// richiama in x nn indicato nel precedente codice
                  {rcl_n();}
               
               if (codProg ==  69)// ruota su catasta
                  { ruotaSU();  }
  //----------------------------------------------------------           
  //  ****   TRIGONOMETRICHE ANGOLO IN RADIANTI  *****
             
               if (codProg ==  70) // PI GRECO
                   { lastx = regx; regx = PI;}// richiama pigreco
                   
               if (codProg ==  71) // seno di x angolo in RADIANTI
                    {lastx = regx;  regx = sin (regx);}          
                
               if (codProg ==  72)// coseno  x  angolo in x in RADIANTI
                    {  lastx = regx; regx = cos (regx);}                    
              
               if (codProg ==  73)//tangente  x  angolo in x in RADIANTI  
                    {  lastx = regx; regx = tan (regx);}        
         
          if (codProg ==  74)// arco seno di x  
              {arcosen_x();} 
          if (codProg ==  75)// arco coseno di x  
              {arcocos_x();}      
          if (codProg ==  76)// arco tangente di x  
              {arcotan_x();} 
//---------------------------------------------------------------     
//  ****   FUNZIONI PER FLUSSO SUB GOTO  *****
//  la 88 Xeq_nn richiama altre funzioni aggiuntive
             
         if (codProg ==  80) 
              {  }// chiamata sub0  (90)
                   
         if (codProg ==  81) 
              {  }  // chiamata sub1  (91)     
                
         if (codProg ==  82)
             {  }    // chiamata sub2  (92)              
         
             
         if (codProg ==  83) // // chiamata sub3 (93)
              {  }
                   
         if (codProg ==  84) // // chiamata sub4 (94)
              {  }     
                
         if (codProg ==  85) // // chiamata sub5 (95)   
              {  } 
         
         if (codProg ==  86) // disp
              {  }
                   
         if (codProg ==  87) // disp
              {  }          
                
         if (codProg ==  88) // esegue la funzione nn da 1 a nn
               { Xeq_nn();}                    
              // alle funzioni scritte se ne possono aggiungere
              //  altre.          
         if (codProg ==  89) // disp
              {  }          
//---------------------------------------------------------------               
//  ****  funzioni flusso LABEL  DELLE SUB E DEL GOTO  *****
// LA 99 END-END chiude il programma 
             
         if (codProg ==  90) 
              { }// label  LBL0
                   
         if (codProg ==  91) // label
              {}          
                
         if (codProg ==  92)// label
             {  }                    
              
              
          if (codProg ==  93) // label
              { }
                   
         if (codProg ==  94) // label 
              {}          
                
         if (codProg ==  95) // label
             {  }            
        
         if (codProg ==  96) // DISP
              {}          
                
         if (codProg ==  97) // DISP 
             {  }            
        if (codProg ==  98) //  DISP
              {}          
                
         if (codProg ==  99) // end-end
             {codProg = 46; } // end        
        
//----------------------------------------------------------------    
              
  return;
}// fine chiamata funzioni di programma utente
//****************************************************************
//****************************************************************
//****************************************************
// ESEGUE LE FUNZIONI CHIAMATE
//**************************************************** 
//****************************************************************
// parte intera di un numero si scrive su visore
void impostacodice()
{
   xeq = true;
   
   while(xeq == true)
   {
   byte cifra = 0;
   byte cifra2 = 0;
   
   tasto();
   if (codice == 62){xeq = false;}
   
      if ((codice  >= 48) && (codice <= 57 ))
     
          {
           cifra =  codice - 48;   
          } 
   
   tasto();
       if (codice == 62){xeq = false;} 
       
          if ((codice  >= 48) && (codice <= 57 ))
          {
           cifra2 =  codice - 48; 
           codProg = cifra*10 + cifra2;
               if ((codProg >= 0 )&& (codProg < 100))
                  {xeq = false;}         
          } 
   
         
   if (codice == 43){}  
   if (codice == 45){}
   if (codice == 46){}
   if (codice == 60){}
   if (codice == 61){}
   }
}
//---------------------------------------------------------------
  
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;}
        
}
//----------------------------------------------------------
//***************************************************************



void unosux() //
{
  if (regx == 0)return;
  regx = ( 1 /regx);
}

void somma()// 
{
  // somma il contenuto di x con y
  // ricorda in lastx e last y i due valori
  // azzera la y in x abbiamo il risultato
  lastx = regx;
  regx = (regx + regy); 
  regy = regz;
  regz = regt;
  regt = regu;
  
  del();
  }
  
void  sottrazione()// 
{
 // sottrae x da y
  lastx = regx; 
  regx = (regy - regx);
  regy = regz;
  regz = regt;
  regt = regu;
  
  del();
}
  // punto decimali
void punto()
{
  pdec = 1;
  ndec = 0;
  codice =0;
}
 //cancella carattere
void del() //60
{
 visore = 0; 
 poscifra =0;
 codice = 0;
 pdec = 0;
 ndec = 0;
}
  
  //61 da codice
void enter()
{
regu = regt;
regt = regz;
regz = regy;
regy = regx; 
regx = visore;
//lastx = regx; 
// prima sale la catasta
// poi azzera 
 del();
}
      
   // moltiplicazione  // 
       void moltiplicazione()
        { 
          lastx = regx;        
          regx = (regy * regx); // esegue la moltiplicazione
          regy = regz;
          regz = regt;
          regt = regu;
  
          del();
        }   
        //divisione  //
         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()
          { 
            regu = regt;
            regt = regz;
            regz = regy;
            regy = regx;
            regx = lastx;
          } 
          
         //  x<>y scambio
          void scambio()
          {
            float scambio = regx;
            regx = regy;
            regy = scambio;
          }     
         //ruota giu la catasta
           void ruota()
          { 
           float ruota = regx;
            regx = regy;
            regy = regz;
            regz = regt;
            regt = regu;
            regu = ruota;
          }    
          
          //ruota SU la catasta
           void ruotaSU()
          { 
           float ruota = regu;
            regu = regt;
            regt = regz;
            regz = regy;
            regy = regx;
            regx = ruota;
          }    
          //cambiosegno
           void cambiasegno()
          {
            lastx = regx; regx = regx * -1;
           }  
                 
         // FIX----- scelta numero decimali dopo il punto da 0 a 5
          void visfix()
          { if (( visore < 0 )|| (visore > 5)) return;
              else fix = visore;
           }  
  
  void arcosen_x() // funzione XEQ 1 ritorna angolo in x in RADIANTI
        { if ((regx < -1)||( regx > 1)) return;
             {lastx = regx; regx = asin (regx);}
        }
                 
   void arcocos_x() // funzione XEQ 3 ritorna angolo in x in RADIANTI
       { if ((regx < -1)|| ( regx > 1)) return;
          {lastx = regx; regx = acos (regx);}
       }                 
                       
                 
   void arcotan_x() // funzione XEQ 2  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 XEQ 5
          {
            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 insere in x la coordinata x ed in y la cooordinata y
        // 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 19 fattoriale *****
       {
         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

//---------------------------------------------------------------------------------------
 //--------------------------------------------------------------------------------------         
        // STO n  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 12 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 = indirizzo;
            
             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;
                          
                          
                          
                      }
        }
        
 
 //-------------------------------------------------------------------------------------------------
 void Xeq_nn()
         { int mem = visore;
            if (( mem < 1 )|| ( mem > 99)) return;
             
             switch (mem)
                {
                 case 1:
                        {arcosen_x();}// arcoseno di x in radianti
                        break;
                 case 2:
                        {arcotan_x();}// arcotangente  ritorna angolo in x in RADIANTI
                        break;
                 case 3:
                        {arcocos_x();} // arco coseno di x in radianti
                        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:
                       // converte da radianti in sessagesimali
                       {lastx = regx; regx = regx*180.0/PI; sedec_sessa();}
                       //Log10
                       // {lastx = regx; regx = log10(regx);}
                        break;
                 case 8:
                       // da gradi sessagesimali a radianti 
                      {lastx = regx; sess_sedec();regx = regx*PI/180.0;}
                      
                        break;
                 case 9:
                        // cancella registri e catasta
                         { cancella();}      //CLST
                        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(); //EEX
                        break;
                 case 15:
                          // ln
                      {lastx = regx; regx = log(regx);} 
                        break; 
                       
                  case 16:
                          // exp e^x
                       {lastx = regx; regx = exp(regx);}
                        break;
                        
                  case 17:
                            //10alla x
                        {if (regx < 30)
                            {lastx = regx; regx = pow(10,regx);}}
                        break;
                        
                   case 18:
                          // disponibile
                        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:
                           // disponibile
                          break;  
                          
                          
                          case 23:
                          // disponibile
                        break;
                        
                        case 24:
                          // disponibile
                        break;
                        
                     case 25:
                           // disponibile
                          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;     
             
            }     
         } // fine void XEQ
//**********************************************************************************************
   

//***********************************************************************************************
// ************ per simulare il for *************************************************************
// nella inc1, inc2 ... ecc viene inserito il valore target lo prende da x in fase inserimento
// lo step è fisso uguale ad 1
// la variabile cont viene azzerata in fase di inserimento
// **********
// nella fase di elaborazione con gira == true 
// cont viene incrementato di 1 ad ogni passaggio
// il registro x viene salvato in lastx in regx viene posto il cont attuale
// nel registro regy viene posto inc (target)
// a questo punto si può effettuare un controllo x con y ed verificare se il target è raggiunto.
//***********************************************************************************************

        void inc_n() 
           { 
             int mem = visore;
             
             if (( mem < 1 )||(mem > 6)) return;
              
              switch (mem)
                       {
                         case 1:
                            if (gira == false){inc1 = regx;  cont1 = 0;} // nella fase inserimento
                            
                               else { cont1 = cont1+1; lastx = regx; regx = cont1; regy = inc1; }
                                    // nella fase elaborazione gira = true
                                   
                            break;
                            
                          case 2:
                              if (gira == false){inc2 = regx; cont2 = 0;}
                               else { cont2 = cont2+1; lastx = regx; regx = cont2; regy = inc2; }
                          break;
                          case 3:
                              if (gira == false){inc3 = regx; cont3 = 0;}
                               else { cont3 = cont3+1; lastx = regx; regx = cont3; regy = inc3; }
                          break; 
                          case 4:
                              if (gira == false){inc4 = regx; cont4 = 0;}
                               else { cont4 = cont4+1; lastx = regx; regx = cont4; regy = inc4; }
                          break;
                          
                           case 5:
                            if (gira == false){inc5 = regx;  cont5 = 0;}
                               else { cont5 = cont5+1; lastx = regx; regx = cont5; regy = inc5; }
                            break;
                          case 6:
                              if (gira == false){inc6 = regx; cont6 = 0;}
                               else { cont6 = cont6+1; lastx = regx; regx = cont6; regy = inc6; }
                          break;
                          
                          
                       }                 
            } // fine void inc_n
//-------------------------------------------------------------------------      
    void delay_mm() 
           { 
             //int mem = visore;
             int mem = indirizzo;
             
             if (( mem < 1 )||(mem > 6)) return;
              
              switch (mem)
                       {
                         case 1:
                              { delay(5);}
                            break;
                          case 2:
                              { delay(10);}
                          break;
                          case 3:
                              { delay(50);}
                          break; 
                          case 4:
                              { delay(100);}
                          break;
                              { delay(250);}
                           case 5:
                               { delay(500);}
                            break;
                          case 6:
                                { delay(1000);}
                          break;
                          
                          
                       }                 
            } // fine 
            
 //*******************************************************************************
//********************************************************************************
//      F I N E   L I S T A T O **************************************************
//
//********************************************************************************
            


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