Electrónica y programación para Microcontroladores.

Libros técnicos para electrónica programable.

Email
Contactanos en:

consultas@firtec.com.ar

Arduino

Nextion es probablemente una de las mejores opciones para crear proyectos con electrónica, podemos hacerlas funcionar con cualquier microcontrolador que disponga de un puerto serial. Para crear una interfaz gráfica en una pantalla Nextion usaremos el editor Nextion, un software provisto por el propio fabricante que hace la tarea del diseño realmente simple.
Una vez que tenemos todo los elementos de la interfaz desplegados en la pantalla se envía la programación a la propia pantalla usando una simple conexión serial.
Este editor de Nextion es la mejor solución, en realidad casi la única para crear proyectos con estas pantallas inteligentes.
Lamentablemente solo existe en versión para Windows que se descarga a través del enlace oficial de Nextion.
Proponemos diseñar la siguiente interfaz gráfica.
La pantalla dispone solamente de 4 pines. Dos de ellos son de alimentación (cable rojo y negro) y los otros dos son de recepción para el envío de datos por la conexión serial, recepción cable amarillo y transmisión cable azul, para conectar la pantalla a Raspberry PI estos cables se deben conectan cruzados TX con el cable amarillo y RX con el cable azul. 
La pantalla se programa por medio de una conexión serial desde el propio editor Nextion, para programar la pantalla se debe desconectar de Raspberry y conectarla al computador mediante un adaptador USB-RS232.
Cuando queremos mostrar un dato en la pantalla solo “apuntamos” al componente de la pantalla donde queremos enviar los datos y enviamos la información que se me mostrará donde se indicó, en este ejemplo hay una ventana donde se muestran datos de conversión que se identifica como n0 y que tiene una propiedad que se llama val. Solo debemos apuntar al objeto y su propiedad para mostrar los datos.

Sin embargo los mensajes están estructurados en un protocolo propio que se debe conocer para poder dialogar con la pantalla, los mensajes tienen el siguiente formato 65000501FFFFFF donde el número 65 indica que no hay errores, el siguiente número es la página (una interfaz gráfica puede tener varias páginas), luego tenemos el ID del componente que ha enviado el mensaje, luego el evento y por último tres bytes con FF que son los indicativos de fin de trama.
Por ejemplo imagine que quiere enviar datos al panel n0 desde Python escribimos lo siguiente:

puerto.write(b"n0.val=" + str(dato).encode() + b"\xFF\xFF\xFF")

El indicativo b dice que estamos enviando una cadena de bytes, en dato está el valor a mostrar y finalmente los tres bytes de EOF.
Si quiero recibir un evento desde la pantalla tengo que analizar la trama para saber desde cual página, cual elemento y que acción me esta llegando.
Como en este ejemplo solo tenemos una página y un solo botón las cosas son bastantes simples solo basta el siguiente código para saber cuando el botón envía mensajes y encender un LED según el caso.

datos_nextion = binascii.hexlify(puerto.readline())
mensaje = str(datos_nextion) 
for indice in range(len(mensaje)): 
          if indice > 3:
                        if mensaje[7] == "3" and bandera == 0: 
                                    bandera = 1 
                                    GPIO.output(16, 0) 
                       else:
                                    GPIO.output(16, 1) 
                                    bandera = 0 

El código completo para leer datos de un conversor MCP3201 y mostrarlos en un panel, también se detecta la acción de un botón para cambiar el estado de un LED conectado a un pin del puerto Raspberry.

3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
import binascii
import time
import spidev
from serial import Serial
import RPi.GPIO as GPIO # Modulo para gestionar los pines GPIO
GPIO.setwarnings(False) # Ignora las advertencias
GPIO.setmode(GPIO.BCM) 	# Los pines serán referidos como Broadcom
spi = spidev.SpiDev()
spi.open(0, 0)
spi.max_speed_hz = 7629
time.sleep(1)
GPIO.setup(16, GPIO.OUT)# Pin 16 será salida
GPIO.output(16, 1)
 
puerto = Serial("/dev/ttyS0", baudrate=9600, timeout=0.2)
if puerto.isOpen() == False:
    puerto.open()
 
puerto.flushInput()
puerto.flushOutput()
bandera = 0
 
 
def Conversor():  # Lee el conversor MCP3201
    
    adc = spi.xfer2([0, 0])
    hi = (adc[0] & 0x1F);
    low = (adc[1] & 0xFe);
    dato = (hi << 8) | low;
    puerto.write(b"n0.val=" + str(dato).encode() + b"\xFF\xFF\xFF")
    
while 1:
    Conversor()
    try:   # Recibe los datos desde la pantalla Nextion     
        datos_nextion = binascii.hexlify(puerto.readline()) 
        mensaje = str(datos_nextion)        # Procesa los datos recibidos
        for indice in range(len(mensaje)):  # Recorre los bytes del mensaje
            if indice > 3:                  # Pantalla envió un mensaje?
                if mensaje[7] == "3" and bandera == 0:  # Mensaje del objeto?
                    bandera = 1             # Avisa que el LED está apagado
                    GPIO.output(16, 0)      # Pin 16 pasa a nivel bajo
                else:
                        GPIO.output(16, 1)  # Pin 16 pasa a nivel alto
                        bandera = 0         # Avisa que el LED está encendido
 
        puerto.flushInput()
        puerto.flushOutput()
        
    except (KeyboardInterrupt, SystemExit):
        puerto.close()
        spi.close()
        GPIO.cleanup()
        raise

En este ejemplo no interesa la página puesto sabemos que es 0 y el botón tiene el ID 3 (podrías ser cualquier número) que también sabemos viene en el casillero 7 de acuerdo a como Python 3 ensambla la trama de recepción.
El resultado final de la aplicación en funcionamiento es el siguiente:

Todo el manejo de pantallas Nextión lo encontrará en nuestros Libros Técnicos.

Si se estira una tira de metal conductor, se volverá más delgada y más larga, ambos cambios resultan en un aumento de la resistencia eléctrica de un extremo a otro. Por el contrario, si una tira de metal conductor se coloca bajo fuerza de compresión (sin pandeo), se ensanchará y acortará. Si estas tensiones se mantienen dentro del límite elástico de la tira de metal (de modo que la tira no se deforme permanentemente), la tira se puede utilizar como elemento de medición de la fuerza física, es decir que la cantidad de fuerza aplicada se puede conocer al medir el cambio resistencia eléctrica.
La mayoría de estos sensores son bastante pequeños apenas unos milímetros montados sobre un brazo metálico  que es el que recibe la fuerza física, su aspecto es como el mostrado en la imagen, observe que tiene una flecha indicadora de hacia donde se debe ejercer la fuerza a medir.

Las resistencias típicas de estas celdas de carga oscilan entre 30 Ω y 3 kΩ (sin tensión). Esta resistencia puede cambiar sólo una pequeña fracción de un porcentaje para todo el rango de fuerza, dadas las limitaciones impuestas por los límites elásticos del material de la propia celada. Fuerzas lo suficientemente grandes como para inducir cambios de resistencia mayores deformarían permanentemente el material de la celda y / o los propios conductores del sensor, arruinando así el dispositivo de medición. Por lo tanto, para utilizar la galga extensiométricas como un instrumento práctico, debemos medir cambios extremadamente pequeños en la resistencia con alta precisión.
Una precisión tan exigente requiere un circuito de medición puente. A diferencia del puente de Wheatstone para mantener un estado de equilibrio, un circuito puente para celdas de carga indica la deformación medida por el grado de desequilibrio en una de sus resistencias y utiliza un voltímetro de precisión en el centro del puente para proporcionar una medición precisa de ese desequilibrio. Es normal hablar de un conversor de 24 bits como mínimo para poder medir estas pequeñas variaciones eléctricas en el puente.
Uno de los problemas con los puentes para celdas de cargas son las variaciones de temperatura, es por esto que normalmente un puente para celdas de carga tienen mínimo dos a cuatro celdas para compensar estos corrimientos por temperatura.
La temperatura actúa sobre todos los elementos del puente por lo tanto su efecto es despreciable.


Interfaz de celda de carga HX711.

Este módulo es una interfaz entre las celdas de carga y el procesador, permitiendo poder leer el peso de manera sencilla. Internamente se encarga de la lectura del puente wheatstone formado por la celda de carga, convirtiendo la lectura analógica a digital con su conversor A/D interno de 24 bits.
Es muy utilizado en procesos industriales, sistemas de medición automatizada e industria médica.
Se comunica mediante 2 pines (Clock y Data) de forma serial.

Ejemplo de uso con Raspberry PI. 
En el siguiente ejemplo vamos a leer el peso colocado en una celda de carga con capacidad de medir hasta 10Kg sin embargo como se puede ver, podemos discriminar gramos sin ningún problema.

La precisión puede ser ajustada para lecturas mas exactas sin embargo como ejemplo de funcionamiento consideramos que es mas que suficiente.
El código está escrito para Python 3 y es el siguiente.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
#!/usr/bin/env python3
import RPi.GPIO as GPIO  # importa GPIO
from hx711 import HX711  # importa la clase HX711
GPIO.setwarnings(False)  # elimina los warnings
 
try:
    GPIO.setmode(GPIO.BCM)  # Pines GPIO en numeración BCM
    # Crea un objeto hx que represente el chip HX711 real
    # Los parámetros de entrada obligatorios son solo 'Pin_Dato' y 'PD_sck'
    hx = HX711(dout_pin=21, pd_sck_pin=20)
    # Medir la tara y guardar el valor como compensación para el canal actual
    # y ganancia seleccionada. Eso significa canal A y ganancia 128
    err = hx.zero()
    # Verifica si todo está correcto
    if err:
        raise ValueError('La tara no se puede definir.')
 
    reading = hx.get_raw_data_mean()
    if reading:     # Verificar si el valor correcto 
                    # ahora el valor está cerca de 0
        print('Datos restados por compensación pero todavía no convertidos a unidades:',
              reading)
    else:
        print('Dato invalido', reading)
 
    # Para calcular la tasa de conversión a algunas unidades, en en este caso gramos,
    # Se debe partir de un peso conocido para ajustar.
    input('Coloque un peso conocido en la balanza y luego presione Enter')
    reading = hx.get_data_mean()
    if reading:
        print('Valor medio de HX711 restado para compensar:', reading)
        known_weight_grams = input(
            'Escriba cuántos gramos eran y presiona Enter: ')
        try:
            value = float(known_weight_grams)
            print(value, 'gramos')
        except ValueError:
            print('Entero o flotante esperado y tengo:',
                  known_weight_grams)
 
       
        # establecer la relación de escala para un canal en particular y una ganancia
        # utilizada para calcular la conversión a unidades. El argumento requerido es solo
        # una relación de escala. Sin argumentos 'canal' y 'ganancia_A' establece
        # la relación entre el canal actual y la ganancia.
        ratio = reading / value   # calcular la relación para el canal A y la ganancia 128
        hx.set_scale_ratio(ratio) # Determina la proporción para el canal actual
        print('Relación de peso establecida.')
    else:
        raise ValueError('No se puede calcular el valor medio . ERROR', reading)
 
    # Leer datos varias veces y devolver el valor medio
    # restado por compensación y escalado a las 
    # unidades deseadas. En este caso en gramos.
    print("Ahora, leeré datos en un bucle infinito. Para salir presione 'CTRL + C'")
    input('Presione Enter para comenzar a leer')
    #print('El peso actual en la balanza en gramos es: ')
    while True:
        print("El peso actual en gramos es de %.2f" % (hx.get_weight_mean(20)))
 
except (KeyboardInterrupt, SystemExit):
    print('Chau :)')
 
finally:
    GPIO.cleanup()

Archivos disponibles para su descarga en el siguiente link.
 

 

 La Pantalla OLED de 1.3 pulgadas con el controlador SSH1106 de 128x64 píxeles son de uso común con Arduino sin  embargo también las podemos usar con Raspberry PI. 
Si bien estas pantallas son muy pequeñas también son muy visibles dado su alto contraste incluso a plena luz del día. 
El driver interno es un SSH1106 que se comunica por I2C (también existen por SPI). Internamente todo el conjunto funciona a 3,3V pero se han acoplado tanto la alimentación como los pines de entrada para funcionar perfectamente a 5V lo que lo hace ideal para utilizar con cualquier microcontrolador de 5V.
El consumo general depende en gran medida de cuantos píxeles están encendidos, pero el consumo medio ronda los 80mA.
El ejemplo propuesto es bastante simple, obtiene algunos datos del estado interno de la placa Raspberry y los muestra en la pantalla.
Para hacer funcionar la pantalla será necesario cargar una biblioteca que se encarga de resolver todos los problemas de hardware y su acople con Raspberry PI a través del bus I2C. 
Para instalar el correspondiente driver escribimos directamente en la terminal lo siguiente:

sudo -H pip3 install --upgrade luma.oled

Para verificar su funcionamiento podemos ejecutar el siguiente sript Python:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
#!/usr/bin/env python
# -*- coding: utf-8 -*-
 
from luma.core.interface.serial import i2c
from luma.core.render import canvas
from luma.oled.device import ssd1306, ssd1325, ssd1331, sh1106
from time import sleep
 
import os
import sys
import time
import psutil
from pathlib import Path
from datetime import datetime
 
 
if os.name != 'posix':
    sys.exit('{} platform not supported'.format(os.name))
 
from demo_opts import get_device
from luma.core.render import canvas
from PIL import ImageFont
 
 
serial = i2c(port=1, address=0x3C)
device = sh1106(serial, rotate=0)
 
font_path = str(Path(__file__).resolve().parent.joinpath('fonts', 'C&C Red Alert [INET].ttf'))
font2 = ImageFont.truetype(font_path, 12)
 
def bytes2human(n):
   
    symbols = ('K', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y')
    prefix = {}
    for i, s in enumerate(symbols):
        prefix[s] = 1 << (i + 1) * 10
    for s in reversed(symbols):
        if n >= prefix[s]:
            value = int(float(n) / prefix[s])
            return '%s%s' % (value, s)
    return "%sB" % n
 
def mem_usage():
    usage = psutil.virtual_memory()
    return "Memoria: %s %.0f%%" \
        % (bytes2human(usage.used), 100 - usage.percent)
 
def disk_usage(dir):
    usage = psutil.disk_usage(dir)
    return "SD:  %s %.0f%%" \
        % (bytes2human(usage.used), usage.percent)
 
with canvas(device) as draw:
        draw.text((5, 0), "Raspberry PI Status", fill="white")
        draw.text((5, 6), "-------------------", fill="white")
        draw.text((0, 16), mem_usage(), font=font2, fill="white")
        draw.text((0, 30), disk_usage('/'), font=font2, fill="white")
        draw.text((9, 50), "www.firtec.com.ar", fill="white")
 

Con el siguiente resultado.

Es importante estar seguro de cual es el controlador de la pantalla, puede ser SSD1306 o SH1106, no son exactamente iguales en lo que es el manejo de memoria interna, observe que en el programa se lee device = sh1106(serial, rotate=0) donde se especifica el controlador de pantalla y en este caso no se rota la pantalla. La rotación de pantalla puede ser 90, 180 o 360 grados, puede consultar la ayuda de la biblioteca y los ejemplos que se descargan con el propio driver.
Puede ser necesario descargar "psutil" con  sudo -H pip3 install psutil  esto depende de la instalación que tiene de Python3

 

 

Los robots por software pueden resultar muy útiles a la hora del desarrollo de sistemas de control, mediante el uso de un Bot vamos a iniciar un chat por Telegram con una placa electrónica para leer datos de un sensor BME280 y controlar el estado de un pin.
Telegram fué anunciada oficialmente en el 2013, está enfocada a la mensajería instantánea, el envío de varios archivos y la comunicación en masa, la aplicación se parece mucho a WhatsApp con algunas funciones extras.

La idea es conectar ESP32 programado con el IDE de Arduino para que envíe mensajes de chat a Telegram, también se puede hacer lo mismo para WhatsApp sin embargo debido a las bibliotecas disponibles en este momento, es mas simple conectar con Telegram.
Para ensamblar el proyecto vamos a necesitar algunas bibliotecas siendo necesario que la versión de ArduinoJson encargada de manejar los textos de los mensajes enviados hacia y desde Telegram sea versión 5.x ya que versiones superiores no funcionan con la biblioteca de Arduino para Telegram.   

  • ArduinoJson-5.x.x.
  • Universal-Arduino-Telegram-Bot.
  • Bibliotecas para programar ESP32.

NOTA:
Para agregar las bibliotecas necesarias para el manejo de ESP32 con Arduino vamos a Archivos > Preferencias > Gestor de URLs Adiciones de Tarjetas y agregamos la siguiente línea: https://dl.espressif.com/dl/package_esp32_index.json