Para quienes trabajamos en el mundo de la electrónica y quienes la estudiamos, en algún momento nos hemos visto en la necesidad de dotar nuestros proyectos con alguna capacidad de comunicación, es decir, nos hemos visto en la necesidad de interactuar con ellos de alguna manera (normalmente a través de una computadora) y poder realizar captura de datos, o disparar acciones específicas entre otras cosas. La comunicación serial es para mí, el tipo de comunicación más simple que podríamos aplicar entre dos dispositivos, también están otras muy comunes y ampliamente extendidos y aplicados que veremos luego, como el I^{2}C o el SPI, entre otros.

baby_orangutan

A continuación te dejo un enlace a este sitio web donde podrás encontrar una gran cantidad de información sobre lo que es la comunicación serial, lo tipos de comunicación e incluso los circuitos electrónicos necesarios para este tipo de comunicación, y una gran cantidad de información relevante para quienes no conocer los protocolos o quieren aprender más.

En esta oportunidad vamos a ver como realizar la configuración mínima de la comunicación serial con Python utilizando el módulo PySerial (aquí te muestro cómo instalarlo).

Creando un Objeto Serial

El título puede sonar extraño, lo que quiero decir es que a continuación, utilizando el módulo serial de Python vamos a instanciar un objeto y vamos a conocer un poco sobre sus parámetros y los valores que éstos pueden recibir.

El constructor del objeto presenta los siguiente parámetros, según la documentación oficial que se muestra en este sitio.

class serial.Serial

__init__(port=None, 
                 baudrate = 9600, 
                 bytesize = EIGHTBITS, 
                 parity = PARITY_NONE, 
                 stopbits = STOPBITS_ONE, 
                 timeout = None, 
                 xonxoff = False, 
                 rtscts = False, 
                 write_timeout = None, 
                 dsrdtr = False, 
                 inter_byte_timeout = None)

A continuación indicaré una breve descripción de los 6 parámetros más importantes en el constructor de nuestro objeto serial, esta descripción es breve y en los casos pertinentes vas a encontrar un enlace a algún recurso que te explicará con más profundidad el concepto involucrado.

  • port:    recibe una cadena (string) indicando el nombre del puerto serial, por ejemplo '/dev/ttyUSB1' en sistemas GNU/Linux o nombres como 'COM1' en Windows, el valor por defecto de este parámetro es None.
  • baudrate:    Indicamos la velocidad de transferencia en baudios (básicamente la cantidad de bits por segundo), por defecto su valor es 9600 como se mostró en el constructor del objeto. Los valores posibles para éste pueden ser: 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800, 9600, 19200, 38400, 57600, 115200.
  • bytesize:        

 

Enviando Datos por el Puerto Serial.

El siguiente script configura un objeto para abrir el puerto serial ‘ttyUSB0‘ (donde tengo conectado un Arduino), lo configuramos para que: el dato enviado tenga un frame de 8 bits, se no se utiliza paridad, se utiliza solo un bit de parada y la velocidad de transferencia será de 9600 baudios. El script intenta (try) abrir el puerto serial ‘ttyUSB0‘ que hemos configurado, si la apertura del puerto es exitosa, entonces se envía el caracter ‘a’ y un segundo después se envía el caracter ‘b’ ya que en el programa que corre el microcontrolador con estos dos caracteres enciendo y apago una luz.

#!/usr/bin/python3
import serial
import time

# Arduino official doc:https://www.arduino.cc/en/serial/begin
# by default Arduino set 8 bit frame, parity none and 1 stop bit

puerto   = serial.Serial(port = '/dev/ttyUSB0',
                         baudrate = 9600,
                         bytesize = serial.EIGHTBITS,
                         parity   = serial.PARITY_NONE,
                         stopbits = serial.STOPBITS_ONE)

try:
    puerto.write('a'.encode())
    time.sleep(1)
    puerto.write('b'.encode())
    puerto.close()

except serial.SerialException:
    print('Port is not available') 

except serial.portNotOpenError:
    print('Attempting to use a port that is not open')
    print('End of script') 


Reciviendo Datos por el Puerto Serial.

Teniendo en cuenta las funciones que nos proporciona la API del módulo serial de python y el ejemplo anterior donde enviamos dos caracteres, ahora vamos a ver mediante otro script un ejemplo de cómo recibir datos de forma adecuada utilizando el mismo módulo serial.

La propiedad in_waiting del puerto es sumamente importante ya que nos indica cuántos bytes están disponibles para ser leídos desde el buffer (es decir, cuántos bytes han sido recibidos).

El método read(size) nos sirve para capturar los datos presentes en el buffer, el parámetro que recibe es un valor entero que indica la cantidad de bytes que queremos que sean leídos, es importante recordar que read() es una función bloqueante, lo que quiere decir que se puede quedar esperando indefinidamente a que hayan datos disponibles y mantener bloqueada la ejecución de nuestro programa (ésto puede llegar a ser un grave problema), es en esta situación donde son relevantes las propiedades in_waiting y timeout, la primera para indicar exactamente la cantidad de bytes que están disponibles para su lectura y la segunda para indicar el tiempo máximo de espera que puede tomar el método read(size) en caso de que no hayan datos para ser leídos, es decir, timeout=1 indica que como máximo el programa se  bloquearía (se detendría a esperar) máximo por un segundo, la función read() retornará lo que haya alcanzado a capturar en ese tiempo y luego el programa continuará su ejecución.

Vamos a introducir dos métodos más, el primero es reset_input_buffer( ) y se encarga de limpiar (borrar) el contenido presente en el buffer de entrada, esto es importante realizarlo en primera instancia porque puede que en este buffer contenga lo que llamaríamos basura y por lo tanto podríamos tener resultados inconsistentes (porque no tuvimos en cuenta que había datos basura ¡ay que limpiar antes de trabajar!). El segundo método es reset_output_buffer( ) es el que se encarga de limpiar el buffer de salida, es decir antes de enviar datos, sirve para limpiar la basura y evitar que datos indeseados se envíen al dispositivo receptor (cuidado porque según la documentación, éste método aborta la transacción que se esté llevando a cabo, por eso llámalo antes que a write(data)).

 


Esto es todo por ahora, este artículo probablemente sea actualizado pronto, sin embargo dejaré esta información inicial en caso de que te resulte útil.

Author: Julio C. Echeverri M.

Anuncios