Archivo de la categoría: Serial Ports

Serial Ports

Cambiar los ‘SerialPort Settings’ en tiempo de ejecución.

Atendiendo a una consulta de los foros de MSDN, me complace compartir con vosotros una solución para asignar los ajustes de apertura del puerto serie al vuelo.

Entendiendo que en algunas situaciones, puede ser ventajoso poder cambiar la velocidad, paridad, bits… etc, ‘On Line’. Aunque para la mayoría de comunicaciones con dispositivos dichos parámetros son ajustados en tiempo de puesta en marcha y no acostumbran a variar en el transcurso del tiempo.

Esperando os sea útil… Saludos,
Pep Lluis,

PD. Si queréis podéis descargaros la solución de ejemplo en ‘attachments’.

using System;

using System.IO.Ports;

using System.Windows.Forms;

 

namespace SerialPortSettings

{

    public partial class Form1 : Form

    {

        public Form1()

        {

            InitializeComponent();

        }

 

        private void Form1_Load(object sender, EventArgs e)

        {

            // Asignar las Velocidades seleccionables al Combo

            object[] Velocidades = { 19200, 9600, 4800, 2400, 1200 };

            this.comboBox_bits_por_segundo.Items.AddRange(Velocidades);

           

            // Asignar Paridades Seleccionables desde la enumeracion

            foreach (string s in Enum.GetNames(typeof(Parity)))

            {

                this.comboBox_paridad.Items.Add(s);

            }

           

            // Seleccionar los items por defecto

            this.comboBox_bits_por_segundo.SelectedIndex = 0;

            this.comboBox_paridad.SelectedIndex = 0;

            // Abrir el puerto serie con los items por defecto

            SeleccionCambiada(sender,e);

            // Asignar la funcion a ejecutar por disparo de evento al cambio de indice en el combobox

            this.comboBox_bits_por_segundo.SelectedIndexChanged += new System.EventHandler(this.SeleccionCambiada);

            this.comboBox_paridad.SelectedIndexChanged += new System.EventHandler(this.SeleccionCambiada);

        }

 

       

        private void SeleccionCambiada(object sender, EventArgs e)

        {

            // Deberemos añadir un control de excepciones si queremos capturar posibles errores

 

            // Para reasignar valores… primero cerrar el puerto

            this.serialPort1.Close();

            // Asignar los nuevos Settings

            this.serialPort1.BaudRate = Convert.ToInt16(comboBox_bits_por_segundo.Text);

            this.serialPort1.Parity = (Parity)Enum.Parse(typeof(Parity), comboBox_paridad.Text);

 

            this.serialPort1.Open();

            // Ver las asignaciones actuales.

            this.Velocidad.Text = this.serialPort1.BaudRate.ToString();

            this.Paridad.Text = this.serialPort1.Parity.ToString();

        }

 

    }

}

 

Como Enumerar los Com’s de nuestro equipo en Vb y en C#

Contestando a la pregunta de Meta, sobre el código en VB:

Me.ComboBox1.Items.AddRange(My.Computer.Ports.SerialPortNames.ToArray)

‘ En el evento SelectedIndexChanged… del ComboBox1

PuertoSerie.Close()
PuertoSerie.PortName = ComboBox1.SelectedItem
PuertoSerie.Open()

<Meta>
Mi pregunta es, ¿puedes hacer lo mismo en Visual C#?
Creo que falta más detalle en la explicación, ya que deseo que en el comboBox tenga el COM1 y COM2 para seleccionar. … vb no lo interpreto bien.

private System.Windows.Forms.ComboBox comboBox1;

private System.IO.Ports.SerialPort PuertoSerie;

 

public Form1()

{

InitializeComponent();

      this.comboBox1 = new System.Windows.Forms.ComboBox();

      // comboBox1

      this.comboBox1.FormattingEnabled = true;

      this.comboBox1.Name = «comboBox1»;

      this.Controls.Add(this.comboBox1);

}

 

private void Form1_Load(object sender, EventArgs e)

{
      // GetPortNames, nos devuelve un array con los nombres

      // de los puertos instalados en nuestro equipo

String[] Ports = System.IO.Ports.SerialPort.GetPortNames();

      this.comboBox1.Items.AddRange(Ports);

}

 

// En el evento SelectedIndexChanged… del ComboBox1

{     

      // … Por ejemplo
      PuertoSerie.Close();

      PuertoSerie.PortName = this.comboBox1.SelectedItem.ToString();

      PuertoSerie.Open();

}

 

En el ejemplo anterior para no crear confusión he incluido la parte de añadir el comboBox al form, de esa forma le podemos seguir la pista. También puedes inicializar directamente los ítems del combo , pero he preferido utilizar el array ‘Ports’ para diferenciar la operación. De esa forma quizás sean más inteligible.

Saludos,
Pep Lluis,

Enviar datos en hex por el puerto serie.

A la pregunta:

è Necesitaría información de cómo enviar datos en hex por el puerto serie, porque por defecto lo hace en ASCII.

Realmente la información no se envía en ASCII por defecto, si no en función al ‘Encoding’ utilizado. En realidad estamos serializando un Byte…

        Dim MiPuerto = My.Computer.Ports.OpenSerialPort(«COM1»)

        MiPuerto.Write(&HFF)    ‘Enviar valor hex FF

        Dim Valor As Byte = 255

        MiPuerto.Write(Valor)   ‘Enviar byte 255


En ambos casos enviaremos ocho bits ‘1111 1111’ si utilizamos una longitud de 8, por lo que el DTE recibirá el valor binario 255.

En determinadas situaciones, el micro controlador espera que le mandemos los ‘nibbles’ encapsulados en ASCII, o sea para enviarle el valor de 8 bits, necesitaremos su representación hexadecimal en forma de dos Bytes ASCII, por ejemplo los caracteres ‘7’ y ‘F’ para el valor 127, por lo tanto estaremos mandando 16bits de datos para representar un valor hexadecimal de 8bits.

En tal caso simplemente especificaremos

        Valor = 127

        MiPuerto.Write(Hex(Valor))

 

En este supuesto el micro controlador recibirá ‘7F’, correspondiente al valor binario 127.

No dudéis en continuar esta conversación si la explicación no resulta lo suficientemente clara.
Pep Lluis,

Marcacion de un numero de telefono – Mandato ATDT

Atendiendo a la pregunta de :

 

>Necesito hacer una aplicación que haga una llamada telefónica utilizando el modem de la pc,no algo muy complejo solo por ejemplo hasta la idea de una agenda donde al dar clic en un registro salga la llamada hacia dicho número, esto en vb.net

 

Dim PuertoSerie As SerialPort = My.Computer.Ports.OpenSerialPort(«COM1», 9600)

PuertoSerie.DtrEnable = True

PuertoSerie.Write(«ATDT0123456789» & vbCrLf)

‘En este momento el modem marcara el numero 0123456789

‘Si no recuerdo mal la mayoria de modems disponen de ATH0 / ATH1 para colgar y descolgar el auricular

‘cuando recibes llamadas o para finalizar la que tienes en curso.

‘Tambien es bueno recordar con ATZ… retornas el modem a su estado inicial «Reset»

 

A pesar de la sencillez para marcar un numero, es aconsejable leer el manual de comandos del modem suministrado por el fabricante, en el encontraras la información relevante para poder tener un control adecuado del modem.

Espero vuestros comentarios,
Pep Lluis,

Entre 485 y 232

Atendiendo a la pregunta de :

> Hola, estoy leyendo el foro buscando información sobre programar una rutina en Visual Basic, para conectar con unos dispositivos que trabajan con RS485.

En una conexión serie, estamos intercambiando información a través de una conexión de Tu a Tu (Peer To Peer) en Ingles. Ello significa que cada trama enviada por un DCE es recibida en el otro extremo por un DCE o DTE y viceversa, electrónicamente las señales estan diseñadas como entradas/salidas, por lo que una salida de un extremo se corresponde a la entrada en el otro, en una topología 485 la primera distinción es la característica de utilizar dos hilos conectados a la electrónica a través de unas Entradas/Salidas triestado, ello significa que utilizando las mismas patillas podemos enviar y recibir datos. La señal del puerto serie trasmite la información por diferencial de voltaje entre el GND y el correspondiente transmisor/receptor, el 485 distingue los niveles por diferencial de voltaje entre sus dos hilos (+) y (-), por lo que es mas inmune a las interferencias, su comportamiento es mucho mejor que el 232 en entornos industriales y evidentemente su cableado mucho mas sencillo.

Por sus características de impedancia, el 485 permite la conexión de hasta 32 dispositivos y creo que hasta 100m, mientras el 232 solo permite la conexión de 1 dispositivo y creo que el máximo según la especificación es de 15m.

La primera particularidad de cualquier dispositivo 485 es que debe estar preparado para configurarse como un único dispositivo dentro de la red y además solo uno de los dispositivos deberá disponer del rol de “Host” o anfitrión de manera que el resto de dispositivos solo participaran en el intercambio de datos respondiendo a las solicitudes del anfitrión.

Por poner un ejemplo, imaginemos un PC con un conversor USB/485 configurado a través de un puerto serie, y este tiene conectadas 4 basculas numeradas del  ’01’ al ‘04’… el software del PC, para leer el peso de todas las basculas deberá componer las tramas direccionando a cada una de ellas y recibiendo la información de una en una…

Imaginemos el formato de la trama de petición : PPUN
Donde PP = “Pedir Peso” y UN = Numero Unidad de Bascula

PC -> enviara : PP01
PP01 -> Respondera :  RB011,500

Donde RB = “Resultado Bascula”, 01 es la unidad de bascula que responde y 1,500 los Kilos.

En la siguiente operación el PC deberá enviar : PP02.. Para recibir el peso de la segunda bascula y así sucesivamente.

Espero vuestras preguntas para ir matizando sobre el tema… pues es mas amplio y espefico de lo que parece.

Saludos,
Pep Lluis,

Acceso al puerto paralelo LPT – Algo Más que encender un LED o Imprimir un DOC

Durante más de medio año y sobre todo desde LatinoAmerica estoy recibiendo cantidad de solicitudes de ayuda para manejar el puerto paralelo del Ordenador y poder así activar relés que ponen en marcha cualquier tipo de artilugio eléctrico o electrónico. He sido reticente a escribir nada al respecto, pues consideraba que existen mil y una soluciones actuales tanto en HardWare como en SoftWare que permiten controlar motores, luces o cualquier tipo de mecatronica pero de forma profesional  con tecnología y medios actuales. Pensar el soluciones del tiempo de MS-DOS, me parece como menos equivocado siempre y cuando la finalidad no sea como ejercicio docente o como una forma de aprender y experimentar. Una vez entendida la declaración me complace compartir la siguiente explicación para contextualizar que encender un ‘led’ utilizando el puerto paralelo no es ningún logro, aunque sin despreciar la experiencia pueda ser divertido, teniendo en cuenta que la interacción con el sistema operativo es la que marcan los cánones a pesar de que de vez en cuando podamos hacerle un giño.  A demás no debemos olvidar que a día de hoy no todos los ordenadores incorporan la antigua especificación para el puerto paralelo.

Una de las características de la arquitectura x86 es el direccionamiento de dispositivos periféricos a través de un bus de entradas/salidas. Si nos remontamos en el tiempo, para la mayoría de los que utilizaron “Macro Assembler” o “C” en los tiempos de sistemas operativos como CP/M o MS/DOS, recordaran como nos hacíamos con el control de los dispositivos desviando los vectores de interrupción a nuestras rutinas y por supuesto comunicándonos directamente con los dispositivos a través de sus puertos mapeados en tal bus de E/S. Estamos hablando de dispositivos como el Teclado, Puerto Serie, Paralelo, Memoria, Timer, etc … ciertamente todos los dispositivos que componían la estructura básica de nuestro sistema. Por supuesto estábamos más que familiarizados con la utilización de las instrucción ‘in’ y ‘out’, ellas nos permitían enviar o recibir un byte utilizando un puerto (Mapa E/S) que conectaba directamente y permitía el intercambio de información con un periférico en concreto.

En esos tiempos los sistemas operativos estaban orientados a la ejecución mono-Usuario, Mono tarea, sin entorno grafico y con la única posibilidad de interaccionar a través de un ‘prompt’  por parte del usuario.

Con la llegada y evolución de los sistemas gráficos, multitarea, multiusuario para plataformas Intel, tuvieron que adaptarse a una arquitectura adecuada para tal cometido. Dicha arquitectura dicta las normas en las deben efectuarse las llamadas a  procedimientos, manejar las interrupciones y como no las excepciones, por citar algunas.

Dicho esquema, familiar para cualquier estudiante de informática como mecanismo de protección reconoce en forma de aros, en concreto cuatro aros concéntricos que representan cuatro niveles de privilegio del 0 al 3, la principal razón para usar ese esquema se vasa en mejorar la fiabilidad del propio sistema operativo.

Privilegios

El primer aro en el centro es utilizado por módulos de código que contienen partes vitales y criticas del sistema, por lo tanto disponen del nivel de privilegios más alto. El resto de módulos con menor nivel de privilegio solo pueden acceder al nivel superior a través de un estricto controlador llamado “puerta” o “gate”, intentar acceder a un segmento privilegiado de un nivel superior directamente o si utilizar la protección “gate” sin los suficientes permisos causara una excepción de protección general.

En nuestro entorno Intel/Windows, tuvimos la posibilidad de utilizar las instrucciones de ‘in’ ‘out’ tanto desde lenguajes como Asm, C y Basic y los sistemas operativos DOS, 95 y 98. Sin embargo con la tecnología NT, el uso de estas instrucciones por programas con privilegios de usuarios generaba la consecuente excepción en el sistema.

Cabe dejar claro que es del todo irreconciliable la mentalidad de acceder al puerto paralelo enviando un byte a la dirección de su puerto en un entorno como el nuestro. Difícilmente podemos justificar una programación orientada a controlar los dispositivos… ese tiempo ya paso y precisamente una de las tareas más eficientes que nuestro sistema operativo es capaz de llevar a cabo es ese control. No debemos perder la perspectiva que si necesitamos programar partes especificas que justifican ese nivel de privilegios, debemos utilizar las herramientas que nos facilita el fabricante del SO, tales como SDK, DDK..etc.  Es evidente que necesitamos una serie de conocimientos avanzados, para encajar nuestra pieza en todo este puzle, pero sin duda solo siguiendo esos patrones seremos capaces de construir soluciones profesionales aptas para superar las pruebas a nivel de los mercados a los que van dirigidos.

Advertencia y Aclaración.
Está claro que os facilito este articulo por vuestra insistencia, aunque debo advertiros que el mal uso del soldador con el conector de 25 al intentar realizar experimentos o utilizar inadecuadamente el puerto paralelo conectando aparatos o dispositivos inadecuados o incompatibles, puede causar averías en el equipo o en el peor de los casos daños personales, debo rechazar categóricamente cualquier responsabilidad por el uso de la información contenida, cualquier aplicación o uso derivada de la información de este artículo y su alcance es estrictamente responsabilidad del lector aunque estaré encantado de recibir vuestros comentarios.

En el caso que nos ocupa, para poder enviar o recibir un byte de puerto, necesitaremos estar dentro del anillo de ‘driver’ que nos proporcione los derechos de privilegio suficiente para realizar dicha operación. La mayoría de nosotros carecemos de los conocimientos suficientes para desarrollar un adaptador que nos permita fabricarnos nuestro propio ‘driver’ aunque podemos encontrar multitud de ejemplos en la red, existe una conocida librería llamada ‘inpout32.dll’ que viene a implementar ese ‘kernel model driver’. Podemos descargarnos esa librería desde un montón de ubicaciones, solo es necesario buscar ‘inpout32.dll DownLoad’ en la red y una vez dispongamos de ella copiarla en “\windows\system32”.

Luego solo nos restara crear un nuevo proyecto en Visual Studio e incluir nuestras referencias como sigue:

‘Declaraciones para leer/ecribir un puerto E/S utilizando inpout32.dll

Public Declare Function leer Lib «inpout32.dll» Alias «Inp32» _

       (ByVal puerto As Short) As Short

Public Declare Sub escribir Lib «inpout32.dll» Alias «Out32» _

       (ByVal puerto As Short, ByVal Valor As Short)

 

Finalmente en el evento clic del botón por ejemplo:

    ‘ Para la prueba de los led’s

    ‘ Conectar los led’s a traves de una resistencia.

    ‘ La resistencia debe soldarse a la masa en las

    ‘ patillas del conector de (25pins) correspondientes

    ‘ a los pines 19,20,21,22,23,24,25 (son todos masa).

    ‘ El otro extremo de la resistencia lo soldaremos al

    ‘ negativo del led, y el positivo del mismo a las

    ‘ patillas 2,3,4,5,6,7,8,9 que corresponden a la salida

    ‘ del registro de datos del puerto serie.

 

    Private Sub Button1_Click() Handles Button1.Click

        Static OnOff As Boolean = False

        ‘el puerto &h378 corresponde a la direccion

        ‘del registro ‘data’ del LPT1:

        If OnOff Then

            ‘Apagar todos los led’s

            escribir(&H378, &H0)

        Else

            ‘Encender todos los led’s

            escribir(&H378, &HFF)

        End If

        OnOff = Not OnOff

    End Sub

 

Luego para leer el estado de las líneas del registro de datos:

    Private Sub Button2_Click() Handles Button2.Click

        MessageBox.Show(leer(&H378))

    End Sub

 Saludos,
Pep Lluis,

Serial Port – Enumeración & Disponibilidad

 

         Saber sobre la disponibilidad de nuestros puertos serie antes de su selección en un combobox.

  How to know about availability of our computer serial ports before select one from a combo box.

A menudo las aplicaciones que requieren seleccionar un dispositivo antes de efectuar algún tipo de comunicacion, no ofrecen ninguna información adicional sobre el estado del dispositivo. Sobre todo si hablamos del puerto serie, normalmente nos ofrecen una simple enumeración de los COM. Esto último es el causante de que la aplicación nos permita seleccionar un puerto que en ocasiones no existe o está siendo usado por otro programa.

Os propongo una idea con la intención de mejorar y facilitar la selección de este tipo de dispositivos en nuestras aplicaciones.

Básicamente se trata de enumerar en un ‘ComboBox’ personalizado los puertos existentes en nuestro equipo, utilizando el mandato :

My.Computer.Ports.SerialPortNames.ToArray

En el momento de la inicialización del ‘combobox’ asignaremos el evento de ‘DrawItem’ a la función que enriquecerá el aspecto, añadiendo al nombre un rectángulo coloreado y el texto correspondiente a la disponibilidad del puerto.

AddHandler ComboBox1.DrawItem, AddressOf cmbo_SerialPorts_Status

No dudéis en contactar conmigo si necesitáis aclarar o necesitáis entender alguna parte del código.

Para poder darle mayor difusión los comentarios del código están en inglés, aunque si os parece oportuno y necesario puedo posteároslo también en español.

Sometimes our communications applications are required to select any type of external device, and normally these applications are not giving any extra information about their availability. This is the case when talk around serial ports, normally when select the port only have a simple enumeration of COM’s, this may be confusing at time leaving at users selecting inexistent ports or ports that simply are already in use.

With this sample, you can improve and make easy these device selections in our applications.

The main think is enumerate serial port inside our customized ‘ComboBox’, using :

My.Computer.Ports.SerialPortNames.ToArray

After when initialize our combo only need assign ‘DrawItem’ event to function with our personalized combo draw,

AddHandler ComboBox1.DrawItem, AddressOf cmbo_SerialPorts_Status

This function are adding red rectangle and “busy” text when no have availability, and green rectangle and “available” text when the port is free.

Please no doubt in contact with me if you need any other explanation or opinion about this.

 

 SerialEnum_Es

SerialEnum_en 

 

Public Class Form1
    ‘Enumerate Serial Ports on Machine
    ‘Get Serial Port availability

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        ‘Just drag & drop combobox from toolbox to form designer
        Me.ComboBox1.DrawMode = DrawMode.OwnerDrawVariable                     ‘select my own drag mode
        Me.ComboBox1.DropDownStyle = ComboBoxStyle.DropDownList                ‘aspect when drop down
        Me.ComboBox1.DataSource = My.Computer.Ports.SerialPortNames.ToArray    ‘enumerate serialports
        Me.ComboBox1.TabIndex = 0                                              ‘select first tabindex
        AddHandler ComboBox1.DrawItem, AddressOf cmbo_SerialPorts_Status       ‘draw my personal cmbo
    End Sub
   
    ‘ Draw our custom combo
    Private Sub cmbo_SerialPorts_Status( _
        ByVal sender As Object, _
        ByVal CmboItem As System.Windows.Forms.DrawItemEventArgs)

        ‘ Draw the background of the item.
        CmboItem.DrawBackground()
       
        ‘Default Values if port is available
        Dim status As String = «Available»
        Dim brush As New SolidBrush(Color.Green)
        Dim font As System.Drawing.Font = Me.Font
        Dim fontbrush As Brush = Brushes.Black
        Dim rectangle As Rectangle = New  _
            Rectangle(2, CmboItem.Bounds.Top + 2, _
                         CmboItem.Bounds.Height, _
                         CmboItem.Bounds.Height – 4)
       
        ‘Check for port availability
        Try
            ‘ If port open & close with no exception
            ‘ draw the item with default font and green rectangle
            Dim PortTest As New System.IO.Ports.SerialPort
            PortTest = My.Computer.Ports.OpenSerialPort(My.Computer.Ports.SerialPortNames(CmboItem.Index))
            PortTest.Close()
        Catch ex As Exception
            ‘ If port is not available
            ‘ draw the item with italic & strikeout font and red rectangle
            brush = New SolidBrush(Color.Red)
            status = «In Use»
            font = New Font(FontFamily.GenericSansSerif, Me.Font.Size, FontStyle.Italic Xor FontStyle.Strikeout)
            fontbrush = Brushes.DimGray
        End Try

        ‘fill combo item rectangle
        CmboItem.Graphics.FillRectangle(brush, rectangle)
        ‘write text with actual port status for this item
        CmboItem.Graphics.DrawString( _
            My.Computer.Ports.SerialPortNames(CmboItem.Index) + » – « + status, _
            font, _
            fontbrush, _
            New  _
                    RectangleF(CmboItem.Bounds.X + rectangle.Width, _
                               CmboItem.Bounds.Y, _
                               CmboItem.Bounds.Width, _
                               CmboItem.Bounds.Height) _
        )
        ‘ Draw focus rectangle when mouse are over an item.
        CmboItem.DrawFocusRectangle()
    End Sub
End
Class

System.IO.Ports.SerialPort – Conversiones y Codificaciones.

Considerando interesante y curiosa la cuestión planteada por Favi, me complace compartir con vosotros la resolución.
—- Pregunta ——————————–
Estoy actualizando un programa hecho en vb versión 3 que utiliza un control ‘mscomm’ de 16 bits. Ahora en net lo he transformado utilizando ‘System.IO.Ports.serialport’.
El problema en concreto es, que los caracteres que recibo del buffer se me quedan el más alto al transformarlo a hexadecimal en 3F cuando en la versión vb3 en la misma lectura me indica 8D.
Es decir como si el juego de caracteres interno del objeto ‘serialport’ fuera menor que el juego de caracteres del control ‘mscomm’ de la versión vb 3. Con el control ‘mscomm’ de vb3 se pueden leer caracteres que llegarían 255 decimal FF hexadecimal pero con el ‘serialport’ de net los deja capados en 3F no me interpreta caracteres de valor superior.
No si puede ser, que no utiliza un juego de caracteres extendido o algo así ?
Utilizo el ‘serialport.readexisting’ para recuperar las cadenas

—- Respuesta J  ——————————–
SerialPort1.Encoding = System.Text.Encoding.Default

Por defecto y supongo que aunque discutible la decodificación de los bytes recibidos se realiza utilizando la primera pagina de la tabla de caracteres ASCII, suponiendo que si se utilizan 8 bits para los datos, deberíamos utilizar ambas. Para poder representar el juego de caracteres de ambas paginas deberemos asignar ‘Encoding.Default’ al encoding de nuestro puerto serie.

No dudéis en continuar esta conversión si la consideráis interesante.
Pep LLuis

ChonChoff u otramente conocidos xOn xOff

Como ya os he contado en diversas ocasiones y con cierto tono de humor os dejo este corto.

Creo que los puertos serie y los puertos paralelo son de las pocas electrónicas incombustibles que han sobrevivido a los tiempos. Es evidente que como cualquier otra electrónica al servicio de las comunicaciones ha evolucionado con el tiempo, adaptándose y aumentado prestaciones, aunque esto último parezca mentira pues estamos hablando de comunicaciones a bajas velocidades. Para los que consideréis que estoy exagerando, os contare que soy uno de los privilegiados que hace mas de 25 años tuve en las manos un “Zapatofono”, el tal zapatofono no era más que un adaptador del auricular/micrófono del teléfono, que a través de unas ventosas retransmitía los sonidos recibidos en el micro demodulándolos, para posteriormente generar las respectivas ondas del espectro audible modulandolas por el auricular para que el otro extremo las demodulara. Esto claro que se convirtió en el precursor de lo que hasta ahora hemos conocido como MODEM’s. Lo increíble es que la señal entre el teléfono y el modem se transmitía por el sonido generado o captado, o sea analógicamente y su velocidad rascaba el vértigo de 300Bauds… que no Bits por segundo J, que distan mucho de las velocidades de hoy en día… En fin…

En aquellos tiempos existían una serie de chips que implementaban por ‘hardware’ la funcionalidad de UART, pudiendo transmitir y procesar datos recibidos a través de un interface serie, pero sin posibilidad de implementar ninguna pila que les permitiera tener una cierta programabilidad por software. Llegado este punto entenderéis que no disponían de un buffer de recepción o proceso ilimitado, este era el caso de teletipos, impresoras o ese tipo de dispositivos que simplemente solo eran receptores de información. El problema surgía cuando por esos misterios de lo asíncrono los bytes enviados por el transmisor llegaban con una cadencia superior a la que el dispositivo era capaz de procesar. Es evidente que ello provocaba un desbordamiento de los ‘buffers’ con la consecuente pérdida de información, así que al enviar “donde dije diego” a la impresora o el dispositivo en cuestión, solo recibía… por poner un ejemplo “dodidi”.

En este mundo de avispados ingenieros enseguida conseguimos la solución en la especificación del RS232 incluimos las señales RTS/CTS con ellas podríamos conseguir controlar el flujo de información entre el DCE (Data Computer Equipment) y el DTE (Data Terminal Entry) de forma que cuando el DTE estaba agotando la capacidad en su ‘buffer’ de recepción ponía la señal de “Listo para recibir” o CTS en Bajo de esa forma l DCE sabia debía detener el envió de información para evitar su perdida. En el momento en que el DTE estaba aliviado volvía a levantar la señal CTS para que el DCE pudiera restablecer el envió de información. Simultáneamente el DCE debería adaptar su señal RTS o “Petición de envío” para que el DCE supiera de las intenciones de este ultimo..

Todo era un mar de felicitaciones, pues trabajando estas señales de “hardware” podíamos controlar el flujo, hasta que alguien se dio cuenta de que determinados dispositivos carecían de la posibilidad de trabajar estas señales, pues implementaban el nivel más bajo de la especificación que es cablear los pines del 2 al 3 en un extremo y del  3 al 2  en el otro así como cablear la masa. En esta configuración de ‘hardware’ continuábamos con el mismo problema y la única posibilidad que disponíamos era la implementación de ese control de flujo a través de protocolo por “software” … e volia… apareció el nuestro entrañable xON xOFF.
Cuando el dispositivo estaba a punto de desbordarse enviaba el código xOff, ello indicaría al transmisor la eminente necesidad de detenerse en el envío de información, una vez desahogado volvería a mandar un xOn con lo que el transmisor continuaría mandando la información pendiente.

Aunque xOn e xOff corresponden concretamente a un carácter ASCII, su implementación acostumbra a ser por protocolo, con lo que no es necesario perpetuar acción alguna. Me explico si en nuestro “apretón de manos” o “handshaking” configuramos la opción de xOn/xOff, automáticamente la operación de escritura se detendrá al recibir un “DC3” sin necesidad de que nuestra aplicación tenga que efectuar ninguna opción adicional, igualmente al recibir un “DC1” reanudara automáticamente el envío de los ‘bytes’ del ‘buffer’ pendientes de ser enviados.

Codigo

Leyenda

Teclado

ASCII

Codigo Hex

Codigo DEC

xOff

Pausar

CTRL+S

DC3

0x13

19

xOn

Reanudar

CTRL+Q

DC1

0x11

17

 

Finalmente para los que en su dia trabajábamos detrás de un terminal de un Cyber, podremos recordar la pulsación de [CTRL+S] / [CTRL+Q], que nos permitían controlar cuando y como deteníamos el paso de las líneas lanzadas desbocadamente desde el sistema, para con ello darnos un respiro y tener tiempo de leerlas… sin ir más lejos estábamos utilizando xOn/xOff.

Los mas incrédulos podrán contrastar esta información, fijaros si fue importante que aun hoy en día, se encuentra implementada en la consola del sistema pues su salida virtualiza un TTY y por supuesto aun hoy en día mantiene la funcionalidad xOn / xOff… para rememorar viejos tiempos podéis ejecutar una instancia del “símbolo de sistema”, buscaros un archivo ‘log’ con el suficiente tamaño para que ocupe varias pantallas y copiároslo al directorio en el que trabajéis, finalmente lanzar la orden “C:\Type NombreDelArchivo.log”… manteniendo el CTRL pulsado y alternando S y Q veréis como el desplazamiento de líneas recibidas se detiene y reanuda al ritmo que marquéis con el xOn y xOff… que sin dudar aun existen!

Espero que esto venga en primer lugar a distraeros y en segundo lugar a responder alguna que otra cuestión que desde la opción de [Contacto] recibo a menudo.

Por cierto ¿Cómo se implementa en System.IO.Ports?

        Dim SerialPort1 As New IO.Ports.SerialPort
        SerialPort1.Handshake = IO.Ports.Handshake.XOnXOff

Cuidaros mucho.

Leer los ceros y unos de un micro-controlador

En muchas situaciones, sobre todo cuando hablamos de PIC’s se plantean cuestiones en torno como manejar un simple aplicación de intercambio de datos utilizando el IO.Ports.

A falta de un ejemplo concreto os facilito este código, aunque en anteriores Post’s podéis aprender algunas observaciones y consideraciones a tener en cuenta.

El siguiente ejemplo, envía una petición al micro-controlador cada 100ms, siempre y cuando no este ocupado esperando una respuesta. La respuesta se compone del Byte enviado mas un ‘0’ o un ‘1’, por lo tanto después de identificar la respuesta añadiremos el estado a un ‘Label1’ que acumulara todas las respuestas o dicho de otro modo todos los Ceros y Unos J

CerosYUnos

No dudéis en seguir la conversación si os interesa discutir algún aspecto en concreto. Pero como siempre estos ejemplos son muy ligeros, pretendiendo ser una idea inicial para demostrar que es posible, aunque distan mucho de ser la solución completa o ideal.

Saludos,
Pep Lluis,

Public Class Form1
    Private PuertoSerie As New IO.Ports.SerialPort
    Private Temporizado As New System.Timers.Timer
    Private IOEncurso As Boolean = False
    Delegate Sub ActualizarTexto(ByVal Texto As String)

    Private Sub Form1_Load(….) Handles MyBase.Load
        Temporizado.Interval = 100
        ‘cada 100ms ejecutar la funcion TareasTemporizadas
        AddHandler Temporizado.Elapsed, AddressOf TareasTemporizadas
        ‘Abrir el puerto serie
        PuertoSerie = My.Computer.Ports.OpenSerialPort(«COM1», 115200, IO.Ports.Parity.Even, 7, IO.Ports.StopBits.Two)
        ‘ejecutar la funcion recepcion al recibir datos
        AddHandler PuertoSerie.DataReceived, AddressOf Recepcion
        Temporizado.Start()
    End Sub

    ‘Buffer de recepcion
    Private Dato(1) As Byte
    Sub Recepcion()
        Try
            ‘Añadir la recepcion actual al buffer           
            If PuertoSerie.BytesToRead > 1 Then
                ‘Leer dos bytes
                PuertoSerie.Read(Dato, 0, 2)
                ‘Verificar que el primero identifica inicio
                Select Case Chr(Dato(0))
                    Case «R»
                        ‘añadir el status leido (0 o 1) al Label
                        Actualizar_Etiqueta(Label1.Text + Chr(Dato(1)))
                    Case Else
                        ‘descartar el contenido del buffer
                        ‘pues el dato(0) no corresponde a inicio
                        PuertoSerie.DiscardInBuffer()
                End Select
                ‘Dar por finalizada la respuesta
                IOEncurso = False
            End If
        Catch ex As Exception
            MessageBox.Show(ex.Message)
            IOEncurso = False
        End Try
    End Sub
   
    ‘Utilizamos el INVOKE de LABEL1 Para evitar error..
    ‘ Operación no válida a través de subprocesos:
      Se tuvo acceso al control ‘Label1’ desde
      un subproceso distinto a aquel en que lo creó.
    Private Sub Actualizar_Etiqueta(ByVal [texto] As String)
        ‘Mostrar los bytes recibidos en el Label1       
        If Me.Label1.InvokeRequired Then
            Dim delegado As New ActualizarTexto(AddressOf Actualizar_Etiqueta)
            Me.Invoke(delegado, New Object() {[texto]})
        Else
            Me.Label1.Text = [texto]
        End If
    End Sub
   
    ‘Controlar el envio de peticiones
    ‘ en nuestro caso cada 100ms
    Sub TareasTemporizadas()
        ‘Solo enviar una nueva peticion
        ‘si se ha completado la anterior
        If Not IOEncurso Then
            PuertoSerie.Write(«R»)
            IOEncurso = True
        End If
    End Sub
End
Class

Para finalizar y dar otros puntos de vista, según las escuelas pueden utilizarse formas tales como:

Dim PuertoSerie As New IO.Ports.SerialPort
PuertoSerie =
My.Computer.Ports.OpenSerialPort(«COM1»)
….

….

PuertoSerie.Write(«Peticion»)
System.Threading.Thread.Sleep(100) 
‘Dar tiempo al dispotivo
Dim Resultado() As Byte(Longitud)
PuertoSerie.Read(Resultado, 0, Longitud, 10000)

 

  ‘ donde 10000 es el timepo predefinido para
  ‘ que el puerto serie dispare una excepcion

  ‘ por tiempo de expera excedido

A pesar de que en mi opinión, utilizar ‘Sleeps’ y técnicas de esperar un fuera de tiempo no cumple con las expectativas de un programa que se precie. Pero esto ultimo no deja de ser una opinión muy personal.