简体   繁体   中英

PIC16F1829 UART RX Interrupt not working using MPLABX and XC8 compiler

I am new to writing firmware for 8-bit PICs and could use some help with my code. I am using a PIC16F1829 for an LED module which gets RX commands. I am just trying to get the basics setup like turn on LEDs when a certain value is received on RX pin, but can't even get that.

Would like to get UART working via interrupts but can't even get it working with polling in main loop. My interrupt vector is commented out in the code below.

RX pin: RC5

TX pin: RB7

Pin to toggle LEDs on and off: RA5

Pin RA5 works fine to toggle LEDs on and off. TX pin is working, though I have not confirmed if interrupt TXIF is also not working like RCIF is not working.

I have tried reading RCIF and PIR1bits.RCIF. Both of them compiled. Neither one worked. I have tried this on two different PICs on 2 different LED modules. They turn on, but reading RX pin didn't work on either.

Variable RXIN is initially defined as 3 and thus due to the RXIN-- loop within the main loop the lights flash 3 times at startup so I know it is entering the main loop. But as far as I can tell the RCIF interrupt is not firing upon reception at RX pin.

I have confirmed on oscilloscope that the signal into RX and out of TX pins using same baud, so I think baud rate is configured correctly (300 baud, 8N1.) I have also confirmed on oscilloscope RX pin receiving strong and clean 5V signal. Neither polling RCIF or using an interrupt service routing has worked thus far. If anyone can see the issues with my code that I am not seeing, your help would be greatly appreciated.

My code:

#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*/

Some microcontrollers stop receiving bytes if there was some kind of error. Be sure to clear those errors. Usually by clearing some UART control register bits.

SOLVED THE PROBLEM

I am not sure what exactly solved the problem but I will share the major changes I made and the new code.

  1. I had TXIE enabled. TXIF is almost always high, so it generates continuous interrupts. I don't see a reason to enable TX interrupts, though there may be a good one. If you want to TX wait until TXIF is not zero and transmit, otherwise why use the flag?

  2. I had the interrupts enabling in the wrong order. I should have enabled the peripherals, then their individual interrupts if necessary, then PEIE, and finally GIE.

  3. I wasn't handling FERR and OERR in my interrupt, though they may be firing and causing interrupts.

Also I had RXDTSEL set wrong in my original code. Here is the new, working code. Right now all it does is echo the RX signal and blink the LEDs the number of times that is transmitted.

#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*/

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM