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.
Todo esto y mucho mas encontrará en nuestros Libros Técnicos.