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

RS232 with PIC18F2520, can not receive data

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



Joined: 13 Jul 2023
Posts: 37

View user's profile Send private message

RS232 with PIC18F2520, can not receive data
PostPosted: Fri Jul 28, 2023 1:47 pm     Reply with quote

Hello everyone,

I am trying to send and receive data between PC and PIC via Putty application.

I can use printf(), putc(), puts() functions properly and I can see the data I am sending from the terminal. But when I try to send data from terminal to PIC, none of getc(), gets(), scanf() work.
I dont understand how to use these receive functions properly. If I can transmit properly from the serial port, why can't I receive with the same configuration?

When I check it with Scope, I can see the signal coming out of the terminal, but for some reason I cannot receive that signal with the PIC.

I tried the example EX_RS232_BUFFER.c and also so many different ways.
Do I need to use interrupt to receive signal from RS232? Or can I get messages by periodically querying in a loop?

Since I can't receive data yet, I didn't need to share a code, but my configuration is as follows.

Code:

#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7, parity=N, stop=1, bits=8)
#use delay(internal=32MHz)


Here are my settings on Putty:

[img] https://ibb.co/bKTYG5Y [/img]

Please help me how to properly receive 4 bytes of data coming from rs232 line?
temtronic



Joined: 01 Jul 2010
Posts: 9243
Location: Greensville,Ontario

View user's profile Send private message

PostPosted: Fri Jul 28, 2023 2:04 pm     Reply with quote

you'll need to add 'errors' to the #USE RS232 (.....options...... ) otherwise the incoming UART buffer will 'overrun' and the UART will 'lockup'.
Also pretty sure use delay() has to come before use rs232()
PrinceNai



Joined: 31 Oct 2016
Posts: 480
Location: Montenegro

View user's profile Send private message

PostPosted: Fri Jul 28, 2023 3:20 pm     Reply with quote

For me the easiest way was always with an interrupt, something like this:
Code:

// variables for the UART
char SerialData = 0;             // variable to hold serial data
#define BUFFER_SIZE 4            // data buffer
char Buffer[BUFFER_SIZE];
int8 NextBuffer = 0; 

// ******************************************************************
// RECEIVE DATA FROM SERIAL
// ******************************************************************
#INT_RDA
void  RDA_isr(void)
{
   SerialData = fgetc();               // get received char from UART and clear interrupt flag
   Buffer[NextBuffer] =  SerialData;   // get the data in the buffer
   NextBuffer++;                       // increment IN pointer
   if(NextBuffer == BUFFER_SIZE) {     // if the buffer is full, go back to 0         
      NextBuffer = 0;                           
   }
}


You can add something to turn on a LED and stop inside the interrupt to check if you even got there when you sent data from Putty.
bmete



Joined: 13 Jul 2023
Posts: 37

View user's profile Send private message

PostPosted: Fri Jul 28, 2023 8:23 pm     Reply with quote

temtronic wrote:
you'll need to add 'errors' to the #USE RS232 (.....options...... ) otherwise the incoming UART buffer will 'overrun' and the UART will 'lockup'.
Also pretty sure use delay() has to come before use rs232()


I upgraded my code now I can receive data from terminal. No communication if I don't nibble the enable bit (PIN_C2).
my main goal is to send and receive 8 bytes of data. I know this is not possible with getc(), but I could not use the gets() function.

Code:

#include <18F2520.h>
#device ADC=10
#FUSES NOWDT                    //No Watch Dog Timer
#use delay(internal=32MHz)
#use FIXED_IO(C_outputs=PIN_C2)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7, parity=N, stop=1, bits=8, ERRORS)
void main()
{
   while(TRUE)
   {

           printf("Enter:  \n");
           output_low(PIN_C2);
           delay_ms(3);
           int32 T = getc();
           delay_ms(3);
           output_high(PIN_C2);
           delay_ms(3);
           printf("\n %Lu ", T);   
           printf(" %c ", T);
           printf(" %X \n", T);
}
}


When I run this code and enter abcd in the terminal, the "O▒▒▒" appears, then it prints each byte one by one as I want. But the problem is, I don't understand why it calls printf(Enter: ) before other printfs.

Sometimes characters that I have never entered appear in the terminal, sometimes different characters appear even though I have entered the same data.

this is terminal:
[img] https://ibb.co/7vzhRzs [/img]

No matter how much data I want to send, I think I can only receive 3 characters.

There is a problem but I haven't been able to solve it yet.
Ttelmah



Joined: 11 Mar 2010
Posts: 19539

View user's profile Send private message

PostPosted: Sat Jul 29, 2023 2:05 am     Reply with quote

Firs thing, it sends the Enter message where you have it coded. You have it
in front of the getc, so it is sent first.
Now the three characters thing comes from the size of the FIFO in the
serial receive. The chip has a single RX receive register, and two characters
of FIFO. So 2.9999 characters can be received before the UART overflows.
Now on the basic UART if the characters are not read, and another arrives
the RX FIFO will hang. Adding 'ERRORS' gets rid of this hang, but still
leaves you only able to receive 2.9999 characters before data will be lost.
You need to implement software receive buffering to avoid this. Using
either the routines in the code library or by adding this to the #USE
RS232. So:
Code:

include <18F2520.h>
#device ADC=10
#FUSES NOWDT                    //No Watch Dog Timer
#use delay(internal=32MHz)
#use FIXED_IO(C_outputs=PIN_C2)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7, parity=N, stop=1, bits=8, RECEIVE_BUFFER=16,ERRORS)
void main(void)
{
    enable_interrupts(GLOBAL);
    while(TRUE)


This adds an interrupt driven 16 character receive buffer. You can
make this larger if required.

Now this works well, but has slight 'issues'. If you overflow the buffer
data will just be overwritten. The version in the code library allows
this to be handled more tidily, or you to change how this is done.

Be aware though You are outputting a huge number of characters
round the loop, and delaying as well (why?). In that time you could
potentially receive perhaps 30 characters, and you are only reading
one. Result, very easy indeed to overflow any buffer. You have to
understand that if you repeatedly send more characters than are received
you will overflow any size buffer eventually.

Now the spurious characters could be from two different things. First
the internal clock in this chip is only just accurate enough for reliable
RS232, at 5v and room temperature. If your supply is not reliable
or the chip is rather hot/cold, the clock could be drifting enough to
give incorrect characters. However this would only result in incorrect
characters being sent/received, not extra ones appearing. If you are
getting extra ones then it implies you have a problem with electrical
noise somewhere in your circuit. Look in particular at how things
are actually grounded and interconnected.
bmete



Joined: 13 Jul 2023
Posts: 37

View user's profile Send private message

PostPosted: Sat Jul 29, 2023 6:46 am     Reply with quote

Hello
Ttelmah wrote:

Now the three characters thing comes from the size of the FIFO in the
serial receive. The chip has a single RX receive register, and two characters
of FIFO. So 2.9999 characters can be received before the UART overflows.
Now on the basic UART if the characters are not read, and another arrives
the RX FIFO will hang. Adding 'ERRORS' gets rid of this hang, but still
leaves you only able to receive 2.9999 characters before data will be lost.
You need to implement software receive buffering to avoid this. Using
either the routines in the code library or by adding this to the #USE
RS232
This adds an interrupt driven 16 character receive buffer. You can
make this larger if required.

So does that mean RECEIVE_BUFFER=16 or 32 or 64 how many characters to receive in a message, do I understand correctly? Can I even send a 29999 character string if I do the right things?

As far as I know the getc function only requests 1 byte of data, how can I get the remaining bytes or how can I properly use functions that call strings like "gets"?

Ttelmah wrote:

Now this works well, but has slight 'issues'. If you overflow the buffer
data will just be overwritten. The version in the code library allows
this to be handled more tidily, or you to change how this is done.

I can not find any in code library can you please share?

Ttelmah wrote:

Be aware though You are outputting a huge number of characters
round the loop, and delaying as well (why?). In that time you could
potentially receive perhaps 30 characters, and you are only reading
one. Result, very easy indeed to overflow any buffer. You have to
understand that if you repeatedly send more characters than are received
you will overflow any size buffer eventually.

I removed the useless delays, only the delay after turning on the enable pin remained. spurious characters appear in printf when i dont use it. However, despite the 4-5 characters I entered from the terminal, I can only receive 1 of them

Ttelmah wrote:

Now the spurious characters could be from two different things. First
the internal clock in this chip is only just accurate enough for reliable
RS232, at 5v and room temperature. If your supply is not reliable
or the chip is rather hot/cold, the clock could be drifting enough to
give incorrect characters. However this would only result in incorrect
characters being sent/received, not extra ones appearing. If you are
getting extra ones then it implies you have a problem with electrical
noise somewhere in your circuit. Look in particular at how things
are actually grounded and interconnected.

actually the 5v power supply is reliable, The chip appears to be operating at normal temperature. However, the thing that comes to my mind is the situation that I am not sure about: I am using SN75176 in the circuit, it is possible that it does not support the protocol and the pull-ups I put in its inputs. The schematic is as follows:

[img] https://ibb.co/S5yvPGY [/img]

Also this is the code:
Code:


#include <18F2520.h>
#device ADC=10
#FUSES NOWDT                    //No Watch Dog Timer
#use delay(internal=32MHz)
#use FIXED_IO(C_outputs=PIN_C2)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7, parity=N, stop=1, bits=8, RECEIVE_BUFFER=16, ERRORS)
void main()
{
   enable_interrupts(GLOBAL);
   while(TRUE)
   {

           printf("Enter:  \n");
           output_low(PIN_C2);
           delay_ms(3);
           int32 T = getc();
           output_high(PIN_C2);
           delay_ms(3);
           printf("\n %Lu ", T);   
           printf(" %c ", T);
           printf(" %X \n", T);
}
}



When I run the code, still returns 1 character no matter what I give to the RECEIVE_BUFFER=16 or32 or 64. Also " ▒ " is still displayed.
Terminal:
[img] https://ibb.co/M8VLfbY [/img]


Apart from these, I have one more important question. As far as I've noticed, when I call the getc function, the main loop stops until it get a response. This is actually not good for me because the rest of the code does the operations that would require the main function. Actually, I need a code that takes an interrupt when the message arrives and saves it to a string, but I'm still stuck in the receive part. How should I go about this?
temtronic



Joined: 01 Jul 2010
Posts: 9243
Location: Greensville,Ontario

View user's profile Send private message

PostPosted: Sat Jul 29, 2023 7:36 am     Reply with quote

One very important detail....
you're using RS-485 , which had a control signal for xmt/rcv that you need to assign in the #USE RS232(....options.....)

also

make the buffer 1.5 to 2x larger than number of characters you think may come in.if possible, make it a 'binary' number like 64 ,128, 256. Some programs work better,faster ,cleaner. I don't know what the max chars for the CCS 'buffer=' is though.
PrinceNai



Joined: 31 Oct 2016
Posts: 480
Location: Montenegro

View user's profile Send private message

PostPosted: Sat Jul 29, 2023 7:46 am     Reply with quote

Code:

           int32 T = getc();
           output_high(PIN_C2);
           delay_ms(3);
           printf("\n %Lu ", T);   
           printf(" %c ", T);
           printf(" %X \n", T);


This is wrong. T isn't a 32 bit variable. You will receive 4 separate 8bit characters in 4 separate transmissions that you need to store in a buffer somewhere and later display them.


If you care to use interrupts, do it the way I showed you above in the thread.
bmete



Joined: 13 Jul 2023
Posts: 37

View user's profile Send private message

PostPosted: Sat Jul 29, 2023 10:06 am     Reply with quote

PrinceNai wrote:

This is wrong. T isn't a 32 bit variable. You will receive 4 separate 8bit characters in 4 separate transmissions that you need to store in a buffer somewhere and later display them.


If you care to use interrupts, do it the way I showed you above in the thread.


Hello PrinceNai

Thanks, based on what you said I updated the code and now I can get 8 bytes of data. I think you meant to say something like this when you said save to buffer.
I'll try your code for the interrupt after I get the data transfer properly, thank you.

What I want to ask is, is it possible to find out how many bytes the incoming message will be and call the getc() function accordingly?

Code:

#use delay(internal=32M)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7, parity=N, stop=1, bits=8, RECEIVE_BUFFER=64, ERRORS)

void main()
{
         output_high(PIN_C2); // enable
         enable_interrupts(GLOBAL);

while (TRUE)
{
            printf("Enter:    \n");
            output_low(PIN_C2);
            delay_ms(5);
            int16 A = getc();
            int16 B = getc();
            int16 C = getc();
            int16 D = getc();
            int16 E = getc();
            int16 F = getc();
            int16 G = getc();
            int16 H = getc();
           
            output_high(PIN_C2);
            delay_ms(5);
            printf(" %X ", A);
            printf(" %X ", B);
            printf(" %X ", C);
            printf(" %X ", D);
            printf(" %X ", E);
            printf(" %X ", F);
            printf(" %X ", G);
            printf(" %X \n", H);
}
}



temtronic wrote:
One very important detail....
you're using RS-485 , which had a control signal for xmt/rcv that you need to assign in the #USE RS232(....options.....)


Hello temtronic

Maybe that reason I have to switch enable pin manually?


temtronic wrote:

make the buffer 1.5 to 2x larger than number of characters you think may come in.if possible, make it a 'binary' number like 64 ,128, 256. Some programs work better,faster ,cleaner. I don't know what the max chars for the CCS 'buffer=' is though.


Thanks for the advice,
PrinceNai



Joined: 31 Oct 2016
Posts: 480
Location: Montenegro

View user's profile Send private message

PostPosted: Sat Jul 29, 2023 10:54 am     Reply with quote

I'd still go the interrupt route. The example I posted works, I'm using it everywhere. Make Buffer_Size as big as you need and then some more. Regarding the question about the length of your data. You know what you are sending or trying to receive :-). If it is fixed length you can count the characters. There is a problem with that if you start receiving in the middle. So what I'd do is start the string with a character that is never used in your data, like '#' and started filling the buffer after that character. And stop when another special character is received. BTW, your integers A, B,... should be int8 or chars, which is the same.
Ttelmah



Joined: 11 Mar 2010
Posts: 19539

View user's profile Send private message

PostPosted: Sat Jul 29, 2023 11:53 am     Reply with quote

You always only get one character. getc, stands for 'get character'. One
character.
The point is you need to use the kbhit, which tells you if there is a character
and if so, receive the character.
You code has to rebuild the 4 characters into one larger value. However
there also _must_ be something to tell you where the value starts.
With RS232 (or 485), there has to be a format to the data, with some
form of marker to say where the data starts.
PrinceNai



Joined: 31 Oct 2016
Posts: 480
Location: Montenegro

View user's profile Send private message

PostPosted: Sat Jul 29, 2023 3:13 pm     Reply with quote

As Mr. Ttelmah said, # for example would be the marker (I was looking for that word :-) ) at the start of your data. If it is of fixed length, that one is enough. You said your main has other things to do while receiving the data. kbhit() is ok, but it wastes a lot of time just sitting there waiting. Faster approach is using the interrupt. It takes like 30 instructions to get to the interrupt and than maybe another 20 instructions to store the data. With the speed you are running the PIC and the slowest possible baud rate you are using that's a lot of time to do whatever you want in the meantime. So, fill the buffer behind the scenes. When the data is in, simply raise a flag for the main, for example GotData = 1. When main sees that flag, clear the flag and do something with the data.
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