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.

pic serial port problem (16f88)

Status
Not open for further replies.

Dakta

New Member
Hi guys, it's been a long time since I've programmed microcontrollers, i'm back into it by the looks of things unfortunately a lot seems to have slipped my mind since last year :(

i'm having a bit of an amateurish problem, i've attempted to utilise an ft232rl serial<>usb converter on one of my boards and whilst it seems electrically ok (don't have a scope) it has been a right nightmare to get working.

Sending from pic (16f88) to pc seems to work fine, or at least I receive sentences okay in terminal, rewceiving on the other hand has been a bit of a pig.

I'm trying to handle the data as it comes in through an interrupt, the interrupt literally saves the byte to a buffer and sets a flag. That's it. The main program checks the flag, if set it adds it to a circular buffer then checks the sequence of bytes in that buffer to see if a command has been received (commands are 6 bytes long) if so then it goes and executes command x - flag gets reset and process should merely repeat.

I also drive an led activity light at the same time, and for testing reasons the program periodically transmits the contents of the circular buffer as well, so that I can see the received data.

I managed to get it so that when you send a byte, the byte is added to the buffer, and the contents are shifted one in the buffer array , so if we start with an empty buffer and send 0x01 we get:

0x00 0x00 0x00 0x00 0x00 0x01

and if we send 0x01 again we get

0x00 0x00 0x00 0x00 0x01 0x01 and so on.

Anyway the problem is, if you send a byte larger than 0xF7/F8 - let's say 0xFF for arguements sake - the pic freezes. It doesn't crash, it freezes - it's stuck and won't respond to anything...unless (and this is probably a big clue to the more experienced) you send a low value, like 0x00 which magically unfreezes the system and it then continues to run as if nothing happened. The buffer then does not contain 0xff, but rather 0xf1.

I've attached an untidy code listing, i'll try and clean it up if it's too complex :(

I'm quietly confident the hardware side of things is okay, i don't have a scope to see what's happening but I can see activity on the respective pins.

I've been a bit breif with details as I'm shooting out but if there's anything that's needed that I've missed let me know - if anyone has ideas it'd be much appreciated, it's probably some daft oversight of mine :(

Personally I think the biggest clue is with the program freezing when sent a byte near 0xff and unfreezing when 0x00 is sent, it's like the programs waiting for a stop bit and the 0x00 is seen as it or something. I have set the registers up manually aswell as using the compilers own function as you'll see further down in my code, so it's a weird one.

cheers
Kris

Code:
// test program

//variable declerations
unsigned char RX_Buffer[5];  //rx receive buffer
unsigned char RX_Temp_Buffer = 0;   //temporary area for received bytes
unsigned char ByteReceivedFlag = 0;   //this is set in the interrupt when a byte is received by uart
unsigned char CommandReceivedFlag = 0;  //this is set when a sequence of received bytes match a command's profile
unsigned char ActivityLEDFlag = 0;     //set this to a number to cause activity led to come on (higher means light on longer)

//functions
 //interrupt handler

void interrupt() {

if (uart1_data_ready() == 1){  //if data is ready for reading
RX_Temp_Buffer = uart1_read(); //read byte
ByteReceivedFlag = 1;          //set flag to identify to main program that new data wants adding to the command buffer
}
}

void ReceiveData(){ //function for taking received data and putting it into buffer, checking for command etc
ActivityLEDFlag = 2; //set activity light
RX_Buffer[0] = RX_Buffer[1];
RX_Buffer[1] = RX_Buffer[2];
RX_Buffer[2] = RX_Buffer[3];
RX_Buffer[3] = RX_Buffer[4];
RX_Buffer[4] = RX_Buffer[5];
RX_Buffer[5] = RX_Temp_Buffer;
ByteReceivedFlag = 0;
}



void main() {
//set up chip
trisa = 255;
trisb = 255; //everything inputs

//disable analogue for selected pins
ansel.b0 = 0;
ansel.b1 = 0;
ansel.b2 = 0;
ansel.b3 = 0;
ansel.b4 = 0;
ansel.b5 = 0;
ansel.b6 = 0;


//set up outputs
//led's
trisa.b1=0;  //power
trisa.b0=0; //activity
trisb.b7=0; //notice?

//switch on power LED
 porta.b1=1;
 porta.b0=0;
 portb.b7=0;

trisb.b0 = 0; //pwm out - use this later in development
trisb.b5 = 0; //tx output


//set up uart
 uart1_init(9600);
 rcsta.spen = 1;
 rcsta.rx9 = 0;
 rcsta.cren = 1;
 txsta.tx9 = 0;
 txsta.txen = 1;
 txsta.sync = 0;
 
 spbrg = 129;
 txsta.brgh = 1;
 
 //set up rx interrupt
 intcon.b7 = 1; //int enabled
  intcon.b6 = 1; //peripheral int enabled
  pie1 = 0x00;
  pie1.b5 = 1; //rx int enabled

//main loop

while (1){

//check if activity has occured recently and put light on if so (and decrement LED activity counter)
    if (ActivityLEDFlag > 1) {
     porta.b0 = 1; //led on
     ActivityLEDFlag--;
    } else {
    ActivityLEDFlag = 0; //led off
    porta.b0 = 0;
    }

     //check if byte is received - if so execute function to add byte to buffer
 if (ByteReceivedFlag == 1) ReceiveData();


  //main loop delay
  delay_ms(2);
  
  //write contents of buffer to pc
uart1_write(RX_Buffer[0]);
 delay_ms(30);
uart1_write(RX_Buffer[1]);
 delay_ms(30);
uart1_write(RX_Buffer[2]);
 delay_ms(30);
uart1_write(RX_Buffer[3]);
 delay_ms(30);
uart1_write(RX_Buffer[4]);
 delay_ms(30);
uart1_write(RX_Buffer[5]);
 delay_ms(30);
 delay_ms(1000);
 







}//end main loop

}
 
The only thing I can suggest is to either exclusively use the library function or only use the hardware. At the moment you are setting up the hardware but using the library routines to read/write.

As I don't know the particular library I always use the hardware (the code is possibly smaller anyway).

So, change your interrupt to be,
Code:
void interrupt() { 
  if (pir1.rcif == 1){  		//if data is ready for reading
    RX_Temp_Buffer = rcreg; 		//read byte
    ByteReceivedFlag = 1;          	//set flag to identify to main program that new data wants adding to the command buffer
  }
}

and add a write function,
Code:
void write(unsigned char dat){
  while(pir1.txif==0);			//wait for buffer clear
  txreg = dat;
}

One thing that could be your problem is an overflow error. If the PC sends bytes too fast then they will be missed when you transmit the buffer back. Check the OERR bit to see if this is your problem. I can't see why this would only happen with the stated values but I can't see what your ReceiveData routine does. Edit, I just realized, due to your interrupt it can't be an overflow error.

Edit, BTW, what compiler are you using. Normal convention would require pir1.txif to be pir1.TXIF, so I'm just curious.

Mike.
 
Last edited:
thanks Mike, i've plumbed your suggestions in (compiler is MikroC by the way) - unfortunately still got issues.

I'm not sending a lot of data at once so I don't think it's an overrun (I'm punching in numbers sending one by one with a terminal so lots of 'delay' there between bytes).

I've added code to initialise the buffer to 0 when the program starts, so when the program runs it displays on the terminal:

0 0 0 0 0 0
0 0 0 0 0 0 etc etc

when I transmit 0x01 - what we get is not

0 0 0 0 0 1

but actually:

00 00 00 00 f1 01

and if I then transmit 0x02 we get:

00 00 00 f1 b1 02

I can't help but think this is some sort of baudrate issue or something to do with the ftdi though i've programmed the ftdi with settings that should work (no signal inversion etc) a very strange one! I wish I had a scope.

The last received digit in the buffer is always correct now, but as soon as it gets shuffled onto the buffer it seems to go corrupt :/
 
Without seeing the ReceivedData routine it's hard to make any suggestions.

Mike.
 
sorry, i thought it was in there :/

Code:
void ReceiveData(){ //function for taking received data and putting it into buffer, checking for command etc
ActivityLEDFlag = 2; //set activity light
RX_Buffer[0] = RX_Buffer[1];
RX_Buffer[1] = RX_Buffer[2];
RX_Buffer[2] = RX_Buffer[3];
RX_Buffer[3] = RX_Buffer[4];
RX_Buffer[4] = RX_Buffer[5];
RX_Buffer[5] = RX_Temp_Buffer;
ByteReceivedFlag = 0;
}

basically it just shuffles every element of an array up one and places the new variable at the top (or bottom) depending on your perspective.

eventually code will be added to detect if a valid command is received as each 'command' will have a unique three byte header, but ive not got that far yet :(
 
It does sound like a baud rate error. Have you tried simply echoing back all characters received? I.E.
Code:
while (1){ 
 if (ByteReceivedFlag == 1){
    write(RX_Temp_Buffer);
    ByteReceivedFlag = 0;
 }
 delay_ms(2); 
}//end main loop

Mike.
 
Last edited:
Yeah I have, works absolutely fine when done like that (though if there was a baud error wouldn't as gap between transmissions allow errors to settle as the timing is set on the start bit isn't it?).

As long as we only try and handle on byte it's as happy as a pig in mud. Which might suggest (to me anyway) longer delays between transmissions, that said as this will end up being a datalogger i'd like to keep that to a minumum so it's not really the direction i want to go haha :p
 
I think I may have found your bug. Your buffer is 5 bytes long and those locations are 0 to 4 but you are using 0 to 5. You're scrolling a random value in to there.

Have fun.

Mike.
 
shouldn't be - the array is six elements long, there's six assignments in the datareceived routine, 5 of them are assigning the first five of them to the value of the element next to it and the final one where we run out assigns the latest received byte to come through the uart to the last element - unless i'm missing something blindingly obvious what should happen is the values should cascade down (the oldest being dropped completely) and the newest being the byte that was received.

should work a bit like a waterfall

byte 1 should become byte 2
byte 2 " " byte 3
byte 3 " " byte 4
byte 4 " " byte 5
byte 5 " " byte 6
byte 6 = retreive from uart






Don't think it's related to the ftdi anyway which is a bit of a releif (running firmware in pc based simulator and it's no better)
 
ooooooooooorrrr.. is it that the compiler sees:

declare array arrayname[10]; for example as declaring ten elements, not eleven?

maybe i've been out of the micro scene too long because every language i've used in a long time has gone the way of the latter
 
I'm going of

unsigned char RX_Buffer[5]; //rx receive buffer

So, 0 to 4 not 1 to 6.

Mike.
 
Right it looks like you have found the bug, it was a combination of something I overlooked and also something I deliberately and intentionally did.

I wanted six elements right, so I (quite deliberately) declared an array i.e declare array[5] - ive been away working with vb.net and I habitually take one out as with that it includes 0 as an element - looks like that doesn't work here! (doh!)

I've now just increased the element size to 6, but obviously that isn't enough as I was still looking to element zero to work with which obviously doesn't exist - that was my oversight.

A days work completed with a simple fix. I know i'm back to the world of micro.

I won't call it case closed but my computerised simulation with a array declared as six, using elements 1 to 6 seems to be working on there a lot better than the same but with 0-5. Weird!
 
well that's what i've always assumed, so my mistake was assuming the sixth (well, element 0 to be exact) would be included in the array declaration where I specified 5.

in vb.net i might say i dunno

public thisvariable(5) as string, and there I have it - six strings, 0-5 :p

doesn't work here, it's an amateur error of course but it's always the simple things isn't it.
 
public thisvariable(5) as string, and there I have it - six strings, 0-5 :p

I find that very confusing. If you say "thisvariable(5)", I would expect the array to have 5 elements, not six. .. well what can you do. Everybody wants to be different :)

In some languages (designed for mathematics) indexing starts from one, not zero. I can see how that is convenient in math intensive applications, but I do not understand that VB style.
 
VB actually does it right in a funny way. They count zero as a number and so Dim Array(0) has one element. Once you get used to it, it makes perfect sense.

Mike.
 
VB actually does it right in a funny way. They count zero as a number and so Dim Array(0) has one element. Once you get used to it, it makes perfect sense.

Mike.

Everything makes sense once you get used to it.. it is called brainwashing :)
How do you define an array of zero elements (a pointer).. Dim Array(-1)? That makes sense?

Ok.. I admit.. this is getting silly. I have to try what C compiler does with "int variable[0]" .. or "int variable[-1]"

EDIT: gave an error for foo[-1], but not even a warning for foo[0]. I don't know if that is a pointer.. what else could it be?
 
Last edited:
An array with no elements does indeed return a length of -1.

Thinking about it, it is brainwashing. The old VB6 used length 0 for an empty array but that meant you had to do for i = 0 to ubound(array)-1.

Mike.
 
An array with no elements does indeed return a length of -1.

Thinking about it, it is brainwashing. The old VB6 used length 0 for an empty array but that meant you had to do for i = 0 to ubound(array)-1.

Mike.

I never though that something like a simple array comes up and teaches me something new.. I actually had a summer job once where I had to program with VB. And I have always used C# before that.. Now I am thinking how many bugs I did because of that array thing. Well... it is better to have too long array than too short :)
 
Status
Not open for further replies.

Latest threads

New Articles From Microcontroller Tips

Back
Top