Autor Tema: Enviar comando en hexadecimal a sensor RS485  (Leído 2126 veces)

0 Usuarios y 1 Visitante están viendo este tema.

Desconectado claudiovega

  • PIC10
  • *
  • Mensajes: 31
Enviar comando en hexadecimal a sensor RS485
« en: 16 de Agosto de 2016, 15:52:18 »
Estimados:
Tengo un sensor RS485 el cual recibe un comando en hexadecimal y responde un dato de profundidad en ASCII. El comando a enviar es: 24 30 31 52 50 30 33 33 0D
Una respuesta sería: *01+5.0000 (viene con \r al final)

Problema:
No recibo respuesta desde el sensor en una protoboard. Si tengo respuesta en una simulación con proteus (en el terminal del sensor escribo algo y presiono enter).

Datos:
PIC: 16F82550
Compilador: CCS 4

A continuación pego el código C usado:

Código: [Seleccionar]
#include <18F2550.h>
#include <stdlib.h>

#fuses INTRC,MCLR,NOWDT,NOPROTECT,NOPUT,NOBROWNOUT,NOLVP,NOCPD
#use delay(clock=4000000)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7, STREAM=SENSOR, parity=N, bits=8)
#use rs232(baud=9600, xmit=PIN_B6, rcv=PIN_B7, STREAM=SCREEN, parity=N, bits=8)

char p, response[20] = "", command[9];
int k = 0, i = 0, contador = 0;
int1 newresponse = 0, newsecond = 0;
#define TX_485_ENABLE PIN_C0

// subrutina de interrupción del timer1
#int_TIMER1                               
void TIMER1_isr(){ 
contador++;
if(contador == 2){
newsecond = 1;
contador = 0;
}           
set_timer1(3036);
}

//interrupcion por usart del pic
#INT_RDA
void usart_modem(void)

p = fgetc(SENSOR);
if(p == '\r') {
response[k] = '\0';
newresponse = 1;
k = 0;
}else if(p){
response[k] = p;
k++;
}
}
//funciones 485
void USART_activa_tx(void){
  output_high(TX_485_ENABLE);
  delay_ms(5);
}
void USART_activa_rx(void){
  delay_ms(5);
  output_low(TX_485_ENABLE);
  delay_ms(1);
}
/********* Programa Principal *********/
void main(void)
{
setup_timer_1(T1_INTERNAL|T1_DIV_BY_8);
enable_interrupts(INT_TIMER1);
enable_interrupts(INT_RDA);
enable_interrupts(GLOBAL);
set_timer1(3036);
//activo PIN_B7 como entrada
set_tris_b(0b10000000);
//pines B0 a B5 apagados, B6 y B7 no se tocan
output_bit(PIN_B0, 0);
output_bit(PIN_B1, 0);
output_bit(PIN_B2, 0);
output_bit(PIN_B3, 0);
output_bit(PIN_B4, 0);
output_bit(PIN_B5, 0);
//activo PIN_C7 como entrada
set_tris_c(0b10000000);
//pines C0 a C5 apagados, C6 y C7 no se tocan
output_bit(PIN_C0, 0);
output_bit(PIN_C1, 0);
output_bit(PIN_C2, 0);
output_bit(PIN_C3, 0);
output_bit(PIN_C4, 0);
output_bit(PIN_C5, 0);
//mensajes sólo para saber que terminal es de cada dispositivo
fprintf(SCREEN, "SCREEN\r");
USART_activa_tx();
fprintf(SENSOR, "SENSOR\r");
USART_activa_rx();
//defino comando a enviar
command[0] = 36;
command[1] = 48;
command[2] = 49;
command[3] = 82;
command[4] = 80;
command[5] = 48;
command[6] = 51;
command[7] = 51;
command[8] = 13; 
//compruebo que se enciende led en C1
output_bit(PIN_C1, 1);
delay_ms(500);
output_bit(PIN_C1, 0);

while(TRUE)
{
if(newresponse){
//si se recibe una respuesta la escribo en SCREEN
newresponse = 0;
fprintf(SCREEN, "%s", response);
//prendo led en C1
output_bit(PIN_C1, 1);
delay_ms(100);
output_bit(PIN_C1, 0);
}else if (newsecond){
//si ha pasado un segundo envio comando
USART_activa_tx();
for(i=0; i<9; i++)
putc(command[i]);
USART_activa_rx();
newsecond = 0;
//activo led en C2
output_bit(PIN_C2, 1);
delay_ms(100);
output_bit(PIN_C2, 0);
}
}
}

Adjunto también imagen png del esquema en proteus.
De antemano gracias por cualquier ayuda.

Desconectado KILLERJC

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 8242
Re:Enviar comando en hexadecimal a sensor RS485
« Respuesta #1 en: 16 de Agosto de 2016, 16:11:45 »
Código: C
  1. void USART_activa_rx(void){
  2.   delay_ms(5);
  3.   output_low(TX_485_ENABLE);
  4.   delay_ms(1);
  5. }

Tal ves los delays te estan molestando, pienso que deberias usar alguna otra funcion que te permita saber si ya se envio todo, y cuando finalize proceda a cambiar el enable. Se como hacerlo con los registros pero en CCS no.

Otras cosas que veo y que no entiendo:
Estas usando set_tris cuando no tenes puesto los puertos como FAST_IO
Estas modificando uno por uno los pines en ves de usar output_x()
Te complicas con decimales (en el array command ) cuando podrias haberlo escrito en hexadecimal tranquilamente 0x24 0x30 0x31 0x52 0x50, en ASCII '*','0','1' o podrias haberlo realizado un string:

Código: C
  1. command[]= "*01RP033\r";

El set_timer debe estar primero en la rutina de TIMER1, antes de contador++ para minimizar el error.
El if(p) no tiene sentido en la rutina de interrupcion, simplemente con el else es suficiente.

Desconectado claudiovega

  • PIC10
  • *
  • Mensajes: 31
Re:Enviar comando en hexadecimal a sensor RS485
« Respuesta #2 en: 16 de Agosto de 2016, 17:45:21 »
Hola, gracias por la respuesta.
Implementé los cambios sugeridos, el resultado es el mismo.
Aquí los cambios en el código:
Código: [Seleccionar]
#include <18F2550.h>
#include <stdlib.h>

#fuses INTRC,MCLR,NOWDT,NOPROTECT,NOPUT,NOBROWNOUT,NOLVP,NOCPD
#use delay(clock=4000000)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7, STREAM=SENSOR, parity=N, bits=8)
#use rs232(baud=9600, xmit=PIN_B6, rcv=PIN_B7, STREAM=SCREEN, parity=N, bits=8)

char p, response[20] = "", command[9];
int k = 0, contador = 0;
int1 newresponse = 0, newsecond = 0;
#define TX_485_ENABLE PIN_C0

// subrutina de interrupción del timer1
#int_TIMER1                               
void TIMER1_isr(){ 
set_timer1(3036);
contador++;
if(contador == 2){
newsecond = 1;
contador = 0;
}           
}

//interrupcion por usart del pic
#INT_RDA
void usart_modem(void)

p = fgetc(SENSOR);
if(p == '\r') {
response[k] = '\0';
newresponse = 1;
k = 0;
}else if(p){
response[k] = p;
k++;
}
}
//funciones 485
void USART_activa_tx(void){
  output_high(TX_485_ENABLE);
  delay_ms(5);
}
void USART_activa_rx(void){
  output_low(TX_485_ENABLE);
}
/********* Programa Principal *********/
void main(void)
{
setup_timer_1(T1_INTERNAL|T1_DIV_BY_8);
enable_interrupts(INT_TIMER1);
enable_interrupts(INT_RDA);
enable_interrupts(GLOBAL);
set_timer1(3036);
output_B(0b10000000);
//mensajes sólo para saber que terminal es de cada dispositivo
fprintf(SCREEN, "SCREEN\r");
USART_activa_tx();
fprintf(SENSOR, "SENSOR\r");
USART_activa_rx();
strcpy(command, "$01RP033\r");
//compruebo que se enciende led en C1
output_bit(PIN_C1, 1);
delay_ms(500);
output_bit(PIN_C1, 0);

while(TRUE)
{
if(newresponse){
//si se recibe una respuesta la escribo en SCREEN
newresponse = 0;
fprintf(SCREEN, "%s", response);
//prendo led en C1
output_bit(PIN_C1, 1);
delay_ms(100);
output_bit(PIN_C1, 0);
}else if (newsecond){
//si ha pasado un segundo envio comando
USART_activa_tx();
fprintf(SENSOR, "%s", command);
USART_activa_rx();
newsecond = 0;
//activo led en C2
output_bit(PIN_C2, 1);
delay_ms(100);
output_bit(PIN_C2, 0);
}
}
}
Estuve probando con una consola serial (Hércules).
Si envío la cadena "$01RP033\r" el sensor no responde.
Si envío como hexadecimal (24 30 31 52 50 30 33 33 0D) el sensor responde correctamente.
Eso me dice que el sensor no está respondiendo pues no entiende el comando.
¿Alguna idea de por qué podría pasar esto último?

Desconectado KILLERJC

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 8242
Re:Enviar comando en hexadecimal a sensor RS485
« Respuesta #3 en: 16 de Agosto de 2016, 18:57:24 »
Citar
Si envío la cadena "$01RP033\r" el sensor no responde.
Si envío como hexadecimal (24 30 31 52 50 30 33 33 0D) el sensor responde correctamente.
Eso me dice que el sensor no está respondiendo pues no entiende el comando.
¿Alguna idea de por qué podría pasar esto último?

Que este enviando mas cosas. tal ves envie un \n\r cuando presionas Enter. Normalmente podes ver lo enviado en hexadecimal, no se si lo permite el Hercules, asi vas a ver si esta enviando algo mas. el \r es para el lenguaje C, si lo envias por el Hercules seria como 2 letras '\' y 'r'

Desconectado claudiovega

  • PIC10
  • *
  • Mensajes: 31
Re:Enviar comando en hexadecimal a sensor RS485
« Respuesta #4 en: 17 de Agosto de 2016, 13:43:32 »
Finalmente era un problema del circuito armado en la protoboard, de alguna forma distorsionaba el mensaje.
Este es el código final, el cual creo que tiene algún problema de corrupción de memoria dado que después de un tiempo el comando se ve alterado, razón por la cual asigno de nuevo la variable command justo antes de enviarla al sensor (eso soluciona el problema).
Si alguien quiere darle una mirada e indicarme como podría mejorarlo para evitar dicha corrupción. Yo imagino que debería estar en la variable response (la respuesta del sensor es siempre de largo 12)

Código: [Seleccionar]
#include <18F2550.h>
#include <stdlib.h>

#fuses INTRC,MCLR,NOWDT,NOPROTECT,NOPUT,NOBROWNOUT,NOLVP,NOCPD
#use delay(clock=4000000)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7, STREAM=SENSOR, parity=N, bits=8)
#use rs232(baud=9600, xmit=PIN_B6, rcv=PIN_B7, STREAM=SCREEN, parity=N, bits=8)

char p, response[13] = "", command[9];
int k = 0, contador = 0, i = 0;
int1 newresponse = 0, newsecond = 0;
#define TX_485_ENABLE PIN_C0

// subrutina de interrupción del timer1
#int_TIMER1                               
void TIMER1_isr(){ 
set_timer1(3036);
contador++;
if(contador == 10){
newsecond = 1;
contador = 0;
}           
}

//interrupcion por usart del pic
#INT_RDA
void usart_modem(void)

p = fgetc(SENSOR);
if(p == '\r') {
response[k] = '\0';
newresponse = 1;
k = 0;
}else if(p){
response[k] = p;
k++;
}
}

//funciones 485
void USART_activa_tx(void){
  output_high(TX_485_ENABLE);
  delay_ms(5);
}
void USART_activa_rx(void){
  delay_ms(5);
  output_low(TX_485_ENABLE);
  delay_ms(1);
}

/********* Programa Principal *********/
void main(void)
{
setup_timer_1(T1_INTERNAL|T1_DIV_BY_8);
enable_interrupts(INT_TIMER1);
enable_interrupts(INT_RDA);
enable_interrupts(GLOBAL);
set_timer1(3036);
output_B(0b10000000);
//led
output_bit(PIN_C1, 1);
output_bit(PIN_C2, 1);
delay_ms(500);
output_bit(PIN_C1, 0);
output_bit(PIN_C2, 0);
while(TRUE)
{
if(newresponse){
newresponse = 0;
fprintf(SCREEN, "%s", response);
output_bit(PIN_C1, 1);
delay_ms(100);
output_bit(PIN_C1, 0);
}else if (newsecond){
//comando a enviar
command[0] = 36;
command[1] = 48;
command[2] = 49;
command[3] = 82;
command[4] = 80;
command[5] = 48;
command[6] = 51;
command[7] = 51;
command[8] = 13;
USART_activa_tx();
for(i=0; i<9; i++)
putc(command[i]);
USART_activa_rx();
newsecond = 0;
output_bit(PIN_C2, 1);
delay_ms(100);
output_bit(PIN_C2, 0);
}
}
}

Desconectado KILLERJC

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 8242
Re:Enviar comando en hexadecimal a sensor RS485
« Respuesta #5 en: 17 de Agosto de 2016, 14:33:09 »
Usa al menos:

Código: C
  1. const char command[9] = {36,48,49,82,80,48,51,51,13};

Asi lo guarda en la flash y no en la RAM, entonces no vas a tener problema de que algo lo escriba, y si intentas hacerlo el compilador te deberia dar error.