• 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.

PIC16F887-PC / Receiving garbage characters after word ends.

Status
Not open for further replies.

Kylobeetle

Member
Hello everyone, Im playing with a PIC16F887 to practice my coding skills and I managed to connect it to my computer via UART. I made a simply code to
Send a text to my pc and then answer back anything inserted, then procced to show it back and confirm what i wrote. But im facing something weird when i do this because after the word is completed, next to it appears a chain of garbage chracters, i have tried to limit the array and set a null value to the last digit of the array to let it know that the word will end there. I dont know if you have give me a hand to succesfull enter any word of X characters and then show it back with no garbage in it. Excuse me if some part of my redaction doesnt make sense at some parts, Im not a native english speaker. thanks !

Info:
Compiler XC8
Config.h = are the config bits made into that file for quick working (PIC16F887 , using inner osc)

http://prntscr.com/j4lpsc (image of the test result)


Main code (for any reason i couldnt not use the insert code command, it just hangs and does nothing so i ll paste the code here.

#include <xc.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include "config.h"
#include "uart.h"
#define _XTAL_FREQ 4000000

int main() {

TRISB = 0x00; //All B ports as output
PORTB = 0x01; // b0 on as ON pilot led.

char block[]; //test purposes
char stone[3]; // test purposes
stone[3] = "\0"; // assign null to the last space of the array stone

usart_init();
__delay_ms(500);
UART_Write_Text("Insert something to display\r\n");
UART_Read_Text(block, 5); // using word ERROR
UART_Write_Text(block); // shows ERROR+garbage
__delay_ms(800);
UART_Write_Text("Insert something to display\r\n");
UART_Read_Text(stone, 2); // OK as test word
UART_Write_Text(stone); gets OK+garbage
__delay_ms(800);
UART_Write_Text("This is a test\r\n"); // nothing special

return 0;

}



UART.H


void usart_init(){
TRISCbits.TRISC7=1;//pin RX as digital input
TRISCbits.TRISC6=0;//pin TX as digital output
TXSTA=0b00100110;// settings
RCSTA=0b10010000;// settings
SPBRG=25;// 9600 bauds for 4mhz osc.
}


char UART_TX_Empty()
{
return TRMT;
}

char UART_Data_Ready()
{
return RCIF;
}
char UART_Read()
{

while(!RCIF);
return RCREG;
}

void UART_Read_Text(char *Output, unsigned int length)
{
int i;
for(int i=0;i<length;i++)
Output = UART_Read();
}

void UART_Write(char data)
{
while(!TRMT);
TXREG = data;
}

void UART_Write_Text(char *text)
{
int i;
for(i=0;text!='\0';i++)
UART_Write(text);
}


test.png

 

Attachments

Pommie

Well-Known Member
Most Helpful Member
Your char arrays don't have a length and when you write to them you don't write a terminating zero.

I also don't see how your UART_Write_Text() function ever writes anything but the first character or how it terminates (the pointer isn't incremented!). Or how your read function returns anything more than 1 character.

Mike.
 

Kylobeetle

Member
Thanks for your reply Mike,

As you might see, Im kind of new to this world and sometimes what i see is not what will work haha..

About the UART_Write_Text() .. my computer is getting the full string, since it is just plain text and doesnt execute anything and my terminal is getting all the chain, what is wrong with this function? (i just ask because for me it is working, i believe, otherwise would you take sometime to explain me and help me to fix it ? )

can i add the null character by myself ? is this valid ? = stone[3] = "\0";

If you can explain me and help me i would thank you a lot, i want to learn what i do at the same time i progress,


i have to add that the key words "ERROR, and OK" are words entered by me, it waits for an input and thats what i wrote for this test purpose. also the Insert something here text is also coded by me, just for clarification.

thanks in advance!
 
Last edited:

Pommie

Well-Known Member
Most Helpful Member
I've just tried your code with the simulator and it just constantly goes around the UART_Write_Text() function.

I've had a play with it and got rid of all the pointers.

Try this - note no uart.h file.
Code:
#include <xc.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include "config.h"
#define _XTAL_FREQ 4000000

//prototypes
void usart_init();
void UART_Write_Text();
char UART_Read();
void UART_Read_Text(unsigned int length);
unsigned char send[32];      //buffer to send from
unsigned char rec[32];      //buffer to receive to


int main() {

TRISB = 0x00; //All B ports as output
PORTB = 0x01; // b0 on as ON pilot led.


    usart_init();
    strcpy(send,"Insert something to display\r\n");
    UART_Write_Text();
    UART_Read_Text(5);      // using word ERROR
    strcpy(send,rec);       //copy received text to send buffer
    UART_Write_Text();      // shows ERROR+garbage

    while(1);       //wait forever
}

void usart_init(){
    TRISCbits.TRISC7=1;//pin RX as digital input
    TRISCbits.TRISC6=0;//pin TX as digital output
    TXSTA=0b00100110;// settings
    RCSTA=0b10010000;// settings
    SPBRG=25;// 9600 bauds for 4mhz osc.
}

void UART_Write(char data){
    while(!TRMT);
    TXREG = data;
}

void UART_Write_Text(){
unsigned int i;
    i=0;
    while(send[i]!=0){
        UART_Write(send[i]);
        i++;
    }
}
 
char UART_Read(){
    while(!RCIF);
    return RCREG;
}

void UART_Read_Text(unsigned int length){
unsigned int i;
    for(i=0;i<length;i++)
        rec[i] = UART_Read();
    rec[i+1]=0;
}
I noted that you include the string library but never use it so I used strcpy (string copy) to get the strings into the buffers.

However, I'm still at a loss how that code did anything at all.

Mike.
Edit, in case you really want to use pointers, you can do the following,
Code:
void UART_Write_Text(unsigned char* text){
    while(*text!=0){
        UART_Write(*text++);
    }
}
and call it with UART_Write_Text(send);
you'll need to change the prototype as well.
 
Last edited:

Kylobeetle

Member
Thanks again for your time, right now im at the work, in about 12 hours i will go back to home and try the code, since i cant test it right now, the way you arranged it, it doesnt show garbage anymore ? and if not, whats the reason behind the garbage characters ?
 

Pommie

Well-Known Member
Most Helpful Member
I still have no idea how that code worked and suspect the pic was running earlier code.

The garbage characters are due to there not being a terminating zero on the strings.
Note
Code:
void UART_Read_Text(unsigned int length){
unsigned int i;
    for(i=0;i<length;i++)
        rec[i] = UART_Read();
    rec[i+1]=0;
}
The final line adds a zero after the last character.

Mike.
 

Kylobeetle

Member
I will kindly try this fix later today, but for your knowledge, I 100% sure that I burned that HEX into my PIC. in fact, before using the UART_Write_Text, i tested the UART_Write, to just send a character alone, when i saw it worked then procceded to use the text one, i know that i have to study a little more about the pointer. I thought that the garbage stuff was a faulty pic haha .. even bought another pic to discover that this one had the same behavoir, this was i acknowledge that the code had something wrong.. I like this stuff but its kinda confusing haha ..
 

Kylobeetle

Member
Can you give me any source where i can learn about this FIFO ring buffers? i have been reading about them yesterday but it is a little confusing ..
 

Pommie

Well-Known Member
Most Helpful Member
What I normally do is read the Usart until a CR has been received..

But I normally use a ring FIFO buffer and interrupts... Shutting up now...
Me too. However, in this case I tried to stay as close to the original code as possible.

Mike.
 

Kylobeetle

Member
Thanks for your precious time, like i said before, once i arrive home later , i would like to check this and then discuss the possibility if you can you aid me to make this ring buffer, i have read that this technique is the best for UART Rx stuff and its very efficient for data managing.
 

Kylobeetle

Member
As I promised, Im back home to test the code, thanks for your effort, here is the screen shot.
works.jpg
no more garbage... I have read about that Circular FIFO buffer, can you help me to build one, at least with [15] chars, or if you know a good source to read and try to understand first a little more.
 

Ian Rogers

User Extraordinaire
Forum Supporter
Most Helpful Member
Serial reception is always better using interrupts..

Simple concept... Endpoint, Startpoint, position and buffsize..

When an interrupt happens place it in the next available buffer position and increase the endpoint by one. Decrease the buffer size by one.. If the buffer size is 90%( ish ) of the total buffer unset the CTS... If the endpoint rolls over, set it to 0.

when you read the buffer, read and increase the startpoint by one and decrease the buffer size by 1.. If the startpoint rolls over set it to0.. You can read until endpoint = startpoint... If the buffer size is below the 90% ( ish) used set the CTS..

Here is a simple implementation in Oshonsoft basic
Code:
Proc clrfifo()
Dim x As Byte
 For x = 0 To 31
  fifo(x) = 0
 Next x
 fifo_head = 0
 fifo_tail = 0
 fifo_count = 0
 PORTC.5 = 0
End Proc  
-----------------------------------                                    
Proc addtofifo()
 If fifo_count >= 24 Then
  PORTC.5 = 1
 Else
  PORTC.5 = 0
 Endif
 fifo(fifo_head) = RCREG
 fifo_count = fifo_count + 1
 fifo_head = fifo_head + 1
 If fifo_head >= 31 Then fifo_head = 0
End Proc      
------------------------------------------                                
Function getfromfifo() As Byte
 
 If fifo_count = 0 Then
  getfromfifo = 0
  Exit
 Endif
 INTCON.GIEH = 0
 getfromfifo = fifo(fifo_tail)
 fifo_tail = fifo_tail + 1
 fifo_count = fifo_count - 1
 If fifo_tail >= 31 Then fifo_tail = 0
 If fifo_count < 24 Then PORTC.5 = 0
 INTCON.GIEH = 1
End Function
Worked very well... PORTC.5 is the CTS
 

Pommie

Well-Known Member
Most Helpful Member
Here's my fifo implementation in C.
Code:
#define FifoLength 32
unsigned char FifoBuffer[FifoLength];
unsigned char *FifoStart;
unsigned char *FifoEnd;
unsigned char count;

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

void PutFifo(unsigned char chr){
    *FifoEnd++=chr;
    count++;
    if(FifoEnd==FifoBuffer+FifoLength)      //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++;
    count--;
    if(FifoStart==FifoBuffer+FifoLength)    //wrapped?
        FifoStart=FifoBuffer;               //yes
    return(chr);
}

unsigned char FifoCount(void){
    return(count);
}
After initialising the fifo you call PutFifo from your interrupt when you receive a character.
Calling FifoCount will tell you how many bytes are in the fifo and GetFifo will get a character out.

Mike.
 

Kylobeetle

Member
Thank you guys,it will take me some days to understand it to apply it for any case that i could need. I will try to do my best to do it, any case i ll ask but first i will take my time to understand both of them, again, thanks for your time,
 
Last edited:
Status
Not open for further replies.

Latest threads

EE World Online Articles

Loading
Top