Rs 485 communication status

For C and ASSEMBLY users to post questions and code snippets for programming in C and ASSEMBLY. And for any other C or ASM course related questions.

Moderators: Benj, Mods

Post Reply
saravana_3
Posts: 61
Joined: Thu Dec 20, 2007 4:23 pm
Location: singapore
Contact:

Rs 485 communication status

Post by saravana_3 »

Hi friends,
I am using the pic 16f877a for the RS 485 master slave communication, I want to see the status of the master chip in the slave boards output, I want logic high in one of the slave output, if some thing happend to the master side the slave side output should goes to the logic low, for this purpose which is the correct bit to be monitored from the master side.

in my application when press the master side PORTB,0 the output will be in the master side PORTD,0, the same output will be transmitted tho the slave side PORTD,0. If I off the master board then the master side PORTD,0 is OFF but in the slave side PORTD,0 is still ON.
how to avoide this, when ever the power off in the master I want to reflect in the slave side
how to do this
please advise me
thanks
Saran
saran

User avatar
Benj
Matrix Staff
Posts: 15312
Joined: Mon Oct 16, 2006 10:48 am
Location: Matrix TS Ltd
Has thanked: 4803 times
Been thanked: 4314 times
Contact:

Re: Rs 485 communication status

Post by Benj »

Hello Saran

I would do the following to get the functionality you require.

Master transmits a byte at a regular interval to state that it is still online. Eg 0.

If the slave device goes for a certain period without receiving this regular byte then it will switch off all of its outputs.

If you require values such as 0 to be sent via the master as data then you could use a array of bytes say 0x55, 0xAA to do the regular update.

I would use the timer interrupts to get this functionality so you get a dependable frequency of transmits and receives.

Hope this helps.

saravana_3
Posts: 61
Joined: Thu Dec 20, 2007 4:23 pm
Location: singapore
Contact:

Re: Rs 485 communication status

Post by saravana_3 »

Hi BENJ,
I have attached the master slave codes can you guide me where to modify to get the regular update (i am using the Micro C)
please
thanks
MASTER

Code: Select all

unsigned int COUNT1, COUNT2, COUNT3, COUNT4, COUNT5, COUNT6, COUNTER_STATUS;
//unsigned int input;
//int test_bit;
//char oldinput;
 char Output_Status , Output_Stat;

char dat[10];                                // buffer for receving/sending messages

// global flegs and counters
char send = 0;
unsigned int SamplePeriod, timer1_count = 0;

// timer1 settings
const char timer1_prescaler = 3;             // timer1 prescaler : real value | timer1_count value
                                             //                    -----------+-------------------
                                             //                         8     |        3
                                             //                         4     |        2
                                             //                         2     |        1
                                             //                         1     |        0

const unsigned int ticks_per_second = 1000;  // set timer1 overflow period : 10     -> 100msec
                                             //                              100    -> 10msec
                                             //                              1000   -> 1msec
                                             //                              10000  -> 100us
                                             //                              100000 -> 10us
                                             // note : for values under 10 and over 100000
                                             //        user must make sure that timer1 supports them
                                             //        with settings in config_timer1() function
                                             //        and change these settings if neccessery

// communication protocol constants (user defined)
const char COMMAND = 0x0AA;
const char DATA = 0xF0;
const char LCD_WRITE = 0x55;
const char COMMANDD = 0x0AB;
// auxilary variables
unsigned int temp;                           // sampled value temporary storage variable
unsigned long tmr1_temp;                     // timer1 reload value storage variable

//-------------- Interrupt routine
void interrupt(){
  if( PIR1.RCIF == 1 ) {                     // if uart interrupt
    RS485master_receive(dat);                // receive rs485 packets
//                                             // Note : this is uneccessery in this example
//                                             // considering that master does not expact
//                                             // any kind of response from slave
  }
  else
    if( PIR1.TMR1IF == 1 ) {                 // if timer1 interrupt
      timer1_count++;                        // increment counter
        if (timer1_count == SamplePeriod) {  // if sample period is reached
          timer1_count = 0;                  // clear counter
          send = 1;                          // set send flag
        }
      TMR1H = tmr1_temp >> 8;                // reload timer1 high
      TMR1L = tmr1_temp;                     // reload timer1 low
      PIR1.TMR1IF = 0;                       //clear timer1 interrupt flag
    }
}//~


void Configure_timer1(char SamplePeriodMs){
  SamplePeriod = SamplePeriodMs;             // set sample period

  T1CON = 0;
  T1CON.TMR1CS = 0;                          // internal clock (Fosc/4)
  T1CON |= timer1_prescaler << 4;            // set timer1 prescaler

  tmr1_temp = (Get_Fosc_kHz()*1000)/(4*(1 << timer1_prescaler)*ticks_per_second);
  tmr1_temp = 65535 - tmr1_temp;             // calc timer1 reload value (period = 1msec)

  TMR1H = tmr1_temp >> 8;                    // load timer1 high
  TMR1L = tmr1_temp;                         // load timer1 low

  T1CON.TMR1ON = 1;                          // enable timer1
}

void configure_interrupts(){
  PIE1.RCIE = 1;                             // enable uart receive interrupts
  PIE1.TMR1IE= 1;                            // enable timer1 interrupt
  INTCON.PEIE = 1;                           // enable periferal interrupts
  INTCON.GIE = 1;                            // global interrupt enable
}

void main(){






  ADCON1 |= 0x06;                            // set all pins as digita I/O
  CMCON  |= 0x07;                            // disable comparators
  PORTD = 0;
  TRISD = 0x00;                        // set PORTD as output

  USART_init(19200);                         // initialize usart module
  Delay_ms(1000);

  Rs485master_Init(&PORTC, 2);               // intialize mcu as master

  Configure_timer1(1);                       // configure timer1 & set sample period in msec
 Configure_interrupts();                    // enable interrupts

 STATUS      = 0X03;
PORTA       = 0X05;
PORTB       = 0X06;
OUTPUT_STATUS = 0X21;
COUNT1        = 0X22;
COUNT2        = 0X23;
//COUNTER_STATUS  = 0X24;
COUNT3          = 0X25;
COUNT4          = 0X26;
COUNT5          = 0X27;
//COUNT6          = 0X28;
//test_bit        = 0X29;
Output_Stat       = 0X30;
PORTA           = 0x0;
TRISA           = 0X00;
PORTB           = 0X0;
TRISB           = 0XFF;
PORTC           = 0;
TRISC           = 0x33;       //30
PORTD           = 0;
TRISD           = 0;
PORTE           = 0;
TRISE           = 0;
 Output_Status   = 0;
 Output_Stat       = 0;
// input = PORTA;
// oldinput = input;
  while (1)           // endless loop
  {


   }

      if (send == 1) {                         // if send fleg is set
      dat[0] = COMMAND;                      // =
      //dat[1] = LCD_WRITE;                   // |
      dat[2] = PORTD;                        // | fill rs485 packet with appropriate values
      dat[5] = 0;                            // |
      dat[6] = 0;                            // =
     Rs485master_Send(dat,3,160);           // send packet
      send = 0;
      }                        //clear send flag
     Delay_ms(30);            //THIS TIMING TO ADJUST THE BUTTON SCANNING

      if (send == 1) {                         // if send fleg is set
      dat[0] = COMMANDD;                      // =
      //dat[1] = LCD_WRITE;                   // |
      dat[2] = PORTE;                        // | fill rs485 packet with appropriate values
      dat[5] = 0;                            // |
      dat[6] = 0;                            // =
     Rs485master_Send(dat,3,160);           // send packet
      send = 0;
      }                        //clear send flag
     Delay_ms(30);            //THIS TIMING TO ADJUST THE BUTTON SCANNING

      if (send == 1) {                         // if send fleg is set
      dat[0] = LCD_WRITE;                      // =
      //dat[1] = LCD_WRITE;                   // |
      dat[2] = PORTA;                        // | fill rs485 packet with appropriate values
      dat[5] = 0;                            // |
      dat[6] = 0;                            // =
     Rs485master_Send(dat,3,160);           // send packet
      send = 0;
      }                        //clear send flag
      Delay_ms(30);    //THIS TIMING TO ADJUST THE BUTTON SCANNING
     asm {
     goto Start
     }

  }

}//~!


SLAVE

Code: Select all

char dat[10];                             // buffer for receving/sending messages

// communication protocol constants (user defined)
const char COMMAND = 0xAA;
const char DATA = 0xF0;
const char LCD_WRITE = 0x55; //initial 0x55
const char COMMANDD = 0xAB;
// auxilary variables
char txt[8];                             // string for holding formated data for lcd display

//-------------- Interrupt routine
void interrupt(){
  Rs485slave_Receive(dat);               // received rs485 packet
}//~

void main() {
   unsigned long temp;
  ADCON1 |= 0xFF;                        // configure all pins as digital I/O
  CMCON  |= 0x07;                        // disable comparators
  PORTD = 0;
  TRISD = 0;                             // configure PORTD as output
   PORTA = 0;
  TRISA = 0;                             // configure PORTD as output
  PORTB = 0;
  TRISB = 0;                             // configure PORTB as output
  PORTE = 0;
  TRISE = 0;
  USART_init(19200);                     // initialize usart module
  Rs485slave_Init(&PORTC, 2, 160);       // intialize mcu as slave, address 160
  dat[4] = 0;                            //esure message reveived flag is zero
  dat[5] = 0;                            // ensure that message received flag is 0
  dat[6] = 0;                            // ensure that error flag is 0
    PIE1.RCIE = 1;                         // enable interrupts
  INTCON.PEIE = 1;                       // on byte received
  PIE2.TXIE = 0;                         // via USART (RS485)
  INTCON.GIE = 1;                        // global interrupt enable


     while (1) {                            // endless loop
       if (dat[4]) {                        // upon completed valid message receive
      dat[4] = 0;                        // data[4] is set to 0xFF
     if( dat[0] == COMMAND )            // if command is received
     
             {
       
          temp = dat[2] << 8;              // load high byte of received data
          temp |= dat[1];                  // load low byte of received data
         PORTD = (temp * 4) / 1024;   // scale 10bit adc result to fit 8bit port
        
      }
              if( dat[0] == LCD_WRITE ) {

           temp = dat[2] << 8;              // load high byte of received data
         temp |= dat[1];                  // load low byte of received data
          PORTA = (temp * 4) / 1024;     // scale 10bit adc result to fit 8bit port
    }
       
    
    
     //if (dat[5])  {                       // if an error detected, signal it by
//      PORTE = 0x01;
//      }      // setting portd to 0xAA
     if( dat[0] == COMMANDD ) {

           temp = dat[2] << 8;              // load high byte of received data
         temp |= dat[1];                  // load low byte of received data
          PORTE = (temp * 4) / 1024;     // scale 10bit adc result to fit 8bit port
    }
    // Delay_ms(10);
    }
  }
}//~!
saran

saravana_3
Posts: 61
Joined: Thu Dec 20, 2007 4:23 pm
Location: singapore
Contact:

Re: Rs 485 communication status

Post by saravana_3 »

hI Benj,
as you mention up i send a sequence of bits from master to slave for the regular update, when there is the communication breakdown in between the master and slave, the slave hollding the latest value from the master when the communication was good because after the breakdown the master cannot send the current value.
for example I am sending continious '1' from master to slave and the slave display the received bit in portE,0. when there is the breakdown the master cannot send the '1' to the slave but the slave still holding the previous value '1' even after the breakdown, it is not updated to the '0'.
i feel eventhough the master want to send the data because of the breakdown the data cannot be send to the slave
any way to solve it.
thanks
Saran
saran

User avatar
Benj
Matrix Staff
Posts: 15312
Joined: Mon Oct 16, 2006 10:48 am
Location: Matrix TS Ltd
Has thanked: 4803 times
Been thanked: 4314 times
Contact:

Re: Rs 485 communication status

Post by Benj »

Hello Saran

The UART will lock up if the buffer gets full. Performing a receive should remove the block and allow the UART to function again.

Here are things to look out for.

1) Is there any data going to the Master, Maybe you could do a dummy RS232 read somewhere through your program loop to avoid the incoming buffer becoming saturated.

2) Is the receive buffer becoming full. Eg if the receive buffer has 3 bytes and a 4th byte is sent then the module will go into its error mode. Performing a receive will clear the error but the receiver will still have 3 bytes in its buffer. Therefore maybe have a macro to clear out the buffer every so often. Alternatively transmit bytes less often to the slave.

Post Reply