|
|
View previous topic :: View next topic |
Author |
Message |
mkuang
Joined: 14 Dec 2007 Posts: 257
|
Help with RS485 communication between two pics |
Posted: Wed Jun 03, 2009 8:33 am |
|
|
Hello,
I am trying to get two pic18f2525 two talk over a rs485 interface. Each pic is on a separate pcb and each board has a MAX487 RS485 transceiver. Right now I am just trying to establish some sort of one way communication and it is not working. I have created a test program so that pic1 simply sends a character every second based on which one of two RB switches are activated. The code for PIC 1 looks like this:
Code: |
#include <18F2525.h>
#device ADC=10 //set for 10 bit A/D
#fuses INTRC_IO,NOWDT,NOPROTECT,BROWNOUT,PUT,NOLVP
#use delay(clock=4000000)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7)
#define NORMAL_OP 1
#define CAL 2
#define FAIL 3
#define OFFLINE 4
#define OFFLINE_RST_SW_ACT 1
#define ZERO_SPAN_SW_ACT 2
#define EXMO_NO_SW 7
#define EXMO_CAL_SW 8
#define EXMO_RST_SW 9
#define SENSOR_ZERO_HIGH_BYTE_ADDX 10
#define SENSOR_ZERO_LOW_BYTE_ADDX 11
#define SENSOR_SPAN_HIGH_BYTE_ADDX 20
#define SENSOR_SPAN_LOW_BYTE_ADDX 21
#define NUM_MSG_NORMAL_OP 3
#define ZERO_SPAN_SW PIN_B5
#define OFFLINE_RESET_SW PIN_B4
#define SENSPOT_CS PIN_B3
#define DE_RE PIN_B0
#define DEBUG1
#define SPI_MODE_0_0 (SPI_L_TO_H | SPI_XMIT_L_TO_H)
#define SPI_MODE_0_1 (SPI_L_TO_H)
#define SPI_MODE_1_0 (SPI_H_TO_L)
#define SPI_MODE_1_1 (SPI_H_TO_L | SPI_XMIT_L_TO_H)
unsigned char exmo_sw=4;
#include <sce5774.c>
#INT_RB
void rb_isr(void)
{
if (input(OFFLINE_RESET_SW) == 0)
{
exmo_sw = EXMO_RST_SW;
}// if (input(OFFLINE_RESET_SW) == 0)
else if ( input(ZERO_SPAN_SW) == 0)//else zero_span switch activated
exmo_sw = EXMO_CAL_SW;
} //end void rb_isr(void)
void main(void)
{
output_low(DE_RE);
reset_display();
setup_spi(SPI_MASTER | SPI_MODE_0_0 |SPI_CLK_DIV_4);
SETUP_ADC_PORTS(AN0_TO_AN2 | VSS_VREF);
setup_adc(ADC_CLOCK_DIV_4 |ADC_TAD_MUL_4 );
setup_ccp1(CCP_PWM);
setup_timer_2(T2_DIV_BY_4, 255, 1);
clear_interrupt(INT_RB);
enable_interrupts(INT_RB);
enable_interrupts(GLOBAL);
while (1)
{
output_high(DE_RE);
printf("\n%u\r," exmo_sw);
output_low(DE_re);
delay_ms(1000);
}
|
And this appears to be doing what it is suppose to do. I took a peek using hyperterminal and see that it is printing 4 to start and when I activate one of the switches, the RB interrupt causes it to print 8 or 9 as it should.
The receiving PIC code looks like:
Code: |
#include <18F2525.h>
#device ADC=10 //set for 10 bit A/D
#fuses INTRC_IO,NOWDT,NOPROTECT,BROWNOUT,PUT,NOLVP
#use delay(clock=4000000)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7)
#define NORMAL_OP 1
#define CAL 2
#define FAIL 3
#define OFFLINE 4
#define OFFLINE_RST_SW_ACT 1
#define ZERO_SPAN_SW_ACT 2
#define EXMO_NO_SW 7
#define EXMO_CAL_SW 8
#define EXMO_RST_SW 9
#define SENSOR_ZERO_HIGH_BYTE_ADDX 10
#define SENSOR_ZERO_LOW_BYTE_ADDX 11
#define SENSOR_SPAN_HIGH_BYTE_ADDX 20
#define SENSOR_SPAN_LOW_BYTE_ADDX 21
#define NUM_MSG_NORMAL_OP 3
#define ZERO_SPAN_SW PIN_B5
#define OFFLINE_RESET_SW PIN_B4
#define SENSPOT_CS PIN_B3
#define DE_RE PIN_B0
#define DEBUG1
#define SPI_MODE_0_0 (SPI_L_TO_H | SPI_XMIT_L_TO_H)
#define SPI_MODE_0_1 (SPI_L_TO_H)
#define SPI_MODE_1_0 (SPI_H_TO_L)
#define SPI_MODE_1_1 (SPI_H_TO_L | SPI_XMIT_L_TO_H)
unsigned char ch;
#include <sce5774.c>
void main(void)
{
output_low(DE_RE);
reset_display();
setup_spi(SPI_MASTER | SPI_MODE_0_0 |SPI_CLK_DIV_4);
SETUP_ADC_PORTS(AN0_TO_AN2 | VSS_VREF);
setup_adc(ADC_CLOCK_DIV_4 |ADC_TAD_MUL_4 );
setup_timer_0(RTCC_INTERNAL|RTCC_DIV_4);
setup_ccp1(CCP_PWM); // Configure CCP2 as a PWMDAC
setup_timer_2(T2_DIV_BY_4, 255, 1);
while (1)
{
if (kbhit())
{
ch = getch();
// format_adc_to_display(ch);
}//if (kbhit())
else
{
ch = 49;
}
format_adc_to_display(ch);
delay_ms(500);
clear_display();
delay_ms(500);
}//while
}//main
|
The problem is that the receiving pic only grabs the first tranmission on power up and after that it always prints 49 as the value for ch meaning that kbhit() is false.
Anyone has any ideas what the problem might be?
Thanks.
MK |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
|
mkuang
Joined: 14 Dec 2007 Posts: 257
|
|
Posted: Wed Jun 03, 2009 12:12 pm |
|
|
Following the link you gave I added 1.2k pullup and pulldown on the A and B lines of the RS485 and a 120Ohm between the A and B. I got the same result. That is: I power up both boards and the receiving pic gets the correct character, once, but then doesn't get any subsequent transmissions. Furthermore if I add the line
Code: | format_adc_to_display(kbhit())
|
instead of
Code: |
format_adc_to_display(ch);
|
I see that kbhit is always zero on my display. I put a scope probe right on the the Rx pin (RC7) of the receiving pic and I do see 0/5V signals that idle high. So for some reason the pic doesn't think there are bytes coming in. |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Wed Jun 03, 2009 12:32 pm |
|
|
Quote: | #use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7) |
Why don't you edit the #use rs232() statement, and add the ENABLE
parameter, and specify your DE pin there. And then, remove the
manual DE control statements in your code. Let the CCS library code
handle the RS-485 enable pin. Do this in your transmitter PIC program. |
|
|
mkuang
Joined: 14 Dec 2007 Posts: 257
|
|
Posted: Wed Jun 03, 2009 12:44 pm |
|
|
PCM programmer wrote: | Quote: | #use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7) |
Why don't you edit the #use rs232() statement, and add the ENABLE
parameter, and specify your DE pin there. And then, remove the
manual DE control statements in your code. Let the CCS library code
handle the RS-485 enable pin. Do this in your transmitter PIC program. |
I did that and same thing. I stripped away all the unnecessary stuff in the code and now the TX PIC code is:
Code: |
#include <18F2525.h>
#device ADC=10
#fuses XT,NOWDT,NOPROTECT,BROWNOUT,PUT,NOLVP
#use delay(clock=4000000)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7, ENABLE = PIN_B0)
#define ZERO_SPAN_SW PIN_B5
#define OFFLINE_RESET_SW PIN_B4
#define DE_RE PIN_B0
#define EXMO_CAL_SW 8
#define EXMO_RST_SW 9
unsigned char exmo_sw=3; //assign ch dummy value to start
#INT_RB
void rb_isr(void)
{
if (input(OFFLINE_RESET_SW) == 0)
{
exmo_sw = EXMO_RST_SW;
}// if (input(OFFLINE_RESET_SW) == 0)
else if ( input(ZERO_SPAN_SW) == 0)//else zero_span switch activated
exmo_sw = EXMO_CAL_SW;
} //end void rb_isr(void)
void main(void)
{
clear_interrupt(INT_RB);
enable_interrupts(INT_RB);
enable_interrupts(GLOBAL);
while (1)
{
printf("\n%u\r," exmo_sw); //only talk when receive a '$' from main bd.
delay_ms(1000);
}//while
}//main
|
And the receiving PIC code is:
Code: |
#include <18F2525.h>
#device ADC=10 //set for 10 bit A/D
#fuses XT,NOWDT,NOPROTECT,BROWNOUT,PUT,NOLVP
#use delay(clock=4000000)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7)
#define EXMO_CAL_SW 8
#define EXMO_RST_SW 9
#define ZERO_SPAN_SW PIN_B5
#define OFFLINE_RESET_SW PIN_B4
#define DE_RE PIN_B0
#define SPI_MODE_0_0 (SPI_L_TO_H | SPI_XMIT_L_TO_H)
#define SPI_MODE_0_1 (SPI_L_TO_H)
#define SPI_MODE_1_0 (SPI_H_TO_L)
#define SPI_MODE_1_1 (SPI_H_TO_L | SPI_XMIT_L_TO_H)
unsigned char j;
unsigned char ch = 99;
unsigned char messages[3][22] = {
">>>PPM>=>>>>>>>>>>>>>",
">>DEGC>=>>>>>>>>>>>>>",
">STATE>=>>>>>>>>>>>>>"};
#include <string.h>
#include <sce5774.c>
void main(void)
{
output_low(DE_RE);
reset_display();
setup_spi(SPI_MASTER | SPI_MODE_0_0 |SPI_CLK_DIV_4);
set_brightness(0b11110110);
while (1)
{
if (kbhit())
{
ch = getch();
}//if (kbhit())
else
{
ch = 49;
}
format_adc_to_display(ch);
delay_ms(500);
}//while
}//main
|
|
|
|
Humberto
Joined: 08 Sep 2003 Posts: 1215 Location: Buenos Aires, La Reina del Plata
|
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Wed Jun 03, 2009 12:50 pm |
|
|
You haven't stripped it down enough. Get rid of all the #int_rb stuff
and all the SPI stuff.
You have this huge delay of 500ms in your receiver loop. This prevents
incoming characters from being read from the UART. If you get more
than 2 chars in the UART, it will lock up the receiver. Get rid of that
delay, and also add the ERRORS parameter to the #use rs232()
statement in the receiver PIC code (and transmitter, too). This will
automatically clear an overrun errors that occur. |
|
|
mkuang
Joined: 14 Dec 2007 Posts: 257
|
|
Posted: Wed Jun 03, 2009 1:26 pm |
|
|
Okay, I think this is as bare as it can be. For the TX:
Code: |
#include <18F2525.h>
#device ADC=10
#fuses XT,NOWDT,NOPROTECT,BROWNOUT,PUT,NOLVP
#use delay(clock=4000000)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7, ENABLE = PIN_B0, ERRORS)
#define DE_RE PIN_B0
unsigned char exmo_sw=3;
void main(void)
{
while (1)
{
printf("\n%u\r," exmo_sw);
delay_ms(1000);
}//while
}//main
|
And for the RX:
Code: |
#include <18F2525.h>
#device ADC=10 //set for 10 bit A/D
#fuses XT,NOWDT,NOPROTECT,BROWNOUT,PUT,NOLVP
#use delay(clock=4000000)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7,ERRORS)
#define EXMO_CAL_SW 8
#define EXMO_RST_SW 9
#define TEST_PIN PIN_B2
#define ZERO_SPAN_SW PIN_B5
#define OFFLINE_RESET_SW PIN_B4
#define DE_RE PIN_B0
unsigned char ch = 99;
void main(void)
{
output_low(DE_RE);
while (1)
{
if (kbhit())
{
ch = getch();
output_low(TEST_PIN);
}//if (kbhit())
else
{
ch = 49;
output_high(TEST_PIN);
}
}//while
}//main
|
So now if kbhit is true then my TEST_PIN is low and if kbhit is false then TEST_PIN is high. And I always see TEST_PIN high. |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Wed Jun 03, 2009 1:45 pm |
|
|
With that loop, it will only go low for a few usec, before it goes high again.
You might not see it.
A better test would be to toggle the pin every time you get a character:
Code: | void main()
{
int8 ch;
output_low(TEST_PIN);
while(1)
{
ch = getch();
output_toggle(TEST_PIN);
}
}
|
Or, more simple than that, simply wait until you get a character.
Then set the pin high.
Code: | void main()
{
int8 ch;
output_low(TEST_PIN);
ch = getch(); // Wait for a char
output_high(TEST_PIN);
while(1);
} |
|
|
|
mkuang
Joined: 14 Dec 2007 Posts: 257
|
|
Posted: Wed Jun 03, 2009 3:03 pm |
|
|
Looks like one of the MAX487 chips has gone bonkers on me. I used another bd as the RX and it appears to work with the test programs, I see the testpin toggle using the first code you suggested.
Thanks. |
|
|
mkuang
Joined: 14 Dec 2007 Posts: 257
|
|
Posted: Wed Jun 03, 2009 3:36 pm |
|
|
PCM Programmer, with regards to this test program:
Code: |
void main()
{
int8 ch;
output_low(TEST_PIN);
while(1)
{
ch = getch();
output_toggle(TEST_PIN);
}
}
|
How long does the PIC wait to get a character with the getch() function before timing out? Can I assume that if it reaches the output_toggle() then it has received a character? On the scope the testpin is low most of time and goes high for about 1.25 ms at a time. |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Wed Jun 03, 2009 3:41 pm |
|
|
It never times out. It waits forever, if necessary. |
|
|
mkuang
Joined: 14 Dec 2007 Posts: 257
|
|
Posted: Thu Jun 04, 2009 9:58 am |
|
|
Thanks PCM Programmer. I modified the test programs slightly so that PIC1 talks, PIC2 waits using kbhit, then look for the character 'E' in the message, and then grab the character after the E and send that out via the printf. So essentially the two pics take turns talking on the RS485 line so there is no bus conflict. So for the the TX pic:
Code: |
#include <18F2525.h>
#device ADC=10
#fuses XT,NOWDT,NOPROTECT,BROWNOUT,PUT,NOLVP
#use delay(clock=4000000)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7, ENABLE = PIN_B0, ERRORS)
#define ZERO_SPAN_SW PIN_B5
#define OFFLINE_RESET_SW PIN_B4
#define DE_RE PIN_B0
#define EXMO_CAL_SW 8
#define EXMO_RST_SW 9
unsigned char exmo_sw=4; //assign ch dummy value to start
void main(void)
{
while (1)
{
printf("\nE%u", exmo_sw);
delay_ms(1000);
}//while
}//main
|
And for the RX pic (which answers)
Code: |
#include <18F2525.h>
#device ADC=10 //set for 10 bit A/D
#fuses XT,NOWDT,NOPROTECT,BROWNOUT,PUT,NOLVP
#use delay(clock=4000000)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7, ENABLE = PIN_B0, ERRORS)
#define EXMO_CAL_SW 8
#define EXMO_RST_SW 9
#define TEST_PIN PIN_B2
#define ZERO_SPAN_SW PIN_B5
#define OFFLINE_RESET_SW PIN_B4
#define DE_RE PIN_B0
void main()
{
int8 ch;
output_low(TEST_PIN);
while(1)
{
if (kbhit())
{
ch = getch();
if (ch == 'E')
{
ch = getchar();
output_toggle(TEST_PIN);
printf("\nI received %c", ch);
}
}
}
}
|
And I see in hyperterminal:
Code: |
4
I received 4
4
I received 4
.
.
.
|
|
|
|
|
|
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
|