Código Ensamblador PIC16F84: Comunicación Serie UART, Control de Paridad y Antirrebote con Interrupciones

Electrónica9,75 KB

Programación en ensamblador del PIC16F84: interrupciones, comunicación serie y control de paridad

A continuación se presenta el código en ensamblador de un microcontrolador PIC16F84 que combina interrupciones, comunicación serie asíncrona (USART), control de paridad y eliminación de rebotes en pulsadores.

Definición de variables

Las variables se asignan a posiciones de la memoria RAM mediante la directiva EQU. Algunas variables, como DATO3RX a DATO11RX o R1, O1 y N1, no tienen dirección explícita, por lo que deberían revisarse.

N         EQU 0X20
CONTROL   EQU 0X21
;BIT 7 ESTÁ A 0: PARIDAD PAR. A 1: PARIDAD IMPAR
;BIT 6 SE PONE A 1 CUANDO SE RECIBE UNA 'w' Y ESTÁ DENTRO DEL RANGO

DATO      EQU 0X22
UNOS      EQU 0X23

ACTUAL    EQU 0X24
PREVIO    EQU 0X25
XOR       EQU 0X26

DATO1RX   EQU 0X27
DATO2RX   EQU 0X28
DATO3RX   EQU
DATO4RX   EQU
DATO5RX   EQU
DATO6RX   EQU
DATO7RX   EQU
DATO8RX   EQU
DATO9RX   EQU
DATO10RX  EQU
DATO11RX  EQU
DATO12RX  EQU 0X32

E1        EQU 0X33
R1
R2        EQU 0X35

D1        EQU 0X36
O1
N1
E2        EQU 0X39

PUNTERORX EQU 0X3A
CONTADOR  EQU 0X3B
NUMDATOSTX EQU 0X3C

N_AUX     EQU 0X3D

Vector de reset e interrupciones

        ORG 0
        GOTO INICIO
        ORG 4
        GOTO ISR
        ORG 5

Configuración inicial (INICIO)

Configuración de puertos

Se seleccionan las páginas de memoria mediante RP0 y se configuran los puertos como entradas o salidas usando el registro TRIS:

INICIO
        BSF STATUS,RP0

        BSF TRISA,0
        BSF TRISA,1
        BSF TRISA,2
        BSF TRISA,3
        BSF TRISA,4
        BSF TRISA,5

        MOVLW 0X06
        MOVWF ADCON1

        BCF TRISB,1       ; RB1 como salida

        BSF TRISB,0
        BSF TRISB,7
        BSF TRISB,6

        BSF TRISC,7       ; RX como entrada
        BCF TRISC,6       ; TX como salida

Habilitación de interrupciones

        BSF INTCON,GIE
        BSF INTCON,PEIE
        BSF INTCON,T0IE
        BSF INTCON,RBIE
        BSF INTCON,INTE
        BCF PIE1,TXIE
        BSF PIE1,RCIE

Configuración del TMR0 y del preescalador

        BCF OPTION_REG,T0CS
        BSF OPTION_REG,PSA
        BCF OPTION_REG,PS2
        BCF OPTION_REG,PS1
        BCF OPTION_REG,PS0

        BCF OPTION_REG,INTEDG

Configuración de la USART

Se establece la velocidad de transmisión mediante el registro SPBRG y el bit BRGH (alta velocidad):

        BSF TXSTA,BRGH
        BCF TXSTA,SYNC
        BSF TXSTA,TXEN

        MOVLW .12
        MOVWF SPBRG

        BCF STATUS,RP0

        BSF RCSTA,SPEN
        BSF RCSTA,CREN

Inicialización de variables

        MOVLW .106
        MOVWF TMR0

        MOVLW .100
        MOVWF N
        MOVWF N_AUX

        MOVLW 0X28
        MOVWF PUNTERORX

MAIN
        GOTO MAIN

Rutina de servicio de interrupción (ISR)

La ISR identifica la fuente de la interrupción mediante la consulta de los flags correspondientes y salta a la rutina adecuada:

ISR
        BTFSC INTCON,T0IF
        GOTO TEMPORIZADOR
        BTFSC INTCON,RBIF
        GOTO BOTONX
        BTFSC INTCON,INTF
        GOTO BOTON0
        BTFSC PIR1,RCIF
        GOTO RECEPCION
        BTFSC PIR1,TXIF
        GOTO TRANSMISION
        RETFIE

Transmisión serie (TRANSMISION)

Envía sucesivamente los bytes almacenados a partir de la dirección apuntada por FSR:

TRANSMISION
        INCF FSR,1
        MOVFW INDF
        MOVWF TXREG

        DECFSZ NUMDATOSTX,1
        RETFIE

        BSF STATUS,RP0
        BCF PIR1,TXIE
        BCF STATUS,RP0

        MOVFW PUNTERORX
        MOVWF FSR
        RETFIE

Pulsador en RB0 (BOTON0): cambio de paridad

Cada pulsación alterna el modo de paridad activo, almacenado en el bit 7 de la variable CONTROL:

BOTON0
        BCF INTCON,INTF

        BTFSC CONTROL,7
        GOTO CAMBIAMOS_A_PAR
        GOTO CAMBIAMOS_A_IMPAR

CAMBIAMOS_A_IMPAR
        BSF CONTROL,7
        RETFIE

CAMBIAMOS_A_PAR
        BCF CONTROL,7
        RETFIE

Pulsadores en RB6 y RB7 (BOTONX): ajuste del valor N

Al detectarse un cambio en PORTB, se compara el estado actual con el anterior para determinar qué pulsador ha cambiado. Se implementa un antirrebote sencillo mediante la verificación del estado del pin tras el cambio.

BOTONX
        MOVFW PORTB
        MOVWF ACTUAL
        XORWF PREVIO,0
        MOVWF XOR

        BTFSC XOR,7
        GOTO BOTON7
        BTFSC XOR,6
        GOTO BOTON6
        RETFIE

BOTON6
        MOVFW ACTUAL
        MOVWF PREVIO
        BCF INTCON,RBIF

        BTFSS PORTB,6
        RETFIE

        MOVFW N
        XORLW .1
        BTFSS STATUS,Z
        DECF N,1

        MOVFW N
        MOVWF N_AUX
        RETFIE

BOTON7
        MOVFW ACTUAL
        MOVWF PREVIO
        BCF INTCON,RBIF

        BTFSS PORTB,7
        RETFIE

        MOVFW N
        XORLW .255
        BTFSS STATUS,Z
        INCF N,1

        MOVFW N
        MOVWF N_AUX
        RETFIE

Temporizador (TEMPORIZADOR)

Cada desbordamiento del TMR0 genera una interrupción. Cuando el contador N_AUX llega a cero, se realiza la lectura del puerto PORTA y el cálculo de la paridad:

TEMPORIZADOR
        BCF INTCON,T0IF
        MOVLW .106
        MOVWF TMR0

        DECFSZ N_AUX,1
        RETFIE

        ; YA HE CONTADO N x 150 US
        MOVFW N
        MOVWF N_AUX

        MOVFW PORTA
        ANDLW B'00111111'
        MOVWF DATO

        MOVLW .6
        MOVWF CONTADOR
        CLRF UNOS

BUCLE
        BTFSS DATO,0
        GOTO TENGO_UN_CERO
        GOTO TENGO_UN_UNO

TENGO_UN_CERO
        RRF DATO,1
        DECFSZ CONTADOR,1
        GOTO BUCLE
        GOTO SEGUIMOS

TENGO_UN_UNO
        RRF DATO,1
        INCF UNOS,1
        DECFSZ CONTADOR,1
        GOTO BUCLE
        GOTO SEGUIMOS

Evaluación de la paridad

Tras contar los unos en los 6 bits, se determina si el número es par o impar y se compara con el modo configurado en CONTROL,7. El resultado se refleja en RB1:

SEGUIMOS
        BTFSS UNOS,0
        GOTO TENEMOS_PARIDAD_PAR
        GOTO TENEMOS_PARIDAD_IMPAR

TENEMOS_PARIDAD_PAR
        BTFSC CONTROL,7
        GOTO ME_PIDEN_IMPAR
        GOTO ME_PIDEN_PAR

ME_PIDEN_IMPAR
        BSF PORTB,RB1
        RETFIE

ME_PIDEN_PAR
        BCF PORTB,RB1
        RETFIE

TENEMOS_PARIDAD_IMPAR
        BTFSS CONTROL,7
        GOTO ME_PIDEN_IMPAR
        GOTO ME_PIDEN_PAR

Recepción serie (RECEPCION)

La recepción utiliza la variable CONTADOR para distinguir entre el primer y el segundo byte recibido. Cuando se recibe la letra 'w' seguida de un valor dentro del rango 0x50 - 0x70, se activa el bit 6 de CONTROL y se inicia la recepción de los bytes restantes:

RECEPCION
        ; CONTADOR
        ; 00 -> RX DATO 1
        ; 01 -> RX DATO 2

        ; BIT 6 SE PONE A 1 CUANDO SE RECIBE UNA 'w' Y ESTÁ DENTRO DEL RANGO
        BTFSC CONTROL,6
        GOTO SEGUIMOS_RECIBIENDO

        MOVFW CONTADOR
        BTFSC STATUS,Z
        GOTO RX_DATO1
        GOTO RX_DATO2

RX_DATO1
        INCF CONTADOR,1
        MOVFW RCREG
        MOVWF DATO1RX
        RETFIE

RX_DATO2
        CLRF CONTADOR
        MOVFW RCREG
        MOVWF DATO2RX

        ; YA EMPIEZO A COMPROBAR
        MOVFW DATO1RX
        XORLW 'w'
        BTFSS STATUS,Z
        GOTO TX_ERR

        MOVFW DATO2RX
        SUBLW 0X50
        BTFSC STATUS,C
        GOTO TX_ERR

        MOVFW DATO2RX
        SUBLW 0X70
        BTFSS STATUS,C
        GOTO TX_ERR

        BSF CONTROL,6
        RETFIE

SEGUIMOS_RECIBIENDO
        INCF FSR,1
        MOVFW RCREG
        MOVWF INDF

        MOVFW FSR
        XORLW 0X32
        BTFSS STATUS,Z
        RETFIE
        GOTO TX_DONE

        BCF CONTROL,6
        RETFIE

Gestión de respuestas (TX_ERR y TX_DONE)

Según el resultado de la verificación, se prepara el envío de una respuesta de error (3 bytes) o de confirmación (4 bytes) activando la interrupción de transmisión:

TX_ERR
        MOVLW 0X32
        MOVWF FSR

        MOVLW .3
        MOVWF NUMDATOSTX

        BSF STATUS,RP0
        BSF PIE1,TXIE
        BCF STATUS,RP0
        RETFIE

TX_DONE
        MOVLW 0X35
        MOVWF FSR

        MOVLW .4
        MOVWF NUMDATOSTX

        BSF STATUS,RP0
        BSF PIE1,TXIE
        BCF STATUS,RP0
        RETFIE

END

Observaciones sobre el código

  • Las variables DATO3RX a DATO11RX, así como R1, O1 y N1, carecen de dirección asignada y deben completarse antes de compilar.
  • Las etiquetas TRANSMISION y RECEPCION utilizan el registro FSR como puntero indirecto sobre INDF, lo que requiere que el área de datos esté correctamente inicializada.
  • La instrucción ANDLW B'00111111',0 de la versión original contenía un argumento sobrante que se ha eliminado, ya que ANDLW solo admite un operando.

Descargar

PDF Word HTML