|
|
View previous topic :: View next topic |
Author |
Message |
Audi80
Joined: 07 Sep 2007 Posts: 41
|
Rs485 problem |
Posted: Tue Nov 27, 2007 10:57 am |
|
|
Hi there! I´m using the Rs485 prot to connect 20 pics to a PC. By now i´m only using one to see if i can get results. The problem is that i get the first printf and then when i try to send a char i guess that my pic doesn´t get it. There may be two problems. the first is that the R/T pin may not be down when i try to receive, the other is that can be a problem with my schematic. . Can anyone help me?
here´s the code
Code: |
#ifndef RS485_DRIVER
#define RS485_DRIVER
#ifndef RS485_ID
#define RS485_ID 0x10 // The device's RS485 address or ID
#endif
#ifndef RS485_USE_EXT_INT
#define RS485_USE_EXT_INT FALSE // Select between external interrupt
#endif // or asynchronous serial interrupt
#if(RS485_USE_EXT_INT == FALSE)
#ifndef RS485_RX_PIN
#define RS485_RX_PIN PIN_C7 // Data receive pin
#endif
#ifndef RS485_TX_PIN
#define RS485_TX_PIN PIN_C6 // Data transmit pin
#endif
#ifndef RS485_ENABLE_PIN
#define RS485_ENABLE_PIN PIN_B3 // Controls DE pin. RX low, TX high.
#endif
#ifndef RS485_RX_ENABLE
#define RS485_RX_ENABLE PIN_B3 // Controls RE pin. Should keep low.
#endif
#use rs232(baud=9600, xmit=RS485_TX_PIN, rcv=RS485_RX_PIN, enable=RS485_ENABLE_PIN, bits=9, long_data, errors, stream=RS485)
#use rs232(baud=9600, xmit=RS485_TX_PIN, rcv=RS485_RX_PIN, enable=RS485_ENABLE_PIN, bits=9, long_data, force_sw, multi_master, errors, stream=RS485_CD)
#if getenv("AUART")
#define RCV_OFF() {setup_uart(FALSE);}
#else
#define RCV_OFF() {setup_uart(FALSE);}
#endif
#else
#ifndef RS485_RX_PIN
#define RS485_RX_PIN PIN_B0 // Data receive pin
#endif
#ifndef RS485_TX_PIN
#define RS485_TX_PIN PIN_B3 // Data transmit pin
#endif
#ifndef RS485_ENABLE_PIN
#define RS485_ENABLE_PIN PIN_B4 // Controls DE pin. RX low, TX high.
#endif
#ifndef RS485_RX_ENABLE
#define RS485_RX_ENABLE PIN_B5 // Controls RE pin. Should keep low.
#endif
#use rs232(baud=9600, xmit=RS485_TX_PIN, rcv=RS485_RX_PIN, enable=RS485_ENABLE_PIN, bits=9, long_data, errors, stream=RS485)
#use rs232(baud=9600, xmit=RS485_TX_PIN, rcv=RS485_RX_PIN, enable=RS485_ENABLE_PIN, bits=9, long_data, multi_master, errors, stream=RS485_CD)
#define RCV_OFF() {disable_interrupts(INT_EXT);}
#endif
#define RS485_wait_time 20 // Wait time in milliseconds
#bit rs485_collision = rs232_errors.6
#ifndef RS485_RX_BUFFER_SIZE
#define RS485_RX_BUFFER_SIZE 40
#endif
int rs485_state, rs485_ni, rs485_no;
int rs485_buffer[RS485_RX_BUFFER_SIZE];
// Purpose: Enable data reception
// Inputs: None
// Outputs: None
void RCV_ON(void) {
#if (RS485_USE_EXT_INT==FALSE)
while(kbhit(RS485)) {getc();} // Clear RX buffer. Clear RDA interrupt flag. Clear overrun error flag.
#if getenv("AUART")
setup_uart(UART_ADDRESS);
setup_uart(TRUE);
#else
setup_uart(TRUE);
#endif
#else
clear_interrupt(INT_EXT);
enable_interrupts(INT_EXT);
#endif
}
// Purpose: Initialize RS485 communication. Call this before
// using any other RS485 functions.
// Inputs: None
// Outputs: None
void rs485_init() {
RCV_ON();
rs485_state=0;
rs485_ni=0;
rs485_no=0;
#if RS485_USE_EXT_INT==FALSE
enable_interrupts(INT_RDA);
#else
ext_int_edge(H_TO_L);
enable_interrupts(INT_EXT);
#endif
enable_interrupts(GLOBAL);
output_low(RS485_RX_ENABLE);
}
// The index for the temporary receive buffer
int8 temp_ni;
// Purpose: Add a byte of data to the temporary receive buffer
// Inputs: The byte of data
// Outputs: None
void rs485_add_to_temp(int8 b) {
// Store the byte
rs485_buffer[temp_ni] = b;
// Make the index cyclic
if(++temp_ni >= RS485_RX_BUFFER_SIZE)
{
temp_ni = 0;
}
}
// Purpose: Interrupt service routine for handling incoming RS485 data
#if (RS485_USE_EXT_INT==FALSE)
#int_rda
#else
#int_ext
#endif
void incomming_rs485() {
int16 b;
static int8 cs,state=0,len;
static int16 to,source;
b=fgetc(RS485);
cs^=(int8)b;
switch(state) {
case 0: // Get from address
temp_ni=rs485_ni;
source=b;
cs=b;
rs485_add_to_temp(source);
break;
case 1: // Get to address
to=b;
#if (getenv("AUART")&&(RS485_USE_EXT_INT==FALSE))
setup_uart(UART_DATA);
#endif
break;
case 2: // Get len
len=b;
rs485_add_to_temp(len);
break;
case 255: // Get checksum
if ((!cs)&&(bit_test(to,8))&&(bit_test(source,8))&&((int8)to==RS485_ID)) { // If cs==0, then checksum is good
rs485_ni=temp_ni;
}
#if (getenv("AUART")&&(RS485_USE_EXT_INT==FALSE))
setup_uart(UART_ADDRESS);
#endif
state=0;
return;
default: // Get data
rs485_add_to_temp(b);
--len;
break;
}
if ((state>=3) && (!len)) {
state=255;
}
else {
++state;
}
}
// Purpose: Send a message over the RS485 bus
// Inputs: 1) The destination address
// 2) The number of bytes of data to send
// 3) A pointer to the data to send
// Outputs: TRUE if successful
// FALSE if failed
// Note: Format: source | destination | data-length | data | checksum
int1 rs485_send_message(int8 to, int8 len, int8* data) {
int8 try, i, cs;
int1 ret = FALSE;
RCV_OFF();
#if RS485_USE_EXT_INT
disable_interrupts(GLOBAL);
#endif
for(try=0; try<5; ++try) {
rs485_collision = 0;
fputc((int16)0x100|rs485_id, RS485_CD);
fputc((int16)0x100|to, RS485_CD);
fputc(len, RS485_CD);
for(i=0, cs=rs485_id^to^len; i<len; ++i) {
cs ^= *data;
fputc(*data, RS485_CD);
++data;
}
fputc(cs, RS485_CD);
if(!rs485_collision) {
ret = TRUE;
break;
}
delay_ms(RS485_ID);
}
RCV_ON();
#if RS485_USE_EXT_INT
enable_interrupts(GLOBAL);
#endif
return(ret);
}
// Purpose: Wait for wait time for the RS485 bus to become idle
// Inputs: TRUE - restart the watch dog timer to prevent reset
// FALSE - watch dog timer not restarted
// Outputs: None
void rs485_wait_for_bus(int1 clrwdt)
{
int16 i;
RCV_OFF();
for(i=0; i <= (rs485_wait_time*20); ++i)
{
if(!input(RS485_RX_PIN))
i = 0;
else
delay_us(50);
if(clrwdt)
restart_wdt();
}
}
// Purpose: Get a message from the RS485 bus and store it in a buffer
// Inputs: 1) A pointer to a buffer to store a message
// 2) TRUE - wait for a message
// FALSE - only check if a message is available
// Outputs: TRUE if a message was received
// FALSE if wait is FALSE and no message is available
// Note: Data will be filled in at the pointer as follows:
// FROM_ID DATALENGTH DATA...
int1 rs485_get_message(int* data_ptr, int1 wait)
{
while(wait && (rs485_ni == rs485_no)) {}
if(rs485_ni == rs485_no)
return FALSE;
else {
int n;
n = rs485_buffer[(rs485_no+1)%sizeof(rs485_buffer)] + 2;
for(; n>0; --n)
{
*data_ptr = rs485_buffer[rs485_no];
if(++rs485_no >= sizeof(rs485_buffer))
{
rs485_no = 0;
}
++data_ptr;
}
return TRUE;
}
}
#endif
|
And the rest!!!
Code: |
#include <16F876A.h>
#device *=16
#fuses HS, NOWDT, NOLVP, NOBROWNOUT, NOPROTECT, PUT
#use delay(clock=20000000)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7, stream=PC)
#define RS485_RX_BUFFER_SIZE 64
#define RS485_USE_EXT_INT TRUE
int8 OUR_RS485_ID = 0;
#define RS485_ID OUR_RS485_ID
#include <rs485.c>
#include <stdlib.h>
int8 in_char = 0;
int8 next_in = 0;
int8 next_out = 0;
int8 msg[64];
#INT_RDA
void serial_isr()
{
printf("Interrupt");
in_char = getc(PC);
}
#INT_TIMER1
void timer1_isr()
{
int8 i;
if(rs485_get_message(msg, FALSE))
{
printf("\n\r%d: ", msg[0]);
for(i=0; i < msg[1]; ++i)
putc(msg[i+2]);
printf("\n\r");
}
}
void RS485send(char* s, int8 id)
{
int8 size;
for(size=0; s[size]!='\0'; ++size);
rs485_wait_for_bus(FALSE);
while(!rs485_send_message(id, size, s))
delay_ms(OUR_RS485_ID);
}
char PCgetc()
{
in_char = 0;
while(!in_char);
return in_char;
}
int8 PCgetInt()
{
int8 i, s[3];
for(i=0; (s[i]=PCgetc()) != '\r' && i<3; ++i);
return atoi(s);
}
char* PCgetMsg()
{
int8 i;
for(i=0; (msg[i] = PCgetc()) != '\r' && i<64; ++i);
msg[i] = '\0';
return &(msg[0]);
}
void main()
{
int8 i, send_addr = 0;
char command;
setup_timer_1(T1_INTERNAL | T1_DIV_BY_1);
enable_interrupts(INT_RDA);
enable_interrupts(GLOBAL);
rs485_init();
while(OUR_RS485_ID == 0 || OUR_RS485_ID >= 255)
{
printf("Please choose a network ID (1-255): ");
OUR_RS485_ID = PCgetInt();
}
printf("\n\rYour ID is: %d\n\r\n\rIf you require assistance, press h.\n\r", OUR_RS485_ID);
while(command != 'Q')
{
enable_interrupts(INT_TIMER1);
command = toupper(PCgetc());
disable_interrupts(INT_TIMER1);
switch(command)
{
case 'S':
if(send_addr == 0 || send_addr > 255)
{
printf("\n\r\n\rEnter send address (1-255): ");
send_addr = PCgetInt();
}
printf("\n\r%d:>", send_addr);
RS485send(PCgetMsg(), send_addr);
printf("\n\r");
break;
case 'C':
send_addr = 0;
while(send_addr == 0 || send_addr > 255)
{
printf("\n\r\n\rEnter send address (1-255): ");
send_addr = PCgetInt();
printf("\n\r");
}
break;
case 'I':
OUR_RS485_ID = 0;
while(OUR_RS485_ID == 0 || OUR_RS485_ID >= 255)
{
printf("\n\rPlease choose a network ID (1-255): ");
OUR_RS485_ID = PCgetInt();
}
printf("\n\rYour ID is: %d\n\r\n\r", OUR_RS485_ID);
break;
case 'H':
printf("\n\rCommands: (S)end message, (C)hange Send Address, ");
printf("Change (I)D, (H)elp, (Q)uit.\n\r");
break;
default:
if(command != 'Q')
printf("\n\rInvalid command!\n\r");
}
}
}
|
And the schematic...
http://www.mikroe.com/en/books/picbasicbook/09/rs485.gif
By the way i´m using the Bray terminal is very useful...
Thanks in advance... |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Tue Nov 27, 2007 11:32 am |
|
|
Quote: | void main()
{
int8 i, send_addr = 0;
while(send_addr == 0 || send_addr > 255) |
I didn't look closely at your code, but I did notice that you're testing
to see if an unsigned 8-bit integer will be greater than 255. It can't
be. It's range is only from 0 to 255. |
|
|
Audi80
Joined: 07 Sep 2007 Posts: 41
|
|
Posted: Tue Nov 27, 2007 11:51 am |
|
|
You´re right but it doesn´t even get there. that´s to test if an user set the RS485 ID wrong. I´ve got that example in mplab and the driver too so if i only change the control pins it should work right? the problem is that with the hyperterminal i get the follow message:
"Please choose a network ID (1-255): "
And then when i press 2 it seems that the character doesnt get to the rx in the pic.
If you have any idea would be appreciated...
Thanks... |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Tue Nov 27, 2007 12:12 pm |
|
|
Another problem is that your schematic shows the Enable pin for the
driver chip is connected to pin E0. But your source code uses pin B3.
The source code needs to match the schematic. |
|
|
Audi80
Joined: 07 Sep 2007 Posts: 41
|
|
Posted: Wed Nov 28, 2007 3:53 am |
|
|
Once again your right but i have changed the control pin to PIN_B3 and i´m not using the 16F877 i´m using the 16F876A i think that the example that was in mplab is not controling the RD/WR pin. Do you have any working example?
Thanks |
|
|
|
|
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
|