Programació en C del PIC 18F45K20

Referència Trucs Perifèrics   Recursos CITCEA
Tutorial Exemples Projectes   Inici

Exemple MP - Dades a la memòria de programa

En el programa següent (similar al de l'exemple EE) guardem uns valors a la memòria de programa en el moment de programar (definits com a constants) i després els llegim de la memòria de programa.

El nostre programa tindrà 8 patrons d'encesa dels LED guardats en un vector i els anirà mostrant cada cop que premem el polsador. Quan els hagi mostrat tots dos cops llegirà un nou joc de patrons de la memòria de programa (adreça 0x600) i els mostrarà en lloc dels antics.

Els valors que guardem són:

	   Patrons inicials					   Patrons alternatius
	   LED			Valor			   	   LED			Valor
	76 54 32 10		(hex)				76 54 32 10		(hex)
	00 11 00 11		 33				11 10 11 10		 EE
	10 10 10 10		 AA				00 01 00 01		 11
	11 11 00 00		 F0				11 11 00 01		 F1
	11 00 11 00		 CC				00 01 11 11		 1F
	01 01 01 01		 55				10 00 00 01		 81
	00 00 11 11		 0F				01 11 11 10		 7E
	10 01 10 01		 99				10 01 01 10		 96
	01 10 01 10		 66				01 10 10 01		 69

I el programa és:

#pragma config FOSC = INTIO67, FCMEN = OFF, IESO = OFF				// CONFIG1H
#pragma config PWRT = OFF, BOREN = SBORDIS, BORV = 30				// CONFIG2L
#pragma config WDTEN = OFF, WDTPS = 32768					// CONFIG2H
#pragma config MCLRE = OFF, LPT1OSC = OFF, PBADEN = ON, CCP2MX = PORTC		// CONFIG3H
#pragma config STVREN = ON, LVP = OFF, XINST = OFF				// CONFIG4L
#pragma config CP0 = OFF, CP1 = OFF, CP2 = OFF, CP3 = OFF			// CONFIG5L
#pragma config CPB = OFF, CPD = OFF						// CONFIG5H
#pragma config WRT0 = OFF, WRT1 = OFF, WRT2 = OFF, WRT3 = OFF			// CONFIG6L
#pragma config WRTB = OFF, WRTC = OFF, WRTD = OFF				// CONFIG6H
#pragma config EBTR0 = OFF, EBTR1 = OFF, EBTR2 = OFF, EBTR3 = OFF		// CONFIG7L
#pragma config EBTRB = OFF							// CONFIG7H
#include "p18f45k20.h"				// Carrega el fitxer d'adreces i paràmetres del PIC 18F45K20
#include <xc.h>					// Carrega el fitxer de funcions
unsigned char Posicio;  			// Variable de 8 bits per a l'índex
unsigned char Itera;  				// Variable de 8 bits per controlar les iteracions
unsigned long Adressa;				// Variable de 32 bits per a l'adreça
unsigned int Llarg;				// Variable de 16 bits per a la llargada
						// La següent llista de valors es guarda a la memòria de programa
						// (ja que hem posat const) a l'adreça 0x600
const unsigned char LlistaMP[8] @ 0x600 = {0xEE, 0x11, 0xF1, 0x1F, 0x81, 0x7E, 0x96, 0x69};
unsigned char Llista[8] = {0x33, 0xAA, 0xF0, 0xCC, 0x55, 0x0F, 0x99, 0x66};
void main (void)
{
	TRISD = 0b00000000;     		// El port D és de sortida
	ANSEL = 0;				// Desactiva totes les entrades analògiques
	ANSELH = 0;	
	INTCON2bits.RBPU = 0;			// Habilita el control de resistències de pull-up al port B
	WPUBbits.WPUB0 = 1;			// Activa la resistència de pull-up a RB0
	TRISBbits.TRISB0 = 1;      		// RB0 és entrada
						// Configuració d'interrupció a INT0 (RB0)
	INTCON2bits.INTEDG0 = 0;		// Interrupció quan es desactiva (quan es prem el polsador)
						// INT0 sempre és de prioritat alta, no cal definir-ho
	INTCONbits.INT0IF = 0;			// Inicialitzem amb el bit de control desactivat
	INTCONbits.INT0IE = 1;			// Habilitem la interrupció INT0
	RCONbits.IPEN = 0;			// Només un nivell d'interrupció
	Posicio = 0;				// Comencem a la posició 0
	Itera = 0;
	Adressa = 0x600;			// Defineix l'adreça que hem de llegir
	Llarg = 8;				// Indica la llargada del registre
	LATD = Llista[Posicio];			// Primer element als LED
	INTCONbits.PEIE = 1;			// Permet les interrupcions de perifèrics
	INTCONbits.GIE = 1;			// Permet les interrupcions globalment
	while (1)				// Bucle infinit sense fer res
		;
}
void interrupt polsador(void)			// funció d'interrupcions
{
	if (INTCONbits.INT0IF)			// Comprovem que hi ha interrupció per INT0
	{
		_delay(20000);	    		// Retard per evitar rebots
		INTCONbits.INT0IF = 0;		// Desactivem el bit que indica la interrupció
		if (PORTBbits.RB0 == 0)		// Si el polsador encara està premut
		{
			Posicio++;		// Incrementem la variable
			if (Posicio == 8)
			{
				Posicio = 0;	// Quan haguem fet els 8, tornem a començar
				Itera++;	// Nova iteració
			}
			if ((Itera == 2) && (Posicio == 0))
						// A les dues voltes
				ReadFlash(Adressa, Llarg, Llista);
						// Llegeix els nous valors per a la llista
			LATD = Llista[Posicio];	// Llegeix el valor i ho posa als LED
		}
	}
}

Ara farem servir l'escriptura. Definirem dos vectors (Llista1 i Llista 2) a la memòria de dades in un (Llista MP) a la memòria de programa. Tota l'estona farem servir el vector de la memòria de programa per activar els LED però cada dues iteracions copiarem la llista contraria a la memòria de programa.

#pragma config FOSC = INTIO67, FCMEN = OFF, IESO = OFF				// CONFIG1H
#pragma config PWRT = OFF, BOREN = SBORDIS, BORV = 30				// CONFIG2L
#pragma config WDTEN = OFF, WDTPS = 32768					// CONFIG2H
#pragma config MCLRE = OFF, LPT1OSC = OFF, PBADEN = ON, CCP2MX = PORTC		// CONFIG3H
#pragma config STVREN = ON, LVP = OFF, XINST = OFF				// CONFIG4L
#pragma config CP0 = OFF, CP1 = OFF, CP2 = OFF, CP3 = OFF			// CONFIG5L
#pragma config CPB = OFF, CPD = OFF						// CONFIG5H
#pragma config WRT0 = OFF, WRT1 = OFF, WRT2 = OFF, WRT3 = OFF			// CONFIG6L
#pragma config WRTB = OFF, WRTC = OFF, WRTD = OFF				// CONFIG6H
#pragma config EBTR0 = OFF, EBTR1 = OFF, EBTR2 = OFF, EBTR3 = OFF		// CONFIG7L
#pragma config EBTRB = OFF							// CONFIG7H
#include "p18f45k20.h"				// Carrega el fitxer d'adreces i paràmetres del PIC 18F45K20
#include <xc.h>					// Carrega el fitxer de funcions
unsigned char Posicio;  			// Variable de 8 bits per a l'índex
unsigned char Itera;  				// Variable de 8 bits per controlar les iteracions
unsigned long Adressa;				// Variable de 32 bits per a l'adreça de lectura
unsigned long Fi_esborra;			// Final de l'esborrat
unsigned int Llarg;				// Variable de 16 bits per a la llargada
						// Definim les dues llistes i la llista de treball
						// Inicialment LlistaMP = Llista1
const unsigned char LlistaMP[8] @ 0x800 = {0x33, 0xAA, 0xF0, 0xCC, 0x55, 0x0F, 0x99, 0x66};
unsigned char Llista1[8] = {0x33, 0xAA, 0xF0, 0xCC, 0x55, 0x0F, 0x99, 0x66};
unsigned char Llista2[8]  = {0xEE, 0x11, 0xF1, 0x1F, 0x81, 0x7E, 0x96, 0x69};
void main (void)
{
	TRISD = 0b00000000;     		// El port D és de sortida
	ANSEL = 0;				// Desactiva totes les entrades analògiques
	ANSELH = 0;	
	INTCON2bits.RBPU = 0;			// Habilita el control de resistències de pull-up al port B
	WPUBbits.WPUB0 = 1;			// Activa la resistència de pull-up a RB0
	TRISBbits.TRISB0 = 1;    		// RB0 és entrada
						// Configuració d'interrupció a INT0 (RB0)
	INTCON2bits.INTEDG0 = 0;		// Interrupció quan es desactiva (quan es prem el polsador)
						// INT0 sempre és de prioritat alta, no cal definir-ho
	INTCONbits.INT0IF = 0;			// Inicialitzem amb el bit de control desactivat
	INTCONbits.INT0IE = 1;			// Habilitem la interrupció INT0
	RCONbits.IPEN = 0;			// Només un nivell d'interrupció
	Posicio = 0;				// Comencem a la posició 0
	Itera = 0;
	Llarg = 8;				// Indica la llargada del registre
	Adressa = 0x800;			// Defineix l'adreça
	Fi_esborra = Adressa + Llarg;		// Posicions a esborrar
	LATD = LlistaMP[Posicio];		// Primer element als LED
	INTCONbits.PEIE = 1;			// Permet les interrupcions de perifèrics
	INTCONbits.GIE = 1;			// Permet les interrupcions globalment
	while (1)				// Bucle infinit sense fer res
		;
}
void interrupt polsador(void)			// funció d'interrupcions
{
	if (INTCONbits.INT0IF)			// Comprovem que hi ha interrupció per INT0
	{
		_delay(20000);	    		// Retard per evitar rebots
		INTCONbits.INT0IF = 0;		// Desactivem el bit que indica la interrupció
		if (PORTBbits.RB0 == 0)		// Si el polsador encara està premut
		{
			Posicio++;		// Incrementem la variable
			if (Posicio == 8)
			{
				Posicio = 0;	// Quan haguem fet els 8, tornem a començar
				Itera++;	// Nova iteració
			}
			if ((Itera == 2) && (Posicio == 0))
			{			// A les dues voltes passem a la llista 2
				EraseFlash(Adressa, Fi_esborra);		// Esborra la memòria de programa
				WriteBytesFlash(Adressa, Llarg, Llista2);	// Escriu a la memòria de programa
			}
			if ((Itera == 4) && (Posicio == 0))
			{			// A les quatre voltes passem a la llista 1
				EraseFlash(Adressa, Fi_esborra);		// Esborra la memòria de programa
				WriteBytesFlash(Adressa, Llarg, Llista1);	// Escriu a la memòria de programa
				Itera = 0;	// Torna a posar a zero
			}
			LATD = LlistaMP[Posicio];				// Llegeix el valor
										// i ho posa als LED
		}
	}
}

Si després de picar a la icona Program Device fem:

View Program Memory

Obtindrem:

View Program Memory

és a dir, els valors que hem posat a const unsigned char LlistaMP[8] encara que, si ens fixem bé, no en l'ordre correcte. El motiu del canvi d'ordre és que a la finestra s'està interpretant el que es llegeix a la memòria de programa com si fossin instruccions. El processador guarda les instruccions en 16 bits però guarda primer el segon byte i després el primer. Nosaltres hem escrit:

	0x800		 33
	0x801		 AA
	0x802		 F0
	0x803		 CC
	...

Però ell ho interpreta així:

	AA33		BTFSS 0x33, 5, ACCESS
	CCF0		MOVFF 0xCF0, 0xF55
	...

i, per això ho escriu en ordre contrari. Un cop sabut això, observem que hi ha exactament els valors que hem definit.

Si ara premem el botó Read Device Memory obtindrem la mateixa pantalla amb els mateixos valors.

Però si premem el polsador de la placa més de 16 vegades (per exemple 17) i tornem a llegir la memòria del dispositiu, obtindrem els nous valors:

O sigui que en tot moment podem veure el contingut real de la memòria de programa.

 

 

Llicència de Creative Commons
Aquesta obra d'Oriol Boix està llicenciada sota una llicència no importada Reconeixement-NoComercial-SenseObraDerivada 3.0.