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

Temas similares

03/08/2014 #21

Avatar de Meta

Entendido. Es mejor ver los bits para tener las cosas claras.



El siguiente y último reto que nunca he usado la EEPROM interna del PIC16F88, no me sale a pesar de leer bien su hoja de datos. En la página 29 del datasheet te dice códigos pero a mi no me funciona o no se hacerlo.

Lo que quiero hacer es guardar los últimos datos seleccionados por el pulsador de las dos tablas de la verdad. Por ejemplo, si estamos en el número 2 del Display, al apagarlo y encenderlo otra vez el PIC, aparezca precisamente el 2, que es el último número que se mostró. Se incluye también el guardado de la tabla de la verdad de datos.



Los que sepan, una ayudita. Por lo que veo, no se me da para nada bien guardar y recuperar datos en la EEPROM interna del PIC. Fijándome bien, se necesita una celda para guardar los 8 bits o un byte de la Tabla de la verdad gris del Display, y otra celda o posición de memoria también de 8 bits o un byte en la Tabla de la verdad verde de datos.



De todas formas, voy a intentarlo por si acaso.

Desde que funcione todo, subo un vídeo.

Saludo.
04/08/2014 #22

Avatar de JoaquinFerrero

No necesitas dos posiciones de la EEPROM para guardar la información. Solo necesitas una (la del contador).

El código para leer y escribir en la EEPROM está en la hoja que muestras. Tienes que agregarlo en tu código. El de lectura, antes del bucle principal, cuando se inicializa a 0 el contador, lo cambias por la lectura de la EEPROM (aquí pondría un and para asegurarme de que sólo guardo un valor de 1 a 4). Y luego, en el bucle principal, al final, poner la escritura de la EEPROM (guardar el contador).

---------- Actualizado después de 31 minutos ----------

Una pregunta de curiosidad...

En las imágenes estoy viendo que estás usando el USB-PIC School, así que asumo que el PIC que estas usando es el de color negro de 18 patillas que está en la parte superior.

Pero... ¿qué chip es el de color naranja que está pinchado en la placa de prototipos?

Y, ¿por qué usas un display de 7 segmentos en la placa? El USB-PIC School tiene dos ya integrados.

Por otra parte... ¿qué tal es ese USB-PIC School? Parece que tiene buena pinta. ¿Lo puedes programar desde el MPLAB X?
04/08/2014 #23

Avatar de Meta

JoaquinFerrero dijo: Ver Mensaje
No necesitas dos posiciones de la EEPROM para guardar la información. Solo necesitas una (la del contador).

El código para leer y escribir en la EEPROM está en la hoja que muestras. Tienes que agregarlo en tu código. El de lectura, antes del bucle principal, cuando se inicializa a 0 el contador, lo cambias por la lectura de la EEPROM (aquí pondría un and para asegurarme de que sólo guardo un valor de 1 a 4). Y luego, en el bucle principal, al final, poner la escritura de la EEPROM (guardar el contador).

Lo intentaré, ahora me toca copiar el código.

---------- Actualizado después de 31 minutos ----------

Una pregunta de curiosidad...

En las imágenes estoy viendo que estás usando el USB-PIC School, así que asumo que el PIC que estas usando es el de color negro de 18 patillas que está en la parte superior.

Compré la versión DELUXE completa junto con el libro, tiene muchos ejemplos en asm y en C.
Aquí hice tres impresiones por si quiere saber más detalle cuando lo compré.


Pero... ¿qué chip es el de color naranja que está pinchado en la placa de prototipos?

Es un encapsulado de 8 resistencias de 330 Ω cada una en paralelo.

Y, ¿por qué usas un display de 7 segmentos en la placa? El USB-PIC School tiene dos ya integrados.

Porque el que te viene en la placa son de ánodo común y el que vamos a usar para un proyecto es de cátodo común, así de simple.

Es más, voy hacer una placa por mi mismo con más módulos que aquí no caben, como EEPROM por I2C 24LC256, Display de 7 segmentos de cátoco común, LCD de 20x4 y otro tipo LCD gráfico, y mucho más sensores. Como el USB'PICSchool tiene módulo de expanción para otra placa que voy hacer, aprovecho, es una buena ventaja.
Lo mejor de todo, que sus módulos le va muy bien con Arduino.

Por otra parte... ¿qué tal es ese USB-PIC School? Parece que tiene buena pinta. ¿Lo puedes programar desde el MPLAB X?

No lo he probado aún con el MPLAB X. Funciona muy bien con el MPLAB 8.92 y como depurador. El grabador de USB'PICSCHOOL es actualizable, en realidad es un clone de PicKit 2. Como tiene conector ICSP, te vale un grabador externo PicKit 3 si lo desea, ya que esta placa está preparado para ello.

Como no uso el depurador desde hace tiempo. Intentaré hacer pruebas si MPLAB X lo reconoce. Con el MPLAB 8, graba directamente a la placa. Normalmente suelo usar "PICKit 2 Programmer" para grabar PIC, es más rápido.

Lo bueno del USB, que puedes usar la placa desde el PC programándolo con FlowCode.

¿Alguna otra pregunta, caballero?

La verdad que estoy muy contento con esta placa.

Un cordial saludo.
04/08/2014 #24

Avatar de Meta

No se guarda los datos en la EEPORM, algo no hago bien.

Código:
;
; Un pulsador en RA4 va incrementando un contador, entre [1-4].
; La salida se envía a un display de 7 seg. en PORTB, y hacia salidas en PORTA.
;
; (Contador)  |RB 76543210 |RA 76543210
; ------------|------------------------
;       1     |   00000011 |   00000010
;       2     |   00100100 |   00000101
;       3     |   00001100 |   00000110
;       4     |   00111100 |   00001001
;
; PORTA:
;  RA0 : OE1
;  RA1 : OE2
;  RA2 : A21
;  RA3 : AUX
;  RA4 : Pulsador
; PORTB : display de 7 segmentos. a = RB0
;

; ZONA DE DATOS ****************************************************************

;*******************************************************************************
; Listado y condiciones de ensamblado

    LIST   P=16F88          ; 4 Mhz
    radix       dec
    errorlevel  -302            ; Turn off banking message

;*******************************************************************************
; Bibliotecas

    INCLUDE <P16f88.INC>

;*******************************************************************************
; Fusibles

    __CONFIG _CONFIG1, _CP_OFF & _DEBUG_OFF & _WRT_PROTECT_OFF & _CPD_OFF & _LVP_OFF & _BODEN_OFF & _MCLR_ON & _PWRTE_ON & _WDT_OFF & _INTRC_IO
;_XT_OSC

; _CP_OFF: Protección de código DESACTIVADO.
; _DEBUG_OFF: Debug en circuito DESACTIVADO.
; _WRT_PROTECT_OFF: Protección a escritura en memoria de programa DESACTIVADO.
; _CPD_OFF: Protección de código de datos DESACTIVADO.
; _LVP_OFF: Programación en baja tensión DESACTIVADO.
; _BODEN_OFF: Reset por Brown-out DESACTIVADO.
; _MCLRE_ON: Reset por pin externo ACTIVADO.
; _PWRTE_ON: Retraso al reset ACTIVADO.
; _WDT_OFF: Watchdog DESACTIVADO.
; _XT_OSC: Oscilador externo del tipo XT.

    __CONFIG _CONFIG2, _IESO_OFF & _FCMEN_OFF

; _IESO_OFF: Modo de intercambio de externo a interno DESACTIVADO.
; _FCMEN_OFF: Monitor de CLK DESACTIVADO.


;*******************************************************************************
; Definiciones

; Máscaras de E/S de los puertos
; 0 = salida, 1 = entrada
;                    |76543210|
#define PORTA_ES    b'00010000'
#define PORTB_ES    b'00000000'

;*******************************************************************************
; Variables
area_compartida:    udata_shr

contador            res 1                       ; Contador [1-4]


; ZONA DE CÓDIGOS **************************************************************

programa:           code

                    ORG     000h

Inicio:
                    banksel ANSEL           ; bank 1
                    clrf    ANSEL           ; Puerto analógico a digital.
                    movlw   PORTA_ES        ; definir E/S puerto A
                    movwf   TRISA
                    movlw   PORTB_ES        ; definir E/S puerto B
                    movwf   TRISB
;
                    movlw   0               ; inicializamos contador
                    movwf   contador
                    call    Leer_EEPROM     ; Lectura de la EEPROM.

; Bucle principal
                    BANKSEL OSCCON
                    movlw   b'01100000'     ; 4 MHz
                    movwf   OSCCON
                    banksel PORTA           ; bank 0, siempre
                    goto Inicializado
Principal:
                    movf    PORTA, w        ; leer puerto A
                    andlw   PORTA_ES        ; nos quedamos sólo con lo interesante

                    btfss   STATUS, Z       ; ¿Se ha pulsado? Lo está si RA4 == 0
                    goto    Principal       ; No, esperar
;
; Aquí llegamos con el botón pulsado
Inicializado:
                    call    incrementa_contador
                    call    visualiza_contador
                    call    salida_hacia_A

; Esperamos que levante el botón
Espera_levantar:
                    call    Retardo_100ms   ; Esperar la suelta del pulsador
                    movf    PORTA, w        ; leer puerto A
                    andlw   PORTA_ES        ; nos quedamos sólo con lo interesante
                    btfsc   STATUS, Z       ; ¿Sigue pulsado? Lo está si RA4 == 0
                    goto    Espera_levantar ; No, esperar
;
                    goto    Principal


; ******************************************************************************
;; salida_hacia_A
;
; Según el valor del contador ([1-4]), lo transforma en otro, basado en una
; tabla y lo saca por el puerto A
;

salida_hacia_A:     call    transforma_contador
                    movwf   PORTA           ; visualiza en puerto A
                    return

transforma_contador:
                    decf    contador,w      ; leemos el contador y le restamos 1
                    addwf   PCL, f          ; saltamos dentro de la tabla

;                            |76543210|
                    retlw   b'00000010'
                    retlw   b'00000101'
                    retlw   b'00000110'
                    retlw   b'00001001'

; ******************************************************************************
;; incrementa_contador
;
; Incrementa el valor de la variable contador, entre 1 y 4, inclusives.
;

incrementa_contador:
                    bcf     contador,2
                    incf    contador
                    return

; ******************************************************************************
;; visualiza_contador
;
; Muestra el valor del contador en el display de 7 segmentos
;

visualiza_contador:
                    movfw   contador        ; leemos contador
                    call    w_a_digito      ; transformación a dígito 7 segmentos
                    movwf   PORTB           ; visualiza en puerto B
                    return

w_a_digito:         addwf   PCL, f          ; salta al dígito indexado por w

;                            |76543210|
                    retlw   b'00111111'     ; 0
                    retlw   b'00000110'     ; 1
                    retlw   b'01011011'     ; 2
                    retlw   b'01001111'     ; 3
                    retlw   b'01100110'     ; 4
                    retlw   b'01101101'     ; 5
                    retlw   b'01111101'     ; 6
                    retlw   b'00000111'     ; 7
                    retlw   b'01111111'     ; 8
                    retlw   b'01101111'     ; 9

; ----------------------------------------------------------------------------------------------------
; Espera = 100ms
; Frecuencia de reloj = 4Mhz
;
; Espera real = 0.1 segundos = 100000 ciclos
; Error = 0.00 %

Retardo_par:        udata_shr

Retardo_100ms_d1    res 1
Retardo_100ms_d2    res 1


Retardo_code:       code

Retardo_100ms:
                                    ;99993 ciclos
                    movlw   0x1E
                    movwf   Retardo_100ms_d1
                    movlw   0x4F
                    movwf   Retardo_100ms_d2

Retardo_100ms_loop:
                    decfsz  Retardo_100ms_d1, f
                    goto    $+2
                    decfsz  Retardo_100ms_d2, f
                    goto    Retardo_100ms_loop

                                    ;3 ciclos
                    goto    $+1
                    nop

                                    ;4 ciclos (incluyendo la llamada)
                    return

                    call    Escribir_EEPROM

; Generado por delay_pic.pl (Joaquín Ferrero. 2014.07.22)
; ./delay_pic.pl -s Retardo_100ms 4Mhz 100ms
; mar 22 jul 2014 19:22:23 CEST
; http://perlenespanol.com/foro/generador-de-codigos-de-retardo-para-microcontroladores-pic-t8602.html
; ----------------------------------------------------------------------------------------------------

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

;Subrutinas EEPROM -----------------------------------------------------------

Leer_EEPROM
    BANKSEL EEADR           ; Selecciona el registro EEADR.
    movf    contador, W
    movwf   EEADR           ; Dato dirección de momoria a leer.
    BANKSEL EECON1          ; Selecciona el banco EECON1.
    bcf     EECON1, EEPGD    ; Punto a memoria de datos
    bsf     EECON1, RD      ; a Leer.
    BANKSEL EEDATA          ; Seleccionar banco de EEDATA.
    movf    EEDATA, W       ; W = EEDATA.
    return

Escribir_EEPROM
    BANKSEL EECON1          ; Selecciona banco de EECON1.
    btfsc   EECON1, WR      ; Espera para escribir
    goto    $-1             ; a completar.
    BANKSEL EEADR           ; Selecciona el banco EEADR.
    movf    contador, W
    movwf   EEADR           ; Dirección dato de memoria a escribir.
    BANKSEL EECON1          ; Selecciona el banco EECOn1.
    bcf     EECON1, EEPGD   ; Punto a dato de memoria.
    bsf     EECON1, WREN    ; Activar escritura.
    bcf     INTCON, GIE     ; Desactiva interrupciones.

; El fabricante especifica que hay que seguir esta secuencia para escritura en EEPROm.

    movlw   0x55
    movwf   EECON2          ; Escribe 55h.
    movlw   0xAA
    movwf   EECON2          ; Escribe AAh.
    bsf     EECON1, WR

    bsf     INTCON, GIE     ; Activa interrupciones.
    bcf     EECON1, WREN    ; Desactiva escrituras.


                END
Saludo.
04/08/2014 #25

Avatar de JoaquinFerrero

Es cierto que llamas a Leer_EEPROM, pero... ¿te das cuenta de que cuando regresas de la subrutina has cambiado de banco? Debes volver al bank 0.

Y el Escribir_EEPROM... aunque lo has puesto en el código, no lo estás llamando desde ningún sitio. La llamada call está fuera del código que ejecuta el programa.

Prueba a poner el call dentro de la subrutina incrementa_contador, entre la instrucción incf y el return.

Además... le falta un return. Además... tiene el mismo problema que al leer: cambia de banco.
04/08/2014 #26

Avatar de Meta

Hola:

No graba. Hice este. Algo se me escapa.

Código:
;
; Un pulsador en RA4 va incrementando un contador, entre [1-4].
; La salida se envía a un display de 7 seg. en PORTB, y hacia salidas en PORTA.
;
; (Contador)  |RB 76543210 |RA 76543210
; ------------|------------------------
;       1     |   00000011 |   00000010
;       2     |   00100100 |   00000101
;       3     |   00001100 |   00000110
;       4     |   00111100 |   00001001
;
; PORTA:
;  RA0 : OE1
;  RA1 : OE2
;  RA2 : A21
;  RA3 : AUX
;  RA4 : Pulsador
; PORTB : display de 7 segmentos. a = RB0
;

; ZONA DE DATOS ****************************************************************

;*******************************************************************************
; Listado y condiciones de ensamblado

    LIST   P=16F88          ; 4 Mhz
    radix       dec
    errorlevel  -302            ; Turn off banking message

;*******************************************************************************
; Bibliotecas

    INCLUDE <P16f88.INC>

;*******************************************************************************
; Fusibles

    __CONFIG _CONFIG1, _CP_OFF & _DEBUG_OFF & _WRT_PROTECT_OFF & _CPD_OFF & _LVP_OFF & _BODEN_OFF & _MCLR_ON & _PWRTE_ON & _WDT_OFF & _INTRC_IO
;_XT_OSC

; _CP_OFF: Protección de código DESACTIVADO.
; _DEBUG_OFF: Debug en circuito DESACTIVADO.
; _WRT_PROTECT_OFF: Protección a escritura en memoria de programa DESACTIVADO.
; _CPD_OFF: Protección de código de datos DESACTIVADO.
; _LVP_OFF: Programación en baja tensión DESACTIVADO.
; _BODEN_OFF: Reset por Brown-out DESACTIVADO.
; _MCLRE_ON: Reset por pin externo ACTIVADO.
; _PWRTE_ON: Retraso al reset ACTIVADO.
; _WDT_OFF: Watchdog DESACTIVADO.
; _XT_OSC: Oscilador externo del tipo XT.

    __CONFIG _CONFIG2, _IESO_OFF & _FCMEN_OFF

; _IESO_OFF: Modo de intercambio de externo a interno DESACTIVADO.
; _FCMEN_OFF: Monitor de CLK DESACTIVADO.


;*******************************************************************************
; Definiciones

; Máscaras de E/S de los puertos
; 0 = salida, 1 = entrada
;                    |76543210|
#define PORTA_ES    b'00010000'
#define PORTB_ES    b'00000000'

;*******************************************************************************
; Variables
area_compartida:    udata_shr

contador            res 1                       ; Contador [1-4]


; ZONA DE CÓDIGOS **************************************************************

programa:           code

                    ORG     000h

Inicio:
                    banksel ANSEL           ; bank 1
                    clrf    ANSEL           ; Puerto analógico a digital.
                    movlw   PORTA_ES        ; definir E/S puerto A
                    movwf   TRISA
                    movlw   PORTB_ES        ; definir E/S puerto B
                    movwf   TRISB
;
                    movlw   0               ; inicializamos contador
                    movwf   contador
                    call    Leer_EEPROM     ; Lectura de la EEPROM.

; Bucle principal
                    BANKSEL OSCCON
                    movlw   b'01100000'     ; 4 MHz
                    movwf   OSCCON
                    banksel PORTA           ; bank 0, siempre
                    goto Inicializado
Principal:
                    movf    PORTA, w        ; leer puerto A
                    andlw   PORTA_ES        ; nos quedamos sólo con lo interesante

                    btfss   STATUS, Z       ; ¿Se ha pulsado? Lo está si RA4 == 0
                    goto    Principal       ; No, esperar
;
; Aquí llegamos con el botón pulsado
Inicializado:
                    call    incrementa_contador
                    call    visualiza_contador
                    call    salida_hacia_A

; Esperamos que levante el botón
Espera_levantar:
                    call    Retardo_100ms   ; Esperar la suelta del pulsador
                    movf    PORTA, w        ; leer puerto A
                    andlw   PORTA_ES        ; nos quedamos sólo con lo interesante
                    btfsc   STATUS, Z       ; ¿Sigue pulsado? Lo está si RA4 == 0
                    goto    Espera_levantar ; No, esperar
;
                    goto    Principal


; ******************************************************************************
;; salida_hacia_A
;
; Según el valor del contador ([1-4]), lo transforma en otro, basado en una
; tabla y lo saca por el puerto A
;

salida_hacia_A:     call    transforma_contador
                    movwf   PORTA           ; visualiza en puerto A
                    return

transforma_contador:
                    decf    contador,w      ; leemos el contador y le restamos 1
                    addwf   PCL, f          ; saltamos dentro de la tabla

;                            |76543210|
                    retlw   b'00000010'
                    retlw   b'00000101'
                    retlw   b'00000110'
                    retlw   b'00001001'

; ******************************************************************************
;; incrementa_contador
;
; Incrementa el valor de la variable contador, entre 1 y 4, inclusives.
;

incrementa_contador:
                    bcf     contador,2
                    incf    contador
                    call    Escribir_EEPROM ; Escribir dato en la EEPROM.
                    return

; ******************************************************************************
;; visualiza_contador
;
; Muestra el valor del contador en el display de 7 segmentos
;

visualiza_contador:
                    movfw   contador        ; leemos contador
                    call    w_a_digito      ; transformación a dígito 7 segmentos
                    movwf   PORTB           ; visualiza en puerto B
                    return

w_a_digito:         addwf   PCL, f          ; salta al dígito indexado por w

;                            |76543210|
                    retlw   b'00111111'     ; 0
                    retlw   b'00000110'     ; 1
                    retlw   b'01011011'     ; 2
                    retlw   b'01001111'     ; 3
                    retlw   b'01100110'     ; 4
                    retlw   b'01101101'     ; 5
                    retlw   b'01111101'     ; 6
                    retlw   b'00000111'     ; 7
                    retlw   b'01111111'     ; 8
                    retlw   b'01101111'     ; 9

; ----------------------------------------------------------------------------------------------------
; Espera = 100ms
; Frecuencia de reloj = 4Mhz
;
; Espera real = 0.1 segundos = 100000 ciclos
; Error = 0.00 %

Retardo_par:        udata_shr

Retardo_100ms_d1    res 1
Retardo_100ms_d2    res 1


Retardo_code:       code

Retardo_100ms:
                                    ;99993 ciclos
                    movlw   0x1E
                    movwf   Retardo_100ms_d1
                    movlw   0x4F
                    movwf   Retardo_100ms_d2

Retardo_100ms_loop:
                    decfsz  Retardo_100ms_d1, f
                    goto    $+2
                    decfsz  Retardo_100ms_d2, f
                    goto    Retardo_100ms_loop

                                    ;3 ciclos
                    goto    $+1
                    nop

                                    ;4 ciclos (incluyendo la llamada)
                    return

; Generado por delay_pic.pl (Joaquín Ferrero. 2014.07.22)
; ./delay_pic.pl -s Retardo_100ms 4Mhz 100ms
; mar 22 jul 2014 19:22:23 CEST
; http://perlenespanol.com/foro/generador-de-codigos-de-retardo-para-microcontroladores-pic-t8602.html
; ----------------------------------------------------------------------------------------------------

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

;Subrutinas EEPROM -----------------------------------------------------------

Leer_EEPROM
    BANKSEL EEADR           ; Selecciona el registro EEADR.
    movf    contador, W
    movwf   EEADR           ; Dato dirección de momoria a leer.
    BANKSEL EECON1          ; Selecciona el banco EECON1.
    bcf     EECON1, EEPGD    ; Punto a memoria de datos
    bsf     EECON1, RD      ; a Leer.
    BANKSEL EEDATA          ; Seleccionar banco de EEDATA.
    movf    EEDATA, W       ; W = EEDATA.
    BANKSEL PORTA
    return

Escribir_EEPROM
    BANKSEL EECON1          ; Selecciona banco de EECON1.
    btfsc   EECON1, WR      ; Espera para escribir
    goto    $-1             ; a completar.
    BANKSEL EEADR           ; Selecciona el banco EEADR.
    movf    contador, W
    movwf   EEADR           ; Dirección dato de memoria a escribir.
    BANKSEL EECON1          ; Selecciona el banco EECOn1.
    bcf     EECON1, EEPGD   ; Punto a dato de memoria.
    bsf     EECON1, WREN    ; Activar escritura.
    bcf     INTCON, GIE     ; Desactiva interrupciones.

; El fabricante especifica que hay que seguir esta secuencia para escritura en EEPROm.

    movlw   0x55
    movwf   EECON2          ; Escribe 55h.
    movlw   0xAA
    movwf   EECON2          ; Escribe AAh.
    bsf     EECON1, WR

    bsf     INTCON, GIE     ; Activa interrupciones.
    bcf     EECON1, WREN    ; Desactiva escrituras.
    BANKSEL PORTA
    return

                END
04/08/2014 #27

Avatar de JoaquinFerrero

En Leer_EEPROM, no estás indicando de forma correcta la dirección de la EEPROM que hay que leer... y lo mismo para Escribir_EEPROM.

Vamos a ver: una cosa es "contador" (una dirección de la SRAM donde se guarda el valor del contador), y otra cosa distinta es la dirección de la EEPROM donde quieres guardar y leer el valor del contador.

(Si lo pensamos bien, resulta que este problema ya no necesita que contador esté en la SRAM, y podría bastar con que estuviera en la EEPROM, pero si tenemos una copia en la SRAM es más rápido para leer).

Entonces... lo que tienes que decidir es qué dirección de la EEPROM quieres usar para guardar el dato del contador.

Lo dice la documentación en el primer párrafo: «Para leer un dato de una posición de memoria, el usuario debe escribir la dirección en el registro EEADR, limpiar el bit de control EEPGD (EECON1<7>) y entonces activar el bit de control RD (EECON1<0>)».

La cuestión ahora es saber qué direcciones de la EEPROM tienes disponibles. Eso depende del PIC que estés usando.

¿Tienes 128 o 256 bytes de EEPROM? Bueno, al final, da igual. Solo necesitas una dirección. Podría ser la 0

Bueno, pues ya tienes adjudicada esa dirección. Debes modificar las dos subrutinas para que accedan/escriban a/en ella.

Y... en Leer_EEPROM, acuérdate de guardar el valor leído de la EEPROM, en la variable contador (tampoco lo tienes puesto).
04/08/2014 #28

Avatar de Meta

Hola:

He puesto este códig por ahora incompleto.

Código:
; ###############################################################################
                    BANKSEL EEADR
                    clrf    EEADR            ; Selecciona dirección 00 de EEPROM.
                    call    Leer_EEPROM     ; Lectura de la EEPROM.


                    BANKSEL EEDATA
                    movlw    0xFF
                    subwf    EEDATA,W
                    BANKSEL PORTA           ;Banco 0
                    btfss    STATUS,Z        ;Es la 1ª vez que se usa la EEPROM ??
                    goto    Inicializado            ;No, el sistema ya se ha usado.
                    clrf    contador

; ###############################################################################
Código principal para que veas como está.
Código:
;
; Un pulsador en RA4 va incrementando un contador, entre [1-4].
; La salida se envía a un display de 7 seg. en PORTB, y hacia salidas en PORTA.
;
; (Contador)  |RB 76543210 |RA 76543210
; ------------|------------------------
;       1     |   00000011 |   00000010
;       2     |   00100100 |   00000101
;       3     |   00001100 |   00000110
;       4     |   00111100 |   00001001
;
; PORTA:
;  RA0 : OE1
;  RA1 : OE2
;  RA2 : A21
;  RA3 : AUX
;  RA4 : Pulsador
; PORTB : display de 7 segmentos. a = RB0
;

; ZONA DE DATOS ****************************************************************

;*******************************************************************************
; Listado y condiciones de ensamblado

    LIST   P=16F88          ; 4 Mhz
    radix       dec
    errorlevel  -302            ; Turn off banking message

;*******************************************************************************
; Bibliotecas

    INCLUDE <P16f88.INC>

;*******************************************************************************
; Fusibles

    __CONFIG _CONFIG1, _CP_OFF & _DEBUG_OFF & _WRT_PROTECT_OFF & _CPD_OFF & _LVP_OFF & _BODEN_OFF & _MCLR_ON & _PWRTE_ON & _WDT_OFF & _INTRC_IO
;_XT_OSC

; _CP_OFF: Protección de código DESACTIVADO.
; _DEBUG_OFF: Debug en circuito DESACTIVADO.
; _WRT_PROTECT_OFF: Protección a escritura en memoria de programa DESACTIVADO.
; _CPD_OFF: Protección de código de datos DESACTIVADO.
; _LVP_OFF: Programación en baja tensión DESACTIVADO.
; _BODEN_OFF: Reset por Brown-out DESACTIVADO.
; _MCLRE_ON: Reset por pin externo ACTIVADO.
; _PWRTE_ON: Retraso al reset ACTIVADO.
; _WDT_OFF: Watchdog DESACTIVADO.
; _XT_OSC: Oscilador externo del tipo XT.

    __CONFIG _CONFIG2, _IESO_OFF & _FCMEN_OFF

; _IESO_OFF: Modo de intercambio de externo a interno DESACTIVADO.
; _FCMEN_OFF: Monitor de CLK DESACTIVADO.


;*******************************************************************************
; Definiciones

; Máscaras de E/S de los puertos
; 0 = salida, 1 = entrada
;                    |76543210|
#define PORTA_ES    b'00010000'
#define PORTB_ES    b'00000000'

;*******************************************************************************
; Variables
area_compartida:    udata_shr

contador            res 1                       ; Contador [1-4]


; ZONA DE CÓDIGOS **************************************************************

programa:           code

                    ORG     000h

Inicio:
                    banksel ANSEL           ; bank 1
                    clrf    ANSEL           ; Puerto analógico a digital.
                    movlw   PORTA_ES        ; definir E/S puerto A
                    movwf   TRISA
                    movlw   PORTB_ES        ; definir E/S puerto B
                    movwf   TRISB
;
                    movlw   0               ; inicializamos contador
                    movwf   contador

; ###############################################################################
                    BANKSEL EEADR
                    clrf    EEADR            ; Selecciona dirección 00 de EEPROM.
                    call    Leer_EEPROM     ; Lectura de la EEPROM.


                    BANKSEL EEDATA
                    movlw    0xFF
                    subwf    EEDATA,W
                    BANKSEL PORTA           ;Banco 0
                    btfss    STATUS,Z        ;Es la 1ª vez que se usa la EEPROM ??
                    goto    Inicializado            ;No, el sistema ya se ha usado.
                    clrf    contador

; ###############################################################################

; Bucle principal
                    BANKSEL OSCCON
                    movlw   b'01100000'     ; 4 MHz
                    movwf   OSCCON
                    banksel PORTA           ; bank 0, siempre
                    goto Inicializado
Principal:
                    movf    PORTA, w        ; leer puerto A
                    andlw   PORTA_ES        ; nos quedamos sólo con lo interesante

                    btfss   STATUS, Z       ; ¿Se ha pulsado? Lo está si RA4 == 0
                    goto    Principal       ; No, esperar
;
; Aquí llegamos con el botón pulsado
Inicializado:
                    call    incrementa_contador
                    call    visualiza_contador
                    call    salida_hacia_A

; Esperamos que levante el botón
Espera_levantar:
                    call    Retardo_100ms   ; Esperar la suelta del pulsador
                    movf    PORTA, w        ; leer puerto A
                    andlw   PORTA_ES        ; nos quedamos sólo con lo interesante
                    btfsc   STATUS, Z       ; ¿Sigue pulsado? Lo está si RA4 == 0
                    goto    Espera_levantar ; No, esperar
;
                    goto    Principal


; ******************************************************************************
;; salida_hacia_A
;
; Según el valor del contador ([1-4]), lo transforma en otro, basado en una
; tabla y lo saca por el puerto A
;

salida_hacia_A:     call    transforma_contador
                    movwf   PORTA           ; visualiza en puerto A
                    return

transforma_contador:
                    decf    contador,w      ; leemos el contador y le restamos 1
                    addwf   PCL, f          ; saltamos dentro de la tabla

;                            |76543210|
                    retlw   b'00000010'
                    retlw   b'00000101'
                    retlw   b'00000110'
                    retlw   b'00001001'

; ******************************************************************************
;; incrementa_contador
;
; Incrementa el valor de la variable contador, entre 1 y 4, inclusives.
;

incrementa_contador:
                    bcf     contador,2
                    incf    contador
                    call    Escribir_EEPROM ; Escribir dato en la EEPROM.
                    return

; ******************************************************************************
;; visualiza_contador
;
; Muestra el valor del contador en el display de 7 segmentos
;

visualiza_contador:
                    movfw   contador        ; leemos contador
                    call    w_a_digito      ; transformación a dígito 7 segmentos
                    movwf   PORTB           ; visualiza en puerto B
                    return

w_a_digito:         addwf   PCL, f          ; salta al dígito indexado por w

;                            |76543210|
                    retlw   b'00111111'     ; 0
                    retlw   b'00000110'     ; 1
                    retlw   b'01011011'     ; 2
                    retlw   b'01001111'     ; 3
                    retlw   b'01100110'     ; 4
                    retlw   b'01101101'     ; 5
                    retlw   b'01111101'     ; 6
                    retlw   b'00000111'     ; 7
                    retlw   b'01111111'     ; 8
                    retlw   b'01101111'     ; 9

; ----------------------------------------------------------------------------------------------------
; Espera = 100ms
; Frecuencia de reloj = 4Mhz
;
; Espera real = 0.1 segundos = 100000 ciclos
; Error = 0.00 %

Retardo_par:        udata_shr

Retardo_100ms_d1    res 1
Retardo_100ms_d2    res 1


Retardo_code:       code

Retardo_100ms:
                                    ;99993 ciclos
                    movlw   0x1E
                    movwf   Retardo_100ms_d1
                    movlw   0x4F
                    movwf   Retardo_100ms_d2

Retardo_100ms_loop:
                    decfsz  Retardo_100ms_d1, f
                    goto    $+2
                    decfsz  Retardo_100ms_d2, f
                    goto    Retardo_100ms_loop

                                    ;3 ciclos
                    goto    $+1
                    nop

                                    ;4 ciclos (incluyendo la llamada)
                    return

; Generado por delay_pic.pl (Joaquín Ferrero. 2014.07.22)
; ./delay_pic.pl -s Retardo_100ms 4Mhz 100ms
; mar 22 jul 2014 19:22:23 CEST
; http://perlenespanol.com/foro/generador-de-codigos-de-retardo-para-microcontroladores-pic-t8602.html
; ----------------------------------------------------------------------------------------------------

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

;Subrutinas EEPROM -----------------------------------------------------------

Leer_EEPROM
    BANKSEL EEADR           ; Selecciona el registro EEADR.
    movf    contador, W
    movwf   EEADR           ; Dato dirección de momoria a leer.
    BANKSEL EECON1          ; Selecciona el banco EECON1.
    bcf     EECON1, EEPGD    ; Punto a memoria de datos
    bsf     EECON1, RD      ; a Leer.
    BANKSEL EEDATA          ; Seleccionar banco de EEDATA.
    movf    EEDATA, W       ; W = EEDATA.
    BANKSEL PORTA
    return

Escribir_EEPROM
    BANKSEL EECON1          ; Selecciona banco de EECON1.
    btfsc   EECON1, WR      ; Espera para escribir
    goto    $-1             ; a completar.
    BANKSEL EEADR           ; Selecciona el banco EEADR.
    movf    contador, W
    movwf   EEADR           ; Dirección dato de memoria a escribir.
    BANKSEL EECON1          ; Selecciona el banco EECOn1.
    bcf     EECON1, EEPGD   ; Punto a dato de memoria.
    bsf     EECON1, WREN    ; Activar escritura.
    bcf     INTCON, GIE     ; Desactiva interrupciones.

; El fabricante especifica que hay que seguir esta secuencia para escritura en EEPROm.

    movlw   0x55
    movwf   EECON2          ; Escribe 55h.
    movlw   0xAA
    movwf   EECON2          ; Escribe AAh.
    bsf     EECON1, WR

    bsf     INTCON, GIE     ; Activa interrupciones.
    bcf     EECON1, WREN    ; Desactiva escrituras.
    BANKSEL PORTA
    return

                END
05/08/2014 #29

Avatar de JoaquinFerrero

Cuidado... estás usando como dirección de la EEPROM el valor que contiene contador... así que estás escribiendo/leyendo en las direcciones 1 a 4, no en una dirección fija.

A mi esto me funciona:
Código PHP:
;
Un pulsador en RA4 va incrementando un contadorentre [1-4].
La salida se envía a un display de 7 segen PORTBy hacia salidas en PORTA.
El contador queda guardado en la EEPROM.
;
; (
Contador)  |RB 76543210 |RA 76543210
; ------------|------------------------
;       
1     |   00000011 |   00000010
;       2     |   00100100 |   00000101
;       3     |   00001100 |   00000110
;       4     |   00111100 |   00001001
;
PORTA:
;  
RA0 OE1
;  RA1 OE2
;  RA2 A21
;  RA3 AUX
;  RA4 Pulsador
;
PORTB display de 7 segmentosRB0
;

;*******************************************************************************
Listado y condiciones de ensamblado

                    processor   16F88           
4 Mhz
                    radix       dec
                    errorlevel  
-302            Turn off banking message

;*******************************************************************************
Bibliotecas

                    
include p16f88.inc

;*******************************************************************************
Fusibles

  __CONFIG _CONFIG1
_CP_OFF _DEBUG_OFF _WRT_PROTECT_OFF _CPD_OFF _LVP_OFF _BODEN_OFF _MCLR_ON _PWRTE_ON _WDT_OFF _INTRC_IO

_CP_OFF           Protección de código
_DEBUG_OFF        Debug en circuito
_WRT_PROTECT_OFF  Protección a escritura en memoria de programa
_CPD_OFF          Protección de código de datos
_LVP_OFF          Programación en baja tensión
_BODEN_OFF        Reset por Brown-out
_MCLRE_ON         Reset por pin externo
_PWRTE_ON         Retraso al reset
_WDT_OFF          Watchdog
_XT_OSC           Oscilador externo del tipo XT


;*******************************************************************************
Definiciones

Máscaras de E/S de los puertossalidaentrada
;                    |76543210|
#define PORTA_IO    b'00010000'
#define PORTB_IO    b'00000000'

Incorporar sentencias de comprobación de la EEPROM
#define test_eeprom 0

;*******************************************************************************
Variables
                    udata_shr

contador            res 1                   
contador en la SRAM

; ******************************************************************************
EEPROM

Dirección del contador dentro de la EEPROM
ee_contador
:        equ     0x02

Debemos desplazarnos a la zona de memoria más allá del 0x2100que corresponde
a la zona de la EEPROM en la mayoría de los PIC (ver documentación).
Este valor es el que se grabará en la EEPROM en el momento de grabar el programa
en el µcontrolador.
                    
org     0x2100 ee_contador

                    de      1               
valor inicial de ee_contador

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

                    
code    0x0000

_Start
:
                    
banksel ANSEL           bank 1
                    clrf    ANSEL           
puerto A digital
                    movlw   PORTA_IO        
definir E/S puerto A
                    movwf   TRISA
                    movlw   PORTB_IO        
definir E/S puerto B
                    movwf   TRISB
                    movlw   
b'01100000'     4 MHz
                    movwf   OSCCON

Leer valor del contador en la EEPROM
                    banksel EEADR           
bank 2
                    movlw   ee_contador     
dirección de la EEPROM a leer
                    movwf   EEADR

                    banksel EECON1          
bank 3
                    bcf     EECON1
EEPGD   acceso a la memoria de datos
                    bsf     EECON1
RD      inicia la lectura

                    banksel EEDATA          
bank 2
                    movf    EEDATA
w       dato leído en W
                    movwf   contador        
guardar en SRAM
;
                    
banksel PORTA           bank 0durante el programa

#if test_eeprom
Comprobar que el contador es correcto (esta parte es opcional)
                    
decf    contadorw     leemos el contador y le quitamos 1
                    andlw   0x3             
nos quedamos solo con los bits inferiores
                    addlw   0x1             
volvemos a sumarle 1
                    movwf   contador        
y lo guardamos
#endif
                    
goto    Visualiza       ir a presentar

Bucle principal
Principal
:          btfsc   PORTARA4      leer pulsador
                    
goto    Principal       Noesperar
;
Se ha pulsado el botón
                    call    incrementa_contador
Visualiza
:          call    visualiza_contador
                    call    salida_hacia_A

Esperar liberación del botón
Espera_levantar
:    call    Retardo_100ms   Esperar la suelta del botón

                    btfss   PORTA
RA4      leer pulsador
                    
goto    Espera_levantar Noesperar

Repetir
                    
goto    Principal


; ******************************************************************************
;; 
salida_hacia_A
;
Según el valor del contador ([1-4]), lo transforma en otrobasado en una
tabla y lo saca por el puerto A
;

salida_hacia_A:     call    transforma_contador
                    movwf   PORTA           
visualiza en puerto A
                    
return

transforma_contador:
                    
decf    contadorw     leemos el contador y le restamos 1
                    addwf   PCL
f          saltamos dentro de la tabla

;                            |76543210|
                    
retlw   b'00000010'
                    
retlw   b'00000101'
                    
retlw   b'00000110'
                    
retlw   b'00001001'

; ******************************************************************************
;; 
incrementa_contador
;
Incrementa el valor de la variable contadorentre 1 y 4inclusives.
;

incrementa_contador:
                    
bcf     contador2     Si el contador valía 4ahora vale 0
                    incf    contador
f     Incrementa el contador

Escribe el contador en la EEPROM
                    banksel EECON1          
bank 3
                    btfsc   EECON1
WR      esperar para poder escribir
                    
goto    $-1

                    banksel EEADR           
bank 2
                    movlw   ee_contador     
dirección donde vamos a escribir
                    movwf   EEADR

                    movf    contador
w     el valor que vamos a escribir
                    movwf   EEDATA

                    banksel EECON1          
bank 3
                    bcf     EECON1
EEPGD   acceso a la memoria de datos
                    bsf     EECON1
WREN    activa la escritura

;                    bcf     INTCONGIE     desactivar interrupciones

                    movlw   
b'01010101'     valores mágicos (requeridos)
                    
movwf   EECON2
                    movlw   
b'10101010'
                    
movwf   EECON2

                    bsf     EECON1
WR      comienza la escritura

;                    bsf     INTCONGIE     reactiva interrupciones

                    bcf     EECON1
WREN    desactiva escrituras

                    banksel PORTA           
volvemos a bank 0
                    
return

; ******************************************************************************
;; 
visualiza_contador
;
Muestra el valor del contador en el display de 7 segmentos
;

visualiza_contador:
                    
movfw   contador        leemos contador
                    call    w_a_digito      
transformación a dígito 7 segmentos
                    movwf   PORTB           
visualiza en puerto B
                    
return

w_a_digito:         addwf   PCLf          salta al dígito indexado por w

;                            |76543210|
                    
retlw   b'00111111'     0
                    retlw   
b'00000110'     1
                    retlw   
b'01011011'     2
                    retlw   
b'01001111'     3
                    retlw   
b'01100110'     4
                    retlw   
b'01101101'     5
                    retlw   
b'01111101'     6
                    retlw   
b'00000111'     7
                    retlw   
b'01111111'     8
                    retlw   
b'01101111'     9

; ----------------------------------------------------------------------------------------------------
Espera 100ms
Frecuencia de reloj 4Mhz
;
Espera real 0.1 segundos 100000 ciclos
Error 0.00 %

Retardo_var:        udata_shr

Retardo_100ms_d1    res 1
Retardo_100ms_d2    res 1

Retardo_code
:       code

Retardo_100ms
:
                                    ;
99993 ciclos
                    movlw   0x1E
                    movwf   Retardo_100ms_d1
                    movlw   0x4F
                    movwf   Retardo_100ms_d2

Retardo_100ms_loop
:
                    
decfsz  Retardo_100ms_d1f
                    
goto    $+2
                    decfsz  Retardo_100ms_d2
f
                    
goto    Retardo_100ms_loop

                                    
;3 ciclos
                    
goto    $+1
                    nop

                                    
;4 ciclos (incluyendo la llamada)
                    return

Generado por delay_pic.pl (Joaquín Ferrero2014.07.22)
; ./
delay_pic.pl -s Retardo_100ms 4Mhz 100ms
mar 22 jul 2014 19:22:23 CEST
http://perlenespanol.com/foro/generador-de-codigos-de-retardo-para-microcontroladores-pic-t8602.html
; ----------------------------------------------------------------------------------------------------

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


                    
end 
Con la ayuda de 'de' inicializamos el valor de la posición 0x02 de la EEPROM a '1' (según el mapa de memoria, esa dirección de EEPROM corresponde a la 0x2102 en la mayor parte de los PIC 1x -no de los PIC 18- Ver más información sobre 'de' en el manual del ensamblador MPASM). Ese valor es el que se graba en el momento de grabar el programa en el µcontrolador, como valor inicial.

Después de inicializar el µcontrolador, leemos la EEPROM. Luego comprobamos que el valor esté realmente entre los valores que queremos (1 a 4) (esta parte es opcional y la controla un #define).

Y luego sigue todo lo demás.

Un detalle, que he dejado comentado, son las líneas que activan y desactivan las interrupciones, en la parte de la escritura en la EEPROM, porque este programa no tiene interrupciones definidas (al menos de momento).

Además, he simplificado la forma de leer el botón.
06/08/2014 #30

Avatar de Meta

JoaquinFerrero dijo: Ver Mensaje
Cuidado... estás usando como dirección de la EEPROM el valor que contiene contador... así que estás escribiendo/leyendo en las direcciones 1 a 4, no en una dirección fija.

A mi esto me funciona:
Código PHP:
;
Un pulsador en RA4 va incrementando un contadorentre [1-4].
La salida se envía a un display de 7 segen PORTBy hacia salidas en PORTA.
El contador queda guardado en la EEPROM.
;
; (
Contador)  |RB 76543210 |RA 76543210
; ------------|------------------------
;       
1     |   00000011 |   00000010
;       2     |   00100100 |   00000101
;       3     |   00001100 |   00000110
;       4     |   00111100 |   00001001
;
PORTA:
;  
RA0 OE1
;  RA1 OE2
;  RA2 A21
;  RA3 AUX
;  RA4 Pulsador
;
PORTB display de 7 segmentosRB0
;

;*******************************************************************************
Listado y condiciones de ensamblado

                    processor   16F88           
4 Mhz
                    radix       dec
                    errorlevel  
-302            Turn off banking message

;*******************************************************************************
Bibliotecas

                    
include p16f88.inc

;*******************************************************************************
Fusibles

  __CONFIG _CONFIG1
_CP_OFF _DEBUG_OFF _WRT_PROTECT_OFF _CPD_OFF _LVP_OFF _BODEN_OFF _MCLR_ON _PWRTE_ON _WDT_OFF _INTRC_IO

_CP_OFF           Protección de código
_DEBUG_OFF        Debug en circuito
_WRT_PROTECT_OFF  Protección a escritura en memoria de programa
_CPD_OFF          Protección de código de datos
_LVP_OFF          Programación en baja tensión
_BODEN_OFF        Reset por Brown-out
_MCLRE_ON         Reset por pin externo
_PWRTE_ON         Retraso al reset
_WDT_OFF          Watchdog
_XT_OSC           Oscilador externo del tipo XT


;*******************************************************************************
Definiciones

Máscaras de E/S de los puertossalidaentrada
;                    |76543210|
#define PORTA_IO    b'00010000'
#define PORTB_IO    b'00000000'

Incorporar sentencias de comprobación de la EEPROM
#define test_eeprom 0

;*******************************************************************************
Variables
                    udata_shr

contador            res 1                   
contador en la SRAM

; ******************************************************************************
EEPROM

Dirección del contador dentro de la EEPROM
ee_contador
:        equ     0x02

Debemos desplazarnos a la zona de memoria más allá del 0x2100que corresponde
a la zona de la EEPROM en la mayoría de los PIC (ver documentación).
Este valor es el que se grabará en la EEPROM en el momento de grabar el programa
en el µcontrolador.
                    
org     0x2100 ee_contador

                    de      1               
valor inicial de ee_contador

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

                    
code    0x0000

_Start
:
                    
banksel ANSEL           bank 1
                    clrf    ANSEL           
puerto A digital
                    movlw   PORTA_IO        
definir E/S puerto A
                    movwf   TRISA
                    movlw   PORTB_IO        
definir E/S puerto B
                    movwf   TRISB
                    movlw   
b'01100000'     4 MHz
                    movwf   OSCCON

Leer valor del contador en la EEPROM
                    banksel EEADR           
bank 2
                    movlw   ee_contador     
dirección de la EEPROM a leer
                    movwf   EEADR

                    banksel EECON1          
bank 3
                    bcf     EECON1
EEPGD   acceso a la memoria de datos
                    bsf     EECON1
RD      inicia la lectura

                    banksel EEDATA          
bank 2
                    movf    EEDATA
w       dato leído en W
                    movwf   contador        
guardar en SRAM
;
                    
banksel PORTA           bank 0durante el programa

#if test_eeprom
Comprobar que el contador es correcto (esta parte es opcional)
                    
decf    contadorw     leemos el contador y le quitamos 1
                    andlw   0x3             
nos quedamos solo con los bits inferiores
                    addlw   0x1             
volvemos a sumarle 1
                    movwf   contador        
y lo guardamos
#endif
                    
goto    Visualiza       ir a presentar

Bucle principal
Principal
:          btfsc   PORTARA4      leer pulsador
                    
goto    Principal       Noesperar
;
Se ha pulsado el botón
                    call    incrementa_contador
Visualiza
:          call    visualiza_contador
                    call    salida_hacia_A

Esperar liberación del botón
Espera_levantar
:    call    Retardo_100ms   Esperar la suelta del botón

                    btfss   PORTA
RA4      leer pulsador
                    
goto    Espera_levantar Noesperar

Repetir
                    
goto    Principal


; ******************************************************************************
;; 
salida_hacia_A
;
Según el valor del contador ([1-4]), lo transforma en otrobasado en una
tabla y lo saca por el puerto A
;

salida_hacia_A:     call    transforma_contador
                    movwf   PORTA           
visualiza en puerto A
                    
return

transforma_contador:
                    
decf    contadorw     leemos el contador y le restamos 1
                    addwf   PCL
f          saltamos dentro de la tabla

;                            |76543210|
                    
retlw   b'00000010'
                    
retlw   b'00000101'
                    
retlw   b'00000110'
                    
retlw   b'00001001'

; ******************************************************************************
;; 
incrementa_contador
;
Incrementa el valor de la variable contadorentre 1 y 4inclusives.
;

incrementa_contador:
                    
bcf     contador2     Si el contador valía 4ahora vale 0
                    incf    contador
f     Incrementa el contador

Escribe el contador en la EEPROM
                    banksel EECON1          
bank 3
                    btfsc   EECON1
WR      esperar para poder escribir
                    
goto    $-1

                    banksel EEADR           
bank 2
                    movlw   ee_contador     
dirección donde vamos a escribir
                    movwf   EEADR

                    movf    contador
w     el valor que vamos a escribir
                    movwf   EEDATA

                    banksel EECON1          
bank 3
                    bcf     EECON1
EEPGD   acceso a la memoria de datos
                    bsf     EECON1
WREN    activa la escritura

;                    bcf     INTCONGIE     desactivar interrupciones

                    movlw   
b'01010101'     valores mágicos (requeridos)
                    
movwf   EECON2
                    movlw   
b'10101010'
                    
movwf   EECON2

                    bsf     EECON1
WR      comienza la escritura

;                    bsf     INTCONGIE     reactiva interrupciones

                    bcf     EECON1
WREN    desactiva escrituras

                    banksel PORTA           
volvemos a bank 0
                    
return

; ******************************************************************************
;; 
visualiza_contador
;
Muestra el valor del contador en el display de 7 segmentos
;

visualiza_contador:
                    
movfw   contador        leemos contador
                    call    w_a_digito      
transformación a dígito 7 segmentos
                    movwf   PORTB           
visualiza en puerto B
                    
return

w_a_digito:         addwf   PCLf          salta al dígito indexado por w

;                            |76543210|
                    
retlw   b'00111111'     0
                    retlw   
b'00000110'     1
                    retlw   
b'01011011'     2
                    retlw   
b'01001111'     3
                    retlw   
b'01100110'     4
                    retlw   
b'01101101'     5
                    retlw   
b'01111101'     6
                    retlw   
b'00000111'     7
                    retlw   
b'01111111'     8
                    retlw   
b'01101111'     9

; ----------------------------------------------------------------------------------------------------
Espera 100ms
Frecuencia de reloj 4Mhz
;
Espera real 0.1 segundos 100000 ciclos
Error 0.00 %

Retardo_var:        udata_shr

Retardo_100ms_d1    res 1
Retardo_100ms_d2    res 1

Retardo_code
:       code

Retardo_100ms
:
                                    ;
99993 ciclos
                    movlw   0x1E
                    movwf   Retardo_100ms_d1
                    movlw   0x4F
                    movwf   Retardo_100ms_d2

Retardo_100ms_loop
:
                    
decfsz  Retardo_100ms_d1f
                    
goto    $+2
                    decfsz  Retardo_100ms_d2
f
                    
goto    Retardo_100ms_loop

                                    
;3 ciclos
                    
goto    $+1
                    nop

                                    
;4 ciclos (incluyendo la llamada)
                    return

Generado por delay_pic.pl (Joaquín Ferrero2014.07.22)
; ./
delay_pic.pl -s Retardo_100ms 4Mhz 100ms
mar 22 jul 2014 19:22:23 CEST
http://perlenespanol.com/foro/generador-de-codigos-de-retardo-para-microcontroladores-pic-t8602.html
; ----------------------------------------------------------------------------------------------------

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


                    
end 
Muchas gracias por el código, lo he probado y funciona.

Con la ayuda de 'de' inicializamos el valor de la posición 0x02 de la EEPROM a '1' (según el mapa de memoria, esa dirección de EEPROM corresponde a la 0x2102 en la mayor parte de los PIC 1x -no de los PIC 18- Ver más información sobre 'de' en el manual del ensamblador MPASM). Ese valor es el que se graba en el momento de grabar el programa en el µcontrolador, como valor inicial.

En libros en español e incluso en el datasheet del PIC16F88, no he encontrado esa información que debo ponerlo en dos direcciones más adelante. Con razón que me volvía loco de la cabeza.


Después de inicializar el µcontrolador, leemos la EEPROM. Luego comprobamos que el valor esté realmente entre los valores que queremos (1 a 4) (esta parte es opcional y la controla un #define).

Y luego sigue todo lo demás.

Un detalle, que he dejado comentado, son las líneas que activan y desactivan las interrupciones, en la parte de la escritura en la EEPROM, porque este programa no tiene interrupciones definidas (al menos de momento).

Entendido y es verdad.

Además, he simplificado la forma de leer el botón.
Gracias por todo, aún así buscaré información sobre este tema, sobre todo en MPASM.


06/08/2014 #31

Avatar de JoaquinFerrero

Ya veo que funciona, y muy bien

La información sobre lo de usar 'de' la encontré por pura casualidad Es la página 96 del documento "mpasmx/Docs/MPASM_MPLINK_User_Guide.pdf" (DS33014L). Busqué por la palabra EEPROM en el documento, para ver si ponía algún ejemplo de cómo hacer la lectura/escritura, y salió eso, así que lo agregué al programa.

Se trata de una característica propia del ensamblador, y sólo para inicializar la EEPROM en el momento de la grabación del programa. Si no se va a grabar nada en la EEPROM, al principio, pues no hace falta.

En el caso del compilador XC8 de MPLAB, se hace con la macro __EEPROM_DATA() o el cualificador __eeprom.
06/08/2014 #32

Avatar de Meta

Lo tendré que leer más a fondo.

Una cosa que no entiendo lo que hiciste aquí.

Código:
#if test_eeprom
; Comprobar que el contador es correcto (esta parte es opcional)
                    decf    contador, w     ; leemos el contador y le quitamos 1
                    andlw   0x3             ; nos quedamos solo con los bits inferiores
                    addlw   0x1             ; volvemos a sumarle 1
                    movwf   contador        ; y lo guardamos
#endif
                    goto    Visualiza       ; ir a presentar
Está claro que es para comprobar, pero hay un pero en las EEPROM, que duran un tiempo. Si pasa esos ciclos que creo que eran unos mil, esa zona de memoria dejará de funcionar.

Saludo.
07/08/2014 #33

Avatar de JoaquinFerrero

La presencia de esas cuatro líneas en el ensamblado del programa depende del valor que tenga el #define del símbolo test_eeprom (unas líneas más arriba). Por defecto, lo he dejado en 0, para no incluirlas, ya que se supone que el 'de' va a funcionar y el programador del PIC va a grabar el valor inicial del contador en la memoria EEPROM.

Y no sé dónde has leído eso de la memoria EEPROM, pero según la página 3 (page 1) del datasheet del PIC16F88, esa memoria aguanta 1 millón de ciclos de lectura/escritura, y los datos guardados pueden mantenerse (es decir, sin alimentación) durante ¡más de 40 años!
07/08/2014 #34

Avatar de Meta

Cierto.

Por cierto.
Cuando pones etiquetas como esta incrementa_contador:
es decir, con : al final. En realidad no hace falta.

¿Es una ventaja poner : al final de la etiqueta que cuando no los tiene?

Otra curisosidad. En la variables o variables RES 1, me quita una pocisión de memoria, si pongo RES 15 me quita 15. Si solo uso un byte, a pesar de usar 15 como reserva, queda como ocupada los 15 byte.

¿Qué utilidad tiene realmente?

A mi me funciona igual.
07/08/2014 #35

Avatar de JoaquinFerrero

Con el ensamblador de MPASM, no, no hay ventaja. Se pueden poner o no.

Si los pongo es simplemente por costumbre: muchos otros lenguajes ensambladores sí que lo necesitan. Incluso el conocido ensamblador ASxxxx usa el '::' para declarar la etiqueta como global.

Otra cosilla... en el código dejé 0x02 como dirección de ee_contador, pero podría haber sido cualquier otra, en el rango 0x00 a 0xFF.
07/08/2014 #36

Avatar de Meta

JoaquinFerrero dijo: Ver Mensaje

Otra cosilla... en el código dejé 0x02 como dirección de ee_contador, pero podría haber sido cualquier otra, en el rango 0x00 a 0xFF.
Pensé que poner desde 0x00 daba problemas y se recomendaba a 0x02 en adelante.
07/08/2014 #37

Avatar de JoaquinFerrero

Pues no, puedes elegir la dirección que quieras. Revisa la página 96 indicada antes, donde se describe 'de', y verás que te explica lo del desplazamiento 0x2100, para referirnos a la EE_PROM.

Lo de dejarlo en 0x02 es porque estuve haciendo pruebas con el depurador del MPASM, ejecutando el programa paso a paso, para ver qué hacía, y es ahí donde me di cuenta del fallo gordo que había en los primeras versiones del programa. Estaba usando

movf ee_contador, w ; mover el contenido de ee_contador a w

en lugar de lo correcto, que es

movlw ee_contador ; mover la dirección de ee_contador a w

Vamos, que estaba confundiendo el contenido con la dirección del contenido.

Hasta que no ejecutas el programa paso a paso, con el depurador del MPASM no te das cuenta de estas cosas

Otra cosilla... acabo de darme cuenta que el mnemónico movfw realmente es una pseudo-instrucción, y Microchip recomienda no usarla, así que la línea

movfw contador ; leemos contador

se debe cambiar a

movf contador,w ; leemos contador
07/08/2014 #38

Avatar de Meta

El movfw, nunca lo uso. Por algo será que Microchip no quiere que lo usemos. De todas formas, se permite usarlo.
15/08/2014 #39

Avatar de Meta

Buenas:

Voy hacerles una pregunta. Sobre el código de arriba quiero hacer algo parecido del PIC16F88 al PIC16F630 para saber si realmente funciona. Hablo de adaptación del código y usando un decodificador 74LS48.

Transformar este esquema...


Con este otro.

Habiendo el primer circuito con menos componentes. ¿Por qué usar el segundo esquema también?

Porque otras personas que quieren montar el circuito no pueden debido a que su local de electrónica favorita no tienen el PIC16F88 y si el PIC16F630 junto con el decodificador de 7 segmentos 74LS48.

Partiendo del código de abajo del PIC16F88 para analizarlo bien.
Código:
;
; Un pulsador en RA4 va incrementando un contador, entre [1-4].
; La salida se envía a un display de 7 seg. en PORTB, y hacia salidas en PORTA.
; El contador queda guardado en la EEPROM.
;
; (Contador)  |RB 76543210 |RA 76543210
; ------------|------------------------
;       1     |   00000011 |   00000010
;       2     |   00100100 |   00000101
;       3     |   00001100 |   00000110
;       4     |   00111100 |   00001001
;
; PORTA:
;  RA0 : OE1
;  RA1 : OE2
;  RA2 : A21
;  RA3 : AUX
;  RA4 : Pulsador
;
; PORTB : display de 7 segmentos. a = RB0
;

;*******************************************************************************
; Listado y condiciones de ensamblado

                    processor   16F88           ; 4 Mhz
                    radix       dec
                    errorlevel  -302            ; Turn off banking message

;*******************************************************************************
; Bibliotecas

                    include p16f88.inc

;*******************************************************************************
; Fusibles

  __CONFIG _CONFIG1, _CP_OFF & _DEBUG_OFF & _WRT_PROTECT_OFF & _CPD_OFF & _LVP_OFF & _BODEN_OFF & _MCLR_ON & _PWRTE_ON & _WDT_OFF & _INTRC_IO

; _CP_OFF           : Protección de código
; _DEBUG_OFF        : Debug en circuito
; _WRT_PROTECT_OFF  : Protección a escritura en memoria de programa
; _CPD_OFF          : Protección de código de datos
; _LVP_OFF          : Programación en baja tensión
; _BODEN_OFF        : Reset por Brown-out
; _MCLRE_ON         : Reset por pin externo
; _PWRTE_ON         : Retraso al reset
; _WDT_OFF          : Watchdog
; _XT_OSC           : Oscilador externo del tipo XT


;*******************************************************************************
; Definiciones

; Máscaras de E/S de los puertos. 0 = salida, 1 = entrada
;                    |76543210|
#define PORTA_IO    b'00010000'
#define PORTB_IO    b'00000000'

; Incorporar sentencias de comprobación de la EEPROM
#define test_eeprom 0

;*******************************************************************************
; Variables
                    udata_shr

contador            res 1                   ; contador en la SRAM

; ******************************************************************************
; EEPROM

; Dirección del contador dentro de la EEPROM
ee_contador:        equ     0x02

; Debemos desplazarnos a la zona de memoria más allá del 0x2100, que corresponde
; a la zona de la EEPROM en la mayoría de los PIC (ver documentación).
; Este valor es el que se grabará en la EEPROM en el momento de grabar el programa
; en el µcontrolador.
                    org     0x2100 + ee_contador

                    de      1               ; valor inicial de ee_contador

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

                    code    0x0000

_Start:
                    banksel ANSEL           ; bank 1
                    clrf    ANSEL           ; puerto A digital
                    movlw   PORTA_IO        ; definir E/S puerto A
                    movwf   TRISA
                    movlw   PORTB_IO        ; definir E/S puerto B
                    movwf   TRISB
                    movlw   b'01100000'     ; 4 MHz
                    movwf   OSCCON

; Leer valor del contador en la EEPROM
                    banksel EEADR           ; bank 2
                    movlw   ee_contador     ; dirección de la EEPROM a leer
                    movwf   EEADR

                    banksel EECON1          ; bank 3
                    bcf     EECON1, EEPGD   ; acceso a la memoria de datos
                    bsf     EECON1, RD      ; inicia la lectura

                    banksel EEDATA          ; bank 2
                    movf    EEDATA, w       ; dato leído en W
                    movwf   contador        ; guardar en SRAM
;
                    banksel PORTA           ; bank 0, durante el programa

#if test_eeprom
; Comprobar que el contador es correcto (esta parte es opcional)
                    decf    contador, w     ; leemos el contador y le quitamos 1
                    andlw   0x3             ; nos quedamos solo con los bits inferiores
                    addlw   0x1             ; volvemos a sumarle 1
                    movwf   contador        ; y lo guardamos
#endif
                    goto    Visualiza       ; ir a presentar

; Bucle principal
Principal:          btfsc   PORTA, RA4      ; leer pulsador
                    goto    Principal       ; No, esperar
;
; Se ha pulsado el botón
                    call    incrementa_contador
Visualiza:          call    visualiza_contador
                    call    salida_hacia_A

; Esperar liberación del botón
Espera_levantar:    call    Retardo_100ms   ; Esperar la suelta del botón

                    btfss   PORTA, RA4      ; leer pulsador
                    goto    Espera_levantar ; No, esperar

; Repetir
                    goto    Principal


; ******************************************************************************
;; salida_hacia_A
;
; Según el valor del contador ([1-4]), lo transforma en otro, basado en una
; tabla y lo saca por el puerto A
;

salida_hacia_A:     call    transforma_contador
                    movwf   PORTA           ; visualiza en puerto A
                    return

transforma_contador:
                    decf    contador, w     ; leemos el contador y le restamos 1
                    addwf   PCL, f          ; saltamos dentro de la tabla

;                            |76543210|
                    retlw   b'00000010'
                    retlw   b'00000101'
                    retlw   b'00000110'
                    retlw   b'00001001'

; ******************************************************************************
;; incrementa_contador
;
; Incrementa el valor de la variable contador, entre 1 y 4, inclusives.
;

incrementa_contador:
                    bcf     contador, 2     ; Si el contador valía 4, ahora vale 0
                    incf    contador, f     ; Incrementa el contador

; Escribe el contador en la EEPROM
                    banksel EECON1          ; bank 3
                    btfsc   EECON1, WR      ; esperar para poder escribir
                    goto    $-1

                    banksel EEADR           ; bank 2
                    movlw   ee_contador     ; dirección donde vamos a escribir
                    movwf   EEADR

                    movf    contador, w     ; el valor que vamos a escribir
                    movwf   EEDATA

                    banksel EECON1          ; bank 3
                    bcf     EECON1, EEPGD   ; acceso a la memoria de datos
                    bsf     EECON1, WREN    ; activa la escritura

;                    bcf     INTCON, GIE     ; desactivar interrupciones

                    movlw   b'01010101'     ; valores mágicos (requeridos)
                    movwf   EECON2
                    movlw   b'10101010'
                    movwf   EECON2

                    bsf     EECON1, WR      ; comienza la escritura

;                    bsf     INTCON, GIE     ; reactiva interrupciones

                    bcf     EECON1, WREN    ; desactiva escrituras

                    banksel PORTA           ; volvemos a bank 0
                    return

; ******************************************************************************
;; visualiza_contador
;
; Muestra el valor del contador en el display de 7 segmentos
;

visualiza_contador:
                    movfw   contador        ; leemos contador
                    call    w_a_digito      ; transformación a dígito 7 segmentos
                    movwf   PORTB           ; visualiza en puerto B
                    return

w_a_digito:         addwf   PCL, f          ; salta al dígito indexado por w

;                            |76543210|
                    retlw   b'00111111'     ; 0
                    retlw   b'00000110'     ; 1
                    retlw   b'01011011'     ; 2
                    retlw   b'01001111'     ; 3
                    retlw   b'01100110'     ; 4
                    retlw   b'01101101'     ; 5
                    retlw   b'01111101'     ; 6
                    retlw   b'00000111'     ; 7
                    retlw   b'01111111'     ; 8
                    retlw   b'01101111'     ; 9

; ----------------------------------------------------------------------------------------------------
; Espera = 100ms
; Frecuencia de reloj = 4Mhz
;
; Espera real = 0.1 segundos = 100000 ciclos
; Error = 0.00 %

Retardo_var:        udata_shr

Retardo_100ms_d1    res 1
Retardo_100ms_d2    res 1

Retardo_code:       code

Retardo_100ms:
                                    ;99993 ciclos
                    movlw   0x1E
                    movwf   Retardo_100ms_d1
                    movlw   0x4F
                    movwf   Retardo_100ms_d2

Retardo_100ms_loop:
                    decfsz  Retardo_100ms_d1, f
                    goto    $+2
                    decfsz  Retardo_100ms_d2, f
                    goto    Retardo_100ms_loop

                                    ;3 ciclos
                    goto    $+1
                    nop

                                    ;4 ciclos (incluyendo la llamada)
                    return

; Generado por delay_pic.pl (Joaquín Ferrero. 2014.07.22)
; ./delay_pic.pl -s Retardo_100ms 4Mhz 100ms
; mar 22 jul 2014 19:22:23 CEST
; http://perlenespanol.com/foro/generador-de-codigos-de-retardo-para-microcontroladores-pic-t8602.html
; ----------------------------------------------------------------------------------------------------

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


                    end  


Antes de tocar algo.

¿Debo saber algo más?

Un saludo.

PD: Espero que no sea mucho de machacarte las neuronas por una adapación en asm.
15/08/2014 #40

Avatar de JoaquinFerrero

Meta dijo: Ver Mensaje
Porque otras personas que quieren montar el circuito no pueden debido a que su local de electrónica favorita no tienen el PIC16F88 y si el PIC16F630
Pero... si hoy en día todo el mundo compra la electrónica por Internet... Sale barato y te lo llevan a casa en menos de 48 horas...

Meta dijo: Ver Mensaje
junto con el decodificador de 7 segmentos 74LS48
¿Realmente lo necesitas? El PIC puede seguir entregando 7 salidas dedicadas para el dígito. Ese PIC tiene 12 E/S.

Además... fíjate que la patilla b siempre está a nivel alto, así que, te puedes ahorrar el conectarla al PIC
¿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.