.NET Tutorial 31. Usando el puerto serie (Parte I)

La comunicación con un dispositivo de hardware externo al PC es un tema apasionante y que puede dar mucho juego.

Nota del autor: Estepost puede resultar demasiado "técnico". Lo que intentaré explicar de la mejor forma posible se estudia en algunas carreras de ingeniería y/o ciclos superiores. De todos modos esto no tiene porque haceros tener "miedo", más bien al contrario. 🙂

Dicho esto, imaginaos poder controlar una estación meteorológica, un termómetro, una báscula, un automáta programable, un motor paso a paso, un brazo robotizado, un semáforo, una foto-célula, una barrera, una alarma…

En muchos de los ejemplos anteriores (por no decir todos) se puede utilizar el puerto serie del PC.
En la "informática doméstica" este puerto prácticamente ya no se utiliza. Es algo parecido a las diqueteras de 3.5». Prácticamente todoslos PCs que podemos comprar hoy en día ya no disponen de este tipo de disquetera.

Esto no ocurre en el "ámbito industrial" ya que este tipo de comunicación (así como la comunicación 422, 485) se siguen usando con muchísima frecuencia .

De todos modos, existen adaptadores "USB" a "Serie". Ya que el puerto USB (Universal Serial Bus)no es mas que un puerto "serie de más velocidad" (muy muy muy a groso modo, que no se me enfade nadie eh!) . Suelen tener este aspecto:

Donde como veís, por un extremo es "usb" y por el otro es "serie" (típico conector macho de 9 pines o también conocido como DB9)

El conector DB9 será el que usaremos para "comunicarnos" con el hardaware.

Todos los puertos serie se muestran en el Administrador de dispositivos de Windows en la sección "Puertos (COM y LPT)":

Se enumerán COM1, COM2, COM3,… El máximo numero de puertos que puede gestionar Windows (ahora no recuerdo si Linux y otros S.O, también) es de 256.
En algunos portátiles, se reserva en "COM3" para el modem interno del portátil.

El puerto serie dispone de dos "pines" (patillas) "interesantes" para nuestros propositos:

  • El pin 2 es el de la recepción (RxD)
  • El pin 3 es el de la transmisión (TxD)

Un esquema típico de interconexión es el siguiente:

Que quiere decir este esquema:

Lo que "envía" el dispositivo hacia el PC "entra"  por la "recepción" del PC
Lo que "envía" el PC hacía el dispositivo "entra" por la "recepción" del dispositivo.

Existen más señales que se pueden interconectar. Este "tipo" de cables se llaman Null modem

Desgraciadamente para nosotros, la parte del "dispositivo" no siempre tiene porque ser así. Lo que está claro es que la parte del "PC" si que será siempre así.

Para hacer pruebas son realmente útiles los softwares que "virtualizan" un puerto serie: 


(Haz click para ampliar)

Estos programas crean "pares interconectados" de puertos

Existen programas de pago (como el mostrado arriba) y tambien gratuitos como el com0com (http://com0com.sourceforge.net

Estos programas hacen dos cosas:

  • Crean puertos "virtuales" en el PC
  • Por defecto, interconexionan dichos puertos como si de un Null modem se trata

Para poder ver el resultado del código de este tutorial tenéis estas posibilidades:

  • Usar un software para "virtualizar" puertos
  • Usar 2 PCs. En uno se ejecuta el hyperterminal (lo veremos a continuación). En el otro PC se ejecuta el código del tutorial. La conexión entre los dos PCs se hace con un cable "Null modem" (con cruzar los pines 2 y 3 respectivamente más la tierra (GND) es suficiente para las pruebas)

Antes de entrar en el ejemplo comentar algo sobre los caracteres ASCII.

Como bien sabéis, los 31 primeros códigos ASCII son caracteres "de control". Tabla ASCII

Estos carácteres son muy habituales en estas comunicaciones. Normalmentehablamos de "datagramas" o "tramas de comunicación". Una trama típica podría ser:

<STX>HOLA<ETX><CR><LF>

Ahí se transmiten 8 bytes:

  • 1: Carácter ASCII 2 (<STX> o tambien llamado Start of Text)
  • 2: Carácter ASCII "H"
  • 3: Carácter ASCII "O"
  • 4: Carácter ASCII "L"
  • 5: Carácter ASCII "A"
  • 6: Carácter ASCII 3 (<ETX> o tambien llamado End of Text)
  • 7: Carácter ASCII 13 (0x0D en hexadecimal) (<CR> o lo que se conoce como Carry Return o Retorno de carro)
  • 8: Carácter ACII 10 (0x0A en hexadecimal) (<LF> o lo que se conoce como Line Feed o Salto de línea)

La trama de comunicación depende exclusivamente del dispositivo, pudiendo ser mas o menos compleja.

Por último, los dispositivos tienen básicamente dos formas de funcionar:

  • El dispositivo, cada cierto intervalo de tiempo envía la trama de comunicación hacia el PC. Esto suele conocerse como envío continuo
  • El dispositivo únicamente envía la trama de comunicación hacía el PC cuando ha recibido una "petición". En este caso el PC envía "algo" al dispositivo, el dispositivo lo procesa y "contesta". Esto suele conocerse como envío por petición o por "polling"

En los ejemplos que acompañan el tutorial encontraréis dos ejemplos, precisamente uno de envío en "continuo" y otro de envío por "petición".

Bueno, al lio 🙂

Para menejar los puertos series desde .NET tendremos que importar el siguiente Namespace:

Imports System.IO.Ports

Este Namespace incorpora una serie de objetos y clases para el manejo de los puertos serie.

Lo que haremos será "simular" un dispositivo, en este caso en particularuna báscula. Si alguien conoce el protocolo empleado le regalo un gallifante 🙂

Para la "rececpción" usaremos el programa hyperterminal de Windows.

Nota: El hyperterminal de Windows está disponible en Windows XP en el apartado de Accesorios -> Comunicaciones. En Vista / 7 no está disponible (sic). Si este es vuestro caso teneis dos opciones:

  • Esperar a la siguiente entrega (Parte II) donde construiremos en "receptor"
  • Utilizar cualquier otro software "terminal" (Google it 🙂

Los ejemplos utilizan el COM9, que está "interconectado" con un softwarede virtualización con el COM8, que es el que usaremos en el hyperterminal.

Pues bien, lo primero que hacemos es abrir el hyperterminal y seleccionar el COM8:

A continuación establecemos las propiedades del puerto así:

Al aceptar vemos la "consola" del hyperterminal:


(Haz click para ampliar)

Como véis, no se está recibiendo "nada". Ahora ejecutamos el Tutorial31_Continuo y pulsamos en el botón "Abrir":


(Haz click para ampliar)

A partir de ese momento, se empiezan a recibir datos en el hyperterminal.

Al variar los datos, se envía la trama con dichas variaciones:


(Haz click para ampliar)

Y aquí más variaciones:


(Haz click para ampliar)

En función del los valores de "BRUTO" y "TARA" podéis observar que la trama es distinta.

De todos modos, la idea es observar que las tramas se envían de forma "continua" 

Para el envío a petición procedemos así:

En nuestro caso en particular, nuestro simulador Tutorial31_Peticion debe recibir la trama <SOH><CR><LF> para enviar los datos.

El "problema" está en que el carácter <SOH> no es imprimible (ver lo comentado antes)

Para solucionarlo nos generamos un fichero de texto con el bloc de notasdonde escibimos la letra "a" y a continuación pulsamos la tecla ENTER 

La tecla ENTER introduce los caracteres <CR><LF>.

Salvamos el documento y lo llamamos, por ejemplo peticion.txt

Ahora necesitamos abrir dicho fichero pero con un edito hexadecimal, por ejemplo, el HxD (http://mh-nexus.de/en/hxd) que es bueno, bonito y barato (freeware):

(Haz click para ampliar)

Lo que haremos es cambiar el byte 0x61H que corresponde al caracter ASCII a por el valor 01, que corresponde al caracter ASCII <SOH> (Start of heading):


(Haz click para ampliar)

Nota sabionda: el carácter <SOH> se puede "simular" como un CTRl+A

Guardamos los cambios y ahora abrimos el hyperterminal.

En la configuración del hyperterminal hay que cambiar la configuración y ponerla tal que así:


(Haz click para ampliar)

Si ahora pulsamos CTRL+A y pulsamos ENTER vemos lo siguiente:


(Haz click para ampliar)

La diferencia con el caso "continuo" es que ahora nuestro "simulador" solo envía la trama de comunicación cuando éste recibe <SOH><CR><LF> y no de forma continua como ocurría con el ejemplo anterior.

Vamos a enviarle el fichero que modificamos en el editor hexadecimal:


(Haz click para ampliar)

Y este es el resultado:


(Haz click para ampliar)

 

Bueno, hasta aquí esta entrada.

En este caso comprenderé perfectamente que no comentéis nada, ya que es muy posible que todo este "rollo" os suene a "chino" a la mayoría 🙂

Tampoco he querido entrar a "fondo" por el mismo motivo. De todas formas, si tenéis dudas o queréis profundizar más en el tema, podéis mandarme un MP para comentar cualquier cosa.

 

Saludos.
mov eax,ollydbg; Int 13h 

 

Descargar código fuente del .NET Tutorial 31
(32 KB. Visual Studio 2008)

.NET Tutorial 30. Animación sprites (Parte II)

En el Tutorial 6 vimos como "animar" un sprite.

Hoy vamos a ver lo mismo pero usando XNA y VB.NET.

En esta ocasión, cada uno de los fotogramas que componen nuestra "animación" son imagenes independientes, en total 7 imagenes:

Nos definimos estas dos variables:

Private Animacion As List(Of Texture2D) = New List(Of Texture2D)
Private _currentFrame As Integer = 0

Aminmacion será un a"lista de texturas" (ver Tutorial 29) mientras que _currentFrame nos va a servir para saber que textura mostrar dentro de esa lista.

En el LoadContent cargamos las texturas en la lista con este simple For:

For i As Integer = 1 To 7
   Animacion.Add(Content.Load(Of Texture2D)("su_idle" & i))
Next

Finalmente, en el método Draw dibujamos los sprites con esta línea:

spriteBatch.Draw(Animacion(_currentFrame), New Vector2(0, 180), Color.White)

Como podréis observar, lo único que tenemos que hacer ahora es ir variando el valor de la variable _currentFrame para que dicho valor vaya cambiando entre 1,2,3,4,5,6 y 7. De esta forma se iran mostrando las distintas texturas que hay guardadas en la lista.

Este cambio se realizará obviamente en el método Update.

Primero necesitaremos definir estas dos variables:

Private _animacionFPS As Integer = 14
Private _animacionIncrease As Integer = 0

Y dentro del método Update haremos lo siguiente:

_animacionIncrease += gameTime.ElapsedGameTime.TotalMilliseconds
If _animacionIncrease >= (1000 / _animacionFPS) Then
   If _currentFrame >= Animacion.Count – 1 Then
      _currentFrame = 0
   Else
      _currentFrame += 1
   End If
   _animacionIncrease = 0
End If

Mini-explicación: El método Update se ejecuta 60 veces por segundo. Lo que hacemos es ir almacenando en _animacionIncrease milisegundos.

El 1000 / _animacionFPS representa los milisegundos que hay que "esperar" entre fotograma y fotograma.

_animacionFPS hemos decidido que vale 14. Esto quiere decir que cada segundo se muestran 14 fotogramas, o lo que es lo mismo, entre fotograma y fotograma hay un "retardo" de 1000 milisegundos  / 14 Fotogramas = 71,4285 milisegundos.

Resumiendo: Que cada vez que pasen 71,4285 milisegundos, se actualiza la variable _currentFrame a menos que sea la última textura de la lista, si es dicho caso se establece con el valor 0.

He añadido algun "extra", como es el de hacer un "mirror" del sprite o "agrandarlo", pero básicamente el fundamento de la animación es el que hemos visto.

El resultado final es algo como esto:

Las teclas son las que se muestran en pantalla:

F1: Intercambia entre pantalla completa y modo ventana
A: Mirror del sprite
D: sprite sin mirror
S: Aumenta la escala del sprite

 

Saludos.
mov eax,ollydbg; Int 13h 

 

Descargar código fuente del .NET Tutorial 30
(1.19 MB. Visual Studio 2008 Professional / XNA GS 3.1)

Descargar binarios del .NET Tutorial 30
(588 KB. Requiere .NET Framework 3.5 / XNA Framework 3.1

 

.NET Tutorial 29. Uso de List (Of T). Ejemplo práctico con XNA

Según la MSDN la clase List es el equivalente genérico de la clase ArrayList. Implementa la interfaz genérica IList mediante una matriz cuyo tamaño aumenta dinámicamente según se requiera.

Ya vimos como funcionaban los ArrayList (Ver Tutorial 19). Hoy veremos que como tener un "array clases" con List (Of T)

Lo que haremos será lo siguiente:

1) Vamos a simular el Tutorial 5 que ya vimos en su día, que como recordaréis no fue más que la excusa para introducir el concepto de "array"

2) Tendremos una clase (misSprites.vb) que contendrá una serie de métodos públicos y privados

3) Crearemos una "lista de clases" de la clase misSprites.vb para conseguir esto:


(Haz click para agrandar)

Por cierto, notar que hay 2000 sprites "rebotando" por la pantalla a 60 FPS:

Pues bien, manos a la obra.

El objeto que va a manejar la lista lo declaramos así:

Private Sprites As List(Of misSprites) = New List(Of misSprites)

donde misSprites representa que es la clase de "1" sprite en particular.

¿Cómo se añaden elementos a la Lista?

Pues muy simple:

Dim lSprite As New misSprites()
Sprites.Add(lSprite)

¿Cómo se recorren todos los elementos dela Lista?

Pues más simple si cabe:

For Each lSprite As misSprites In Sprites
   ‘Hacer lo que sea con el objeto lSprite
Next

¿Cómo se borra un "elemento" de la Lista?

Esto borraría el último elemento:

Sprites.RemoveAt(Sprites.Count – 1)

y esto borraría toda lalista:

Sprites.Clear()

Como habéis visto, se usan los métodos "habituales" que usabamos con los ArraysList: Add, Clear, RemoveAt… No hay ningún misterio en eso.

En el caso particular de este tutorial la clase misSprites tiene 2 sobrecargas del método New (). Podéis ver que una inicializa un sprite en la posición (0,0) con un valor aleatorio de textura y unos valores fijos de "velocidad" y el otro método inicializa el sprite en una determinada posición (x,y), con un valor concreto de textura y con unos determinados valores de "velocidad".

Además, posee dos métodos públicos: Update y Draw 

El método Update llama intermamente al método privado MoverSprite, de tal forma de que cada vez que se llame al método Update se actualizará la posición de aquel sprite en particular.

El método Draw dibuja el sprite en la posición actual.

Desde nuestra clase principal se utilizan los métodos Update y Draw desde las funciones Protected Overrides Sub Update(ByVal gameTime As GameTime) y Protected Overrides Sub Draw(ByVal gameTime As Microsoft.Xna.Framework.GameTime) respectivamente.

Dentro de Update actualizamos la posición de los sprites así:

For Each lSprite As misSprites In Sprites
   lSprite.Update()
Next

Dentro de Draw dibujamos los sprites así:

For Each lSprite As misSprites In Sprites
   lSprite.Draw(spriteBatch)
Next

Como véis es extremadamente simple, a la par de flexible y potente.

El código completo lo podéis encontrar aquí:
CBaseClient.vb
misSprites.vb

Por último notar que la rutina que controla la pulsación de las teclas, ControlTeclado( ), está diseñada para funcionar "exclusivamente" si anteiormente se "soltó" la tecla en cuestión.

De no hacerlo así se añadirían múltiples sprites al pulsar por ejemplo la tecla "A".Será necesario "pulsar" y "soltar" para añadir/quitar sprites.

 

Saludos.
mov eax,ollydbg; Int 13h 

 

Descargar código fuente del .NET Tutorial 29
(1.31 MB. Visual Studio 2008 Professional / XNA GS 3.1)

Descargar binarios del .NET Tutorial 29
(20.91 KB. Requiere .NET Framework 3.5 / XNA Framework 3.1

.NET Tutorial 28. XNA GS 3.1 en VB.NET. XNAvbNET Parte II

En el tutorial anterior vimos como crear un proyecto "básico"de XNA usando VB.NET.

Hoy vamos a ver como cargar una imagen de fondo y mover un "sprite". Será la "versión" XNA del tutorial 2 y tutorial 3 que ya vimos en su momento.

Tomando como base el tutorial 27 haremos lo siguiente:

En el Content añadiremos la imagen de fondo y el sprite del tutorial 2. Para hacer eso, nada mas simple que pulsar en el Content y añadir un elemento existente.

Al cargar los dos archivos deberiamos tener algo como esto:

La imagen de fondo será el archivo background1.jpg y el sprite el archivo glow.png

En el Content vamos a añadir un nuevo elemento, en este caso un "Sprite Font" que nos servirá para "escribir" cosas en pantalla:

Le daremos como nomre "Test.spritefont"

Definiremos una variable tal que así:

Private Background As Texture2D

Los gráficos los cargamos en el procedimiento LoadContent:

Protected Overrides Sub LoadContent()

de la siguiente forma:

Background = Content.Load(Of Texture2D)("background1")

Donde "background1" es el nombre "interno" del background en en Content, que se puede ver en la ventana de propiedades. (El "Asset Name" en la ventana de propiedades)

Cómo veís, no tiene complicación ninguna.

La "fuente" la cargamos de forma similar:

font = Content.Load(Of SpriteFont)("Test")

Donde font es un objeto de tipo:

Private font As SpriteFont

Pues bien, para "dibujar" las cosas lo haremos en el prodecimiento Draw:

Protected Overrides Sub Draw(ByVal gameTime As Microsoft.Xna.Framework.GameTime)

Todo lo que "dibujemos" ha de estar comprendido entre el spriteBatch.Begin y el spriteBatch.End, de tal modo que lo haremos así:

spriteBatch.Draw(Background, New Vector2(0, 0), Color.White)

Existen hasta 7 sobrecargas del método Draw.

Para el sprite se hace exáctamente igual.

La rutina que actualiza el movimiento del sprite se llama desde el procedimiento Update:

Protected Overrides Sub Update(ByVal gameTime As GameTime)

El resultado final es algo como esto:


(Haz click para agrandar)

Si analizáis el código podréis ver que utilizo dos "formas" de cargar un sprite, uno usando objetos en la clase "base" y otro usando una clase llamada "spriteClass". Ambas formas con correctas, pero de ahora en adelante usaremos a menudo un "array" de clases para tener el código más organizado.

Lo habitual es tener la clase "nave", la clase "disparo", la clase "enemigo", la clase "powerUp", etc. De esta forma podremos usar el operador List Of ( ) para tenerlo todo controlado. Esto lo veremos en el próximo tutorial, donde haremos la "versión XNA" del tutorial 5 que vimos en su día. Donde por cierto podréis comprobar que el código pinta igual de rápido 1 sprite como 500.

Si alguien controla algo de XNA con C# podrá ver que lo que hacemos aquí es exactamente lo mismo que se hace en el código de C#, pero con la "sintaxis" de VB.NET. ¿Quien dijo que no se podía usar XNA en VB.NET? 🙂

 

Espero vuestros comentarios.

 

Saludos.
mov eax,ollydbg; Int 13h 

 

Descargar código fuente del .XNAvbNET Tutorial 2
(2.13 MB. Visual Studio 2008 Professional / XNA GS 3.1)