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
descargar archivos en Dropbox