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

EX_SISR.C Advice needed.

 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
hansknec



Joined: 30 Sep 2004
Posts: 25
Location: Virginia, USA

View user's profile Send private message Visit poster's website

EX_SISR.C Advice needed.
PostPosted: Tue Aug 02, 2005 1:26 pm     Reply with quote

I have an application with multiple PICs listening to the same serial line. The master (PC) polls each PIC individually and asks it to perform a function. Each PIC of course has its own address and will not reply unless called.

I've been searching the forum for several days now and have been testing code trying to figure out the best method to use.
Each PIC would be addressed with a "PSD" followed by its address number. Following the address there is either a "?" to query the PICs current value or a word which will correspond to a function the PIC should perform.

Example: PSD03?<CR> from the master will trigger the PIC number 03 to respond with a value.

PSD03 65534<CR> from the master will tell the PIC number 03 to do some particular function.

These PICs can't spend their whole existence listening to the serial port, but they must respond within a reasonable amount of time to the master.
It appears that the best approach is to use code similar to that of EX_SISR.C and buffer the incoming serial while the PIC is off doing other things, then go back and search the buffer to see if it was addressed and then read the next characters to see if it was a query (?) or a command and respond accordingly. If they weren't addressed during that time period then they can flush the data and go off to do something else for a few hundred msec then search the buffer again.

It seems that I want to avoid reading in strings with get_string() because ALL the PICS on the network would hang up if serial comm was lost in the middle of a write and there was never a carriage return.

Am I on the right track with this? I will be using the USART on PIC16F877's at 20MHz.

I'm not too proud to accept advice or sample code. Rolling Eyes

Thanks,
John
newguy



Joined: 24 Jun 2004
Posts: 1907

View user's profile Send private message

PostPosted: Tue Aug 02, 2005 1:56 pm     Reply with quote

What you want to do is pretty straightforward. In this thread you'll find some interrupt driven code for receiving and transmitting characters via the USART: http://www.ccsinfo.com/forum/viewtopic.php?t=22221&highlight=intrda

In the RDA (receive data available) interrupt, you'll need a variable to keep track of what I call the "lock state". Basically a state machine.

In pseudocode, this is what I'd do:

lock_state = 0 (defined out of the ISR)

In the ISR:

rx_buffer[rx_wr_index] = getc()
rxd = rx_buffer[rx_wr_index]
if (rxd == 'P' && lock_state == 0), lock_state++
else if (rxd == 'S' && lock_state == 1), lock_state++
else if (rxd == 'D' && lock_state == 2), got_intro = TRUE
else lock_state = 0;
if (got_intro && rxd == 0x0d) got_intro = FALSE, okay_to_check_buffer = TRUE

What this code does is search for "PSD" - in that order, and if it receives that string, it basically "unlocks" the pic. It then continues to receive characters into rx_buffer. When it receives 0x0d (a carriage return, I believe), it then makes "okay_to_check_buffer" true.

You'd look for "okay_to_check_buffer" in your main routine. If it ever becomes true, you'd then search through rx_buffer for your ID code, and the ? or the command.

Hope this makes sense.
hansknec



Joined: 30 Sep 2004
Posts: 25
Location: Virginia, USA

View user's profile Send private message Visit poster's website

PostPosted: Tue Aug 02, 2005 7:31 pm     Reply with quote

Thanks for your help,
I understand your state machine and its ability to find the proper code, but I'm failing to understand why it is more efficient than doing a string comparison to look for the entire "PSD03" in the collected buffer? (In reality it only needs to find "D03".) Once the address is found, it would look for the ? or a word. I'm kind of new to this and I'll be the first to admit that I don't clearly understand the buffer in EX_SISR.C. If the buffer is a circular buffer that overwrites itself then it should be easy to catch my address and the data that follows it. The buffer can be compared as a string cant it?
Since the other units are also called PSD01,PSD02,.....PSD99, it will be getting the PSD and carriage returns quite often.

John
newguy



Joined: 24 Jun 2004
Posts: 1907

View user's profile Send private message

PostPosted: Tue Aug 02, 2005 7:58 pm     Reply with quote

I suppose there's no difference between doing it this way and with a string comparison. Everyone's brain works differently, and this way makes the most sense to me.

One thing I'd be a little leery about is how much code the string comparison would use compared to this method. Tied in to that is execution speed.

Another little trick that I use is to reset the index (rx_wr_index) to 0 when a valid "beginning" is detected. That way the data always falls at the same offset into the buffer. The only way the buffer ever truly wraps is if more characters than are anticipated are received without seeing the true "begin."

Here's my rda interrupt from a project I'm currently developing:

Code:
#int_RDA
void RDA_isr(void) {
   rx_buffer[rx_wr_index] = getc();
   if (rx_buffer[rx_wr_index] == 0x24) { // 0x24 = $
      rx_wr_index = 0;
      gps_found_start = TRUE;
   }
   else if ((rx_buffer[rx_wr_index] == 0x0d) && gps_found_start) { // CR
      gps_data_acquired = TRUE;
      gps_found_start = FALSE;
   }
   if (++rx_wr_index == RX_BUFFER_SIZE) {
      rx_wr_index = 0;
   }
}


This code is designed to detect a full GPS data string. The receiver I'm using allows me to turn GPS "sentences" on or off, so I only have one sentence to search. It always has the following format:

$GPRMC,blah,blah,blah,,,,,,,<CR><LF>

So if I receive a "$" (0x24), I know it's the start of the sentence, and set the index back to 0. I then fill the buffer with the received sentence until I get a CR. That signals the reception of the complete sentence, which then allows me to search through it for the information that I need: time, date, latitude, longitude. No more than about 65 characters get sent, so I set the buffer size to be 80.

The buffer wrap provision is in there just in case the pic "wakes up" or starts to receive/listen in the middle of a GPS sentence, or if the $ somehow gets corrupted and missed by the pic.

I guess that I could have done the same with a string compare or other string routines, but I did it this way. Like I said earlier: this way just makes sense to me. Do whatever makes sense for you.
hansknec



Joined: 30 Sep 2004
Posts: 25
Location: Virginia, USA

View user's profile Send private message Visit poster's website

PostPosted: Wed Aug 03, 2005 7:27 am     Reply with quote

Very clever!
Now I see it more clearly after a night of sleep. Now I just need to get my feet wet with this interrupt stuff. I'm moving over to C from PicBasic Pro, so this interrupt multitasking and real passing of variables is new to me. I took a couple of years of C++, so the syntax is familiar, but we never had to use interrupts.

My initial fear of using the get_string() was well founded because if the pic never recieved the carriage return it would hang. I can now see that in your code if the carraige return is never received it would simply never set the "data ready" bit in the main loop.

I guess I should have seen this in the other examples discussed on the forum, but I needed that push to get it.

Thanks.

John
newguy



Joined: 24 Jun 2004
Posts: 1907

View user's profile Send private message

PostPosted: Wed Aug 03, 2005 9:32 am     Reply with quote

The one thing about the built-in functions and most of the examples that come with the compiler that really bugs me: most of them aren't interrupt driven.

Interrupts are the holy grail. Why bother writing programs that don't use them?

The example I always gave to my students was: You phone up a pizza place and order a couple of pizzas. What's a better use of your time while you wait for them to arrive: sit on the couch and watch some tv, read a book, do some housework.....whatever - in other words, put your time to good use, OR......run from the front door to the back door and back to the front etc., constantly checking to see if the pizza delivery guy has arrived?

Why not put your time to good use and rely on an interrupt (the doorbell) to alert you to the arrival of the pizzas? Even if all you do with your time is waste it (i.e. by watching tv), that's still better than running back & forth trying to anticipate the delivery of the pizzas.

In other words:

Code:
while (TRUE) {
   restart_wdt();
   if (pizza_arrived) {
      pizza_arrived = FALSE;
      eat_pizza_and_drink_beer();
      burp();
   }
   if (itchy_butt) {
      itchy_butt = FALSE;
      scratch_butt();
   }
}


Most of the pic's time is spent doing absolutely nothing, but if the pizza does arrive, it can react quickly. Likewise, if you detect an itchy bottom, you can react quickly to provide relief. Very Happy
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Page 1 of 1

 
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