Comunicación RS-485 PIC C CCS

una consulta yo veo que en el programa que enviaste pusiste msg[10] pregunto porque no manejo mucho string no es como un BASIC que podes tu nombre y lo envia C es mas rompe con eso y mucho no lo se, pero en deduccion veo que podes enviar 9 caracteres entiendo, entonces : el programa que envia dice msg[0]='a' ; si quiero enviar dos letras ejemplo a1 pondria msg="a1", y con eso listo error el compilador no me tira calculo que esta bien, y en el caso receptor puse *msg="a1" porque si no coloco asterisco me da error, pero veo que no funciona , el receptor que enviaste pusiste msg[2]='a', pero si recibo dos letras como "a1" no me llega noto
 
Por eso te mencioné que la función usa un arreglo pasado cómo puntero.
También dije que para usar un int y no un arreglo, se tendrían que realizar más modificaciones.

Ya tienes la base, sólo te resta modificar la librería.
 
Hola aqui intente hacer una respuesta con lo que me enseñaste, con la unica modificacion que hice ahora que fue agregar dos leds en el receptor y cuando envio "L1ON" del master enciende el Led 1, "L2ON" enciende el led dos en el esclavo y "L3OFF" apaga los dos medio que me esta funcionando o quiero entender que la respuesta del esclavo hacia el master llega porque sino no me enviaria el otro dato pero noto que no me encienden los leds como quiero como que por momentos engancha y momentos no algo no me esta engranando ahi.
Siendo que lo que envia el master lo envia bien y en el esclavo estoy viendo como llega por ejemplo el "L1ON"

lo raro que cuando uso el comando switch funciona o tiende a funcionar con el IF no en el esclavo eso.

MASTER
Código:
#include <16F818.h>
#device  *=16
#ignore_warnings  201, 216
#fuses   NOWDT
#use     delay(internal = 8MHz)  // Usar 20 MHz para montaje en físico.
#use     rs232(baud=9600, xmit=PIN_B2, rcv=PIN_B1, stream=PC)

#define  RS485_RX_BUFFER_SIZE 12
#define  RS485_USE_EXT_INT    TRUE


#define RS485_RX_PIN       PIN_B0   // Data receive pin
#define RS485_TX_PIN       PIN_B7   // Data transmit pin
#define RS485_ENABLE_PIN   PIN_B3   // Controls DE pin.  RX low, TX high.
#define RS485_RX_ENABLE    PIN_B2   // Controls RE pin.  Should keep low.



int8 OUR_RS485_ID = 0x10;
#define RS485_ID OUR_RS485_ID

#include <rs485.c>
#include <stdlib.h>

int1 flag_rs485=0;
int8 i;
char msg[10];
char dato[10];

#INT_TIMER1
void timer1_isr()
{
 //  int8 i;

   if(rs485_get_message(msg, FALSE))
   {
      flag_rs485 = 1;
       for(i=0; i < msg[1]; ++i)
         dato[i] = (msg[i+2]);
      //printf("\n\r%d: ", msg[0]);
      /*
      for(i=0; i < msg[1]; ++i)
         putc(msg[i+2]);
         printf("\n\r");
         */
   }
}


void clean_msg (void)
{
   for(i=0;i<sizeof(msg);i++)
   {
      msg[i] = 0x00;
      dato[i] = 0x00;
   }
}

void RS485send(char* s, int8 id)
{
   int8 size;

   for(size=0; s[size]!='\0'; ++size);

   rs485_wait_for_bus(FALSE);

   while(!rs485_send_message(id, size, s))
      delay_ms(OUR_RS485_ID);
           
}

int1 ask()
{
      if(flag_rs485)
      {
         disable_interrupts(INT_TIMER1);
         flag_rs485 = 0;
         
         if(msg[2] == '1')
            output_high(PIN_B4);         
         
         delay_ms(50);
         output_low(PIN_B4); 
         delay_ms(50);
         
         clean_msg();
        // rs485_wait_for_bus(FALSE);
         enable_interrupts(INT_TIMER1);
         delay_ms(100);      
         return true;
      }
}


void main()
{
   //int8 i;
   setup_timer_1(T1_INTERNAL | T1_DIV_BY_1);
   //enable_interrupts(INT_RDA);
//   enable_interrupts(GLOBAL);
   rs485_init();
   enable_interrupts(INT_TIMER1);
   
   while (true)
   {
      //if(!input(PIN_A2))
      //{
      do
      {
         msg = "L1ON";
         RS485send(msg, 0x12);
         delay_ms(150); 
      }
      while(!ask());
      //   while(!input(PIN_A2));
      //}

     
      do
      {
         msg = "L2ON";
         RS485send(msg, 0x12);
         delay_ms(150); 
      }
      while(!ask());
      
      do
      {
         msg = "L3OFF";
         RS485send(msg, 0x12);
         delay_ms(150); 
      }
      while(!ask());
      

   }
}



ESCLAVO
Código:
#include <16F887.h>
#device  *=16
#ignore_warnings  201, 216
#fuses   NOWDT
#use     delay(internal = 8MHz)  // Usar 20 MHz para montaje en físico.

#define  RS485_RX_BUFFER_SIZE 12
#define  RS485_USE_EXT_INT    TRUE

#define RS485_RX_PIN       PIN_B0   // Data receive pin
#define RS485_TX_PIN       PIN_B1   // Data transmit pin
#define RS485_ENABLE_PIN   PIN_B7   // Controls DE pin.  RX low, TX high.
#define RS485_RX_ENABLE    PIN_B6   // Controls RE pin.  Should keep low.


int8 OUR_RS485_ID = 0x12;
#define RS485_ID OUR_RS485_ID


#include <rs485.c>
//#include <string.h>

int1 flag_rs485 = 0;
int8 i;
char msg[10];
char dato[10];

#INT_TIMER1
void timer1_isr()
{ 
   
   if(rs485_get_message(msg, FALSE))
   {
      flag_rs485 = 1;
 
      for(i=0; i < msg[1]; ++i)
         {dato[i] = (msg[i+2]);}

   }
}

void clean_msg (void)
{
   for(i=0;i<sizeof(msg);i++)
   {
      msg[i] = 0x00;
      dato[i] = 0x00;
   }
}

void RS485send(char* s, int8 id)
{
   int8 size;

   for(size=0; s[size]!='\0'; ++size);

   rs485_wait_for_bus(FALSE);

   while(!rs485_send_message(id, size, s))
      delay_ms(OUR_RS485_ID);
}

void main()
{  char* d;
   output_low(PIN_A0);
   
   setup_timer_1(T1_INTERNAL | T1_DIV_BY_8);
//   enable_interrupts(GLOBAL);
   rs485_init();
   enable_interrupts(INT_TIMER1);

   while (true)
   {
      if(flag_rs485)
      {
         disable_interrupts(INT_TIMER1);
         flag_rs485 = 0;

         //if(msg[2] == 'L'){
         //   switch(msg[3]){
         //      case '1': output_high(PIN_A0);
         //               break;
         //      case '2': output_high(PIN_A1); 
          //              break;
         //      case '3': output_low(PIN_A0); 
         //                output_low(PIN_A1); 
         //                break;
         //   }*/
            
            switch(dato){
               case "L1ON" :   output_high(PIN_A0);  break;
               case "L2ON" :   output_high(PIN_A1);   break;
               case "L3OFF" :   output_low(PIN_A0); output_low(PIN_A1);   break;
            }
//           if(dato=="L1ON")
//              output_high(PIN_A0);
//           if(dato=="L2ON")
//              output_high(PIN_A1);
//           if(dato=="L3OFF")
//               {output_low(PIN_A0); output_low(PIN_A1);}
           
           // }
         }
      
            delay_ms(300);
            clean_msg();
            enable_interrupts(INT_TIMER1);
            msg[0] = '1';
            RS485send(msg, 0x10);
   }
 }

la ASK se me ocurrio hacerlo asi y no saldria del DO hasta que no halla una respuesta capaz hay algo mas practico
int1 ask()
{
if(flag_rs485)
{
disable_interrupts(INT_TIMER1);
flag_rs485 = 0;

if(msg[2] == '1')
output_high(PIN_B4);

delay_ms(50);
output_low(PIN_B4);
delay_ms(50);

clean_msg();
// rs485_wait_for_bus(FALSE);
enable_interrupts(INT_TIMER1);
delay_ms(100);
return true;
}
}
do
{
msg = "L1ON";
RS485send(msg, 0x12);
delay_ms(150);
}
while(!ask());
 

Adjuntos

  • master-slave 01.zip
    187 KB · Visitas: 47
Última edición:
Recuerda que es un arreglo, no puedes comparar de esa forma.
El arreglo tendrá lo siguiente:
Arreglo msg.jpg
Entonces es lógico que la comparación falle si haces...
case "L1ON" : output_high(PIN_A0); break;

Para eso tendrás que formatear la cadena usando strcpy y después la comparas con strcmp.
 
Si observas msg guarda datos de longitud, dirección y dato, lo que hice es utilizar una variable dato donde almaceno el dato puro sin dirección ni longitud, es strcpy no copia string? Entonces la consulta teniendo la variable dato con el dato puro no alcanza? Strcmp compara string pero se puede usar por ejemplo if(strcmp(dato, "L1ON")==0) voy a probar la verdad no lo use eso pero creo que es algo así

 
aqui subo el Zip con todo el contenido Quiero comunicar como decia varios modulos con un master donde se comunican por RS485, donde si preciono el switch de un modulo que el master sepa que se preciono y se encendio tal salida de ese modulo como tambien el master si quiere apagar una salida de tal modulo lo pueda hacer, me explico? adjunto archivos hay dos carpetas de modulos porque aun estoy indeciso su utilizar un modelo u otro pero hago los dos modelos y despues decidire.
 

Adjuntos

  • smartcenter 002.zip
    339.5 KB · Visitas: 40
HOLA Gente del foro, solucione una parte del problema pero sigo con inconvenientes!, tengo una central que seria el Master y varios modulos Esclavos, por razones de pruebas solo hice uno en proteus, entonces en el modulo Esclavo preciono el primer Boton, enciende una salida del modulo y le avisa a la central y puse un testigo que me avisa que se encendio una luz del modulo el testigo en el Master esta en PIN_A4 , (mas adelante escribira en un display por ahora solo gice eso para hacerlo mas rapido), pero bueno ahora al reves, preciono un Boton del MASTER o CENTRAL que entra por PIN_B7 (lo hago asi para probar, en realidad tendria que ser por bluetooth), y me tiene que encender o apar el pin_C0 del modulo 1.
la realidad no lo hace, es mas se me traba el modulo 1 y ya no me responde nada porque sucede eso? me podrian ayudar?, para mi se queda esperando o en algun loop o algo porque para que no responda. y cuando preciono en el modulo tampoco envia al master en pocas palabras no funciona mas.

Para probarlo adjunto un zip, haganlo correr y precionen el primer boton del MOdulo 1 y observen que se enciende PIN_C0 del modulo y PIN_A4 del master, pero preciono el boton 1 del Master y no enciende o apaga el PIN_C0 del modulo sino que ya tampoco funciona mas el modulo ni envia al master.
 

Adjuntos

  • smartcenter 003.zip
    399.4 KB · Visitas: 46
Hola amigos después de haber realizado una comunicación exitosa en CCS compiler con la configuración #use rs232 estoy profundizando en el caso para estar mas claro, les agradezco sus aportes,
Por ejemplo
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7,BITS=8,ERRORS, PARITY=N, stream=COM1)

Baud = 9600. De estas instrucción solo se que es la cantidad de bit por segundo que puedo trasmitir.
Le agradezco que me corrijan o que aporten mas a este información.

Xmit,rcv es donde colo los pines de trasmisión Tx y Rx

Bits: entiendo que esto se usa para saber cuantos bits se envían en el bytes, y pueden ser configurados con 8,7,6 y 5.
Entiendo que este tipo de transmisión se da en bytes. Por ende puedo deducir que puedo trasmitir hasta 1200 bytes por segundo ya que tengo definido que se trasmitan 9600 bits por segundo.
Le agradezco que me corrijan o que aporten mas a este información.

PARITY= N *Los bits de paridad se utilizan como la forma más simple de*código para la detección de error.*
Tengo entendido que hay dos tipo de paridad y para este caso yo indico que no utilizo este sistema de detección de errores.
Entiendo que el mismo solo se usa para transmisión.
Le agradezco que me corrijan o que aporten mas a este información.
N = No se utiliza paridad
E = Patidad Par
O = Paridad Impar.

ERRORS: De esta instrucción lo que conozco es que se usa para detectar errores de trasmisión y si en alguna interrupción que se este esperando el dato trasmitido existe por alguna razón un error y se cuelga la comunicación, esta función libera le ataco. Pero a subes esta instrucción nos permite usar una variable RS232_ERRORS de los cuales no conozco casi nada, solo se que se usan para apañar el mensaje de error para poder presentarlo en un lcd o algo así.
#bit ninth_bit = RS232_ERRORS.7
#bit collision = RS232_ERRORS.6
Le agradezco que me corrijan o que aporten mas a este información.

Si puede hacer un ejemplo de como se usan las variables RS232_ERRORS y que significa .7 y .6 se los voy a agradecer.
 
En la ayuda del compilador se encuentra todo lo que necesitas saber sobre #USE RS232.
Tan sólo presiona la tecla F1 y aparecerá.
Ahí verás un menú con varias pestañas, selecciona Índice y podrás realizar una búsqueda escrita o deslizante.
También puedes obtener información situando el cursor sobre alguna instrucción y después presionar la tecla F1.
 
Hola, para no abrir otro foro, escribo aca estuve un tiempo probando el RS485, adjunto un archivo zip, deje un tiempo y retome estoy tratando de comunir 3 placas con un pic16f886, cada placa tiene 4 pulsadores y un led que corresponde a cada pulsador, y a su vez un dipswitch, donde si activo el pin 1 del dipswitch trasmite el boton 1 y asi sucecivamente. entonces si todos tienen la misma direccion recibiran esa informacion sino no. Entonces preciono por ejemplo el boton 1 y si tienen el mismo nombre las otras encienden el 1 me explico?. y si otra placa preciono el 1 y si estaban todas encendidas se apagan y si preciono en otra el 1 se encienden, no importa de donde porque todas se comunican. sea boton 1 o 2 o cualquiera. En fin el problema que en el proteus parece que funcionara aunq no me gusta mucho, y lo peor en vida real uno recibe el otro no, y si llego encender las 3 placas cuando preciono para apagar se apagan dos y la otra no es como que costara que las 3 reciban la misma informacion. y eso que pruebo con 3 nose que pasaria si pongo mas placas que esa es mi intencion no solo 3 pero en la vida real no se comunican bien porque es siempre algo se pierde no hacen todas lo mismo. adjunto zip. Gracias
 

Adjuntos

  • sModule v3.zip
    120.7 KB · Visitas: 29
El problema tal vez se deba a que estás usando mal la función atoi(string).
Debes pasarle el valor con strcpy(dest, scr) y usar un arreglo sin datos, o como puntero.

En tu caso es más fácil transferir el dato a atoi como puntero, tan solo agrega un * a tu arreglo.
Por ejemplo:
char *msg[tope_array];

De esa forma, atoi comprenderá el dato y retornará un valor correcto, de otra forma, siempre retornará 0
 
hola D@rkbytes, esa funcion es para otro metodo lee mas abajo del programa, esa que leiste es si recibo por bluetooth, el problema que tengo es cuando preciono el boton enciende el led de la placa esa y la que envia a otras y lo hace con otro if no con el atoi. con
asi envia
Código:
if(!input(KEY1)){disable_interrupts(INT_TIMER1); output_toggle(SAL1); envia_luz(1,input_state(SAL1),input(PC0)); while(!input(KEY1)); enable_interrupts(INT_TIMER1);}
envio a las otras placas y se recibe con un int_timer1

y los if son asi para selectar cual led

Código:
         ///// DATOS RECIVIDOS POR TECLA DE OTRO DISPOSITIVO
         IF((msg[0]==RS_ID)&&(msg[2]=='L'))
         { 
            switch (msg[3]) {
               case 1: output_bit(sal1,msg[4]); break;
               case 2: output_bit(sal2,msg[4]); break;
               case 3: output_bit(sal3,msg[4]); break;
               case 4: output_bit(sal4,msg[4]); break;
            }
         }

no hay atoi, por eso pregunto por favor que sucede que no reciben bien porfa, y me desconcierta
proteus funciona por eso subi el archivo y vida real recibe no todos capaz dos a veces los 3 o apan dos placas y la tercera no y no veo el error en el programa.
 
Última edición:
Veo algunas cosas extrañas en tu programa que pueden ocasionar problemas.
Estar limpiando constantemente el array msg, hace que todo el tiempo se permanezca dentro del bucle de esa rutina.
Eso hace perder tiempo inútilmente.
Sería mejor limpiar el array después de cualquier uso.

Leer los datos usando un timer no lo veo buena opción y mucho menos como lo estás haciendo.
No estás recargando el timer 1 para un desborde establecido, sino que esperas su desborde por defecto.
Eso hará que se pierdan datos, porque no podrán ser leídos constantemente.

Te recomiendo que realices una depuración ICD para que mires los valores del array msg.
Ya que de esa forma podrás comprobar si en verdad estás obteniendo los valores que se esperan.
En tu simulación pude comprobar que tampoco estás realizando depuración y hacerlo es algo muy útil.
 
Por las dudas Aclaro que no soy un esperto por las dudas, tengo un problemita no puedo hacer ICD y nunca hice eso si se puede hacer todo simulado para ver capaz si pero en vida real estoy usando cosas basicas, hasta mi programador, aqui adjunto otra modificacion del programa, pero lo que me da bronca que en proteus funciona. Me guio bastante con eso. son 3 placas conectados por un par telefonico con esos modulitos RS485 con los pic esos que ves en Proteus. Pero prende apaga bien por momentos falla uno placa luego vuelve a recibir y reacciona. Yo utilizo el Timer1 porque es como aprendi para recibir :(
Estoy probando igual sacando como dijiste los clean_msg().
Utilice el SET_TIMER , pero no veo que los datos lleguen de manera confiable, como veras los envio varias veces para ver si se recibe. Pero Aun es Nulo los resultados igual. Voy a tratar de descansar y mañana seguire yo me guio con un ejemplo que me enviaste en este foro que conectaste dos pic y dos botones uno que enciende y o tro apaga a base de eso realice pero es increible que no me funcione con 3.
Mi Grabador es un TMprog de paso para saber que utilizo y creo que no se puede hacer debugger con ese.
O el problema es la cantidad de datos?
 

Adjuntos

  • sModule v3 rev2.zip
    92.8 KB · Visitas: 21
Última edición:
Sigo sin Lograrlo lo que hice ahora es tratado de Comprimir los datos osea enviar menos datos osea el receptor recibe menos msg, antes venia uno para uno con la direccion el otro la cantidad de datos otro que decia si es una luz, otro que decia cual y otro el estado encendido 1 o apagado 0. lo que hice ahora es unir estos dos ultimos a uno donde los primeros 4 bits dice cual es y los ultimos 4 el estado. pero sigue sin funcionar pense que enviando menos datos iban a recibir mejor pero siguen a veces sin recibir si o no , asique no va por ese lado y nose como hacerlo para que el dato llegue confiable, eh enviado mismos datos un par de veces por si no recibia en la primera pero veo que no funciona tampoco. no tienen un ejemplo de algo parecido a lo que quiero hacer de unir varias placas asi veo como funciona esa comunicacion. gracias :cry:
nose si esta peor que antes o mejor :cry:

hay una linea en la funcion envia_luz que dice as RS485send(dato,10); eso lo puse porque hay otra placa que aun no la arme que recibe informacion de todas las placas de lo que estan haciendo, pero esa linea puede hacer que no se comuniquen entre ellas? pregunto porque es como enviar dato a una placa y la linea de abajo de esa envia a otra no creo que moleste eso o si? pero por favor si tienen algo que hayan echo capaz pueda ayudarme a ver porque nose me doy cuenta. Y es algo sencillo como pecionar un boton y encender el led :(
 

Adjuntos

  • sModule v3 menos datos.zip
    118.5 KB · Visitas: 24
Última edición:
Hola, aqui hay otra version del programa el circuito en proteus lo pueden utilizar de los otros zip que subi arriba y se le carga el programa este, lo que noto que en la Computadora y proteus funciona, Perooo, en la vida real entre dos placas funciona bien cuando coloco una tercera comienza el problema asiq nose si es problema de comunicacion?, si entre dos funciona perfecto y una tercera hace que funcione a veces si o no, capaz es problema del cable puede ser? hay algun secreto de como instalar los cables? Estoy utilizando los modilos RS485 de arduino esos chiquitos saben cuales digo? capaz hay que hacer alo que nose. Por eso hay alguna manera de conectarlos o algo que tenga que tener en cuenta? por ese mal funcionamiento. Gracias Y porfa ayudenme porque me escribi todo solo estos 3 me olvide aclarar nose si sirva los modulitos rs485 los alimento con 5v y los cables son par telefonicos :cry:
 

Adjuntos

  • module v1r2.zip
    53.2 KB · Visitas: 28
Última edición:
Lamentablemente no programo en C pero he visto que usas velocidad de 9600, intenta bajar a 1200 que para la aplicación esa es mas que suficiente.
No se como estas usando el RX y TX, yo uso la UART incluida dentro del microcontrolador y al inicio de la emisión envió un carácter de control que hace que todos los que están "escuchando", sepan que habrá una emisión a continuación.
También cada integrante de la red tiene una identificación que debe ser emitida/recibida para individualizar los mensajes específicos.
Ejemplo: A1, A2, A3,...A35.
Realice un control para 35 estaciones RS485 con el IC 75176 y lo probé en físico con 5 en simultaneo con cable UTP y funciona bien y envió mas información para ser mostrada en display en cada estación y comandar un tablero remoto con display grandes.
El lenguaje que use fue el Basic de Proton, lamentablemente como es un desarrollo comercial, no puedo compartir el software.
 
Última edición:
Hola ricbevi,yo utilizo esos modulitos que se venden RS485 que son esos finitos que tienen para conectar do cables, sabes cuales digo no? y te comento yo no utilizo la UART del pic sino otros pines, y la recepcion cuando llega un mensaje hace una interrupcion por RB0 y comienza a leer, y utilizo par telefonico en la comunicacion y me pasa eso entre dos plaquetas todo perfecto pongo una tercera y a veces anda otras no, y en PROTEUS funciona perfecto, por eso consulto si es problema de cable, o son esas plaquetas cosas que no creo en internet hay infinidades de ejemplos con esas cosas y funcionan, o nose la verdad. :confused::confused::cry:
 
Proteus es solo un simulador y da por echo cosas que en el "mundo real" no son así.
Un ejemplo de ello son los ruidos/interferencias que en el entorno virtual Proteus no los tiene en cuenta .
El cable para una red 485 ideal, no es un par telefónico y deberías como mínimo usar un UTP o STP, se a los módulos que te refieres, yo ese esquema los realice en la misma placa de circuito impreso de cada terminal.
Es importante usar los módulos internos que traen los micro-controladores a no ser que puedas mejorarlos externamente, no me parece el caso de la comunicación serie que te ocupa y esta resuelta de maravilla en casi todos los micro-controladores de los últimos tiempos.
Si seguís haciendo lo mismo y no atacas el problema donde radica, terminaras cansándote del proyecto.
Revisa las recomendaciones de los que te hemos tratado de ayudar y seguramente llegaras a buen puerto.
Saludos.

Ric.
 
hola ricbevi, a ve si entendi vos decis que ataque por el lado de los cables entonces? a ver si mejora es asi? Te comento por las dudas que utilizo un cable par telefonico blindado de unos 60 o 70 cm no mas estoy probando todo en una mesa por eso nose si influye el ruido en esa distancias?
Yo tengo esos modulos uno en cada extremo y tengo otro modulo ponele a mitad de camino de esa linea osea a unos 40 cm tengo un modulo en el medio, entonces uno en cada extremo y otro a mitad de camino, la pregunta es, Es necesario esa resistencia de 120 ohm utilizando esos modulos? y otro capaz tambien ayude el modulo que veo que tiene inconveniente es el que esta a mitad de camino no el de los extremos. Cuando logo que responde mas o menos , veo que los que estan a los extremos se comunican bastante bien, pero el que esta a la mitad no, si no se queda trabado en cendido no enciende, o pierdo el control un poco a veces el del medio suponiendo que quiero apagar el led del que me quedo encendido de la plaqueta que controla el modulo del medio como que me cuesta, el que tiene incoenvenientes es el del medio el que mas la sufre, pero porque? nose :cry:
 
Última edición:
Atrás
Arriba