UART en PIC16F1829 - La interrupción RCIF para el pin RX no funciona, no puede recibir nada incluso con el sondeo

0

El código está escrito en MPLABX v4.00 con el compilador XC8.

Soy nuevo en escribir firmware para PIC de 8 bits y podría necesitar ayuda con mi código. Estoy usando un PIC16F1829 para un módulo LED que recibe comandos de RX. Solo estoy tratando de obtener la configuración básica como encender los LED cuando se recibe un cierto valor en el pin RX, pero ni siquiera puedo obtener eso.

Me gustaría que la UART funcione a través de interrupciones, pero ni siquiera funciona con el sondeo en el ciclo principal. Mi vector de interrupción se comenta en el siguiente código.

RX pin: RC5

Pin TX: RB7

Pin para encender y apagar los LED: RA5

El pin RA5 funciona bien para encender y apagar los LED. El pin TX está funcionando, aunque no he confirmado si la interrupción TXIF tampoco está funcionando como si RCIF no estuviera funcionando.

He intentado leer RCIF y PIR1bits.RCIF. Ambos compilados. Ninguno de los dos trabajó. He intentado esto en dos PIC diferentes en 2 módulos LED diferentes. Se encienden, pero la lectura del pin RX tampoco funcionó.

La variable RXIN se define inicialmente como 3 y, por lo tanto, debido al bucle RXIN-- dentro del bucle principal, las luces parpadean 3 veces al inicio, así que sé que está ingresando al bucle principal. Pero por lo que puedo decir, la interrupción de RCIF no se dispara cuando se recibe en el pin RX.

He confirmado en el osciloscopio que la señal en RX y fuera de los pines de TX que usan el mismo baudios, así que creo que la velocidad de transmisión está configurada correctamente (300 baudios, 8N1). También confirmé en el osciloscopio que el pin RX recibe una señal fuerte y limpia de 5 V señal. Hasta el momento no se ha realizado el sondeo de RCIF ni el uso de un enrutamiento de interrupciones. Si alguien puede ver los problemas con mi código que no estoy viendo, su ayuda sería muy apreciada.

Mi código:

#include <stdio.h>
#include <stdlib.h>
#include <xc.h>

// This is for 300 baud rate
#define _BAUD_PRESCALER_LOW_ 0x2A
#define _BAUD_PRESCALER_HIGH_ 0x68
#define _XTAL_FREQ 32000000

#pragma config FOSC = INTOSC    // Oscillator Selection->INTOSC oscillator: I/O function on CLKIN pin
#pragma config WDTE = OFF    // Watchdog Timer Enable->WDT enabled
#pragma config PWRTE = OFF    // Power-up Timer Enable->PWRT disabled
#pragma config MCLRE = OFF    // MCLR Pin Function Select->MCLR/VPP pin function is digital input
#pragma config CP = OFF    // Flash Program Memory Code Protection->Program memory code protection is disabled
#pragma config CPD = OFF    // Data Memory Code Protection->Data memory code protection is disabled
#pragma config BOREN = ON    // Brown-out Reset Enable->Brown-out Reset enabled
#pragma config CLKOUTEN = OFF    // Clock Out Enable->CLKOUT function is disabled. I/O or oscillator function on the CLKOUT pin
#pragma config IESO = OFF    // Internal/External Switchover->Internal/External Switchover mode is disabled
#pragma config FCMEN = OFF    // Fail-Safe Clock Monitor Enable->Fail-Safe Clock Monitor is disabled

// CONFIG2
#pragma config WRT = OFF    // Flash Memory Self-Write Protection->Write protection off
#pragma config PLLEN = ON    // PLL Enable->4x PLL enabled
#pragma config STVREN = ON    // Stack Overflow/Underflow Reset Enable->Stack Overflow or Underflow will cause a Reset
#pragma config BORV = LO    // Brown-out Reset Voltage Selection->Brown-out Reset Voltage (Vbor), low trip point selected.
#pragma config LVP = OFF

int flagRXFramingError = 0;
int flagRXOverrunError = 0;
volatile unsigned char RXIN = 3;

unsigned char UARTRead(){
    return RCREG;
}

void writeRXIN(unsigned char a){
    RXIN = a;
}

void TX(unsigned char a){
    while(!TXIF){}
    TXREG = a;
}

int main(int argc, char** argv) {

    // SCS FOSC; SPLLEN disabled; IRCF 8MHz_HF; 
    OSCCON = 0xF0;
    // TUN 0; 
    OSCTUNE = 0x00;
    // Set the secondary oscillator
    // Wait for PLL to stabilize
    while(PLLR == 0)
    {
    }

    // WDTPS 1:65536; SWDTEN OFF; 
    WDTCON = 0x16;
    __delay_ms(5);

    GIE = 1; // Global interrupts enabled
    __delay_ms(5);
    PEIE = 1; // Active peripheral interrupts enabled
    __delay_ms(5);
    RCIE = 1; // Enable USART Receive interrupt
    __delay_ms(5);
    TXIE = 1; // Enable USART Transmitter interrupt
    __delay_ms(5);
    ADIE = 1; // Enable ADC interrupts
    __delay_ms(5);
    RXDTSEL = 0; // RX is on RC5 pin
    __delay_ms(5);
    TXCKSEL = 0; // TX is on RB7 pin
    __delay_ms(5);

    TRISC5 = 1; // RX pin set as input 
    __delay_ms(5);

    SPEN = 1; // Serial Port Enabled
    __delay_ms(5);
    SYNC = 0; // Asynchronous mode
    __delay_ms(5);
    RX9 = 0; // 8 bit reception
    __delay_ms(5);
    TX9 = 0; // 8-bit transmission
    __delay_ms(5);
    CREN = 1; // Receiver enabled
    __delay_ms(5);
    TXEN = 1; // Transmitter enabled 
   __delay_ms(5);
    BRG16 = 1; // 16-bit baud generation
    __delay_ms(5);
    BRGH = 1; // High baud rate enabled
    __delay_ms(5);
    ABDEN = 0; // Auto baud detect disabled
    __delay_ms(5);

    // Baud prescaler n = [Fosc/(D*BR)] - 1

    SPBRGH = _BAUD_PRESCALER_HIGH_;
    __delay_ms(5);
    SPBRGL = _BAUD_PRESCALER_LOW_;
    __delay_ms(5);

    TRISC6 = 0; // IadjPWM pin configured as output
    __delay_ms(5);
    ANSC6 = 0; // IadjPWM pin not analog input
    __delay_ms(5);
    TRISA5 = 0; // DimPWM pin configured as output
    __delay_ms(5);

    LATC6 = 1; // Max current for now until PWM written
    __delay_ms(5);

    while(1){

    // Inline assembly code to clear watchdog timer
    //asm("CLRWDT");

    /*if(RXIN == 5){
        RA5 = 1;
    }
    else{
        RA5 = 0;
    }*/

        if(PIR1bits.RCIF){
            writeRXIN(UARTRead());
            //RA5 = 0;
            TX(RXIN);
        } // end if RCIF

        while(RXIN > 0){
            RA5 = 1;
            __delay_ms(100);
            RA5 = 0;
            __delay_ms(100);
            RXIN--;
        }

    } 
    // infinite loop
    // never leave this loop

    RA5 = 1;
    return (EXIT_SUCCESS);
} // end main

/*void interrupt ISR(void){
    if(RCIF){// if USART Receive interrupt flag
        RA5 = 1;

        if(FERR){
            flagRXFramingError = 1;
            SPEN = 0;
            SPEN = 1;

        }
        if(OERR){
            flagRXOverrunError = 1;
            CREN = 0;
            CREN = 1;
        }

        while(RCIF){ // RCIF high as long as there is data in FIFO register. Read RCREG to clear RCIF flag
            writeRXIN(UARTRead());
        }

        RA5 = 0;
    }

    if (TXIF){// if USART Transmit interrupt
        TXIF = 0; // Clear interrupt flag
    }
} // end ISRs*/
    
pregunta humanistscience

1 respuesta

-1

RESUELVE EL PROBLEMA

No estoy seguro de qué resolvió exactamente el problema, pero compartiré los cambios principales que hice y el nuevo código.

  1. He habilitado TXIE. TXIF es casi siempre alta, por lo que genera interrupciones continuas. No veo una razón para habilitar las interrupciones de TX, aunque puede haber una buena. Si desea TX, espere hasta que TXIF no sea cero y transmita, de lo contrario, ¿por qué usar la bandera?

  2. Tuve las interrupciones habilitadas en el orden incorrecto. Debería haber habilitado los periféricos, luego sus interrupciones individuales si fuera necesario, luego PEIE y finalmente GIE.

  3. No estaba manejando FERR y OERR en mi interrupción, aunque pueden estar disparando y causando interrupciones.

También tenía RXDTSEL configurado incorrectamente en mi código original. Aquí está el nuevo código de trabajo. En este momento, todo lo que hace es repetir la señal de RX y hacer parpadear los LED la cantidad de veces que se transmite.

#include <stdio.h>
#include <stdlib.h>
#include <xc.h>

// This is for 300 baud rate
#define _BAUD_PRESCALER_LOW_ 0x2A
#define _BAUD_PRESCALER_HIGH_ 0x68
#define _XTAL_FREQ 32000000
#define _PIN_DIMPWMPIN_ RA5

#pragma config FOSC = INTOSC    // Oscillator Selection->INTOSC oscillator: I/O function on CLKIN pin
#pragma config WDTE = OFF    // Watchdog Timer Enable->WDT enabled
#pragma config PWRTE = OFF    // Power-up Timer Enable->PWRT disabled
#pragma config MCLRE = OFF    // MCLR Pin Function Select->MCLR/VPP pin function is digital input
#pragma config CP = OFF    // Flash Program Memory Code Protection->Program memory code protection is disabled
#pragma config CPD = OFF    // Data Memory Code Protection->Data memory code protection is disabled
#pragma config BOREN = ON    // Brown-out Reset Enable->Brown-out Reset enabled
#pragma config CLKOUTEN = OFF    // Clock Out Enable->CLKOUT function is disabled. I/O or oscillator function on the CLKOUT pin
#pragma config IESO = OFF    // Internal/External Switchover->Internal/External Switchover mode is disabled
#pragma config FCMEN = OFF    // Fail-Safe Clock Monitor Enable->Fail-Safe Clock Monitor is disabled

// CONFIG2
#pragma config WRT = OFF    // Flash Memory Self-Write Protection->Write protection off
#pragma config PLLEN = ON    // PLL Enable->4x PLL enabled
#pragma config STVREN = ON    // Stack Overflow/Underflow Reset Enable->Stack Overflow or Underflow will cause a Reset
#pragma config BORV = LO    // Brown-out Reset Voltage Selection->Brown-out Reset Voltage (Vbor), low trip point selected.
#pragma config LVP = OFF

int flagRXFramingError = 0;
int flagRXOverrunError = 0;
volatile unsigned char RXIN = 3;

unsigned char RX(){
    return RCREG;
}

void writeRXIN(volatile unsigned char a){
    RXIN = a;
}

void TX(unsigned char a){
    while(!PIR1bits.TXIF); // TXIF is usually 1, only 0 when busy transmitting
    TXREG = a;
}

int main(int argc, char** argv) {

    // SCS FOSC; SPLLEN disabled; IRCF 8MHz_HF; 
    OSCCON = 0xF0;
    // TUN 0; 
    OSCTUNE = 0x00;
    // Set the secondary oscillator
    // Wait for PLL to stabilize
    while(OSCSTATbits.PLLR == 0){}

    ADCON0bits.ADON = 0;
    ANSELA = 0x00;
    ANSELB = 0x00;
    ANSELC = 0x00;
    PIE1bits.ADIE = 0; // Disable ADC interrupts

    TRISCbits.TRISC5 = 1; // RX pin set to input
    TRISCbits.TRISC6 = 0; // IadjPWM pin configured as output
    TRISAbits.TRISA5 = 0; // DimPWM pin configured as output

    LATCbits.LATC6 = 1; // Max current for now until PWM written

    //UART Init
    BAUDCONbits.BRG16 = 1; // 16-bit baud generation
    TXSTAbits.BRGH = 1; // High baud rate enabled
    BAUDCONbits.ABDEN = 0; // Auto baud detect disabled

    // Baud prescaler n = [Fosc/(D*BR)] - 1
    SPBRGH = _BAUD_PRESCALER_HIGH_;
    __delay_ms(1);
    SPBRGL = _BAUD_PRESCALER_LOW_;
    __delay_ms(1);

    APFCON0bits.RXDTSEL = 1; // RX is on RC5 pin
    APFCON0bits.TXCKSEL = 0; // TX is on RB7 pin
    TXSTAbits.SYNC = 0; // Asynchronous mode
    RCSTAbits.SPEN = 1; // Serial Port Enabled
    RCSTAbits.RX9 = 0; // 8 bit reception
    TXSTAbits.TX9 = 0; // 8-bit transmission

    RCSTAbits.CREN = 1; // Receiver enabled
    TXSTAbits.TXEN = 1; // Transmitter enabled 

    PIE1bits.TXIE = 0; // Enable USART Transmitter interrupt
    PIE1bits.RCIE = 1; // Enable USART Receive interrupt
    while(PIR1bits.RCIF){
        writeRXIN(RX());
    }

    INTCONbits.PEIE = 1; // Enable peripheral interrupts
    INTCONbits.GIE = 1; // Enable global interrupts

    while(1){
        while(RXIN > 0){
            TX(RXIN);
            _PIN_DIMPWMPIN_ = 1;
            __delay_ms(100);
            _PIN_DIMPWMPIN_ = 0;
            __delay_ms(100);
            RXIN--;
        }

    } 
    // infinite loop
    // never leave this loop
    return (EXIT_SUCCESS);
} // end main

void interrupt ISR(void){

    if(PIE1bits.RCIE && PIR1bits.RCIF){ // handle RX pin interrupts
        while(PIR1bits.RCIF){
            writeRXIN(RX());
        }
        if(RCSTAbits.FERR){
            flagRXFramingError = 1;
            SPEN = 0;
            SPEN = 1;

        }
        if(RCSTAbits.OERR){
            flagRXOverrunError = 1;
            CREN = 0;
            CREN = 1;
        }
    } // end RX pin interrupt handlers

} // end ISRs*/
    
respondido por el humanistscience

Lea otras preguntas en las etiquetas