CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to CCS Technical Support

question about the RS232 frame between two pics
Goto page 1, 2  Next
 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
Vittorio
Guest







question about the RS232 frame between two pics
PostPosted: Mon Oct 20, 2008 4:00 am     Reply with quote

hi all,

I have read some threads in the forum asking about the communication between two pics, most of them want to send just one character , I´d like to know if it is possible to send a frame which contains int16 variable , a byte and two bits, is there a limit for its length ?

is this possible in one frame ?, or should I send byte-by-byte ?

Frame: ____Frequency(int16),status(byte),a(bit),b(bit)____


I also have another question: I read (I don´t remember exactly where), that in the begining of RS232 frame we put a symbol (like $), can anyone explain me its role ?



thanks in advance dears.
RLScott



Joined: 10 Jul 2007
Posts: 465

View user's profile Send private message

Re: question about the RS232 frame between two pics
PostPosted: Mon Oct 20, 2008 6:46 am     Reply with quote

You need to break up whatever frame of data you have into 8-bit characters and send them one at a time. In the receiving PIC you can receive those characters and then re-package the data into whatever data structure you want. But the communication is essentially character-based.

As for using a special character like "$", that is sometimes done to mark the beginning of a packet of data. It provides for error recovery so that the receiving end has a way to synchronize to the data format.
_________________
Robert Scott
Real-Time Specialties
Embedded Systems Consulting
asmallri



Joined: 12 Aug 2004
Posts: 1635
Location: Perth, Australia

View user's profile Send private message Send e-mail Visit poster's website

Re: question about the RS232 frame between two pics
PostPosted: Mon Oct 20, 2008 8:31 am     Reply with quote

RLScott wrote:
You need to break up whatever frame of data you have into 8-bit characters and send them one at a time. In the receiving PIC you can receive those characters and then re-package the data into whatever data structure you want. But the communication is essentially character-based.

As for using a special character like "$", that is sometimes done to mark the beginning of a packet of data. It provides for error recovery so that the receiving end has a way to synchronize to the data format.


I think you over simplified the answer.

The UART provides a 7 or 8 bit wide data interface. In most implementations 8 bits width is used which allows you to send any value represented in 8 bits so the payload could be an ascii character or it could be a byte. The UART frames each byte with a start bit and one or more (typically one) stop bits and optional parity bit. The framing is stripped of by the receiving UART.

When sending data out of the UART, the data is sent as a sequence of bytes. Often a programmer will convert a byte into a pair of ASCII characters representing the high nibble and low nibble of the byte respectively. In this way data is represented as a sequence of ASCII 0 to 9 and A to F characters. This enables the programmer to frame the data into a record by inserting some start-of-record and end-of-record characters. This could be <STX><ETX> or it could be with the use of a <CR> and/or <LF> at the end of a record without using a start of record identifier or any other framing sequence. The advantage with using the ASCII format and framing the data is that it is easy to identify the respective components within the data record. The disadvantage is that you need to send twice the amount of traffic over the serial port than if you sent the data raw.

Another way is to send the raw data without encoding it into ASCII. The challenge with this approach is that it is not easy to determine the start-of-record or end-of-record. One mechanism to detect an end-of-record is to reset a timer every time a character is received and wait for a timeout condition. For example, if you know you have a minimum of a 20 character gap between data records, you could set the timer to timeout after a 3 character gap. Every time a character is received the timer is reset. When the time expires you have detected the end of a data record and you can identify the individual components of the record from their respective offset from the last byte of the record. With this method you could optionally add a start of record character, such as a $, When the end-of-record gap has been detected, you then check if the first byte of the record is $ and if so, you have a high degree of confidence that you have found a correctly framed record. Note that the $ could appear anywhere inside the data so the $ start-of-record is only valid if an end-or-record gap has been detected and the $ symbol is at the correct beginning of record offset.
_________________
Regards, Andrew

http://www.brushelectronics.com/software
Home of Ethernet, SD card and Encrypted Serial Bootloaders for PICs!!
Vittorio
Guest







Re: question about the RS232 frame between two pics
PostPosted: Mon Oct 20, 2008 3:24 pm     Reply with quote

RLScott wrote:
You need to break up whatever frame of data you have into 8-bit characters and send them one at a time. In the receiving PIC you can receive those characters and then re-package the data into whatever data structure you want. But the communication is essentially character-based.

As for using a special character like "$", that is sometimes done to mark the beginning of a packet of data. It provides for error recovery so that the receiving end has a way to synchronize to the data format.


Hi RLScott,

Thank you for answering me, so what do you think about converting my data into a string then sending them at once, isn´t puts() dedicated for that ? By this way I'll be able to send more than one character at a time !


Starting with the int16 variable (the frequency)

in the first PIC :

Code:
char string[5];

#int_RDA
void RDA_isr ( )   
{
 itoa(frequency,10,string);
 puts(string);
}



Receiver PIC

Code:

#int_RDA
void RDA_isr ( )   
{

string=gets();

}


Then I'll have to convert this string to an integer, so that I get the frequency . Rolling Eyes

What do you think about this method ?
Vittorio
Guest







Re: question about the RS232 frame between two pics
PostPosted: Mon Oct 20, 2008 3:32 pm     Reply with quote

Hi asmallri,

wow, great explications sir, I´m really glad to found this kind of help here,
RLScott



Joined: 10 Jul 2007
Posts: 465

View user's profile Send private message

Re: question about the RS232 frame between two pics
PostPosted: Mon Oct 20, 2008 3:32 pm     Reply with quote

Vittorio wrote:

Code:
char string[5];

#int_RDA
void RDA_isr ( )   
{
 itoa(frequency,10,string);
 puts(string);
}


No, this is wrong because int_RDA is about receiving, and you are transmitting. Also you would never call puts() from within an interrupt routine. Also, your gets() below is going to need to see a carriage return ('\r') to mark the end of the string, so you better send one:
Code:

  printf("%5.4f\r",frequency);


Quote:

Receiver PIC

Code:

#int_RDA
void RDA_isr ( )   
{

string=gets();

}


No, this is also wrong. When int_RDA is called, there is usually just one character available to be read. You can't wait around in an interrupt routine for more characters to come in. Just use gets() in your main program.
_________________
Robert Scott
Real-Time Specialties
Embedded Systems Consulting
Guest








PostPosted: Mon Oct 20, 2008 3:41 pm     Reply with quote

puts() is still breaking down the string into bytes.

Why not just make a function that loads all of your data into a buffer array, and then sends the buffer, one byte at a time.

Something like this:
Code:

// Transmit Side

void load_buffer(int16 freq, int8 stat, int1 a, int1 b)
{
  int8 buffer[5];
  int8 i;

  buffer[0] = (int8)(freq>>4);
  buffer[1] = (int8)(freq&0x00FF);
  buffer[2] = stat;
  buffer[3] = (int8)a;
  buffer[4] = (int8)b;

  for(i=0;i<5;i++)
  {
    putc(buffer[i]);
   }
}
Vittorio
Guest







Re: question about the RS232 frame between two pics
PostPosted: Wed Oct 22, 2008 3:40 pm     Reply with quote

Hi RLScott,

Thank you again for your support Smile , I tried to modify my code as you said, but I failed to receive data.
Vittorio
Guest







PostPosted: Wed Oct 22, 2008 3:50 pm     Reply with quote

hi guest,
I think it´s a suitable idea, I´ll try it, but firstly I´ll have to think about the code of receiving them in PIC2.

By the way, I saw two examples of codes EX_SISR.C (receiver)and EX_TISR.C (sender) in the Examples folder of my compiler which use buffers and a functions called bgetc() and bputc(), I think that those examples would help me.

I´ll try and I´ll be back.

Any suggestion is welcome.
MarcosAmbrose



Joined: 25 Sep 2006
Posts: 38
Location: Adelaide, Australia

View user's profile Send private message

PostPosted: Wed Oct 22, 2008 8:45 pm     Reply with quote

Vittorio wrote:

Any suggestion is welcome.


Hi Vittorio,
I've been following this thread and I thought you might be interested in the scheme I use whenever I'm sending data in framed packets. The scheme works like this...

A packet always starts with an 0x02 (STX) and ends with an 0x03 (ETX) and you pack your data in between. This however raises the problem of what to do if you want to transmit 0x02 or 0x03 as data. To get around this problem, I send an ESC character 0x10 before the data (ie 0x02 or 0x03) then add 0x10 to the data before sending it. Likewise, if you send 0x10 as data, you send the ESC character first then add 0x10 to the data.

So for example if you had a buffer that contained the following data to be transmitted
Code:

int8 buffer[6]={0xAA,0x02, 0x55, 0x10, 0x13,0x03);

The data transmitted would be
Code:

0x02 0xAA 0x10 0x12 0x55 0x10 0x20 0x13 0x10 0x13 0x03


In your receiver code:
:-When you receive an 0x02, you know it's the start of a packet frame.
:-When you receive an 0x10, you discard it and subtract 0x10 from the next byte received.
:-When you receive an 0x03, you know you've received the last byte in the packet frame.

Using this scheme, you can be guaranteed the only time you'll receive 0x02/0x03 is at the start and end of your packet frames. Hope this helps. If you're interested, I'll post my transmit and receive interrupt routines.
Vittorio
Guest







PostPosted: Thu Oct 23, 2008 1:20 am     Reply with quote

MarcosAmbrose wrote:
Vittorio wrote:

Any suggestion is welcome.


Hi Vittorio,
I've been following this thread and I thought you might be interested in the scheme I use whenever I'm sending data in framed packets. The scheme works like this...

I´m glad to have your help and code, nevertheless I have questions/remarks about your ´coding´:
-My variables are not written in the hex base, if I have to send them by the putc() or bputc() functions, will you have to do conversions ?
-Imagine that there is a 0xFF to send, the addition of 0x10 will overflow it and distord the trasmitted data Rolling Eyes

asmallri wrote:
This could be <STX><ETX> or it could be with the use of a <CR> and/or <LF> at the end of a record without using a start of record identifier or any other framing sequence. The advantage with using the ASCII format and framing the data is that it is easy to identify the respective components within the data record. The disadvantage is that you need to send twice the amount of traffic over the serial port than if you sent the data raw.

if I´m sure that I will not use ´$´ anywhere in my transmitted data, can I use it as a start of record character and omit the end-or-record gap ?


to asmallri and everybody: how can I make <CR> and/or <LF> in C code ?, how will this send twice the amount of traffic over the serial port ? Question
MarcosAmbrose



Joined: 25 Sep 2006
Posts: 38
Location: Adelaide, Australia

View user's profile Send private message

PostPosted: Thu Oct 23, 2008 3:28 pm     Reply with quote

Vittorio wrote:
-My variables are not written in the hex base, if I have to send them by the putc() or bputc() functions, will you have to do conversions ?
Yes, If you're going to express your variables in decimal you will have to convert them. ie 0x10 as opposed to 16 decimal. You will find however that when you're working with microprocessors, it's a lot easier to think in hex.


Vittorio wrote:
-Imagine that there is a 0xFF to send, the addition of 0x10 will overflow it and distord the trasmitted data Rolling Eyes
Under the scheme I described you would only add 0x10 to your data if the data being transmitted was 0x02, 0x03 or 0x10. These three bytes have special meaning to the formatting of a packet of data. (ie they mark out the start/end of a frame and define the ESC character).



Vittorio wrote:
-to asmallri and everybody: how can I make <CR> and/or <LF> in C code ?,

This will transmit a CRLF.
Code:
printf("\n\r");

or
Code:
#define CR 0x0D
#define LF 0x0A

putc(CR);
putc(LF);
Vittorio
Guest







PostPosted: Thu Oct 23, 2008 4:44 pm     Reply with quote

MarcosAmbrose wrote:
Vittorio wrote:
-My variables are not written in the hex base, if I have to send them by the putc() or bputc() functions, will you have to do conversions ?
Yes, If you're going to express your variables in decimal you will have to convert them. ie 0x10 as opposed to 16 decimal. You will find however that when you're working with microprocessors, it's a lot easier to think in hex.


Vittorio wrote:
-Imagine that there is a 0xFF to send, the addition of 0x10 will overflow it and distord the trasmitted data Rolling Eyes
Under the scheme I described you would only add 0x10 to your data if the data being transmitted was 0x02, 0x03 or 0x10. These three bytes have special meaning to the formatting of a packet of data. (ie they mark out the start/end of a frame and define the ESC character).


Hi Marcos,


about the addition of 0x10 , excuse me I was wrong though you explained it well in the scheme (by the way, I would like to thank you for that Wink ).

MarcosAmbrose wrote:

Vittorio wrote:
-to asmallri and everybody: how can I make <CR> and/or <LF> in C code ?,

This will transmit a CRLF.
Code:
printf("\n\r");

or
Code:
#define CR 0x0D
#define LF 0x0A

putc(CR);
putc(LF);


thanks, of course in the other side, I´ll have to check whether it is present or not. but if I use your code I will not need them I think...



MarcosAmbrose wrote:
Using this scheme, you can be guaranteed the only time you'll receive 0x02/0x03 is at the start and end of your packet frames. Hope this helps. If you're interested, I'll post my transmit and receive interrupt routines.


Yes I am . Smile
MarcosAmbrose



Joined: 25 Sep 2006
Posts: 38
Location: Adelaide, Australia

View user's profile Send private message

PostPosted: Thu Oct 23, 2008 6:45 pm     Reply with quote

Vittorio wrote:
[Yes I am . Smile


Ok Vittorio, here's the "Nuts N Bolts". I have edited my routines a bit to make them more presentable. I haven't checked it for any errors, but you should still get the general idea. -Hope this helps.

Code:
#define ESCchar             0x10
#define STX                 0x02
#define ETX                 0x03
#define BUFF_SIZE       20

int1 YOU_HAVE_DATA=0;
int1 ESC_Flag=0;
unsigned int8 RXbuffer[BUFF_SIZE];
unsigned int8 BufferIndex;


Routine to send data
Code:
////////////////////////////////////////////////////////////////////////////////
// Function:   SEND_BYTE(int8 TXbyte)
//
// Purpose:    Routine sends one byte out the serial port. Byte is first checked
//             to see if it's an STX, ETX or ESC character. If so, byte is first
//             prepended with ESC character.
//
// Parameters: pTXBYTE - Byte to transmitted.
//
// Returns:    None.
////////////////////////////////////////////////////////////////////////////////
void Send_Byte(int8 pTXbyte)
{
   if((pTXbyte==STX) || (pTXbyte==ETX) || (pTXbyte==ESCchar))
   {
      putc(ESCchar);        //Send ESC character
      pTXbyte+=ESCchar;     //Add 0x10 to data and send
   }

   Putc(pTXbyte);
}


Receiver Interrupt Service Routine
Code:
////////////////////////////////////////////////////////////////////////////////
// Function:   Serial port Interrupt service routine
//
// Purpose:    Handles data received by the UART.
//
// Parameters: NONE
//
// Returns:    NONE
////////////////////////////////////////////////////////////////////////////////
#INT_RDA
void SerialPort_isr(void)
{
   unsigned int8 RXbyte;
   
   //Loop here while there are characters to retrieve from the UART buffer.
   while(kbhit())
   {
      RXbyte=getc();             //Fetch one character at a time.
     
      //Check to see if start of frame has arrived.
      if(RXbyte==STX)           
      {
         BufferIndex=0;          //If received byte is STX, then it's the start         
         ESC_Flag=0;             //of a frame, so reset the buffer index and flags
      }
         

      //Check to see if previous byte was an ESC character
      if(ESC_Flag)
      {
         RXbyte-=ESCChar;        //If the previously received byte was an ESC char
                                 //then we have to subtract 0x10 from this byte
                           
         RXBuffer[BufferIndex++] //Save data to the buffer and increment buff index
         
         ESC_Flag=0;             //Clear the ESC flag
      }
      else
      {
         //Check to see if received byte is the ESC character
         if(RXbyte==ESCchar)
         {
            ESC_Flag=1;          //If received byte is the ESC character, set
         }                       //flag so next byte will be treated correctly
         else
         {
            RXBuffer[BufferIndex++] //Save data to the buffer
         }
      }

      //Don't let RX buffer index run past end of buffer
      if(BufferIndex >= BUFF_SIZE)
      {
         BufferIndex=0;
      }

      //Check to see if end of frame has arrived.
      if(RXbyte==ETX)
      {
         //You now have a complete packet of data in the RX buffer.
         //DO NOT process the received data inside the ISR. Set a flag
         //instead and process the buffer in your main program.
         YOU_HAVE_DATA=1;
      }
   }
}

Putting it all together
Code:

void main()
{
   int8 SomeDataToSend[7]={0xAA, 0x02, 0x55, 0x10, 0x13, 0x03, 0xFF);
   int8 Idx;
   
   //Send start of frame
   putc(STX);

   //Send Data
   for(Idx=0; Idx<7; Idx++)
   {
      Send_Byte(SomeDataToSend[Idx]);
   }

   //Send end of frame
   putc(ETX);

   while(1)
   {
      if(YOU_HAVE_DATA)
      {
         //Process your received data

         YOU_HAVE_DATA=0;
      }
   }
}
Vittorio
Guest







PostPosted: Fri Oct 24, 2008 7:40 am     Reply with quote

Hi Marcos,

thank you for posting your code Wink ,
I´ll check it in my compiler, but have a little question ,below you comment that you save data to the buffer however I don´t see an assignment, did you omit it voluntarily?
Code:
         else
         {
            RXBuffer[BufferIndex++][b] //Save data to the buffer[/b]
         }


Code:
      //Check to see if previous byte was an ESC character
      if(ESC_Flag)
      {
         RXbyte-=ESCChar;        //If the previously received byte was an ESC char
                                 //then we have to subtract 0x10 from this byte
                           
         RXBuffer[BufferIndex++] [b]//Save data to the buffer and increment buff index[/b]
         
         ESC_Flag=0;             //Clear the ESC flag
      }
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Goto page 1, 2  Next
Page 1 of 2

 
Jump to:  
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