Autor Tema: Ayuda con comunicación serie en pic16f88  (Leído 2753 veces)

0 Usuarios y 1 Visitante están viendo este tema.

Desconectado BORIScristian

  • PIC10
  • *
  • Mensajes: 13
Ayuda con comunicación serie en pic16f88
« en: 21 de Octubre de 2015, 17:54:39 »
Hola podrían ayudarme con este problema de comunicación serie?
Necesito comparar lo que recibo por el puerto serie con un registro y si lo que recibí es  por ejemplo una r en código ascii el programa reinicia, la parte de la comparación la borre del programa porque nunca se ponía a 1 el flag PIR1,RCIF asi que decidi primero resolver este problema
El programa es un contador que decentementa o incrementa y para esto utilice el TMR0, así que necesito comunicar el pic sin este TMR0.

Seguí paso a paso lo que decia el datasheet pero lo pruebo en proteus  y no funciona. Lo pruebo en pic simulator IDE y tampoco funciona nisiquiera prende el led cuando pregunto por el PIR1,rcif.
Si alguien tiene algún programita en .asm que utilice esta comunicación asincronica  se los agradeceria


";====================================================================
; Main.asm file generated by New Project wizard
;
; Created:   mar mar 17 2015
; Processor: PIC16F88
; Compiler:  MPASM (MPLAB)
;====================================================================

;====================================================================
; DEFINITIONS
;====================================================================

#include p16f88.inc                ; Include register definition file
__CONFIG _CONFIG1, _CP_OFF & _WDT_OFF & _BODEN_OFF & _PWRTE_OFF &  _MCLR_OFF& _LVP_OFF & _INTRC_IO


;====================================================================
; VARIABLES
;====================================================================
    cblock H'70'
   d1
   d2
    uni
    dec
    cent
    contint
    DATIN
   
   endc


;====================================================================
; RESET and INTERRUPT VECTORS
;====================================================================

      ORG   0x00
      goto  Start

      ORG   0x04
      goto  interrupcion


;====================================================================
; CODE SEGMENT
;====================================================================

PGM   code


Start
;---------------------puertos--------------------------------------------------
      bsf       STATUS, RP0
      movlw    b'00000111'
      movwf    TRISA
     
      MOVLW     B'00100100'
     MOVWF     TRISB

      movlw     0x60
      movwf     OSCCON
      clrf      ANSEL
   
;---------------------timer----------------------------------------------------
      bsf       STATUS, RP0
      movlw     b'00000111'
      movwf     OPTION_REG
      BANKSEL   PORTA
      movlw     d'61'
      movwf     TMR0
;---------------------comunicacion serie----------------------------------------
      banksel SPBRG
      MOVLW     D'25'       ;  9600 BAUD @ 20 MHZ FOSC +0.16 ERR
     MOVWF     SPBRG
     MOVLW     B'00100100'    ; BRGH = 1
      MOVWF     TXSTA      ; ENABLE ASYNC TRANSMISSION, SET BRGH
     BANKSEL   RCSTA       ; BANK0
     MOVLW     B'10010000'
     MOVWF     RCSTA      ; ENABLE ASYNC RECEPTION


     MOVF      RCREG,W
     MOVF      RCREG,W
     MOVF      RCREG,W     ; FLUSH RECEIVE BUFFER
;---------------------registros------------------------------------------------
      call      LCD_inicializa
      clrf      uni
      clrf      dec
      clrf      cent
      clrf      contint




;-----------------------PROGRAMAPRINCIPAL--------------------------------------

loop
    call    mostrar_dis
    call    datos
    btfsc   PORTA, 0
    call    reanudar
    btfsc   PORTA,1
    call    parar
    btfsc   PORTA,2
    CALL    resetear
    goto    loop
;-----------------------RUTINAS-----------------------------------------------
mostrar_dis
      movf  uni, w
      swapf uni,w
      movwf PORTA
      bcf   PORTB, 0

      bsf   PORTB, 0
      movf  dec, w
      swapf dec,w
      movwf PORTA
      bcf   PORTB, 1

      bsf   PORTB, 1
      movf  cent, w
      swapf cent,w
      movwf PORTA
      bcf   PORTB,3

      bsf   PORTB,3
      return
;------------------------------------------------------------------------------
mostrar_lcd
    call    borra_display
    movf    cent, w
    addlw   d'48'   ;pasaje decimal a ASCII , para que se muestre en LCD
    call    LCD_caracter
    movf    dec, w
    addlw   d'48'   ;pasaje decimal a ASCII , para que se muestre en LCD
    call    LCD_caracter
    movf    uni, w
    addlw   d'48'   ;pasaje decimal a ASCII , para que se muestre en LCD
    call    LCD_caracter
    call    Delay
    return
;------------------------------------------------------------------------------
resetear
    btfsc   PORTA,2
    GOTO    resetear
    clrf    uni
    clrf    dec
    clrf    cent
    BANKSEL TRISA
    clrf    INTCON
    BANKSEL PORTA
    return
;------------------------------------------------------------------------------
parar
    btfsc   PORTA,1
    goto    parar
    BANKSEL TRISA
    clrf    INTCON
    BANKSEL PORTA
    return
;------------------------------------------------------------------------------
reanudar
      btfsc   PORTA,0
      goto    reanudar
      BANKSEL TRISA
      movlw     b'10100000'
      movwf     INTCON
      BANKSEL PORTA
      return
;------------------------------------------------------------------------------
datos
    BANKSEL PIR1
    BTFSS   PIR1,RCIF
    RETURN
    bsf     PORTA,3
    MOVWF   RCREG,W
    return

   
;------------------------------------------------------------------------------
decrementar
    btfsc   PORTA, 3
    goto    decrementar
    movlw   d'61'
    movwf   TMR0
    clrf    contint
    decf    uni
    movlw   d'255'
    subwf   uni, w
    btfsc   STATUS, Z
    call    decdec
    return
decdec
    movlw  d'9'
    movwf  uni
    decf   dec
    movlw   d'255'
    subwf   dec, w
    btfsc   STATUS, Z
    call    deccent
    return
deccent
    movlw d'9'
    movwf dec
    decf  cent
    movlw   d'255'
    subwf   cent, w
    btfsc   STATUS, Z
    call    cargarcent
    return
cargarcent
    movlw   d'9'
    movwf   cent
    return
;------------------------------------------------------------------------------
incrementar
    btfsc   PORTA, 2
    goto    incrementar
inc MOVLW   D'61'
    movwf   TMR0
    clrf    contint
    incf    uni
    movlw   d'10'
    subwf   uni, w
    btfsc   STATUS, Z
    call    incdec
    return
incdec
    clrf    uni
    incf    dec
    movlw   d'10'
    subwf   dec, w
    btfsc   STATUS, Z
    call    inccent
    return
inccent
    incf    cent
    clrf    dec
    movlw   d'10'
    subwf   cent, w
    btfsc   STATUS, Z
    clrf    cent
    return
;------------------------------------------------------------------------------

   

;-------------------------RETARDOS----------------------------------------------

Delay
    movlw   0x86
   movwf   d1
   movlw   0x14
   movwf   d2
Delay_0
   decfsz   d1, f
   goto   $+2
   decfsz   d2, f
   goto   Delay
    goto   $+1
   nop
    return


;-------------------------INTERRUPCIONES---------------------------------------

;interrupcion para 1 microsegundo(TMR0 EN 256 EN CONFIG)-----------------------
;call    incint
;movlw   d'256'
;movwf   TMR0
;bcf     INTCON,2
;RETFIE



;INTERRUPCION PARA 1 SEGUNDO(CAMBIANDO EL TMR0 A 61 EN CONFIG)------------------
interrupcion

 
 incf    contint
 movlw   d'20'
 subwf   contint, w
 btfsc   STATUS, Z
 call    incint
 movlw   d'61'
 movwf   TMR0
 bcf INTCON, 2
 retfie

incint
 clrf    contint
 call    incrementar
 return

#INCLUDE <LCD8BITS.INC>
;====================================================================
      END


« Última modificación: 26 de Octubre de 2015, 14:40:22 por BORIScristian »

Desconectado KILLERJC

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 8242
Re:Ayuda con comunicación serie en pic16f88
« Respuesta #1 en: 22 de Octubre de 2015, 00:20:21 »
Bueno voy a poner los "errores" o "sugerencias" sobre el codigo, veo que lo has programado bien, y supiste dividir el codigo en secciones y un loop principal, asi que voy a ser concreto por que creo que vas a entenderme, sino sos libre de preguntarme las dudas que tengas.

- Mostrar_dis:

Código: ASM
  1. bcf   PORTB,3
  2.       bsf   PORTB,3
Eso no creo que sea tu proposito.. Imagino que es un error, ya que a 20Mhz estaria en 0, 200ns y luego encendido todo el tiempo hasta que llegue nuevamente a ese BCF, tal ves ese BCF deberia estar al comienzo de esa rutina

Código: ASM
  1. bsf   PORTB, 0
  2.       movf  dec, w
  3.       swapf dec,w
  4.       movwf PORTA
  5.       bcf   PORTB, 1

Tambien la muestra en los displays, en el proteus va a funcionar por que es una simulacion, en real no se si tanto. Ya que tu display estaria encendido por 4 instrucciones, a 20Mhz eso es 800ns y luego apagado que estoy mas que seguro que apagado es mucho mas tiempo, pero mucho mas. entonces vas a ver poco y nada en un display real, pero en proteus lo vas a ver bien. Tenelo en cuenta a esto

- Datos:
 Aqui obviamente deberias hacerlo por interrupcion no queda otra. Es un SI o SI. Especialmente cuando los botones tienen un bloqueo (resetear,parar,reanudar), lo cual no tiene sentido para lo que hace, ya que podrias estar borrando constantemente INTCON sin ningun problema en los botones.

Interrupciones
En este caso te falta guardar el contexto, es decir apenas entras a la interrupcion tenes que guardar W y STATUS en 2 "variables" y luego cuando salis de la interrupcion debes recuperarlos y dejarlos como estaban, asi cuando el programa vuelve, tiene W y las banderas STATUS con el mismo valor que cuando salio para la interrupcion, o lo que es lo mismo que el programa no se de cuenta que hubo una interrupcion. En el datasheet si buscas sobre interrupciones te da el codigo para poner apenas entra y cuando salis de la interrupcion.

- interrupcion:
Deberias recargar rapidamente el TMR0 , seria lo primero que harias, si usas la interrupcion de recepcion entonces deberias preguntar primero por cual interrupcion ocurrio, si es el caso del TMR0, ahi recargarlo, hacer tus cosas y luego salir.
Esta por demas decirte que la interrupcion del TMR0 no te va a dar justo ya que deberias contar las instrucciones anteriores + ciclos que tarda en entrar a la interrupcion ( que creo que son 3 para es PIC ). Podrias usar el modulo CCP + Timer1 y solucionarte un poco la vida con respecto a recargar el TMR, la complica un poco mas la configuracion.
El CALL a incint es un call que no tiene sentido, estas haciendo un call por 2 instrucciones, con lo que respecta el tiempo.

- incrementar:
Esto es llamada desde la interrupcion. Y hay un problema

Código: ASM
  1. incrementar
  2.     btfsc   PORTA, 2
  3.     goto    incrementar

Puede quedarse para siempre ahi... Una interrupcion debe durar lo menos posible y salir, por lo cual deberias evitar a toda costa cosas como esas, en el cual se pueda quedar en la interrupcion bastante tiempo, Por que cuando entra a la interrupcion se desactivan, entonces si tu timer que cargaste con el valor 61, llega a 255 y rebalsa, no va a comenzar de nuevo la interrupcion, por que estan desactivadas :P, estarias perdiendo esas "interrupciones" del timer, si es un boton podes estar hablando de varios segundos.

Código: ASM
  1. clrf    contint
  2. inc MOVLW   D'61'
  3.     movwf   TMR0

Recargas Nuevamente el timer.. seguro que lo hiciste por lo que dije anteriormente, y ademas volves a poner a 0 a contint, lo cual hiciste hace un ratito antes de hacer el CALL a incrementar. Estarias poniendo un 0 en un 0.

Código: ASM
  1. btfsc   STATUS, Z
  2.     call    incdec
  3.     return
  4. incdec

Por que un CALL para eso ? Directamente cambia la logica de BTFSC a BTFSS y ponele que salte el RETURN asi:

Código: ASM
  1. BTFSS   STATUS,Z
  2.         RETURN

-decrementar:
No esta usado, pero se pueden ver los mismos errores que incrementar.

Moraleja:
Las interrupciones:

- Guardar y reponer W y STATUS, SIEMPRE
- Lo mas rapidas posibles, nada deberia consumir mucho tiempo en estas

Timers:
- Si necesitas una verdadera base de tiempo intenta usar el TMR1 + CCP si es que lo tiene en modo compare.


Solucionado todo esto podemos tratar el tema de las interrupciones del puerto serie ( las cuales faltan habilitar por supuesto )
Pero es imposible intentar hacer las interrupciones cuando ya tenes estos errores. Primero hacer funcionar lo que hay y luego agregarlo lo necesario.
« Última modificación: 22 de Octubre de 2015, 01:32:51 por KILLERJC »

Desconectado BORIScristian

  • PIC10
  • *
  • Mensajes: 13
Re:Ayuda con comunicación serie en pic16f88
« Respuesta #2 en: 23 de Octubre de 2015, 04:43:34 »
Muchisimas gracias, ya estoy arreglando estos errores, el tema de mostrar el display puse bcf y después bsf porque no recordaba si era cátodo común o ánodo común el entrenador, pero ahora que veo tu correción recordé que es como vos decis, ademas claro se mantendria apagado hasta volver a mostrar el display, cuando termine de arreglar el código vuelvo a subirlo, lo del TMR0 es por pedido de un profesor pero como decías que lo mejor es tardar lo menos posible se me ocurrió  asignarle un registro que se ponga a 1 cuando tenga que incrementar y hacerlo durante el programa fuera de la interrupción estaría bien?

Desconectado KILLERJC

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 8242
Re:Ayuda con comunicación serie en pic16f88
« Respuesta #3 en: 23 de Octubre de 2015, 05:03:21 »
Ah pense que estabas haciendo algo para alguien o para vos, si es un pedido exacto el del TMR0 ( a pesar que sea mas complejo usar TMR1 + CCP ) hacelo con el TMR0.

Lo que decia era esto:

Código: ASM
  1. Interrupcion:
  2.        ;Aca guardas W y STATUS
  3.  
  4.        BTFSC INTCON,TMR0IF ; Creo que asi se llamaba :P
  5.        GOTO   Int_Timer
  6.        BTFSC PIRx,RCIF
  7.        GOTO   Int_USART
  8.  
  9. Fin_int:
  10.       ; Devuelvo W y STATUS
  11.       RETFIE
  12.  
  13. Int_Timer:
  14.       MOVLW 0x61        ;Lo primero que haces
  15.       MOVWF TMR0
  16.       BCF   INTCON,TMR0IF    ;Limpio flag
  17.       ;aca lo que sea
  18.       GOTO Fin_int
  19.  
  20. Int_USART:
  21.       BCF   PIRx,RCIF    ;Limpio flag
  22.       ;aca lo que sea
  23.       GOTO Fin_int

Eso nomas... lo cargas lo mas pronto posible, eso es todo lo que queria decir. por que sino deberias tener en cuenta, los ciclos que tarda en entrar a la interrupcion, los ciclos de cada instruccion antes de cargar al timer  ya que eso es tiempo que esta pasando y cuando vos cargues tu valor en el timer lo vas a perder. El modulo CCP poner a 0 el timer1 por hardware, lo cual lo hace mas simple para vos. y no perdes "ciclos" ni necesidad de contar. Pero si es una obligacion usalo, al fin la idea es que funcione :P, asi que si queres ni te la compliques, no creo que el profesor le busque los microsegundos de diferencia.

Desconectado BORIScristian

  • PIC10
  • *
  • Mensajes: 13
Re:Ayuda con comunicación serie en pic16f88
« Respuesta #4 en: 25 de Octubre de 2015, 00:38:12 »
Tarde un poco en subir el nuevo código porque se me complico el tema de la interrupción, pero ya lo pude solucionar. El tema del multiplexado lo dejé así porque cuando lo cambie fallaba en el proteus, lo único que voy a hacer es agregarle un delay de 50 ms aproximadamente entre el apagado y el encendido del mismo cuando tenga que probarlo en el entrenador digital.
Ahora si el problema seria como recibir por usart un código ascii y apartir de que letra represente llamar a alguna rutina, por ejemplo si recibí una "s"  el programa comienza a contar (s de start), yo tenia pensado mover RCREG a algun registro y ahi compararlo con h73 o h73, pero primero que nada debería lograr recibir los datos jajajajaj  :-)
;======================================================================================
;====================================================================
; Main.asm file generated by New Project wizard
;
; Created:   mar mar 17 2015
; Processor: PIC16F88
; Compiler:  MPASM (MPLAB)
;====================================================================

;====================================================================
; DEFINITIONS
;====================================================================

#include p16f88.inc                ; Include register definition file
__CONFIG _CONFIG1, _CP_OFF & _WDT_OFF & _BODEN_OFF & _PWRTE_OFF &  _MCLR_OFF& _LVP_OFF & _INTRC_IO


;====================================================================
; VARIABLES
;====================================================================
    cblock H'70'
   d1
   d2
    uni
    dec
    cent
    contint
    DATIN
    STATUS_TEMP
    W_TEMP
    PCLATH_TEMP
   endc


;====================================================================
; RESET and INTERRUPT VECTORS
;====================================================================

      ORG   0x00
      goto  Start

      ORG   0x04
      goto  interrupcion


;====================================================================
; CODE SEGMENT
;====================================================================

PGM   code


Start
;---------------------puertos--------------------------------------------------
      bsf       STATUS, RP0
      movlw    b'00000111'
      movwf    TRISA
     
      MOVLW     B'00100100'
     MOVWF     TRISB

      movlw     0x60
      movwf     OSCCON
      clrf      ANSEL
   
;---------------------timer----------------------------------------------------
      bsf       STATUS, RP0
      movlw     b'00000111'
      movwf     OPTION_REG
      BANKSEL   PORTA
      movlw     d'61'
      movwf     TMR0
;---------------------comunicacion serie----------------------------------------
      banksel SPBRG
      MOVLW     D'25'       ;  9600 BAUD @ 20 MHZ FOSC +0.16 ERR
     MOVWF     SPBRG
     MOVLW     B'00100100'    ; BRGH = 1
      MOVWF     TXSTA      ; ENABLE ASYNC TRANSMISSION, SET BRGH
     BANKSEL   RCSTA       ; BANK0
     MOVLW     B'10010000'
     MOVWF     RCSTA      ; ENABLE ASYNC RECEPTION


     MOVF      RCREG,W
     MOVF      RCREG,W
     MOVF      RCREG,W     ; FLUSH RECEIVE BUFFER
;---------------------registros------------------------------------------------
      call      LCD_inicializa
      clrf      uni
      clrf      dec
      clrf      cent
      clrf      contint




;-----------------------PROGRAMAPRINCIPAL--------------------------------------

loop
    call    mostrar_dis
    btfsc   PORTA, 0
    call    reanudar
    btfsc   PORTA,1
    call    parar
    btfsc   PORTA,2
    CALL    resetear
    goto    loop
;-----------------------RUTINAS-----------------------------------------------
mostrar_dis
     
      movf  uni, w
      swapf uni,w
      movwf PORTA
      bcf   PORTB, 0
      bsf   PORTB,0
     
      movf  dec, w
      swapf dec,w
      movwf PORTA
      bcf   PORTB, 1
      BSF   PORTB,1


      movf  cent, w
      swapf cent,w
      movwf PORTA
      bcf   PORTB,3
      BSF   PORTB,3
      return
;------------------------------------------------------------------------------
mostrar_lcd
    call    borra_display
    movf    cent, w
    addlw   d'48'   ;pasaje decimal a ASCII , para que se muestre en LCD
    call    LCD_caracter
    movf    dec, w
    addlw   d'48'   ;pasaje decimal a ASCII , para que se muestre en LCD
    call    LCD_caracter
    movf    uni, w
    addlw   d'48'   ;pasaje decimal a ASCII , para que se muestre en LCD
    call    LCD_caracter
    call    Delay
    return
;------------------------------------------------------------------------------
resetear
    btfsc   PORTA,2
    GOTO    resetear
    clrf    uni
    clrf    dec
    clrf    cent
    BANKSEL TRISA
    clrf    INTCON
    BANKSEL PORTA
    return
;------------------------------------------------------------------------------
parar
    btfsc   PORTA,1
    goto    parar
    BANKSEL TRISA
    clrf    INTCON
    BANKSEL PORTA
    return
;------------------------------------------------------------------------------
reanudar
      btfsc   PORTA,0
      goto    reanudar
      BANKSEL TRISA
      movlw     b'10100000'
      movwf     INTCON
      BANKSEL PORTA
      return
;------------------------------------------------------------------------------
datos
    BANKSEL PIR1
    BTFSS   PIR1,RCIF
    RETURN
    bsf     PORTA,3
    MOVF    RCREG,W
    return

   
;------------------------------------------------------------------------------
decrementar
    btfsc   PORTA, 3
    goto    decrementar
    movlw   d'61'
    movwf   TMR0
    clrf    contint
    decf    uni
    movlw   d'255'
    subwf   uni, w
    btfsc   STATUS, Z
    call    decdec
    return
decdec
    movlw  d'9'
    movwf  uni
    decf   dec
    movlw   d'255'
    subwf   dec, w
    btfsc   STATUS, Z
    call    deccent
    return
deccent
    movlw d'9'
    movwf dec
    decf  cent
    movlw   d'255'
    subwf   cent, w
    btfsc   STATUS, Z
    call    cargarcent
    return
cargarcent
    movlw   d'9'
    movwf   cent
    return
;------------------------------------------------------------------------------
incrementar
    btfsc   PORTA, 2
    goto    incrementar
inc MOVLW   D'61'
    movwf   TMR0
    clrf    contint
    incf    uni
    movlw   d'10'
    subwf   uni, w
    btfsc   STATUS, Z
    call    incdec
    return
incdec
    clrf    uni
    incf    dec
    movlw   d'10'
    subwf   dec, w
    btfsc   STATUS, Z
    call    inccent
    return
inccent
    incf    cent
    clrf    dec
    movlw   d'10'
    subwf   cent, w
    btfsc   STATUS, Z
    clrf    cent
    return
;------------------------------------------------------------------------------

   

;-------------------------RETARDOS----------------------------------------------

Delay
    movlw   0x86
   movwf   d1
   movlw   0x14
   movwf   d2
Delay_0
   decfsz   d1, f
   goto   $+2
   decfsz   d2, f
   goto   Delay
    goto   $+1
   nop
    return


;-------------------------INTERRUPCIONES---------------------------------------

;interrupcion para 1 microsegundo(TMR0 EN 256 EN CONFIG)-----------------------
;call    incint
;movlw   d'256'
;movwf   TMR0
;bcf     INTCON,2
;RETFIE



;INTERRUPCION PARA 1 SEGUNDO(CAMBIANDO EL TMR0 A 61 EN CONFIG)------------------
interrupcion
    MOVWF   W_TEMP ;Copy W to TEMP register
    SWAPF   STATUS, W ;Swap status to be saved into W
    CLRF    STATUS ;bank 0, regardless of current bank, Clears IRP,RP1,RP0
    MOVWF   STATUS_TEMP ;Save status to bank zero STATUS_TEMP register
    MOVF    PCLATH, W ;Only required if using page 1
    MOVWF   PCLATH_TEMP ;Save PCLATH into W
    CLRF    PCLATH ;Page zero, regardless of current page


    BTFSC   INTCON,2
    GOTO    Int_Tmr
    BTFSC   PIR1,RCIF
    GOTO    Int_Rcreg

Int_Rcreg
    movf    RCREG,W
    GOTO    salir


Int_Tmr
    incf    contint
    movlw   d'20'
    subwf   contint, w
    btfss   STATUS, Z
    goto     salir
    MOVLW   D'61'
    movwf   TMR0
    clrf    contint
    incf    uni
    movlw   d'10'
    subwf   uni, w
    btfss   STATUS, Z
    goto    salir
    clrf    uni
    incf    dec
    movlw   d'10'
    subwf   dec, w
    btfss   STATUS, Z
    goto    salir
    incf    cent
    clrf    dec
    movlw   d'10'
    subwf   cent, w
    btfsc   STATUS, Z
    clrf    cent
    banksel TRISA
    BCF     INTCON,2
    BANKSEL PORTA
    goto    salir
salir
    BCF   INTCON,2
    MOVWF W_TEMP ;Copy W to TEMP register
    SWAPF STATUS, W ;Swap status to be saved into W
    CLRF STATUS ;bank 0, regardless of current bank, Clears IRP,RP1,RP0
    MOVWF STATUS_TEMP ;Save status to bank zero STATUS_TEMP register
    MOVF PCLATH, W ;Only required if using page 1
    MOVWF PCLATH_TEMP ;Save PCLATH into W
    CLRF PCLATH ;Page zero, regardless of current page
    RETFIE


#INCLUDE <LCD8BITS.INC>
;====================================================================
      END




Desconectado KILLERJC

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 8242
Re:Ayuda con comunicación serie en pic16f88
« Respuesta #5 en: 25 de Octubre de 2015, 01:29:27 »
Bueno no me fije demasiado en el programa, solo fui directo a la interrupcion. Esta mucho mejor hay algunas cosas a corregir, habia un :

Código: ASM
  1. BCF     INTCON,2

dentro de "salir", no hagas eso, por que si por alguna casualidad se dispara la interrupcion del timer mientras esta en la interrupcion de la UART por como esta realizado el programa ( con GOTO ) vas a perder esa interrupcion, asi que eso lo dejas unicamente dentro de la rutina del timer. Intenta usar los nombres de los bits, tal como:

Código: ASM
  1. BCF     INTCON,TMR0IF

Es mas practico de ver, ya que indica TMR (timer) 0 (cero ) IF ( Interrupt Flag ) que es. al igual que para habilitarlo TMR0IE ( de Interrupt Enable ).
Como el timer 0 no para, es decir NO hay un bit para decirle que deje de contar, la unica forma de "pararlo" es desactivar las interrupciones del timer, PERO si tenes activadas las interrupciones de la UART va a entrar por igual a la rutina de interrupcion, y el flag del timer 0 se va a setear siempre que exista un overflow (por mas que no esten habilitadas las interrupciones y como sigue contando pone a 1). Entonces, decidi cambiar el orden, antes estaba el TMR0 primer y luego la UART, ahora es al reves.

Código: ASM
  1. BTFSC   PIR1,RCIF
  2.     GOTO    Int_Rcreg
  3.     BTFSC   INTCON,TMR0IF
  4.     GOTO    Int_Tmr

Si llega a estar desactivada las interrupciones del timer0 ( como para pararlo ) y entra a una interrupcion, si o si entraria a la de la UART (que es la unica que puede hacerlo entrar ahi) y saldria de ahi dentro sin que se ejecute la rutina del TMR. Distinto hubiera sido si hubiera CALL en ves de GOTO, si  tuvieras unos CALL ahi, por mas que desactives las interrupciones entraria y deberias preguntar por si estan habilitadas o no.
Luego el codigo es simple:

Utilize un registro mas que llame TEMP.
Código: ASM
  1. Int_Rcreg
  2.         MOVF    RCREG,W ;Esto ya me borra el flag de la UART
  3.         MOVWF   TEMP            ;Registro temporal para mantener el dato
  4.         MOVLW   's'
  5.         SUBWF   TEMP,W          ; 's' - TEMP = W, si TEMP era 's' Z = 1 , start
  6.         BTFSC   STATUS,Z
  7.         GOTO    RX_Timer_Start
  8.         MOVLW   'p'             ; 'p' STOP
  9.         SUBWF   TEMP,W
  10.         BTFSC   STATUS,Z
  11.         BCF     INTCON,TMR0IE   ; Deshabilito las interrupciones del timer
  12.         MOVLW   'c'             ; 'c' Clear - Borra todo
  13.         SUBWF   TEMP,W
  14.         BTFSS   STATUS,Z
  15.         GOTO    salir          
  16.         CLRF    uni             ; Solo resetea, no para el timer para nada. si quisiera parar el timer usaria
  17.         CLRF    dec             ; otro BCF INTCON,TMR0IE
  18.         CLRF    cent
  19.         MOVLW   D'61'           ; Cargo el timer de nuevo, esto es por que el TMR0 no puede parar
  20.         MOVWF   TMR0           
  21.         BCF     INTCON,TMR0IF   ; Borro flag, sino entraria rapidamente a la interrupcion, ya que como no para esto estaria en 1
  22.         GOTO    salir  
  23.  
  24. RX_Timer_Start                  ; Comienzo?
  25.         MOVLW   D'61'           ; Cargo el timer de nuevo, esto es por que el TMR0 no puede parar
  26.         MOVWF   TMR0           
  27.         BCF     INTCON,TMR0IF   ; Borro flag, sino entraria rapidamente a la interrupcion, ya que como no para esto estaria en 1
  28.         BSF     INTCON,TMR0IE   ; Habilito de nuevo las interrupciones del Timer0
  29.         GOTO    salir

Aunque esta explicado en los comentarios, basicamente compruebo los 3 valores, ( 's' - Start , 'p' - Stop , 'c' - Clear )
Si es Stop, lo que hago es simplemente desactivar las interrupciones del TMR0 y con eso detengo que se ejecute lo del timer, lo cual no incrementaria mas, no me importa la flag del timer, ni nada mas
Si es Clear, borro los valores guardados, pero sigue incrementando con el TMR0, Cargo el timer y borro el flag, asi de esa forma el TMR comienza de 0, sino cuando lo active podria pasar menos tiempo hasta que cuente 1.
Si es Start, tengo que resolver un problema antes de comenzar. como el TMR0 no para debo cargar el numero y borrar el flag, ya que si no borro el flag, quedaria en 1 de los anteriores overflows en el cual tuve desactivada las interrupciones del TMR0.

Otro error que tuviste... es este:

Código: ASM
  1. salir
  2.     MOVWF W_TEMP ;Copy W to TEMP register
  3.     SWAPF STATUS, W ;Swap status to be saved into W
  4.     CLRF STATUS ;bank 0, regardless of current bank, Clears IRP,RP1,RP0
  5.     MOVWF STATUS_TEMP ;Save status to bank zero STATUS_TEMP register
  6.     MOVF PCLATH, W ;Only required if using page 1
  7.     MOVWF PCLATH_TEMP ;Save PCLATH into W
  8.     CLRF PCLATH ;Page zero, regardless of current page

Observa donde recuperaste STATUS y todas las instrucciones que pusiste luego, instrucciones como MOVF y CLRF que actualizan la bandera Z, perdiendo el objetivo de lo que hiciste antes. Tambien otro error son las instrucciones de PCLATH, si observas estas sobreescribiendo lo que guardaste en la entrada.
Fijate en el datasheet que son distintos los codigos, de entrada y de salida de las interrupciones, se utilizan SWAPF por que no actualizan banderas del STATUS, observaras que PCLATH se pone al comienzo, etc. ( para encontrarlo rapido en el datasheet busca por STATUS_TEMP ), en el datasheet tenes bien el codigo, fijate.

Y ya con eso harias tu UART, solo quedaria la habilitacion de las interrupciones. Apenas recibas un dato si estan habilitadas entraria a la interrupcion. Y listo, terminado tu programa.
« Última modificación: 25 de Octubre de 2015, 07:28:59 por KILLERJC »

Desconectado BORIScristian

  • PIC10
  • *
  • Mensajes: 13
Re:Ayuda con comunicación serie en pic16f88
« Respuesta #6 en: 26 de Octubre de 2015, 14:15:56 »
Sigo con el mismo problema y ya active las interrupciones la baud rate y todos los registros necesarios y sigue sin ponerse a uno el PIR1,RCIF ; Podrá ser algun problema en la simulación?
Revise el datasheet y guardar y reponer W y STATUS, está igual a como lo puse en el programa; el programa quedo asi :

;=======================================================================

;====================================================================
; Main.asm file generated by New Project wizard
;
; Created:   mar mar 17 2015
; Processor: PIC16F88
; Compiler:  MPASM (MPLAB)
;====================================================================

;====================================================================
; DEFINITIONS
;====================================================================

#include p16f88.inc
             ; Include register definition file
__CONFIG _CONFIG1, _CP_OFF & _WDT_OFF & _BODEN_OFF & _PWRTE_OFF &  _MCLR_OFF& _LVP_OFF & _INTRC_IO


;====================================================================
; VARIABLES
;====================================================================
    cblock H'70'
   d1
   d2
    uni
    dec
    cent
    contint
    TEMP
    STATUS_TEMP
    W_TEMP
    PCLATH_TEMP
   endc


;====================================================================
; RESET and INTERRUPT VECTORS
;====================================================================

      ORG   0x00
      goto  Start

      ORG   0x04
      goto  interrupcion


;====================================================================
; CODE SEGMENT
;====================================================================

PGM   code


Start
;---------------------puertos--------------------------------------------------
      bsf       STATUS, RP0
      movlw    b'00000111'
      movwf    TRISA
     
      MOVLW     B'00100100'
     MOVWF     TRISB

      movlw     0x60
      movwf     OSCCON
      clrf      ANSEL
   
;---------------------timer----------------------------------------------------
      bsf       STATUS, RP0
      movlw     b'00000111'
      movwf     OPTION_REG
      BANKSEL   PORTA
      movlw     d'61'
      movwf     TMR0
;---------------------comunicacion serie----------------------------------------
      banksel   SPBRG
      MOVLW     D'25'       ;  9600 BAUD @ 20 MHZ FOSC +0.16 ERR
     MOVWF     SPBRG
     MOVLW     B'00100100'    ; BRGH = 1
      MOVWF     TXSTA      ; ENABLE ASYNC TRANSMISSION, SET BRGH
     BANKSEL   RCSTA       ; BANK0
     MOVLW     B'10010000'
     MOVWF     RCSTA      ; ENABLE ASYNC RECEPTION
      BANKSEL   PIE1
      BSF       PIE1,5
      BANKSEL   INTCON
      BSF       INTCON,7
      BSF       INTCON,6


     MOVF      RCREG,W
     MOVF      RCREG,W
     MOVF      RCREG,W     ; FLUSH RECEIVE BUFFER
;---------------------registros------------------------------------------------
      call      LCD_inicializa
      clrf      uni
      clrf      dec
      clrf      cent
      clrf      contint




;-----------------------PROGRAMAPRINCIPAL--------------------------------------

loop
    call    mostrar_dis
    btfsc   PORTA, 0
    call    reanudar
    btfsc   PORTA,1
    call    parar
    btfsc   PORTA,2
    CALL    resetear
    goto    loop
;-----------------------RUTINAS-----------------------------------------------
mostrar_dis
     
      movf  uni, w
      swapf uni,w
      movwf PORTA
      bcf   PORTB, 0
      bsf   PORTB,0
     
      movf  dec, w
      swapf dec,w
      movwf PORTA
      bcf   PORTB, 1
      BSF   PORTB,1


      movf  cent, w
      swapf cent,w
      movwf PORTA
      bcf   PORTB,3
      BSF   PORTB,3
      return
;------------------------------------------------------------------------------
mostrar_lcd
    call    borra_display
    movf    cent, w
    addlw   d'48'   ;pasaje decimal a ASCII , para que se muestre en LCD
    call    LCD_caracter
    movf    dec, w
    addlw   d'48'   ;pasaje decimal a ASCII , para que se muestre en LCD
    call    LCD_caracter
    movf    uni, w
    addlw   d'48'   ;pasaje decimal a ASCII , para que se muestre en LCD
    call    LCD_caracter
    call    Delay
    return
;------------------------------------------------------------------------------
resetear
    btfsc   PORTA,2
    GOTO    resetear
    clrf    uni
    clrf    dec
    clrf    cent
    BANKSEL TRISA
    clrf    INTCON
    BANKSEL PORTA
    return
;------------------------------------------------------------------------------
parar
    btfsc   PORTA,1
    goto    parar
    BANKSEL TRISA
    clrf    INTCON
    BANKSEL PORTA
    return
;------------------------------------------------------------------------------
reanudar
      btfsc   PORTA,0
      goto    reanudar
      BANKSEL TRISA
      movlw     b'10100000'
      movwf     INTCON
      BANKSEL PORTA
      return
;------------------------------------------------------------------------------
datos
    BANKSEL PIR1
    BTFSS   PIR1,RCIF
    RETURN
    bsf     PORTA,3
    MOVF    RCREG,W
    return

   
;------------------------------------------------------------------------------
decrementar
    btfsc   PORTA, 3
    goto    decrementar
    movlw   d'61'
    movwf   TMR0
    clrf    contint
    decf    uni
    movlw   d'255'
    subwf   uni, w
    btfsc   STATUS, Z
    call    decdec
    return
decdec
    movlw  d'9'
    movwf  uni
    decf   dec
    movlw   d'255'
    subwf   dec, w
    btfsc   STATUS, Z
    call    deccent
    return
deccent
    movlw d'9'
    movwf dec
    decf  cent
    movlw   d'255'
    subwf   cent, w
    btfsc   STATUS, Z
    call    cargarcent
    return
cargarcent
    movlw   d'9'
    movwf   cent
    return
;------------------------------------------------------------------------------
incrementar
    btfsc   PORTA, 2
    goto    incrementar
inc MOVLW   D'61'
    movwf   TMR0
    clrf    contint
    incf    uni
    movlw   d'10'
    subwf   uni, w
    btfsc   STATUS, Z
    call    incdec
    return
incdec
    clrf    uni
    incf    dec
    movlw   d'10'
    subwf   dec, w
    btfsc   STATUS, Z
    call    inccent
    return
inccent
    incf    cent
    clrf    dec
    movlw   d'10'
    subwf   cent, w
    btfsc   STATUS, Z
    clrf    cent
    return
;------------------------------------------------------------------------------

   

;-------------------------RETARDOS----------------------------------------------

Delay
    movlw   0x86
   movwf   d1
   movlw   0x14
   movwf   d2
Delay_0
   decfsz   d1, f
   goto   $+2
   decfsz   d2, f
   goto   Delay
    goto   $+1
   nop
    return


;-------------------------INTERRUPCIONES---------------------------------------

;interrupcion para 1 microsegundo(TMR0 EN 256 EN CONFIG)-----------------------
;call    incint
;movlw   d'256'
;movwf   TMR0
;bcf     INTCON,2
;RETFIE



;INTERRUPCION PARA 1 SEGUNDO(CAMBIANDO EL TMR0 A 61 EN CONFIG)------------------
interrupcion
    MOVWF   W_TEMP ;Copy W to TEMP register
    SWAPF   STATUS, W ;Swap status to be saved into W
    CLRF    STATUS ;bank 0, regardless of current bank, Clears IRP,RP1,RP0
    MOVWF   STATUS_TEMP ;Save status to bank zero STATUS_TEMP register
    MOVF    PCLATH, W ;Only required if using page 1
    MOVWF   PCLATH_TEMP ;Save PCLATH into W
    CLRF    PCLATH ;Page zero, regardless of current page

    BTFSC   PIR1,RCIF
    GOTO    Int_Rcreg
    BTFSC   INTCON,2
    GOTO    Int_Tmr
   

Int_Rcreg
        BSF     PORTA,3
        MOVF    RCREG,W ;Esto ya me borra el flag de la UART
        MOVWF   TEMP            ;Registro temporal para mantener el dato
        MOVLW   's'
        SUBWF   TEMP,W          ; 's' - TEMP = W, si TEMP era 's' Z = 1 , start
        BTFSC   STATUS,Z
        GOTO    RX_Timer_Start
        MOVLW   'p'             ; 'p' STOP
        SUBWF   TEMP,W
        BTFSC   STATUS,Z
        BCF     INTCON,TMR0IE   ; Deshabilito las interrupciones del timer
        MOVLW   'r'             ; 'c' Clear - Borra todo
        SUBWF   TEMP,W
        BTFSS   STATUS,Z
        GOTO    salir
        CLRF    uni             ; Solo resetea, no para el timer para nada. si quisiera parar el timer usaria
        CLRF    dec             ; otro BCF INTCON,TMR0IE
        CLRF    cent
        MOVLW   D'61'           ; Cargo el timer de nuevo, esto es por que el TMR0 no puede parar
        MOVWF   TMR0
        BCF     INTCON,TMR0IF   ; Borro flag, sino entraria rapidamente a la interrupcion, ya que como no para esto estaria en 1
        GOTO    salir2

RX_Timer_Start                  ; Comienzo?
        MOVLW   D'61'           ; Cargo el timer de nuevo, esto es por que el TMR0 no puede parar
        MOVWF   TMR0
        BCF     INTCON,TMR0IF   ; Borro flag, sino entraria rapidamente a la interrupcion, ya que como no para esto estaria en 1
        BSF     INTCON,TMR0IE   ; Habilito de nuevo las interrupciones del Timer0
        GOTO    salir2


Int_Tmr
    incf    contint
    movlw   d'20'
    subwf   contint, w
    btfss   STATUS, Z
    goto     salir
    MOVLW   D'61'
    movwf   TMR0
    clrf    contint
    incf    uni
    movlw   d'10'
    subwf   uni, w
    btfss   STATUS, Z
    goto    salir
    clrf    uni
    incf    dec
    movlw   d'10'
    subwf   dec, w
    btfss   STATUS, Z
    goto    salir
    incf    cent
    clrf    dec
    movlw   d'10'
    subwf   cent, w
    btfsc   STATUS, Z
    clrf    cent
    banksel TRISA
    BCF     INTCON,2
    BANKSEL PORTA
    goto    salir
salir
    BCF   INTCON,2
    MOVWF W_TEMP ;Copy W to TEMP register
    SWAPF STATUS, W ;Swap status to be saved into W
    CLRF STATUS ;bank 0, regardless of current bank, Clears IRP,RP1,RP0
    MOVWF STATUS_TEMP ;Save status to bank zero STATUS_TEMP register
    MOVF PCLATH, W ;Only required if using page 1
    MOVWF PCLATH_TEMP ;Save PCLATH into W
    CLRF PCLATH ;Page zero, regardless of current page
    RETFIE

salir2
    MOVWF W_TEMP ;Copy W to TEMP register
    SWAPF STATUS, W ;Swap status to be saved into W
    CLRF STATUS ;bank 0, regardless of current bank, Clears IRP,RP1,RP0
    MOVWF STATUS_TEMP ;Save status to bank zero STATUS_TEMP register
    MOVF PCLATH, W ;Only required if using page 1
    MOVWF PCLATH_TEMP ;Save PCLATH into W
    CLRF PCLATH ;Page zero, regardless of current page
    RETFIE


#INCLUDE <LCD8BITS.INC>
;====================================================================
      END

Desconectado KILLERJC

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 8242
Re:Ayuda con comunicación serie en pic16f88
« Respuesta #7 en: 31 de Octubre de 2015, 08:09:49 »
Perdona que no conteste, se me habia puesto en la cabeza que lo habia hecho.
Voy a nombrar las cosas mal:

- Este es el codigo correcto para la salida de la interrupcion, lo tuyo esta mal, el datasheet que tengo tiene este codigo de salida:

Código: ASM
  1. salir
  2.         MOVF    PCLATH_TEMP, W
  3.         MOVWF   PCLATH
  4.         SWAPF   STATUS_TEMP, W
  5.         MOVWF   STATUS
  6.         SWAPF   W_TEMP, F
  7.         SWAPF   W_TEMP, W
  8.         RETFIE

- Deberias flushear ANTES de activar las interrupciones

Código: ASM
  1. ;---------------------comunicacion serie----------------------------------------
  2.       banksel   SPBRG
  3.       MOVLW     D'25'       ;  9600 BAUD @ 20 MHZ FOSC +0.16 ERR
  4.      MOVWF     SPBRG
  5.      MOVLW     B'00100100'    ; BRGH = 1
  6.       MOVWF     TXSTA      ; ENABLE ASYNC TRANSMISSION, SET BRGH
  7.      BANKSEL   RCSTA       ; BANK0
  8.      MOVLW     B'10010000'
  9.      MOVWF     RCSTA      ; ENABLE ASYNC RECEPTION
  10.  
  11.      MOVF      RCREG,; FLUSH RECEIVE BUFFER
  12.  
  13.       BANKSEL   PIE1
  14.       BSF       PIE1,RCIE
  15.       BANKSEL   INTCON
  16.       BSF       INTCON,GIE
  17.       BSF       INTCON,PEIE

- Recien me doy cuenta de esto en Mostrar_Display:

Código: ASM
  1. movf  uni, w
  2.       swapf uni,w

   Para eso directamente poner el SWAPF y quita el MOVF, ya que estarias sobreescribiendo W,

- Seguis cargando mal el timer:

Código: ASM
  1. Int_Tmr
  2.     incf    contint
  3.     movlw   d'20'
  4.     subwf   contint, w
  5.     btfss   STATUS, Z
  6.     goto     salir
  7.     MOVLW   D'61'
  8.     movwf   TMR0

En el caso que no sea 20, tenes que :
   No se borro el flag del timer
   No se cargo con '61'

Solucion simple (tambien te solucionaria los demas "goto salir" que tenes y no limpiaste flag):

Código: ASM
  1. Int_Tmr
  2.     MOVLW   D'61'
  3.     movwf   TMR0
  4.     BCF     INTCON,TMR0IF
  5.     incf    contint
  6.     movlw   d'20'
  7.     subwf   contint, w
  8.     btfss   STATUS, Z
  9.     goto     salir
  10.     ;Aca el resto de la interrupcion


- Por que usar banksel?

Código: ASM
  1. banksel TRISA
  2.     BCF     INTCON,2
  3.     BANKSEL PORTA

Si INTCON es accesible de todos los bancos


Y... la configuracion de la UART esta bien. Lo unico que noto mal es eso..