Electrónica y programación para Microcontroladores.

Cursos técnicos para electrónica programable

Mapa
Estamos en

Urquiza 1695, Entre Ríos, Gualeguaychú

Email
Contactanos

consultas@firteconline.com.ar

Arduino

 En ocasiones puede ser necesario llevar un historial de los datos de un sensor, el ejemplo propuesto (parte del material de estudio de nuestros cursos) lee los datos de un sensor DHT22 y mediante el puerto UART a 9600 baudios se conecta con un enlace LORA. Este los transmite a una placa Raspberry PI donde se ejecuta MariaDB, el servidor web Apache y PHP. En lugar de Raspberry PI podríamos tener un simple computador sin embargo para no esclavizar un computador en una tarea redundante hemos decidido ocupar una placa Raspberry.
El microcontrolador PIC ha sido programado con MikroC para PIC y el código completo 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
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
/****************************************************************************
**  Descripción  : Lectura de temperatura y humedad con un sensor DHT22.
**  Target       : 40PIN PIC18F4620 con sensor DHT22 en pin RE0
**  Compiler     : MikroC para PIC v 7.1
**  XTAL         : 40MHZ - (XTAL 10Mhz con PLLx4)
**  NOTA         : El pin de datos del sensor se conecta al pin 8 (RE0)
**                 (Librerias C_Type, Sprintf y LCD)
*****************************************************************************/
// Pines asignados al LCD
sbit LCD_RS at LATE1_bit;
sbit LCD_EN at LATE2_bit;
sbit LCD_D4 at LATD4_bit;
sbit LCD_D5 at LATD5_bit;
sbit LCD_D6 at LATD6_bit;
sbit LCD_D7 at LATD7_bit;
sbit LCD_RS_Direction at TRISE1_bit;
sbit LCD_EN_Direction at TRISE2_bit;
sbit LCD_D4_Direction at TRISD4_bit;
sbit LCD_D5_Direction at TRISD5_bit;
sbit LCD_D6_Direction at TRISD6_bit;
sbit LCD_D7_Direction at TRISD7_bit;
 
// Conexiones del sensor
sbit DHT22_Bus_In at RE0_bit;
sbit DHT22_Bus_Out at RE0_bit;
sbit DHT22_Bus_Dir at TRISE0_bit;
 
// Variables del programa
char DHT22_Data[5] = {0, 0, 0, 0, 0};
unsigned int humedad = 0, temperatura = 0;
volatile char Dato = 0, Kbhit=0;
char temp_humedad[12];
 
/********************************************************************************
*   Esta función es el servicio de interrupción para la recepción de caracteres.
*   (En este ejemplo no se reciben datos pero si fuera el caso la función ya está
*   disponible para su implementación).
*********************************************************************************/ 
void ISR_UART() iv 0x0008 ics ICS_AUTO {
  if (PIR1.RCIF) {         // Verifica la bandera de RX
    Dato = Uart1_Read();   // Lee dato recibido
    Kbhit=1;               // Indica que se ha recibido un dato
    PIR1.RCIF=0;           // Borra bandera de interrupción
    }
  }
 
/*******************************************************
*   Esta función lee los dato desde el sensor DHT22    *
*******************************************************/
char Leer_DHT22(unsigned *humedad, unsigned *temperature) {
  char i = 0, j = 1;
  char tiempo_espera = 0;
  char sensor_byte;
  DHT22_Bus_Out = 0;
  delay_ms(100);
 
  DHT22_Bus_Dir = 1;     // Establece Bus como entrada
  DHT22_Bus_Dir = 0;     // Establece Bus como salida
  DHT22_Bus_Out = 1;     // Bus en alto por 100 milisegundos
  Delay_ms(100);         // Espera 100ms
  DHT22_Bus_Out = 0;     // Inicia señal baja min: 0.8ms, tip: 1ms, max: 20ms
  Delay_ms(2);           // Espera 2ms
  DHT22_Bus_Out = 1;     // Bus en alto
  DHT22_Bus_Dir = 1;     // Bus como entrada
 
  // Libera el bus por un tiempo min: 20us, tip: 30us, max: 200us
  tiempo_espera = 200;
  while (DHT22_Bus_In == 1) {
    Delay_us(1);
    if (!tiempo_espera--) {
      return 1;
    } //ERROR: El sensor no responde
  }
 
  // Señal de respuesta del sensor min: 75us, tip: 80us, max: 85us
  while (!DHT22_Bus_In) { // Responde en un tiempo bajo
    Delay_us(85);
  }
  while (DHT22_Bus_In) {  // Responde en un tiempo alto
    Delay_us(55);
  }
 
  i = 0; // Obtener 5 bytes
  for (i = 0; i < 5; i++) {
    j = 1;
    for (j = 1; j <= 8; j++) { // Se leen 8 bits desde el sensor
      while (!DHT22_Bus_In) {
        Delay_us(1);
      }
      Delay_us(30);
      sensor_byte <<= 1;       // Agregar el byte bajo
      if (DHT22_Bus_In) {
        sensor_byte |= 1;
        delay_us(45);
        while (DHT22_Bus_In) {
          Delay_us(1);
        }
      }
    }
    DHT22_Data[i] = sensor_byte;
  }
 
  *humedad = (DHT22_Data[0] << 8) + DHT22_Data[1];
  *temperature = (DHT22_Data[2] << 8) + DHT22_Data[3];
 
  return 0;
}
/**********************************************************
*   Esta función ajusta los valores lídos desde el sensor
*   y los muestra en la pantalla LCD
**********************************************************/
void Mostrar_Datos(unsigned humedad, unsigned temperatura) {
  char txt[15];
  float temporal_1, temporal_2;
 
  temporal_1 = humedad / 10.0;
  Lcd_Out(1,1,"Humed.:");
  sprintf(txt, "%2.1f ", temporal_1); // Formato para la humedad
  Lcd_Out(1,9,txt);
  Lcd_Chr(1,14,0x25);
 
  temporal_2 = temperatura / 10.0;
  Lcd_Out(2,1,"Temp. :");
  sprintf(txt, "%2.1f ", temporal_2); // Formato para la temperatura
  Lcd_Out(2,9,txt);
 
  // En la siguiente línea se ensambla una trama con la temperatura 
  // y humedad separados por una coma (,).
  sprintf(temp_humedad,"%2.1f,%2.1f ", temporal_2,temporal_1);
  UART1_Write_Text(temp_humedad);
  Lcd_Chr(2,14,0x43);
}
/**********************************************************
*   Esta función ajusta los valores por defecto de la
*   pantalla LCD y coloca los carteles iniciales.
**********************************************************/
void Display_Init(){
  LCD_Init();
  LCD_Cmd(_LCD_CLEAR);
  Lcd_Cmd(_LCD_CURSOR_OFF);
  Lcd_Out(1,3,"Sensor DHT22");
  Lcd_Out(2,1,"Sensor???");
  delay_ms(2000);
   LCD_Cmd(_LCD_CLEAR);
}
/**********************************************************
*  Esta es la función principal del programa.
*  Configura pines, comparadores, canales analógicos y se
*  llama al resto de las funciones.
*  También configura el funcionamiento de la UART
**********************************************************/
void main() {
  char k = 0, t;
  CMCON |=7;
  ADCON1 = 0x0f;
  Display_Init();
  UART1_Init(9600); // Configura la UART a 9600 baudios.
  INTCON.GIE = 1;
  INTCON.PEIE = 1;
  PIE1.RCIE = 1;
 
  while (1) {
    if (Leer_DHT22(&humedad, &temperatura) == 0)
      Mostrar_Datos(humedad, temperatura);
    else {
      LCD_Cmd(_LCD_CLEAR);
      Lcd_Cmd(_LCD_CURSOR_OFF);
      Lcd_Out(1,1,"ERROR en el");
      Lcd_Out(2,1,"Sensor!!!");
    }
 
    Delay_ms(1000); // Espera 1 segundo
  }
}

Para simplificar el procesamiento los datos del sensor son concatenados en una cadena con dos campos, uno para el valor de temperatura y otro para la humedad separados por una coma.
La cadena final que será transmitido por LORA se almacena en temp_humedad y la linea de código que concatena los valores es la siguiente.

sprintf(temp_humedad,"%2.1f,%2.1f ",temporal_2,temporal_1)

Del lado de Raspberry tenemos un programa en Python 3 que es el encargado de procesar los datos recibidos por LORA y también escribir los datos en la base de datos y este es su código.

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
import time			# Modulo para el manejo de tiempos
from serial import Serial	# Modulo para el manejo de la UART
import RPi.GPIO
import mysql.connector as mariadb # Conexión entre Python y la base de datos
db = mariadb.connect(host = "localhost",user = "firtec",passwd = "1234",db = "DHT22") # Credenciales
cur = db.cursor()	# Instancia para la base de datos
temperatura = 0		# Variables usadas en el programa
humedad = 0
GPIO.setwarnings(False) # Ignora las advertencias
GPIO.setmode(GPIO.BCM) 	# Los pines serán referidos como Broadcom
 
puerto = Serial("/dev/ttyS0", baudrate=9600, timeout=0.2) # Configura la UART en Raspberry PI
 
if puerto.isOpen() == False:	# El puerto esta en uso?
    puerto.open()
 
puerto.flushInput()
puerto.flushOutput()
datos_viejos = 0    
while 1:   
    try: 
        datos_lora= puerto.readline().decode('utf-8').rstrip()
        
        if (datos_lora != ''):
            if (datos_viejos != datos_lora):
                datos_viejos = datos_lora
                temperatura = datos_lora.split(",")[0]	# Separa los campos usando el separador (,)
                humedad = datos_lora.split(",")[1]
                print ('Datos del PIC & Lora:')
                print (datos_lora)
                print ('========================')
                try:		# Accede la base de datos escribiendo los datos en la tabla “sensor” 
                    cur.execute("""INSERT INTO sensor(Temperatura, Humedad) VALUES(%s, %s)""" %
                            						(temperatura, humedad))
                    db.commit()
                except:
                    db.rollback()
                       
    except (KeyboardInterrupt, SystemExit):
        puerto.close()
        GPIO.cleanup()
        raise

Para poder acceder a los datos desde cualquier computador en la red necesitamos de un sitio web con PHP bajo el control del Apache. 

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
<html>
 <head>
 <title>DHT22</title>
 </head>
 <body>
 <FONT COLOR = "teal">
 <H1 align="center">Sensor DHT22 + PIC con PHP</h1>
</FONT>
 <H5 align="right">by. Firtec Argentina</h5>
<hr size="2"align="center"noshade="">
<!---------------------Inicia código PHP ------------------------->
<?php
// Permisos para acceder a la base de datos (dir, usuario,pass, bd)
$conn = mysqli_connect('localhost', 'firtec', '1234', 'DHT22');
if (!$conn) {
 echo "Error: No se pudo conectar a MySQL." . PHP_EOL;
 echo "errno de depuración: " . mysqli_connect_errno() . PHP_EOL;
 echo "error de depuración: " . mysqli_connect_error() . PHP_EOL;
 exit;
}
?>
<!-- --------------------Termina código PHP ------------------------>
<table border="5"align="center"> <!-- Crea tabla HTML -->
<tr align="center" bottom="middle"> <!-- fila alineado al centro -->
 <td>Temperatura</td> <!-- td crea columna llamada Temperatura -->
 <td>Humedad</td>	    <!-- td crea columna llamada Humedad -->
 <td>Fecha_Hora</td>  <!-- td crea columna llamada Fecha_Hora -->
 </tr> <!-- Fin de la fila con cuatro columnas -->
<!-- ------------------Inicia nuevo código PHP ------------------- -->
<?php
// Consulta la tabla sensor y guarda en $datos la info leída.
$datos_sensor = mysqli_query($conn,"SELECT * FROM sensor");
// Los valores contenidos en $datos_sensor son vectorizados en un $dato_array
while($dato_array = mysqli_fetch_array($datos_sensor)){ ?> <!-- Fin PHP -->
 
<tr>
 <td align="center"><?php echo $dato_array["Temperatura"]; ?></td>
 <td align="center"><?php echo $dato_array["Humedad"]; ?></td>
 <td><?php echo $dato_array["Fecha"]; ?></td>
 </tr>
 <?php
 }
 ?>
</table>
<hr size="2"align="center"noshade="">
</body>
<!-- ------------------Inicia nuevo código PHP ------------------- -->
<?php
$version = apache_get_version(); // Obtiene la versión de Apache
echo "$version\n"; // Muestra la versión de Apache
echo PHP_OS; // Muestra el sistema operativo
?> <!-- Fin código PHP -->
</html>

Resultado obtenido con el ejemplo. 

Para crear la base de dato usamos phpMyAdmin por su simpleza. La base de datos se llama DHT22, contiene solo una tabla que se llama sensor con tres columnas, una para la temperatura otra para la humedad y otra para le fecha y hora. 


 

Los motores paso a paso se pueden ver como motores eléctricos sin escobillas.
Es típico que todos los bobinados del motor sean parte del estator, y el rotor puede ser un imán permanente o, en el caso de los motores de reluctancia variable, un cilindro sólido con un mecanizado en forma de dientes parecido a un engranaje construido con un material magnéticamente dócil como el hierro dulce.
La conmutación de las bobinas se maneja con un controlador o driver que a su vez recibe información desde un microcontrolador.
La frecuencia que se aplica a las bobinas está dentro del espectro de audio y se pueden lograr grandes velocidades con estos motores.
Estos motores paso a paso tienen un comportamiento muy diferente al de los motores de corriente continua. En primer lugar, no giran libremente, los motores paso a paso avanzan girando por pasos determinados por un tren de pulsos. También se diferencian de los motores comunes de continua en la relación par motor. Los motores de continua no son buenos para ofrecer un buen torque a baja velocidad sin la ayuda de una reducción mecánica, sin embargo los motores paso a paso trabajan de manera opuesta siendo su mayor capacidad de torque a baja velocidad.

Los motores paso a paso tienen una característica adicional, el llamado par de detención, que no existe en los motores de continua. El torque de detención hace que un motor paso a paso se mantenga firme en su posición cuando no está girando, esta característica es muy útil cuando el motor deja de moverse y, mientras está detenido, la fuerza de carga permanece aplicada a su eje eliminando  la necesidad de un mecanismo de freno mecánico.
Los motores paso a paso requieren de trenes de pulsos aplicados convenientemente en sus bobinas, esto significa que hacer girar un motor paso a paso no es tan simple como en un motor de continua al que solo basta con aplicar voltaje y este empieza a girar.
Se requiere un circuito de control, que será el responsable de convertir las señales de avance y sentido de giro en la correcta  secuencia de activación de los bobinados.
El siguiente es un ejemplo simple para mover un motor de este tipo con un popular driver fabricado por Pololu, el A4988 de uso común en la plataforma Arduino y las impresoras 3D.

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
# =========================================================
# - Ejemplo para el manejo de un motor Paso a Paso
# - Driver A4988
# - Firtec Argentina
# - www.firtec.com.ar
# =========================================================
# -*- coding: utf-8 -*-
import time                     
import RPi.GPIO as GPIO
GPIO.setmode(GPIO.BOARD)        
GPIO.setwarnings(False) 	
 
pinDir = 24                     # Pin para el sentido de giro
pinStep = 26                    # Pin para los pasos
numSteps = 220                  # Número de pasos del motor
microPausa = 0.003              # Tiempo entre los pasos
 
 
GPIO.setup(pinDir,GPIO.OUT)
GPIO.setup(pinStep,GPIO.OUT)
 
while True:
 
        GPIO.output(pinDir,0)           # La dirección puede ser (0 o 1)
 
        for x in range(0,numSteps):
                GPIO.output(pinStep, True)
                time.sleep(microPausa)
                GPIO.output(pinStep, False)
                time.sleep(microPausa)
 
        time.sleep(microPausa)
 
        GPIO.output(pinDir, 1)          # Cambio del sentido de giro
 
        for x in range(0,numSteps):
                GPIO.output(pinStep, True)
                time.sleep(microPausa)
                GPIO.output(pinStep, False)
                time.sleep(microPausa)
 
GPIO.cleanup()          # Sale prolijamente

 En el vídeo se puede ver el resultado obtenido al ejecutar el programa.

 Este y otros temas forman parte del curso "Electrónica con Raspberry PI".

 

 

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 sobre el manejo de estas pantallas lo encontrará en nuestro nuevo curso para Raspberry PI).

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.