CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to support@ccsinfo.com

RS485 big and undetected problem

 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
oscaraen



Joined: 03 Jan 2017
Posts: 3

View user's profile Send private message Send e-mail Visit poster's website

RS485 big and undetected problem
PostPosted: Thu May 11, 2017 11:14 pm     Reply with quote

Hello and thanks for taking the time to help me. I'm having some issues with rs485 comunication. I've designed a network with one master and 3 slaves. I've checked that timing is ok in every slave and in the master, oscilators are working nice, and terminations of the bus are connected as the standard requires. The bus is about 100ft long (50 meters) and when i send a message is received, and it's processed by the right slave. The big problem is, after a time working well, the network seems to crash. Because one slave stops acting after a mesage is sent, and a little time after, the second and the third slaves stop making the actions based on the message. I've tried everything i know but the problem persists. Please help me.
The master of the network is retransmitting the messages received trough i2c
Thanks and apologise me for my english (not so good).
Question Question

This is the master's code. I have a pic16f886 connected to a max485.
The RE and DE pins are the control pins of the IC, and I'm using the hardware usart of the pic.
Code:

#include<16f886.h>
#device ADC=16
#FUSES NOWDT                   //No Watch Dog Timer
#FUSES PUT                     //Power Up Timer
#FUSES NOBROWNOUT              //No brownout reset
#FUSES NOLVP                   //No low voltage prgming, B3(PIC16) or B5(PIC18) used for I/O
#fuses nomclr
#use delay(crystal=20000000)

#define led1 pin_a0
#define led2 pin_a1
#define led3 pin_a2
#define rele5 pin_b3
#define rele4 pin_b4
#define rele3 pin_b7
#define rele2 pin_b6
#define rele1 pin_b5

#define re pin_c0
#define de pin_c6
#define esclavo1 0x0a
#define esclavo2 0x0b
#define esclavo3 0x0c
#define midireccion 0x05 //my address in rs485 network

#use rs232 (baud=9600, bits=8, xmit=pin_c6, rcv=pin_c7,enable=pin_b1, parity=N,Stream=stream)
#use i2c(Slave,Fast,sda=PIN_C4,scl=PIN_C3,force_hw,address=0x31)//el anterior es 12
#define tamano 80
//*******************************************************zona de declaracion de variables*******************************************************
byte posicion=0;
unsigned int8 fstate;
typedef enum {NOTHING, CONTROL_READ,ADDRESS_READ} I2C_STATE;  //

int8 bufferi2c[tamano]={0,0,0,0,0,0,0,0,0,0};  //buffer de recepcion de 3 bytes
int8 recibidos[tamano]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};  //buffer de datos recibidos de esclavos
unsigned int i=0,index=0,multiplicador;
int1 bandera1=0,bandera2=0,bandera3=0,envio=0;
//**********************************************************************************************************************************************
#INT_SSP
void  SSP_isr(void)
{
   byte incoming;                //donde se recibe el byte que manda el maestro
   fstate = i2c_isr_state();     //estado del bus tras la interrupción
   if (fstate == 0x80) {  //Si no hay dato recibido, lectura  del esclavo por el master
   //Manda al maestro la información contenida en la posición de memoria que le ha solicitado     
      i2c_write(bufferi2c[posicion]);
   } 
   else { //Sino es que hay dato en el bus I2C...
      incoming = i2c_read(0);     //... lo lee     
      if (fState == NOTHING){    //Información recibida es aviso de                                que va mandar algo master
         fState = CONTROL_READ;     //Siguiente información será la                             posición donde guardar dato     
      }
      else if (fState == CONTROL_READ) {  //Información recibida                                        corresponde a la posicion
         posicion = incoming;       //Se guarda posición
         fState = ADDRESS_READ;     //Siguiente información recibida                                será el dato     
      }
      else if (fState == ADDRESS_READ){ //Información recibida                                         corresponde al dato
         bufferi2c[posicion] = incoming;   //Se guarda dato
         fState = NOTHING;              //Siguiente información será                                  aviso de nuevo envío del master
         envio=1;
      }
  }
         
}

#int_rda
void serial_isr(){ //rutina de interrupcion por recibido de datos seriales
   char dato;
   dato=getch();
   recibidos[index]=dato;
   index=index+1;
   if(index>70){
      output_toggle(led1); //desborde en led 3
      index=0;
   }
}


void leer(int8 direccion);
void escribir(int8 direccion);
void test_broadcast();
void test_envio1(char direccion);
void test_envio2(char direccion);
void test_envio3(char direccion);
void r_check();
void reconocer();

void main(){
   output_low(re);
   enable_interrupts(int_ssp);
   enable_interrupts(int_rda);
   enable_interrupts(global);//activa las interrupciones para comunicaciones

   output_high(led1);
   output_high(led2);
   output_high(led3);
   delay_ms(1000);
   output_low(led1);
   output_low(led2);
   output_low(led3);
 
   while(true){
      r_check();
      if(bufferi2c[7]!=0){   //si hay direccion esta actua como trigger

        if(bufferi2c[6]==1){   //funcion escribir
           escribir(bufferi2c[7]);
        }
         bufferi2c[7]=0;   //resetea el buffer para determinar que se salió de aqui     
      }
      if(bufferi2c[20]==0xfe){
         reconocer();   //ojo que si no reconoce ,entra a un loop infinito, usar un timeout
         envio=1;
         bufferi2c[20]=0;
      }
      if(bufferi2c[1]==0xaa){
         reset_cpu();
      }
     if(envio){
      envio=0;
         for(i=0;i<55;i++){   //paso al buffer i2c para poder ser leido desde el pc
            bufferi2c[20+i]=recibidos[i];
         }
         
      }
   }
}

void r_check(){
   if(bufferi2c[1]==1){
      output_high(rele1);}
   else{
      output_low(rele1);}
   if(bufferi2c[2]==1){
      output_high(rele2);
   }
   else{
      output_low(rele2);}
   if(bufferi2c[3]==1){
      output_high(rele3);
   }
   else{
      output_low(rele3);}
   if(bufferi2c[4]==1){
      output_high(rele4);
   }
   else{
      output_low(rele4);}
   if(bufferi2c[5]==1){
      output_high(rele5);
   }
   else{
      output_low(rele5);
   }
}

void escribir(int8 direccion){
   output_high(pin_c6);
   output_high(pin_c0);
   putc(0x00);
   putc(0x00);
   putc(direccion);
   for(i=8;i<17;i++){
      putc(bufferi2c[i],stream);
   }
   putc(0xa0,stream);
   putc(0xa1,stream);
   output_low(pin_c6);
   output_low(pin_c0);
}

void reconocer(){//rutina hacerla por esclavos
   for(i=6;i<80;i++){
      recibidos[i-6]=0;//para borrar desde el cero
      bufferi2c[i]=0;//para
   }
   index=0;
   putc(0x00,stream);
   putc(0x0a,stream);  //llama al esclavo 1 y le manda señal para que responda
   putc('!',stream);  //llamado para esclavo 1
   delay_ms(50);
   putc(0x00,stream);
   putc(0x0b,stream);  //llama al esclavo 2 y le manda señal para que responda
   putc('!',stream);  //llamado para esclavo 2
   delay_ms(50);
   putc(0x00,stream);
   putc(0x0c,stream);  //llama al esclavo 3 y le manda señal para que responda
   putc('!',stream);
   delay_ms(50);
   
}


and this is the code for 1 of the 3 slaves. They have the same code, the only thing i've changed is the direction.
Code:

//
#include<16f886.h>
#device ADC=16

#use delay(crystal=20000000) //para 20mhz
#use rs232 (baud=9600, bits=8, xmit=pin_c6, rcv=pin_c7, parity=N, enable=pin_c1,stream=master1)

#FUSES NOWDT                   //No Watch Dog Timer
#FUSES noPUT                     //Power Up Timer
#FUSES NOBROWNOUT              //No brownout reset
#FUSES NOLVP,nomclr            //No low voltage prgming, B3(PIC16) or B5(PIC18) used for I/O
#fuses hs //para 20mhz

#define led1 pin_a0
#define led2 pin_a1
#define led3 pin_a2
#define re pin_c0 //pin de habilitacion del recibidor
#define de pin_c1 //pin de habilitacion del data sendd

#define midireccion 0x0a  //esclavo 1 tiene direccion 10
#define anchopwm50 40
#define anchopwm20 75  //
#define marca_de1 590
#define espacio_de1 1600
#define marca_de0 590
#define espacio_de0 490

//**********************************************************************
#define tamano 40  //buffer de 40 bytes
int index  = 0;
int contador=1;
int recibidos[tamano]={0,0,0,0,0,0,0,0,0};
int1 flag1=0,flag2=0,flag3=0;
int16 direccion,velocidad,temperatura;
void actuacion_datos(int16 code,int primera);


#INT_RDA
void serial_isr()  //rutina de recepcion de datos con un recibidos
{  //version con modificacion en la rutina de recepcion
   char dato;
   dato=getch();
   output_toggle(led2);  //bus activo o inactivo
   if(dato==midireccion){  //si se recibe ok
      index=0;  //posicionamiento en cero cuando reciba la dirección
      flag1=1;
      output_toggle(led1);  //led 1 si recibe a mi direccion
   }
   if(dato=='!'){  //broadcast si se recibe ok
      flag2=1;
   }
   recibidos[index]=dato;
   index=index+1;
   if(index>30){
      index=0;  //queda listo para la proxima recepcion
      output_toggle(led3);
   }
}




void main(){
   setup_timer_2(T2_DIV_BY_1,130,1);      //26.2 us overflow, 26.2 us interrupt -- estaba t2 div by 1, 130, 1
   output_low(re);
   output_low(de);
   //hacer la prueba si se puede modificar la rutina actuacion_datos para funcionar con el timer2 
   enable_interrupts(INT_RDA);      //Habilita interrupción por recepción RS232
   enable_interrupts(GLOBAL);       //Habilita interrupcion global
   output_low(pin_c2);
   setup_ccp1(CCP_PWM|CCP_SHUTDOWN_AC_L|CCP_SHUTDOWN_BD_L);
   set_pwm1_duty(0);
   
   
   while(true){

   
    set_pwm1_duty(0);
    output_toggle(led3);
    delay_ms(200);
     if(flag1  && recibidos[index-1]==0xa1 && recibidos[index-2]==0xa0){

            delay_us(5240);
            actuacion_datos(direccion,1);
            actuacion_datos(velocidad,0);
            actuacion_datos(temperatura,3);
            recibidos[0]=0;//borra para no volver a entrar a la rutina
            recibidos[index]=0;
            flag1=0;
            contador=0;
     }

    if(flag1 && flag2){//si se recibe orden de broadcast
            putc('*');
            putc('e');
            putc('s');
            putc('c');
            putc('1');
            putc('o');
            putc('k');
            putc('*');
            flag1=0; flag2=0;
            output_toggle(led2);

     }
   }
}
   
}

As I said these routines are working. I receive the correct data in every slave and make the functions well, but after a while sending messages everything stops working.


Last edited by oscaraen on Sat May 20, 2017 12:44 am; edited 1 time in total
Ttelmah



Joined: 11 Mar 2010
Posts: 19221

View user's profile Send private message

PostPosted: Fri May 12, 2017 12:42 am     Reply with quote

Question #1.
You talk about termination. Do you have _biasing_ as well as termination?.

<www.ti.com/lit/an/slyt324/slyt324.pdf>
<http://www.edn.com/design/analog/4442598/Understanding-RS-485-passive-fail-safe-biasing->

Some RS485 transceivers are designed to cope without this, but most require it, if you are not to receive garbage when the bus is idle.

Question #2.
What are you doing with the PIC receive inputs when the devices are transmitting?.
Have a look at the threads PCM_programmer points to in this thread:
<http://www.ccsinfo.com/forum/viewtopic.php?t=56154&postdays=0&postorder=asc&start=29>

Both of these are things that will lead to devices receiving things they don't expect....

Then. If you are using the hardware UART (you are), you _must_ have 'ERRORS' in your RS232 declarations, unless you write your own code to handle RS232 error conditions. Not having this can result in the UART receive becoming hung.
Repeat it 50* as a 'mantra'....

Assuming that (for instance) the lack of the pullup, or bias (or just some noise), results in a badly formed character being received, then without this, the receiving UART will become locked.
oscaraen



Joined: 03 Jan 2017
Posts: 3

View user's profile Send private message Send e-mail Visit poster's website

PostPosted: Fri May 12, 2017 10:57 am     Reply with quote

Hello and thanks for replying. About the first question, yes, I have termination resistor in the beginning and in the end of the bus. About biasing, I'm using the max485. In its datasheet it says that "The receiver input has a fail-safe feature that
guarantees a logic-high output if the input is open circuit.", even the application circuit showed is without those resistors because of the feature in the IC.

About the second question, the receiver has two inputs, RE and DE. The first thing I tried was to put DE high and RE low. So, when someone transmits it listens itself. But i wasn't doing nothing with that, so i decided to change, and for every transmission put DE and RE high, and then put RE and DE low, keeping the bus "free" for the use.
Other thing i did was to only put the slaves to listen and receive. Only there is an instruction that make them talk but it was just for checking the network was working and the receivers were working. That worked well and i received "escxok" for each slave (slave=esc), but that instruction was only for my purpose and it won't be used by the end application. In conclusion, the only one who talks is the master every time and the slaves are hearing. About ten or fifteen instructions blum!, the bus hangs Crying or Very sad

I've repeated the mantra, not just 50, 100 times because it was big mistake. I've corrected it and I'm going to reprogram the pics this night.. Very Happy

I have one question, in the threads recommended i saw PCM_programmer suggested a pullup resistor between RX of the pic and RO, I haven't that resistor, can that be part of the problem?

Again thanks a lot for your help I'm going make the program changes and try them and post what happens.

bye Very Happy
temtronic



Joined: 01 Jul 2010
Posts: 9109
Location: Greensville,Ontario

View user's profile Send private message

PostPosted: Sat May 13, 2017 9:57 am     Reply with quote

I didn't see 'errors' in the use rs232(..options...)
If you're using the hardware UART, then you need (must) add errors to the options, it'll keep the UART from 'locking up'....

Also with any serial receive, it's best to use buffers, see ex_sisr.c as an example from CCS.

Jay
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
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