Creative Commons BY-NC-ND 2.5Questo sito e tutto il suo contenuto sono distribuiti sotto la licenza Creative Commons Attribuzione - Non Commerciale - Non opere derivate 2.5 Italia e con le condizioni d'uso definite nel disclaimer: siete pregati di leggere entrambi questi documenti prima di usufruire dei contenuti di questo sito. Per alcuni contenuti è necessaria una registrazione gratuita: non è necessario pagare e non è necessario accumulare punteggi per accedere agli articoli e scaricare i sorgenti. Basta solo essere onesti. Se volete che questo sito continui a rimanere attivo, a contribuire ogni giorno alla diffusione della cultura libera, non copiate il materiale per ripubblicarlo in altri luoghi : chi fa questo è solo un miserabile e un perdente. Se volete partecipare su settorezero e rendere le vostre idee, i vostri progetti, fruibili da tutti senza limitazioni, come dovrebbe essere in un paese civile e acculturato, potete farlo tranquillamente.

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

Autore: Giovanni Bernardo | Data pubblicazione: 9 gennaio 2010
Categorie: PICmicro 10/12/16

honeycombSappiamo che i PICMicro 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 0×08 (8 in decimale) nella locazione 0, il valore 0×12 (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 0×55 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!).

File di supporto alla nona lezione del corso di programmazione picmicro in C (422)

Articoli che potrebbero interessarti

L'articolo ti è piaciuto o ti è stato utile per risolvere un problema? Supporta e mantieni in vita questo sito, ci basta soltanto un caffè o una birra.
Se desiderate che settorezero continui a rimanere gratuito e fruibile da tutti, non copiate il nostro materiale e segnalateci se qualcuno lo fa

Puoi lasciare un commento, o un trackback dal tuo sito.

  1. #1 da leo il 14 febbraio 2010

    finalmente ho trovato una guida per linguaggio c che fa per me
    grazie!!

  2. #2 da Luca il 13 marzo 2010

    Tutto alla perfezione, come sempre, volevo solo aggiungere una postilla. Il 628a non ha il bit EEPGD, quindi a meno che non si risolva differentemente, se da un lato non c’è bisogno nelle routine di scrittura\lettura tale bit, dall’altro in una prima occhiata sembrerebbe impossibile scrivere sulla memoria del programma.

    L’unico problema riscontrato, usando un willem prog 5.0 è la lettura della eeprom dal computer, per permettere la lettura della eeprom a posteriori, è necessario settare su ON il flag “CP EEPROM” (anche se sembrerebbe li contrario). Talvolta, ovvero quasi sempre, il programmatore non riesce a leggere i primi 4 byte della epprom. Quindi ho cercato di evitare di usarli.

    Piccola chicca: __EEPROM_DATA(“C”,”o”,”u”,”n”,”t”,”e”,”r”,”:”);… &&… eei_write_byte(counter,9); …. ;)

    • #3 da Giovanni Bernardo il 13 marzo 2010

      Il 16f628A non ha il bit EEPGD perchè non può riscriversi la memoria programma. Come già detto il bit EEPGD serve per selezionare la scrittura su memoria programma o su memoria dati. Non avendo il 16F628 la possibilità di scrivere la memoria programma tale bit è stato eliminato perchè non avrebbe ragione di esistere potendo solo scrivere la memoria dati. Basta commentare la riga di EEPGD.

      Riguardo alla piccola chicca…. Che cosa sarebbe? Non ci vedo nulla di particolare

  3. #4 da MayTs il 11 aprile 2010

    Ottima guida veramente!
    un piccolo quesito:

    Sto realizzando un tachimetro e dovrei quindi memorizzare in eprom sia i km parziali che i km totali(i totali ogni km, i parziali ogni 100 metri). Essendo quindi la memoria eeprom riscrivibile solo limitate volte(quante volte?), come aggiro il problema?

    • #5 da Giovanni Bernardo il 11 aprile 2010

      Se non erro circa un milione di volte ma non ne sono sicuro, ci dovrebbe star scritto sul datasheet. Usa un ‘eeprom esterna, almeno se si guasta puoi sostituire solo quella e non tutto il circuito. Alcune auto ad esempio memorizzano tutti questi dati proprio sulle 24Cxx. Ma poi perchè i parziali ogni 100 metri? Cosi si che la cella di memoria salta subito.

  4. #6 da MayTs il 11 aprile 2010

    facendo un rapido calcolo, se la eeprom ha un limite di 1.000.000 di scritture riuscirei a fare circa 90.000 km, prima di far saltare la cella….
    Per l’uso che devo farne direi che è accettabile, ma credo che terrò i dati in Ram durante l’uso del tachimetro(quindi in alimentazione costante) e li salverò in eeprom solo quando l’alimentazione principale verrà tolta(ovviamente il circuitò avrà una seconda fonte di alimentazione per permettere esclusivamente il salvataggio dei dati in eeprom).
    In questo modo dovrei riuscire ad eludere tale problema, giusto?

    • #7 da Giovanni Bernardo il 11 aprile 2010

      Così direi che va decisamente meglio. Magari per riuscire ad effettuare il salvataggio è sufficiente soltanto un grosso condensatore con un diodo per non far andare la corrente al resto del circuito (è un’idea, non so se può funzionare). Ovviamente un I/O dovrà ricevere alimentazione fissa, appena l’alimentazione manca effettua il salvataggio

  5. #8 da MayTs il 11 aprile 2010

    Grazie mille per l’aiuto, inoltre, per poter salvare in eeprom valori di tipo float(quindi a virgola mobile)?

    • #9 da Giovanni Bernardo il 11 aprile 2010

      Beh a dirti il vero non mi sono mai posto tale problema per cui adesso su due piedi non ti saprei dire. Generalmente opero sempre su interi. Quando mi servono valori con virgola moltiplico per 10, 100, 1000 per riportarmi a un intero e in fase di visualizzazione (tipo su un display) faccio la divisione intera e il resto della divisione.

    • #10 da Giovanni Bernardo il 13 aprile 2010

      Ho letto meglio il datasheet di un pic preso ad esempio (il 16F628A). Si legge a pagina 3:
      • High-Endurance Flash/EEPROM cell:
      - 100,000 write Flash endurance
      - 1,000,000 write EEPROM endurance
      - 40 year data retention

      Quindi come dicevo l’eeprom la puoi riscrivere un milione di volte (ovviamente lo sarà sicuramente qualcosa di più dal momento che su questi dati si dichiara sempre un valore di sicurezza per stare tranquilli), mentre la memoria programma è più limitata (100mila volte).
      Un’eeprom esterna (ho preso ad esempio la 24LC512) porta scritto:
      More than 1 Million Erase/Write Cycles
      Quindi il parametro è sempre 1milione ma qui c’è scritto “più di”, e comunque se uno ci deve scrivere di continuo, come già detto, è meglio usarne una esterna almeno non si compromette il chip principale. E poi penso che questo parametro sia “per cella” (ma non è specificato quindi non so fino a che punto possa essere vera tale affermazione)

  6. #11 da Luca il 6 luglio 2010

    Caro Giovanni,
    sto cercando di adattare la tua libreria al pic16f1827. le cose sono un bel po differenti, ma per grandi linee la frittata è sempre la stessa.

    Premettendo che il pickit3 mi spara questo errore:
    *****************************************************************************
    Programming…
    The following memory regions failed to program correctly:
    EEData Memory
    Address: 00000001 Expected Value: 00000000 Received Value: 00000001
    Programming failed
    *****************************************************************************

    Pur programmando lo stesso la periferica, il semplicemente aggiunge un unità ad un valore memorizzato nella posizione 1 dell’eeprom ad ogni riavvio e lo stampa sull’lcd; vedo che sull’lcd visualizza la cifra, ma aumenta automaticamente (wtd disabilitato!!) e sembra insensibile ai reset.

    La libreria è questa (ridotta solo alle operazioni su un byte):
    *****************************************************************************
    // legge un BYTE (8bit) dall’indirizzo specificato in “address”
    unsigned char eei_read_byte(unsigned char address)
    {
    EEADRL=address; // indirizzo da cui leggere
    EEPGD=0; // accesso alla memoria eeprom
    CFGS=0;
    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=EEDATL;
    return EEVALUE;
    }

    // scrive un BYTE (8 bit) (valore “data”) nell’indirizzo specificato in “address”
    void eei_write_byte(unsigned char data, unsigned char address)
    {
    EEADRL=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 temp=0;
    if (GIE)
    {
    temp=1;
    GIE=0; // disabilito gli interrupt
    }
    // Queste due istruzioni che seguono sono richieste (vedi datasheet) per avviare la scrittura
    EECON2=0×55;
    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 (temp)
    {
    GIE=1;
    }
    }

    *****************************************************************************
    #include
    #include
    #define PIC_CLK 32000000
    #include “delay.c”
    #include “lcd.c”
    #include “e2prom.c”

    // Fuses di configurazione
    __CONFIG (FOSC_INTOSC & WDTE_OFF & PWRTE_ON & MCLRE_ON & CP_OFF & CPD_OFF & BOREN_OFF & CLKOUTEN_ON & IESO_OFF &
    FCMEN_OFF & WRT_OFF & VCAPEN_OFF & PLLEN_OFF & STVREN_OFF & BORV_19 & DEBUG_ON & LVP_OFF);

    __EEPROM_DATA(0,0,0,0,0,0,0,0);

    // funzione principale, eseguita all’avvio del picmicro
    void main(void)
    {
    OSCCON = 0b11110000; //Oscillatore a 32MHz
    ANSELA=0;
    TRISA=0;
    ANSELB=0;
    TRISB=0;

    int cnt=eei_read_byte(1);
    cnt++;
    eei_write_byte(cnt,1);

    LCD_INIT();
    DelayMs(100);
    LCD_CLEAR();
    LCD_GOTO(1,1);
    LCD_PUTS(“Counter: “);
    LCD_PUTUN(cnt);
    LCD_GOTO(2,1); //
    LCD_PUTS(” S a S !”);
    SLEEP();

    }
    *****************************************************************************
    Qualche lume? (Prometto che stavolta non manderà tutto all’aria, devo assolutamente scrivermi questa libreria, anche se per le operazioni su 16 bit le cose cambiano parecchio dal momento che ho un’indirizzamento su 10 bit e tante altre cosucce che mi incasineranno le cose)

    Grazie,
    Luca

    • #12 da Giovanni Bernardo il 6 luglio 2010

      A parte che non ho ben capito qual è il problema…
      Quel pic ha 2 word di configurazione e, per quanto ne so io, il sistema per settarle non è mettere tutti i parametri nella stessa macro config, ma usare due __config di seguito con i settaggi per la prima e per la seconda word. Poi… Non conosco questo pic, mi è nuovo e vedo che ha davvero un sacco di funzioni, tra cui addirittura la rimappatura delle periferiche sui pin, funzione che era fino a poco tempo fa un’esclusiva delle serie superiori…. Però!
      In parole povere: vuoi far memorizzare un valore nell’eeprom, all’accensione te lo leggi, lo aumenti di una unità e lo mostri a display.
      Tralasciando l’errore del pickit, il programma come si comporta di preciso?

  7. #13 da Luca il 7 luglio 2010

    Allora il fatto delle __CONFIG, ho fatto delle prove, la prima cosa che mi è venuta in mente è __CONFIG1(…); __CONFIG2(…); dal momento che dall’include dell’hitech-c leggo// Config Register: CONFIG1…e // Config Register: CONFIG2 .
    Ma ciò non funge, il compilatore mi da un errore del tipo:
    *****************************************************************************
    Codice:
    9— __CONFIG1(FOSC_INTOSC & WDTE_OFF & PWRTE_ON & MCLRE_ON & CP_OFF & CPD_OFF & BOREN_OFF & CLKOUTEN_ON & IESO_OFF & FCMEN_OFF);
    10– __CONFIG2(WRT_OFF & VCAPEN_OFF & PLLEN_OFF & STVREN_OFF & BORV_19 & DEBUG_ON & LVP_OFF);
    *****************************************************************************
    Errore:
    Executing: “C:\Program Files\HI-TECH Software\PICC\9.70\bin\picc.exe” –pass1 “C:\Users\Luca\Desktop\Programmazione Pic\16F1827\primolcd.c” -q –chip=16F1827 -P –runtime=default –opt=default -D__DEBUG=1 -g –asmlist “–errformat=Error [%n] %f; %l.%c %s” “–msgformat=Advisory[%n] %s” “–warnformat=Warning [%n] %f; %l.%c %s”
    Error [194] C:\Users\Luca\Desktop\Programmazione Pic\16F1827\primolcd.c; 9.11 “)” expected
    Error [194] C:\Users\Luca\Desktop\Programmazione Pic\16F1827\primolcd.c; 10.11 “)” expected

    ********** Build failed! **********
    *****************************************************************************

    Se levo i numeri 1 e 2 affianco a __CONFIG le cose funzionano, e funzionano allo stesso modo se uso una sola riga.

    Ritornando al problema: cancello la eeprom al primo byte, il programma parte, legge il valore all’indirizzo 1, lo aumenta di un unità, lo salva nell’indirizzo 1, e stampa sull’lcd counter: valore, insomma per vedere quante volte è andato in esecuzione in programma.

    Il problema sono riuscito ad isolarlo: funge tutto alla perfezione finchè non utilizzo la riga :
    eei_write_byte(cnt,1);
    sembra sia questa a creare il problema, perchè commentandola fila tutto liscio come l’olio.

    Il programma non dovrebbe nemmeno partire, a detta del pickit la programmazione dovrebbe esser fallita, eppure il programma parte, ogni 2 secondi e mezzo la cifra aumenta da sola. se premo il tasto del reset non aumenta subito dopo (come dovrebbe, dal momento che il programma dovrebbe ripartire dall’inizio), ma semplicemente attende sempre quei due secondi e mezzo e và avanti con la cifra. Ti posso assicurare che in fin dei conti l’eeprom la scrive dal momento che se tolgo l’alimentazione e la rimetto il numero stampato subito dopo l’accensione è quello che mi compariva qualche istante prima di togliere l’alimentazione.

    Un’ultima cosa strana è che per una frazione di secondo, prima di cambiare cifra, sull’lcd compaiono altri caratteri, ad es:

    Counter: 227 questo a 0sec
    S a S !

    Cou ter: 2u7 questo a +200ms
    S a S !

    Counter: 228 questo da 500ms a 2,5s
    S a S !

    In loop, questo è il comportamento, in automatico.
    Che stranezza, eppure ho seguito il datasheet nel modificare la libreria, la cosa troppo strana è quell’errore, non capisco da dove salta fuori.

    • #14 da Luca il 7 luglio 2010

      PROBLEMA RISOLTO:

      Ecco il codice funzionante:
      ************************************************************************************
      #include
      #include
      #define PIC_CLK 32000000
      #include “delay.c”
      #include “lcd.c”
      #include “e2prom.c”

      // Fuses di configurazione
      __CONFIG (FOSC_INTOSC & WDTE_NSLEEP & PWRTE_OFF & MCLRE_ON & CP_OFF & CPD_OFF & BOREN_OFF & CLKOUTEN_ON & IESO_OFF &
      FCMEN_OFF & WRT_ALL & VCAPEN_OFF & PLLEN_OFF & STVREN_OFF & BORV_19 & DEBUG_ON & LVP_OFF);

      __EEPROM_DATA(0,0,0,0,0,0,0,0);

      // funzione principale, eseguita all’avvio del picmicro
      void main(void)
      {
      OSCCON = 0b11110000; //Oscillatore a 32MHz
      ANSELA=0;
      TRISA=0;
      ANSELB=0;
      TRISB=0;

      int cnt=eei_read_byte(0);
      cnt++;

      LCD_INIT();
      DelayMs(100);
      LCD_CLEAR();
      LCD_GOTO(1,1);
      LCD_PUTS(“Counter: “);
      LCD_PUTUN(cnt);
      LCD_GOTO(2,1); //
      LCD_PUTS(” S a S !”);

      eei_write_byte(cnt,0);
      SLEEP();
      }
      *****************************************************************************

      Ho risolto il tutto mettendo la scrittura della eeprom distante dalla lettura; sinceramente non capisco come mai non funzionasse, ma sopratutto la cosa strana è: perchè un problema del genere viene fuori dal momento che programmo? Nel senso: il problema ce l’ho o nel momento che compilo, o a runtime; la programmazione non si limita a flashare il pic, salvando l’hex nella memoria? Perchè mai mi ha dato questo errore? Bah…

      Comunque ora vedo di ultimare la libreria, casomai ti servisse posso inviartela così la puoi pubblicare.
      Grazie del cordialissimo supporto, Luca

      • #15 da Giovanni Bernardo il 7 luglio 2010

        Io continuo a non capire qual è il problema… La lettura della eeprom comunque non la puoi effettuare appena subito dopo una scrittura, questo mi pare di averlo specificato, devi far passare del tempo, adesso non ricordo quanti millisecondi. Se provi a leggere l’eeprom subito dopo una scrittura non ottieni il valore reale. E poi non capisco cos’ha la tua libreria di diverso.

        • #16 da Luca il 9 luglio 2010

          A parte che io effettuavo prima una lettura, poi un’operazione ed infine una scrittura, comunque penso che il problema resti lo stesso. Il problema era: il pickit non programmava, ed il programma non partiva.
          Beh, diciamo che ho cambiato quasi nulla alle fine, a parte sostituire tutti gli mnemonici che ovviamente sono diversi. La struttura è un pò diversa nel 1827, per esempio ha due registri di indirizzamento due di dati. Diciamo che si potrebbe ottimizzare, perchè a quanto ho capito, il pic è già capace da solo di scrivere su più byte contemporaneamente. Non finisce mai di stupirmi questo nuovissimo pic, ma la cosa più gratificante è il DAC integrato (purtroppo solo a 5 bit) che mi sta fungendo da generatore sinusoidale =) (peccato non avere più memoria\più velocità, sai com’è la libreria math.h è un pò pesantuccia per 8MIPS e nemmeno optare per una LUT a 360 occorrenze è cosa perchè troppo grande per la ram interna…ma 1.6Hz sn troppo pochi per me, ed oggi vedrò di ottimizzare un pò. Sai com’è pensavo di salvare tutto nell’eeprom, questo era la mia idea iniziale, ma comunque sarebbe stata un’idea svantaggiosa a causa dei lenti tempi di lettura.
          Ps.è astio quello che leggo, o semplicemente la tua pazienza che con me è andata a farsi friggere? >.< heheh

          • #17 da Giovanni Bernardo il 9 luglio 2010

            No no figurati… anzi i contributi come questo li apprezzo, anche perchè non è che ho la possibilità di provare tutti i pic presenti sul mercato e poi questo per me è un hobby e non lo faccio per lavoro… Quando hai messo a punto tutto, magari cerco di procurarmi pure io quel pic e provo quello che hai fatto tu così metto su un articolo a nome tuo se ti fa piacere. Alla fine questo è un modo per condividere tutti insieme le proprie conoscenze, ampliarle e trasmetterle… il sito l’ho messo in piedi per questo… per imparare e discutere

  8. #18 da Luca il 9 luglio 2010

    Giovanni Bernardo :
    …magari cerco di procurarmi pure io quel pic e provo quello che hai fatto tu così metto su un articolo a nome tuo se ti fa piacere.

    I samples esistono proprio per questo, dovresti vedere la mia collezione :)

    Senti una domanda a bruciapelo, dovendo fare una LUT per memorizzare i valori di una sinusoide, un char valori[360]; non entra nella memoria, ma perchè non ne entrano nemmeno 90? Tutti i valori vanno salvati nella RAM vero? Cioè dove posso stipare tutti i miei dati?

    L’idea è questa:

    *******************************************************************************
    #include
    #include
    #define PIC_CLK 32000000
    #include “delay.c”
    #include “lcd.c”

    // Fuses di configurazione
    __CONFIG (FOSC_INTOSC & WDTE_OFF & PWRTE_OFF & MCLRE_ON & CP_OFF & CPD_OFF & BOREN_OFF & CLKOUTEN_ON & IESO_OFF &
    FCMEN_OFF & WRT_ALL & VCAPEN_OFF & PLLEN_OFF & STVREN_OFF & BORV_19 & DEBUG_ON & LVP_OFF);

    void main(void)
    {
    OSCCON = 0b11110000; //Oscillatore a 32MHz
    TRISA=0b00000100;
    TRISB=0b00000000;
    ANSELA=0b00000100;
    ANSELB=0b00000000;

    DACCON0=0b11100000;
    DACCON1=0b00000000;

    unsigned int t=0;
    unsigned char dac[44]; //le alternative sono 89, 179, 359 ma non c’è spazio dice il compilatore!!

    for(t;t<44;t++)
    {
    dac[t]=0b1111+(char)(0b1111*sin(8*t*((3.14159)/180.0)));
    }

    while(1)
    {
    t=0;
    while(t<44)
    {DACCON1=dac[t];
    t++;
    }
    }
    }
    *******************************************************************************

    Scartata la eeprom, come faccio a salvare un array di 360 char in un pic16f1827? Sembra che non c'è mai spazio! Possibile? Eppure ho una ram di 380 bytes, e non entra nemmeno un array da 180 nè da 90! Mi puzza sta cosa, cioè non capisco il perchè!

    Luca

    • #19 da Giovanni Bernardo il 9 luglio 2010

      Si… Mi sono pure registrato alla Microchip ma non ho mai avuto tempo di mettermi a compilare tutti quei form. La questione della RAM forse è causata dalla versione LITE? Ma mi pare strano, sapevo che limitava unicamente la memoria programma a 2000H words e basta.. non sapevo di un limite sulla RAM. Nel tuo caso non capisco perchè assegni i valori ad un array e poi te lo scansioni per assegnarne i valori ad un registro… Non puoi fare direttamente il ciclo for passando i valori al registro, senza creare un array, che in questo caso non ti serve a nulla?
      Ricorda, poi, che se hai bisogno di più ram e di più potenza di calcolo, esistono le serie 24F e dsPIC33… però li c’è da studiare sodo e imparare il C30, e prepararsi ad un altro modo di programmare.

      • #20 da Luca il 10 luglio 2010

        Allora,
        punto primo, la versione è “pro” :)

        Con array da 90:
        ******************************************************************************
        HI-TECH C Compiler for PIC10/12/16 MCUs (PRO Mode) V9.70
        Copyright (C) 2009 Microchip Technology Inc.
        Serial number: HCPICP-45553 (PRO)
        Error [1250] C:\Users\Luca\Desktop\Programmazione Pic\16F1827\generatoresinusoidale.c; 27. could not find space (89 bytes) for variable _dac
        ******************************************************************************

        Con array da 45:
        ******************************************************************************
        HI-TECH C Compiler for PIC10/12/16 MCUs (PRO Mode) V9.70
        Copyright (C) 2009 Microchip Technology Inc.
        Serial number: HCPICP-45553 (PRO)

        Memory Summary:
        Program space used 61Bh ( 1563) of 1000h words ( 38.2%)
        Data space used A9h ( 169) of 180h bytes ( 44.0%)
        EEPROM space used 0h ( 0) of 100h bytes ( 0.0%)
        Configuration bits used 1h ( 1) of 2h words ( 50.0%)
        ID Location space used 0h ( 0) of 4h bytes ( 0.0%)

        Loaded C:\Users\Luca\Desktop\Programmazione Pic\16F1827\Workspace\generatoresinusoidale.cof.

        ********** Build successful! **********
        ******************************************************************************

        Come vedi c’è spazio a volontà, facendo delle prove ho visto che il problema è che non riesce a manipolare array da più di 80 char. Ho ottimizzato il codice con più array ora. Ma il problema comunque non cambia. Ora mi chiedo, perchè non riesce a gestire array più grandi? could not find space (89 bytes) for variable _dac? Ma di space ne hai a volontà mio caro! Bah…

        Punto secondo:
        anche se 8MIPS saranno tanti (relativamente), non è mai un dsPic(con le sue ottimizzazioni circuitali), e calcolare via math.h punto punto il valore, si forma un collo di bottiglia per il quale la max freq generata è 1.6Hz, se invece io effettuo prima tutti i calcoli, dopo farò in modo che l’unico calcolo che devo fare, è l’assegnazione di un valore ad un registro, ed ecco che la freq max sale a 6.5kHz! Ovviamente questo è il valore massimo raggiungibile, con 45 punti per periodo, usarne di meno è troppo distorta, usarne di più ovviamente rallenta!
        Ottimizzazione, la quintessenza dell’ingegnere!

        Punto terzo:
        il passo più lungo della gamba, il dsPic33 è il mio punto d’arrivo, sono un tipo di larghe vedute, c’è prima da solidificare le fondamenta, e poi dopo rompersi la schiena sul dsp con pic, il mio sogno è un’oscilloscopio (con fft e via di lì) fatto con pic display grafico, la teoria c’è tutta (non possiamo lamentarci con questo dell’università, almeno per questo), il problema è la realizzazione, piano piano ci arriveremo.

        Spero di non romperti troppo con tutte queste mie richieste, se posso essere utile qualche volta, non esitare a chiedere!
        Luca

      • #21 da Luca il 10 luglio 2010

        http://forum.htsoft.com/all/showflat.php?Cat=0&Board=pic&Number=162962&Searchpage=1&Main=162912&Words=&topic=&Search=true

        “Making the array global worked just fine! I’m confused.”…”By changing from auto to static duration, you’ve changed the array’s storage class.”…”Upgraded and error dissapeared. ”

        Funziona… ma porca..certo che sto hitech è fatto veramente una zoza su certe cose! Con un’upgrade il tizio ha alla fine risolto tutto. Secondo me i bug li hanno inseriti di proposito per farmi uscire pazzo!

        Luca

        • #22 da Giovanni Bernardo il 10 luglio 2010

          Scusa ma non ho capito, hanno aggiornato il PICC per questo errore? O hai cambiato tu la definizione dell’array?

          • #23 da Luca il 10 luglio 2010

            L’errore a quanto pare è dovuto al compilatore, la versione aggiornata non presenta tale problema. Nel caso mio, ho preferito non aggiornare il compilatore ma aggirare il problema definendo l’array come globale (mettendolo prima del main) ovviamente la definizione cambia, cambiando anche qualchecosachenonhobencapito (forse la locazione di memoria in cui viene salvato?). Così ho solo un mero limite di memoria, posso aumentare l’array finchè non c’entra fisicamente più.

            Ora devo solo vedere come fare in modo da poter dare in pasto direttamente la frequenza desiderata per vedermi generata la sinusoide corrispondente.

  9. #24 da Luca il 13 luglio 2010

    Guarda che dei pic16f1827…allora l’F1827, ok quello lo puoi richiedere nel 2013, l’LF è già più disponibile, se non sbaglio con spedizione immediata, io personalmente, mi sono “accontentato” con un’attesa di 30 giorni e ho preso direttamente il F1827 E/P…sai…qui fà molto caldo! =)
    Comunque guarda se navighi, trovi la pagina dove presentano la nuova serie 16F1… la nuova serie xlp, vedi che quelli sono lo stato dell’arte della microchip, delle mcu alla “mary poppins”.

    Allora, guarda il DAC è l’unica cosa che funge, insomma 5 bit son veramente pochi, però non ci possiamo lamentare, al massimo si aggiunge un passa basso e tagliamo la testa al toro; se levo tutta quella “meccanica” per la temporizzazione, ho una sinusoide “perfetta”, l’oscilloscopio mi caccia una bella sinusoide, ovviamente la precisione è direttamente proporzionale al numero di punti, ed inversamente proporzionale alla frequenza. Il quarzo interno, anche non calibrandolo con OSCCTUNE (come si fà?) funziona bene o male a dovere.
    Quindi diamo per funzionante la generazione della sinusoide.

    Il problema è il calcolo del “del”; praticamente lo noto anche perchè, notato il malfunzionamento, ho dichiarato una variabile char da uguagliarla a del, giusto per inserirla nel watch del pickit, però non mi compila dandomi un errore strano, secondo me sbaglia a convertire in char.

    ******************************************************************************
    char del=dlcal;
    ….
    Error [314] C:\Users\Luca\Desktop\Programmazione Pic\16F1827\generatoresinusoidale.c; 33.28 “;” expected
    ******************************************************************************

    ovviamente il 33.28 è esattamente 12 caratteri dopo il punto e virgola, sembrerebbe non riesce a convertire a char.
    A maggior ragione lo noto, che praticamente indipendentemente dalla freq assegnata, la sinusoide generata è sempre la stessa!

    Poi non parliamo di un’altra cosa stranissima, tipo che la fmax varia, ieri pomeriggio era a 1720 ieri sera a 1240 (ed il quarzo lavora bene…); hai presente quando si parla di “ripetibilità degli strumenti”? Mah..

    Siano benedetti di dspic.
    Comunque ci sbatterò un altro po la testa fra oggi e domani, magari ti faccio sapere, bisognerebbe analizzare tutti i calcoli che fà inserendoli nel main e controllando gli arrotondamenti, comunque ovviamente l’errore in frequenza è elevatissimo, questo già me lo aspettavo, del tipo anche 200Hz per uS in più o meno, però almeno sulle basse frequenze dovrebbe funzionare.
    Bisogna analizzare il del, e vedere come lavora il preprocessore, c’è qualche modo per analizzare le costanti col pickit? A quanto ho notato non c’è modo di inserirle nel watch, ci trovo solo le variabili che effettivamente variano, nemmeno quelle che rimangono costanti pur definendole variabili.

    Luca

    (OT dell’OT, ti ricordi quando ti chiedevo dell’interrupt su portB e tu mi dicesti a che ti serve?, ecco, la risposta più sensata ( e più utilizzata ) è: “per svegliare il pic dallo stato sleep” )

    • #25 da Giovanni Bernardo il 13 luglio 2010

      E’ ovvio che non ho richiesto i “future products” ma quelli disponibili. Solo che alcuni di quelli “disponibili” avevano la disponibilità tra oltre 80 giorni.

      Quell’errore di “expected ;” non ha senso, è capitato alcune volte anche a me mettendo delle routine di delay sui pic12, mi dava un errore del genere o errore di sintassi, quando la sintassi era assolutamente corretta, preso dallo sconforto i ritardi poi li gestii con gli interrupt. Secondo me si tratta di un altro bug. Dovresti postarlo nel forum della microchip.

    • #26 da Giovanni Bernardo il 13 luglio 2010

      per il resto non ti so rispondere…

      • #27 da Luca il 14 luglio 2010

        Mah vabbè, io intanto sospendo un po questo progetto, mi sta dando fin troppi grattacapi, e con questo caldo, diciamo che le cose si complicano non poco.
        Avevo intenzione di postare il problema sul forum della microchip o su ioprogrammo.it, dove posso trovare un forum con un valido supporto?
        Comunque, vuoi che ti spedisca il sorgente prodotto?con tutte le varianti pregresse?
        A quando il tuo articolo sull’i2c? Qua lo stiamo aspettando con ansia! I miei ds1307 si stanno sciogliendo dal caldo nell’attesaa! =)
        Grazie ancora di tutto, Luca

        • #28 da Giovanni Bernardo il 14 luglio 2010

          Guarda… Pure io non vedo l’ora di mettere online tante di quelle cose che ho accantonate… I2C, RTC, PWM, ponti H ecc ecc Il problema, come vedi, è che sono fin troppo meticoloso e ci perdo davvero tanto tempo che non lo immagini. Poi ultimamente la bimba non mi da tregua, in aggiunta il caldo e tanti altri impegni che ho che davvero non riesco a fare nulla. Se vuoi, appena li trovo, ti mando i codici per l’I2C e per il ds1307 via email così magari ci fai pure qualche test e mi aiuti.

          Quello dell’I2C è una versione che ho riadattato da un sorgente per CCS e funziona bene, la libreria per il DS1307 me la sono scritta io e si appoggia alla libreria I2C, pare che funziona benone ma non si può mai dire (la sfiga è sempre dietro l’angolo).

          E’ una cosa fatta bene, come avrai potuto vedere non si trova niente di buono già pronto in giro: sempre codici “mozzicati”, non documentati e lacunosi. Appena ho tempo di cercarli e se li trovo te li mando al tuo indirizzo email, tanto i codici come mio solito sono abbastanza commentati e dovrebbe essere chiaro tutto. Per i collegamenti però te la vedi tu, tanto non è niente di difficoltoso: basta ricordarsi di mettere le resistenze di pullup sulle due linee I2C, per il resto fa tutto il codice.

          I forum dove in genere “opero” io sono quelli di Sergio Fiocco (che ora si è spostato su http://www.taliaki.net) o quello di robot-italy (www.robot-italy.net). C’è anche il forum di roboitalia: forum.roboitalia.com

          Il codice me lo manderai quando è a buon punto ;) tanto per ora non ho nemmeno il tempo di provarlo.

  10. #29 da odessos il 26 dicembre 2010

    Intanto faccio gli auguri di buon tutto, poi faccio la domandina: all’inizio di questa sezione di corso parli ai una serie di valori che sono da inserire nella eeprom all’inizio del programma con la macro _eeprom_data, non capisco, parli di 10 valori ma in realtà sono due file da 8?
    Questi valori sono generici o c’è una tabella precisa da inserire, nel manuale del compilatore Hitec-C parla di valori progressivi da 0×00 a 0×0F.

  11. #32 da gabrielegalli il 7 novembre 2011

    Buongiorno Giovanni.
    Lavoro con un pickit2 e un pic16f886.
    Carico la EEPROM alla programmazione. il contenuto lo metto in output su una porta e lo leggo con un analizzatore di stati logici.
    Non appena stacco il programmatore pickit2 e alimento dall’esterno l’output va a zero indefinitamente.
    Potresti spiegarmi cortesemente perchè?

  12. #33 da Giovanni Bernardo il 10 luglio 2010

    Ho capito… Allora abbiamo scoperto un’altro problema di questa versione del PICC… buono a sapersi. Quando hai terminato questo progetto del generatore di onde sinusoidali, fammi un fischio che lo pubblichiamo, così lo provo pure io col mio oscilloscopio e metto le immagini delle onde prodotte. nel frattempo se hai degli appunti sull’argomento su cui cominiciare a lavorare me li puoi anche inviare: gianni at settorezero.com

  13. #34 da Luca il 12 luglio 2010

    Lo so lo so, stiamo sforando in un OT colossale, (ma un forum qui no?).
    Insomma, non riesco proprio a rendere il codice versatile al punto da inserire direttamente la frequenza desiderata nel codice. Ti posto tutto il codice commentato, inutile dirti che il timing è tutto sballato, i calcoli teoricamente esatti sono praticamente inefficaci! Non fanno assolutamente quello che devono fare, o almeno lo fanno parecchio male. Mi daresti qualche tua idea sul mio listato? Cosa ne pensi?

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

    #include
    #include
    #define PIC_CLK 32000000
    #include “delay.c”

    // Fuses di configurazione
    __CONFIG (FOSC_INTOSC & WDTE_OFF & PWRTE_OFF & MCLRE_ON & CP_OFF & CPD_OFF & BOREN_OFF & CLKOUTEN_ON & IESO_OFF &
    FCMEN_OFF & WRT_ALL & VCAPEN_OFF & PLLEN_OFF & STVREN_OFF & BORV_19 & DEBUG_ON & LVP_OFF);

    //Faccio fare i conti al preprocessore invece che al pic, e svolgo tutti calcoli possibili a priori
    #define punti 180//selezionare quanti punti per sinusoide mettere (45/90/180/360)
    #define pnt punti-1
    #define mul (360/punti)*(3.14159265359/180)

    #define fre 100 //frequenza desiderata
    #define fmax 1240 //frequenza massima generata commentando la riga di ritardo nella generazione
    #define del (((1/fre)/punti)-(1/fmax)/punti)/1000000

    //mi calcolo il ritardo da aggiungere ad ogni ciclo in modo da raggiungere la frequenza desiderata
    //ho la frequenza massima, mi calcolo il quanto di tempo per ogni ciclo, faccio la differenza
    //con il quanto di tempo ideale per ogni ciclo, e lo converto in microsecondi

    unsigned char dac[pnt]; //lo inserisco qui per evitare il bug secondo il quale se non dichiarata globale
    //l’array non può superare gli 80 char
    int t=0;

    void main(void)
    {
    OSCCON=0b11110000; //Oscillatore a 32MHz
    TRISA=0b00000100;
    TRISB=0b00000000;
    ANSELA=0b00000100;
    ANSELB=0b00000000;
    DACCON0=0b11100000;

    for(t;t<pnt;t++)
    dac[t]=0b10000+(char)(0b1111*sin(t*mul));

    while(1)
    {
    t=0;
    for(t;t<pnt;t++)
    {DACCON1=dac[t];
    DelayUs(del);
    }
    }

    }

    #include
    #include
    #define PIC_CLK 32000000
    #include “delay.c”

    // Fuses di configurazione
    __CONFIG (FOSC_INTOSC & WDTE_OFF & PWRTE_OFF & MCLRE_ON & CP_OFF & CPD_OFF & BOREN_OFF & CLKOUTEN_ON & IESO_OFF &
    FCMEN_OFF & WRT_ALL & VCAPEN_OFF & PLLEN_OFF & STVREN_OFF & BORV_19 & DEBUG_ON & LVP_OFF);

    //Faccio fare i conti al preprocessore invece che al pic, e svolgo tutti calcoli possibili a priori
    #define punti 180//selezionare quanti punti per sinusoide mettere (45/90/180/360)
    #define pnt punti-1
    #define mul (360/punti)*(3.14159265359/180)

    #define fre 100 //frequenza desiderata
    #define fmax 1240 //frequenza massima generata commentando la riga di ritardo nella generazione
    #define del (((1/fre)/punti)-(1/fmax)/punti)/1000000

    //mi calcolo il ritardo da aggiungere ad ogni ciclo in modo da raggiungere la frequenza desiderata
    //ho la frequenza massima, mi calcolo il quanto di tempo per ogni ciclo, faccio la differenza
    //con il quanto di tempo ideale per ogni ciclo, e lo converto in microsecondi

    unsigned char dac[pnt]; //lo inserisco qui per evitare il bug secondo il quale se non dichiarata globale
    //l’array non può superare gli 80 char
    int t=0;

    void main(void)
    {
    OSCCON=0b11110000; //Oscillatore a 32MHz
    TRISA=0b00000100;
    TRISB=0b00000000;
    ANSELA=0b00000100;
    ANSELB=0b00000000;
    DACCON0=0b11100000;

    for(t;t<pnt;t++)
    dac[t]=0b10000+(char)(0b1111*sin(t*mul));

    while(1)
    {
    t=0;
    for(t;t<pnt;t++)
    {DACCON1=dac[t];
    DelayUs(del);
    }
    }

    }
    ******************************************************************************
    Ok ci sono parecchie cose da fare, per esempio gestire in automatico il numero di punti ottimale (con 180 non si puo superare il kHz e mezzo), ok bisogna comunque prevenire l'overflow di del quando utilizzato su DelayUs() [Nb. uso le routine di delay di microchipc.com].. ma almeno per grandi linee..perchè non fungeee?

    Quando la matematica, approssimata, diventa un opinione.

    Ps. debuggando col pickit, controllando i valori con watch expression, inserendo i calcoli nel main, escono valori strani.

    Le tue idee a caldo?

  14. #35 da Giovanni Bernardo il 12 luglio 2010

    Non ti preoccupare… Se sei OT tu è meglio che chiudiamo! Potrei pensare che succede qualche cosa con i tipi di variabile… Il “Mul” lo fai calcolare al preprocessore, però nei calcoli ci metti dentro un 3.14, così com’è dichiarato penso tiri fuori un valore intero con un’approsimazione strana… Il fatto è che non puoi certo dichiararlo di tipo float perchè poi al dac devi comunque passare un intero… Non ti saprei dire … se no puoi provare a dichiararlo come float tanto poi foi forzi il casting in char. Per il resto mi sembra ok….Non vedo perchè non debba funzionare… In teoria mi sembra che non faccia una piega… Il guaio è che non ho mai avuto l’occasione di utilizzare un pic con il DAC integrato quindi non è che posso esserti d’aiuto piu di tanto… Ho fatto la richiesta alla microchip ma questi pic qui avevano la disponibilità tra 90 giorni e così ho desistito. Certo che con solo 5 bit chissà se si riesce a tirare fuori una bella sinusoide… Hai fatto pure delle prove utilizzando un quarzo esterno anzichè quello interno? A me a volte con l’oscillatore interno pure sono successe cose strane, suppongo che il caldo a volte li fa impazzire. Con un oscilloscopio hai provato? Cosa ti tira fuori?

  15. #36 da Giovanni Bernardo il 12 luglio 2010

    Tra l’altro con mia grande sorpresa ho visto che sia il product selector che la ricerca parametrica sul sito della Microchip non hanno in elenco il DAC… Ho comunque trovato disponibile subito il 16F1939… che è un mostro… Adesso chissà quanto tocca aspettare

Devi essere collegato per lasciare un commento.

  1. Ancora nessun trackback
settorezero.com e il logo Zroid™ ©2007÷2012 Giovanni Bernardo - E' vietata la copia e la distribuzione anche parziale dei contenuti di questo sito web senza l'esplicito consenso dell'autore.
I contenuti di settorezero.com sono distribuiti sotto una licenza Creative Commons Attribuzione-Non Commerciale-Non Opere derivate 2.5 Italia a cui vanno aggiunte le condizioni d'uso definite nel disclaimer.
settorezero.com e tutti i suoi contenuti sono tutelati dalla legge sul diritto d'autore per cui i trasgressori sono perseguibili a norma di legge.
Creative Commons BY-NC-ND 2.5
Il tema di questo sito è basato sul tema Fusion per wordpress, realizzato originariamente da digitalnature e fa uso del plugin Wassup per il computo delle statistiche. Per contattare l'autore siete pregati di utilizzare la sezione contatti.
Per essere aggiornato con tutte le novità di settorezero.com seguici anche anche su Facebook Twitter Tumblr Blogspot Youtube.