|
|
View previous topic :: View next topic |
Author |
Message |
trevor
Joined: 03 Mar 2004 Posts: 2
|
Serial Reception on the PIC16F877 |
Posted: Wed Mar 03, 2004 7:09 pm |
|
|
hello everyone,
i am trying to do serial communication between a pic 16f877 and the PC. I am using the RDA interrupt but i am getting problems receiving the data. I can receive either a single character or a floating point number but i must be able to distinguish between them and determine which character was received. the reception of the single character works but the floating point reception is giving trouble.
i cannot see what is the problem with the code. if anyone can help please do.
thanks in advance.
Code: |
#define BUFFER_SIZE 9
char rx_data[BUFFER_SIZE];
char rx_data_L1[BUFFER_SIZE];
char rx_data_L2[BUFFER_SIZE];
int i = 0;
int count = 0;
int rx = 0;
int index = 0;
char mode;
const char Initialize = 'I';
const char Remote = 'R';
const char Stop = 'S';
const char Request = 'Q';
const char Ang_Arm_1 = '$';
const char Ang_Arm_2 = '@';
char rx_char = ' ';
#INT_RDA
serial_int()
{
if (count == 0)
{
rx_data_L1[0] = '$';
rx_data_L2[0] = '@';
for(i = 1; i < BUFFER_SIZE - 1; i++)
{
rx_data_L1[i] = '0';
rx_data_L2[i] = '0';
}
rx_data_L1[BUFFER_SIZE - 1] = '\0';
rx_data_L2[BUFFER_SIZE - 1] = '\0';
}
rx_data[index] = RCREG;
if ((rx_data[0] == Ang_Arm_1) || (rx_data[0] == Ang_Arm_2))
index = 1;
else
index = 0;
if (rx_data[0] == Initialize)
{
mode = Initialize;
count = 0;
return;
}
if (rx_data[0] == Remote)
{
mode = Remote;
count = 0;
return;
}
if (rx_data[0] == Stop)
{
mode = Stop;
count = 0;
return;
}
if (rx_data[0] == Request)
{
mode = Request;
count = 0;
return;
}
if (rx_data[0] == Ang_Arm_1)
{
mode = Ang_Arm_1;
rx_data_L1[count] = rx_data[index];
count++;
rx_data_L1[count]='\0';
if (count == BUFFER_SIZE-2)
{
rx_data_L1[BUFFER_SIZE-1]='\0';
count = 0;
return;
}
}
if (rx_data[0] == Ang_Arm_2)
{
mode = Ang_Arm_2;
rx_data_L1[count] = rx_data[index];
count++;
rx_data_L1[count]='\0';
if (count == BUFFER_SIZE-2)
{
rx_data_L2[BUFFER_SIZE-1]='\0';
count = 0;
return;
}
}
bit_clear(pir1,5);
}
void main()
{
enable_interrupts(global);
enable_interrupts( int_rda);
for(count=0; count<=BUFFER_SIZE;count++)
{
rx_data[count] = '0';
rx_data_L1[count] = '0';
rx_data_L2[count] = '0';
}
count = 0;
printf( "char Initialize = %c, char Remote = %c, ",Initialize, Remote);
printf( "char Stop = %c, char Request = %c ", Stop, Request);
while(1)
{
delay_ms(5000);
printf( "rx_data[0] = %c\n", rx_data[0]);
for(i=1;i<BUFFER_SIZE-1; i++)
{
rx_data_L1[i-1] = rx_data_L1[i];
}
rx_data_L1[BUFFER_SIZE-1] = '\0';
printf("rxdata = %s", rx_data_L1);
if (mode == Ang_Arm_1)
printf("Received data L1 is : %s\n", rx_data_L1);
if (mode == Ang_Arm_2)
printf("Received data L2 is: %s\n", rx_data_L2);
if((mode ==Initialize)|| (mode ==Remote)||(mode ==Stop) || (mode ==Request))
printf("Received data is mode: %c\n", mode);
}
} |
|
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Wed Mar 03, 2004 7:52 pm |
|
|
Aside from other comments, I'll just make these:
Where does your data stream come from ?
Do you design the format, or is determined by
another device and it can't be changed ?
What is the format of the incoming data stream ?
Is it entirely ASCII characters ?
Can you post a sample of the incoming data stream ?
ie., Post an example that shows all of the kinds
of data fields that you wish to parse. Show the complete
stream, including all field separators, start and end of
message characters, control characters, etc. |
|
|
trevor
Joined: 03 Mar 2004 Posts: 2
|
|
Posted: Thu Mar 04, 2004 10:40 am |
|
|
the data stream is supposed to come from MATLAB but for now I am testing it through Hyperterminal. the characters can be either R, S, Q, I. i also want to send two floating point numbers, but in order to distinguish them, I decided to append a character to the start the '$' for one value and the '@' for the other. the data is sent as a string with a '\n' terminator.
the following is the only possible data formats that can be sent
Initialize = I
Remote = R
Stop = S
Request = Q
Ang_Arm_1 = $90.980
Ang_Arm_1 = $-90.98
Ang_Arm_2 = @123.45
Ang_Arm_2 = @-139.5
the data for Ang_Arm_1 and Ang_Arm_2 is formatted with the start character and six characters always.
all are ternimated by the \n character.
i'm not sure if that helps. if you want anything else i will try to give more info.
thanks. |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Thu Mar 04, 2004 1:25 pm |
|
|
I would do this by:
1. Use an interrupt-driven software fifo to receive the incoming
RS232 characters. See the CCS example file, EX_SISR.C.
This would be the only code in the #int_rda routine.
2. In main(), I would have a while(1) loop, in which I check to see
if a char is available in the receive fifo. If so, I would call
another routine (see EX_SISR.C) to get the char from the fifo.
3. I would call each of your strings a "message". I would have a
state variable in main(), that told me whether I was "within a
message" or not. Initially, when the program starts, we are not
within a message.
4. I would then scan the incoming characters from the receive fifo,
and look for one of your special "Message start" chars.
As soon as I found one, I would put it into another buffer,
that holds an incoming message. I would set the flag that indicates
we are "within a message". I would continue to put chars
into the buffer, until I receive a "message done" char (ie., \n).
I would also check to make sure I don't overflow the message
buffer. Make it long enough to hold the longest message, plus
a couple more chars.
5. After receiving a complete message, I would call a routine to
parse the message. I would check the first char in the message
buffer, to determine how to decode the string. I would use
a switch-case statement for this (or a chain of if-else statements).
6. If the message is a floating point value, I would first over-write
the terminator character '\n' with a 0, in order to turn the message
into a string. Then I would call the atof() routine, which converts
a string into a floating point variable. Then, based on the initial
message char, '@' or '$', I would put the float into the proper
variable.
7. You have some other single-byte commands. As soon as you
receive one of those, you can execute the command.
Use a switch-case statement to parse the command byte and
call the proper routine. Within each case statement, you should
verify that other setup parameters are valid, before executing
the command. (ie., Don't let your hardware do anything that
is grossly incorrect). |
|
|
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|