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

Serial data filter

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







Serial data filter
PostPosted: Sat Mar 17, 2007 6:39 am     Reply with quote

Hi all,
i am new in PIC programming and requesting your help. i am using PIC16F876 to communicate with the radio links. the receiver is connected to UART. input will be from computer hyperterminal and pic will receive the data and control motor. for test basis, i wrote a program which will filter only '2' if key 2 is pressed through hyperterminal and return this key . but it's doing nothing. could you pls advice me where i am doing wrong. pls help me.
Code:

#include <16F876.h >
#use delay(clock=4000000)
#fuses XT,NOPROTECT, NOPUT, NOWDT, NOBROWNOUT, NOLVP
#use rs232(baud=19200, xmit=PIN_C6, rcv=PIN_C7, errors )

#define RX_BUFFER_SIZE  32

char data;

#INT_RDA

void rcv_isr(){
   
   char rx_buffer[RX_BUFFER_SIZE];
         int i=0;
         char rxd;

            rx_buffer[i]=getc();
            rxd=rx_buffer[i];
            i++;
      if (i>RX_BUFFER_SIZE){
               i=0;
                           }  //end if
      if (rxd=='2'){
            data=rxd;
                  }  //end if     

}

void main (){

enable_interrupts(global);
enable_interrupts(INT_RDA);


putc(data);


}
Ttelmah
Guest







PostPosted: Sat Mar 17, 2007 9:25 am     Reply with quote

Start with the declaration of the buffer. This declares the buffer _each time the routine is called_. You do not want this, you want a buffer, that stays fixed between calls (static...). Then the declaration of the counter. Your declaration, _clears_ this each time the interrupt occurs. Again you want a declaration that remains _static_.
If the buffer is latter to be used by external code, it should really be 'global' (declared like the 'data' value).
Then you have the problem, that the 'main', doesn't wait for a character to arrive, and will drop of the end of the code, sending the processor to sleep...
Code:

#include <16F876.h >
#use delay(clock=4000000)
#fuses XT,NOPROTECT, NOPUT, NOWDT, NOBROWNOUT, NOLVP
#use rs232(baud=19200, xmit=PIN_C6, rcv=PIN_C7, errors )

#define RX_BUFFER_SIZE  32

char data;
int1 havedata=false;

#INT_RDA
void rcv_isr(){
   static char rx_buffer[RX_BUFFER_SIZE];
   static int i=0;
   char rxd;

   rxd=getc();
   rx_buffer[i]=rxd;
   //indexed accesses take longer than simple accesses - this way round
   //only one is needed
   if (++i>RX_BUFFER_SIZE) i=0;
   if (rxd=='2'){
       data=rxd;
       havedata=true;
   }  //end if     
}

void main (){
   enable_interrupts(global);
   enable_interrupts(INT_RDA);
   while (true) {
       if (havedata) {
           putc(data);
           havedata=false;
       }
   }
}


Best Wishes
MHasan
Guest







PostPosted: Sun Mar 18, 2007 5:08 am     Reply with quote

Dear Ttelmah, thank you very much for ur help and advice. your code worked fine and i understood my problems. i have modified the code again for testing before implementing to final control. but i have found that the processor is not receiving any data while it's busy. for example i have pulled the line high for 5 sec while it receives character '2'. but at that time if i transmit another or same character, the data is seems to be lost. another thing is that it takes two key stroke to receive a data. could you pls advice me once again. i really appreciate your help.
Code:

#include <16F876.h >
#use delay(clock=4000000)
#fuses XT,NOPROTECT, NOPUT, NOWDT, NOBROWNOUT, NOLVP
#use rs232(baud=19200, xmit=PIN_C6, rcv=PIN_C7, errors )

#define RX_BUFFER_SIZE  32

int data;
int1 havedata=false;

#INT_RDA
void rcv_isr(){
   static char rx_buffer[RX_BUFFER_SIZE];
   static int i=0;
   char rxd;

   rxd=getc();
   rx_buffer[i]=rxd;
   //indexed accesses take longer than simple accesses - this way round
   //only one is needed
   if (++i>RX_BUFFER_SIZE) i=0;
   if (rxd=='2'){
      data=2;
   havedata=true;
        }
   else if(rxd=='4'){
      data=4;
   havedata=true;
   }     
       
}

void main (){
   enable_interrupts(global);
   enable_interrupts(INT_RDA);
   while (true) {
       if (havedata) {

           switch(data){
                 case  2: output_high(PIN_C0);
                          delay_ms(5000);
                          output_low(PIN_C0);
                          break;
                  case 4: output_high(PIN_C1);
                           delay_ms(5000);
                           output_low(PIN_C1);
                          break;
                default:  break;
           }
           havedata=false;
       }
   }
}
Ttelmah
Guest







PostPosted: Sun Mar 18, 2007 8:03 am     Reply with quote

The problem here is that the code only uses one flag, 'havedata', to say that a single character ispresent. If _two_ characters come, before the first is dealt with (while you are in a long delay for example), one will get lost. It'll be received, and in the buffer, but the flag only gets set once.
Now the answer to this, is to properly handle the buffer. :-)
Code:

#include <16F876.h >
#use delay(clock=4000000)
#fuses XT,NOPROTECT, NOPUT, NOWDT, NOBROWNOUT, NOLVP
#use rs232(baud=19200, xmit=PIN_C6, rcv=PIN_C7, errors )

#define RX_BUFFER_SIZE  32
char rx_buffer[RX_BUFFER_SIZE]; //declare this as a global variable
int i=0;  //counter for inputting data
int o=0; //counter for _outputting_ data
//Check if buffer is not empty
#define havedata (i!=o)

int buff_getc(void) {
   //routine to retrieve one character from the buffer
   int chr=0;
   if (havedata) {
      //Here a character is waiting
      chr=rx_buffer[o];
      //alternative way of limiting the count
      o = ((o+1) & (RX_BUFFER_SIZE-1));
   }
   return chr;
}

#INT_RDA
void rcv_isr(){
   int rxd;
   rx_buffer[i]=getc();
   i=((i+1) & (RX_BUFFER_SIZE-1));
   if (i==o) {
      //buffer overflow, if the new 'input' pointer, matches the current
      //output pointer - throw away the oldest character.
      o = ((o+1) & (RX_BUFFER_SIZE-1));
   }   
}

void main (){
   enable_interrupts(global);
   enable_interrupts(INT_RDA);
   while (true) {
       if (havedata) {
          //retrieve the character fom the buffer
          data=buff_getc();
          switch(data){
                 case  2: output_high(PIN_C0);
                          delay_ms(5000);
                          output_low(PIN_C0);
                          break;
                  case 4: output_high(PIN_C1);
                           delay_ms(5000);
                           output_low(PIN_C1);
                          break;
                default:  break;
           }
       }
   }
}

Now, there will still be a problem, if more than 32 characters arrive in the very long delays you have. There are solutions to this, using the hardware timers, and a state machine. However this will work except for this situation...

Best Wishes
Guest








PostPosted: Sun Mar 18, 2007 10:05 am     Reply with quote

Dear Ttelmah, thank you very much for your help once again. i tried to test again based upon your modification and it meet my criteria. but as a new programmer i am in confusion with some of your statements. i hope it wont bother you to explain. for the input and output counter increment why did you used
Code:
i=((i+1) & (RX_BUFFER_SIZE-1));

i have tested with

i++;
if (i==32){
i=0;
o=0;
}

and it seems to me that it worked . could you please explain my confusion.

once again thank you and best regards.
Ttelmah
Guest







PostPosted: Sun Mar 18, 2007 12:57 pm     Reply with quote

Yes, Smile
The '&' statement, is a 'bitwise logical and'. Think in binary. RX_BUFFER_SIZE-1, gives '31'. In binary: 00011111. Call this the 'mask'. If you take a number, and 'and' it with this, you get:
Code:

number  result
1           1   
2           2
3           3

......

30         30
31         31
32         0

Now the last, is the 'interesting' line.
Looking in binary, '32', is
00100000
You get a '1', whereever there is a '1' in both the number, _and_ the 'mask', and a zero everywhere else. Hence the name.
When the count moves beyond the low five bits of the mask, the high bit gets cropped.
So for the explicit case of a value like '31' (a value that has ones in all the right hand bits), the '&' gives the same result as performing the 'modulus' function, with a value one greater.
Now it sounds complex, but the nice thing is that the '&' operator, is a core function of the processor, and for a single byte value, is done in just one instruction.
So, the code for a binary buffer size (like 16, 32, 64), performs the buffer handling about as efficiently as possible. Smile

Best Wishes
Guest








PostPosted: Mon Mar 19, 2007 2:53 pm     Reply with quote

Thank you very much. i really appreciate ur help and advice. keep it up.
best wishes.
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