sábado, 26 de noviembre de 2011

Recepción de datos en C++ a través del puerto serial



Recepción de datos en C++ a través del puerto serial
En este programa de C++ recibiremos datos a través del puerto serial, usando la herramienta SerialPort. Los datos serán enviados por el PIC 18f4550 en un circuito montado en Proteus, este pic tendrá un programa de PIC C el cual se encargará de enviar los datos y Visual C++ los recibirá.
Entonces ya teniendo el circuito montado en Proteus crearemos entonces la aplicación en Visual C++.
Esta sólo tendrá un TextBox que recibirá los mostrará los datos, el SerialPort con el cual leeremos los datos del puerto serial y una Label solo para mostrar un título.






Al simular el circuio del Proteus se emulará un puerto serie y aparecerá en el administrador de dispositivos, de ahí tomamos su nombre para la propiedad PortName del SerialPort:

Siendo así el SerialPort “PuertoSerial” tandrá en su propiedad PortName COM10.
Inicia el código.
En la parte pública declaramos una variable entera llamada “numimpresiones” para contar el numero de veces que se imprime en el textbox “DatosRecepcion” cuando se rebase cierta cantidad se limpiará el textbox y se comenzará a imprimir de nuevo.
publicrefclass Form1 : public System::Windows::Forms::Form
       {
       public:
             intnumimpresiones;

Enseguida inicializamos la variable en cero:
Form1(void)
             {
                    InitializeComponent();
                    //
                    //TODO: agregar código de constructor aquí
                    //
                    numimpresiones=0;
Para saber si el puerto serial existe agregamos el siguiente código:

             if(!PuertoSerial->IsOpen)
                    {
                           try
                           {
                           //se abre el puerto serial
                           PuertoSerial->Open();
                           }
                           catch (Exception ^ex)
                           {
                           //manda un mensaje si no hay puerto detectado
                           MessageBox::Show("No hay puertos abiertos");
                           }
                    }

Ahora programamos el evento DataReceived del SerialPort:

Antes de ello declaramos un delegado:

delegatevoidDelegado(String ^ s);

Ahora sí programamos el evento DataReceived

//programacióndeleventoDataReceived
       private: System::Void PuertoSerial_DataReceived_1(System::Object^  sender, System::IO::Ports::SerialDataReceivedEventArgs^  e) {
//se declara una variable s de tipo string
String ^ s;

if(PuertoSerial->BytesToRead>0){ // Si hay datos a leer...
                     s=PuertoSerial->ReadExisting(); // Leemos datos.-
Delegado ^ Escribir=gcnew Delegado(this,&Form1::vCargaDatos); // Invocamos a función que escribe en TextBox
this->Invoke(Escribir,s);
                 }
                     }


Para imprimir los datos recibidos en el TextBoxDatosRecepcion creamos el siguiente método:
//metodo para imprimir en el TextBoxDatosRecepcion
       voidvCargaDatos(String ^ Data){

             if(numimpresiones<30)
             {
//agrega al textboxDatosRecepcion el valor de data
                    DatosRecepcion->Text+=Data;
                    //incremento de la variable numimpresiones
                           numimpresiones=numimpresiones+1;
              }
             else
              {  
                    //limpia textboxDatosRecepcion
                    DatosRecepcion->Text=L"";
                    //agrega al textboxDatosRecepcion el valor de data
             DatosRecepcion->Text+=Data;
                    //inicializa nuevamente la variable numimpresiones en cero
                    numimpresiones=0;
              }
      }


Aquí el código completo:
#pragmaonce

namespacemyserialport {

       usingnamespace System;
       usingnamespace System::ComponentModel;
       usingnamespace System::Collections;
       usingnamespace System::Windows::Forms;
       usingnamespace System::Data;
       usingnamespace System::Drawing;
      

       /// <summary>
       /// Resumen de Form1
       /// </summary>
       publicrefclass Form1 : public System::Windows::Forms::Form
       {
       public:
                    //variable global para contar las veces
                    //que se imprime en el textboxDatosRecepcion
             intnumimpresiones;

             Form1(void)
             {
                    InitializeComponent();
            
                    //
                    //TODO: agregar código de constructor aquí
                    //
                    //se inicializa la variable numimpresiones
                    numimpresiones=0;

             if(!PuertoSerial->IsOpen)
                    {
                           try
                           {
                           //abre el SerialPort
                           PuertoSerial->Open();
                           }
                           catch (Exception ^ex)
                           {
                           //manda un mensaje si no hay puerto detectado
                                  MessageBox::Show("No se encontró el puerto");
                           }
                    }
             }

       protected:
             /// <summary>
             /// Limpiar los recursos que se estén utilizando.
             /// </summary>
             ~Form1()
             {
                    if (components)
                    {
                           delete components;
                    }
             }
       private: System::IO::Ports::SerialPort^  PuertoSerial;
       private: System::Windows::Forms::TextBox^  DatosRecepcion;
       protected:

       private: System::Windows::Forms::Label^  lbdatosrecibidos;
       private: System::ComponentModel::IContainer^  components;

       private:
             /// <summary>
             /// Variable del diseñador requerida.
             /// </summary>


#pragmaregion Windows Form Designer generated code
             /// <summary>
             /// Método necesario para admitir el Diseñador. No se puede modificar
             /// el contenido del método con el editor de código.
             /// </summary>
             voidInitializeComponent(void)
             {
                    this->components = (gcnew System::ComponentModel::Container());
                    this->PuertoSerial = (gcnew System::IO::Ports::SerialPort(this->components));
                    this->DatosRecepcion = (gcnew System::Windows::Forms::TextBox());
                    this->lbdatosrecibidos = (gcnew System::Windows::Forms::Label());
                    this->SuspendLayout();
                    //
                    // PuertoSerial
                    //
                    this->PuertoSerial->PortName = L"COM10";
                    this->PuertoSerial->StopBits = System::IO::Ports::StopBits::Two;
                    this->PuertoSerial->DataReceived += gcnew System::IO::Ports::SerialDataReceivedEventHandler(this, &Form1::PuertoSerial_DataReceived_1);
                    //
                    // DatosRecepcion
                    //
                    this->DatosRecepcion->Location = System::Drawing::Point(12, 34);
                    this->DatosRecepcion->Multiline = true;
                    this->DatosRecepcion->Name = L"DatosRecepcion";
                    this->DatosRecepcion->Size = System::Drawing::Size(362, 255);
                    this->DatosRecepcion->TabIndex = 0;
                    //
                    // lbdatosrecibidos
                    //
                    this->lbdatosrecibidos->AutoSize = true;
                    this->lbdatosrecibidos->BackColor = System::Drawing::Color::Silver;
                    this->lbdatosrecibidos->Font = (gcnew System::Drawing::Font(L"Microsoft Sans Serif", 9.75F, System::Drawing::FontStyle::Bold, System::Drawing::GraphicsUnit::Point,
                           static_cast<System::Byte>(0)));
                    this->lbdatosrecibidos->Location = System::Drawing::Point(12, 9);
                    this->lbdatosrecibidos->Name = L"lbdatosrecibidos";
                    this->lbdatosrecibidos->Size = System::Drawing::Size(122, 16);
                    this->lbdatosrecibidos->TabIndex = 1;
                    this->lbdatosrecibidos->Text = L"Datos recibidos:";
                    //
                    // Form1
                    //
                    this->AutoScaleDimensions = System::Drawing::SizeF(6, 13);
                    this->AutoScaleMode = System::Windows::Forms::AutoScaleMode::Font;
                    this->BackColor = System::Drawing::Color::LightGray;
                    this->ClientSize = System::Drawing::Size(386, 298);
                    this->Controls->Add(this->lbdatosrecibidos);
                    this->Controls->Add(this->DatosRecepcion);
                    this->Name = L"Form1";
                    this->Text = L"Leerpuertoserie";
                    this->Load += gcnew System::EventHandler(this, &Form1::Form1_Load);
                    this->ResumeLayout(false);
                    this->PerformLayout();

             }
#pragmaendregion
            
/* *********************************************************************************************************************************** */
delegatevoidDelegado(String ^ s);
       private: System::Void PuertoSerial_DataReceived_1(System::Object^  sender, System::IO::Ports::SerialDataReceivedEventArgs^  e) {
                     String ^ s;

if(PuertoSerial->BytesToRead>0){ // Si hay datos a leer...
                   s=PuertoSerial->ReadExisting(); // Leemos datos.-
Delegado ^ Escribir=gcnew Delegado(this,&Form1::vCargaDatos); // Invocamos a función que escribe en TextBox
this->Invoke(Escribir,s);
                 }
                     }
                    //metodo para imprimir en el TextBoxDatosRecepcion
       voidvCargaDatos(String ^ Data){

             if(numimpresiones<30)
              {
//agrega al textboxDatosRecepcion el valor de data
                    DatosRecepcion->Text+=Data;
                    //incremento de la variable numimpresiones
                           numimpresiones=numimpresiones+1;
              }
             else
              {  
                    //limpia textboxDatosRecepcion
                    DatosRecepcion->Text=L"";
                    //agrega al textboxDatosRecepcion el valor de data
             DatosRecepcion->Text+=Data;
                    //inicializa nuevamente la variable numimpresiones en cero
                    numimpresiones=0;
              }
      }
};
}








Circuito montado en Proteus:





Código del programa para el pic en PIC C
#include<18f4550.h>
#device adc=8
#fuses HSPLL,NOWDT,NOPROTECT,NOLVP,NODEBUG,USBDIV,PLL5,CPUDIV1,VREGEN
#use delay(clock=48000000)
#include ".\include\usb_cdc.h"

int8 analog=0;

voidusb_debug_task(void)
{
static int8 Last_connected;
static int8 Last_enumerated;
int8 new_connected;
int8 new_enumerated;
static int8 Last_cdc;
int8 new_cdc;

new_connected=usb_attached();
new_enumerated=usb_enumerated();
new_cdc=usb_cdc_connected();
Last_connected=new_connected;
Last_enumerated=new_enumerated;
Last_cdc=new_cdc;
}

void main()
{
setup_adc_ports(AN0);
setup_adc(adc_clock_internal);

while(TRUE)
{
usb_task();
usb_debug_task();

if(usb_cdc_kbhit())
{
}

set_adc_channel(0);
analog=read_adc();
delay_us(50);
printf(usb_cdc_putc,"El valor analogico es: %3u\r\n",analog);
output_d(analog);
delay_ms(100);
}
}

Ejecución del  circuito en proteus:


Ejecutamos el programa en Visual C++.

Cuando no encuentre puerto serie mostrará un MessageBox:


















Cuando el puerto esté abierto mostrará lo siguiente(dependiendo del valor del potenciómetro en el circuito):





Enlace para descargar los archivos:
descargar archivos en Dropbox