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 support@ccsinfo.com

How to get string with end character is '\n'

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



Joined: 15 Feb 2015
Posts: 39

View user's profile Send private message

How to get string with end character is '\n'
PostPosted: Fri Aug 21, 2015 1:47 am     Reply with quote

Hi,
I use Rs232 to receive data from PC with terminal software. With this code below, i can get string which is limited 5 character, more than or least than will cause error and my lcd 16x2 get string not right.
Code:

#include <16f887.h>
#fuses hs,nowdt,nolvp,noprotect,put
#use delay(clock=16M)
#include <lib_lcd.c>
#use rs232(baud=9600,parity=N,xmit=PIN_C6,rcv=PIN_C7,bits=8)
unsigned int data[16],i=0,count;

#int_rda
void rda_isr()
{
   for(i=0;i<5;i++)     {data[i]=getch();}
}

void main()
{
   set_tris_b(0x0f);port_b_pullups(0x0f);
   enable_interrupts(global);
   enable_interrupts(int_rda);
   lcd_init();
   while(true)
   {
      lcd_gotoxy(1,1);
      for(i=0;i<5;i++)     {printf(lcd_putc,"%c",data[i]);}
   }
}

But if a string which i don't know length, how can i get it .EX: i send from PC to pic "Hello ", after i send "Hello world ","abcxyz"... How can i know this length? My terminal have function add '\n' in the end of string, maybe i can use this function to know length of string. But i don't know how to use it to recognize length of string. I was trying every way but it seems not effective. My lcd can not get string in row 1 with random length.

kWoody_uk



Joined: 29 Jan 2015
Posts: 47
Location: United Kingdom

View user's profile Send private message

PostPosted: Fri Aug 21, 2015 2:06 am     Reply with quote

First things first. You're not using your rda_isr in a good way. You should only be collecting one character every time the rda isr fires. Very rarely (if ever) wait in an interrupt.

Look at the example file EX_SISR.C to see a way of buffering received chars.

Secondly, why have you made the variable i global? Only make variables global if really necessary.

Keith
talamahahahe



Joined: 15 Feb 2015
Posts: 39

View user's profile Send private message

PostPosted: Fri Aug 21, 2015 2:31 am     Reply with quote

in ex.sisr, i read on this line
Code:
next_in=(next_in+1) % BUFFER_SIZE;

but i don't understand what purpose it's? can you explain it for me. Thank Smile
kWoody_uk



Joined: 29 Jan 2015
Posts: 47
Location: United Kingdom

View user's profile Send private message

PostPosted: Fri Aug 21, 2015 2:55 am     Reply with quote

Yeah, I know what you mean. It's not the most readable code, but it is efficient, but ONLY when used with buffer sizes of 2^n

Effectively it's just range checking buffer indexer and wrapping if necessary; similar to:-

Code:

if ( next_in < ( BUFFER_SIZE - 1 ) ) {
    next_in++;
} else {
    next_in = 0;
}



Keith
talamahahahe



Joined: 15 Feb 2015
Posts: 39

View user's profile Send private message

PostPosted: Fri Aug 21, 2015 3:10 am     Reply with quote

thank you so much kWoody_uk. Very Happy
But can you explain what different between my way and ccs's way get data. what advance CCS's way ?? because i see ex in ccs just get a 1 char but it's long and more difficult to understand than Smile
kWoody_uk



Joined: 29 Jan 2015
Posts: 47
Location: United Kingdom

View user's profile Send private message

PostPosted: Fri Aug 21, 2015 3:24 am     Reply with quote

With your method, when the first character is received, the interrupt is entered, and will STAY in the interrupt until another 4 characters are received. In other words none of your main-line code will continue until all 5 chars have been received.

With CCS method, the interrupt is entered, stores the received char, increments the buffer indexer and exits the interrupt, meaning the main-line code is able to continue running, so you will be able to do other things instead of just waiting for characters to arrive.

Think of interrupts as your phone ringing. Imagine you're cleaning your house and the phone rings. You have to stop work, answer the phone (interrupt entered), talk for a short period and then hang up (interrupt exits). Only then can you continue cleaning the house.


Keith
talamahahahe



Joined: 15 Feb 2015
Posts: 39

View user's profile Send private message

PostPosted: Fri Aug 21, 2015 6:06 am     Reply with quote

I understand now, thank you so much, kWoody_uk Very Happy I will continue study ex.sisr in ccs Smile. Oh i forget, one more question in the title, how can i get string with '\n' char end of string ? In ex_sisr just have enter interrupts to get 1 character.
ezflyr



Joined: 25 Oct 2010
Posts: 1019
Location: Tewksbury, MA

View user's profile Send private message

PostPosted: Fri Aug 21, 2015 8:53 am     Reply with quote

Hi,

Who decides what the contents of the transmitted string will be? If you have control over that, it's best to have both a 'Start' character, and an 'End' character to mark the beginning and end of the string. I typically use '#' or '!' for my 'Start' characters, and '\n' or '\r' for my 'End' characters. If the data you are transmitting is (relatively) infrequent, and small in volume, a 'linear' buffering scheme is entirely sufficient, and is a bit easier to understand. I posted some code snippets that will get you going in this thread:

http://www.ccsinfo.com/forum/viewtopic.php?t=54142

If you don't have control over the transmitted data, then you will simply have to watch for the '\n' character in the data stream, and then assume that the next character starts the incoming data string. This technique is less efficient, and more prone to error, but can be made to work if sufficient care is taken.
_________________
John

If it's worth doing, it's worth doing in real hardware!
talamahahahe



Joined: 15 Feb 2015
Posts: 39

View user's profile Send private message

PostPosted: Fri Aug 21, 2015 9:47 am     Reply with quote

Hi ezflyr
Thank you for your share,i appreciate it, i was use your code but i just get once time from PC, when i send second time, it seem not right ,my lcd 16x2 show trash

this is code in main to show data to lcd
Code:

void main()
{
   unsigned int i;
    enable_interrupts(INT_RDA);
   enable_interrupts(GLOBAL);
   lcd_init();
   set_tris_b(0xff);port_b_pullups(0xff);
   while(1)
   {
      if ( RX_Command_Ready == TRUE )
      {       
         //disable_interrupts(GLOBAL);
         RX_Command_Ready = FALSE;

            lcd_gotoxy(1,1);
            for(i=0;i<10;i++) printf(lcd_putc,"%c",RxBuffer[i]);
       }
   }
}

The remaining of code like your code
talamahahahe



Joined: 15 Feb 2015
Posts: 39

View user's profile Send private message

PostPosted: Fri Aug 21, 2015 10:01 am     Reply with quote

I was try on this ex_sisr too and write program to get string with end char is '\n' ,i was success in get string with unknown length. But now , i can't send data to PC ,Maybe i was use so many for loop in main. This is my code ,how can resolve this problem.

This part like a ex_sisr to get character so don't care about it
Code:

#int_rda
void rda_isr()
{
   unsigned int temp;
   buffer[next_in]=getc();
   temp=next_in;
   next_in=(next_in + 1) % buffer_size;
   if(next_in==next_out)      next_in=temp;
}

unsigned int get_byte()
{
   unsigned int c;
   while(next_in==next_out);
   c=buffer[next_out];
   next_out=(next_out + 1) % buffer_size;
   return c;
}


This code is used to send string when push button
Code:

void Send_data()
{
   if(!input(pin_b0))
   {
      delay_ms(30);
      if(!input(pin_b0))
      {
         printf("Hello world !!! \n");
         while(!input(pin_b0));
      }
   }
}


And This main ,my trouble in it Sad
Code:

void main()
{
   unsigned int data[32],i=0,count=0;
   set_tris_b(0xff);port_b_pullups(0xff);
   enable_interrupts(global);
   enable_interrupts(int_rda);
   lcd_init();
   while(true)
   {
      send_data();
     
      for(i=0;i<32;i++)
      {
         data[i]=get_byte();                 //get each character in buffer
         count++;                            // count length of string
         if(data[i]=='\n')    {break;}       // get each byte until meet a '\n' then exit for
      }
      lcd_gotoxy(1,1);                       
      for(i=0;i<count;i++)                   //show string is received in lcd 16x2.Note: just show max 16 character cause lcd16x2 have 16 column
      {
         if(data[i]=='\n')       printf(lcd_putc,"               ");
         else                    printf(lcd_putc,"%c",data[i]);
      }
      count=0;                               //reset count
      lcd_gotoxy(1,2);printf(lcd_putc,"                 ");
     
   }
}
ezflyr



Joined: 25 Oct 2010
Posts: 1019
Location: Tewksbury, MA

View user's profile Send private message

PostPosted: Fri Aug 21, 2015 10:10 am     Reply with quote

Hi,

Change this line:

Code:

#use rs232(baud=9600,parity=N,xmit=PIN_C6,rcv=PIN_C7,bits=8)


to this line:

Code:

#use rs232(baud=9600,parity=N,xmit=PIN_C6,rcv=PIN_C7,bits=8, Errors)


Your hardware UART is probably overflowing and locking up. The 'Errors' keyword in the #use rs232 declaration will automatically cure any UART buffer overflows.....

If this doesn't help, post a small, complete & compilable program that we can test!
_________________
John

If it's worth doing, it's worth doing in real hardware!
talamahahahe



Joined: 15 Feb 2015
Posts: 39

View user's profile Send private message

PostPosted: Sat Aug 22, 2015 1:51 am     Reply with quote

Dear ezflyr.

I was try on your change. But it seem not different, My LCD get once time is good ,second time and after then ,it get data not right. This is my part and complete code.

this part is declare, it like your code
Code:

#include <16f887.h>
#fuses hs,nowdt,nolvp,noprotect,put
#use delay(clock=16M)
#include <lib_lcd.c>
#use rs232(baud=9600,parity=N,xmit=pin_c6,rcv=pin_c7,bits=8, Errors)

int RX_Command_Ready;     
#define RX_SIZE 10         
char RxBuffer[RX_SIZE];   
int Index = 0; 


This part is enter interrupts when receive string
Code:

#INT_RDA 
void rs232_isr(void)
{
   char temp;   
   temp = getc();   
   if (temp == '#')
   {   
      Index = 0;
      RxBuffer[Index] = temp;
      Index++;
      return;
   }   
   if (temp == '\n')
   {
      RxBuffer[Index] = temp;
      RX_Command_Ready = TRUE;
      return;
   }   
   RxBuffer[Index]=temp;

   if ( Index >= (RX_SIZE - 1) )
      Index = 0;
   else
      Index++;
}


and This is main
Code:

void main()
{
   set_tris_b(0xff);port_b_pullups(0xff);
   enable_interrupts(global);
   enable_interrupts(int_rda);
   lcd_init();
   while(true)
   {
      lcd_gotoxy(1,1);
      if ( RX_Command_Ready == TRUE )
      {       
         RX_Command_Ready = FALSE;
         printf(lcd_putc,"%s",RxBuffer);
      }
   }
}
talamahahahe



Joined: 15 Feb 2015
Posts: 39

View user's profile Send private message

PostPosted: Sat Aug 22, 2015 1:52 am     Reply with quote

This is my complete code
Code:

#include <16f887.h>
#fuses hs,nowdt,nolvp,noprotect,put
#use delay(clock=16M)
#include <lib_lcd.c>
#use rs232(baud=9600,parity=N,xmit=pin_c6,rcv=pin_c7,bits=8, Errors)

int RX_Command_Ready;     
#define RX_SIZE 10         
char RxBuffer[RX_SIZE];   
int Index = 0;         

#INT_RDA 
void rs232_isr(void)
{
   char temp;   
   temp = getc();   
   if (temp == '#')
   {   
      Index = 0;
      RxBuffer[Index] = temp;
      Index++;
      return;
   }   
   if (temp == '\n')
   {
      RxBuffer[Index] = temp;
      RX_Command_Ready = TRUE;
      return;
   }   
   RxBuffer[Index]=temp;

   if ( Index >= (RX_SIZE - 1) )
      Index = 0;
   else
      Index++;
}

void main()
{
   set_tris_b(0xff);port_b_pullups(0xff);
   enable_interrupts(global);
   enable_interrupts(int_rda);
   lcd_init();
   while(true)
   {
      lcd_gotoxy(1,1);
      if ( RX_Command_Ready == TRUE )
      {       
         RX_Command_Ready = FALSE;
         printf(lcd_putc,"%s",RxBuffer);
      }
   }
}
ezflyr



Joined: 25 Oct 2010
Posts: 1019
Location: Tewksbury, MA

View user's profile Send private message

PostPosted: Sat Aug 22, 2015 7:22 am     Reply with quote

Hi,

Your code has a lot of 'non-optimal' constructs, and one fatal flaw. I've corrected everything below:

Code:

#include <16f887.h>
#fuses hs,nowdt,nolvp,noprotect,put
#use delay(clock=16M)
#include <lib_lcd.c>
#use rs232(baud=9600,parity=N,xmit=pin_c6,rcv=pin_c7,bits=8, Errors, stream=PC)

int1 RX_Command_Ready = False;     
#define RX_SIZE 10         
char RxBuffer[RX_SIZE];   
int8 Index = 0;         

#INT_RDA
void rs232_isr(void)
{
   char temp;   
   temp = fgetc(PC);   
   if (temp == '#')
   {   
      Index = 0;
      RxBuffer[Index] = temp;
      Index++;
      return;
   }   
   if (temp == '\n')
   {
      RxBuffer[Index] = temp;
      RX_Command_Ready = TRUE;
      return;
   }   
   RxBuffer[Index]=temp;

   if ( Index >= (RX_SIZE - 1) )
      Index = 0;
   else
      Index++;
}

void main()
{
   set_tris_b(0xff);port_b_pullups(0xff);
   lcd_init();
   delay_ms(100);
   enable_interrupts(int_rda);
   enable_interrupts(global);

   while(true)
   {
     
      if ( RX_Command_Ready == TRUE )
      {       
         disable_interrupts(int_rda);
         RX_Command_Ready = FALSE;
         lcd_gotoxy(1,1);
         RxBuffer[Index++] = '\0';
         fprintf(PC, "RxBuffer: %s\n\r", RxBuffer); //echo back to the PC
         printf(lcd_putc,"%s",RxBuffer);
         enable_interrupts(int_rda);
      }
   }
}


The 'fatal' flaw is that you are attempting to treat 'RxBuffer' as a string, when in reality it is only an array of characters. To make it a 'string', you must 'null terminate' the array of characters to make it a string. The 'C' language doesn't really have a true 'string' data type, but rather a string is simply an array of characters that is null terminated with the '0' character.

I don't have time to test this, but it should work OK now. I'm also assuming this is real hardware, right??
_________________
John

If it's worth doing, it's worth doing in real hardware!
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