cpicuart

PIC16F887 receiving wrong UART Data


I'm making a cleaning robot in C (XC8) and I've got some problems with UART. Let me explain:

The project got an UART communication between a PIC16F887 and a HC06. Before, the project has a PIC16F1455 and worked great. But I needed more and changed the micro. With an App based on Android (which I never change and I know it works fine) I send a char via Bluetooth to the HC06. Through UART, the HC06 send the char to the pic, and I change a variable named "Pressed" according to the data.

So... I configured everything, changed the registers for the new pic, put a LED to know if I'm receiving something in every receive interruption (which I do) but the variable never change (I guess I'm receiving trash data), and I'm using a simple "Data == Data" function to change the variable. My guess: the problem is the BAUD RATE. HC06 needs 9600, and somehow mine is different.

BAUD RATE needs the pic frequency and some register changes, right?

I need to find why my BAUD RATE isn't 9600, can you help me?

Here go some of my code, starting with the configuration bits. I'm going to use an internal oscillator and 8MHz:

 PIC16F887 Configuration Bit Settings

// CONFIG1
#pragma config FOSC = INTRC_NOCLKOUT // Oscillator Selection bits (INTOSCIO oscillator: I/O function on RA6/OSC2/CLKOUT pin, I/O function on RA7/OSC1/CLKIN)
#pragma config WDTE = OFF       // Watchdog Timer Enable bit (WDT disabled and can be enabled by SWDTEN bit of the WDTCON register)
#pragma config PWRTE = OFF      // Power-up Timer Enable bit (PWRT disabled)
#pragma config MCLRE = OFF      // RE3/MCLR pin function select bit (RE3/MCLR pin function is digital input, MCLR internally tied to VDD)
#pragma config CP = OFF         // Code Protection bit (Program memory code protection is disabled)
#pragma config CPD = OFF        // Data Code Protection bit (Data memory code protection is disabled)
#pragma config BOREN = OFF      // Brown Out Reset Selection bits (BOR disabled)
#pragma config IESO = OFF       // Internal External Switchover bit (Internal/External Switchover mode is disabled)
#pragma config FCMEN = OFF      // Fail-Safe Clock Monitor Enabled bit (Fail-Safe Clock Monitor is disabled)
#pragma config LVP = OFF         // Low Voltage Programming Enable bit

// CONFIG2
#pragma config BOR4V = BOR21V   // Brown-out Reset Selection bit (Brown-out Reset set to 2.1V)
#pragma config WRT = OFF        // Flash Program Memory Self Write Enable bits (Write protection off)

Here goes the main function.

void main(void){
    
    GeneralConfig(); //ConfiguraciĆ³n general.
    BrushStart = 1; //Activamos el cepillo.
    TRISBbits.TRISB0 = 0; //TEST LED
    RB0 = 0; //TEST LED
    
    while(1){
    
        //THIS IS ANOTHER TEST
        if(Pressed==1){RB0 = 1;}
        else if(Pressed==2){RB0 = 0;}
        
    } //Bucle infinito.
     
    return;
}

The important here is: when Pressed is 1, the LED turns on and when it is 0 it turns off. Now, I'm gonna change OSCCON, according to the datasheet, for 8MHz internal oscillator.

//Oscilador
OSCCON = 0b01110101; //Internal 8MHz

Now, with my frequency, I'm configuring the USART:

void USARTConfig(void){ //USART Configuration

    //BAUDRATE (9600) = Fosc/(64*(SPBRG+1))
    
    BAUDCTL = 0b00000000;
    BRGH = 0;
    SPBRG = 12; 
    TXSTA = 0b10100110;
    RCSTA = 0b10010110; 

}

This should give me 9600 BAUD RATE. There is even a table (Table 12-5) in section 12.3 of the datasheet: with 8MHz, BRGH=0, BRG16=0, SPBRG=12 --> BAUD=9600.

Just in case, here is my reception code:

int USARTRead(char *Rxdata){

    int j=0;
    
    while(PIR1bits.RCIF){
         
            if(RCSTAbits.OERR == 1) //Overrun error           
               {RCSTAbits.CREN = 0; //Clear overrun error (disable receiver)                              
                RCSTAbits.CREN = 1;} //Enable receiver       
            if(RCSTAbits.FERR == 1) //Framing error bit
               {RCSTAbits.SPEN = 0; //Serial Port Disable
                RCSTAbits.SPEN = 1;}
                       
            Rxdata[j]=RCREG; 
            j++;
   
        }
    
    return j;

}

Here is what I do with the received data:

void ReceiveControl(char *Rxdata){

    if(DataCompare(Rxdata, "M",1)){
        ManualMode = 1;
        //BrushStart = 0;
        //Stop();
    }
    else if(DataCompare(Rxdata, "A",1)){       
        ManualMode = 0;
    }

    else if(DataCompare(Rxdata, "U",1)){Pressed = 1;} //Forward
    else if(DataCompare(Rxdata, "D",1)){Pressed = 2;} //Backward
    else if(DataCompare(Rxdata, "L",1)){Pressed = 3;} //Left
    else if(DataCompare(Rxdata, "R",1)){Pressed = 4;} //Right
    else if(DataCompare(Rxdata, "S",1)){Pressed = 0;} //Stop
    else if(DataCompare(Rxdata, "B",1)){BrushStart = 1;} //Brush Start
    else if(DataCompare(Rxdata, "X",1)){BrushStart = 0;} //Brush Stop
    

}

And last, how I compare the data received:

int DataCompare(unsigned char Buffer[], unsigned char Data[], unsigned int length){

    int i = 0;
    
    while(i<length){
        if(Buffer[i] == Data[i]){
        
            i++;
            if(i==length){
            
                return 1;
            }   
        }
        if(Buffer[i] != Data[i]){
        
            i=length;
            return 0;
        }           
    }
}

This exact functions where in my last project with the PIC16F1455, and they worked. I only changes registers because this is another pic. And they don't work. Am I missing something?


Solution

  • I might be wrong but I think you made a mistake setting BRGH.

    According to the datasheets I have:

    EUSART settings

    So if you set BRGH = 0 but then do TXSTA = 0b10100110 you are rewriting BRGH (bit 2) to 1, meaning you need to divide by 16 to calculate the baudrate.

    If you load 12 onto SPBRG (n in the equation) you are probably running at 38.4k instead of 9.6kbaud.

    When debugging UARTS I find absolutely necessary to have a scope close at hand to look at the signals.

    The first sentence of your question won you an upvote.