Professional Documents
Culture Documents
Manual 3ra parte En esta parte del curso nos enfocamos al control de perifricos, la comunicacin con otros dispositivos y la organizacin de un proyecto por capas. Temario
Prctica: Chat por puerto serie entre 2 computadoras................................135 Prctica: Comunicacin con Microcontrolador PIC 16F887 va RS232 ......138 Programa para PIC: Comunicacin serie bidireccional con C#.NET...........139 Prctica: Control de puerto paralelo...........................................................144 Patrones de diseo por capas: Datos, Negocio y Presentacin..................149 Monitoreo de PLC's por medio de aplicaciones en C#.NET.........................166 Configurando un PLC KOYO DL06 de Automation Direct...........................168 Configurando un PLC Siemens S7-300 .....................................................174 Aplicacin Cliente para monitorear PLCs desde C#.NET...........................183 Prctica: Monitoreo y Control con Smartphone...........................................190
5 9 4 8 3 7 2 6 1
5 9 4 8 3 7 2 6 1
En nuestro caso utilizamos el COM3. Ahora creamos un nuevo proyecto de windows forms donde arrastramos los siguientes controles:
Button Name: btnEnviar Enabled: False CheckBox Name: chkPuertoSerie TextBox Name: txtNick
135
El puerto serial lo configuramos con los siguientes datos: En nuestro cdigo declaramos un objeto string con mbito para toda la clase.
using using using using using using using using System; System.Collections.Generic; System.ComponentModel; System.Data; System.Drawing; System.Linq; System.Text; System.Windows.Forms;
namespace ProyectoChatRS232 { public partial class frmChat : Form { string datoSerial; public frmChat() { InitializeComponent(); }
Creamos una funcin para manejar el evento TextoRecibido: (se debe teclear manualmente)
private void TextoRecibido(object sender, EventArgs e) { txtConversacion.Text = ""; txtConversacion.AppendText(datoSerial); listBoxChat.Items.Add(datoSerial); }
136
Ahora podemos probar la aplicacin: Si no contamos con otra PC podemos unir los pines 2 y 3 del DB9 y ver como nos llega el dato que enviamos.
137
11 32 31 12
16F887
No ocupa oscilador!
Leds
Resistencias 330 ohm
33 34 35 36 37 38 39 40
DISPLAY LCD
5 Volts
8 9 10 1
15 16 17 18 23 24 25 26
+ -
Resistencias 1k ohm
5 9 4 8 3 7 2 6 1
Microswitch
Material: 1 pic 16F887, 1 conector DB9 hembra,1 microswitch (8 polos), 1 potencimetro de 10 k ohm, 8 resistencias 1 kOhm, 8 resistencias 330 Ohm, 8 leds, 2 protoboard, 1 max232, 4 capacitores 1uf 63volts, 1 metro de cable de red, 1 display lcd 16x2. Equipo necesario: 1 Programador de Pics (40 pines), 1 Fuente de voltaje (5 volts), Pinzas, Multmetro.
MAX232
2 3 4 5 6 7 14 13
RA0/AN0/ULPWU/C12IN0RA1/AN1/C12IN1RA2/AN2/VREF-/CVREF/C2IN+ RA3/AN3/VREF+/C1IN+ RA4/T0CKI/C1OUT RA5/AN4/SS/C2OUT RA6/OSC2/CLKOUT RA7/OSC1/CLKIN RC0/T1OSO/T1CKI RC1/T1OSI/CCP2 RE0/AN5/RD RC2/P1A/CCP1 RE1/AN6/WR RC3/SCK/SCL RE2/AN7/CS RC4/SDI/SDA RE3/MCLR/Vpp/ RC5/SDO RC6/TX/CK RC7/RX/DT
19 20 21 22 27 28 29 30
ENABLE RS RW D4 D5 D6 D7
Capacitores 1 ufaradio
+ + -
138
139
140
Puede bajar los archivos fuente de este proyecto desde: http://www.multitecnologia.com/ArchivosFuentePIC16f887CursoC.rar Si no cuenta con CCS para compilar el programa puede grabar el hexadecimal directamente con MPLAB. Como puede observar el PIC esta siempre esperando tres mensajes y responde a esos comandos: "escribe : Cuando el PIC recibe esta cadena se queda esperando un nmero entre 0255 con el que imprime los datos en el puerto B del PIC. Ra0" : Con este mensaje nos responde con un valor con la conversin a decimal del puerto analogico (0-5 volts), la resolucin es de 8 bits. "byteEnt" : Esta cadena le dice al PIC que nos responda con los 8 bits de entrada. Observe que todos los mensajes PIC PC tienen un final con la cadena: +Fin, esto permite hacer mas eficiente la lectura en C# y conocer el final de la trama de datos: printf("+%u+Fin", valorAnalogo); printf("Se escribio en el puerto B +Fin"); Ahora con su circuito armado y el PIC programado abrimos un nuevo proyecto de windows forms. Arrastramos los siguientes controles:
ListBox Name: listBoxDatosEntrada NumericUpDown Name: numStepByte Minimum: 0 Maximum: 255 CheckBox Name: chkPuertoSerie
141
El puerto serial debe estar con la misma configuracin del PIC: #use rs232(baud=9600,parity=N,xmit=PIN_C6,rcv=PIN_C7,bits=8)
Este ejercicio es similar al Chat, tambin creamos un objeto string visible para toda la clase:
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 ProyectoPIC16f883 { public partial class frmTarjeta : Form { string datoSerial; public frmTarjeta() { InitializeComponent(); }
En el CheckBox escribimos:
private void chkPuertoSerie_CheckedChanged(object sender, EventArgs e) { if (chkPuertoSerie.Checked) {try {if (!serialPort.IsOpen) //si el puerto esta cerrado { serialPort.Open(); } btnMandaByte.Enabled = true; btnRecibeAn0.Enabled = true; btnRecibeDatDig.Enabled = true; chkPuertoSerie.Text = "Puerto Abierto"; chkPuertoSerie.BackColor = Color.YellowGreen; } catch {MessageBox.Show("Algo anda mal con el puerto COM"); } } else {try {if (serialPort.IsOpen) { serialPort.Close(); chkPuertoSerie.BackColor = Color.Red; chkPuertoSerie.Text = "Puerto Cerrado"; btnMandaByte.Enabled = false; btnRecibeAn0.Enabled = false; btnRecibeDatDig.Enabled = false; } } catch { MessageBox.Show("Algo anda mal no pude cerrar el COM"); } }
142
143
Ahora podemos probar la comunicacin con el PIC, cuide no conectar la tierra del DB9 a un voltaje externo.
Al ejecutar puede comprobar como el Pic digitaliza el dato anlogo y los 8 bits de entrada al pulsar los botones en C#, tambin escribe en el puerto B del pic el valor del Numeric Up Down.
144
IMPORTANTE Trabajar con fuentes externas de voltaje y perifricos de la PC presenta un riesgo de quemar componentes de la tarjeta madre, se debe poner en comn la tierra de la PC con la fuente externa y tener mucho cuidado en que no entre voltaje por ese punto a la computadora, esto provocara un dao irreparable. Como consideracin inicial debemos respetar los colores en las lneas del protoboard: Azul = Tierra Rojo = Voltaje Ahora implementamos el circuito:
{
7
13 12
11 10
25 24 23 22 21 20 19 18 17 16 15 14
Para los bits S0,S1,S2, no tenemos acceso, dependiendo la tarjeta madre estos valores pueden ser: 000 111
C0 C1 C2 C3 C4 C5 C6 C7
Registro de Control
El circuito lucir de esta manera
OE
14 15 16 17 18 19 20 21 22 23 24 25
Resistencias 1 kohm
2 3 4 5 6 7 8 9 10 11 12 13
1 2 3 4 5 6 7 8 9 10
20 19 18 17 16 15 14 13 12 11
OE
Leds
74LS541
S3
S4 S5 S6 S7
D0
Resistencias 330 ohm
D7
Tierra
Importante El Bit S7 esta negado internamente, el dato que ingresemos ser invertido al entrar al registro.
+
5 Volts
Fuente
Microswitch
- +
145
El cable DB25 entra al circuito de esta manera: El canal del protoboard separa cada conector de cable plano, por un lado tenemos el bus de datos con la tierra y por el otro el registro de estatus .
Recuerde respetar los colores del protoboard: Lnea azul: Tierra Lnea roja: Voltaje
Buffer
Tierra D7
D0
Antes de conectar el protoboard a la PC probamos los las entradas del buffer, observe que por defecto sus salidas estn activadas, por lo tanto esta esperando una tierra en su entrada para apagar el led, tomamos cualquier cable largo y lo conectamos a tierra, el otro extremo lo posicionamos en cada entrada del buffer para comprobar como se apaga cada led. Una vez probado el protoboard verifique que no existan cables sueltos que puedan provocar cortos. Tambin use su multmetro para probar continuidad entre el cable DB25 y las entradas del buffer. Antes de prender la fuente que alimenta el protoboard observe el monitor de la PC, si nota un parpadeo al encenderla apague rpidamente la fuente o desconecte el cable, esto puede salvar su tarjeta madre, si no hay cambio todo esta bien conectado, en caso de apagarse el monitor y la PC lamento decirle que ha daado su tarjeta madre. Cuando las tarjetas se daan se debe a un choque de niveles de voltaje interno, en estos casos se queman integrados bsicos que pueden ser mas caros de reparar que comprar una tarjeta nueva. Considerando que su hardware externo esta listo vamos con la interfaz de la PC. El puerto paralelo requiere una librera para funcionar: inpout32.dll La descargamos desde: www.multitecnologia.com/inpout32.rar Ahora colocamos este archivo en la carpeta C:\Windows\System32\inpout32.dll Posiblemente se ocupe registrar en la ventana de ejecutar: Escribir: REGSVR32 c:\windows\system32\inpout32.dll Con nuestra interfaz lista nos vamos a VisualStudio y creamos un nuevo proyecto de windows forms.
146
Finalmente ejecutamos y al mover el scrollbar los leds deben cambiar su estado, para leer diferentes datos movemos los interruptores del microswitch y damos click en el btnLeerPuerto para actualizar. 147
ANEXOS
Cdigo de colores para resistencias
4N32
148
CAPA DE DATOS
CAPA DE NEGOCIO
CAPA DE PRESENTACIN
149
Ahora en lenguaje terrcola La capa de presentacin son los formularios, botones y controles con que interacta el usuario, el desarrollador que disea esta capa debe preocuparse por facilitar la navegacin del usuario, hacer atractivos los grficos, presentar la informacin de manera rpida y eficiente, etc. Esta metodologa permite que el equipo de trabajo avance en paralelo, es conveniente que una persona se encargue de interactuar con el cliente en cuestiones de diseo y la otra parte del equipo se enfoque a la parte lgica y de datos. La capa de negocio tiende a confundir en cuanto a su definicin, por lo regular asociamos este trmino con establecimientos comerciales, en este caso negocio se refiere a intercambio de informacin, tambin se le llama capa lgica y es donde reside realmente todo el modelado del sistema, es importante mencionar que aqu no existen formularios ni controles, todo son clases con diferentes tareas. Finalmente la capa de datos es la manera de separar los archivos fsicos como bases de datos, documentos xml o txt que almacenen la informacin, para quien disea la capa de negocio resulta completamente irrelevante cual es el fabricante de la base de datos ya que solo tiene que mandar sus objetos y esperar recibirlos sin preocuparse por las consultas o la conexin al servidor. En resumen, las capas nos facilitan el diseo de cualquier sistema y permiten reutilizar cdigo por bloques sacando mejor provecho a los objetos. Es importante que en nuestras soluciones de VisualStudio se definan las capas por medio de 3 proyectos, lgicamente la capa de presentacin es la nica que maneja formularios, mientras que la de negocio y datos son bibliotecas de clases. Por lo que hemos visto la capa de presentacin no tiene que ver con la capa datos, esto se refleja en las dependencias del proyecto. Comenzamos abriendo un proyecto del tipo Solution en VisualStudio, elegimos solucin en blanco. En esta solucin vamos a agrupar nuestras 3 capas. Lo nombramos SolucionMuestrasSensor En el explorador de soluciones nos aparece de esta manera:
150
Agregamos una carpeta dando click en el cono, la nombramos Proyectos Estando en la carpeta y dando click derecho elegimos agregar proyecto:
De nuevo damos click en la carpeta y agregamos otro proyecto del tipo Biblioteca de Clases, lo nombramos CapaNegocioSensores.
151
Nos queda:
Finalmente agregamos otro proyecto de tipo Biblioteca de Clases con el nombre: CapaDatosSensores.
Ahora vamos a crear la dependencia entre las capas: Damos click derecho en la carpeta References de nuestra capa de presentacin, elegimos agregar referencia.
152
Nos aparece esta ventana donde elegimos la capa de negocio en la pestaa de proyectos:
Ahora nuestra capa de presentacin puede acceder a todas las clases de la capa de negocio:
Repetimos el proceso con la capa de negocio y agregamos como referencia la capa de datos.
Nos queda:
153
Por lgica la capa de datos no depende de otras capas, es decir no tiene por que heredar de otras bibliotecas, esto creara una referencia circular que rompe con el concepto que buscamos sobre separar las tareas. En las capas de Negocio y Datos borramos las clases por defecto Class1.cs Empezamos con la capa de negocio, agregamos las siguientes clases: Muestra, ArrayListMuestras, Sensor. Para ahorrar tiempo las descargamos desde: www.multitecnologia.com/CapaNegocioSensores.rar Damos click derecho agregar elemento existente.
x x
Ahora para la capa de datos descargamos este archivo: www.multitecnologia.com/CapaDatosSensores.rar Siguiendo el mismo proceso agregamos estos 3 elementos existentes:
Elegimos las 3:
Cada una de estas clases se encarga de convertir en un archivo nuestro objeto sensor.
154
An nos falta algo En la capa de datos vamos a agregar dos referencias necesarias para crear la base de datos y poder conectarnos a ella:
Ambas se encuentran en la pestaa de los componentes COM. Las referencias son: Microsoft ActiveX Data Objects 2.8 Library Microsoft ADO Ext. 2.8 for DDL and Security
Otro detalle importante es que los tres proyectos deben ejecutarse para plataforma x86, para seleccionarlo nos vamos a: Proyecto/Propiedades/Generar.
Recuerde seleccionar cada proyecto en particular y abrir esta ventana para seleccionar X86, hacemos esto por que los componentes COM que acabamos de insertar son para esta plataforma. 155
Para que se compile el namespace en cada clase debe tener el mismo nombre que el proyecto, en el caso de la capa de datos las tres clases:
En la capa de negocio las clases tambin deben tener el mismo nombre de proyecto y namespace.
Volvemos a la capa de presentacin y en nuestro formulario arrastramos los siguientes controles: Form Name: frmSensores Text. Generacin de archivos para muestras Button Name: btnCrearMuestra,Text: Crear Muestra DataGridView Name: dGridViewMuestras Columns: Coleccin Hora, Lectura
Button Name: btnGrabarTxt, Text: Grabar Muestras en Texto Button Name: btnGrabarXml, Text: Grabar Muestras en XML Button Name: btnGrabarDB, Text: Grabar Muestras en Base de Datos 156
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 CapaNegocioSensores; //importamos la capa con las clases de negocio namespace CapaPresentacionSensores { public partial class frmSensores : Form {//creamos nuestro objeto sensor con mbito para toda la clase Sensor nuestroSensor = new Sensor(); //con este objeto random obtenemos valores aleatorios en la lectura Random lecturaSensor = new Random(); public frmSensores() { InitializeComponent(); }
Para el btnCrearMuestra:
private void btnCrearMuestra_Click(object sender, EventArgs e) {//creamos una instancia de muestra Muestra m = new Muestra(); m.hora = DateTime.Now.ToString();//guardamos la hora m.lectura = lecturaSensor.Next(255); //guardamos un entero aleatorio //agrega una muestra a nuestro objeto sensor nuestroSensor.agregarMuestra(m); //Imprime la muestra en el datagrid dGridViewMuestras.Rows.Insert(0, m.hora, m.lectura); }
157
Respetando todos estos detalles no debe existir problema para ejecutar, solo creamos algunas muestras con el botn crear muestra y convertimos a diferentes formatos de archivo nuestro objeto Sensor.
158
Para cada caso nos pide el lugar donde vamos a guardar el archivo y nos confirma cuando se gener correctamente.
159
//lo inicializamos con -1 para simbolizar que no ha sido llenado. private int _Lectura = -1; //_Lectura es entero por que las conversiones A-D siempre vienen en enteros public int lectura { get { return _Lectura; } set {_Lectura = value; } } //la propiedad indice es privada,solo con el mtodo asignaIndice se puede modificar private int _Indice; public int indice { get {return _Indice; } //no se ocupa un set por que no deseamos que se escriba este valor directamente } //este mtodo permite recibir la propiedad .count del arraylist public void asignaIndice(int indice) { _Indice = indice; } } }
Clase ArrayListMuestras.cs
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Collections; //Nos permite usar un ArrayList namespace CapaNegocioSensores { public class ArrayListMuestras:ArrayList { //con este mtodo agregamos una instancia de muestra a nuestro ArrayList public void agregarMuestra(Muestra m) { //le mandamos el indice como propiedad a la muestra m.asignaIndice(this.Count); this.Add(m); } //este mtodo nos trae todo el arreglo completo de muestras public ArrayListMuestras traerMuestras() { return this; } //este mtodo recibe el ndice del arreglo y regresa la muestra con ese indice public Muestra traeMuestra(int Indice) { foreach (Muestra m in this) //busca en todas las muestras de esta coleccin { if (m.indice == Indice) { return m; } } return null; } } }
160
Clase Sensor.cs
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Data; //nos permite instanciar DataSet using CapaDatosSensores; namespace CapaNegocioSensores { public class Sensor: ArrayListMuestras { //recordemos que todo el modelado y la lgica de la capa de negocio es //independiente de los datos, nuestras Clases: Sensor, Muestra, ArrayListMuestra //no son instanciables en esta capa, la capa de Negocio depende de la capa de Datos //No viceversa private string _Nombre="Sin Nombre"; //valor inicial public string Nombre { get { return _Nombre; } set { _Nombre = value; } } private string _Tag = "Sin Tag"; //valor inicial public string Tag { get { return _Tag; } set { _Tag = value; } } //esta funcin nos convierte nuestro arraylistMuestras (Indice, Hora, Lectura) en //un DataSet(tabla) que es fcil de mandar a otra capa con los datos ordenados private DataSet ConversionDataset() { DataSet tablaMuestras = new DataSet(); DataTable tabla = new DataTable(); tablaMuestras.Tables.Add(tabla); //agregamos las tres columnas de nuestra tabla: Indice, Hora, Lectura tablaMuestras.Tables[0].TableName = "Muestras"; //nombre de la tabla tablaMuestras.Tables[0].Columns.Add("Indice"); tablaMuestras.Tables[0].Columns.Add("Hora"); tablaMuestras.Tables[0].Columns.Add("Lectura"); foreach (Muestra m in this) { DataRow linea = tablaMuestras.Tables[0].NewRow(); linea[0] = m.indice.ToString(); //columna 0 de la lnea //columna 1 de la lnea linea[1] = m.hora; linea[2] = m.lectura.ToString();//columna 2 de la lnea tablaMuestras.Tables[0].Rows.Add(linea); } return tablaMuestras; }
161
//estas funcines son el intermediario entre la presentacin y capa de datos //recibimos la ruta y debemos mandar la coleccin de muestras en un dataSet public void EscribirTxt( string ruta) { //creamos nuestra instancia de la capa de datos y mandamos //la ruta al constructor como valor inicial EscrituraMuestrasTxt DatosTxt = new EscrituraMuestrasTxt(); if (ruta != null) //si nos llega una ruta vlida { //ahora convertimos nuestra tabla de muestras en un Dataset DataSet TMuestras = ConversionDataset(); // mandamos todo a la capa de datos para que se convierta en archivo txt DatosTxt.EscribeTxt(ruta, this.Nombre, this.Tag, TMuestras); } else { throw new ArgumentException("Existe un error en la coleccin o la ruta"); } } public void EscribirXml(string ruta) { EscrituraMuestrasXml DatosXml = new EscrituraMuestrasXml(); if (ruta != null) //si nos llega una ruta vlida { //nos convierte el arraylist en Dataset DataSet TMuestras = ConversionDataset(); // mandamos todo a la capa de datos para que se convierta en archivo XML DatosXml.EscribeXml(ruta, this.Nombre, this.Tag, TMuestras); } else { throw new ArgumentException("Existe un error en la coleccin o la ruta"); } } public void EscribirBaseDatos(string ruta) { EscrituraMuestrasBaseDatos DatosBD = new EscrituraMuestrasBaseDatos(); if (ruta != null) //si nos llega una ruta vlida { //nos convierte el arraylist en Dataset DataSet TMuestras = ConversionDataset(); // mandamos todo a la capa de datos para que se convierta en archivo MDB DatosBD.EscribeBD(ruta, this.Nombre, this.Tag, TMuestras); } else { throw new ArgumentException("Existe un error en la coleccin o la ruta"); } } } }
162
Clase EscrituraMuestrasBaseDatos.cs
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Text; using System.IO; using ADOX; using System.Data.OleDb; namespace CapaDatosSensores { //con esta clase convertimos nuestro Dataset en una Base de datos Access public class EscrituraMuestrasBaseDatos { public void EscribeBD(string ruta, string nombreSensor, string tagSensor, DataSet Muestras) { ADOX.CatalogClass cat = new ADOX.CatalogClass(); cat.Create("Provider=Microsoft.Jet.OLEDB.4.0; Data Source=" + ruta + ";" + "Jet OLEDB:Engine Type=5"); cat = null; string nombreTabla = nombreSensor; creaTabla(ruta,nombreTabla); //creamos las columnas de la tabla insertaDatos(ruta,nombreTabla, Muestras);//insertamos los valores del Dataset } public void creaTabla(string ruta, string nombreTabla) {//ahora nos conectamos para insertar las columnas con sus tipos de datos string conex = "Provider = Microsoft.Jet.OLEDB.4.0;" + @"Data Source = " + ruta + ";"; OleDbConnection con; string crear = "CREATE TABLE " + nombreTabla + " (Indice INT, Hora VARCHAR(50), Lectura INT);"; con = new OleDbConnection(conex); OleDbCommand cmd = new OleDbCommand(crear, con); con.Open(); cmd.ExecuteNonQuery();//se ejecuta la consulta //cerramos conexin con.Close(); } } public void insertaDatos(string ruta,string nombreTabla, DataSet Muestras) {// nos conectamos para insertar las columnas con sus tipos de datos string conex = "Provider = Microsoft.Jet.OLEDB.4.0;" + @"Data Source = + ruta + ";"; OleDbConnection con; string inserta; con = new OleDbConnection(conex); con.Open(); //abrimos la conexin con la base de datos //con un ciclo vamos insertando cada lnea de la tabla for (int i = 0; i < Muestras.Tables[0].Rows.Count; i++)//lneas { int ID = Convert.ToInt32(Muestras.Tables[0].Rows[i][0]); string Hora = Muestras.Tables[0].Rows[i][1].ToString(); int Lectura = Convert.ToInt32( Muestras.Tables[0].Rows[i][2]); inserta = "INSERT INTO " + nombreTabla + " VALUES (" + ID + ",' + Hora + "'," + Lectura + ")"; OleDbCommand cmd = new OleDbCommand(inserta, con); cmd.ExecuteNonQuery();//se ejecuta la consulta } //cerramos conexin con.Close(); } } }
163
Clase EscrituraMuestrasTxt.cs
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Collections; using System.Data; using System.IO; namespace CapaDatosSensores { //Con esta Clase convertimos un DataSet de las Muestras en un archivo TXT public class EscrituraMuestrasTxt { //La capa de datos solo necesita el nombre, tag y tabla de muestras (Dataset) //para crear un archivo, no le interesa como fueron modelados //los objetos en la capa de negocio public void EscribeTxt(string ruta, string nombreSensor, string tagSensor, DataSet Muestras) { String[] texto; //en este arreglo almacenamos toda la tabla texto = new String[Muestras.Tables[0].Rows.Count + 1]; //Rellenamos la cabecera del archivo texto[0] = "Sensor: " + nombreSensor + " Tag: " + tagSensor + " Estructura: "; //creamos las tres columnas con el encabezado: Indice, Hora, Lectura for (int i = 0; i < Muestras.Tables[0].Columns.Count; i++) { texto[0] += Muestras.Tables[0].Columns[i].ColumnName + ";"; } //Rellenamos los valores de la tabla separando por lneas y comillas String linea; for (int i = 0; i < Muestras.Tables[0].Rows.Count; i++)//lneas { linea = String.Empty; //limpiamos la lnea para reutilizarla for (int j = 0; j < Muestras.Tables[0].Columns.Count; j++)//Columnas { linea += Muestras.Tables[0].Rows[i][j].ToString() + ";"; } texto[i + 1] = linea; //se agrega al arreglo } //Creamos el archivo try { File.WriteAllLines(ruta, texto); } catch { throw new ArgumentException("No pude crear el archivo, esta vaco el DataSet"); } } } }
164
Clase EscrituraMuestrasXml.cs using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Data; using System.Xml; namespace CapaDatosSensores { //En esta clase convertimos nuestro dataset en un archivo XML en forma de rbol public class EscrituraMuestrasXml { public void EscribeXml(string ruta, string nombreSensor, string tagSensor, DataSet Muestras) { //eliminamos las reglas del Dataset para crear el xml Muestras.EnforceConstraints = false; //cambiamos su nombre antes de mandarlo al XML Muestras.DataSetName = "MuestrasSensor"; //grabamos la tabla simplemente asignando el dataset, // C# se encarga de acomodar los datos en forma de rbol XML XmlDataDocument xmldoc = new XmlDataDocument(Muestras); XmlNode NodoRaiz = xmldoc.FirstChild; //localizamos la raz del XML //creamos un nuevo nodo para los datos que faltan: Nombre, Tag XmlNode nuevoNodo = xmldoc.CreateNode(XmlNodeType.Element, "Sensor", null); //creamos un par de atributos con el nombre y tag que nos manda la capa de negocio XmlAttribute AtributoNombre = xmldoc.CreateAttribute("Nombre"); AtributoNombre.Value = nombreSensor; XmlAttribute AtributoTag = xmldoc.CreateAttribute("Tag"); AtributoTag.Value = tagSensor; //ahora agregamos esos atributos al nodo recin creado nuevoNodo.Attributes.Append(AtributoNombre); nuevoNodo.Attributes.Append(AtributoTag); //finalmente situamos ese nuevo nodo en la raz NodoRaiz.AppendChild(nuevoNodo); //guardamos nuestro documento xmldoc.Save(ruta ); } } }
En este ejercicio practicamos el concepto de patrones de diseo por capas y la generacin de archivos a partir de un objeto, es importante que aplique esta metodologa para sacar real provecho a C#.NET.
165
En caso de ocupar ms de dos horas para las pruebas se reinicia el servidor o la PC. En nuestro panel de usuario descargamos KepServer y ClientAce. ClientAce nos permite conectarnos desde C#.NET a nuestro servidor.
166
Una vez descargados comenzamos la instalacin de KepServer cuidando los siguientes detalles:
Debemos seleccionar todos los modelos de PLC a los que deseamos conectarnos, las casillas que no sean activadas no estn incluidas en la instalacin. En nuestro caso debemos activar todos los drivers para Siemens, Allen-Bradley y AutomationDirect. Continuamos los pasos hasta finalizar.
Al instalar nuestro servidor y activarlo obtenemos un panel de monitoreo como el mostrado, si usted tiene alguna simulacin activada posiblemente vea ms datos en la tabla.
En Kepserver los datos de acceso se organizan por medio de canales, cada canal tiene diferentes dispositivos que agrupan nuestros datos. Ahora con nuestro servidor instalado vamos a preparar los PLC's para mandar sus datos.
167
Para establecer comunicacin con el PLC nos vamos al men principal: Connect
Elegimos COM1, si estamos usando un convertidor USB-RS232 y se registro un COM mayor a 2 tenemos que irnos a las propiedades de ese puerto en Windows y cambiarle el ID a 1 o 2.
Antes debemos tener nuestro PLC encendido con el cable conectado al puerto COM de la PC. Al aparecer esta ventana damos click en aadir.
168
Protocolo: K Sequence
Nos queda
Al seleccionarlo es importante tener el PLC en estado de terminal o nos aparecer el siguiente mensaje.
Cuando se crea con xito la conexin, DirectSoft compara las versiones del programa entre PLC y pantalla, posteriormente salta una ventana donde nos pregunta si deseamos cargar a pantalla el programa grabado en el equipo o viceversa.
Elegimos usar Use Disk para comenzar con nuestro proyecto en blanco. Para empezar a crear el diagrama DirectSoft debe estar en modo Program.
Vamos a insertar 3 contactos normalmente abiertos con nuestras entradas digitales y asignaremos la salida fsica Y0. En el PLC DL06 las entradas se encuentran en los registros X y las salidas en los registros Y. Para ver nuestra barra de dispositivo elegimos Edit Mode: ON
169
Ahora se muestran los elementos en la parte inferior. Vamos a arrastrar 3 contactos normalmente abiertos: F2 Nos aparece esta ventana:
Damos click en la lupa: Por lo pronto solo Le asignamos su direccin (X0) y nickname (encendido) Nos queda
Para la salida nos vamos al botn de bobinas manteniendo seleccionado el final del diagrama (NOP).
170
Nos aparece de esta manera pero falta la direccin fsica, de nuevo click en la lupa. Elegimos Y0 con el nickname salida.
Para terminar debemos indicar que nuestro diagrama ha terminado, nos vamos al final de la siguiente lnea. Con F5 asignamos un comando END
Con el botn de Status accionado podemos cerrar y ver se activan los contactos en color azul.
Muy bien, ahora nos falta dar de alta estas direcciones Tags en el servidor IPC (KepServer). Para esto nos vamos men y en archivo elegimos exportar la documentacin de los elementos.
171
Elegimos el mismo protocolo que se uso para programar el PLC: K Sequence No olvidemos habilitar el diagnostico.
Los datos del COM se mantienen con las mismas caractersticas anteriores.
Nos queda:
Ahora agregamos el dispositivo, damos un nombre relativo a la Marca. Elegimos nuestro modelo:
172
Mantenemos el ID=1
Importamos nuestro archivo csv generado anteriormente con DirectSoft32. Continuamos hasta finalizar la conexin: Al principio no aparece nada
Damos click derecho en el dispositivo y en la ventana elegimos la pestaa Database Creation Autocreate.
Ahora al mover nuestros interruptores X0, X1 y X2 del PLC podemos ver como cambian su valor. Con este ejercicio comprobamos que es posible acceder a los datos del PLC DL06 por medio de KepServer. 173
Nos aparece otro programa de nombre HWConfig, aqu configuramos todo el hardware para que coincida con nuestro dispositivo real.
174
En caso de que nuestra versin de Simatic no se encuentre actualizada debemos conectarnos a Internet y descargar todos los modelos actuales:
Cuando se ocupan actualizaciones se crea una lista para descargar y Simatic se encarga de poner al da todo el entorno de programacin.
175
Ahora seleccionamos el 2 y elegimos el CPU 315-2FJ14-0AB0, posiblemente aparezca la ventana de configuracin IP que se muestra, si tenemos el PLC conectado directamente a la PC (sin router) podemos dejar la configuracin mostrada con la IP del PLC 192.168.0.1, por lgica nuestra PC debe tener cualquier otra IP que este en el mismo segmento y que no choque con la del PLC ejemplo: 192.168.0.254.
Continuando con nuestro bastidor nos saltamos hasta el slot 4 dejando el 3 vaco ya que solo se usa en aplicaciones complejas. Arrastramos la tarjeta: DI16/DO16xDC24V al slot 4
176
Para probar la sincrona con nuestro PLC nos vamos al men y elegimos:
Ahora nos pide una confirmacin de la IP del PLC que vamos a asignar.
177
Por defecto nos aparece el bloque OB1 donde vamos a crear nuestro programa en lenguaje de escalera (KOP).
Al elegir KOP y Aceptar nos aparece Step7 para programar nuestro PLC recin configurado.
178
Si no existen problemas de comunicacin podemos probar con los interruptores del PLC. Ahora nos vamos a KepServer para dar de alta nuestro S7-300 El procedimiento para agregar un Tag proveniente del PLC es el siguiente: Dando click derecho elegimos agregar canal: Como nos vamos a conectar por Ethernet a nuestro S7-300 elegimos: Siemens TCPIP/Ethernet y activamos la casilla de diagnostico para localizar errores fcilmente.
179
En el adaptador de red podemos elegir Default y en la siguiente ventana aceptamos la opcin predeterminada.
Finalizamos la conexin...
Al terminar nos queda un canal de comunicacin listo para dar de alta los PLC's.
Ahora elegimos nuestro PLC S7-300 Damos Click en agregar dispositivos y asignamos un nombre relacionado con el rea que se va a automatizar o la marca del equipo:
En esta parte es bsico elegir la direccin IP del PLC que se le asigno desde Simatic al momento de configurar el CPU.
180
Si deseamos comprobar que nuestro PLC ya tiene una IP podemos hacer un PING desde la ventana de comandos de Windows: teclamos cmd
Y ahora escribimos la IP de este ejemplo: ping 192.168.0.1 El PLC debe responder como cualquier dispositivo que maneje TCP/IP.
Ahora nos queda nuestro canal apuntando a un dispositivo en particular, solo nos resta asignarle los tags que vamos a monitorear.
181
Para asignar cada Tag no es necesario importar una Si desconocemos la localidad del Tag la biblioteca de smbolos, solo escribimos la direccin podemos obtener de la tabla de smbolos del PLC: I1.0 del programa HWConfig (Simatic).
Para probar que realmente tenemos acceso a nuestro Tag abrimos el Quick Client
La ventana nos muestra otros accesos a memoria del PLC y propiedades del canal. Nos vamos a Channel1.EquipoSiemens y nuestro Tag debe aparecer con calidad Good en caso contrario debemos reconfigurar la conexin, checar el cableado y que el PLC este operando.
182
Para una entrada analgica solo escribimos la direccin del Tag (IW276) para tener acceso al dato tipo WORD. Si no conocemos el tipo de dato elegimos Default.
Ahora al activar al QuickClient y variar los potencimetros del PLC podemos ver los cambios en la variable.
IMPORTANTE: Observe que no fue necesario programar el PLC para tener acceso a sus datos. Con KepServer manejando nuestros Tags y comunicndose con los dispositivos ya estamos listos para programar el cliente en C#.NET.
Para trabajar en este ejemplo debemos tener a la mano los controles del ClientAce en la barra e herramientas.
Importante: Si a usted no le aparece ClienAceDa_Junction en el cuadro de herramientas lo debe agregar manualmente siguiendo estos pasos...(siguiente hoja).
Al darle click y cerrar estas ventanas nos debe aparecer en el cuadro de herramientas
Ahora ocupamos agregar otra dll al proyecto, nos vamos a la carpeta de referencias y agregamos el archivo Kepware.ClientACE.OpcClient.dll
Se debe ver de esta forma, esta librera no es un componente del cuadro de herramientas. 184
Para evitar problemas a la hora de compilar en algunas mquinas con Windows 7 vamos a desactivar el LoaderLock siguiendo estos pasos: Depurar-> Excepciones->Managed Degubbed assistants-->Loaderlock (desactivarlo).
En nuestro frmCliente arrastramos y configuramos los siguientes controles: Formulario Name: frmCliente, Text: Cliente para KepServer CheckBox Name: chkConectarse, Text: Conectarse a KepServer, Backcolor: Red Label Name: lblTags, Text: Escriba la direccin del Tag TextBox Name: txtTag, Enabled: False Button Name: btnRegistrarTag, Enabled: False, Backcolor: Red
DataGridView Name:dGridTags Columns: 1 columna con Name: DireccinTag HeaderText: Direccin Tag
Agregamos el componente clientAceDA_Junction1 al formulario y conservamos su nombre. Agregamos una columna al dGridTags como se muestra.
185
186
else { //nos desconectamos del servidor daServerMgt.Disconnect(); //cambiamos los grficos para simbolizar la desconexin btnRegistrarTag.Enabled = false; txtTag.Enabled = false; dGridTags.Enabled = false; chkConectarse.Text = "Conectarse a KepServer"; txtTag.Text = ""; chkConectarse.BackColor = Color.Red; btnRegistrarTag.BackColor = Color.Red;
} }
Creamos una funcin para llenar de manera temporal el arreglo para las 10 Tags y evitar errores posteriores.
//esta funcin crea 10 instancias vacas para nuestro arreglo //ItemIdentifier[] itemIdent = new ItemIdentifier[10]; //al momento de registrar cada una se le cambia el nombre, la idea es llenar //el arreglo de manera temporal para no provocar error con valores nulos private void CreaInstancias() { for (int x = 0; x <= 9; x++) { itemIdent[x] = new ItemIdentifier(); itemIdent[x].ItemName = ""; itemIdent[x].ClientHandle = x; itemIdent[x].DataType = null; } }
Ahora otra funcin para suscribir los datos desde nuestro formulario.
private void SuscribirDatos( string nombreTag) { if (numTags < 10) { txtTag.Text = ""; //no importa si se registra o no, el texto del Tag se borra //parmetros de la conexin int clientSubscriptionHandle = 1; bool active = true; int updateRate = 1000; float deadBand = 0.0f; itemIdent[numTags].ItemName = nombreTag; //actualizamos el nombre del Tag int revisedUpdateRate; try { //este mtodo da de alta el grupo de Tags daServerMgt.Subscribe(clientSubscriptionHandle, active, updateRate, out revisedUpdateRate, deadBand, ref itemIdent, out activeServerSubscriptionHandle); if (itemIdent[numTags].ResultID.Succeeded == false) { MessageBox.Show("Falla: " + itemIdent[numTags].ItemName.ToString()); } else {//si llega a este punto el registro fue exitoso dGridTags.Rows.Insert(0, itemIdent[numTags].ItemName.ToString()); numTags++; //incrementamos el identificador del arreglo } }
187
catch (Exception ex) { MessageBox.Show("Fallo: " + ex.Message.ToString()); } }//si el numero de Tags no pasa de 10 else {MessageBox.Show("solo podemos registrar 10 Tags"); } }
Creamos la funcin DataChanged que acta como interrupcin cada vez que algun Tag registrado sufre algn cambio.
//Este mtodo se dispara ante cualquier cambio en los tags registrados private void DataChanged(int clientSubscription, bool allQualitiesGood, bool noErrors, ItemValueCallback[] itemValues) { try //busca en todos los tags registrados para encontrar cual tiene un cambio { foreach (ItemValueCallback itemValue in itemValues) { if (itemValue.ResultID.Succeeded) { //creamos una instancia del formulario para la ventana del Tag frmVentanaDispositivo ventana = new frmVentanaDispositivo(); //mandamos 4 parmetros al mtodo publico en la clase frmVentanaDispositivo(); //public void parametrosTag(string direccion,string valor, //string calidad, string tiempo) ventana.parametrosTag( itemValue.ClientHandle.ToString(), itemValue.Value.ToString(), itemValue.Quality.Name.ToString(), itemValue.TimeStamp.ToString()); ventana.Show(); } } } catch (Exception ex) { MessageBox.Show("Ocurri un error, la razn es ... ", ex.ToString()); } }
En su cdigo agregamos un mtodo pblico que nos permita mandarle datos desde frmCliente.
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 PruebasKepserver { public partial class frmVentanaDispositivo : Form { public frmVentanaDispositivo() { InitializeComponent(); } public void parametrosTag(string direccion,string valor, string calidad, string tiempo) { lblMensaje.Text = "La entrada: " + direccion + " Tiene un valor: " + valor; if (valor == "True") { this.BackColor = Color.YellowGreen; } else { this.BackColor = Color.Red; } } } }
Al ejecutar nos conectamos al servidor y registramos los Tags con el mismo nombre que tienen en la pantalla de KepServer.
Para el ejemplo de este curso los Tags grabados en el PLC Koyo DL06 y KepServer son: Channel1.PLCAutomationDirect.X.accionamiento Channel1.PLCAutomationDirect.X.confirmacin Channel1.PLCAutomationDirect.X.encendido Es necesario que el nombre sea exactamente el mismo, respetando acentos y maysculas.
189
Por ser una versin Demo de ClientAce nos salta esta ventana:
Ahora cuando se va registrando cada nuevo Tag salta la ventana con los valores nuevos.
Si usted mueve el interruptor del Tag registrado debe observar como se crea otra ventana con los datos.
Con este ejercicio comprobamos que es posible conectarnos a un PLC desde C#.NET aplicando el software de Kepware.
Posiblemente ocupe actualizar VisualStudio con los SDK, descargue los marcados dependiendo su sistema operativo e idioma.
190
Creamos un nuevo proyecto tipo Smart Device y seleccionamos Windows Mobile 6 Standard SDK.
Por defecto nos aparece un SmartPhone rectangular, para cambiarlo usamos la propiedad FormFactor: Windows Mobile 6 Standard Landscape QVGA
191
Aparte agregamos otro formulario con las mismas caractersticas: Le asignamos el nombre: frmPlanta.cs
Nos queda: Nuestro proyecto solamente manejar dos formularios, en el primero vamos a monitorear una tabla de alarmas y en el segundo activaremos 4 motores aireadores. Vamos a realizar una prueba de comunicacin: 1.- Conectamos nuestro SmartPhone . o PDA a la PC por su cable USB. 2.- Ejecutamos nuestro proyecto A continuacin salta una ventana donde aparecen las opciones de compilacin:
Si nuestro Smartphone esta conectado elegimos la opcin: Windows Mobile 6 Standard Device, en caso contrario elegimos el emulador mas parecido al dispositivo real. Los emuladores permiten probar el cdigo sin ocupar un dispositivo real, sin embargo no cubren todas las funciones, en este caso de los puertos Bluetooth que aplicaremos en este curso. El ejercicio que vamos a codificar necesita un dispositivo real con puerto Bluetooth y al menos un puerto COM virtual. Si fue posible cargar los formularios a nuestro dispositivo real estamos listos para agregar el cdigo. 192
Una de las diferencias que tienen los proyectos para mviles es que la organizacin de las dependencias es diferente, si ocupamos implementar capas de negocio y datos las vamos a incorporar como carpetas en el mismo proyecto. Dando click derecho sobre el proyecto agregamos una carpeta como se muestra, la nombramos Capa Negocio. Ahora dando click derecho sobre la carpeta CapaNegocio agregamos 3 nuevas clases con los nombres: El cdigo para la clase Alarmas.cs nos define 3 propiedades de tipo string donde guardaremos mensajes de alarmas. Es importante que el namespace tenga el mismo nombre que el proyecto: MonitoreoSmartPhone
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace MonitoreoSmartPhone { class Alarmas {//en esta propiedad guardamos la hora de la Alarma private string _hora; public string Hora { get { return _hora; } set { _hora = value; } } //Esta propiedad guarda el conceptode la Alarma //Ejemplo: "Sobrecalentamiento caldera 5A" private string _concepto; public string Concepto { get { return _concepto; } set { _concepto = value; } } //En esta propiedad se guarda la Accin recomendable para arreglar la //falla para facilitar la operacin y estandarizar el proceso // Ejemplo: "Ajustar el control PID" private string _accin; public string Accin { get { return _accin; } set { _accin = value; } } } }
193
En la clase AlarmasArrayList.cs guardamos la coleccin de objetos alarma y creamos dos mtodos, uno para agregar cada mensaje y otro para crear una tabla de datos que posteriormente se incrustar en un Datagrid del dispositivo mobil.
using System; using System.Linq; using System.Collections.Generic; Es importante que el namespace tenga el using System.ComponentModel; mismo nombre que el proyecto: using System.Data; MonitoreoSmartPhone using System.Text; using System.Collections; namespace MonitoreoSmartPhone Recuerde que heredamos de Arraylist y debe class AlarmasArrayList:ArrayList { estar incorporado System.Collections { //este mtodo crea el arreglo de alarmas public void agregaAlarma(Alarmas alarma) this.Add(alarma); { } //este mtodo crea una tabla a partir del arraylist de alarmas public DataTable TraeTabla() DataSet tablaMuestras = new DataSet(); { DataTable tabla = new DataTable(); tablaMuestras.Tables.Add(tabla); //nombre de la tabla tablaMuestras.Tables[0].TableName = "Alarmas"; //agregamos las tres columnas de nuestra tabla: tablaMuestras.Tables[0].Columns.Add("Hora"); tablaMuestras.Tables[0].Columns.Add("Alarma"); tablaMuestras.Tables[0].Columns.Add("Accion"); //llenamos la tabla con cada objeto Alarma de nuestro Arraylist foreach (Alarmas a in this) DataRow linea = tablaMuestras.Tables[0].NewRow(); { linea[0] = a.Hora; linea[1] = a.Concepto; linea[2] = a.Accin; tablaMuestras.Tables[0].Rows.Add(linea); } //nos regresa una tabla ordenada con todas las alarmas para poder //incrustarla en el DataGrid return tablaMuestras.Tables[0]; } } }
Finalmente creamos la clase Dispositivos.cs, en ella guardamos el estado actual de 4 motores aireadores que se activarn en la pantalla mvil.
using System; using System.Linq; using System.Collections.Generic; using System.Text; namespace MonitoreoSmartPhone { //en esta clase guardamos el estado actual de los dispositivos class Dispositivos private bool _activaAireador1=false; { public bool ActivaAireador1 { get { return _activaAireador1; } set { _activaAireador1 = value; } }
194
private bool _activaAireador2 = false; public bool ActivaAireador2 { get { return _activaAireador2; } set { _activaAireador2 = value; } } private bool _activaAireador3 = false; public bool ActivaAireador3 { get { return _activaAireador3; } set { _activaAireador3 = value; } } private bool _activaAireador4 = false; public bool ActivaAireador4 { get { return _activaAireador4; } set { _activaAireador4 = value; } } } }
Ahora en nuestro frmPrincipal modificamos la resolucin y deshabilitamos la propiedad skin donde aparece el fondo de los botones. El SmartPhone aplicado en este ejercicio es el Sony Erickson modelo Aspen, sin embargo el cdigo tambin puede funcionar con PDA's con windows mobile de versiones anteriores. Para este modelo la resolucin de pantalla es de 320x240 sin embargo al momento de cargar la aplicacin los controles se ven mas chicos, para arreglarlo cambiamos el pixelaje de nuestros formularios a 430x 240. Agregamos los siguientes controles y modificamos las propiedades. DataGrid Name: dGridAlarmas CheckBox Name: chkPuertoSerie Text: Abrir Puerto Serie Label Name: lblPuerto Text: Msg TextBox Name: txtDatoSerie
mainMenu1 viene por defecto
SerialPort Name: serialPort 9,600 baudios, databits 8, paridad None, para este Smartphone seleccionamos el COM0 por Blueetooth.
195
Es importante conocer que este Datagrid para mviles es diferente al DatagridView de las aplicaciones de escritorio, en especial se encuentra muy limitado en sus mtodos ya que no es posible insertar lneas paso por paso, debemos hacerlo por medio de una tabla. En estos pasos vamos a configurarlo para Mapear una tabla con tres columnas: Hora, Alarma, Accin. Configuramos el Datagrid de la siguiente forma: En el dataGridTableStyle escribimos Alarmas en la propiedad MappingName. A la propiedad GridColumnStyles agregamos 3 columnas con las siguientes caractersticas:
namespace MonitoreoSmartPhone { public partial class frmPrincipal : Form { AlarmasArrayList arrayAlarmas = new AlarmasArrayList(); Dispositivos aireadores = new Dispositivos(); string datoSerial; public frmPrincipal() { InitializeComponent(); }
Para instertar bien los datos es necesario que los nombres del mapeo coincidan con la tabla que se insertar a futuro.
196
197
private void TextoRecibido(object sender, EventArgs e) { txtDatoSerie.Text = datoSerial; analisisCadena(datoSerial); } //creamos este mtodo publico para recibir valores //desde el otro formulario de dispositivos public void comandoActivacion(CheckBox chk) { //al cambiar de formualrio se puede cerrar el puerto, por eso se vuelve a abrir if (!serialPort.IsOpen) { serialPort.Open(); } //nos manda el valor del ChkAireador elegido serialPort.Write(chk.Name.ToString() + " : " + chk.Checked.ToString() + "Fin"); }
private void menuItemDispositivos_Click(object sender, EventArgs e) { //Abrimos el otro formulario frmPlanta planta = new frmPlanta(); planta.Show(); } private void menuItemActualizaTabla_Click(object sender, EventArgs e) { //actualizamos el dataGrid con el mtodo TraeTabla DataTable tabla = arrayAlarmas.TraeTabla(); //tabla: trae los valores organizados en 3 columnas: Hora, Alarma, Accin dGridAlarmas.DataSource = tabla; } PictureBox En la propiedad Image y SizeMode asignar a todos: aireador_OFF_small.jpg SizeMode: StretchImage Name: picBox1 Name: picBox2 Name: picBox3 Name: picBox4 CheckBox Name: chkAireador1 Name: chkAireador2 Name: chkAireador3 Name: chkAireador4 Text: Aireador 1 Text: Aireador 2 Text: Aireador 3 Text: Aireador 4
A nuestros 4 controles CheckBox les agregamos un mtodo compartido en su evento Click, lo nombramos AireadorElegido.
using System.ComponentModel; using System.Data; using System.Drawing; using System.Text; using System.Windows.Forms; namespace MonitoreoSmartPhone { public partial class frmPlanta : Form { frmPrincipal principal = new frmPrincipal(); public frmPlanta() { InitializeComponent(); } //con este mtodo cambiamos el grfico del dispositivo //y mandamos el aviso al otro formulario private void AireadorElegido(object sender, EventArgs e) { string ruta = System.IO.Path.GetDirectoryName( System.Reflection.Assembly.GetExecutingAssembly().GetName().CodeBase); ruta = ruta.Replace("file:\\", ""); CheckBox check = ( CheckBox)sender; principal.comandoActivacion(check); if (check.Checked) //se activa la casilla { switch (check.Text) { case "Aireador 1": picBox1.Image = new System.Drawing.Bitmap(ruta + @"\aireador_ON_small.jpg"); break; case "Aireador 2": picBox2.Image = new System.Drawing.Bitmap(ruta + @"\aireador_ON_small.jpg"); break; case "Aireador 3": picBox3.Image = new System.Drawing.Bitmap(ruta + @"\aireador_ON_small.jpg"); break; case "Aireador 4": picBox4.Image = new System.Drawing.Bitmap(ruta + @"\aireador_ON_small.jpg"); break; } } else // se desactiva la casilla { switch (check.Text) {
199
case "Aireador 1": picBox1.Image = new System.Drawing.Bitmap(ruta break; case "Aireador 2": picBox2.Image = new System.Drawing.Bitmap(ruta + break; case "Aireador 3": picBox3.Image = new System.Drawing.Bitmap(ruta + break; case "Aireador 4": picBox4.Image = new System.Drawing.Bitmap(ruta + break; } } }
+ @"\aireador_OFF_small.jpg");
@"\aireador_OFF_small.jpg");
@"\aireador_OFF_small.jpg");
@"\aireador_OFF_small.jpg");
Las imgenes que descargamos contienen el aireador en estado ON y OFF. Para que el dispositivo pueda cargarlas en tiempo de ejecucin debemos guardarla en los archivos de programa del SmartPhone o PDA, en este caso no tenemos la carpeta Bin/Debug.
Hasta ahora ya tenemos el cdigo para el Smartphone, pero nos falta sincronizarlo por medio de un puerto virtual Bluetooth y otra aplicacin de escritorio que no mande y reciba nuestros comandos. IMPORTANTE: Las imgenes deben ser de un tamao chico (menor de 8kbytes), de lo contrario se provocar un error por falta de memoria. Para probar este proyecto es necesario conectarse a una PC con Bluetooth y otra aplicacin en C# que mande los mensajes de alarma y reciba los comandos de activacin de los aireadores. Si su PC no tiene Bluetooth puede utilizar un Dongle como BlueSoleil para crear estos puertos COM virtuales. El sofware de Bluesoleil permite conectarse a cualquier dispositivo Bluetooth por medio de este panel:
200
Cuando se asocia al SmartPhone debe aparecer el puerto COM que puede utilizar en la aplicacin de escritorio de C#.
Para mandar los mensajes podemos usar los ejemplos anteriores de comunicacin Rs232, solo agregamos un botn que mande un mensaje con la sintaxis que requiere nuestro SmartPhone para separar las alarmas. Puede crear un proyecto nuevo de windows forms o modificar un ejemplo anterior.
Al abrir el puerto nuestro botn para mandar alarma debe mandar los mensajes separados por un '+' y con la palabra -FINprivate void btnAlarma_Click(object sender, EventArgs e) { serialPort.Write("12:30 hrs + Sobrecalentamiento + Checar Bomba 1-5 }
-FIN-");
Finalmente tenemos un monitoreo y control inalmbrico en el rango de operacin de nuestro Dongle Bluetooth. 201
Con este tema damos por concluido nuestro curso. Gracias por su participacin Atte. Ing. Aaron Castro Bazua