Autor Tema: Comunicación RS485 entre 2 PICs  (Leído 5096 veces)

0 Usuarios y 2 Visitantes están viendo este tema.

Desconectado pocher

  • Moderador Local
  • DsPIC30
  • *****
  • Mensajes: 2568
Comunicación RS485 entre 2 PICs
« en: 11 de Noviembre de 2007, 06:35:50 »
Sigo repasando cosas que con el tiempo se me olvidaron. Llevo día y medio con esto y no me sale, a ver si me podeis hechar una mano.

Simplemente se trata de provar la comunicación vía RS485 con 2 PICs. El PIC MASTER envia 1 byte y el PIC SLAVE lo recoge y lo saca por el portb.

Os pongo los dos programas, el del MASTER y el del SLAVE:

El del MASTER:

Código: [Seleccionar]
#include <16f876.h>

#fuses XT, NOPROTECT, NOWRT, PUT, NOWDT, NOLVP, NOCPD, BROWNOUT

#use delay(clock=4000000)

#use rs232(baud=1200, xmit=pin_c6, rcv=pin_c7)

#use fast_io(B)

void main(void)
{
   char a[9];
   char b[9];
   int n;
   
   a[0]='1';
   a[1]='1';
   a[2]='1';
   a[3]='1';
   a[4]='0';
   a[5]='0';
   a[6]='0';
   a[7]='0';
   
   b[0]='0';
   b[1]='0';
   b[2]='0';
   b[3]='0';
   b[4]='1';
   b[5]='1';
   b[6]='1';
   b[7]='1';
   
   output_high(pin_c5);       //Habilitamos la transmisión de datos
   
     while(1)
     {   
        if (input(pin_b0))
        {
           for(n=0;n<8;n++)
              putc(a[n]);
        }           
              else
              {
           for(n=0;n<8;n++)
              putc(b[n]);
        }                         
              delay_ms(1000);                           
     } 
}

El del SLAVE:

Código: [Seleccionar]
#include <16f876.h>

#fuses XT, NOPROTECT, NOWRT, PUT, NOWDT, NOLVP, NOCPD, BROWNOUT

#use delay(clock=4000000)

#use rs232(baud=1200, xmit=pin_c6, rcv=pin_c7)

#use fast_io(B)

char a[9];
int j=0;

#int_rda
void recepcion_serie()          // Rutina de interrupción por recepción serie
{
   if(kbhit())
   {
      a[j] = getc();
      j++;
   }     
}     

void main(void)
{
   int i;
   
   set_tris_b(0x00);             //Puerto B-> salidas
   
   enable_interrupts(INT_RDA);
     enable_interrupts(GLOBAL);

   output_low(pin_c5);          //Habilitamos la recepción de datos
   
   output_b(0x00);
   
   //for(i=0;i<8;i++)            //Sin inicializar a 0 también va FÍSICAMENTE
        //a[i]=0;   
   
     while(1)
     {     
        //if(a[0]=='1' && j==8)       //Así no funciona ¿porqué?
        if(j==8)                //Con el IF es mejor que con el WHILE ya que el programa puede hacer otras cosas
        //while( j < 8 );         //Con el WHILE tiene el inconveniente que hay que esperar la llegada de los bytes             
          {
             disable_interrupts(INT_RDA);
         j=0;

             output_bit(PIN_B0,bit_test(a[0],0));       // Se pregunta si ¿el primer bit del byte a[0], es 1 ó 0?     
             output_bit(PIN_B1,bit_test(a[1],0));         
             output_bit(PIN_B2,bit_test(a[2],0));   
             output_bit(PIN_B3,bit_test(a[3],0));           
             output_bit(PIN_B4,bit_test(a[4],0));           
             output_bit(PIN_B5,bit_test(a[5],0));
             output_bit(PIN_B6,bit_test(a[6],0));           
             output_bit(PIN_B7,bit_test(a[7],0));                         
         
             //for(i=0;i<8;i++)         //Sin inicializar a 0 también va FÍSICAMENTE
              //a[i]=0;
           enable_interrupts(INT_RDA);         
          }             
       }         
  }


El caso es que si en el SLAVE pongo if(j==8) sí que lograr sacar el byte por el portb, pero si pongo if(a[0]=='1' && j==8) ya no saca nada, y a mí me interesa esta segunda opción para poder aplicarla a otro programa con más PICs.

Teóricamente debería de sacar 00001111 por el portb del SLAVE cuando RB0=1 en el PIC emisor, pero no ... quiere, si metemos el a[0]=='1' ya no va.

Un saludo

PD. Os dejo los ficheros .dsn, .c y .hex para que lo comproveis. Físicamente responde igual que con PROTEUS

¡No deja adjuntar ningun archivo por pequeño que sea, lo siento!

Os los dejo aquí: DESCARGAR
« Última modificación: 11 de Noviembre de 2007, 08:13:52 por pocher »

Desconectado RedPic

  • Administrador
  • DsPIC33
  • *******
  • Mensajes: 5544
    • Picmania by Redraven
Re: Comunicación RS485 entre 2 PICs
« Respuesta #1 en: 11 de Noviembre de 2007, 06:46:20 »
Amigo Pocher, dale un vistazo a este trabajo que hice por si te sirve de algo: El RS485, un Relé en la lejanía: Hardware y Software

Contra la estupidez los propios dioses luchan en vano. Schiller
Mi Güeb : Picmania

Desconectado pocher

  • Moderador Local
  • DsPIC30
  • *****
  • Mensajes: 2568
Re: Comunicación RS485 entre 2 PICs
« Respuesta #2 en: 11 de Noviembre de 2007, 06:52:30 »
Seguro que sí, amigo Diego voy a llevar a los niños a la feria y esta tarde me lo miro.

Un saludo

Desconectado Azicuetano

  • Moderadores
  • PIC24H
  • *****
  • Mensajes: 1020
    • Aplicaciones Electrónicas en Alicante.
Re: Comunicación RS485 entre 2 PICs
« Respuesta #3 en: 11 de Noviembre de 2007, 10:34:05 »
Hola pocher.

Es posible que que algún duendecillo haya modificado en el slave esto?

output_low(pin_c5);

Para habilitar la comunicación en el emisor lo pones en high, no tendría que ser igual?


Un saludo desde Alicante.

Desconectado MGLSOFT

  • Moderadores
  • DsPIC33
  • *****
  • Mensajes: 7912
Re: Comunicación RS485 entre 2 PICs
« Respuesta #4 en: 11 de Noviembre de 2007, 12:18:46 »
Deberia ser igual una habilitacion que otra, NO?? :lol:
Todos los dias aprendo algo nuevo, el ultimo día de mi vida aprenderé a morir....
Mi Abuelo.

Desconectado pocher

  • Moderador Local
  • DsPIC30
  • *****
  • Mensajes: 2568
Re: Comunicación RS485 entre 2 PICs
« Respuesta #5 en: 11 de Noviembre de 2007, 16:01:05 »
Para habilitar la transmisión del 485 Master, el Enable de transmisión debe de estar en alto (habilitado) y el de recepción  también, y así este último estará bloqueado (va por ceros).

Para habilitar la recepción del 485 Slave, el Enable de recepción debe de estar en bajo (habilitado) y el de transmisión  también para que esté bloqueado (va por unos).

Se pueden habilitar dos pines del PIC para el control de los Enables o bien como hay en el programa cortocircuitar ambos Enables y así solo usar un pin del PIC.

PD. Llego ahora de la calle, voy a mirarme lo de Diego.
« Última modificación: 11 de Noviembre de 2007, 16:03:31 por pocher »

Desconectado RedPic

  • Administrador
  • DsPIC33
  • *******
  • Mensajes: 5544
    • Picmania by Redraven
Re: Comunicación RS485 entre 2 PICs
« Respuesta #6 en: 11 de Noviembre de 2007, 16:11:04 »
Yo tengo los dos enables conectados de forma con con uno solo pin controlo ambos, así en HIHG habilito la transmisión y en LOW la recepción.  :mrgreen:
Contra la estupidez los propios dioses luchan en vano. Schiller
Mi Güeb : Picmania

Desconectado Duende_Azul

  • Colaborador
  • PIC24F
  • *****
  • Mensajes: 902
Re: Comunicación RS485 entre 2 PICs
« Respuesta #7 en: 11 de Noviembre de 2007, 16:33:41 »

...  Es posible que que algún duendecillo haya modificado en el slave esto? ....


ya vas..  :x

Desconectado pocher

  • Moderador Local
  • DsPIC30
  • *****
  • Mensajes: 2568
Re: Comunicación RS485 entre 2 PICs
« Respuesta #8 en: 11 de Noviembre de 2007, 17:18:38 »
Diego he intentado copiar y pegar el código GeSHi (ccp) y me aparecen todos los números de línea del GeSHi y caracteres raros ... un desastre. Podrías ponerlo en otra forma que no dé problemas al copiar?

Desconectado RedPic

  • Administrador
  • DsPIC33
  • *******
  • Mensajes: 5544
    • Picmania by Redraven
Re: Comunicación RS485 entre 2 PICs
« Respuesta #9 en: 11 de Noviembre de 2007, 19:43:48 »
Aqui te lo pego en texto plano.  :mrgreen:

/** \file firmware_iRELE485-628.c
 * \brief Este fichero contiene el cuerpo principal del Firmware del\n
 * dispositivo auxiliar satélite de la iACD V1.0.4. denominado iRELE485-628
 *
 * Integra todos los subsistemas y funciones implementados.\n
 * Source para el compilador CCS C v.3.242
 *
 * Microprocesador : 16F628A (18 pines PDIP) \n\n
 * Fuses utilizados: \n
 * \li INTRC Internal RC Osc
 * \li MCLR Master Clear pin enabled
 * \li NOWDT No Watch Dog Timer
 * \li NOPROTECT Code not protected from reading
 * \li NOPUT No Power Up Timer
 * \li NOBROWNOUT No brownout reset
 * \li NOLVP No low voltage prgming, B3(PIC16)
 * \li NOCPD No EE protection
 *
 * \author Diego Márquez García-Cuervo \n
 * <http://picmania.garcia-cuervo.net>
 *
 * \version 1.0.0.A
 */

///////////////////////////////////////////////////////////////////////////////////////////////////
//
// Definiciones estándar del 16F628A
//
///////////////////////////////////////////////////////////////////////////////////////////////////

#include <16F628A.h>

///////////////////////////////////////////////////////////////////////////////////////////////////
//
// Fuses y ajuste de Clock
//
///////////////////////////////////////////////////////////////////////////////////////////////////

#fuses INTRC,MCLR,NOWDT,NOPROTECT,NOPUT,NOBROWNOUT,NOLVP,NOCPD
#use delay(clock=4000000)

///////////////////////////////////////////////////////////////////////////////////////////////////
//
// Defines y Constantes
//
///////////////////////////////////////////////////////////////////////////////////////////////////

/*! \def DRIVER_RELE
 *   Pin accionador del Relé número 1 \li HIGH : Relé ON.
 */
#define DRIVER_RELE PIN_B4

/*! \def TX_485_ENABLE
 *  Pin que habilita la transmisión por el canal RS485
 * \li LOW Habilita recepción RS485
 * \li HIGH Habilita transmisión RS485.
 */
#define TX_485_ENABLE PIN_B5

/*! \def bytes_for_USART_buffer
 *  \brief Establece el número de bytes de longitud del buffer de la USART.
 */
#define bytes_for_USART_buffer 12

/*! \var const char VERSION
 *  \brief Versión del Firmware.
 */
const char VERSION[]="1.0.0\0";

/*! \var const char WhatAmI
 *  \brief Identificador de tipo de dispositivo: 'R' Relé.
 */
const char WhatAmI = 'R';

/*! \var const char WhoAmI
 *  \brief Identificador de dispositivo.
 */
const char WhoAmI = '1';

/*! \var const char Command_Execute
 *  \brief Comando que indica ejecución de acción : Activar Relé
 */
const char Command_Execute = 'X';

/*! \var const char end_of_transmit
 *  \brief Carácter que indica fin de transmisión (no buffereable)
 */
const char end_of_transmit = '!';

///////////////////////////////////////////////////////////////////////////////////////////////////
//
// Canal de Comunicación
//
///////////////////////////////////////////////////////////////////////////////////////////////////

#use rs232(baud=9600,xmit=PIN_B2,rcv=PIN_B1)

///////////////////////////////////////////////////////////////////////////////////////////////////
//
// Prototipos de Funciones
//
///////////////////////////////////////////////////////////////////////////////////////////////////

void USART_activa_tx(void);
void USART_activa_rx(void);
void USART_add_to_buffer(char c);

///////////////////////////////////////////////////////////////////////////////////////////////////
//
// R A M : Variables Globales Estáticas
//
///////////////////////////////////////////////////////////////////////////////////////////////////

/*! \var USART_buffer
 *  \brief Buffer de la USART
 */
static char USART_buffer[bytes_for_USART_buffer];

/*! \var USART_nextRec
 *  \brief Indice del Buffer de la USART
 */
static int8 USART_nextRec;

/** \var Command
  * \brief Comando válido para ejecutar.
  */
int8 Command;

///////////////////////////////////////////////////////////////////////////////////////////////////
//
// Funciones
//
///////////////////////////////////////////////////////////////////////////////////////////////////

/** \brief Abre el canal RS485 para transmitir.
  * \return void
  */
void USART_activa_tx(void){
  output_high(TX_485_ENABLE);
  delay_ms(5);
}

/** \brief Abre el canal RS485 para recibir.
  * \return void
  */
void USART_activa_rx(void){
  delay_ms(5);
  output_low(TX_485_ENABLE);
  delay_ms(1);
}

/** \brief Inicializa el Buffer de la USART
  *
  * Recoge el último carácter recibido desde la USART sobre USART_buffer
  * e incrementa en 1 el índice USART_nextRec.\n\n
  * Si el carácter recibido es Retorno de carro '\\r' ó 0x0D comprueba identidad de dispositivo y comando recibido
  *
  * \return void
  */
void USART_add_to_buffer(char c){

   USART_buffer[USART_nextRec++]=c;
   if(USART_nextRec==bytes_for_USART_buffer){
      USART_nextRec=0;
   }

   if(c==end_of_transmit){
      --USART_nextRec;
      if(USART_buffer[USART_nextRec-3]==WhatAmI){
         if(USART_buffer[USART_nextRec-2]==WhoAmI){
           if(USART_buffer[USART_nextRec-1]==Command_Execute){
              Command=0x01;
           }
         }
      }
      USART_nextRec = 0;
   }
}

///////////////////////////////////////////////////////////////////////////////////////////////////
//
// Rutinas de Servicio de Interrupciones
//
///////////////////////////////////////////////////////////////////////////////////////////////////

#int_rda
/** \brief Interrupción por : Recepción del Canal Serie.
  *
  */
void interrupt_service_rutine_rda(void) {

   char USART_nextChar;

   USART_nextChar='\0';
   if(kbhit()){
      USART_nextChar=getc();
      USART_add_to_buffer(USART_nextChar);
   }
}

///////////////////////////////////////////////////////////////////////////////////////////////////
//
// M A I N
//
///////////////////////////////////////////////////////////////////////////////////////////////////

/** \brief Constituye el núcleo principal del sistema
  *
  * \return void.
  */
void main(void) {

   setup_oscillator(OSC_4MHZ);
   setup_timer_0(RTCC_INTERNAL|RTCC_DIV_1);
   setup_timer_1(T1_INTERNAL|T1_DIV_BY_4);
   setup_timer_2(T2_DISABLED,0,1);
   setup_comparator(NC_NC_NC_NC);
   setup_vref(FALSE);
   port_b_pullups(False);
   set_tris_b(0b00000010);
   output_low(DRIVER_RELE);
   delay_ms(100);

   USART_nextRec = 0;
   Command = 0x00;

   USART_activa_rx();
   delay_ms(333);

   enable_interrupts(global);
   enable_interrupts(int_rda);

   USART_activa_tx();
   printf("[iRELE485-628] v.%s\r\n",version);
   USART_activa_rx();

   do{

      if(Command==0x01){
         Command =0x00;

         USART_activa_tx();
         printf("R%cA%c\r\n",WhoAmI,end_of_transmit);
         USART_activa_rx();

         output_high(DRIVER_RELE);
         delay_ms(2000);
         output_low(DRIVER_RELE);
       }

   } while(true);
}

///////////////////////////////////////////////////////////////////////////////////////////////////
//
// End of firmware
//
///////////////////////////////////////////////////////////////////////////////////////////////////
Contra la estupidez los propios dioses luchan en vano. Schiller
Mi Güeb : Picmania

Desconectado Nocturno

  • Administrador
  • DsPIC33
  • *******
  • Mensajes: 18286
    • MicroPIC
Re: Comunicación RS485 entre 2 PICs
« Respuesta #10 en: 12 de Noviembre de 2007, 06:19:49 »
Diego he intentado copiar y pegar el código GeSHi (ccp) y me aparecen todos los números de línea del GeSHi y caracteres raros ... un desastre. Podrías ponerlo en otra forma que no dé problemas al copiar?
Siendo Moderador del subforo tú mismo podías hacerlo :D
Basta con darle a "Modificar" para obtener lo que había escrito Diego.

Desconectado MGLSOFT

  • Moderadores
  • DsPIC33
  • *****
  • Mensajes: 7912
Re: Comunicación RS485 entre 2 PICs
« Respuesta #11 en: 12 de Noviembre de 2007, 08:21:12 »
Debe pasarle a Pocher lo que a mi me pasa...
Me cuesta tomar el POST de alguien y corregirlo, por una cuestión de respeto, entonces le escribimos para que el dueño del post tome acción... :mrgreen: :mrgreen:
Todos los dias aprendo algo nuevo, el ultimo día de mi vida aprenderé a morir....
Mi Abuelo.

Desconectado Nocturno

  • Administrador
  • DsPIC33
  • *******
  • Mensajes: 18286
    • MicroPIC
Re: Comunicación RS485 entre 2 PICs
« Respuesta #12 en: 12 de Noviembre de 2007, 08:48:38 »
Claro, a mí también me pasa. Pero si le das a "Modificar", puedes copiar el contenido del post sin darle a "Guardar" y no cambiarás nada.

Bah, sólo lo decía porque alguna vez me ha pasado lo del Geshi y lo he resuelto de esa forma.

Desconectado pocher

  • Moderador Local
  • DsPIC30
  • *****
  • Mensajes: 2568
Re: Comunicación RS485 entre 2 PICs
« Respuesta #13 en: 12 de Noviembre de 2007, 15:12:17 »
Gracias Manolo, gracias Marcos, los dos demostrais tener muy buena voluntad.

Y como no gracias al caballero Don Diego que ha hecho que mis 3 PICs se comuniquen.

Diego te hago unas preguntas, a ver que te parece:

1ª ¿Para que sirve?:

  if(USART_nextRec==bytes_for_USART_buffer){
     USART_nextRec=0;}

Quizá sirva por si se desborda el Buffer, o por si no lee el byte de fin de transmisión (!) que se inicialize el índice.

2ª ¿Los delay_ms tienen que ser del orden de esos valores, para que no hayan problemas? He hecho una prueba cargandomelos y se comunican físicamente bien(y con PROTEUS también).

Seguiré investigando el porqué no funciona el programa que puse inicialmente, le debe de faltar alguna tontería.

En estos próximos días haré una prueba en la que los 3 PICs actuen tanto como Maestros como Esclavos todos a la vez, a ver si se les hace un nudo en la lengua a los condenaos, que me han traido frito.

De nuevo gracias Diego.

Desconectado RedPic

  • Administrador
  • DsPIC33
  • *******
  • Mensajes: 5544
    • Picmania by Redraven
Re: Comunicación RS485 entre 2 PICs
« Respuesta #14 en: 12 de Noviembre de 2007, 15:39:37 »
Diego te hago unas preguntas, a ver que te parece:

1ª ¿Para que sirve?:

  if(USART_nextRec==bytes_for_USART_buffer){
     USART_nextRec=0;}

Quizá sirva por si se desborda el Buffer, o por si no lee el byte de fin de transmisión (!) que se inicialize el índice.

Exacto

2ª ¿Los delay_ms tienen que ser del orden de esos valores, para que no hayan problemas? He hecho una prueba cargandomelos y se comunican físicamente bien(y con PROTEUS también).

Estos delays son para usar el conversor RS232-RS485 para conectarme al PC, es semiautomático y detecta cuando tiene que conmutar  de recepción a transmisión o viceversa y requiere un tiempo para hacerlo. Si tus dispositivos están siempre en el modo correcto puedes eliminarlos y en paz
Contra la estupidez los propios dioses luchan en vano. Schiller
Mi Güeb : Picmania