Continue to Site

Welcome to our site!

Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

  • Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

USART C18 Issued(RFID)

Status
Not open for further replies.

AtomSoft

Well-Known Member
Hey all I seem to be having some trouble with this dag USART on my 18f2525.

Im trying to run it at: 2400bps from 8mhz internal

I just cant get the math right for the code i think.

To calculate i did:
((FOSC/BAUD)/64)-1
so thats
((8000000/2400)/64)-1 = 51.08 = 51

To calculate actual baud from above:
8000000/(64(51+1)) = 2403

Percentage:
(2403-2400)/2400 = 0.00125%

Which i assume is great!

The code im using is:
Code:
    OpenUSART(  USART_TX_INT_OFF  &
                USART_RX_INT_OFF  &
                USART_ASYNCH_MODE &
                USART_EIGHT_BIT   &
                USART_CONT_RX     &
                USART_BRGH_LOW,51);

The issue is i can get data 1 time and when i try to get more info i doesnt work.

full code
Code:
#include <p18f2525.h>
#include <stdio.h>
#include <string.h>
#include <delays.h>
#include <usart.h>


#pragma config WDT = OFF, LVP = OFF, OSC = INTIO67, XINST = OFF

/************************************
Prototypes
*************************************/
void main(void);
void delay_ms(int mS);
void delay_us(int uS);
void delay_s(int S);
char IsNew(char TheID);
char getSlot(void);
char isDataRdyUSART(void);

void e_togg(void);
void lcd_line(char line);
void lcd_cmd(unsigned char letter);
void lcd_char(unsigned char letter);
void lcd_string(char *senpoint);
void lcd_init(void);
void delay_ms(int mS);
void delay_us(int uS);
void delay_s(int S);
void lcdByte(unsigned char dNyb,unsigned char rs);
/************************************
Variables AND Defines
*************************************/
char MyID;
char tmp;

unsigned char sPosition;

unsigned char cards[100];
unsigned char tmpID[10];
unsigned char inputID[10];
unsigned char comp[17]   = "  AtomSoftTech  ";
unsigned char NewStr[17] = "New Card Entered";
unsigned char NonStr[17] = "Card Not Found. ";
unsigned char ExisStr[17]= "Card Exist      ";
unsigned char ShowID[17] = "ID:             ";
unsigned char Blank[17] = "                ";

#define RX_TRIS TRISCbits.TRISC7
#define BadLED LATCbits.LATC2
#define GoodLED LATCbits.LATC3
#define AddUserBtn PORTAbits.RA1
#define AddUserBtnT TRISAbits.TRISA1

#define LCD_CLK_T TRISAbits.TRISA2//C0
#define LCD_DAT_T TRISAbits.TRISA3//C1
#define LCD_E_T TRISAbits.TRISA4//C2

#define LCD_CLK LATAbits.LATA2//C0
#define LCD_DAT LATAbits.LATA3//C1
#define LCD_E   LATAbits.LATA4//C2
/************************************
Main
*************************************/
void main(void){
    char inputstr[12];
    char y,x;

	OSCCON = 0x72;      			//8MHz clock
	while(!OSCCONbits.IOFS);		//wait for osc stable

    y = x = 0;
    sPosition = 0;


    TRISA = TRISB = TRISC = 0;
    AddUserBtnT = RX_TRIS = 1;
    LCD_DAT_T = LCD_CLK_T = LCD_E_T = 0;
    ADCON1 = 0x0F;


    lcd_init();
    delay_ms(50);
	lcd_line(1);
	lcd_string(comp);

    OpenUSART(  USART_TX_INT_OFF  &
                USART_RX_INT_OFF  &
                USART_ASYNCH_MODE &
                USART_EIGHT_BIT   &
                USART_CONT_RX     &
                USART_BRGH_LOW,51);

    //Blank out variable
    for(y=0;y<100;y++){
        cards[y] = 0;
    }       



while(1){
loopit:
    getsUSART( inputstr, 12 );
    if(inputstr[0] != 0x0A) goto loopit;

if(AddUserBtn == 1){
    for(y=0;y<10;y++)
        inputID[y] = inputstr[y+1];

    for(y=0;y<12;y++)
        inputstr[y] = 0;

    if(IsNew(inputID) == 1){        //Card exist
	    lcd_line(2);
	    lcd_string(ExisStr);
    } else {                        //Card is new
        x = 5;
        for(y=0;y<10;y++){
            ShowID[x+y] = inputID[y] ;
        }
	    lcd_line(2);            
	    lcd_string(ShowID);

        sPosition = getSlot();           
        if(sPosition == 0xFF){
            //No Slots Available for new data
        } else {
            for(x=0;x<10;x++)
                cards[sPosition + x] = inputID[x];
        }

        delay_s(1);
	    lcd_line(2);            
	    lcd_string(NewStr);

        delay_s(2);
	    lcd_line(2);            
	    lcd_string(Blank);

        
    }
}

}
}

char IsNew(char TheID){
    char cCount,cPos;
    char x,y;

    for(cCount=0;cCount<10;cCount++){
        cPos = cCount * 10;
    
        for(x=0;x<10;x++){ 
            tmpID[x] = cards[cPos + x];
        }

        if(memcmp(tmpID,TheID,10) == 0)
            return 1;
    }

    return 0;
}

char getSlot(void){
    char cCount, cPos;

    for(cCount=0;cCount<10;cCount++){
        cPos = cCount * 10;
        if(cards[cPos] == 0) 
            return cPos;
    }
    return 0xFF;
}
/***********************************
LCD Functions
************************************
Send String to LCD
************************************/
void lcd_string(char *senpoint){
    delay_ms(1);
	while(*senpoint != '\0'){
		lcd_char(*senpoint);
		senpoint++;
	}
}
/************************************
Send Data(Nybble) to LCD
************************************/
void lcdByte(unsigned char dNyb,unsigned char rs){
	int i;

	LCD_DAT=0;							//Clear 74LS164 set initial bit to 0
	for(i=0;i<8;i++){				    //repeat for 8 bits
		LCD_CLK=1;LCD_CLK=0;			//write 0's to the 164
	}

	for(i=0;i<4;i++){				    //output the nybble
		if((dNyb & 0x08) != 0)
			LCD_DAT=1;
		else
			LCD_DAT=0;

		LCD_CLK=1;LCD_CLK=0;
		dNyb=dNyb<<1;
	}

	LCD_DAT = rs;						    //output the RS bit value
	LCD_CLK=1;LCD_CLK=0;

	LCD_DAT = 0;
	LCD_CLK=1;LCD_CLK=0;
	LCD_CLK=1;LCD_CLK=0;
	LCD_CLK=1;LCD_CLK=0;

	e_togg();
}
/************************************
Toggle E Line
************************************/
void e_togg(void){
	LCD_E=1;LCD_E=0;
}
/************************************
Set LCD Line
************************************/
void lcd_line(char line){
    if(line == 0x01)
        lcd_cmd(0x80);
    else
	    lcd_cmd(0xc0);
}
/************************************
LCD Send Command
************************************/
void lcd_cmd(unsigned char letter){
	unsigned char temp;
	temp=letter;
	temp=temp>>4;
	lcdByte(temp,0);
	temp=letter;
	temp=temp&0x0f;
	lcdByte(temp,0);
}
/************************************
LCD Send Character
************************************/
void lcd_char(unsigned char letter){
	unsigned char temp;
	temp=letter;
	temp=temp>>4;
	lcdByte(temp,1);
	temp=letter;
	temp=temp&0x0f;
	lcdByte(temp,1);
}
/************************************
LCD Initialization
************************************/
void lcd_init(void){

    LCD_E_T = 0;
    LCD_CLK_T = 0;
    LCD_DAT_T = 0;

	lcdByte(0x03,0);
	delay_ms(5);
	e_togg();
	delay_us(160);
	e_togg();
	delay_us(160);
	lcdByte(0x02,0);
	delay_us(160);
	lcd_cmd(0x28);					//set 4-bit mode and 2 lines
	delay_us(160);
	lcd_cmd(0x10);					//cursor move & shift left
	delay_us(160);
	lcd_cmd(0x06);					//entry mode = increment
	delay_us(160);
	lcd_cmd(0x0d);					//display on - cursor blink on
	delay_us(160);
	lcd_cmd(0x01);					//clear display
	delay_ms(500);
}
/************************************
Delays (S,mS,uS) for 20Mhz
************************************/
/*********************
    Delay Second(s)
**********************/
void delay_s(int S){
    int y;
    char x;

    for(y=0;y<S;y++)
        for(x=0;x<4;x++)
            delay_ms(250);

}
/************************
    Delay MilliSecond(s)
*************************/
void delay_ms(int mS){
    int y;

    for(y=0;y<mS;y++)
        Delay1KTCYx(2);
}
/************************
    Delay MicroSeconds
*************************
Lowercase 'u' is common
symbol for Micro
*************************/
void delay_us(int uS){
    int y;
    char x;

    for(y=0;y<uS;y++){
            Nop();
            Nop();
    }
}


As mentioned i can read 1 card then it seems to get suck on the built in function "DataRdyUSART".

Any thoughts?
 
I've gotten so busy, but there is a new kit called WASP. It's a small 18F1320 based IR In/Out, RS232, RS485 and a little I/O controller with optional crystal osc. *it was a custom design but modified to make it kit worthy.
**broken link removed**
Incomplete image of the customizable WASP.
 
Last edited:
It may just be me but that generator doesnt seem to help me. I tried the below image and using the BRGH and SPBRG and it doesnt work at all. Any thoughts?

usart-png.25130
 

Attachments

  • usart.png
    usart.png
    13.3 KB · Views: 1,070
When the video is available you will see where it gets stuck. For some reason it doesnt read it after the first read.

[embed]http://www.youtube.com/v/vM_7QLxu6XU[/embed]

Video is uploaded just processing give it about 1-2 minutes from this post time.
EDIT: Its Working now
 
Last edited:
THE ABOVE "ITS WORKING NOW" IS MEANT FOR THE VIDEO.

The actual project IS NOT working and any thoughts would be great. I just tried it on a 20Mhz Crystal and no luck. I can get 1-3 swipes in and then it konks out and does not move from the DataRdy function.
 
Hi Jason;

You need to check for overrun and / or framing errors, which is most likely the cause of your problems (I recently went through the same thing).

I don't have any asm (handy) for you, but I see you know you're C18, so this should help.

Code:
if (RCSTAbits.OERR)
{
    // overrun error  (this sequence clears the error)
    RCSTAbits.CREN = 0;     // disable the reciever
    RCSTAbits.CREN = 1;     // reenable the reciever
}

if (RCSTAbits.FERR)
{
    // framing error (read the byte to clear the error, but throw it away)
    nextByte = ReadUSART();
}
else
{
    nextByte = ReadUSART();

    // do what you need to with the received character

}

Note: I quickly typed this out as I don't have any sample code with me... so this is untested and is for demonstration only.

Basically, if you stop your code when it gets stuck, you can probably verify that either the OERR or FERR bits are set in the RCSTA register.

I have to run to work, but if you don't get me, I'll post more later. Have a look through PICLIST... I think that's where I got help from when I was pulling my hair out with the same problem! :)
 
Thanks for the info. I checked the RCSTA reg and its a "OERR: Overrun Error bit" issue so far I will implement the code above

The RCSTAbits.FERR part in your code is the same whether the error has occurred or not.
It says to clear it by reading the RCREG and then getting next byte. so maybe :
Code:
if (RCSTAbits.OERR)
{
    // overrun error  (this sequence clears the error)
    RCSTAbits.CREN = 0;     // disable the reciever
    RCSTAbits.CREN = 1;     // reenable the reciever
}

if (RCSTAbits.FERR)
{
    // framing error (read the byte to clear the error, but throw it away)
    nextByte = ReadUSART();    //[B]read it 2 times to skip and get new data.[/B]
}

    nextByte = ReadUSART();

    // do what you need to with the received character
EDIT

With your code and some C18 built in stuff i made the below code. But it still gets stuck.
Code:
void GetRFID(char *buffer){
  char i;                           // Length counter
  unsigned char data;

    for(i=0;i<12;i++)               // Only retrieve len characters
    {
        if (RCSTAbits.OERR)
        {
        // overrun error  (this sequence clears the error)
            RCSTAbits.CREN = 0;     // disable the reciever
            RCSTAbits.CREN = 1;     // reenable the reciever
        }
    
        if (RCSTAbits.FERR)
        {
        // framing error (read the byte to clear the error, but throw it away)
            data = RCREG;           //Skip read to clear
        }
        //[b]It gets stuck here waiting for data to be received[/b]
        while(!PIR1bits.RCIF);      // Wait for data to be received
        data = RCREG;    
        
        *buffer = data;
        buffer++;                   // Increment the string pointer
    }
    
}
 
Last edited:
Ok so far this seems to be working. If it fails ill be mad :( lol
Code:
void GetRFID(char *buffer){
  char i;                           // Length counter
  unsigned char data;

    for(i=0;i<12;i++)               // Only retrieve len characters
    {
          while(!PIR1bits.RCIF);      // Wait for data to be received
        data = RCREG;    
        
        *buffer = data;
        buffer++;                   // Increment the string pointer

        if (RCSTAbits.OERR)
        {
        // overrun error  (this sequence clears the error)
            RCSTA = 0;     // disable the reciever
            delay_ms(100);
            RCSTA = 0b10010000;     // reenable the reciever
            break;
        }
    
        if (RCSTAbits.FERR)
        {
        // framing error (read the byte to clear the error, but throw it away)
            data = RCREG;           //Skip read to clear
        }
    }
    
}

EDIT Here is a video of it in action:

[embed]http://www.youtube.com/v/p77ZrLrMoZg[/embed]
 
Last edited:
The RCSTAbits.FERR part in your code is the same whether the error has occurred or not.

Actually, if you look closely, it's an IF-ELSE statement... so it only gets used IF there is a framing error... it simply reads the character and throws it away... the ELSE part gets run only if there ISN'T a framing error... it looks the same because I haven't included any code below (within the ELSE block) to actually handle the character. The reason I do it this way is to handle each character as I'm building a packet and check certain bytes to make sure they are what they are supposed to be. (I'm sure there are lots of ways to do it, this was simply the first way that I did it that worked, so I haven't touched it since.

Accordingly, I would use it as such;

Code:
if (RCSTAbits.FERR)
{
    data = ReadUSART();
}
else
{

    data = ReadUSART();

    if (data = 0x02)
    {
         // start of a packet
        // do something with the byte

        // continue reading bytes and handling them
        // until an 0x03 is received (end of packet)
    }
}

So, basically, the packet is built only if there are no framing errors. I'll have to post my code when I get home as it is pretty self-explanitory once you see it.

You've got the basic idea anyway and now know what is causing your error -- I've seen your work, so I'm pretty sure you'll figure the rest out without me. ;)
 
0xFF thanks alot.. Whats your name?

I understand the error thanks to you. I think if you have anything to add to this i would like to see it.

I call the function and check the first and last byte since its a ID and contains a 0x0A as the first byte and a 0x0D as the last byte. If i get a error in between it breaks out the function hence it doesnt complete the last byte and the whole corrupt ID isnt used at all.
This is how im testing it
Code:
loopit:
    GetRFID(inputstr);
    if(inputstr[0] != 0x0A) goto loopit;
    if(inputstr[11] != 0x0D) goto loopit;

This is my complete code:
Code:
#include <p18f2525.h>
#include <stdio.h>
#include <string.h>
#include <delays.h>
#include <usart.h>

#pragma config WDT = OFF, LVP = OFF, OSC = HS//INTIO67

/************************************
Prototypes
*************************************/
void main(void);
void delay_ms(int mS);
void delay_us(int uS);
void delay_s(int S);
char IsNew(char TheID);
char getSlot(void);
char isDataRdyUSART(void);

void e_togg(void);
void lcd_line(char line);
void lcd_cmd(unsigned char letter);
void lcd_char(unsigned char letter);
void lcd_string(char *senpoint);
void lcd_init(void);
void delay_ms(int mS);
void delay_us(int uS);
void delay_s(int S);
void lcdByte(unsigned char dNyb,unsigned char rs);

void GetRFID(char *buffer);
/************************************
Variables AND Defines
*************************************/
char MyID;
char tmp;

unsigned char sPosition;

unsigned char cards[100];
unsigned char tmpID[10];
unsigned char inputID[10];
unsigned char comp[17]   = "  AtomSoftTech  ";
unsigned char NewStr[17] = "New Card Entered";
unsigned char NonStr[17] = "Card Not Found. ";
unsigned char ExisStr[17]= "Card Exist      ";
unsigned char ShowID[17] = "ID:             ";
unsigned char Blank[17] = "                ";

#define RX_TRIS TRISCbits.TRISC7
#define BadLED LATCbits.LATC2
#define GoodLED LATCbits.LATC3
#define AddUserBtn PORTAbits.RA1
#define AddUserBtnT TRISAbits.TRISA1

#define LCD_CLK_T TRISAbits.TRISA2//C0
#define LCD_DAT_T TRISAbits.TRISA3//C1
#define LCD_E_T TRISAbits.TRISA4//C2

#define LCD_CLK LATAbits.LATA2//C0
#define LCD_DAT LATAbits.LATA3//C1
#define LCD_E   LATAbits.LATA4//C2
/************************************
Main
*************************************/
void main(void){
    char inputstr[12];
    char y,x;

    y = x = 0;
    sPosition = 0;

    TRISA = TRISB = TRISC = 0;
    RX_TRIS = 1;
    LCD_DAT_T = LCD_CLK_T = LCD_E_T = 0;
    ADCON1 = 0x0F;

    lcd_init();
    delay_ms(50);
	lcd_line(1);
	lcd_string(comp);

    OpenUSART(  USART_TX_INT_OFF  &
                USART_RX_INT_OFF  &
                USART_ASYNCH_MODE &
                USART_EIGHT_BIT   &
                USART_CONT_RX     &
                USART_BRGH_LOW,129);
                //USART_BRGH_LOW,51);


    //Blank out variable
    for(y=0;y<100;y++){
        cards[y] = 0;
    }       



while(1){
loopit:       

    //getsUSART( inputstr, 12 );
    GetRFID(inputstr);
    if(inputstr[0] != 0x0A) goto loopit;
    if(inputstr[11] != 0x0D) goto loopit;
    
    for(y=0;y<10;y++)
        inputID[y] = inputstr[y+1];

    for(y=0;y<12;y++)
        inputstr[y] = 0;

    if(IsNew(inputID) == 1){        //Card exist
	    lcd_line(2);
	    lcd_string(ExisStr);
    } else {                        //Card is new
        x = 5;
        for(y=0;y<10;y++){
            ShowID[x+y] = inputID[y] ;
        }
	    lcd_line(2);            
	    lcd_string(ShowID);

        sPosition = getSlot();           
        if(sPosition == 0xFF){
            //No Slots Available for new data
        } else {
            for(x=0;x<10;x++)
                cards[sPosition + x] = inputID[x];
        }

        delay_s(1);
	    lcd_line(2);            
	    lcd_string(NewStr);
    }

        delay_s(2);
	    lcd_line(2);            
	    lcd_string(Blank);
}
}

void GetRFID(char *buffer){
  char i;                           // Length counter
  unsigned char data;

    for(i=0;i<12;i++)               // Only retrieve len characters
    {
        //It used to get stuck here
        while(!PIR1bits.RCIF);      // Wait for data to be received
        data = RCREG;    
        
        *buffer = data;
        buffer++;                   // Increment the string pointer

        if (RCSTAbits.OERR)
        {
        // overrun error  (this sequence clears the error)
            RCSTA = 0;     // disable the reciever
            delay_ms(100);
            RCSTA = 0b10010000;     // reenable the reciever
            break;
        }
    
        if (RCSTAbits.FERR)
        {
        // framing error (read the byte to clear the error, but throw it away)
            data = RCREG;           //Skip read to clear
            break;
        }
    }
    
}


char IsNew(char TheID){
    char cCount,cPos;
    char x,y;

    for(cCount=0;cCount<10;cCount++){
        cPos = cCount * 10;
    
        for(x=0;x<10;x++){ 
            tmpID[x] = cards[cPos + x];
        }

        if(memcmp(tmpID,TheID,10) == 0)
            return 1;
    }

    return 0;
}

char getSlot(void){
    char cCount, cPos;

    for(cCount=0;cCount<10;cCount++){
        cPos = cCount * 10;
        if(cards[cPos] == 0) 
            return cPos;
    }
    return 0xFF;
}
/***********************************
LCD Functions
************************************
Send String to LCD
************************************/
void lcd_string(char *senpoint){
    delay_ms(1);
	while(*senpoint != '\0'){
		lcd_char(*senpoint);
		senpoint++;
	}
}
/************************************
Send Data(Nybble) to LCD
************************************/
void lcdByte(unsigned char dNyb,unsigned char rs){
	int i;

	LCD_DAT=0;							//Clear 74LS164 set initial bit to 0
	for(i=0;i<8;i++){				    //repeat for 8 bits
		LCD_CLK=1;LCD_CLK=0;			//write 0's to the 164
	}

	for(i=0;i<4;i++){				    //output the nybble
		if((dNyb & 0x08) != 0)
			LCD_DAT=1;
		else
			LCD_DAT=0;

		LCD_CLK=1;LCD_CLK=0;
		dNyb=dNyb<<1;
	}

	LCD_DAT = rs;						    //output the RS bit value
	LCD_CLK=1;LCD_CLK=0;

	LCD_DAT = 0;
	LCD_CLK=1;LCD_CLK=0;
	LCD_CLK=1;LCD_CLK=0;
	LCD_CLK=1;LCD_CLK=0;

	e_togg();
}
/************************************
Toggle E Line
************************************/
void e_togg(void){
	LCD_E=1;LCD_E=0;
}
/************************************
Set LCD Line
************************************/
void lcd_line(char line){
    if(line == 0x01)
        lcd_cmd(0x80);
    else
	    lcd_cmd(0xc0);
}
/************************************
LCD Send Command
************************************/
void lcd_cmd(unsigned char letter){
	unsigned char temp;
	temp=letter;
	temp=temp>>4;
	lcdByte(temp,0);
	temp=letter;
	temp=temp&0x0f;
	lcdByte(temp,0);
}
/************************************
LCD Send Character
************************************/
void lcd_char(unsigned char letter){
	unsigned char temp;
	temp=letter;
	temp=temp>>4;
	lcdByte(temp,1);
	temp=letter;
	temp=temp&0x0f;
	lcdByte(temp,1);
}
/************************************
LCD Initialization
************************************/
void lcd_init(void){

    LCD_E_T = 0;
    LCD_CLK_T = 0;
    LCD_DAT_T = 0;

	lcdByte(0x03,0);
	delay_ms(5);
	e_togg();
	delay_us(160);
	e_togg();
	delay_us(160);
	lcdByte(0x02,0);
	delay_us(160);
	lcd_cmd(0x28);					//set 4-bit mode and 2 lines
	delay_us(160);
	lcd_cmd(0x10);					//cursor move & shift left
	delay_us(160);
	lcd_cmd(0x06);					//entry mode = increment
	delay_us(160);
	lcd_cmd(0x0d);					//display on - cursor blink on
	delay_us(160);
	lcd_cmd(0x01);					//clear display
	delay_ms(500);
}
/************************************
Delays (S,mS,uS) for 20Mhz
************************************/
/*********************
    Delay Second(s)
**********************/
void delay_s(int S){
    int y;
    char x;

    for(y=0;y<S;y++)
        for(x=0;x<4;x++)
            delay_ms(250);

}
/************************
    Delay MilliSecond(s)
*************************/
void delay_ms(int mS){
    int y;

    for(y=0;y<mS;y++)
        Delay1KTCYx(5);
}
/************************
    Delay MicroSeconds
*************************
Lowercase 'u' is common
symbol for Micro
*************************/
void delay_us(int uS){
    int y;
    char x;

    for(y=0;y<uS;y++)
        for(x=0;x<5;x++)
            Nop();
}
 
Last edited:
If you are getting overrun errors then it is probably caused by not reading the serial port often enough. To fix this you could receive the data on interrupt and use a fifo to buffer it. I have code for a fifo if needed.

I have no idea why you would get framing errors unless you switch of the receiver for short periods like in your OERR code.

Mike.
 
it seems to work now. Im not even sure what a "FIFO" is. But i would like to know. Explain in a child manner please... as if you are writing a "For Dummies" book :D i tend to understand it better when explained as if im slow lol
 
A FIFO is a First In First Out buffer. Data is added to the end of the buffer and removed from the beginning. Your interrupt calls PutFifo to store a character and your main code calls GetFifo to retrieve characters. As long as you take out characters before the buffer is full then all is well.

A code example is probably easier to follow.
Code:
unsigned char FifoBuffer[16];
unsigned char *FifoStart;
unsigned char *FifoEnd;


void InitFifo(void){
    FifoStart=FifoBuffer;
    FifoEnd=FifoBuffer;
}

void PutFifo(unsigned char chr){
    *FifoEnd++=chr;
    if(FifoEnd==FifoBuffer+16)      //reached end
        FifoEnd=FifoBuffer;         //yes so wrap
    if(FifoStart==FifoEnd){         //is head eating tail?
        //fifo full so deal with it!!
    }
}

unsigned char GetFifo(void){
unsigned char chr;
    while(FifoStart==FifoEnd);      //if fifo empty then wait
    chr=*FifoStart++;
    if(FifoStart==FifoBuffer+16)    //wrapped?
        FifoStart=FifoBuffer;       //yes
    return(chr);
}

unsigned char FifoCount(void){
    return((FifoEnd-FifoStart)&15);
}

Note the (bad) hard coded length.

Mike.
 
ok so basically it saves the data in the buffer on interrupt starting from the last place and shifting left i suppose. I have to pull data out before it gets full and overwrites itself?
 
There is no shifting. When you get to the end of the buffer you start back at the beginning. It's useful when you have to process a data stream, whilst you're checking/sorting/storing the last input the buffer will fill with the next one.

Mike.
 
If you are getting overrun errors then it is probably caused by not reading the serial port often enough. To fix this you could receive the data on interrupt and use a fifo to buffer it. I have code for a fifo if needed.

I have no idea why you would get framing errors unless you switch of the receiver for short periods like in your OERR code.

Framing errors are, usually, generated on the first read (or any time you try to read a byte when it's "half way" there) - this is normal. That, or your baud rate is off.

I don't see the need for a FIFO either (some also refer to this as a ring, or circular buffer... just for reference). I'm sending out packets to 4 devices, every 300ms, with a read back to detect collisions and never get overrun errors.

Here's how I've setup mine;

Code:
void Rs485ReceiveData(void)
{
	uint8_t lengthByte;
	uint8_t checkByte, nextByte;
	uint8_t i;
	extern uint8_t turnTimeoutOn;
	extern uint8_t hasTimeoutOccured;
	extern uint8_t timeoutCount;

	TMR1_INT_DISABLE();
	timeoutCount = 4;
	hasTimeoutOccured = 0;							// clear the TIMEOUT flag
	turnTimeoutOn = 1;								// turn on TIMEOUT	
	TMR1_INT_ENABLE();

	while(!DataRdyUSART())
	{
		if (hasTimeoutOccured)
			goto BadCommandRead;
	}

	// the serial port has received a byte
	// read the received character
	if (RCSTAbits.OERR == 1)
	{
		// overrun error
		// clear the error and reenable the receiver
		RCSTAbits.CREN = 0;
		RCSTAbits.CREN = 1;
	}

	if (RCSTAbits.FERR == 1)
	{
		// framing error
		// reading a byte clears the error
		// read the byte but don't use it
		nextByte = ReadUSART();
	} 
	else
	{
		// a character was received without a framing error
	   	nextByte = ReadUSART(); 							// get the received character
																// from the USART
		if (nextByte == STX)
		{
			// A new command has begun. 
			// Initialize the array that holds received characters. 
			receivedCommand[0] = STX;						// STX byte

			timeoutCount = 2;								// set the intercharacter timeout (20ms)
			lengthByte = Rs485GetChar();					// LEN byte
			if (hasTimeoutOccured)
				goto BadCommandRead;
			receivedCommand[1] = lengthByte;				// Save the byte in the string

			if (lengthByte < 3)
				return;
			// NOTE: should also check lengthByte for MAX packet length violation

			checkByte = lengthByte;							// Start the XOR checksum

			for(i=2; i < lengthByte - 3; i++)  				// Only retrieve len-2 characters
			{												// ADDRESS, ETX, CHK
				timeoutCount = 2;							// set the intercharacter timeout (20ms)
				nextByte = Rs485GetChar();					// Get a character from the USART
				if (hasTimeoutOccured)
					goto BadCommandRead;
				checkByte ^= nextByte;						// XOR the checkByte 
				receivedCommand[i] = nextByte;				// Save the byte in the string
			}

			timeoutCount = 2;								// set the intercharacter timeout (20ms)
			nextByte = Rs485GetChar();						// ADDRESS uint8_t
			if (nextByte != MY_ADDRESS 						// is the packet addressed to me?
					|| hasTimeoutOccured)					// has a timeout occured?
			{
				if (nextByte == BROADCAST_ADDRESS)
				{
					Nop();
				}
				else
					goto BadCommandRead;					// command is NOT for this device
			}
			checkByte ^= nextByte;							// XOR the checkByte 
			receivedCommand[lengthByte - 3]	= nextByte;		// save the byte in the string				

			timeoutCount = 2;								// set the intercharacter timeout (20ms)
			nextByte = Rs485GetChar();						// ETX uint8_t
			if (nextByte != ETX || hasTimeoutOccured)
				goto BadCommandRead;						// bad read
			receivedCommand[lengthByte - 2] = ETX;			// Save the byte in the string
			timeoutCount = 2;								// set the intercharacter timeout (20ms)
			nextByte = Rs485GetChar();						// Checksum uint8_t
			if (nextByte != checkByte || hasTimeoutOccured)
				goto BadCommandRead;						// bad read
			receivedCommand[lengthByte - 1] = nextByte;		// Save the byte in the string

			// We're done -- good read
			TMR1_INT_DISABLE();
			turnTimeoutOn = 0;								// turn off TIMEOUT
			TMR1_INT_ENABLE();

			// copy the command array to currentCommand and echoDetect
			for (i=0; i<receivedCommand[1]; i++)
			{ 
				currentCommand[i] = receivedCommand[i];
//				echoDetect[i] = receivedCommand[i];
			}

			if (receivedCommand[lengthByte - 3] == BROADCAST_ADDRESS)
				Nop();

			Rs485ProcessReceivedData();
			return;
					
			BadCommandRead:
				Rs485ClearCommand();
				//LogCommandAndReply(currentCommand, FALSE);
				return;
		}
	}
}

and the function to get additional bytes within the above function;

Code:
uint8_t Rs485GetChar(void)
{
	uint8_t rs485RxChar;
	extern uint8_t hasTimeoutOccured;

	while (!DataRdyUSART())
	{
		if (hasTimeoutOccured)
			goto Rs485BadCharacter;	
	}

	// the serial port has received a uint8_t
	// read the received character
	if (RCSTAbits.OERR == 1)
	{
		// overrun error
		// clear the error and reenable the receiver
		RCSTAbits.CREN = 0;
		RCSTAbits.CREN = 1;
	}

	if (RCSTAbits.FERR == 1)
	{
		// framing error
		// reading a byte clears the error
		// read the byte but don't use it
		rs485RxChar = ReadUSART();
		goto Rs485BadCharacter;
	} 
	else
	{
		rs485RxChar = ReadUSART();
		return rs485RxChar;
	}

	Rs485BadCharacter:
		// this needs to be looked at
		return 0xFF;		
}

There's lots of work still to be done on it (some things, I've learned, could be handled a little better and the framing / overrun error checking could be combined to just one function) -- it's been running for a few months now, error free. :)

Kyle

PS - You'll also note the use of a "timeout" counter between received bytes. Probably not so important in your situation, but I use it in case a device stalls and stops transmitting... without it, you'd get stuck waiting for the next byte, which never comes. It's a simple setup of Timer 1.
 
Framing errors are, usually, generated on the first read (or any time you try to read a byte when it's "half way" there) - this is normal. That, or your baud rate is off.
I was hinting (obviously too subtly) in my response that the framing errors were being caused by the way the overflow errors were being handled.
I don't see the need for a FIFO either (some also refer to this as a ring, or circular buffer... just for reference). I'm sending out packets to 4 devices, every 300ms, with a read back to detect collisions and never get overrun errors.

A fifo buffer is required when you need to do some processing on the previous data. Writing it to an LCD may take longer than to receive 2 bytes and cause an overrun error.

I concluded that a fifo would solve the overrun error and therefore the framing error.

Mike.
 
Status
Not open for further replies.

Latest threads

Back
Top