|
|
View previous topic :: View next topic |
Author |
Message |
lisek_lichu
Joined: 27 Aug 2012 Posts: 23
|
RS485 sending text (sometimes work and sometimes not) |
Posted: Mon Aug 27, 2012 2:54 pm |
|
|
Hello,
I'm trying to write a little project to make a communication between few PIC 16F628A and one PC.
communication diagram (for test only one PC and only one PIC) is below:
PC <-> MAX232 <-> MAX485 <-> ........<->MAX485<->PIC
My code is really simple:
Code: |
#include <16F628A.h>
#fuses XT, NOPROTECT, NOCPD, NOLVP, NOWDT, NOBROWNOUT, PUT
#use delay(clock=4M)
#use rs232(baud=9600, xmit=PIN_B2, enable=PIN_B3, rcv=PIN_B1, errors, stream=PC)
void main()
{
trisa = 0;
porta = 0;
int8 character;
fputc('x',PC); //print x char
fprintf(PC,"test_1\r\n"); //print string
while(TRUE)
{
if(kbhit()) //if receive something
{
output_toggle(PIN_A0); //toggle LED (it works)
character=fgetc(PC); //get char
fprintf(PC,"test_2\r\n"); // doesn't work
fputc(character,PC); // doesn't work
fputc('x',PC); // doesn't work
}
}
} |
I use enable PIN in #use rs232.
My problem is that first fputc and fprintf sends data to PC correctly but when program comes into while loop it waits for some data from PC. When I send one character, LED on PIN_A0 toggles but nothing is sent to PC. I tried to send more data and LED blinks but no data is sent.
Why before while loop I can send data but inside I can not?
Can someone help me?
Thanks in advance
Simon |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Mon Aug 27, 2012 3:21 pm |
|
|
Get creative. Do some experiments. Run a test program that doesn't
use the while() loop or most of the code inside it:
Code: |
void main()
{
fputc('x',PC);
fprintf(PC,"test_1\r\n");
delay_ms(500);
fputc('y',PC);
fprintf(PC,"test_2\r\n");
while(1);
}
|
Run a different test with the while() loop, but without the kbhit() test:
Code: |
while(TRUE)
{
output_toggle(PIN_A0);
character=fgetc(PC);
fprintf(PC,"test_2\r\n");
fputc(character,PC);
fputc('x',PC);
}
|
Run another test without the fgetc(). See if that works.
Code: |
while(TRUE)
{
output_toggle(PIN_A0);
fprintf(PC,"test_2\r\n");
fputc(character,PC);
fputc('x',PC);
delay_ms(500);
}
|
In other words, simplify the program and cut out parts of it, to see
which line(s) are the problem.
The two lines below are unnecessary, because the output_toggle(PIN_A0)
function automatically sets the TRIS for Pin A0 to be an output pin:
Quote: |
trisa = 0;
porta = 0;
|
All variable declarations should go at the start of the function. All lines
of code should be placed after the variable declarations:
Quote: |
void main()
{
trisa = 0;
porta = 0;
int8 character; // Move this to the start of main()
|
|
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19515
|
|
Posted: Tue Aug 28, 2012 1:21 am |
|
|
First, how is the PC controlling the enable it's end?. What circuitry/code involved?.
With standard 2 wire RS485, comms is 'half duplex', with only one end able to talk at a time. I'd suspect that when you send data from the PC, _it_ is setting it's enable to take over the bus, and is then not releasing it. Normally if you are using some of the off the shelf packages that are supplies as 'demos' for RS485 cards, they take command when characters are sent, and stay holding the bus, until an ETX, or EOL is sent.
Second comment (not the problem, but may cause problems in the future), bus termination. RS485, is designed to have termination at each end of the bus. Also (depending on the drivers you are using), the termination should be designed to bias the bus to the 'off' state. Texas have some good application notes about this.
As PCM programmer says, start a little simpler. Verify you can send in each direction, and get 'valid'' data, and that the bus goes idle when you are not sending. I suspect this is the problem at the PC end.
Best Wishes |
|
|
RF_Developer
Joined: 07 Feb 2011 Posts: 839
|
|
Posted: Tue Aug 28, 2012 7:54 am |
|
|
If you are using stream names, in this case you're calling the serial stream "PC", then you should use that name in the kbhit call, or anywhere else to do with serial/RS232 comms:
Code: |
if(kbhit(PC)) //if receive something
{
...
}
|
RF Developer |
|
|
gpsmikey
Joined: 16 Nov 2010 Posts: 588 Location: Kirkland, WA
|
|
Posted: Tue Aug 28, 2012 8:17 am |
|
|
One thing I didn't see (although I have not had my coffee yet either) is a delay after sending before you turn off the enable on the transmit side. My favorite trick is to send a character to the uart, then disable the output so I can listen for the next message or whatever forgetting that you need to delay a character time at least so it can be shifted out.
mikey _________________ mikey
-- you can't have too many gadgets or too much disk space !
old engineering saying: 1+1 = 3 for sufficiently large values of 1 or small values of 3 |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19515
|
|
Posted: Tue Aug 28, 2012 8:44 am |
|
|
If you use the CCS 'enable' option in #USE RS232, it waits for the character to be sent, before disabling this.
I'm still most suspicious of the 'enable' handling at the PC end...
Best Wishes |
|
|
lisek_lichu
Joined: 27 Aug 2012 Posts: 23
|
|
Posted: Tue Aug 28, 2012 2:17 pm |
|
|
Thanks for fast reply.
PCM programmer wrote: | Get creative. Do some experiments. Run a test program that doesn't
use the while() loop or most of the code inside it:
Code: |
void main()
{
fputc('x',PC);
fprintf(PC,"test_1\r\n");
delay_ms(500);
fputc('y',PC);
fprintf(PC,"test_2\r\n");
while(1);
}
|
|
I did a lot of experiments. with different loop types, wuth and without loop but for me most strange is that before while loop fputs work, inside loop kbhit works even without stream specified in it beacuse LED was toggling only when i sent some char. But function fput and fprintf doesn't work inside while loop.
Your first program runs correctly. PC received xtest_1 ytest_2
PCM programmer wrote: | Run a different test with the while() loop, but without the kbhit() test:
Code: |
while(TRUE)
{
output_toggle(PIN_A0);
character=fgetc(PC);
fprintf(PC,"test_2\r\n");
fputc(character,PC);
fputc('x',PC);
}
|
|
This program toggle LED every time i send some character from PC to PIC but no character is returned to PC.
PCM programmer wrote: |
Run another test without the fgetc(). See if that works.
Code: |
character = 'b';
while(TRUE)
{
output_toggle(PIN_A0);
fprintf(PC,"test_2\r\n");
fputc(character,PC);
fputc('x',PC);
delay_ms(500);
}
|
|
this program runs correctly. It's toggle LED, print "test_2" send "b" character and wait 0,5s an run again
PCM programmer wrote: |
In other words, simplify the program and cut out parts of it, to see
which line(s) are the problem.
The two lines below are unnecessary, because the output_toggle(PIN_A0)
function automatically sets the TRIS for Pin A0 to be an output pin:
Quote: |
trisa = 0;
porta = 0;
|
|
Thanks i was wondering if it is ok or not.
PCM programmer wrote: |
All variable declarations should go at the start of the function. All lines
of code should be placed after the variable declarations:
Quote: |
void main()
{
trisa = 0;
porta = 0;
int8 character; // Move this to the start of main()
|
|
thanks a lot for those informations. I will try to find this problem |
|
|
lisek_lichu
Joined: 27 Aug 2012 Posts: 23
|
|
Posted: Tue Aug 28, 2012 2:29 pm |
|
|
Ttelmah wrote: | First, how is the PC controlling the enable it's end?. What circuitry/code involved?.
|
I use RTC signal from PC. I have hardware COM port not adapter from USB to RS232.
I use max232 to fit voltage level for TX RX and RTC. also i use Bray terminal for communication with PC and there is an option "Handshaking" where You can set "RTS on TX" and also "invert" so after that wnen a byte is sent RTC is set during this transmission
Ttelmah wrote: |
With standard 2 wire RS485, comms is 'half duplex', with only one end able to talk at a time. I'd suspect that when you send data from the PC, _it_ is setting it's enable to take over the bus, and is then not releasing it.
|
I understand that and I also put a LED with 1k resistor on RTC from PC so I can see when PC has RTC high and after sending a byte it is going low so i think it is ok
Ttelmah wrote: |
Normally if you are using some of the off the shelf packages that are supplies as 'demos' for RS485 cards, they take command when characters are sent, and stay holding the bus, until an ETX, or EOL is sent.
|
Hmm I didn't supose that maybe this is the reason
Ttelmah wrote: |
Second comment (not the problem, but may cause problems in the future), bus termination. RS485, is designed to have termination at each end of the bus. Also (depending on the drivers you are using), the termination should be designed to bias the bus to the 'off' state. Texas have some good application notes about this.
|
In first test i had terminations but nothing work then. so after I get if out some things start to work. but now You said that termination have to set bus to "off" state?? I read in one book that it have to be set to "on"!!
And that was not logical for me hmmmm.
I put a resistor 240ohms from vcc to A and from B to GND and between A and B i put 120ohm rezistor so in this situation the bus was forced to be set to "ON"
hmmmm
Ttelmah wrote: |
As PCM programmer says, start a little simpler. Verify you can send in each direction, and get 'valid'' data, and that the bus goes idle when you are not sending. I suspect this is the problem at the PC end.
Best Wishes |
I realy do a lot of modification to simplify as much as it is possible. but i have to do mooooore |
|
|
lisek_lichu
Joined: 27 Aug 2012 Posts: 23
|
|
Posted: Tue Aug 28, 2012 2:30 pm |
|
|
RF_Developer wrote: | If you are using stream names, in this case you're calling the serial stream "PC", then you should use that name in the kbhit call, or anywhere else to do with serial/RS232 comms:
Code: |
if(kbhit(PC)) //if receive something
{
...
}
|
RF Developer |
I tried with and without and in this simple programs it doesn't matter. But I will remember about it in next programs.
Thanks |
|
|
lisek_lichu
Joined: 27 Aug 2012 Posts: 23
|
|
Posted: Tue Aug 28, 2012 2:33 pm |
|
|
Ttelmah wrote: | If you use the CCS 'enable' option in #USE RS232, it waits for the character to be sent, before disabling this.
I'm still most suspicious of the 'enable' handling at the PC end...
Best Wishes |
I have written few post before how i have it done. Check me maybe I do it wrong but normally when i sent text it works, but when I do it in while loop everything works but not sending a text to PC. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19515
|
|
Posted: Tue Aug 28, 2012 2:52 pm |
|
|
Remember the 'off' state on the RS485 bus, gives 'high' at the PIC. This is where the 'on' confusion comes.
If you are disabling the receive on the transceiver, when you send, then you also need a pull-up resistor on the line from the transceiver to the RX pin on the PIC. If not, then you will also receive every character you send.
Best Wishes |
|
|
lisek_lichu
Joined: 27 Aug 2012 Posts: 23
|
|
Posted: Tue Aug 28, 2012 2:55 pm |
|
|
Ttelmah wrote: | Remember the 'off' state on the RS485 bus, gives 'high' at the PIC. This is where the 'on' confusion comes.
If you are disabling the receive on the transceiver, when you send, then you also need a pull-up resistor on the line from the transceiver to the RX pin on the PIC. If not, then you will also receive every character you send.
Best Wishes |
Hmmm I don't know if I understand it correctly. Can You explain it more detail?
Lisek |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19515
|
|
Posted: Wed Aug 29, 2012 1:32 am |
|
|
The problem is if you talk 0/1, or high/low, versus idle/active.
In TTL async serial, the 'idle' state, is 5v at the chip. So 'high', or '1', is the idle state. When nothing is being received, this line needs to 'idle high'.
Now over RS485, the 'idle' state, is to have the 'A' line at least 200mV above the 'B' line. The bus is defined, so that if this is not true, and the lines are just allowed to float, the receiver output, will hold the last level received, which can result in you continuously receiving zero bytes....
Now separately you have the control of the RS485 buffer. There are two lines, /RE. and DE. You can wire two different ways:
The first, you leave the receiver permanently enabled, and just turn the driver on/off when you want to talk. Done this way, you will receive every character you send (which can be a diagnostic that the data is going onto the bus), but means your software has to be able to cope with this.
For the second, you wire the /RE, and DE lines together, and turn off the receiver, when transmitting. Key here is that since you are turning the receiver 'off', _you_ have to ensure that the RO line is pulled high (idle) when not driven by the receiver, or you _will_ start receiving spurious characters as the line floats.
Now a third thing. Timing of the 'enable' line.
The chip itself has 1.99999 characters of hardware buffering in the transmit. One actual 'buffer', and the output shift register. The CCS code, when asked to control the 'enable' line, checks the TRMT bit (transmit shift register empty), and only raises the 'enable', when this goes true. This means the code has to wait for the characters to send, rather than just getting on while the hardware transmits. If you want to control the line yourself, you need to do the same, or provide a delay (the latter is slightly more dangerous, since if too short, the characters may not finish transmitting, while if too long, you may miss the start of a reply, if this is really fast). A delay is OK, provided there is a slight pause before the other end replies.
Best Wishes |
|
|
|
|
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
|