Comunicación serial RS232 half duplex, Pic C Compiler

En esta sección aprenderÔs a realizar una comunicación serial RS232 half duplex con dos microcontroladores PIC. El objetivo es enviar un comando al PIC esclavo para pedir el valor de diferentes sensores y mostrarlos en una pantalla OLED.

Comunicación serial RS232

La comunicación RS232 es un protocolo de comunicación asíncrono que define cómo los dispositivos deben transmitir y recibir datos y señales de control. Establece normas para la transmisión de señales de control, como el inicio y el fin de los datos, y también define los parÔmetros de los cables y conectores utilizados para la conexión.

AdemÔs, la comunicación RS232 permite una amplia gama de velocidades de transmisión de datos, lo que la hace adecuada para una amplia variedad de aplicaciones. La velocidad de transmisión de datos se puede ajustar según sea necesario para adaptarse a las necesidades específicas de una aplicación.

Comunicación half duplex

La comunicación half duplex es una forma de comunicación en la que dos dispositivos sólo pueden transmitir información en un solo sentido a la vez. Es decir, en cualquier momento dado, sólo uno de los dispositivos puede enviar información mientras que el otro recibe.

Este tipo de comunicación es común en radios walkie-talkies, en los que un usuario presiona un botón para hablar y suelta el botón para escuchar. También se utiliza en algunos dispositivos de red y en sistemas de control de trÔfico aéreo.

En comparación con la comunicación full duplex, la comunicación half duplex es menos eficiente ya que requiere un tiempo adicional para alternar entre el envío y la recepción de información. Sin embargo, puede ser útil en situaciones en las que se requiere un control mÔs estricto sobre quién puede hablar en cualquier momento dado.

En resumen, la comunicación half duplex es una forma de comunicación en la que dos dispositivos pueden transmitir información en un solo sentido a la vez, alternando entre el envío y la recepción de información.

Circuito de conexión

Programación PIC de Maestro

Inicialmente se establecen los parÔmetros de la comunicación RS232.

  • baud = Velocidad de transmisión.
  • parity = Bit de paridad.Ā 
  • xmit = Pin de transmisión.
  • rcv = Pin de recepción.Ā 
  • bits = Datos de transmisión.
  • stream = identificación de transmisión.

#use rs232(baud=9600, parity=N, xmit=PIN_C6, rcv=PIN_C7, bits=8)

Se envían los datos al PIC esclavo para pedir el valor de la medición del puerto analógico AN0.

Los primeros 4 caracteres «PIC1» corresponden a la dirección del PIC esclavo y los siguientes 4 caracteres «PAN0» corresponden al comando para pedir el valor del pin analógico AN0.


 printf("PIC1PAN0\r");

Cuando se envían los datos al PIC esclavo debemos esperar su respuesta con el valor del puerto que solicitamos, la función «kbhit()» espera la recepción del primer caracter  por el puerto RS232, los caracteres recibidos se guardan en la variable «recibido[]» y termina hasta recibir el salto de linea «/r».


void recive()
{
   memset(recibido, 0, sizeof(recibido)); //limpia los registros de la varible
   while(true)
   {
      if (kbhit())//espera el primer caracter
      {
         int8 i=0;
         while(true)
         {
            recibido[i]=getc();//RECIBE EL CARACTER
      
            if(recibido[i]=='\r')//busca el salto de linea \r            
            {
               recibido[i]='\0';//fin de la cadena = caracter nulo \0
               return;
            }
            i++;
         }
      }
   }
}

Se convierte la cadena de caracteres de la variable «recibido» en un entero de 16bits y el valor se guarda en la variable «PAN0».


 PAN0 = (int16)atol(recibido);  //convierte la cadena en un numero de 16bits

Se realiza el mismo procedimiento para obtener el valor del pin analógico AN1 y los pines digitales RD0 y RD1.


      printf("PIC1PAN1\r");
      recive(); 
      PAN1 = (int16)atol(recibido);  //convierte la cadena en un numero de 16bits
      
      printf("PIC1PRD0\r");
      recive(); 
      PRD0 = (int1)atoi(recibido);  //convierte la cadena en un numero de 8bits
      
      printf("PIC1PRD1\r");
      recive(); 
      PRD1 = (int1)atoi(recibido);  //convierte la cadena en un numero de 8bits

Finalmente hace el llamado a la subrutina «mostrar()» para mostrar los valores obtenido de los diferentes sensores y actuadores en el display OLED.


void mostrar()
{
   char texto[20];

   sprintf(texto,"PAN0=%04lu",PAN0);
   OLED_DrawText(1,1,texto,1);

   sprintf(texto,"PAN1=%04lu",PAN1);
   OLED_DrawText(1,10,texto,1);
   
   sprintf(texto,"PRD0=%u",PRD0);
   OLED_DrawText(1,20,texto,1);

   sprintf(texto,"PRD1=%u",PRD1);
   OLED_DrawText(1,30,texto,1);

   OLED_Display();//Muestra la información en pantalla;
}

Código completo PIC de Maestro


#include "string.h"
#include "stdlib.h"

#FUSES NOMCLR

#use i2c(Master,Fast, sda=PIN_B0, scl=PIN_B1, force_sw, stream=OLED_stream)//parametros I2C
#use rs232(baud=9600, parity=N, xmit=PIN_C6, rcv=PIN_C7, bits=8)


#define SH1106_128_64 //DEFINE EL MODELO DE LA PANTALLA OLED
//#define SSD1306_128_64

#include "OLED_I2C.c" //libreria oled I2C

char recibido[20];

int16 PAN0=0;    
int16 PAN1=0;
int1 PRD0=0;     
int1 PRD1=0;

void recive()
{
   memset(recibido, 0, sizeof(recibido)); //limpia los registros de la varible
   while(true)
   {
      if (kbhit())//espera el primer caracter
      {
         int8 i=0;
         while(true)
         {
            recibido[i]=getc();//RECIBE EL CARACTER
      
            if(recibido[i]=='\r')//busca el salto de linea \r            
            {
               recibido[i]='\0';//fin de la cadena = caracter nulo \0
               return;
            }
            i++;
         }
      }
   }
}


void mostrar()
{
   char texto[20];

   sprintf(texto,"PAN0=%04lu",PAN0);
   OLED_DrawText(1,1,texto,1);

   sprintf(texto,"PAN1=%04lu",PAN1);
   OLED_DrawText(1,10,texto,1);
   
   sprintf(texto,"PRD0=%u",PRD0);
   OLED_DrawText(1,20,texto,1);

   sprintf(texto,"PRD1=%u",PRD1);
   OLED_DrawText(1,30,texto,1);

   OLED_Display();//Muestra la información en pantalla;
}



void main()
{
   
   OLED_Begin();
   OLED_ClearDisplay();
      
   while(TRUE)
   {

      printf("PIC1PAN0\r");
      recive(); 
      PAN0 = (int16)atol(recibido);  //convierte la cadena en un numero de 16bits
      
      printf("PIC1PAN1\r");
      recive(); 
      PAN1 = (int16)atol(recibido);  //convierte la cadena en un numero de 16bits
      
      printf("PIC1PRD0\r");
      recive(); 
      PRD0 = (int1)atoi(recibido);  //convierte la cadena en un numero de 8bits
      
      printf("PIC1PRD1\r");
      recive(); 
      PRD1 = (int1)atoi(recibido);  //convierte la cadena en un numero de 8bits
      
      mostrar();  
   }

}

Programación PIC de Esclavo

Inicialmente se establecen los parÔmetros de la comunicación RS232.

  • baud = Velocidad de transmisión.
  • parity = Bit de paridad.Ā 
  • xmit = Pin de transmisión.
  • rcv = Pin de recepción.Ā 
  • bits = Datos de transmisión.
  • stream = identificación de transmisión.

#use rs232(baud=9600, parity=N, xmit=PIN_C6, rcv=PIN_C7, bits=8)

Se habilita la conversión analógico digital para hacer la medición en los pines analógicos.


 setup_adc(ADC_CLOCK_INTERNAL);

En la función «main()» se realizan la mediciones de los componentes conectados a los pines analógico AN0, analogico AN1 y los pines digitales RD0 y RD1.


       set_adc_channel (0); //Habilita el canal AN0
       delay_us(10);
       PAN0 = read_adc(); //lectura del potenciometro

       set_adc_channel (1); //Habilita el canal AN1
       delay_us(10);
       PAN1 = read_adc(); //lectura del sensor de gas

       PRD0 = input(pin_d0); // lectura del boton 
        
       PRD1 = input(pin_d1); // lectura del sensor de presencia

Se habilitan las interrupciónes para la recepción de datos por el puerto RS232.


   enable_interrupts(int_rda);
   enable_interrupts(global);

Cuando se recibe un dato por el puerto Rs232 se activa la interrupción y se introduce en la subrutina Ā«rda_isr()Ā», donde la variable Ā«recibido[]Ā» guarda la cadena de caracteres recibidos hasta recibir el carĆ”cter ‘\r’ y terminar la recepción de los datos.


#int_rda
void rda_isr()
{
   memset(recibido, 0, sizeof(recibido)); //limpia los registros de la varible
   int8 i=0;
   while(true)
   {
      recibido[i]=getc();//RECIBE EL CARACTER

      if(recibido[i]=='\r')//busca el salto de linea \r
      {
         recibido[i]='\0';//fin de la cadena = caracter nulo \0
         enviar();
         return;
      }
      i++;
   }
}

Cuando termina de recibir datos se hace el llamado a la subrutina «enviar()» donde inicialmente identificamos la dirección y el comando.


      for (int i=0; i<=3; ++i)
      {
         address[i] = recibido[i]; //identifica el PIC
      }
      
      for (int i=0; i<=3; ++i)
      {
         com[i] = recibido[i+4]; //identifica el COMANDO
      }

Se compara la dirección del PIC esclavo con la dirección recibida, si son iguales entrara a la condición de lo contrario retornara a la función «main()».


      result = strcmp(address, PIC1);//compara, si son iguales (0), no (+-1)
   
      if (result==0)///si recibe la direccion
      { 

      }

Si la dirección es correcta, se procede a comparar el comando recibido con los comandos del pic esclavo, para identificar cual es el dato que se enviara devuelta el PIC maestro, una vez identificado el comando, se envía el dato por el puerto rs232 al pic maestro y se retorna a la función «main()».


         result = strcmp(com, CPAN0);//compara, si son iguales (0), no (+-1)
         
         if (result==0)
         {
            printf("%04lu\r",PAN0);//envia el valor del pin AN0
            return;
         }
         
         result = strcmp(com, CPAN1);//compara, si son iguales (0), no (+-1)
         
         if (result==0)
         {
            printf("%04lu\r",PAN1);//envia el valor del pin AN1
            return;
         }

Código completo PIC de Esclavo


#include "string.h"
#include "stdlib.h"

#FUSES NOMCLR

#use rs232(baud=9600, parity=N, xmit=PIN_C6, rcv=PIN_C7, bits=8)

char recibido[20];

int16 PAN0=0;     
int16 PAN1=0;
int1 PRD0=0;     
int1 PRD1=0;

void enviar();

#int_rda
void rda_isr()
{
   memset(recibido, 0, sizeof(recibido)); //limpia los registros de la varible
   int8 i=0;
   while(true)
   {
      recibido[i]=getc();//RECIBE EL CARACTER

      if(recibido[i]=='\r')//busca el salto de linea \r
      {
         recibido[i]='\0';//fin de la cadena = caracter nulo \0
         enviar();
         return;
      }
      i++;
   }
}


void enviar()
{
   int8 address[10]; 
   int8 com[10];
   
   int8 PIC1[10]="PIC1";
    
   int8 CPAN0[10] = "PAN0";   
   int8 CPAN1[10] = "PAN1";
   int8 CPRD0[10] = "PRD0";    
   int8 CPRD1[10] = "PRD1";
   
   signed int8 result;
   
   memset(address, 0, sizeof(address)); //limpia los registros de la varible 
   memset(com, 0, sizeof(com)); //limpia los registros de la varible 
   
   while (true)
   {
   
      for (int i=0; i<=3; ++i)
      {
         address[i] = recibido[i]; //identifica el PIC
      }
      
      for (int i=0; i<=3; ++i)
      {
         com[i] = recibido[i+4]; //identifica el COMANDO
      }
      
      result = strcmp(address, PIC1);//compara, si son iguales (0), no (+-1)
   
      if (result==0)///si recibe la direccion
      {  
         result = strcmp(com, CPAN0);//compara, si son iguales (0), no (+-1)
         
         if (result==0)
         {
            printf("%04lu\r",PAN0);//envia el valor del pin AN0
            return;
         }
         
         result = strcmp(com, CPAN1);//compara, si son iguales (0), no (+-1)
         
         if (result==0)
         {
            printf("%04lu\r",PAN1);//envia el valor del pin AN1
            return;
         }
         
         result = strcmp(com, CPRD0);//compara, si son iguales (0), no (+-1)
         
         if (result==0)
         {
            printf("%u\r",PRD0);//envia el valor del pin RD0
            return;
         }
         
         result = strcmp(com, CPRD1);//compara, si son iguales (0), no (+-1)
         
         if (result==0)
         {
            printf("%u\r",PRD1);//envia el valor del pin RD1
            return;
         }     
      }
      return;
   }
}


void main()
{
   
   enable_interrupts(int_rda);
   enable_interrupts(global);
   
   setup_adc(ADC_CLOCK_INTERNAL);
   
   while(TRUE)
   {
       set_adc_channel (0); //Habilita el canal AN0
       delay_us(10);
       PAN0 = read_adc(); //lectura del potenciometro

       set_adc_channel (1); //Habilita el canal AN1
       delay_us(10);
       PAN1 = read_adc(); //lectura del sensor de gas

       PRD0 = input(pin_d0); // lectura del boton 
        
       PRD1 = input(pin_d1); // lectura del sensor de presencia
   }
}
PCBWay2
Scroll al inicio