Autor Tema: COMO HACER UN EJEMPLO SIMPLE EN PROTEUS CON LIBRERÍA RS485.C ?????? HELP!  (Leído 5941 veces)

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

Desconectado BINARIO

  • PIC16
  • ***
  • Mensajes: 156
Estimados colegas!


Quiero implementar un pequeño ejemplo de como hacer una comunicación sencilla RS485 (pero SENCILLA), mediante la libreria RS485.c de CCS, tengo algo armado con RS232 y me esta haciendo falta dar vuelta esto asi que dejo abierta la convocatoria al que se quiera sumar a aportar, dejo aqui la libreria asi todos la conocen, esta en CCS.

Voy a empezar haciendo un ejemplito simple para ver si me sale, ocupando un 18F46K22



Código: [Seleccionar]
/////////////////////////////////////////////////////////////////////////
////                            RS485.c                              ////
////                                                                 ////
////      This file contains drivers for RS-485 communication        ////
/////////////////////////////////////////////////////////////////////////
////                                                                 ////
//// int1 rs485_get_message(int* data_ptr, int wait)                 ////
////     * Get a message from the RS485 bus                          ////
////     * Address can be 1 - 33.                                    ////
////     * A 1 will be returned if a parity check error occurred.    ////
////                                                                 ////
//// int1 rs485_send_message(int to, int len, int* data)             ////
////     * Send a message over the RS485 bus                         ////
////     * Inputs:                                                   ////
////          to    - Destination address                            ////
////          len   - Message length                                 ////
////          *data - Pointer to message                             ////
////     * Returns TRUE if successful, FALSE if failed               ////
////                                                                 ////
//// void rs485_wait_for_bus(int1 clrwdt)                            ////
////     * Wait for the RS485 bus to open. Normally used before      ////
////       sending a message to avoid collisions.                    ////
////     * Pass in TRUE to restart the watch dog timer to prevent    ////
////       the device from resetting.                                ////
////     * This is not needed if sending an immediate response       ////
////                                                                 ////
/////////////////////////////////////////////////////////////////////////
////        (C) Copyright 1996, 2004 Custom Computer Services        ////
//// This source code may only be used by licensed users of the CCS  ////
//// C compiler.  This source code may only be distributed to other  ////
//// licensed users of the CCS C compiler.  No other use,            ////
//// reproduction or distribution is permitted without written       ////
//// permission.  Derivative programs created using this software    ////
//// in object code form are not restricted in any way.              ////
/////////////////////////////////////////////////////////////////////////

#ifndef RS485_DRIVER
#define RS485_DRIVER

#ifndef RS485_ID
#define RS485_ID  0x10                 // The device's RS485 address or ID
#endif

#ifndef RS485_USE_EXT_INT
#define RS485_USE_EXT_INT FALSE        // Select between external interrupt
#endif                                 // or asynchronous serial interrupt


#if(RS485_USE_EXT_INT == FALSE)
   #ifndef RS485_RX_PIN
   #define RS485_RX_PIN       PIN_C7   // Data receive pin
   #endif

   #ifndef RS485_TX_PIN
   #define RS485_TX_PIN       PIN_C6   // Data transmit pin
   #endif

   #ifndef RS485_ENABLE_PIN
   #define RS485_ENABLE_PIN   PIN_B4   // Controls DE pin.  RX low, TX high.
   #endif

   #ifndef RS485_RX_ENABLE
   #define RS485_RX_ENABLE    PIN_B5   // Controls RE pin.  Should keep low.
   #endif

   #use rs232(baud=9600, xmit=RS485_TX_PIN, rcv=RS485_RX_PIN, enable=RS485_ENABLE_PIN, bits=9, long_data, errors, stream=RS485)
   #use rs232(baud=9600, xmit=RS485_TX_PIN, rcv=RS485_RX_PIN, enable=RS485_ENABLE_PIN, bits=9, long_data, force_sw, multi_master, errors, stream=RS485_CD)

   #if getenv("AUART")
      #define RCV_OFF() {setup_uart(FALSE);}
   #else
      #define RCV_OFF() {setup_uart(FALSE);}
   #endif
#else
   #ifndef RS485_RX_PIN
   #define RS485_RX_PIN       PIN_B0   // Data receive pin
   #endif

   #ifndef RS485_TX_PIN
   #define RS485_TX_PIN       PIN_B3   // Data transmit pin
   #endif

   #ifndef RS485_ENABLE_PIN
   #define RS485_ENABLE_PIN   PIN_B4   // Controls DE pin.  RX low, TX high.
   #endif

   #ifndef RS485_RX_ENABLE
   #define RS485_RX_ENABLE    PIN_B5   // Controls RE pin.  Should keep low.
   #endif

   #use rs232(baud=9600, xmit=RS485_TX_PIN, rcv=RS485_RX_PIN, enable=RS485_ENABLE_PIN, bits=9, long_data, errors, stream=RS485)
   #use rs232(baud=9600, xmit=RS485_TX_PIN, rcv=RS485_RX_PIN, enable=RS485_ENABLE_PIN, bits=9, long_data, multi_master, errors, stream=RS485_CD)

   #define RCV_OFF() {disable_interrupts(INT_EXT);}
#endif



#define RS485_wait_time 20             // Wait time in milliseconds

#bit    rs485_collision = rs232_errors.6

#ifndef RS485_RX_BUFFER_SIZE
#define RS485_RX_BUFFER_SIZE  40
#endif

int rs485_state, rs485_ni, rs485_no;
int rs485_buffer[RS485_RX_BUFFER_SIZE];


// Purpose:    Enable data reception
// Inputs:     None
// Outputs:    None
void RCV_ON(void) {
   #if (RS485_USE_EXT_INT==FALSE)
      while(kbhit(RS485)) {getc();} // Clear RX buffer. Clear RDA interrupt flag. Clear overrun error flag.
      #if getenv("AUART")
         setup_uart(UART_ADDRESS);
         setup_uart(TRUE);
      #else
         setup_uart(TRUE);
      #endif
   #else
      clear_interrupt(INT_EXT);
      enable_interrupts(INT_EXT);
   #endif
}


// Purpose:    Initialize RS485 communication. Call this before
//             using any other RS485 functions.
// Inputs:     None
// Outputs:    None
void rs485_init() {
   RCV_ON();
   rs485_state=0;
   rs485_ni=0;
   rs485_no=0;
   #if RS485_USE_EXT_INT==FALSE
   enable_interrupts(INT_RDA);
   #else
   ext_int_edge(H_TO_L);
   enable_interrupts(INT_EXT);
   #endif
   enable_interrupts(GLOBAL);
   output_low(RS485_RX_ENABLE);
}


// The index for the temporary receive buffer
int8 temp_ni;

// Purpose:    Add a byte of data to the temporary receive buffer
// Inputs:     The byte of data
// Outputs:    None
void rs485_add_to_temp(int8 b) {
   // Store the byte
   rs485_buffer[temp_ni] = b;

   // Make the index cyclic
   if(++temp_ni >= RS485_RX_BUFFER_SIZE)
   {
      temp_ni = 0;
   }
}


// Purpose:    Interrupt service routine for handling incoming RS485 data
#if (RS485_USE_EXT_INT==FALSE)
#int_rda
#else
#int_ext
#endif
void incomming_rs485() {
   int16 b;
   static int8  cs,state=0,len;
   static int16 to,source;

   b=fgetc(RS485);
   cs^=(int8)b;

   switch(state) {
      case 0:  // Get from address
         temp_ni=rs485_ni;
         source=b;
         cs=b;
         rs485_add_to_temp(source);
         break;

      case 1:  // Get to address
         to=b;
         #if (getenv("AUART")&&(RS485_USE_EXT_INT==FALSE))
            setup_uart(UART_DATA);
         #endif
         break;

      case 2:  // Get len
         len=b;
         rs485_add_to_temp(len);
         break;

      case 255:   // Get checksum
         if ((!cs)&&(bit_test(to,8))&&(bit_test(source,8))&&((int8)to==RS485_ID)) {  // If cs==0, then checksum is good
            rs485_ni=temp_ni;
         }

         #if (getenv("AUART")&&(RS485_USE_EXT_INT==FALSE))
            setup_uart(UART_ADDRESS);
         #endif

         state=0;
         return;

      default: // Get data
         rs485_add_to_temp(b);
         --len;
         break;
   }
   if ((state>=3) && (!len)) {
      state=255;
   }
   else {
      ++state;
   }
}


// Purpose:    Send a message over the RS485 bus
// Inputs:     1) The destination address
//             2) The number of bytes of data to send
//             3) A pointer to the data to send
// Outputs:    TRUE if successful
//             FALSE if failed
// Note:       Format:  source | destination | data-length | data | checksum
int1 rs485_send_message(int8 to, int8 len, int8* data) {
   int8 try, i, cs;
   int1 ret = FALSE;

   RCV_OFF();
   #if RS485_USE_EXT_INT
      disable_interrupts(GLOBAL);
   #endif

   for(try=0; try<5; ++try) {
      rs485_collision = 0;
      fputc((int16)0x100|rs485_id, RS485_CD);
      fputc((int16)0x100|to, RS485_CD);
      fputc(len, RS485_CD);

      for(i=0, cs=rs485_id^to^len; i<len; ++i) {
         cs ^= *data;
         fputc(*data, RS485_CD);
         ++data;
      }

      fputc(cs, RS485_CD);
      if(!rs485_collision) {
         ret = TRUE;
         break;
      }
      delay_ms(RS485_ID);
   }

   RCV_ON();
   #if RS485_USE_EXT_INT
      enable_interrupts(GLOBAL);
   #endif

   return(ret);
}


// Purpose:    Wait for wait time for the RS485 bus to become idle
// Inputs:     TRUE - restart the watch dog timer to prevent reset
//             FALSE - watch dog timer not restarted
// Outputs:    None
void rs485_wait_for_bus(int1 clrwdt)
{
   int16 i;

   RCV_OFF();
   for(i=0; i <= (rs485_wait_time*20); ++i)
   {
      if(!input(RS485_RX_PIN))
         i = 0;
      else
         delay_us(50);

      if(clrwdt)
         restart_wdt();
   }
}


// Purpose:    Get a message from the RS485 bus and store it in a buffer
// Inputs:     1) A pointer to a buffer to store a message
//             2) TRUE  - wait for a message
//                FALSE - only check if a message is available
// Outputs:    TRUE if a message was received
//             FALSE if wait is FALSE and no message is available
// Note:       Data will be filled in at the pointer as follows:
//             FROM_ID  DATALENGTH  DATA...
int1 rs485_get_message(int* data_ptr, int1 wait)
{
   while(wait && (rs485_ni == rs485_no)) {}

   if(rs485_ni == rs485_no)
      return FALSE;
   else {
      int n;
      n = rs485_buffer[(rs485_no+1)%sizeof(rs485_buffer)] + 2;

      for(; n>0; --n)
      {
         *data_ptr = rs485_buffer[rs485_no];
         if(++rs485_no >= sizeof(rs485_buffer))
         {
            rs485_no = 0;
         }
         ++data_ptr;
      }
      return TRUE;
   }
}

#endif
000101111 101110000011110 00010 11101 110 1 000111 00010010011010111100 101101001 11110000 001 00 10110 111 00001 01110 0010101 01011110 00 00011111111 0011111 011110001111111111 1011111111101100000000

Desconectado BINARIO

  • PIC16
  • ***
  • Mensajes: 156
Re: COMO HACER UN EJEMPLO SIMPLE EN PROTEUS CON LIBRERÍA RS485.C ?????? HELP!
« Respuesta #1 en: 08 de Septiembre de 2014, 09:53:24 »
Estimados!

He estado estudiando el codigo de la libreria en cuestion, y por ahora estoy estudiando a fondo la funcion #USE RS232(), dado que es la que usa esta libreria para poder ocupar RS485, por ahora sigo con esto casi termino esta funcion, espero tener progresos en el dia de hoy, saludos!
000101111 101110000011110 00010 11101 110 1 000111 00010010011010111100 101101001 11110000 001 00 10110 111 00001 01110 0010101 01011110 00 00011111111 0011111 011110001111111111 1011111111101100000000

Desconectado DarioNQN

  • PIC10
  • *
  • Mensajes: 1
Re: COMO HACER UN EJEMPLO SIMPLE EN PROTEUS CON LIBRERÍA RS485.C ?????? HELP!
« Respuesta #2 en: 12 de Septiembre de 2014, 21:49:47 »
Estimado yo también estuve tratando de hacer funcionar la librería de ccs en rs485 y no pude hacerla funcionar, no pude determinar la razón , así que me puse y la modifique, fíjate esta es la versión para 16f62xx a 4mhz  si queres modificar las frecuencias tenes que leer el manual de pic, y modificar SPBRG y BRGH, así como ver si para otros chips cambian las direcciones de los registros de control de la AUART, te envió la simulación de 4 módulos en red.
El driver es una variante del de ccs (no comercial).
Tenes  que cambiar la referencia del driver según donde descomprimas el ejemplo, funciono en el proteus, todavía no lo probé en la realizad, si alguien lo hace porfa que  publique los resultados. Hay que compilar el código. Espero te sirva. Saludos.

Desconectado BINARIO

  • PIC16
  • ***
  • Mensajes: 156
Re: COMO HACER UN EJEMPLO SIMPLE EN PROTEUS CON LIBRERÍA RS485.C ?????? HELP!
« Respuesta #3 en: 16 de Septiembre de 2014, 15:45:58 »
uh buenisimo justo estaba retomando esto ya mismo lo pruebo gracias!!!
000101111 101110000011110 00010 11101 110 1 000111 00010010011010111100 101101001 11110000 001 00 10110 111 00001 01110 0010101 01011110 00 00011111111 0011111 011110001111111111 1011111111101100000000

Desconectado BINARIO

  • PIC16
  • ***
  • Mensajes: 156
Re: COMO HACER UN EJEMPLO SIMPLE EN PROTEUS CON LIBRERÍA RS485.C ?????? HELP!
« Respuesta #4 en: 23 de Septiembre de 2014, 11:36:44 »
Esta buenisimo el ejemplo que armaste lo probe en proteus y estoy comenzando a redefinirlo para implementar un control simple 485, perdon la demora ayer rendi la ultima materia de la facu estaba con eso, ahora si tengo tiempo de meterle a esto seguro sale algo bien hecho para todos los colegas del foro saludos!
000101111 101110000011110 00010 11101 110 1 000111 00010010011010111100 101101001 11110000 001 00 10110 111 00001 01110 0010101 01011110 00 00011111111 0011111 011110001111111111 1011111111101100000000

Desconectado BINARIO

  • PIC16
  • ***
  • Mensajes: 156
Re: COMO HACER UN EJEMPLO SIMPLE EN PROTEUS CON LIBRERÍA RS485.C ?????? HELP!
« Respuesta #5 en: 01 de Octubre de 2014, 15:41:13 »
DarioNQN, podes subir un printscreen de la simulacion que hiciste, porque no puedo abrirla.
000101111 101110000011110 00010 11101 110 1 000111 00010010011010111100 101101001 11110000 001 00 10110 111 00001 01110 0010101 01011110 00 00011111111 0011111 011110001111111111 1011111111101100000000

Desconectado BINARIO

  • PIC16
  • ***
  • Mensajes: 156
Re: COMO HACER UN EJEMPLO SIMPLE EN PROTEUS CON LIBRERÍA RS485.C ?????? HELP!
« Respuesta #6 en: 03 de Octubre de 2014, 10:59:46 »
perdon dario, ya lo pude abrir, tuve que instalar el proteus 8, me llevo mejor con el proteus 7!

saludos!
000101111 101110000011110 00010 11101 110 1 000111 00010010011010111100 101101001 11110000 001 00 10110 111 00001 01110 0010101 01011110 00 00011111111 0011111 011110001111111111 1011111111101100000000

Desconectado BINARIO

  • PIC16
  • ***
  • Mensajes: 156
Re: COMO HACER UN EJEMPLO SIMPLE EN PROTEUS CON LIBRERÍA RS485.C ?????? HELP!
« Respuesta #7 en: 03 de Octubre de 2014, 16:58:11 »
DarioNQN

Ya pude hacer correr el programa que me enviaste con CCS, y simulando en proteus 7, es que lo conozco mejor jeje.
Por hoy termino aca, seguire el lunes. Pero te comento que logre enviar datos de un maestro a un esclavo, ahora quiero implementar algo bien simple, que cuando apretas un boton A el maestro envie el codigo "A", y el esclavo lo reconozca y responda con OK, si pasa todo eso, que presiones otro boton B desde el maestro y envie el codigo "B", entonces que el esclavo responda con un valor que este leyendo en un puerto.
Simple no? aunque implementarlo lleva un tiempo jeje, te agradezco la verdad que esta libreria me ayudo mucho, estimo que en esta semana proxima ya tendre un ejemplo solido y sencillo bien armado y explicado para poder compartir con los colegas.

Saludos desde cordoba!
000101111 101110000011110 00010 11101 110 1 000111 00010010011010111100 101101001 11110000 001 00 10110 111 00001 01110 0010101 01011110 00 00011111111 0011111 011110001111111111 1011111111101100000000

Desconectado BINARIO

  • PIC16
  • ***
  • Mensajes: 156
Re: COMO HACER UN EJEMPLO SIMPLE EN PROTEUS CON LIBRERÍA RS485.C ?????? HELP!
« Respuesta #8 en: 06 de Octubre de 2014, 16:08:05 »
Estimado Dario, reitero mis agradecimientos por tu rutina, es genial y esta funcionando, muestro un poco de lo que implemente, antes voy a comentar la logica planteada.

Seria asi: Mi maestro envia un codigo por el puerto cuando el pin RA2 esta en alto, el codigo es una trama: "SLV1". Cuando esto ocurre, un led del maestro se activa el led_online. Del otro lado el esclavo esta escuchando el puerto, y cuando detecta que llego la palabra "SLV1" se da por aludido y contesta con un "OK!" poniendo ademas en alto su led SLV1ON.

************************************CODIGO DEL MAESTRO*************************************

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

#FUSES NOWDT                    //Sin Watch Dog Timer
#FUSES NOPUT                    //Sin Power Up Timer
#FUSES XT                       //Cristal de  4mhz
#FUSES NOMCLR                   //Master Clear pin enabled
#FUSES NOBROWNOUT               //No brownout reset
#FUSES NOLVP                    //No low voltage prgming, B3(PIC16) or B5(PIC18) used for I/O
#FUSES NOCPD                    //No EE protection
#FUSES NOPROTECT     

//#USE FAST_IO(A)
//#USE FAST_IO(B)
//Code not protected from reading

#use delay(clock=4000000)

#define RS485_ID 0x1
#define RS485_RX_BUFFER_SIZE 15

#include "driver_rs485_JDP.c"

#define led_1  PIN_A0 
#define led_2  PIN_A1 
#define pb7    PIN_A2


int8 msg[4]="SLV1";
int8 msg1[7]="OFFLINE";
int8 msg2[5]="OK!";



void main(void)
{
 set_tris_b(0xD3);
 set_tris_a(0x04);
 rs485_init();
 rs485_wait_for_bus(false);
 
 
 while(1)
      {
        if ( input(PIN_A2) == 1)
         {
          output_high(led_1);
          rs485_wait_for_bus (false);
          rs485_send_message (0x2,5,msg);                                       //esclavo 1
          rs485_wait_for_bus (false);
          rs485_get_message (msg2, false);
          rs485_wait_for_bus (false);
         
          if ( msg2 == "OK!")
              output_high(led_2);
          else
              output_low(led_2);
         }
         else
            {
             rs485_wait_for_bus (false);
             rs485_send_message (0x2,7,msg1);                                       //esclavo 1
             rs485_wait_for_bus (false);
             rs485_get_message (msg2, false);
             output_low(led_1);
             output_low(led_2);
            }
      }

}

********************************CODIGO DEL ESCLAVO*****************************

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

#FUSES NOWDT                    //Sin Watch Dog Timer
#FUSES NOPUT                    //Sin Power Up Timer
#FUSES XT                       //Cristal de  4mhz
#FUSES NOMCLR                   //Master Clear pin enabled
#FUSES NOBROWNOUT               //No brownout reset
#FUSES NOLVP                    //No low voltage prgming, B3(PIC16) or B5(PIC18) used for I/O
#FUSES NOCPD                    //No EE protection
#FUSES NOPROTECT     

//#USE FAST_IO(A)
//#USE FAST_IO(B)
//Code not protected from reading

#use delay(clock=4000000)

#define RS485_ID 0x1
#define RS485_RX_BUFFER_SIZE 15

#include "driver_rs485_JDP.c"

#define led_1  PIN_A0 
#define led_2  PIN_A1 
#define pb7    PIN_A2


int8 msg[4]="SLV1";
int8 msg1[7]="OFFLINE";
int8 msg2[5]="OK!";



void main(void)
{
 set_tris_b(0xD3);
 set_tris_a(0x04);
 rs485_init();
 rs485_wait_for_bus(false);
 
 
 while(1)
      {
        if ( input(PIN_A2) == 1)
         {
          output_high(led_1);
          rs485_wait_for_bus (false);
          rs485_send_message (0x2,5,msg);                                       //esclavo 1
          rs485_wait_for_bus (false);
          rs485_get_message (msg2, false);
          rs485_wait_for_bus (false);
         
          if ( msg2 == "OK!")
              output_high(led_2);
          else
              output_low(led_2);
         }
         else
            {
             rs485_wait_for_bus (false);
             rs485_send_message (0x2,7,msg1);                                       //esclavo 1
             rs485_wait_for_bus (false);
             rs485_get_message (msg2, false);
             output_low(led_1);
             output_low(led_2);
            }
      }

}

El problema que tengo actualmente es que si bien he conseguido que el esclavo vea lo que hay en el canal, es decir que la comunicacion es optima, se me complica como veran la gestion de datos.
A lo que voy es que cuando yo envio SLV1 por el canal, el esclavo no acusa recibo, y actualmente estoy trabajando en ello.

Subire mis progresos en estos dias. saludos!
000101111 101110000011110 00010 11101 110 1 000111 00010010011010111100 101101001 11110000 001 00 10110 111 00001 01110 0010101 01011110 00 00011111111 0011111 011110001111111111 1011111111101100000000

Desconectado GabrielD

  • PIC10
  • *
  • Mensajes: 34
Re: COMO HACER UN EJEMPLO SIMPLE EN PROTEUS CON LIBRERÍA RS485.C ?????? HELP!
« Respuesta #9 en: 10 de Noviembre de 2014, 16:52:47 »
Buenas tardes muchachos,

Yo tambien estoy empezando a trabajar con la comunicacion rs485 y el max485.  Estaba leyendo este post y revisando la libreria rs485 de CCS Yme quedaron un par de dudas. La primera es que no veo en la libreria del rs485 que en ningun momento pongan en alto el pin DE para habilitar el envio de datos, y la segunda es este "driver_rs485_JDP.c" es un driver como tal o es la misma libreria rs485 y le modificaron el nombre?

Gracias y tambien me sumo a la tarea de hacer funcionar esta libreria.

Desconectado GabrielD

  • PIC10
  • *
  • Mensajes: 34
Re: COMO HACER UN EJEMPLO SIMPLE EN PROTEUS CON LIBRERÍA RS485.C ?????? HELP!
« Respuesta #10 en: 12 de Noviembre de 2014, 23:04:33 »
Hola, bueno la verdad por cuestiones de agilizar tiempo he utilizado la rutina que implemento RedPic. Luego con mas tiempo me sentare a probar la libreria de ccs. Igual estare pasando por aqui :)


 

anything