Haz una pregunta
  Foros de Electrónica » Diseño digital » Microcontroladores y sistemas embebidos
Foros Registrarse ¿Olvidaste tu contraseña?

Temas similares

26/02/2013 #21

Avatar de Melghost

Hola, Meta. Si me lo permites, voy a hacerte unas cuantas críticas constructivas.

Bueno, pues así a simple vista...

1- Yo prescindiría de las interrupciones para esta aplicación, pero bueno... para gustos se hicieron los colores.

2- Mira qué truco: Como tienes justo 4 estados para tus LEDs, ¿por qué no haces una cuenta normal de 0 a 3 (que son 4 estados) y en vez de rotar el byte, simplemente lo incrementas? Con una simple instrucción AND consigues que la cuenta nunca tenga más de 2 bits, y por tanto de 3 pasará a 0 automáticamente. ¿Qué consigues con esto? Ahorrarte unas cuantas instrucciones y saltos que ahora mismo están enrevesando un poco tu programa.

3- Si prefieres seguir con el método de la rotación: ModoSiguiente: ¿Primero rotas el byte y luego te aseguras de que el Carry esté a cero? Cambia el orden de esas dos instrucciones, o bien pon a cero el bit 0 del byte que has rotado.

4- Inicio: ¿Configuras los puertos bit a bit, estando en el mismo registro TRISIO? ¿Y si lo configuras de un plumazo?
movlw b'00000100'
movwf TRISIO
Por cierto, has intentado configurar el tipo de puerto con GPIO en vez de con TRISIO.

5- Dentro de la interrupción preguntas si se está pulsando el pulsador. ¿No se trata del mismo pulsador cuya pulsación ha generado la interrupción? Parece un poco redundante...

6- Consultas el estado del byte rotativo de bit en bit, repitiendo 4 veces las instrucciones (menos mal que no son 200 estados diferentes ). Esto es una desventaja de ese sistema rotativo. Luego te voy a contar otro truco con el que resuelves de un plumazo este y varios problemas más.

7- ROM1, ROM2, ROM3, ROM4: Nuevamente construyes el byte de salidas bit a bit. No pasa nada por meter un valor a un bit que esté configurado como entrada. Puedes mandar las salidas con dos únicas instrucciones:
ROM1:
movlw b'00000010'
movwf GPIO

8- Lo mismo, cuatro rutinas (ROM1, ROM2, ROM3, ROM4) para una misma operación: Sacar un valor por los puertos.

Y de momento no voy a analizar más. Ahora te voy a contar el tan esperado truco:

1- Tienes que hacerte una tabla de 4 bytes, y esta tabla la vas a guardar en la misma memoria de programa (o sea, que estará en la EEPROM y será inalterable). Esta tabla contiene los valores que quieres darle al registro GPIO para cada estado.

2- Tienes que hacer el contador de estado de la forma que te dije antes: Un contador de 0 a 3, y que lo reinicias con una simple instrucción AND.

3- El dato que vas a recuperar de la EEPROM y guardar en ella cada vez que haya un cambio de estado, es precisamente ese contador de 0 a 3.

4- Vas a utilizar los registros de acceso a la EEPROM para acceder a la tabla de los valores de salidas (la que creaste en el paso 1 de este truco). Primero inicializas EEADR con la dirección del primer byte de la tabla. Después sólo tienes que sumarle el valor del contador de estado (el que hiciste de 0 a 3) y ya podrás leer de la EEPROM el byte que tienes que enviar al GPIO.

Creo que te va a quedar más elegante así. Inténtalo y verás qué bien.
26/02/2013 #22

Avatar de Meta

Buen explciación.

Empezaré desde cero. Por lo que cuentas, si no hay que usar las interrupciones, mejor que mejor, me tenía loco. Eso si, aprendí un poquito como manejarlas, solo un poco.

También por lo que cuentas, no hacer desplazamiento de bits, ejjejeeej.

Estoy haciendo un diagrama de flujo y explicaciones antes de empezar.



Vuelvo cuando tenga las cosas mejore hechas y los primeros asm configurados. Hay que crear una tabla tipo así, por lo que cuentas.

Código:
Principal
    movf    PORTA,W                ; Lee el valor de las variables de entrada.
    andlw    b'00000111'            ; Se queda con los tres bits de entrada.
    addwf    PCL,F                ; Salta a la configuración adecuada.
Tabla
    goto    Configuracion0
    goto    Configuracion1
    goto    Configuracion2
    goto    Configuracion3
    goto    Configuracion4
    goto    Configuracion5
    goto    Configuracion6
    goto    Configuracion7
Configuracion0
    movlw     b'00001010'            ; (Configuración 0).
    goto    ActivaSalida
Configuracion1
    movlw     b'00001001'            ; (Configuración 1).
    goto    ActivaSalida
Configuracion2
    movlw     b'00100011'            ; (Configuración 2).
    goto    ActivaSalida
Configuracion3
    movlw     b'00001111'            ; (Configuración 3).
    goto    ActivaSalida
Configuracion4
    movlw     b'00100000'            ; (Configuración 4).
    goto    ActivaSalida
Configuracion5
    movlw     b'00000111'            ; (Configuración 5).
    goto    ActivaSalida
Configuracion6
    movlw     b'00010111'            ; (Configuración 6).
    goto    ActivaSalida
Configuracion7
    movlw     b'00111111'            ; (Configuración 7).
ActivaSalida
    movwf    PORTB                ; Visualiza por el puerto de salida.
    goto     Principal

    END
Deja investigar, puedes aportar alguna pista o ayuda si lo deseas.

Saludo.
27/02/2013 #23

Avatar de Melghost

No, no... Mira esto:

(...)
incf ContadorEstado,W ;Incrementa el valor del contador de estado (0..3)
andlw b'00000011' ;Si pasa de 3, lo pone a 0. Si no, no pasa nada.
movwf ContadorEstado ;Guarda el valor donde estaba.
(...)

Con 3 instrucciones y ningún salto, incrementas el contador y si pasa de 3 lo pones a 0.

Mira esto otro:

(...)
bsf status,rp0 ;Banco 1
movlw Tabla ;Primera posición de la tabla
movwf EEADR ;Apunta ahí
movf ContadorEstado,W ;Coge el contador
addwf EEADR ;Suma el contador para apuntar al dato que nos interesa
bsf EECON1,RD ;Lee el valor de la tabla
movf EEDATA,W ;Pasa el valor a W para trabajar con él.
(...)

ORG EEPROM (no sé dónde está; tendrás que leerte el datasheet)
Tabla
DB 0x23 ;Byte de ejemplo para sacar por el puerto en el caso 0
DB 0x53 ;Byte para el caso 1
DB 0x25 ;Caso 2
DB 0x75 ;Caso 3 (son todos ejemplos aleatorios que yo he puesto porque voy con prisa)


Hala, sigue tú.
27/02/2013 #24

Avatar de Meta

Gracias, voy a investigar.

He intentado hacer lo que quiero en C# por probar y curiosidad. Aún creo que no está bien del todo.

La explicación:

1. Encender el aparato en Power ON también enciende el PIC. En ese momento Reset = 0 durante un tiempo.
2. El PIC ignora ese Reset=0 que detecta la primera vez.
3. El PIC lee la EEPROM interna.
4. Si la EEPROM está vacío carga la primera configuración, llamado ROM1. Luego pasa directemente al paso 6.
5. Si la EEPROM ya tiene información almacenada, por ejemplo 1010 que corresponde a la ROM2, irá directamente a ese lugar. (Ver tabla abajo).

GP2|GP0 GP1 GP4 GP5
------+----------------------------
1) | 0 1 0 0 ROM1
2) | 1 0 1 0 ROM2
3) | 0 1 1 0 ROM3
4) | 1 0 0 1 ROM4



Luego paso directamente al paso 6.


6. Si dejas pulsado Reset=0 durante 5 seg. Cambia de configuración. Por ejemplo, si estábamos en el ROM2, nos pasaremos a ROM3.

7. Si pulso Reset=0 solo un momento o inferior a los 5 seg, no hace nada el PIC. Solo se resetea el aparato.



Espero que se entienda, de todas formas pongo el código para que no pezque o te quedes : aplauso:.

Código:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace Prueba2
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.Title = "Simulador PIC12F629 programado v0.01";

            Console.WriteLine("Enciende el aparato al ejecutar esta aplicación.");
            int EEPROM = 0x00; // EEPROM vacío.

            int Contador = 0; // Contador para saber la posición de las ROMs.


            int Flag1 = 1;
            while (true)
            {
                Console.WriteLine("Este paso se repetirá una y otra vez ya que esta pantalla hace de Reset.\n");
                Console.Write("Pulsa el número '0' ó '1' que hace de Reset: ");
                string R = Console.ReadLine(); // Espera que pulses 0 o 1 que hace de Reset.
                string Reset = "0";
                Thread.Sleep(5000); // Retardo de 5 segundos.
                Console.Beep();

            // ¿La EEPROM está vacío?  
            if ((EEPROM == 0100) || (EEPROM == 1010) || (EEPROM == 0110) || (EEPROM == 1001)) // No está vacío.
            {
                //if (Contador == 1)
                //{
                //    Console.WriteLine("Carga la siguiente configuración.");
                //    Console.WriteLine("1111111111111111111111111111111");
                //    EEPROM = 1010;
                //}
                //if (Contador == 2)
                //{
                //    Console.WriteLine("Carga la siguiente configuración.");
                //    Console.WriteLine("2222222222222222222222222222222");
                //    EEPROM = 1010;
                //}
                //if (Contador == 3)
                //{
                //    Console.WriteLine("Carga la siguiente configuración.");
                //    Console.WriteLine("3333333333333333333333333333333.");
                //    EEPROM = 0110;
                    
                //}
                //if (Contador == 4)
                //{
                //    Console.WriteLine("Carga la siguiente configuración.");
                //    Console.WriteLine("44444444444444444444444444444zzzz");
                //    EEPROM = 1001;
                //}
        
            }  
            else // Sí. Entonces carga el primer ROM.
            {
                Console.WriteLine("Carga valor predeterminado de la ROM1 a 0100.");
                Console.WriteLine("Lo guarda en la EEPROM");
                int Predetermonado = 0100;
                EEPROM = Predetermonado;
                Console.WriteLine("Ahora selecciona el primer ROM.");
            }

            

            switch (EEPROM)
            {
                case 0100:
                    if (Flag1 == 1)
                    {
                        Console.ForegroundColor = ConsoleColor.Green;
                        Console.WriteLine("****************************** ROM1 Cargado ******************************");
                        Console.WriteLine("Configuración: 0100.\n");
                        Console.ForegroundColor = ConsoleColor.Gray;
                        Flag1 = 0;
                    }

                    // ¿Se ha pulsado Reset = 0?
                    if (Reset == R)
                    {
                        Console.WriteLine("Has pulsado Reset.");
                        EEPROM = 1010;
                        Contador++;
                        Console.WriteLine("Carga la EEPROM valor 1010 de la ROM2.");
                    }
                    break;
                case 1010:
                    Console.ForegroundColor = ConsoleColor.Magenta;
                    Console.WriteLine("****************************** ROM2 Cargado ******************************");
                    Console.WriteLine("Configuración: 1010.");
                    Console.ForegroundColor = ConsoleColor.Gray;
                    if (Reset == R)
                    {
                        Console.WriteLine("Has pulsado Reset.");
                        EEPROM = 0110;
                        Contador++;
                        Console.WriteLine("Carga la EEPROM valor 0110 de la ROM3.");
                    }
                    break;
                case 0110:
                    Console.ForegroundColor = ConsoleColor.Yellow;
                    Console.WriteLine("****************************** ROM3 Cargado ******************************");
                    Console.WriteLine("Configuración: 0110.");
                    Console.ForegroundColor = ConsoleColor.Gray;
                    if (Reset == R)
                    {
                        Console.WriteLine("Has pulsado Reset.");
                        EEPROM = 1001;
                        Contador++;
                        Console.WriteLine("Carga la EEPROM valor 1001 de la ROM4.");
                    }
                    break;
                case 1001:
                    Console.ForegroundColor = ConsoleColor.Red;
                    Console.WriteLine("****************************** ROM4 Cargado ******************************");
                    Console.WriteLine("Configuración: 1001.");
                    Console.ForegroundColor = ConsoleColor.Gray;
                    if (Reset == R)
                    {
                        Console.WriteLine("Has pulsado Reset.");
                        EEPROM = 0100;
                        Contador++;
                        Console.WriteLine("Carga la EEPROM valor 0100 de la ROM4.");
                        Flag1 = 1;
                    }
                    break;
                default:
                    Console.WriteLine("Default case");
                    break;
            }
            
            }
        }
    }
}
Me acabo de dar cuenta que no funciona con fundamenteo, debo corregirlo mejor. Si todo sale bien, capaz qu elo pruebo con el CCS y menos asm que me tiene negro. .

A parte de mejorarlo, aún no le he puesto los retardos o timer en ningún sitio.

Si dejas pulsado 5 segundos el pin que hace de Reset el PIC a 0, cambia de estado en sus salidas.

Se que el C# no tiene nada que ver con los PIC, el concepto al C de CCS si te lo da.
Aún así voy a investigar con el asm, por lo que veo, hay que usar hasta los TIMER del PIC para conseguir 5 seg. Esto en asm se complica demasiado. Gracias por las ayudas sigo aquí, ejeje.
Un saludo.
Imágenes Adjuntas
Tipo de Archivo: png eeprom.png (75,8 KB (Kilobytes), 54 visitas)
27/02/2013 #25

Avatar de Meta

Sigo de terco con el asm. Por ahora tengo el curpo. Voy analizar lo que dices arriba.

Código:
;-(FlagsModos)=b'00000001'. Está en el modo "Modo1".
;-(FlagsModos)=b'00000010'. Está en el modo "Modo2".
;-(FlagsModos)=b'00000100'. Está en el modo "Modo3".
;-(FlagsModos)=b'00001000'. Está en el modo "Modo4".
;
;
;GP2|GP0 GP1 GP4 GP5
;---+----------------
;1) | 0   1   0   0
;2) | 1   0   1   0
;3) | 0   1   1   0
;4) | 1   0   0   1
;
;ZONA DE DATOS*****************************************************************
    LIST P=12F629                          ;Procesador usado.
    INCLUDE <P12F629.INC>                  ;Fichero que definen las etiquetas.

    __CONFIG   _CP_OFF & _CPD_OFF & _BODEN_OFF & _MCLRE_OFF & _WDT_OFF & _PWRTE_ON & _FOSC_INTRCIO

; Porque uso MPLAB X, es para que se vea el nombre de la RAM.
Temps udata_shr
ContadorEstado res 1
Temp2 res 1
Temp3 res 1
;    CBLOCK  0x20
;    ENDC

;ZONA DE EEPROM****************************************************************
    ORG     0x2100

;ZONA DE CÓDIGOS***************************************************************
    ORG     0                   ;El programa comienza en la dirección 0.
    goto    Inicio

;    ORG     0x04
;    goto    ServicioInterrupcion

Inicio
    clrw
    BANKSEL OSCCAL              ;Selecciona banco 1.
    call    0x3FF
    movlw b'00000100'
    movwf TRISIO
    movlw   b'00001111'
    movwf   OPTION_REG          ;Activa Pull Up.
    movlw   b'0000001'
    movwf   WPU                 ;Activada Pull Up del GP0.
    BANKSEL CMCON               ;Selecciona banco 0.
    movlw   b'00000111'         ;Desactivar comparadores.
    movwf   CMCON
    movlw   b'10010000'         ;Activa la interrupción extena(INTE) y
    movwf   INTCON              ;la general (GIE).
    bsf     STATUS,C

;La sección "Principal" es mantenimiento. Sólo espera las interrupciones.

Principal
    incf ContadorEstado,W ;Incrementa el valor del contador de estado (0..3).
    andlw b'00000011' ;Si pasa de 3, lo pone a 0. Si no, no pasa nada.
    movwf ContadorEstado ;Guarda el valor donde estaba.

    bsf     STATUS,RP0 ;Banco 1
    movlw   Tabla ;Primera posición de la tabla
    movwf   EEADR ;Apunta ahí
    movf    ContadorEstado,W ;Coge el contador
    addwf   EEADR ;Suma el contador para apuntar al dato que nos interesa
    bsf     EECON1,RD ;Lee el valor de la tabla
    movf    EEDATA,W ;Pasa el valor a W para trabajar con él.



;Subrutinas EEPROM ************************************************************


Tabla
    DB 0x23 ;Byte de ejemplo para sacar por el puerto en el caso 0
    DB 0x53 ;Byte para el caso 1
    DB 0x25 ;Caso 2
    DB 0x75 ;Caso 3 (son todos ejemplos aleatorios que yo he puesto porque voy con prisa)

    INCLUDE  <RETARDOS.inc>

    ORG     0x3FF
    retlw   0x20
    END
No te gustan las interrupciones, pues no las uso, de todas me tenía loco..

Se atasca enla parte de la tabla.
27/02/2013 #26

Avatar de Melghost

¡Ay, Meta, no me has entendido...!

Vamos a ver, las interrupciones son para lo que son, y me gustan mucho, pero no las utilizaría para esto. Tú hazlo como prefieras.

Normal que se te atasque en la tabla de datos... Es que no es código ejecutable. No te limites a copiar y pegar el código que te he puesto, porque sólo es un ejemplo para que entiendas cómo lo haría yo. Por favor, estúdiatelo.

Te lo voy a explicar de nuevo, a ver:

Tú tienes que sacar por el puerto de salida 4 combinaciones diferentes de LEDs. Y cada una de esas 4 combinaciones es un byte que podemos sacar por el puerto GPIO. ¿Correcto?

Lo que yo te propongo es que guardes en una tabla esas 4 combinaciones. Es, por tanto, una tabla de 4 bytes, y la guardamos en la EEPROM.

Ahora tenemos que acceder a esa tabla. Fíjate que el primer byte está en la dirección Tabla + 0, el segundo en Tabla + 1, el tercero en Tabla + 2 y el cuarto en Tabla + 3. O sea, siempre es la dirección Tabla + c, siendo "c" un número del 0 al 3. Llamemos a ese número "Contador".

Me viene muy bien que tengas 4 estados diferentes, porque así yo voy a manejar mi contador muy fácilmente. Para pasar de un valor al siguiente lo incremento, y después tengo que asegurarme que del 3 pasa de nuevo al 0. Si observas estos números en binario, verás que en los 2 bits de menos peso, el 4 es igual que el 0. Te lo demuestro:

0 dec = 00000000 bin
1 dec = 00000001 bin
2 dec = 00000010 bin
3 dec = 00000011 bin
4 dec = 00000100 bin

De esta forma, en vez de tener que hacer comparaciones y saltos, me basta con hacerle al contador un AND con el valor 3 (00000011 bin) y ya he conseguido el mismo objetivo; que del 3 pase al 0.

¿Y para qué quiero un contador del 0 al 3? Pues para acceder a los distintos datos de la tabla que puse en la EEPROM. Si yo cojo la dirección Tabla y le sumo el valor del contador, ya tengo a mi disposición el valor que tengo que sacar por el puerto. Es muy fácil trabajar así, y te ahorras un porrón de instrucciones.

El último detalle que nos queda ver, es que el valor del contador también debe ir guardado en una variable en la EEPROM, para que así mantenga su valor aunque apagues el PIC. Léete el datasheet del PIC para saber cómo coger ese valor o guardarlo. Yo te puse un ejemplo cogiendo un dato de la tabla, pero eso era sólo un trozo del programa; no termina ahí.

Otra cosa, por favor, ¿puede alguien explicarme cómo hacéis para incluir los archivos de texto? No sé cuál es la opción y es muy complicado explicar algo de esta forma. Gracias.

Venga, Meta. Resetea tu cabeza, que creo que debes de estar hecho un lío, y ánimo compañero, que todos hemos pasado por ahí. (sólo que algunos no tuvimos Internet para consultar)
Archivos Adjuntos
Tipo de Archivo: txt Nuevo Documento de texto (2).txt (445 Bytes, 14 visitas)
27/02/2013 #27

Avatar de Meta

Melghost dijo: Ver Mensaje
¡Ay, Meta, no me has entendido...!

Vamos a ver, las interrupciones son para lo que son, y me gustan mucho, pero no las utilizaría para esto. Tú hazlo como prefieras.

Entendido.

Normal que se te atasque en la tabla de datos... Es que no es código ejecutable. No te limites a copiar y pegar el código que te he puesto, porque sólo es un ejemplo para que entiendas cómo lo haría yo. Por favor, estúdiatelo.

Te lo voy a explicar de nuevo, a ver:

Tú tienes que sacar por el puerto de salida 4 combinaciones diferentes de LEDs. Y cada una de esas 4 combinaciones es un byte que podemos sacar por el puerto GPIO. ¿Correcto?

Clarísico.

Lo que yo te propongo es que guardes en una tabla esas 4 combinaciones. Es, por tanto, una tabla de 4 bytes, y la guardamos en la EEPROM.

Ahora tenemos que acceder a esa tabla. Fíjate que el primer byte está en la dirección Tabla + 0, el segundo en Tabla + 1, el tercero en Tabla + 2 y el cuarto en Tabla + 3. O sea, siempre es la dirección Tabla + c, siendo "c" un número del 0 al 3. Llamemos a ese número "Contador".

Me viene muy bien que tengas 4 estados diferentes, porque así yo voy a manejar mi contador muy fácilmente. Para pasar de un valor al siguiente lo incremento, y después tengo que asegurarme que del 3 pasa de nuevo al 0. Si observas estos números en binario, verás que en los 2 bits de menos peso, el 4 es igual que el 0. Te lo demuestro:

0 dec = 00000000 bin
1 dec = 00000001 bin
2 dec = 00000010 bin
3 dec = 00000011 bin
4 dec = 00000100 bin

De esta forma, en vez de tener que hacer comparaciones y saltos, me basta con hacerle al contador un AND con el valor 3 (00000011 bin) y ya he conseguido el mismo objetivo; que del 3 pase al 0.

¿Y para qué quiero un contador del 0 al 3? Pues para acceder a los distintos datos de la tabla que puse en la EEPROM. Si yo cojo la dirección Tabla y le sumo el valor del contador, ya tengo a mi disposición el valor que tengo que sacar por el puerto. Es muy fácil trabajar así, y te ahorras un porrón de instrucciones.

Eso de ahorrar mucho código mejor que mejor.
Mi idea era un poco diferente. Sólo siempre usar un byte de toda la EEPROM para guardar y leer datos, puede que un byte más para guardar el Contador.

La EEPROM es para modificarla. Los 4 bytes que almacenas en EEPROM, ¿no es mejor guardarla en la Flash?

El motivo lo digo que siempre esos son de solo lectura, lo que vas a modificar en un byte de los 4 estados que hay a su salida de del PIC. ¿Me entiendes?

Ojo, lo que digo es un concepto, no tiene que ser así. Aún así seguiré tu criterio.


El último detalle que nos queda ver, es que el valor del contador también debe ir guardado en una variable en la EEPROM, para que así mantenga su valor aunque apagues el PIC. Léete el datasheet del PIC para saber cómo coger ese valor o guardarlo. Yo te puse un ejemplo cogiendo un dato de la tabla, pero eso era sólo un trozo del programa; no termina ahí.

Otra cosa, por favor, ¿puede alguien explicarme cómo hacéis para incluir los archivos de texto? No sé cuál es la opción y es muy complicado explicar algo de esta forma. Gracias.

Venga, Meta. Resetea tu cabeza, que creo que debes de estar hecho un lío, y ánimo compañero, que todos hemos pasado por ahí. (sólo que algunos no tuvimos Internet para consultar)

Estuve mucho tiempo sin Internet para consultar .
Lo que hice en C# simulando un PIC12F629, el código fuente lo tienes arriba. Esto es como curiosidad y tener las cosas claras. En temas de tiempo mejor usar ya el C si se complica el PIC.



Acuérdate que cambié de idea. Hay que programar el PIC que al pulsar 5 seg el botón del PIC, cambia de estado, si lo pulsas en un momento, el PIC no hace nada.

Aquí hay información y en español.

Memoria de Datos EEPROM

La memoria de datos EEPROM se puede leer y escribir durante una operación normal (rango completo de VDD). Esta memoria no está mapeada directamente en el espacio del archivo de registro. En su lugar, es indirectamente direccionada a través de los Registros de Función Especial (SFR). Hay cuatro SFRs utilizados para leer y escribir esta memoria:
• EECON1
• EECON2 (no es un registro implementado físicamente)
• EEDATA
• EEADR

EEDATA contiene los 8 bits de datos de lectura y escritura, y EEADR contiene la dirección de acceso a la ubicación de la EEPROM. Los PIC12F629/675 tienen 128 bytes de datos EEPROM con un rango de direccionamiento de 0h a 7Fh.
La memoria de datos EEPROM permite la lectura y escritura de bytes. La escritura de un byte automáticamente borra la ubicación y escribe el nuevo dato (borra antes de escribir). La clasificación de la memoria de datos EEPROM está preparada para elevados ciclos de borrado y escritura. El tiempo de escritura está controlado por un temporizador interno. El tiempo de escritura varía con la tensión y la temperatura, así como de un chip a otro. Consulta las especificaciones de AC para límites exactos.

Cuando la memoria de datos tiene protección de código, la CPU puede continuar leyendo y escribiendo los datos de la memoria EEPROM. El programador del dispositivo no puede acceder a esta memoria.
Información adicional sobre la EEPROM de datos está disponible en el manual de referencia PIC®Mid-Range, (DS33023).


bit 7-0 EEDATn: valor del Byte a leer o escribir desde la EEPROM de datos


bit 7 Sin implementar: debería estar a 0
bit 6-0 EEADR: especifica una de las 128 localizaciones para operaciones de Lectura/Escritura de la EEPROM

EEADR
El registro EEADR puede direccionar hasta un máximo de 128 bytes de datos EEPROM. Sólo siete de los ocho bits en el registro (EEADR<6:0 >) son necesarios. Se ignora el MSb (bit 7).
El bit superior siempre debe ser ‘0’ para seguir siendo compatible con dispositivos que tengan más memoria de datos EEPROM.

Registros EECON1 Y EECON2
EECON1 es el registro de control con cuatro bits bajos físicamente implementados. Los cuatro bits superiores están sin implementar y se leen como '0's.
Los bits de control RD y WR inician la lectura y escritura, respectivamente. Estos bits no se pueden borrar, tan sólo activarse, vía software. Se borran por hardware al completarse una operación de la lectura o escritura. La incapacidad para borrar el bit WR por software previene una accidental terminación prematura de una operación de escritura.
El bit WREN, cuando está activado, permitirá una operación de escritura. En Power-up, el bit WREN está borrado. El bit WRERR está activado cuando una operación de escritura es interrumpida por un MCLR Reset, o un WDT Time-out Reset durante una operación normal. En estas situaciones, a seguir de un RESET, el usuario puede comprobar el bit WRERR, borrarlo y volver a escribir la ubicación. Los datos y la dirección se borrarán, por lo tanto, los registros EEDATA y EEADR tendrán que ser reinicializados.
El bit de bandera de interrupción EEIF en el registro PIR1 se establece cuando se completa la escritura. Este bit debe desactivarse por software. EECON2 no es un registro físico. La lectura de EECON2 leerá todos como '0'. El registro EECON2 se utiliza exclusivamente en la secuencia de escritura de datos en la EEPROM.


bit 7-4 Sin implementar: Se leen como '0'
bit 3 WRERR: bit de bandera EEPROM error
1 = una operación de escritura terminada prematuramente (cualquier MCLR Reset o WDT Reset durante una operación normal o BOD detectado)
0 = operación de escritura terminada
bit 2 WREN: bit de habilitación de escritura EEPROM
1 = permite ciclos de escritura
0 = inhibe escritura de datos
bit 1 WR: bit de Control de Escritura
1 = inicia un ciclo de escritura (El bit es borrado por hardware una vez la escritura finaliza. El bit WR puede únicamente activarse, no borrarse, por software)
0 = el ciclo de escritura de datos EEPROM se ha completado
bit 0 RD: bit de Control de Escritura
1 = inicia una lectura EEPROM (La lectura toma un ciclo. RD se borra por hardware. El bit RD puede únicamente activarse, no borrarse, por software)
0 = no inicia una lectura EEPROM

Leyendo la Memoria de Datos EEPROM
Para leer una posición de la memoria de datos, el usuario debe escribir la dirección en el registro EEADR y, a continuación, activar el bit de control RD (EECON1<0>), como se muestra en el ejemplo 8-1. Los datos están disponibles, en el siguiente ciclo, en el registro EEDATA. Por lo tanto, puede leerse en la siguiente instrucción. EEDATA mantiene este valor hasta otra lectura, o hasta que se escribe por el usuario (durante una operación de escritura).



Escribiendo en la Memoria de Datos EEPROM
Para escribir en una posición de la EEPROM, el usuario en primer lugar debe escribir la dirección en el registro EEADR y los datos al registro EEDATA. A continuación, el usuario debe seguir una secuencia específica para iniciar la escritura de cada byte, como se muestra en el ejemplo 8-2.



La escritura no iniciará si la secuencia anterior no se sigue exactamente (escribir 55h en EECON2, escribir AAh en EECON2 y activar el bit WR) para cada byte. Se recomienda encarecidamente que las interrupciones se deshabiliten durante este segmento de código. Un contador de ciclo se ejecuta durante la secuencia necesaria. Cualquier número que no sea igual a los ciclos necesarios para ejecutar la secuencia impedirá que los datos se escriban en la EEPROM.
Además, se debe activar el bit WREN en EECON1 para habilitar la escritura. Este mecanismo impide escrituras accidentales de datos en la EEPROM debido a una errante (inesperada) ejecución de código. El usuario debe mantener el bit WREN a 0 en todo momento, excepto cuando se actualiza la EEPROM. El bit WREN no se borra por hardware.
Después de que se haya iniciado una secuencia de escritura, borrar el bit WREN no afectará a este ciclo de escritura. El bit WR no podrá activarse a menos que el bit WREN esté activado.
Al final del ciclo de escritura, el bit WR será borrado por hardware y se activa el bit de bandera EE de interrupción de escritura completada (EEIF). El usuario puede habilitar esta interrupción o sondear este bit. El bit EEIF del registro (PIR<7>) debe ser borrado por software.

Verificar Escritura
Dependiendo de la aplicación, buenas prácticas de programación pueden dictar que el valor que se escribe en la EEPROM de datos deba ser verificado (ver ejemplo 8-3) para confirmar la escritura del valor deseado.



Usando la EEPROM de Datos
La memoria de datos EEPROM es una matriz de bytes direccionables de alta-resistencia, que se ha optimizado para el almacenamiento de información con cambios frecuentes (por ejemplo, las variables de programa u otros datos que se actualizan con frecuencia).
Frecuentes cambios de los valores normalmente se actualizarán más a menudo que las especificaciones D120 o D120A. Si esto no es el caso, debe realizarse una actualización de la matriz. Por esta razón, las variables que cambian con poca frecuencia (como constantes, ID, calibración, etc.) deberían ser almacenadas en la memoria de programa FLASH.

Protección contra falsas Escrituras
Hay condiciones en las que el dispositivo no debe escribir datos a la memoria EEPROM. Para proteger contra las falsas Escrituras EEPROM, se han construido diversos mecanismos. En Power-up, se borra WREN. Además, el Power-up Timer (72 ms de duración) previene de escrituras en la EEPROM.
La secuencia de inicio de escritura y el bit WREN juntos ayudan a prevenir una escritura accidental durante:
• Brown-out
• Problemas de energía
• Mal-funcionamiento del software

Memoria de datos EEPROM con CODE PROTECT
La Memoria de Datos puede tener protección de código programando el bit CPD a ‘0’.
Cuando la memoria de datos tiene protección de código, la CPU es capaz de leer y escribir datos en la EEPROM. Se recomienda proteger el código de la memoria de programa (CP) cuando se protege el código de la memoria de datos (CPD). Esto impide que cualquier persona programe ceros sobre el código existente (que se ejecutará como NOPs) para llegar a una rutina añadida, programada en posiciones no utilizadas de la memoria de programa, que sacará el contenido de la memoria de datos. Programar posiciones que no se utilizan a ‘0’ también ayudará a prevenir que la protección del código de la memoria de datos sea alterada.



Nota(1): EECON2 no es un registro físico.

Hay que leer bien.
Imágenes Adjuntas
Tipo de Archivo: gif Animado.gif (43,0 KB (Kilobytes), 51 visitas)
27/02/2013 #28

Avatar de Melghost

Sí, precisamente en uno de mis proyectos tengo un montón de tablas de datos y están todas en la Flash, la misma memoria donde se guarda el programa. Lo que pasa es que en el datasheet del PIC que estás utilizando no he visto la forma de acceder a tablas en la Flash; por eso te comenté lo de hacerlo en la EEPROM.
27/02/2013 #29

Avatar de Meta



Entendido, sabía que había un buen motivo. Contar de que funcione, me va de maravilla.

Has escrito:

ORG EEPROM (no sé dónde está; tendrás que leerte el datasheet)
Tabla
DB 0x23 ;Byte de ejemplo para sacar por el puerto en el caso 0
DB 0x53 ;Byte para el caso 1
DB 0x25 ;Caso 2
DB 0x75 ;Caso 3 (son todos ejemplos aleatorios que yo he puesto porque voy con prisa)


Se introduce así, al menos en mi caso.
Código:
;ZONA DE EEPROM******************************************
    ORG     0x2100
    DE      0x23, 0x53, 0x25, 0x75, 0x00
El 0x00 del final indica precisamente el final.



En vez d usar en el MPLAB X el:
CBLOCK 0x20
Var1
var2
var3
ENDC

Se usa:
VARIABLE UDATA_SHR
var1 res 1
var2 res 1
var3 res 1

Más parte de información por aquí.

Por cierto, esos bits que pusiste arriba indicado en verde, no concuerda con lo que dicen aquí abajo.

0 dec = 00000000 bin
1 dec = 00000001 bin
2 dec = 00000010 bin
3 dec = 00000011 bin
4 dec = 00000100 bin






Perdón, es el contador.

Siguiendo tus esquemas, aún no me funcona las salida. Voy a seguir investigando, al menos los GPIOS que no muestran nada a su salida.

Código:
; No olvidar que si GP2 detecta un un 0 en la entreda menor de 5 segundos,
;el PIC no actua, vuelve a lo suyo como si no pasara nada.
;
; Cuando detecte 
;GP2|GP0 GP1 GP4 GP5
;---+----------------
;1) | 0   1   0   0
;2) | 1   0   1   0
;3) | 0   1   1   0
;4) | 1   0   0   1
;
;ZONA DE DATOS*****************************************************************
    LIST P=12F629                          ;Procesador usado.
    INCLUDE <P12F629.INC>                  ;Fichero que definen las etiquetas.

    __CONFIG   _CP_OFF & _CPD_OFF & _BODEN_OFF & _MCLRE_OFF & _WDT_OFF & _PWRTE_ON & _FOSC_INTRCIO

    CBLOCK  0x20
    ContadorEstado
    RAM_ret         
    RAM_ret_1
    ENDC

;ZONA DE EEPROM****************************************************************
    ORG     0x2100
Tabla
    DE      0x23, 0x53, 0x25, 0x75, 0x00
;ZONA DE CÓDIGOS***************************************************************
    ORG     0                   ;El programa comienza en la dirección 0.
    goto    Inicio

;    ORG     0x04
;    goto    ServicioInterrupcion

Inicio
    BANKSEL OSCCAL              ;Selecciona banco 1.
    call    0x3FF
    movlw b'00000100'
    movwf TRISIO
    movlw   b'00001111'
    movwf   OPTION_REG          ;Activa Pull Up.
    movlw   b'0000001'
    movwf   WPU                 ;Activada Pull Up del GP0.
    BANKSEL CMCON               ;Selecciona banco 0.
    movlw   b'00000111'         ;Desactivar comparadores.
    movwf   CMCON

;La sección "Principal" es mantenimiento. Sólo espera las interrupciones.

Principal
;    call    Retardo_20ms
    incf    ContadorEstado,W     ;Incrementa el valor del contador de estado (0..3).
    andlw   b'00000011'         ;Si pasa de 3, lo pone a 0. Si no, no pasa nada.
    movwf   ContadorEstado         ;Guarda el valor donde estaba.

;Subrutinas EEPROM ************************************************************

Lee_Dato_EEPROM
    bsf     STATUS,RP0             ;Banco 1
    movlw   Tabla                 ;Primera posición de la tabla
    movwf   EEADR                 ;Apunta ahí
    movf    ContadorEstado,W     ;Coge el contador
    addwf   EEADR                 ;Suma el contador para apuntar al dato que nos interesa
    bsf     EECON1,RD             ;Lee el valor de la tabla
    movf    EEDATA,W             ;Pasa el valor a W para trabajar con él.
    return

Escribe_Dato_EERPOM
    bsf        STATUS,RP0                ;Banco 1.
    bsf        EECON1,WREN                ;Habilitar
    bcf     INTCON,GIE                ;Deshabilitar intercepciones.
    movlw     0x55                    ;Desbloquear escritura.
    movwf     EECON2
    movlw     0xAA
    movwf     EECON2
    bsf     EECON1,WR                ;Inicie la escritura.
    bsf     INTCON,GIE                ;Habilitar INTS.
    return
;    INCLUDE  <RETARDOS.inc>

    ORG     0x3FF
    retlw   0x20
    END
Aún me falta completar códigos con fundamente sobre GPIO, y usar si es posible un timer o un retardo sobre el tema de los 5 seg, es decir:

El GP2 o pulsador detecta 0, si es menor el tiempo de 5 seg, lo ignora, el PIC se comporta normal. Si el PIC detecta que tienes el botón pulsado más de 5 seg. cambie de configuración del PIC de sus 4 Leds.

En resumen, cada vez que dejes pulsado el PIC durante 5 seg, cabia en su salida los estados de los Leds.

Saludo.
Imágenes Adjuntas
Tipo de Archivo: gif Animado.gif (8,4 KB (Kilobytes), 46 visitas)
28/02/2013 #30

Avatar de Melghost

Vale, ya estás en la onda.

La tabla que te puse era con valores que me inventé porque llevaba prisa ese día, perdona.
Los valores verdaderos que tienes que poner en ella son los bytes que quieres sacar por el puerto GPIO para encender los LEDs. Los puedes poner en binario así:
Código:
;ZONA DE EEPROM***************************
    ORG     0x2100
Tabla
    DE      b'00000010', b'00010001',b'00010010',b'00100001', 0x00
Fíjate que los "1" se corresponden con los puertos de salida que quieres activar en cada caso. Ese es el truco. Ahora que ya sabes cómo leer la tabla, tienes que sacar ese valor por el puerto.

Ya he visto que has incluido la subrutina para guardar el valor del contador en la EEPROM. Bien. Ahora tienes que hacer el código para:
1- Coger de la EEPROM el valor del contador al comenzar
2- Guardar en la EEPROM el valor del contador cuando cambie de valor.

Venga, que ya lo tienes fácil.

---------- Actualizado después de 6 minutos ----------

Por cierto, veo que activas el pull-up de la entrada GP0, cuando estás hablando de poner el pulsador en la entrada GP2. Lo del pull-up interno del PIC es sólo por si quieres ahorrarte la resistencia del pulsador; por tanto, el pull-up que tendrías que activar sería el del GP2.
28/02/2013 #31

Avatar de Meta

AJAJa que despiste. Voy a corregirlo.

Estoy haciendo el programa aún.
Edito:

Ya lo cambié a:
movwf OPTION_REG ;Activa Pull Up.
movlw b'0000100'

Mirando bien los datos son así:

Código:
    ORG     0x2100
Tabla
    DE      b'00000100', b'00001010',b'00000110',b'00001001', 0x00
Parece que volviste a tener prisas, ejejeje. No pasa nada campeón.

¿En qué dirección de la EEPROM quieres guardar los datos guardados?
Me refiero la configuración de Leds de su salida.
28/02/2013 #32

Avatar de Meta

Hola de nuevo, intento fallido.

Código:
; No olvidar que si GP2 detecta un un 0 en la entreda menor de 5 segundos,
;el PIC no actua, vuelve a lo suyo como si no pasara nada.
;
; Cuando detecte 
;GP2|GP0 GP1 GP4 GP5
;---+----------------
;1) | 0   1   0   0
;2) | 1   0   1   0
;3) | 0   1   1   0
;4) | 1   0   0   1
;
;ZONA DE DATOS*****************************************************************
    LIST P=12F629                          ;Procesador usado.
    INCLUDE <P12F629.INC>                  ;Fichero que definen las etiquetas.

    __CONFIG   _CP_OFF & _CPD_OFF & _BODEN_OFF & _MCLRE_OFF & _WDT_OFF & _PWRTE_ON & _FOSC_INTRCIO
    ERRORLEVEL -302
    CBLOCK  0x20
    ContadorEstado
    RAM_ret         
    RAM_ret_1
    ENDC

;ZONA DE EEPROM****************************************************************
    ORG     0x2100
Tabla
    DE      b'00000100', b'00001010',b'00000110',b'00001001', 0x00
;ZONA DE CÓDIGOS***************************************************************
    ORG     0                   ;El programa comienza en la dirección 0.
    goto    Inicio

;    ORG     0x04
;    goto    ServicioInterrupcion

Inicio
    BANKSEL OSCCAL              ;Selecciona banco 1.
    call    0x3FF
    movlw b'00000100'
    movwf TRISIO
    movlw   b'00001111'
    movwf   OPTION_REG          ;Activa Pull Up.
    movlw   b'0000100'
    movwf   WPU                 ;Activada Pull Up del GP0.
    BANKSEL CMCON               ;Selecciona banco 0.
    movlw   b'00000111'         ;Desactivar comparadores.
    movwf   CMCON
    clrw

;La sección "Principal" es mantenimiento. Sólo espera las interrupciones.

Principal    
    incf    ContadorEstado,W     ;Incrementa el valor del contador de estado (0..3).
    andlw   b'00000011'         ;Si pasa de 3, lo pone a 0. Si no, no pasa nada.
    movwf   ContadorEstado         ;Guarda el valor donde estaba.
    
    call    Lee_Dato_EEPROM    

    movfw    GPIO

    call    Escribe_Dato_EERPOM
    goto Principal
;Subrutinas EEPROM ************************************************************

Lee_Dato_EEPROM
    bsf     STATUS,RP0             ;Banco 1
    movlw   Tabla                 ;Primera posición de la tabla
    movwf   EEADR                 ;Apunta ahí
    movf    ContadorEstado,W     ;Coge el contador
    addwf   EEADR                 ;Suma el contador para apuntar al dato que nos interesa
    bsf     EECON1,RD             ;Lee el valor de la tabla
    movf    EEDATA,W             ;Pasa el valor a W para trabajar con él.
    return

Escribe_Dato_EERPOM
    bsf        STATUS,RP0                ;Banco 1.

    movlw    0x10                    ;Elijo esta dirección de la EEPROM y
    movwf    EEADR                    ;lo cargo en EEADR con el dato a escribir.
    movlw    Tabla
    movfw    EEDAT                    ; Cargo el registro EEDAT con el dato a escribir.

    bsf        EECON1,WREN                ;Habilitar
    bcf     INTCON,GIE                ;Deshabilitar intercepciones.
    movlw     0x55                    ;Desbloquear escritura.
    movwf     EECON2
    movlw     0xAA
    movwf     EECON2
    bsf     EECON1,WR                ;Inicie la escritura.
    bsf     INTCON,GIE                ;Habilitar INTS.
    return

    ORG     0x3FF
    retlw   0x20
    END
28/02/2013 #33

Avatar de Melghost

Vaaaaamos a ver...

Esta es tu tabla:

GP2|GP0 GP1 GP4 GP5
;---+----------------
;1) | 0 1 0 0
;2) | 1 0 1 0
;3) | 0 1 1 0
;4) | 1 0 0 1

Entiendo que donde dices "GP4" y "GP5" te refieres a los puertos 4 y 5 del puerto.

Supongo que si te has metido a programar en asm sabrás manejar el código binario. En un byte, los bits se numeran de izquierda a derecha así: 7, 6, 5, 4, 3, 2, 1, 0. Por ejemplo, en este número binario: "00100000 bin" está a 1 el bit número 5.

Mirando el datasheet del PIC12F629 vemos que el puerto tiene 6 bits, y que se nombran de izquierda a derecha así (comenzando desde el bit 5): GP5, GP4, GP3, GP2, GP1, GP0.

Así que vuelve a poner la tabla que yo te di, o no te funcionará.

Otras cosillas:

En "Principal" comienzas incrementando el contador de la forma que te recomendé, pero todavía no has cogido el valor de la EEPROM. Por tanto, ¿qué es lo que incrementas? Además, ¿no se supone que este incremento debía producirse después de estar pulsando GP2 durante 5 segundos? Tampoco veo la lectura de GP2 ni el anti-rebotes, ni la espera de 5 segundos.

Tienes algunos errores de sintaxis con la instrucción movwf (has puesto movfw)

Has elegido la dirección 0x10 de la EEPROM para guardar el dato. Correcto, es una dirección libre y está bien. Pero estás guardando ahí la dirección de comienzo de la tabla. Eso no te sirve de nada. Lo que tienes que guardar ahí es el contador.

Arregla esas cosillas y ya estarás más cerca.

Voy a tener que empezar a cobrarte...
28/02/2013 #34

Avatar de Meta

Melghost dijo: Ver Mensaje
Vaaaaamos a ver...

Esta es tu tabla:

GP2|GP0 GP1 GP4 GP5
;---+----------------
;1) | 0 1 0 0
;2) | 1 0 1 0
;3) | 0 1 1 0
;4) | 1 0 0 1

Entiendo que donde dices "GP4" y "GP5" te refieres a los puertos 4 y 5 del puerto.

Supongo que si te has metido a programar en asm sabrás manejar el código binario. En un byte, los bits se numeran de izquierda a derecha así: 7, 6, 5, 4, 3, 2, 1, 0. Por ejemplo, en este número binario: "00100000 bin" está a 1 el bit número 5.

Mirando el datasheet del PIC12F629 vemos que el puerto tiene 6 bits, y que se nombran de izquierda a derecha así (comenzando desde el bit 5): GP5, GP4, GP3, GP2, GP1, GP0.

Así que vuelve a poner la tabla que yo te di, o no te funcionará.

Ufff, que despiste, me olvidé ese momento los GP. Tiene toda la razón.

Otras cosillas:

En "Principal" comienzas incrementando el contador de la forma que te recomendé, pero todavía no has cogido el valor de la EEPROM. Por tanto, ¿qué es lo que incrementas? Además, ¿no se supone que este incremento debía producirse después de estar pulsando GP2 durante 5 segundos? Tampoco veo la lectura de GP2 ni el anti-rebotes, ni la espera de 5 segundos.

Tienes algunos errores de sintaxis con la instrucción movwf (has puesto movfw)

Error al teclear. Lo que no se, porqué el compilador no me ha avisado.

Has elegido la dirección 0x10 de la EEPROM para guardar el dato. Correcto, es una dirección libre y está bien. Pero estás guardando ahí la dirección de comienzo de la tabla. Eso no te sirve de nada. Lo que tienes que guardar ahí es el contador.

Arregla esas cosillas y ya estarás más cerca.

Los antirebotes lo dejo para después, debo comprabar primero. Exacto, el 0x10 es para el contador. En cuanto a los 5 seg., por ahora con el TIMER estoy seco y bien jodido.


Voy a tener que empezar a cobrarte...
Se que no está acabado, pero hay que terminar poco a poco cada parte. Hasta que llegue a los timer. Lo menos que se me da.

Código:
; No olvidar que si GP2 detecta un un 0 en la entreda menor de 5 segundos,
;el PIC no actua, vuelve a lo suyo como si no pasara nada.
;
; Cuando detecte 
;GP2|GP0 GP1 GP4 GP5
;---+----------------
;1) | 0   1   0   0
;2) | 1   0   1   0
;3) | 0   1   1   0
;4) | 1   0   0   1
;
;ZONA DE DATOS*****************************************************************
    LIST P=12F629                          ;Procesador usado.
    INCLUDE <P12F629.INC>                  ;Fichero que definen las etiquetas.

    __CONFIG   _CP_OFF & _CPD_OFF & _BODEN_OFF & _MCLRE_OFF & _WDT_OFF & _PWRTE_ON & _FOSC_INTRCIO
    ERRORLEVEL -302
    CBLOCK  0x20
    ContadorEstado
    RAM_ret         
    RAM_ret_1
    ENDC

;ZONA DE EEPROM****************************************************************
    ORG     0x2100
Tabla
    DE      b'00000010', b'00010001',b'00010010',b'00100001', 0x00
;ZONA DE CÓDIGOS***************************************************************
    ORG     0                   ;El programa comienza en la dirección 0.
    goto    Inicio

;    ORG     0x04
;    goto    ServicioInterrupcion

Inicio
    BANKSEL OSCCAL              ;Selecciona banco 1.
    call    0x3FF
    movlw b'00000100'
    movwf TRISIO
    movlw   b'00001111'
    movwf   OPTION_REG          ;Activa Pull Up.
    movlw   b'0000100'
    movwf   WPU                 ;Activada Pull Up del GP0.
    BANKSEL CMCON               ;Selecciona banco 0.
    movlw   b'00000111'         ;Desactivar comparadores.
    movwf   CMCON
    clrw

;La sección "Principal" es mantenimiento. Sólo espera las interrupciones.

Principal
    call    Lee_Dato_EEPROM        

    btfsc    GPIO,2                    ;¿Reset=0? ¿Has pulsado el pulsador?
    goto    Principal            ;Vuelve a Principal.
    incf    ContadorEstado,W     ;Incrementa el valor del contador de estado (0..3).
    andlw   b'00000011'         ;Si pasa de 3, lo pone a 0. Si no, no pasa nada.
    movwf   ContadorEstado         ;Guarda el valor donde estaba.
    movwf    GPIO
    call    Escribe_Dato_EERPOM
    goto Principal
;Subrutinas EEPROM ************************************************************

Lee_Dato_EEPROM
    bsf     STATUS,RP0             ;Banco 1
    movlw   Tabla                 ;Primera posición de la tabla
    movwf   EEADR                 ;Apunta ahí
    movf    ContadorEstado,W     ;Coge el contador
    addwf   EEADR                 ;Suma el contador para apuntar al dato que nos interesa
    bsf     EECON1,RD             ;Lee el valor de la tabla
    movf    EEDATA,W             ;Pasa el valor a W para trabajar con él.
    return

Escribe_Dato_EERPOM
    bsf        STATUS,RP0                ;Banco 1.

    movlw    0x10                    ;Elijo esta dirección de la EEPROM y
    movwf    EEADR                    ;lo cargo en EEADR con el dato a escribir.
    movlw    Tabla
    movwf    EEDAT                    ; Cargo el registro EEDAT con el dato a escribir.

    bsf        EECON1,WREN                ;Habilitar
    bcf     INTCON,GIE                ;Deshabilitar intercepciones.
    movlw     0x55                    ;Desbloquear escritura.
    movwf     EECON2
    movlw     0xAA
    movwf     EECON2
    bsf     EECON1,WR                ;Inicie la escritura.
    bsf     INTCON,GIE                ;Habilitar INTS.
    return

    ORG     0x3FF
    retlw   0x20
    END
28/02/2013 #35

Avatar de Melghost

Venga, ánimo, que ya te queda menos.

Con lo del timer te digo lo mismo que con las interrupciones. Si no necesitas que sean 5 segundos exactos, quizás lo puedas hacer con bucles vacíos y olvidarte del timer. Eso, como tú quieras. Lo del timer tiene su utilidad cuando tu programa necesita contar el tiempo exacto mientras realiza otras operaciones, pero si sólo vas a estar esperando... entonces es a tu gusto.

---------- Actualizado después de 22 minutos ----------

Mira, me he tomado la libertad de hacerte unos cambios en el código para que veas cómo hay que hacerlo, en mi opinión.

Échale un vistazo a las instrucciones y comentarios que te he puesto.

No te lo entrego terminado porque es tu proyecto y eres tú quien debe sacarlo adelante, aunque veo que te está costando un poco... pero bueno, todos hemos empezado así (bueno, y yo empecé haciendo a mano la traducción de asm a código máquina utilizando unas tablas que estaban equivocadas. No te cuento nada...)


Código:
; No olvidar que si GP2 detecta un un 0 en la entreda menor de 5 segundos,
;el PIC no actua, vuelve a lo suyo como si no pasara nada.
;
; Cuando detecte 
;GP2|GP0 GP1 GP4 GP5
;---+----------------
;1) | 0   1   0   0
;2) | 1   0   1   0
;3) | 0   1   1   0
;4) | 1   0   0   1
;
;ZONA DE DATOS*****************************************************************
    LIST P=12F629                          ;Procesador usado.
    INCLUDE <P12F629.INC>                  ;Fichero que definen las etiquetas.

    __CONFIG   _CP_OFF & _CPD_OFF & _BODEN_OFF & _MCLRE_OFF & _WDT_OFF & _PWRTE_ON & _FOSC_INTRCIO
    ERRORLEVEL -302
    CBLOCK  0x20
    ContadorEstado
    RAM_ret         
    RAM_ret_1
    ENDC

;ZONA DE EEPROM****************************************************************
    ORG     0x2100
Tabla
    DE      b'00000010', b'00010001',b'00010010',b'00100001', 0x00
;ZONA DE CÓDIGOS***************************************************************
    ORG     0                   ;El programa comienza en la dirección 0.
    goto    Inicio

;    ORG     0x04
;    goto    ServicioInterrupcion

Inicio
    BANKSEL OSCCAL              ;Selecciona banco 1.
    call    0x3FF
    movlw b'00000100'
    movwf TRISIO
    movlw   b'00001111'
    movwf   OPTION_REG          ;Activa Pull Up.
    movlw   b'0000100'
    movwf   WPU                 ;Activada Pull Up del GP0.
    BANKSEL CMCON               ;Selecciona banco 0.
    movlw   b'00000111'         ;Desactivar comparadores.
    movwf   CMCON
    clrw


;Coge de la EEPROM el valor del contador y lo pone en la variable en RAM
	CALL	Coge_Contador

;La sección "Principal" es mantenimiento. Sólo espera las interrupciones.
Principal    

;Espera a que se pulse RESET
    btfsc    GPIO,2                    ;¿Reset=0? ¿Has pulsado el pulsador?
    goto    Principal            ;Vuelve a Principal.

;Se ha pulsado RESET. Ahora espera 5 segundos con RESET pulsado.
	;Aquí iría el código de espera y comprobación de RESET mantenido 5 segundos


;Ya han pasado los 5 segundos. Ahora incrementa el contador
    incf    ContadorEstado,W     ;Incrementa el valor del contador de estado (0..3).
    andlw   b'00000011'         ;Si pasa de 3, lo pone a 0. Si no, no pasa nada.
    movwf   ContadorEstado         ;Guarda el valor donde estaba.

;Ahora coge de la tabla el valor que hay que sacar a los puertos
	CALL	Lee_Dato_EEPROM

;Ahora SÍ saca el dato al puerto
    movwf    GPIO			;Saca el dato al puerto
    call    Escribe_Dato_EERPOM	;Actualiza la EEPROM con el nuevo valor del contador

;Ahora hay que esperar a que se suelte la tecla RESET, para no hacer excesivas escrituras en la EEPROM y gastarla.
;Además yo esperaría un rato después de que se suelte la tecla (por los rebotes)

    goto Principal


;Subrutinas EEPROM ************************************************************


;Coge de la EEPROM el valor del contador
Coge_Contador
	;Aquí iría el código. A ver si sabes hacerlo, es muy parecido a Lee_Dato_EEPROM.

	RETURN


;Coge de la tabla de la EEPROM el valor que hay que sacar a los puertos
Lee_Dato_EEPROM
    bsf     STATUS,RP0             ;Banco 1
    movlw   Tabla                 ;Primera posición de la tabla
    movwf   EEADR                 ;Apunta ahí
    movf    ContadorEstado,W     ;Coge el contador
    addwf   EEADR                 ;Suma el contador para apuntar al dato que nos interesa
    bsf     EECON1,RD             ;Lee el valor de la tabla
    movf    EEDATA,W             ;Pasa el valor a W para trabajar con él.
    return



;Guarda en la EEPROM el valor del contador
Escribe_Dato_EERPOM
    bsf        STATUS,RP0                ;Banco 1.

    movlw    0x10                    ;Elijo esta dirección de la EEPROM y
    movwf    EEADR                    ;lo cargo en EEADR con el dato a escribir.
    movlw    Tabla
    movwf    EEDAT                    ; Cargo el registro EEDAT con el dato a escribir.

    bsf        EECON1,WREN                ;Habilitar
    bcf     INTCON,GIE                ;Deshabilitar intercepciones.
    movlw     0x55                    ;Desbloquear escritura.
    movwf     EECON2
    movlw     0xAA
    movwf     EECON2
    bsf     EECON1,WR                ;Inicie la escritura.
    bsf     INTCON,GIE                ;Habilitar INTS.
    return

    ORG     0x3FF
    retlw   0x20
    END
28/02/2013 #36

Avatar de Meta

Estoy codeando.

Por si acaso del temporizador.

Para que los Led cambien de estado. Tienes que pulsar durante 5 segundos y cambian de estado, luega suelta el Reset.

Si solo lo pulsas un momento o menos de 5 seg. No hace nada el PIC, los estados se quedan com está.

Espero que lo hayas entendido desde el princio que es así.

Sigo codeando, me está costando mucho entenderlo. jajaja. Si no consigues 5 seg exacto no pasa nada, al menos que se aproxime.
28/02/2013 #37

Avatar de Meta

Estoy codeando.

Por si acaso del temporizador.

Para que los Led cambien de estado. Tienes que pulsar durante 5 segundos y cambian de estado, luega suelta el Reset.

Si solo lo pulsas un momento o menos de 5 seg. No hace nada el PIC, los estados se quedan com está.

Espero que lo hayas entendido desde el princio que es así.

Sigo codeando, me está costando mucho entenderlo. jajaja. Si no consigues 5 seg exacto no pasa nada, al menos que se aproxime.

---------- Actualizado después de 52 minutos ----------

Hola de nuevo:

Algo pasa que no me salta esta instrucción tenga 1 o a 0.
Código:
;Espera a que se pulse RESET
    btfsc   Pulsador                    ;¿Reset=0? ¿Has pulsado el pulsador?
    goto    Principal            ;Vuelve a Principal.
Código aun sin temporizador de 5 seg. Tiene ya el atirrebote.

Código:
; No olvidar que si GP2 detecta un un 0 en la entreda menor de 5 segundos,
;el PIC no actua, vuelve a lo suyo como si no pasara nada.
;
; Cuando detecte 
;GP2|GP0 GP1 GP4 GP5
;---+----------------
;1) | 0   1   0   0
;2) | 1   0   1   0
;3) | 0   1   1   0
;4) | 1   0   0   1
;
;ZONA DE DATOS*****************************************************************
    LIST P=12F629                          ; Procesador usado.
    INCLUDE <P12F629.INC>                  ; Fichero que definen las etiquetas.

VARIABLES UDATA_SHR
ContadorEstado     res 1
RAM_ret         res 1
RAM_ret_1       res 1

    __CONFIG   _CP_OFF & _CPD_OFF & _BODEN_OFF & _MCLRE_OFF & _WDT_OFF & _PWRTE_ON & _FOSC_INTRCIO
    ERRORLEVEL -302

#DEFINE Pulsador    GPIO,2        ;Pulsador.

;ZONA DE EEPROM****************************************************************
    ORG     0x2100
Tabla
    DE      b'00000010', b'00010001',b'00010010',b'00100001', 0x00
;ZONA DE CÓDIGOS***************************************************************
    ORG     0                       ; El programa comienza en la dirección 0.
    goto    Inicio

;    ORG     0x04
;    goto    ServicioInterrupcion

Inicio
    BANKSEL OSCCAL                  ; Selecciona banco 1.
    call    0x3FF
    movlw     b'00000100'
    movwf     TRISIO
    movlw   b'00001111'
    movwf   OPTION_REG              ; Activa Pull Up.
    movlw   b'0000100'
    movwf   WPU                     ; Activada Pull Up del GP0.
    BANKSEL CMCON                      ; Selecciona banco 0.
    movlw   b'00000111'             ; Desactivar comparadores.
    movwf   CMCON
    clrw


;Coge de la EEPROM el valor del contador y lo pone en la variable en RAM
    CALL    Coge_Contador

;La sección "Principal" es mantenimiento. Sólo espera las interrupciones.
Principal    

;Espera a que se pulse RESET
    btfsc    Pulsador                ; ¿Pulsador presionado?, ¿(Pulsador)=0?
    goto    Fin                        ; No. Vuelve a leerlo.
    call    Retardo_20ms            ; Espera que se estabilicen los niveles de tensión.
    btfsc    Pulsador                ; Comprueba si es un rebote.
    goto    Fin                        ; Era un rebote y sale fuera.
    call    ContadorEstado            ; Incrementa el contador.
EsperaDejePulsar
    btfss    Pulsador                ; ¿Dejó de pulsar?. ¿(Pulsador)=1?
    goto    EsperaDejePulsar        ; No. Espera que deje de pulsar.

;Se ha pulsado RESET. Ahora espera 5 segundos con RESET pulsado.
;Aquí iría el código de espera y comprobación de RESET mantenido 5 segundos


;Ya han pasado los 5 segundos. Ahora incrementa el contador
    incf    ContadorEstado,W         ; Incrementa el valor del contador de estado (0..3).
    andlw   b'00000011'             ; Si pasa de 3, lo pone a 0. Si no, no pasa nada.
    movwf   ContadorEstado             ; Guarda el valor donde estaba.

;Ahora coge de la tabla el valor que hay que sacar a los puertos
    CALL    Lee_Dato_EEPROM

;Ahora SÍ saca el dato al puerto
    movwf    GPIO                    ; Saca el dato al puerto
    call    Escribe_Dato_EERPOM        ; Actualiza la EEPROM con el nuevo valor del contador

;Ahora hay que esperar a que se suelte la tecla RESET, para no hacer excesivas escrituras en la EEPROM y gastarla.
;Además yo esperaría un rato después de que se suelte la tecla (por los rebotes)

Fin    
    goto    Principal                ; Vuelve a Principal.


;Subrutinas EEPROM ************************************************************


;Coge de la EEPROM el valor del contador
Coge_Contador
    ;Aquí iría el código. A ver si sabes hacerlo, es muy parecido a Lee_Dato_EEPROM.
    bsf     STATUS,RP0                 ; Banco 1
    movlw      ContadorEstado          ; Primera posición de la tabla
    movwf   EEADR                     ; Apunta ahí
    movf    ContadorEstado,W         ; Coge el contador
    addwf   EEADR                     ; Suma el contador para apuntar al dato que nos interesa
    bsf     EECON1,RD                 ; Lee el valor de la tabla
    movf    EEDATA,W                 ; Pasa el valor a W para trabajar con él.
    RETURN


;Coge de la tabla de la EEPROM el valor que hay que sacar a los puertos
Lee_Dato_EEPROM
    bsf     STATUS,RP0                 ; Banco 1
    movlw   Tabla                     ; Primera posición de la tabla
    movwf   EEADR                     ; Apunta ahí
    movf    ContadorEstado,W         ; Coge el contador
    addwf   EEADR                     ; Suma el contador para apuntar al dato que nos interesa
    bsf     EECON1,RD                 ; Lee el valor de la tabla
    movf    EEDATA,W                 ; Pasa el valor a W para trabajar con él.
    return



;Guarda en la EEPROM el valor del contador
Escribe_Dato_EERPOM
    bsf      STATUS,RP0             ; Banco 1.

    movlw    0x10                   ; Elijo esta dirección de la EEPROM y
    movwf    EEADR                  ; lo cargo en EEADR con el dato a escribir.
    movlw    Tabla
    movwf    EEDAT                  ; Cargo el registro EEDAT con el dato a escribir.

    bsf      EECON1,WREN            ; Habilitar
    bcf     INTCON,GIE              ; Deshabilitar intercepciones.
    movlw     0x55                  ; Desbloquear escritura.
    movwf     EECON2
    movlw     0xAA
    movwf     EECON2
    bsf     EECON1,WR               ; Inicie la escritura.
    bsf     INTCON,GIE              ; Habilitar INTS.
    return
    
;Subrutina Retardo_20ms ************************************************************
 ; Retardo = 0.02 segundos.
; Frecuencia Reloj = 4 MHz.

; Retardo actual = 0.02 segundos = 20000 ciclos.
; Error = 0 %
;    cblock
;RAM_ret     res 1
;RAM_ret_1   res 1
;    endc

Retardo_20ms
            ;19993 ciclos.
    movlw    0x9E
    movwf    RAM_ret
    movlw    0x10
    movwf    RAM_ret_1
Retardo_20ms_0
    decfsz    RAM_ret, f
    goto    $+2
    decfsz    RAM_ret_1, f
    goto    Retardo_20ms_0

            ;3 ciclos.
    goto    $+1
    nop

            ;4 ciclos (incluyendo call).
    return   
    ORG     0x3FF
    retlw   0x20
    END
Edito:

Vuelvo con otro código completamente nuevo pero tampoco me sale.
Código:
; No olvidar que si GP2 detecta un un 0 en la entreda menor de 5 segundos,
;el PIC no actua, vuelve a lo suyo como si no pasara nada.
;
; Cuando detecte
;GP2|GP0 GP1 GP4 GP5
;---+----------------
;1) | 0   1   0   0
;2) | 1   0   1   0
;3) | 0   1   1   0
;4) | 1   0   0   1
;
;ZONA DE DATOS*****************************************************************
    LIST P=12F629                          ; Procesador usado.
    INCLUDE <P12F629.INC>                  ; Fichero que definen las etiquetas.

VARIABLES UDATA_SHR
ContadorEstado     res 1
RAM_ret         res 1
RAM_ret_1       res 1
Configuracion   res 1

    __CONFIG   _CP_OFF & _CPD_OFF & _BODEN_OFF & _MCLRE_OFF & _WDT_OFF & _PWRTE_ON & _FOSC_INTRCIO
    ERRORLEVEL -302

#DEFINE        Pulsador    GPIO,2      ; Pulsador.

;ZONA DE EEPROM****************************************************************
    ORG     0x2100
Tabla
    DE      b'00000010', b'00010001',b'00010010',b'00100001', 0x00
;ZONA DE CÓDIGOS***************************************************************
    ORG     0                       ; El programa comienza en la dirección 0.
    goto    Inicio

;    ORG     0x04
;    goto    ServicioInterrupcion

Inicio
    BANKSEL OSCCAL                  ; Selecciona banco 1.
    call    0x3FF
    movlw     b'00000100'
    movwf     TRISIO
    movlw   b'00001111'
    movwf   OPTION_REG              ; Activa Pull Up.
    movlw   b'0000100'
    movwf   WPU                     ; Activada Pull Up del GP0.
    BANKSEL CMCON                      ; Selecciona banco 0.
    movlw   b'00000111'             ; Desactivar comparadores.
    movwf   CMCON
    clrw





  
    movlw    Configuracion            ; Lee la posición 0x00 de memoria EEPROM de datos
    call    Lee_Dato_EEPROM            ; donde se guarda el turno.
    movwf    ContadorEstado                ; Se guarda.
    call    Visualiza                ; Lo visualiza.
Principal
    btfss    Pulsador                ; Lee el pulsador.
    call    IncrementaVisualiza        ; Salta a incrementar y visualizar el contador.
    goto    Principal

; Subrutina "IncrementaVisualiza" -------------------------------------------------------

IncrementaVisualiza
    call    Retardo_20ms
    btfsc    Pulsador
    goto    Fin_Visualiza
    incf    ContadorEstado,F        ; Incrementa el contador y lo visualiza.
Visualiza
    movwf   GPIO
    movlw    .3                      ; Ahora comprueba si el contador supera la
    subwf    ContadorEstado,W                ; centena. (W = Contador-.3).
    btfsc    STATUS,C                ; ¿C=0?, ¿W es negativo?, ¿Contador < .3?
    clrf    ContadorEstado                ; Pone a cero el contador.
    movf    ContadorEstado,W
    movlw    Configuracion                ; Se escribe en la posición de memoria EEPROM de
    movwf    EEADR                    ; datos donde se guarda el turno. En este caso en
    movf    ContadorEstado,W                ; la posición 00h de la EEPROM.
    call    Escribe_Dato_EERPOM
EsperaDejePulsar
    btfss    Pulsador
    goto    EsperaDejePulsar
Fin_Visualiza
    return
















;Coge de la tabla de la EEPROM el valor que hay que sacar a los puertos
Lee_Dato_EEPROM
    bsf     STATUS,RP0                 ; Banco 1
    movlw   Tabla                     ; Primera posición de la tabla
    movwf   EEADR                     ; Apunta ahí
    movf    ContadorEstado,W         ; Coge el contador
    addwf   EEADR                     ; Suma el contador para apuntar al dato que nos interesa
    bsf     EECON1,RD                 ; Lee el valor de la tabla
    movf    EEDATA,W                 ; Pasa el valor a W para trabajar con él.
    return



;Guarda en la EEPROM el valor del contador
Escribe_Dato_EERPOM
    bsf     STATUS,RP0             ; Banco 1.

    movlw   0x10                   ; Elijo esta dirección de la EEPROM y
    movwf   EEADR                  ; lo cargo en EEADR con el dato a escribir.
    movlw   Tabla
    movwf   EEDAT                  ; Cargo el registro EEDAT con el dato a escribir.

    bsf     EECON1,WREN            ; Habilitar
    bcf     INTCON,GIE              ; Deshabilitar intercepciones.
    movlw   0x55                  ; Desbloquear escritura.
    movwf   EECON2
    movlw   0xAA
    movwf   EECON2
    bsf     EECON1,WR               ; Inicie la escritura.
    bsf     INTCON,GIE              ; Habilitar INTS.
    return


;Subrutina Retardo_20ms ************************************************************
 ; Retardo = 0.02 segundos.
; Frecuencia Reloj = 4 MHz.

; Retardo actual = 0.02 segundos = 20000 ciclos.
; Error = 0 %
;    cblock
;RAM_ret     res 1
;RAM_ret_1   res 1
;    endc

Retardo_20ms
            ;19993 ciclos.
    movlw    0x9E
    movwf    RAM_ret
    movlw    0x10
    movwf    RAM_ret_1
Retardo_20ms_0
    decfsz    RAM_ret, f
    goto    $+2
    decfsz    RAM_ret_1, f
    goto    Retardo_20ms_0

            ;3 ciclos.
    goto    $+1
    nop

            ;4 ciclos (incluyendo call).
    return
    ORG     0x3FF
    retlw   0x20
    END


Edito 2:

Hola de nuevo, un nuevo intento.

Código:
; No olvidar que si GP2 detecta un un 0 en la entreda menor de 5 segundos,
;el PIC no actua, vuelve a lo suyo como si no pasara nada.
;
; Cuando detecte 
;GP2|GP0 GP1 GP4 GP5
;---+----------------
;1) | 0   1   0   0
;2) | 1   0   1   0
;3) | 0   1   1   0
;4) | 1   0   0   1
;
;ZONA DE DATOS*****************************************************************
    LIST P=12F629                          ; Procesador usado.
    INCLUDE <P12F629.INC>                  ; Fichero que definen las etiquetas.

VARIABLES UDATA_SHR
ContadorEstado     res 1
RAM_ret         res 1
RAM_ret_1       res 1
Contador        res    1

    __CONFIG   _CP_OFF & _CPD_OFF & _BODEN_OFF & _MCLRE_OFF & _WDT_OFF & _PWRTE_ON & _FOSC_INTRCIO
    ERRORLEVEL -302

#DEFINE        Pulsador    GPIO,2      ; Pulsador.
#DEFINE     Leds        GPIO        ; Leds está conectado al GPIO.

;ZONA DE EEPROM****************************************************************
    ORG     0x2100
Tabla
    DE      b'00000010', b'00010001',b'00010010',b'00100001', 0x00
;ZONA DE CÓDIGOS***************************************************************
    ORG     0                       ; El programa comienza en la dirección 0.
    goto    Inicio

;    ORG     0x04
;    goto    ServicioInterrupcion

Inicio
    BANKSEL OSCCAL                  ; Selecciona banco 1.
    call    0x3FF
    movlw     b'00000100'
    movwf     TRISIO
    movlw   b'00001111'
    movwf   OPTION_REG              ; Activa Pull Up.
    movlw   b'0000100'
    movwf   WPU                     ; Activada Pull Up del GP0.
    BANKSEL CMCON                      ; Selecciona banco 0.
    movlw   b'00000111'             ; Desactivar comparadores.
    movwf   CMCON
    clrw
;***************************************************************************

Principal
    btfsc    Pulsador                ; ¿Pulsador presionado?, ¿(Pulsador)=0?
    goto    Fin                        ; No. Vuelve a leerlo.
;    call    Retardo_20ms            ; Espera que se estabilicen los niveles de tensión.
    btfsc    Pulsador                ; Comprueba si es un rebote.
    goto    Fin                        ; Era un rebote y sale fuera.
    call    IncrementaVisualiza        ; Incrementa el contador y lo visualiza.
EsperaDejePulsar
    btfss    Pulsador                ; ¿Dejó de pulsar?. ¿(Pulsador)=1?
    goto    EsperaDejePulsar        ; No. Espera que deje de pulsar.
Fin    goto    Principal

; Subrutina "IncrementaVisualiza" ---------------------------------------------------------

IncrementaVisualiza
    incf    Contador,F                ; Incrementa el contador y comprueba si ha
    movlw     .4                    ; llegado a su valor máximo mediante una
    subwf    Contador,W                ; resta. (W)=(Contador)-4.
    btfsc    STATUS,C                ; ¿C=0?, ¿(W) negativo?, ¿(Contador)<4?
InicializaContador
    clrf    Contador                ; No, era igual o mayor. Por tanto, resetea.
Visualiza
    movf    Contador,W
    call    ConfiguracionLed
    movwf    Leds                    ; visualizado en el Leds.
    return

ConfiguracionLed
    andlw    b'00000011'                ; Se queda con el nibble bajo.
    DE      b'00000010', b'00010001',b'00010010',b'00100001', 0x00
    return


;***************************************************************************    
   ;Coge de la tabla de la EEPROM el valor que hay que sacar a los puertos
Lee_Dato_EEPROM
    bsf     STATUS,RP0                 ; Banco 1
    movlw   Tabla                     ; Primera posición de la tabla
    movwf   EEADR                     ; Apunta ahí
    movf    ContadorEstado,W         ; Coge el contador
    addwf   EEADR                     ; Suma el contador para apuntar al dato que nos interesa
    bsf     EECON1,RD                 ; Lee el valor de la tabla
    movf    EEDATA,W                 ; Pasa el valor a W para trabajar con él.
    return



;Guarda en la EEPROM el valor del contador
Escribe_Dato_EERPOM
    bsf      STATUS,RP0             ; Banco 1.

    movlw    0x10                   ; Elijo esta dirección de la EEPROM y
    movwf    EEADR                  ; lo cargo en EEADR con el dato a escribir.
    movlw    Tabla
    movwf    EEDAT                  ; Cargo el registro EEDAT con el dato a escribir.

    bsf      EECON1,WREN            ; Habilitar
    bcf     INTCON,GIE              ; Deshabilitar intercepciones.
    movlw     0x55                  ; Desbloquear escritura.
    movwf     EECON2
    movlw     0xAA
    movwf     EECON2
    bsf     EECON1,WR               ; Inicie la escritura.
    bsf     INTCON,GIE              ; Habilitar INTS.
    return
    
;Subrutina Retardo_20ms ************************************************************
 ; Retardo = 0.02 segundos.
; Frecuencia Reloj = 4 MHz.

; Retardo actual = 0.02 segundos = 20000 ciclos.
; Error = 0 %
;    cblock
;RAM_ret     res 1
;RAM_ret_1   res 1
;    endc

Retardo_20ms
            ;19993 ciclos.
    movlw    0x9E
    movwf    RAM_ret
    movlw    0x10
    movwf    RAM_ret_1
Retardo_20ms_0
    decfsz    RAM_ret, f
    goto    $+2
    decfsz    RAM_ret_1, f
    goto    Retardo_20ms_0

            ;3 ciclos.
    goto    $+1
    nop

            ;4 ciclos (incluyendo call).
    return   
    ORG     0x3FF
    retlw   0x20
    END
Archivos Adjuntos
Tipo de Archivo: txt Ejemplo del 16F84A.txt (2,1 KB (Kilobytes), 1 visitas)
01/03/2013 #38

Avatar de Meta

Hola:

Olvida todo lo de arriba:

He conseguido casi algo. Sin contar el temporizador. Casi, casi me funciona. Lo que no da buena lectura al final.

Código:
;No olvidar que si GP2 detecta un un 0 en la entreda menor de 5 segundos,
;el PIC no actua, vuelve a lo suyo como si no pasara nada.
;
; Cuando detecte 
;GP2|GP0 GP1 GP4 GP5
;---+----------------
;1) | 0   1   0   0
;2) | 1   0   1   0
;3) | 0   1   1   0
;4) | 1   0   0   1
;
;ZONA DE DATOS*****************************************************************

    LIST P=12F629                          ; Procesador usado.
    INCLUDE <P12F629.INC>                  ; Fichero que definen las etiquetas.

    __CONFIG   _CP_OFF & _CPD_OFF & _BODEN_OFF & _MCLRE_OFF & _WDT_OFF & _PWRTE_ON & _FOSC_INTRCIO
    ERRORLEVEL -302

#DEFINE     Pulsador    GPIO,2      ; Pulsador.
#DEFINE     Leds        GPIO        ; Leds está conectado al GPIO.

ContadorEstado    equ 20h
RAM_ret         equ 21h
RAM_ret_1       equ 22h
Contador        equ 23h


;ZONA DE CÓDIGOS***************************************************************
    ORG     0                       ; El programa comienza en la dirección 0.
    goto    Inicio

Inicio
    bsf     STATUS,RP0                  ; Selecciona banco 1.
    call    0x3FF                    ; Lo el valor de la calibración que sera almacenada en W.
    movwf   OSCCAL                    ; Paso el valor de W a OSCCAL para calibrar el oscilador.
    movlw   b'00000100'
    movwf   TRISIO
    movlw   b'00001111'
    movwf   OPTION_REG              ; Activa Pull Up.
    movlw   b'0000100'
    movwf   WPU                     ; Activada Pull Up del GP0.
    bcf     STATUS,RP0                      ; Selecciona banco 0.
    movlw   b'00000111'             ; Desactivar comparadores.
    movwf   CMCON
    clrf    Contador
;***************************************************************************

Principal
    btfsc   Pulsador                ; ¿Pulsador presionado?, ¿(Pulsador)=0?
    goto    Principal               ; No. Vuelve a leerlo.
;    call    Retardo_20ms            ; Espera que se estabilicen los niveles de tensión.
    btfsc   Pulsador                ; Comprueba si es un rebote.
    goto    Principal               ; Era un rebote y sale fuera.
    call    Incrementar             ; Incrementa el contador y lo visualiza.
EsperaDejePulsar
    btfss    Pulsador                ; ¿Dejó de pulsar?. ¿(Pulsador)=1?
    goto    EsperaDejePulsar         ; No. Espera que deje de pulsar.
Fin    goto    Principal

Incrementar
     incf   Contador, f              ; Contador tendrá un valor entre 0 y 3 (4 estados).
     movlw  b'00000011'              ; Dejo siempre los dos ultimo bits con lo que la máxima cuenta sera 11 .pasando luego a 00.
     andwf  Contador, w             ; W = Contador & 0b'00000011'.
     movwf  Contador                 ; Contador = W.
     call   Tabla                      ; Llamo una tabla que me devuelve lo que tengo que sacar por
     movwf  GPIO                      ; el puerto y lo envío al mismo. 
     ;call   Graba_EEPROM
     return

;***************************************************************************    

Tabla      
    addwf PCL,f                      ; Sumo W al contador de programa. 
    retlw b'00000010'   
    retlw b'00010001'           
    retlw b'00010010'                 ; Retorno con el valor correspondiente.  
    retlw b'00100001'

    
;Subrutina Retardo_20ms ************************************************************
 ; Retardo = 0.02 segundos.
; Frecuencia Reloj = 4 MHz.
; Retardo actual = 0.02 segundos = 20000 ciclos.

Retardo_20ms
            ;19993 ciclos.
    movlw    0x9E
    movwf    RAM_ret
    movlw    0x10
    movwf    RAM_ret_1
Retardo_20ms_0
    decfsz    RAM_ret, f
    goto    $+2
    decfsz    RAM_ret_1, f
    goto    Retardo_20ms_0
            ;3 ciclos.
    goto    $+1
    nop
            ;4 ciclos (incluyendo call).
    return

    END
Saludo.
07/03/2013 #39

Avatar de Meta

Hola:

Siguiendo el tema, por fin en el MPLAB v8.90 y MPLAB X 1.70 me cuente correctamente desde el paso 1) al 4) y vuel ta a empezar, lo curioso que en Proteus 7.10 SP0 me cuenta directamente desde el paso 4).

¿Por qué?

Por ahora he hecho lo básico, sin EEPROM ni TIMER.
Código:
;No olvidar que si GP2 detecta un un 0 en la entreda menor de 5 segundos,
;el PIC no actua, vuelve a lo suyo como si no pasara nada.
;
; Cuando detecte
;GP2|GP0 GP1 GP4 GP5
;---+----------------
;1) | 0   1   0   0
;2) | 1   0   1   0
;3) | 0   1   1   0
;4) | 1   0   0   1
;
;ZONA DE DATOS*****************************************************************

    LIST P=12F629                          ; Procesador usado.
    INCLUDE <P12F629.INC>                  ; Fichero que definen las etiquetas.

    __CONFIG   _CP_OFF & _CPD_OFF & _BODEN_OFF & _MCLRE_OFF & _WDT_OFF & _PWRTE_ON & _FOSC_INTRCIO
    ERRORLEVEL -302

#DEFINE     Pulsador    GPIO,2      ; Pulsador.
#DEFINE     Leds        GPIO        ; Leds está conectado al GPIO.

VARIABLES    UDATA_SHR
ContadorEstado    RES    1
RAM_ret        RES    1
RAM_ret_1    RES    1
Contador    RES    1

;ContadorEstado     equ  20h
;RAM_ret         equ 21h
;RAM_ret_1       equ 22h
;Contador        equ 23h


;ZONA DE CÓDIGOS***************************************************************
    ORG     0                       ; El programa comienza en la dirección 0.
    goto    Inicio

Inicio
    bsf     STATUS,RP0                  ; Selecciona banco 1.
    call    0x3FF                    ; Lo el valor de la calibración que sera almacenada en W.
    movwf   OSCCAL                    ; Paso el valor de W a OSCCAL para calibrar el oscilador.
    movlw   b'00000100'
    movwf   TRISIO
    movlw   b'00001111'
    movwf   OPTION_REG              ; Activa Pull Up.
    movlw   b'0000100'
    movwf   WPU                     ; Activada Pull Up del GP0.
    bcf     STATUS,RP0                      ; Selecciona banco 0.
    movlw   b'00000111'             ; Desactivar comparadores.
    movwf   CMCON
    movlw    .3
    movwf    Contador
;***************************************************************************

Principal
    btfsc   Pulsador                ; ¿Pulsador presionado?, ¿(Pulsador)=0?
    goto    Principal               ; No. Vuelve a leerlo.
    call    Retardo_20ms            ; Espera que se estabilicen los niveles de tensión.
    btfsc   Pulsador                ; Comprueba si es un rebote.
    goto    Principal               ; Era un rebote y sale fuera.
    call    Incrementar             ; Incrementa el contador y lo visualiza.
EsperaDejePulsar
    btfss    Pulsador                ; ¿Dejó de pulsar?. ¿(Pulsador)=1?
    goto    EsperaDejePulsar         ; No. Espera que deje de pulsar.
Fin    goto    Principal

Incrementar
;***************************************************************************
; Subrutina "IncrementaVisualiza" ---------------------------------------------------------

IncrementaVisualiza
    incf    Contador,F                ; Incrementa el contador y comprueba si ha
    movlw     d'4'                    ; llegado a su valor máximo mediante una
    subwf    Contador,W                ; resta. (W)=(Contador)-4.
    btfsc    STATUS,C                ; ¿C=0?, ¿(W) negativo?, ¿(Contador)<4?
InicializaContador
    clrf    Contador                ; No, era igual o mayor. Por tanto, resetea.
Visualiza
    movf    Contador,W
    call    Tabla                    ; Lo pasa a siete segmento para poder ser
    movwf    GPIO                    ; visualizado en el display.
    return


Tabla
    addwf     PCL,F                      ; Sumo W al contador de programa. ;
    retlw     b'00000010'  ;1
    retlw     b'00010001'  ;2
    retlw     b'00010010'  ;3               ; Retorno con el valor correspondiente.
    retlw     b'00100001'  ;4

;Subrutina Retardo_20ms ************************************************************
 ; Retardo = 0.02 segundos.
; Frecuencia Reloj = 4 MHz.
; Retardo actual = 0.02 segundos = 20000 ciclos.

Retardo_20ms
            ;19993 ciclos.
    movlw    0x9E
    movwf    RAM_ret
    movlw    0x10
    movwf    RAM_ret_1
Retardo_20ms_0
    decfsz    RAM_ret, f
    goto    $+2
    decfsz    RAM_ret_1, f
    goto    Retardo_20ms_0
            ;3 ciclos.
    goto    $+1
    nop
            ;4 ciclos (incluyendo call).
    return

    END
Un cordial saludo.
07/03/2013 #40
Moderador

Avatar de D@rkbytes

Meta dijo: Ver Mensaje
lo curioso que en Proteus 7.10 SP0 me cuenta directamente desde el paso 4).

¿Por qué?
No es que entre al paso 4, lo que pasa es que olvidaste iniciar el puerto en 0.
Cuando entres al banco 0 en "Inicio", haz un clrf GPIO
Así los pines de salida de GPIO tendrán un estado inicial en 0.

Saludos.
¿Tienes una mejor respuesta a este tema? ¿Quieres hacerle una pregunta a nuestra comunidad y sus expertos? Registrate

Foros de Electrónica » Diseño digital » Microcontroladores y sistemas embebidos

Powered by vBulletin® Version 3.8.4
Copyright ©2000 - 2017, Jelsoft Enterprises Ltd.
Search Engine Optimization by vBSEO ©2011, Crawlability, Inc.