Continue to Site

Welcome to EDAboard.com

Welcome to our site! EDAboard.com is an international Electronics Discussion Forum focused on EDA software, circuits, schematics, books, theory, papers, asic, pld, 8051, DSP, Network, RF, Analog Design, PCB, Service Manuals... and a whole lot more! To participate you need to register. Registration is free. Click here to register now.

[PIC] RS485 Hanging Problem

Status
Not open for further replies.

apsua

Member level 3
Member level 3
Joined
Feb 13, 2015
Messages
62
Helped
1
Reputation
2
Reaction score
1
Trophy points
8
Activity points
538
Hello,

I have a two board rs485 communicating system, one uses PIC18F452, the other uses PIC16F628.
When I start serial communication, it hangs after some time passes, it stops communicating. If I restart PIC16F628 when 4-5 second non-communication happens, it starts working correctly. Sometimes PIC18 also needs to be resetted.

What can be the problem? I don't want to reset the chips.

Thanks in advance.
 

It could be many things but it looks like the problem is at the 16F628 end of the link. It is almost certainly a software problem, possibly a stack overflow as it happens after a while. You will have to post your software so we can investigate.

Brian.
 
  • Like
Reactions: apsua

    apsua

    Points: 2
    Helpful Answer Positive Rating
The interrupts and rs485 lib is as below. By the way, the controller doesn't hang, the communication stops.
I couldn't find the reason(maybe it is an easy thing), so I temporarily apply reset function, but it is not good solution.

Code:
#define	RS485_RX_PIN				PIN_B1
#define	RS485_TX_PIN				PIN_B2
#define	RS485_ENABLE_PIN			PIN_B0
#bit		BIT_RS485_EN_PIN			= getenv("sfr:PORTB").0
#bit		RS485_CREN					= getenv("bit:CREN")
#define	RS485_BAUD					9600
#define	RS485_RX_BUFFER_SIZE		40

#ifndef	MULTI_ALL
#define	MULTI_ALL					0
#endif

#define	OFF							0
#define	ON								1

#use rs232(BAUD=RS485_BAUD, xmit=RS485_TX_PIN, rcv=RS485_RX_PIN, enable=RS485_ENABLE_PIN, bits=9, long_data, errors, stream=RS485)

int rs485IndexLast;
int rs485IndexFirst;
int tempIndexLast;
int rs485Buffer[RS485_RX_BUFFER_SIZE];	//
int rs485ID;	// 
int tempMultiMode;
int to;
int1 addressMode;	
int ctrl_length;
int unusedReg0;
int unusedReg1;
int unusedReg2;
int unusedReg3;

void RcvOn();
void RcvOff();
void Rs485Init();
void Rs485SetID(int);
void Rs485AddToTemp(int);
void Rs485IncomingData();
void Rs485SendData(int, int, int*);
int1 Rs485GetData(int*);


void RcvOn()
{
	// RCREG ve FIFO'lar doluysa boşalt
	while(kbhit(RS485)) {getc();}

	if(addressMode == OFF)
	{
		setup_uart(UART_DATA);
	}
	else // addressMode == ON
	{
		setup_uart(UART_ADDRESS);
	}
	setup_uart(TRUE);
	enable_interrupts(INT_RDA);
}

void RcvOff()
{
	RS485_CREN = 0;
	disable_interrupts(INT_RDA);
}

void Rs485Init(int1 addMode)
{
	addressMode = addMode;
	RcvOn();
	rs485IndexLast = 0;
	rs485IndexFirst = 0;
	enable_interrupts(INT_RDA);
	enable_interrupts(GLOBAL);
	BIT_RS485_EN_PIN = 0;
}

void Rs485SetID(int ID)
{
	rs485ID = ID;
}

void Rs485AddToTemp(int data)
{
	rs485Buffer[tempIndexLast] = data;
	// geçici indexi arttır, dizi boyutunu geçerse 0 yap.
	if(++tempIndexLast >= RS485_RX_BUFFER_SIZE)
	{
		tempIndexLast = 0;
	}
}

void Rs485IncomingData()
{
	int16 data;
	int1 clearState = 0;
	static int checksum;	
	static int state;	
	static int length;	
	//static int to;	
	static int source;	

	data = fgetc(RS485);
	checksum ^= (int8)data;

	switch(state)
	{
		case 0:	// Source
			if((data & 0xF0) == 0xE0)
			//if((data & 0x0F) == 1)					// SERIAL_MASTER
			{
				clearState = 0;
				checksum = data;
				data &= 0x0F;
				tempIndexLast = rs485IndexLast;
				source = data;
				Rs485AddToTemp(data);
			}
			else
			{
				clearState = 1;
			}
			break;
		case 1:	// To
			if((data & 0xF0) == 0xF0)
			//if((data & 0x0F) == 2)					// SERIAL_SLAVE
			{
				clearState = 0;
				data &= 0x0F;
				to = data;
			}
			else
			{
				clearState = 1;
			}
			break;
		case 2:	// Length
			//length = data;
			//Rs485AddToTemp(data);
			length = data;
			if(length > 5)
			{
				clearState = 1;
				length = 0;
			}
			else
			{
				Rs485AddToTemp(data);
			}
			break;
		case 255: // Checksum
			if((checksum == 0) && ((to == rs485ID) || (to == MULTI_ALL) || (to == tempMultiMode)))
			{
				rs485IndexLast = tempIndexLast;
			}
			state = 0;
			return;
		default:	// Data
			Rs485AddToTemp(data);
			--length;
			break;
	}
	if(clearState)
	{
		state = 0;
	}
	else if(state >= 3 && !length)
	{
		state = 255;
	}
	else
	{
		state++;
	}
}

void Rs485SendData(int to, int length, int* data)
{
	int index;
	int checksum;
	int tempID;
	int tempTo;
	int16 address = 0;

	tempID = 0xE0 | rs485ID;
	tempTo = 0xF0 | to;

	if(addressMode == 0)
	{
		address = 0x100;
	}
	RcvOff();
	disable_interrupts(GLOBAL);
	output_high(RS485_ENABLE_PIN);
	delay_ms(4);
	fputc((int16)address|tempID, RS485);
	delay_ms(2);
	//fputc((int16)address|rs485ID, RS485);
	fputc((int16)address|tempTo, RS485);
	delay_ms(2);
	fputc((int16)address|length, RS485);
	delay_ms(2);
	checksum = tempTo^tempID^length;
	for(index = 0; index < length; index++)
	{
		checksum ^= *data;
		fputc((int16)address|*data, RS485);
		delay_ms(2);
		++data;
	}
	fputc((int16)address|checksum, RS485);
	enable_interrupts(GLOBAL);
	RcvOn();
}

int1 Rs485GetData(int* data)
{
	int length;
	int temp;

	if(rs485IndexLast == rs485IndexFirst)
		return FALSE;

	temp = rs485IndexFirst + 1;
	if(temp == RS485_RX_BUFFER_SIZE)
	{
		temp = 0;
	}

	length = rs485Buffer[temp] + 2;
	ctrl_length = length;

	for(; length > 0; length--)
	{
		*data = rs485Buffer[rs485IndexFirst];
		if(++rs485IndexFirst == RS485_RX_BUFFER_SIZE)
		{
			rs485IndexFirst = 0;
		}
		++data;
	}
	return TRUE;
}

Code:
#INT_RDA
void rsReceiveInt()
{
	/*if(RCSTAFERR || RCSTAOERR)
	{
		int a;
		RS485_CREN = 0;
		a = RCREG;
		RCSTAFERR = 0;
		RCSTAOERR = 0;
		RS485_CREN = 1;
		proteus++;
		return;
	}*/
	Rs485IncomingData();
}
 

@btwixt : Now, I got the point, I am investigating it, I will inform here if solved.

- - - Updated - - -

I have checked the program in Proteus, and I see that in the stack information box, I see addresses like 0x15FB. It seems too high for PIC16F628. The indicator was also the 8th stage. I will try to correct it, but I cant find where the problem is because of the abnormal address points. The previous stack address is in RS485AddToTemp Function which is as below:

Code:
//*********************************************************
// Explanation 	:	Adding the RS485 data to buffer
// Input              : 	data - The data to add to the buffer
// Returning Value : 	None
//*********************************************************
void Rs485AddToTemp(int data)
{
	rs485Buffer[tempIndexLast] = data;
	if(++tempIndexLast >= RS485_RX_BUFFER_SIZE)
	{
		tempIndexLast = 0;
	}
}
 

Hello,
I have solved the resetting problem, but other problems occuring. So I decided to try to change the rs485.c file completely with the one exists in the drivers directory of the ccs c.

But now, no serial communication is happening, because of the rs232 collision error. I am attaching the codes below:

Main card - PIC18F452 - Interrupt routine
Code:
#INT_TIMER1
void timerInt()
{
   disable_interrupts(GLOBAL);
   set_timer1 (40536);           
//   TMR1IF = 0;
	PIR1TMR1IF = 0;
   baseTimerB = 1;
   enable_interrupts(GLOBAL);
   clear_interrupt(int_timer1);
   return;
}

// RS232 receive interrupt
#INT_RDA HIGH

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;
   }
}

Main card - PIC18F452 - rs485.c
Code:
/////////////////////////////////////////////////////////////////////////
////                            RS485.c                              ////
////                                                                 ////
////      This file contains drivers for RS-485 communication        ////
/////////////////////////////////////////////////////////////////////////
////                                                                 ////
//// int1 rs485_get_message(int* data_ptr, int wait)                 ////
////     * Get a message from the RS485 bus                          ////
////     * Address can be 1 - 33.                                    ////
////     * A 1 will be returned if a parity check error occurred.    ////
////                                                                 ////
//// int1 rs485_send_message(int to, int len, int* data)             ////
////     * Send a message over the RS485 bus                         ////
////     * Inputs:                                                   ////
////          to    - Destination address                            ////
////          len   - Message length                                 ////
////          *data - Pointer to message                             ////
////     * Returns TRUE if successful, FALSE if failed               ////
////                                                                 ////
//// void rs485_wait_for_bus(int1 clrwdt)                            ////
////     * Wait for the RS485 bus to open. Normally used before      ////
////       sending a message to avoid collisions.                    ////
////     * Pass in TRUE to restart the watch dog timer to prevent    ////
////       the device from resetting.                                ////
////     * This is not needed if sending an immediate response       ////
////                                                                 ////
/////////////////////////////////////////////////////////////////////////
////        (C) Copyright 1996, 2004 Custom Computer Services        ////
//// This source code may only be used by licensed users of the CCS  ////
//// C compiler.  This source code may only be distributed to other  ////
//// licensed users of the CCS C compiler.  No other use,            ////
//// reproduction or distribution is permitted without written       ////
//// permission.  Derivative programs created using this software    ////
//// in object code form are not restricted in any way.              ////
/////////////////////////////////////////////////////////////////////////

#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_C4   // Controls DE pin.  RX low, TX high.
   #endif

   #ifndef RS485_RX_ENABLE
   #define RS485_RX_ENABLE    PIN_C4   // 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, force_sw, 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*/



// 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

Serial card - PIC16f628 - Interrupts
Code:
#INT_RDA
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;
   }
}

#INT_TIMER1
void timerInt()
{
   disable_interrupts(GLOBAL);
   set_timer1 (15535); 
//   TMR1IF = 0;
	PIR1TMR1IF = 0;
   b_baseTimer = 1;
   enable_interrupts(GLOBAL);
   clear_interrupt(int_timer1);

   return;
}

Serial card - PIC16f628 - Rs485.c
Code:
/////////////////////////////////////////////////////////////////////////
////                            RS485.c                              ////
////                                                                 ////
////      This file contains drivers for RS-485 communication        ////
/////////////////////////////////////////////////////////////////////////
////                                                                 ////
//// int1 rs485_get_message(int* data_ptr, int wait)                 ////
////     * Get a message from the RS485 bus                          ////
////     * Address can be 1 - 33.                                    ////
////     * A 1 will be returned if a parity check error occurred.    ////
////                                                                 ////
//// int1 rs485_send_message(int to, int len, int* data)             ////
////     * Send a message over the RS485 bus                         ////
////     * Inputs:                                                   ////
////          to    - Destination address                            ////
////          len   - Message length                                 ////
////          *data - Pointer to message                             ////
////     * Returns TRUE if successful, FALSE if failed               ////
////                                                                 ////
//// void rs485_wait_for_bus(int1 clrwdt)                            ////
////     * Wait for the RS485 bus to open. Normally used before      ////
////       sending a message to avoid collisions.                    ////
////     * Pass in TRUE to restart the watch dog timer to prevent    ////
////       the device from resetting.                                ////
////     * This is not needed if sending an immediate response       ////
////                                                                 ////
/////////////////////////////////////////////////////////////////////////
////        (C) Copyright 1996, 2004 Custom Computer Services        ////
//// This source code may only be used by licensed users of the CCS  ////
//// C compiler.  This source code may only be distributed to other  ////
//// licensed users of the CCS C compiler.  No other use,            ////
//// reproduction or distribution is permitted without written       ////
//// permission.  Derivative programs created using this software    ////
//// in object code form are not restricted in any way.              ////
/////////////////////////////////////////////////////////////////////////

#ifndef RS485_DRIVER
#define RS485_DRIVER

#ifndef RS485_ID
#define RS485_ID  0x20                 // 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_B1   // Data receive pin
   #endif

   #ifndef RS485_TX_PIN
   #define RS485_TX_PIN       PIN_B2   // Data transmit pin
   #endif

   #ifndef RS485_ENABLE_PIN
   #define RS485_ENABLE_PIN   PIN_B0   // Controls DE pin.  RX low, TX high.
   #endif

   #ifndef RS485_RX_ENABLE
   #define RS485_RX_ENABLE    PIN_B0   // 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*/



// 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

I will be very glad for the helps.
Thanks.
 

Status
Not open for further replies.

Similar threads

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top