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
fem:

Obtindrem:

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

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