Comunicaciones seriales c# 2012

Preview:

DESCRIPTION

Recurso Didáctico para la Materia Sistemas Embebidos y Control

Citation preview

Caso: Visual C# 2012 ExpressMICROCHIP MCP2200

Por:

M.C. ANDRÉS GERARDO FUENTES COVARRUBIAS

1

Sistemas Digitales Avanzados

Instalación de Virtual Serial PortCreación de una nueva aplicación en

C# 2012 toolStrip y componentes básicosManejo de los puertos serialesApertura de un puertoTransmisiónRecepción

Autor: Andrés Gerardo Fuentes Covarrubias 2

Forma comoda de depurar las aplicaciones al crear puertos seriales virtuales pareados

Un puerto serial para la simulación en ISIS Proteus

Un puerto serial para el programa en Visual C# 2012

Autor: Andrés Gerardo Fuentes Covarrubias 3

Autor: Andrés Gerardo Fuentes Covarrubias 4

Abrir VC# 2012 y elegir“Archivo”->”Nuevo Proyecto”

Después “Aplicación de Windows Forms y el botón “Aceptar” después de darle nombre al nuevo proyecto

Autor: Andrés Gerardo Fuentes Covarrubias 5

• Elegir dos controles:

1. Para manejo de los puertos seriales: “SerialPort”, será el encargado de manejar todas las propiedades, métodos y eventos relacionados con el puerto o los puertos seriales de la aplicación, crear tantos como puertos seriales se necesite.

2. Para manejo de los controles básicos de las comunicaciones seriales, así como mensajes e indicadores, elija el control “ToolStrip”

Estos controles no son visibles en la forma principal, por lo tanto se colocan en el “Status Strip”

Autor: Andrés Gerardo Fuentes Covarrubias 6

Controles en la aplicación, ToolStrip.

Observe que para .Net el control para puerto serial contiene todas las propiedades para las características de la trama en tiempo de diseño

ComboBox

TextBox Boton Label

Autor: Andrés Gerardo Fuentes Covarrubias 7

Controles en la aplicación, área de trabajo

TabControl

OvalShape

Botones

toolStrip

Autor: Andrés Gerardo Fuentes Covarrubias 8

using System;using System.Collections.Generic;using System.ComponentModel;using System.Data;using System.Drawing;using System.Linq;using System.Text;using System.Windows.Forms;using System.IO;using System.IO.Ports;using System.Threading;using Microsoft.VisualBasic.PowerPacks;

namespace consolaSerialCDC{ public partial class Form1 : Form { public Form1() { InitializeComponent(); }

private void Form1_Load(object sender, EventArgs e) { }

}

El código fuente inicial solo describe las librerías a ser utilizadas al momento y el esqueleto inicial para el “namespace” correspondiente a nuestra aplicación.

Por lo general, este esqueleto de Clase principal es creada por VisualStudio al momento de inicializar el nuevo proyecto.

Finalmente el desarrollador debe indicar explícitamente las referencias externas con instrucciones “using” seguidas del “namespace” relacionado con la librería.

Agregar estas referenciasexternas

Autor: Andrés Gerardo Fuentes Covarrubias 9

if(!serialPort1.IsOpen){

try{

serialPort1.Open();}catch (System.Exception ex){

MessageBox.Show(ex.ToString());}

}

La apertura de un puerto serial en Visual C# es tan sencillo como agregar el siguiente código al botón “Conectar” del ToolStrip:

Las propiedades del control SerialPort se pueden establecer en tiempo de diseño mediante el cuadro de propiedades.

Autor: Andrés Gerardo Fuentes Covarrubias 10

serialPort1.BaudRate = 9600; // Velocidad de transmisión serialPort1.Parity = Parity.None; //Tipo de paridad serialPort1.DataBits = 8; //Número de bits de datos serialPort1.StopBits = StopBits.One; //Número de bits de parada serialPort1.PortName = toolStripTextBox1.Text; //Use el control adecuado para el usuario serialPort1.Open(); //Abrir el puerto

Siempre se puede abrir un puerto con el código siguiente y tambien establecer las caracteristicas de la trama:

Vincule el código anterior con un botón y podrá abrir el puerto serial capturado en el control “toolStripTextBox1” al presionar el botón “Conectar”

Sin embargo, es recomendable usar los controles adecuados que listen los recursos reconocidos por el sistema y que los pongan a disposición del usuario de la aplicación, para eso se agregaran en el toolStrip.

Autor: Andrés Gerardo Fuentes Covarrubias 11

•Siempre que haya un puerto serial abierto se puede enviar datos por ese puerto.

•En el TabControl “Consola”, Agregue dos controles

TextBox Botón

private void button1_Click(object sender, EventArgs e) { if (conectado == true) { if (tbTerminalEnviar.Text.Length > 0) { serialPort1.WriteLine("@" + tbTerminalEnviar.Text + "\r"); } else { MessageBox.Show("MENSAJE VACIO"); } } else { MessageBox.Show("Puerto Serial NO CONECTADO"); } }

Agregue el código del botón

Autor: Andrés Gerardo Fuentes Covarrubias12

byte[] miBuffer= new byte[1];

miBuffer[0] = 0x62; //Carácter a enviar por el puerto.SP1.Write(miBuffer, 0, miBuffer.Length);

Siempre es posible enviar también un solo caracter por el puerto serial:

// Enviar tramabyte[] miBuffer= new byte[3]; // Tres caracteres máximo.

miBuffer[0] = 0x74;miBuffer[1] = 0x54;miBuffer[2] = 0x13;

SP1.Write(miBuffer, 0, miBuffer.Length);

Por ejemplo, si lo que se desea es enviar una trama completa, entonces:

Autor: Andrés Gerardo Fuentes Covarrubias 13

strBufferOut = "1"; //Buffer de transmisión serialPort1.DiscardOutBuffer(); //Limpiamos el buffer de transmisión serialPort1.Write(strBufferOut); //Enviar caracteres

Cada control incluye código:

Indicadores con el control Ovalshape para simular leds.

Salidas por botón

También se puede vincular código a otros controles de usuario:

Autor: Andrés Gerardo Fuentes Covarrubias 14

El control comboBox nos permite listar los recursos hardware de comunicaciones seriales.

También mediante un control “textBox” se puede visualizar el puerto serial seleccionado, posteriormente mediante un “Botón” ejecutar el código vinculado con la apertura del puerto.

Un control adicional tipo “Label” se puede visualizar si el puerto seleccionado esta en estado “Conectado” o “No Conectado”, también cambiar la propiedad “ForeColor” a Green o Red respectivamente.

Autor: Andrés Gerardo Fuentes Covarrubias 15

private void UpdateSerialPorts() { toolStripComboBox1.Items.Clear();

// Añadir solo los puertos válidos try { foreach (String d in SerialPort.GetPortNames()) { toolStripComboBox1.Items.Add(d);} } catch { UpdateSerialPorts(); return; }

toolStripComboBox1.SelectedIndex = toolStripComboBox1.Items.Count - 1; if (toolStripComboBox1.Items.Count > 0) { toolStripComboBox1.SelectedIndex = 0; toolStripTextBox1.Text = toolStripComboBox1.Items[toolStripComboBox1.SelectedIndex].ToString(); } }

private void btActualizar_Click(object sender, EventArgs e)

{ UpdateSerialPorts(); }

Autor: Andrés Gerardo Fuentes Covarrubias 16

El código de “Actualizar” nos permite atender un evento de “Conexión en caliente”. Es decir cuando un usuario conecta una nueva interfaz serial USB cuando nuestra aplicación se esta ejecutando, de esta manera se puede actualizar la colección de datos del control “comboBox” y el usuario podrá localizar en esta su interfaz.

Invocar la función UpdateSerialPorts() en nuestra función Form_Load1() para que la colección de nombres de puertos sea actualizada en el mismo momento de la carga de la forma principal.

private void Form1_Load(object sender, EventArgs e) { UpdateSerialPorts();

lblEstadoPuerto.Text = "No Conectado"; lblEstadoPuerto.ForeColor = Color.Red; conectado = false;

}

Autor: Andrés Gerardo Fuentes Covarrubias 17

Agregar un evento para actualizar el textBox del toolStrip cada vez que el nombre de puerto serial cambie, de esta manera se podrá conectar el puerto serial correcto al presionar el botón “Conectar”

private void toolStripComboBox1_TextChanged(object sender, EventArgs e)

{ toolStripTextBox1.Text =

toolStripComboBox1.Items[toolStripComboBox1.SelectedIndex].ToString();

}

Autor: Andrés Gerardo Fuentes Covarrubias 18

Agregue una variable booleana tipo bandera para el manejo del estado del puerto serial, de esta manera será mas cómoda la validación del estado de la interfaz de comunicaciones.

public Boolean conectado;

Autor: Andrés Gerardo Fuentes Covarrubias 19

El proceso de recepción de datos es un proceso un poco mas complejo, ya que es necesario instalar el vector de interrupción del evento “DataReceived” y crear un nuevo Thread (hilo) que atienda al manejador de ese evento.

Autor: Andrés Gerardo Fuentes Covarrubias 20

Autor: Andrés Gerardo Fuentes Covarrubias 21

Crear un nuevo control TextBox, que sea multilínea, con ScrollBar vertical y ajustado a la parte inferior del formulario. Este control va a operar como nuestra consola del usuario, para desplegar mensajes de la aplicación, los datos enviados y los recibidos.

Autor: Andrés Gerardo Fuentes Covarrubias 22

1. Codigo de al cargar el formulario:

public Form1() {

txtRecibidos.Text = ""; strBufferIn = ""; serialPort1.DataReceived += new

SerialDataReceivedEventHandler(serialPort1_DataReceived);

}

Para crear un manejador, se debe agregar un nuevo manejador de eventos, y vincularlo con el método apropiado del control “serialPort”, el procedimiento consta de tres pasos:

Autor: Andrés Gerardo Fuentes Covarrubias 23

2. El codigo del manejador de eventos

private void serialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e)

{ strBufferIn = "";

//Debemos hacer una pausa, para que el buffer se llene por completo //y pueda cargar todos los datos. //Si esta pausa no se realiza, no carga las lineas por completo y solo //nos muestra parte del mensaje enviado.

Thread.Sleep(250); strBufferIn += serialPort1.ReadExisting(); if (serialPort1.BytesToRead > 0) strBufferIn += serialPort1.ReadExisting();

String Linea; Linea = strBufferIn; //Guardamos la cadena original para

"Split" //Posterior

this.Invoke(new EventHandler(Actualiza_textbox)); }

Autor: Andrés Gerardo Fuentes Covarrubias 24

2. El codigo del “delegado”

private void Actualiza_textbox(object s, EventArgs e) { txtRecibidos.Text += strBufferIn + "\r\n"; }

Autor: Andrés Gerardo Fuentes Covarrubias 25

Siempre es posible manejar la barra de estado de nuestro formulario:

•Barra de estado

•Menú de opciones

Autor: Andrés Gerardo Fuentes Covarrubias 26

Agregue un control “timer”

Para agregar el reloj del sistema a la barra de estado:

Configure las propiedades

Ejecute los siguientes pasos en el orden indicado:

Autor: Andrés Gerardo Fuentes Covarrubias 27

Agregar el código al control del timer:

private void timer1_Tick(object sender, EventArgs e){ statusStrip1.Items[0].Text = DateTime.Now.ToLongTimeString();}

1 2 3

Cambie la propiedad“Text” a “hh:mm:ss”

Control mas efectivo sobre los caracteres delimitadores

Posibilidad de hacer parsing en línea

Autor: Andrés Gerardo Fuentes Covarrubias 28

Autor: Andrés Gerardo Fuentes Covarrubias 29

private void serialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e)

{ recibidos = ""; carSerial = (char) 0; while(carSerial!=';') { carSerial = (char) serialPort1.ReadChar(); if (carSerial == ';') break; recibidos += carSerial.ToString(); }

this.Invoke(new EventHandler(Actualiza_textbox)); }

Use un delimitador de campo, por lo general es el caracter “,”

Use un delimitador de cadena, por lo general es el caracter “;”

Use el método SplitProcese los tokens encontrados

Autor: Andrés Gerardo Fuentes Covarrubias 30

public Form1() { InitializeComponent(); }

private void btSplit_Click(object sender, EventArgs e)

{ str = txtCadena.Text; string[] parts =

str.Split(seps); for (int i = 0; i < parts.Length;

i++) cadenaSplit += parts[i]+"\

r\n"; txtConsola.Text =

cadenaSplit; } }}

Autor: Andrés Gerardo Fuentes Covarrubias 31

using System;using System.Collections.Generic;using System.ComponentModel;using System.Data;using System.Drawing;using System.Linq;using System.Text;using System.Windows.Forms;

namespace splitCampos{ public partial class Form1 : Form { string str; char[] seps={','}; string cadenaSplit;

private void Actualiza_textbox(object s, EventArgs e) { string[] parts = recibidos.Split(seps); //Tokenizamos la trama

if (parts.Length == 3) //Validamos numero de //tokens encontrdos, deben ser 3

{ lblTemp.Text = parts[1]; //Actualizamos etiquetas lblVolt.Text = parts[2]; } lblRecibido.Text = recibidos; //Visualizamos trama actual txtRecibidos.Text += recibidos+"\r\n"; //Actualizamos el textBox

consola }

Autor: Andrés Gerardo Fuentes Covarrubias 32

'Definir las características de la comunicación Serie.BaudRate = 19200 'Fijar velocidad de comunicaciones Serie.DataBits = 8 'Longitud en bits para Byte de datos Serie.Parity = Parity.Even 'Asignar paridad(enumeration parity) Serie.StopBits = StopBits.Two 'Bits parada después byte de datos

'Abrir/Control/Liberar Puerto Serie.Open() 'Abrir el puerto Serie Serie.Close() 'Cerrar el Puerto Serie Serie.Dispose() 'Liberar objeto

Dim SiNo As Integer SiNo = Serie.IsOpen 'El Puerto esta abierto?

Dim Puerto As String Puerto = Serie.PortName 'Nombre del puerto

Autor: Andrés Gerardo Fuentes Covarrubias 33

'Manejo y Control de señales Dim Estado As Boolean 'True=Activa / False=Inactiva

Estado = Serie.CDHolding 'Estado de la señal carrier detect Estado = Serie.CtsHolding 'Señal Clear to Send Estado = Serie.DsrHolding 'Señal Data Set Ready Serie.DtrEnable = True 'Activar de Data Terminal Ready Serie.RtsEnable = True 'Activar Request To Send

'Control Transmission/Recepcion Serie.ReadBufferSize = 1024 'Dimensionar tamaño buffer recepción Serie.WriteBufferSize = 1024 'Dimensionar tamaño buffer envío Serie.ReadTimeout = 10 'Fuera de tiempo para las lecturas Serie.WriteTimeout = 10 'Fuera de tiempo para las escrituras Serie.Handshake = Handshake.XOnXOff 'Tipo control para recepción/envío Serie.DiscardInBuffer() 'Borrar el buffer de entrada Serie.DiscardOutBuffer() 'Borrar el buffer de salida

Autor: Andrés Gerardo Fuentes Covarrubias 34

'Enviar datos Contador = Serie.BytesToWrite 'Bytes en espera de ser

escritos Serie.Write("Hola Mundo") 'Enviar una cadena de caracteres Serie.WriteLine("Hola Mundo") 'Enviar una línea 'Leer datos

Contador = Serie.BytesToRead 'Bytes en espera de ser leídos Serie.ReadByte() 'Leer un byte Serie.ReadChar() 'Leer un char Serie.ReadLine() 'Leer una línea Serie.ReadExisting() 'Leer los datos existentes en

buffer

Autor: Andrés Gerardo Fuentes Covarrubias 35

Interfaz serial RS232C MCP2200Circuito LM35z a °CRegistrador de temperaturasGraficador de 2 canales

Autor: Andrés Gerardo Fuentes Covarrubias 36

Autor: Andrés Gerardo Fuentes Covarrubias 37

El hardware de interfaz consta de un convertidor de protocolo serial – paralelo a USB, lo que lo hace muy atractivo para estas aplicaciones.

El circuito esta basado en el MCP2200 de Microchip, este cuenta con una DLL (librería) muy rica en funciones para configuración de patillaje, entrada de niveles digitales y salidas de control.

Autor: Andrés Gerardo Fuentes Covarrubias 38

Principales características:

•Modo full – duplex hasta 1Mbps•Manejo de la conexión en modo Virtual Serial Port bajo todas las versiones de Windows, Linux y Mac•Soporta Control de flujo•Hasta 8 pines de propósito general •Memoria de usuario de 256 bytes de propósito general•Leds de actividad para el monitoreo del bus

•Totalmente programable en lenguajes visuales mediante DLL de usuario.

Autor: Andrés Gerardo Fuentes Covarrubias 39

Para la implementación del modelo de programación basta con instalar la referencia externa en el proyecto a la DLL provista por el fabricante.

Invocación de los objetos y métodos dentro del código del proyecto

Autor: Andrés Gerardo Fuentes Covarrubias 40

bool ClearPin(pinNumber) Pone en nivel 0 “pinNumber”

bool SetPin(pinNumber) Pone en nivel 1 “pinNumber”

bool ReadPin(pinNumber, *pinValue) Lee el nivel lógico en la entrada “pinNumber”

y lo refleja en la variable booleana “pinValue” int ReadPinValue(pinNumber)

Lee el nivel lógico en la entrada “pinNumber”

Autor: Andrés Gerardo Fuentes Covarrubias 41

bool ReadPort(*portValue) Lee el valor completo del puerto GPx

como int y lo refleja en la variable “portValue”

bool ReadPort(*portValue)

bool WritePort(portValue)

Autor: Andrés Gerardo Fuentes Covarrubias 42

void InitMCP2200(VID, PID)bool ConfigureIO(mask)

Autor: Andrés Gerardo Fuentes Covarrubias 43

bool IsConnected() int ReadEEPROM(uiEEPAddress) int WriteEEPROM(uiEEPAddress,

ucValue)

Autor: Andrés Gerardo Fuentes Covarrubias 44

ComPim: Para salida de datos por medio de un Virtual Port

Monitoreo por medio de la Terminal Virtual

Autor: Andrés Gerardo Fuentes Covarrubias 45

Interconecta por “cable cruzado” la terminal virtual y el control ComPim

Por medio de un programa de hiperterminal se puede monitorear la actividad serial RS232C

No se necesita convertidor de protocolo MAX232

Autor: Andrés Gerardo Fuentes Covarrubias 46

Comunicaciones Full-DuplexCompatibilidad 9600, 8 , N, 1Programable en lenguaje de alto

nivelBaudRate totalmente configurableCapaz de manejar e identificar

paridad

Autor: Andrés Gerardo Fuentes Covarrubias 47

ZedGraph es uno de los controles mas utilizados en ingeniería para desplegar gráficos de puntos o líneas.

Como es un control externo es necesario instalarlo como un componente adicional.

Autor: Andrés Gerardo Fuentes Covarrubias 48

La primera parte consiste en su inicialización

La segunda parte ocurre tambien en tiempo de ejecución y consiste en la impresión de los puntos recibidos y unirlos mediante lineas.

Autor: Andrés Gerardo Fuentes Covarrubias 49

Autor: Andrés Gerardo Fuentes Covarrubias 50

Consiste en la inicialización del control

Generalmente se efectúa al cargar la forma principal por primera vez

Se puede usar una función de usuario

1. Definir un objeto tipo lista:PointPairList list1 = new PointPairList();

2. Crear la función de usuario:private void inicializaGrafico(ZedGraphControl zgc){ GraphPane myPane = zgc.GraphPane; // Titulos myPane.Title.Text = "Gráfico de temperaturas"; myPane.XAxis.Title.Text = "Muestra"; myPane.YAxis.Title.Text = "Temperatura"; myPane.YAxis.Scale.Max = 150; // Inicializa una curva con diamantes en cada

muestra // la palabra "temperatura" como titulo de la muestra

LineItem myCurve = myPane.AddCurve("Temperatura",

list1, Color.Red,

SymbolType.None);}

3. Inicializarla dentro de Form_Load14. No olvidar referenciar el NameSpace ZedGraph con

el Using correspondiente

Autor: Andrés Gerardo Fuentes Covarrubias 51

private void Form1_Load(object sender, EventArgs e){

UpdateSerialPorts(); inicializaGrafico(graficoTemp);}

private void inicializaGrafico(ZedGraphControl zgc){

GraphPane myPane = zgc.GraphPane;

// Titulos myPane.Title.Text = "Gráfico de temperaturas"; myPane.XAxis.Title.Text = "Muestra"; myPane.YAxis.Title.Text = "Temperatura"; myPane.YAxis.Scale.Max = 150;

// Inicializa una curva con diamantes en cada muestra tomada // la palabra "temperatura" como titulo de la muestra

LineItem myCurve = myPane.AddCurve("Temperatura", list1, Color.Red, SymbolType.None);

}

Autor: Andrés Gerardo Fuentes Covarrubias 52

La recepción debe cambiar ya que tradicionalmente se procesa el buffer de recepción en conjunto.

Ahora deberá procesarse carácter a carácter hasta obtener un carácter de fin de trama = “;”

Despues de recibir el fin de trama deberá separarse los campos con el método Split

Autor: Andrés Gerardo Fuentes Covarrubias 53

private void Actualiza_textbox(object s, EventArgs e){ string[] parts = strBufferIn.Split(seps);

if (parts.Length == 3) { lblTemp.Text = parts[1]; temperaturaCanal1 = Convert.ToSingle(parts[1]); numMuestra++; float x = (float)numMuestra; float y = (float)temperaturaCanal1; list1.Add(x, y); graficoTemp.AxisChange(); graficoTemp.Refresh(); lblVolt.Text = parts[2]; } txtConsola.Text += strBufferIn + "\r\n";}

Autor: Andrés Gerardo Fuentes Covarrubias 54

fuentesg@ucol.mx fuentesg85@hotmail.com fuentesg@gmail.comFacebook:

/Andres.FuentesCovarrubias

Autor: Andrés Gerardo Fuentes Covarrubias 55