|
|
View previous topic :: View next topic |
Author |
Message |
talamahahahe
Joined: 15 Feb 2015 Posts: 39
|
How to get string with end character is '\n' |
Posted: Fri Aug 21, 2015 1:47 am |
|
|
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
|
|
Posted: Fri Aug 21, 2015 2:06 am |
|
|
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
|
|
Posted: Fri Aug 21, 2015 2:31 am |
|
|
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 |
|
|
kWoody_uk
Joined: 29 Jan 2015 Posts: 47 Location: United Kingdom
|
|
Posted: Fri Aug 21, 2015 2:55 am |
|
|
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
|
|
Posted: Fri Aug 21, 2015 3:10 am |
|
|
thank you so much kWoody_uk.
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 |
|
|
kWoody_uk
Joined: 29 Jan 2015 Posts: 47 Location: United Kingdom
|
|
Posted: Fri Aug 21, 2015 3:24 am |
|
|
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
|
|
Posted: Fri Aug 21, 2015 6:06 am |
|
|
I understand now, thank you so much, kWoody_uk I will continue study ex.sisr in ccs . 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
|
|
Posted: Fri Aug 21, 2015 8:53 am |
|
|
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
|
|
Posted: Fri Aug 21, 2015 9:47 am |
|
|
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
|
|
Posted: Fri Aug 21, 2015 10:01 am |
|
|
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
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
|
|
Posted: Fri Aug 21, 2015 10:10 am |
|
|
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
|
|
Posted: Sat Aug 22, 2015 1:51 am |
|
|
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
|
|
Posted: Sat Aug 22, 2015 1:52 am |
|
|
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
|
|
Posted: Sat Aug 22, 2015 7:22 am |
|
|
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! |
|
|
|
|
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
|