|
|
View previous topic :: View next topic |
Author |
Message |
oscaraen
Joined: 03 Jan 2017 Posts: 3
|
RS485 big and undetected problem |
Posted: Thu May 11, 2017 11:14 pm |
|
|
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).
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: 19594
|
|
Posted: Fri May 12, 2017 12:42 am |
|
|
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
|
|
Posted: Fri May 12, 2017 10:57 am |
|
|
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
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..
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 |
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9273 Location: Greensville,Ontario
|
|
Posted: Sat May 13, 2017 9:57 am |
|
|
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 |
|
|
|
|
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
|