Corso programmazione PICMicro in C – Lezione 9 – Gestione della EEprom interna.Visualizzazione valore a 32bit da eeprom a lcd e counter up/down con reset e memoria

Sappiamo che i microcontrollori PIC® hanno un certo quantitativo di memoria interna, variabile da Pic a Pic, atta a memorizzare il programma da eseguire. Tale memoria è ovviamente una memoria di tipo ROM: le istruzioni vengono salvate in maniera permanente (non si cancellano difatti una volta tolta l’alimentazione: sarebbe assurdo dover riprogrammare il pic ogni volta!) e, all’occorrenza, tale memoria può essere riscritta e quindi anche cancellata elettricamente (andando più nello specifico, questa memoria è di tipo Flash, ovvero una varietà di EEPROM, ma nel caso del picmicro si parla più semplicemente di memoria programma).

I Pic hanno anche un certo quantitavo di memoria RAM, che viene utilizzata per allocare le variabili che normalmente utilizziamo per svolgere le varie operazioni durante l’esecuzione dei programmi.

Tutte le variabili che fin’ora abbiamo dichiarato nei nostri programmi di esempio sono allocate nella memoria RAM, a parte quelle dichiarate con la parola chiave CONST che vengono invece allocate nella memoria programma (ROM). Le variabili dichiarate con CONST sono quindi memorizzate in maniera permanente all’atto della programmazione e non possono essere sovrascritte durante l’esecuzione del programma: ecco perchè “const” : devono rimanere costanti.

La RAM è una memoria volatile: le informazioni in essa contenuta vengono perse una volta tolta l’alimentazione. Per sua natura, la RAM è però una memoria molto veloce: i tempi di accesso alle variabili in essa contenuta sono molto ristretti e quindi tale tipo di memoria è ormai indispensabile all’esecuzione dei programmi. Difatti alcuni pic di fascia molto alta hanno addirittura la possibilità di poter gestire memoria RAM esterna, ma si tratta di applicazioni molto complicate e non alla portata di tutti.

Facciamo adesso un esempio: vogliamo realizzare un’applicazione classica: un termostato in cui impostiamo l’attivazione di un relè ad una data temperatura. Per tale tipo di applicazione abbiamo bisogno ovviamente che il valore di temperatura da noi impostato non vada via in caso di mancanza di alimentazione. In questo caso quindi non possiamo fare affidamento alla memoria ram (il dato salvato verrebbe perso se va via la corrente) nè tantomeno alla memoria programma (il valore dovrebbe rimanere costante e comunque non possiamo inserirlo dall’esterno). In tali casi si fa quindi ricorso alla memoria EEPROM.

Tutti i picmicro hanno un certo quantitativo di memoria EEPROM, utile appunto per poter salvare le nostre variabili in maniera permanente e poter anche modificare semplicemente il valore contenuto qualora ve ne fosse bisogno. La memoria di tipo EEPROM, però, per sua natura è molto lenta, per tale motivo non viene generalmente utilizzata per “fare calcoli” durante un programma ma unicamente per memorizzare valori da richiamare alla bisogna.

La memoria EEPROM di un picmicro, così come la memoria programma, non è eterna: dopo molti anni o dopo un certo numero di volte che è stata scritta va fuori uso (questo “numero di volte” è comunque abbastanza alto per le normali applicazioni), per tale motivo non se ne deve abusare e i nostri programmi dovranno scrivere sull’eeprom soltanto nei casi di estrema necessità ed in maniera oculata.

Quando ci troviamo a realizzare un’applicazione basata su microcontrollore, quindi, è sempre bene dare anche un occhio alla tabella in cui vengono riportati i quantitativi di memoria che abbiamo a disposizione, tale tabella si trova generalmente nelle prime pagine del datasheet, analizziamo la tabella dei pic16f87x:

tabella_memoria_pic16f87x

Vediamo che il PIC16F877A ha una memoria programma di 14.3KBytes (equivalenti a 8192 istruzioni singole), una memoria RAM di 368Bytes e una memoria EEPROM di 256Bytes.

In tabella leggiamo “SRAM”, la memoria RAM dei PICMicro è difatti di tipo SRAM (memoria ram statica), a differenza degli odierni moduli di memoria ram montati nei pc, che sono di tipo DRAM (memoria ram dinamica). La differenza tra i due tipi di memoria sta principalmente nelle tecniche costruttive utilizzate per realizzarla. Una SRAM è generalmente più costosa perchè richiede più componentistica, ed ha anche un minor consumo elettrico, quindi è molto adatta a questi dispositivi così piccoli. Se volete approfondire l’argomento potete vedere su wikipedia: SRAM DRAM

Una memoria RAM di 368bytes, ad esempio, ci indica che noi, nel nostro programma, potremo definire massimo 368 variabili di tipo CHAR (ovvero 368 numeri da 0 a 255), oppure 184 variabili di tipo SHORT o INT e così via (fate riferimento alla terza lezione per sapere quanti byte occupano i vari tipi di dato).

Lo stesso ragionamento vale ovviamente anche per l’eeprom: abbiamo a disposizione 256 Bytes di memoria da poter gestire come vogliamo.

Nel caso 256 Bytes di EEPROM non ci dovessero bastare, i picmicro hanno a bordo delle periferiche  (ad esempio il bus I2C) che permettono di indirizzare delle memorie eeprom esterne. Questo argomento sarà trattato in una prossima lezione. In questa lezione si parlerà esclusivamente della memoria EEPROM che si trova a bordo del picmicro.

La memoria EEPROM di un picmicro può essere scritta e letta “al volo” durante l’esecuzione di un programma (tramite apposite istruzioni), oppure può anche essere scritta durante la programmazione.

Innanzitutto cerchiamo di capire come funziona l’eeprom e facciamo il caso del 16F877 che ha 256 Bytes di tale memoria (uno vale l’altro: il meccanismo che sta alla base è sempre lo stesso).

Dobbiamo immaginare tale eeprom come una grande scatola, all’interno della quale vi sono 256 “celle”: in ogni cella può essere contenuto un numero (una variabile, un carattere) di 8 bit (un byte). Quando avremo bisogno di scrivere o di leggere un dato memorizzato nella eeprom, avremo bisogno di sapere esattamente in quale “cella” è contenuto il valore che vogliamo: questo è molto semplice perchè decidiamo noi dove andare a piazzare ogni variabile: abbiamo le celle numerate da zero a 255, se una variabile decidiamo di metterla nella cella n°30, ogni qualvolta avremo bisogno di recuperare o di aggiornare tale valore, dovremo sempre specificare che vogliamo il contenuto della cella numero 30. Spero che fin qui sia chiaro come è organizzata la memoria.

Ovviamente è più facile  da ricordare una parola al posto del numero di cella di memoria, così possiamo fare una cosa del tipo:

#define TEMPERATURA 30

In questo modo è più facile ricordarci che il valore di temperatura è memorizzato nella cella numero 30: faremo riferimento alla parola “TEMPERATURA” e non al numero 30; questo torna utile quando ci sono parecchie variabili da gestire e non riusciamo a ricordarci dove le abbiamo posizionate.

Come vedete, nel caso della memoria eeprom, è necessario specificare la locazione (la cella) di memoria in cui operare a differenza dei valori che memorizziamo nella RAM. In realtà anche nella RAM vi sono delle “celle” di memoria in cui i valori vengono memorizzati, ma programmando in C non ce ne dobbiamo occupare in quanto fa tutto tale linguaggio di programmazione “dietro le quinte”, chi programma in assembler, invece, deve specificare le posizioni di memoria anche per i valori memorizzati nella RAM.

Bene. Passiamo ora a vedere come si possono memorizzare e recuperare i valori nell’eeprom interna, i metodi sono vari ed elenco qui quelli più classici.

Scrittura dell’eeprom all’atto della compilazione da programma

A pagina 209 del manuale dell’Hitec-C troviamo la spiegazione di una macro chiamata:

_EEPROM_DATA

Tale macro deve avere obbligatoriamente come argomento 8 valori ad 8 bit che saranno scritti nelle 8 locazioni di memoria eeprom seguenti a partire dalla zero. Ad esempio:

__EEPROM_DATA(0x08,0x12,0x15,0x3B,0x44,0x5C,0x0C,0x71)
__EEPROM_DATA(0x8D,0xD1,0xAA,0x1B,0x2C,0x3D,0x4E,0xAF)

Tali istruzioni scriveranno il valore 0x08 (8 in decimale) nella locazione 0, il valore 0x12 (18) nella locazione 1 ecc fino ad arrivare al valore 0xAF (175) scritto nella locazione 15. Tale macro va richiamata ovviamente prima del main e produce la scrittura dei valori da noi definiti nell’eeprom al momento della programmazione. Come già detto è necessario mettere, per ogni chiamata della macro, 10 valori, quelli che non ci servono li possiamo settare a 0xFF che è il valore di default.

Compiliamo il seguente, semplice, programma:

#include <pic.h>
__CONFIG (HS & WDTDIS & PWRTEN & BORDIS & LVPDIS & DUNPROT & WRTEN & DEBUGDIS & UNPROTECT);
__EEPROM_DATA(0x08,0x12,0x15,0x3B,0x44,0x5C,0x0C,0x71);
__EEPROM_DATA(0x8D,0xD1,0xAA,0x1B,0x2C,0x3D,0x4E,0xAF);
 
void main(void)
{
}

Tale programma come vedete non fa niente: si limita soltanto a riempire le prime 16 celle di memoria dell’eeprom nel momento della programmazione.

Adesso apriamo il software del pickit2 e carichiamo l’HEX generato dal programma precedente. Vediamo che la finestra del Pickit2 programmer ha due aree dati: quella superiore, denominata “Program Memory” contiene il programma vero e proprio che viene caricato nel PICMicro, ovviamente scritto in linguaggio macchina. Il riquadro inferiore, denominato “EEPROM Data” contiene invece i dati facenti parte dell’area di memoria eeprom del picmicro. Guardate cosa appare proprio in questa finestra:

eeprom_pickit2

Sono proprio i valori che abbiamo messo da codice!

Tenendo selezionato Byte ASCII o Word ASCII, la finestra è divisa a metà: sulla sinistra ci sono i valori in esadecimale e sulla destra c’è la loro rappresentazione in ASCII.

Effettuando la programmazione, l’eeprom sarà scritta in quelle locazioni con quei valori. Appena uscito di fabbrica il picmicro ha tutte le celle di memoria poste al loro valore massimo, trattandosi di celle ad 8 bit il valore massimo è 0xFF (255).

Vediamo inoltre che c’è una checkbox denominata “Enabled” che di default è spuntata: tenendola spuntata, la memoria eeprom viene scritta con i valori indicati nella finestra, togliendo invece la selezione appare:

eeprom_pickit2_2

Il che sta ad indicare che, anche se ci sono valori nella finestra dei dati eeprom, questi non verranno scritti per cui se sul picmicro già ci sono dei valori memorizzati, questi non saranno sovrascritti.

Tale caratteristica del programma funziona anche se effettuate la lettura del picmicro: in tale finestra verranno riportati i valori letti dall’area eeprom.

Possiamo anche modificare a mano i valori numerici che si trovano nell’area di memoria: basta cliccare col mouse sulla posizione in cui vogliamo inserire il valore, digitarlo sulla tastiera e quindi premere invio.

Come vedete possiamo anche effettuare la lettura/scrittura solo dell’area memoria programma, delle aree memoria programma ed eeprom oppure solo eeprom: basta abilitare/disabilitare i checkbox che si trovano nelle due aree.

Scrittura e Lettura dell’EEPROM interna da programma

Per utilizzare l’EEPROM da programma è necessario prima sapere alcune cose, dal momento che i codici belli e pronti non servono a nulla se non si capisce tutto quello che c’è dietro. Ci sono alcuni registri speciali che si occupano di dialogare con l’EEPROM. Ci occuperemo in questa sede solo di quelli più utili ai nostri scopi:

EEDATA : in questo registro vengono memorizzati gli 8 bit letti o da scrivere sull’EEPROM.

EEADR : è il registro che contiene l’indirizzo della cella di memoria in cui scrivere o da cui leggere.

EECON1 : è il registro che si occupa degli accessi alla memoria in generale.

In tale registro sono contenuti i sono i bit :

EEPGD (bit 7)  : setta l’accesso alla memoria programma (EEPGD=1) o all’eeprom (EEPGD=0). Difatti sappiamo che i picmicro microchip hanno anche le funzioni di self-programming: possono auto riscriversi le aree di memoria programma, questa è la funzione svolta, ad esempio, dai bootloader.

RD e WR (bits 0 e 1) : servono ad eseguire la lettura e la scrittura rispettivamente. Questi bit non possono essere impostati a zero da programma ma solo ad 1, vengono resettati dall’hardware al termine delle operazioni.

WREN (bit 2) : se settato, abilita le operazioni di scrittura. E’ quindi un flag di abilitazione.

WRERR (bit 3) : viene impostato ad 1 nel caso in cui un’operazione di scrittura o di lettura sia fallita (o terminata prematuramente) a causa di un reset (dovuto a MCLR o al watchdog timer): in questo caso, controllando tale bit, da software si può decidere se rieseguire le operazioni.

Importante è anche la presenza del bit EEIF (EEprom Interrupt Flag), localizzato nel registro PIR2, che viene impostato ad 1 quando le operazioni di sola scrittura sono terminate.

EECON2 : è un registro utilizzato in maniera “speciale” durante le operazioni di scrittura, vedremo dopo come.

Le operazioni di lettura e scrittura dell’eeprom devono rispettare una certa sequenza, nel caso del pic16F877 tali operazioni sono descritte a pagina 35 del datasheet (37 da Adobe Reader):

  • Lettura dell’EEPROM
  1. Impostare, nel registro EEADDR, il numero di cella di memoria da cui andare a leggere il valore. Se il picmicro ha 128 Bytes di memoria eeprom e impostiamo 129 come indirizzo da cui leggere, verrà letta la posizione 0 e così via.
  2. Portare a zero il bit EEPGD in maniera tale da specificare al picmicro che vogliamo operare sulla memoria eeprom e non sulla memoria programma.
  3. Avviare la lettura portando a 1 il bit RD.
  4. Il dato ora è disponibile nel registro EEDATA il quale può essere letto dopo un ciclo.

Il valore contenuto in EEDATA rimarrà in tale registro fino a che non ci sarà un’altra operazione di lettura o di scrittura.

  • Scrittura dell’EEPROM
  1. Impostare, nel registro EEADDR, il numero di cella di memoria in cui andare a scrivere il valore. Ovviamente ci sono picmicro con 256Bytes di memoria eeprom ed altri con 128, per cui siate sicuri della posizione in cui andate a scrivere: se scriviamo nella posizione 129 di un picmicro che ha 128bytes, non otterremo nulla.
  2. Impostare, nel registro EEDATA, il valore ad 8 bit da scrivere nella cella di memoria specificata prima.
  3. Portare a zero il bit EEPGD in maniera tale da specificare al picmicro che vogliamo operare sulla memoria eeprom e non sulla memoria programma.
  4. Portare il bit WREN ad 1 per abilitare la scrittura. Come vedete per la scrittura c’è da abilitare un flag prima di avviare le operazioni. Questo è fatto per motivi di sicurezza. Tale flag, inoltre, non viene resettato dall’hardware e bisogna farlo a mano.
  5. Disabilitare gli interrupt se sono abilitati. Se si verifica un interrupt durante la fase di scrittura, le conseguenze possono essere imprevedibili!
  6. A questo punto entra in gioco il registro EECON2: per abilitare la scrittura è necessario specificare una specie di “password” in maniera tale che l’eeprom non possa essere scritta per cause accidentali. Come vedete il livello di sicurezza è molto alto. Come da datasheet bisogna scrivere in EECON2 prima il valore 0x55 e poi il valore 0xAA: è proprio come se stessimo specificando una password.
    Tutte queste precauzioni vengono prese in maniera tale da evitare che le aree di memoria possano essere scritte accidentalmente a causa di disturbi o altri problemi, causando quindi gravi danni.
  7. Portare ad 1 il bit WR. La scrittura viene eseguita.
  8. Azzerare il bit WREN.
  9. Alla fine della scrittura il bit WR viene messo a zero in automatico e viene settato il bit EEIF per segnalare l’interrupt, quindi dobbiamo portare a zero anche il bit EEIF.

Come vedete è apparentemente complicato, in realtà queste informazioni ci sono utili per poter scrivere una semplice libreria per poter eseguire la lettura/scrittura dell’EEPROM.

In realtà tutti i compilatori hanno già delle librerie standard per eseguire queste operazioni, ma che sfizio c’è? Per l’Hitec-C le due routine qui specificate sono definite tramite macro e si trovano nella libreria “eeprom_routines.c” che viene inclusa in automatico in “pic.h”. Queste due funzioni sono poi disponibili come eeprom_read(indirizzo) ed eeprom_write(indirizzo,valore). Ma noi, ovviamente, abbiamo bisogno di capire come si svolgono le operazioni per avere la piena padronanza del nostro programma.

Vediamo quindi come scrivere noi una libreria per poter accedere all’eeprom interna da programma, in base alle informazioni fornite dal datasheet:

// legge un BYTE (8bit)  dall'indirizzo specificato in "address"
unsigned char eei_read_byte(unsigned char address)
	{
	EEADR=address; // indirizzo da cui leggere
	EEPGD=0; // accesso alla memoria eeprom
	RD=1; // avvio la lettura
	// il valore contenuto in EEDATA è disponibile dal prossimo ciclo
	// se effettuo un return EEDATA, non ottengo nulla
	char EEVALUE;
	EEVALUE=EEDATA;
	return EEVALUE;
	}
 
// scrive un BYTE (8 bit) (valore "data") nell'indirizzo specificato in "address"
void eei_write_byte(unsigned char data, unsigned char address)
	{
	EEADR=address; // indirizzo in cui scrivere
	EEDATA=data; // dati da scrivere
	EEPGD=0; // accesso alla memoria eeprom
	WREN=1; // abilito la scrittura
	// Controllo se sono attivi gli interrupt e mi memorizzo la condizione
	static bit PREGIE=0;
	if (GIE)
		{
		PREGIE=1;
		GIE=0; // disabilito gli interrupt
		}
	// Queste due istruzioni che seguono sono richieste (vedi datasheet) per avviare la scrittura
	EECON2=0x55;
	EECON2=0xAA;
	WR=1; // avvio un ciclo di scrittura
	while(!EEIF); // attendo che la scrittura sia completa
	WREN=0; // disabilito la scrittura sull'eeprom
	EEIF=0; // resetto il flag di scrittura completa
	 // reimposto gli interrupt allo stato in cui si trovavano
	if (PREGIE)
		{
		GIE=1;
		}
	}

Come vedete non è poi così difficile, non abbiamo fatto altro che tramutare in codice le informazioni preziose fornite dal datasheet, prevedendo gli opportuni accorgimenti come il “while(!EEIF)” che ci fa ciclare di continuo fino a che l’operazione di scrittura non è completa e i costrutti IF per verificare se gli interrupt sono attivi o meno e quindi ripristinarli al loro stato una volta finite le operazioni di scrittura.

Quando vorremo scrivere un valore (esempio: 80) nella locazione di eeprom n°25 ci basterà eseguire:

eei_write_byte(80,25); // scrivo 80 nella cella 25

Quando vorremo recuperarlo:

unsigned char valore=0; // mi definisco una variabile per contenere il valore letto
valore = eei_read_byte(25); // leggo dalla cella n°25

Le nozioni fornite con l’articolo precedente: “Gli operatori di scorrimento. Scomporre un valore a 16 bit in due da 8 bit e viceversa“, ci saranno molto, molto utili! Ci permetteranno difatti di scrivere altre funzioni per poter leggere e memorizzare anche valori di tipo INT (16bit) e di tipo LONG (32bit).

Alla fine dell’articolo, con gli esempi, è presente la libreria completa creata da me (eeprom_internal.c) che permette di leggere/scrivere sull’eeprom valori ad 8, a 16 e a 32 bit.

La libreria difatti contiene anche le funzioni per leggere/scrivere numeri interi a 16bit (eei_read_int / eei_write_int) e a 32 bit (eei_read_long / eei_write_long). Avendo a disposizione la libreria suddetta, possiamo compilare un semplice esempio, utilizzando il circuito mostrato nella lezione sugli LCD, per farvi capire come operano queste funzioni e qual’è il risultato, mostrato su display:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
#define  XTAL_FREQ 20MHZ
#include
 
__CONFIG (HS & WDTDIS & PWRTEN & BORDIS & LVPDIS & DUNPROT & WRTEN & DEBUGDIS & UNPROTECT);
 
#include "settings.h"
#include "delay.c"
#include "lcd.c"
#include "eeprom_internal.c"
 
void main(void)
        {
		settings(); // imposto le porte
		LCD_INIT(); // inizializzo l'LCD
		DelayMs(100); // piccolo ritardo iniziale
		LCD_CLEAR(); // ripulisco il display
 
		// numero di esempio a 32 bit
		unsigned long numero = 3374966197;
 
		/*
		memorizzo il numero a 32 bit nell'eeprom partendo dalla locazione zero.
		Essendo composto da 4 byte, la prossima locazione libera in cui memorizzare
		altri dati sarà la numero 4, in quanto il numero a 32bit mi occuperà le locazioni
		da 0 a 3
		*/
		eei_write_long(numero,0);
 
		// ora recupero il valore dall'eeprom e lo memorizzo in un'altra variabile
		unsigned long lettura = eei_read_long(0);
 
		// mostro il valore letto dall'eeprom sul display
		LCD_PUTUN32(lettura);
 
		while(1)
			{
			}
 
	}

L’esempio è banale: mi definisco un numero a 32 bit, lo memorizzo nell’eeprom a partire dalla cella n°0 (leggete attentamente il commento nel programma!), dopodichè recupero il valore memorizzato nell’eeprom, lo salvo in una seconda variabile e infine lo mostro sul display.

I più attenti si accorgeranno che qui utilizzo una funzione “LCD_PUTUN32” che in realtà non è presente nella libreria lcd.c della settima lezione. Difatti l’ho creata appositamente per questa lezione, e ha la funzione di scrivere sul display i numeri interi senza segno a 32 bit (la funzione di default gestisce massimo 16bit).  Trovate la libreria modificata in fondo all’articolo insieme agli esempi.

Ma adesso… Facciamo qualcosa di più elaborato!

Applicazione pratica : contatore up/down con memoria e reset

Vediamo come sfruttare tutte queste belle cose in maniera pratica: ricordate il contatore della lezione n° 8 ? Bene, vi aggiungeremo due pulsanti: uno per memorizzare il valore letto e un’altro per richiamarlo.

Modificheremo quindi così il circuito, aggiungendo altri due pulsanti sulle porte RD2 e RD3:

counter_con_memoria

Nel nuovo codice, oltre alle routine di memorizzazione e richiamo del numero salvato, ho aggiunto anche l’azzeramento. Per poter effettuare l’azzeramento sarà necessario tenere premuti insieme i pulsanti up e down per un secondo. Questo lo possiamo ottenere con la seguente routine:

81
82
83
84
85
86
87
88
89
90
91
if (btnDn==Pressed && btnUp==Pressed)
		{
		DelayMs(250);
		DelayMs(250);
		DelayMs(250);
		DelayMs(250);
		if (btnDn==Pressed && btnUp==Pressed) // antibounce
			{
			counter=0;
			}
		}

Come vedete, effettuo la verifica della contemporanea pressione dei due pulsanti, e inserisco un ritardo di 1 un secondo, dopodichè se il pulsanti sono ancora entrambi premuti, azzero. Ovviamente andranno modificate anche le routine che gestiranno la pressione singola dei soli pulsanti up e down: in questo caso andiamo a verificare che uno sia premuto e l’altro no, altrimenti la pressione contemporanea dei due pulsanti eseguirebbe tutte e 3 le routine combinando un bel pasticcio!

Per la memorizzazione e il richiamo ho previsto due routine, richiamate dalla pressione dei due pulsanti. La routine per memorizzare è la seguente:

120
121
122
123
124
125
126
127
128
129
void memory(void)
	{
	dispReg=0;
	displayU=OFF;
	displayD=OFF;
	eei_write_byte(counter,0); // scrivo il valore del counter nella locazione di memoria 0
	DelayMs(250);
	DelayMs(250);
	displayson=1; // riattivo i display
	}

Come vedete spengo i display, effettuo la memorizzazione del valore del counter nella locazione di eeprom numero zero e aspetto mezzo secondo per poter rimettere tutto in funzione normalmente.  Il significato del flag “displayson” è presto detto: mi serve a non eseguire la procedura di refresh dei display nel tempo che passa dalla pressione del pulsante al momento in cui la routine di scrittura su eeprom disattiva gli interrupt, tale flag viene posto a zero (qui non è mostrato) subito dopo la pressione del tasto di memorizzazione. E’ inoltre una condizione da verificare per poter controllare anche lo stato dei pulsanti: fintanto che displayson=1 i pulsanti vengono controllati, se displayson=0 i pulsanti non vengono controllati: questo per evitare falsi aggiornamenti/letture eeprom se si preme accidentalmente un tasto durante le operazioni di lettura/scrittura.

L’effetto di tutto questo serve anche a fare un po’ di scena: all’atto della pressione del pulsante memoria, i display si spengono per mezzo secondo dopodichè si riattivano riprendendo il numero. Questo dà all’utente finale la conferma che tutto sta funzionando per bene.

La routine di richiamo del valore invece è quanto di più semplice possibile:

131
132
133
134
void recall(void)
	{
	counter=eei_read_byte(0); // il counter ora ha il valore messo in memoria
	}

Premendo il pulsante richiamo memoria, appare subito il numero salvato. Se provate a spegnere e riaccendere il circuito, e a premere il tasto di richiamo memoria, vedete che sul display riappare il valore memorizzato in precedenza. Potete anche effettuare la lettura dell’eeprom con il pickit e vedere che in posizione zero ora c’è il numero che abbiamo salvato col circuito (ricordatevi sempre che però i valori mostrati sul pickit sono scritti in esadecimale!).

Downloads

Nota: i programmi di esempio sono stati sviluppati con una versione precedente dell’Hitec-C Compiler, per cui compilati con la nuova versione, restituiscono errori. Fate riferimento a questo articolo per maggiori informazioni su come adattare i vecchi programmi. Consiglio spassionato se volete davvero imparare a programmare: non utilizzate l’include legacy headers, ma imparate a cambiare i nomi mnemonici.

Se questo articolo ti è piaciuto, condividilo su un social:
Se l'articolo ti è piaciuto o ti è stato utile, potresti dedicare un minuto a leggere questa pagina, dove ho elencato alcune cose che potrebbero farmi contento? Grazie :)