Hello!
I have a problem in a personal project about a prototipe sanitization booth, for this project I use the MLX90614 family sensors with a OLED screen (the most basic one SSD1306). I use the OLED screen to display two values, the first one is the lecture of an alcohol MQ-3 sensor and the second one is a "setup" value that is configured with a potenciometer, the OLED screen also displays the temperature read from the MLX when a TCR5000 sensor detect something in front of it.
The project have other functions but the problem that it is giving me is that in some point the OLED screen stops the actualization of the values of alcohol and "setup" and also the entire other functions get blocked.
I have tried debuging it by myself and optimizing some parts of the code but the problem persist and I thought maybe if a comunity member could help me with a quick view of my code.
There is a probability I'm missing something or I'm doing something wrong.
I think it may be the I2C comunicaton because in a version of this project without the MLX sensor I didn't have any problems or bugs.
Here's the code:
#include <Wire.h> //incluye la libreria para I2C
#include <Adafruit_GFX.h> //incluye la libreria GFX para la OLED
#include <Adafruit_SSD1306.h>//Incluye la libreria SSD1306 para la OLED
#include <Adafruit_MLX90614.h>//Incluye la libreria para el sensor de temperatura
Adafruit_SSD1306 display(128, 32, &Wire, 4); //Declara el largo y ancho de pixeles de la OLED, la comunicación y el pin de reset
Adafruit_MLX90614 Melexis = Adafruit_MLX90614();//Crea el objeto para usar el boton de temperatura
//Numeros de pines asiganados a cada variable global y su nombre
int xx = 40; int yy =0; int tt = 0; //Constantes como coordenadas para las imagenes en la OLED
const int LedRojo = 2, LedAmarillo = 3, LedVerde = 4, Relevador = 5, Buzzer = 6, Boton = 7, Nivel = 8, Presencia = 9; //Declarar pines digitales
const unsigned char PROGMEM Mueblares0 [] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x70, 0x00, 0x00, 0x00, 0x00, 0x18, 0x38, 0x00, 0x00, 0x04, 0x82, 0x38, 0x38, 0x00, 0x00, 0x3F, 0xEF, 0x98, 0x38, 0x00, 0x00, 0x37, 0x6D, 0x9C, 0x30, 0x00, 0x00, 0x32, 0x7F, 0xCC, 0xF0, 0x00, 0x00, 0x33, 0x6C, 0x0F, 0xE0, 0x00, 0x00, 0x33, 0x6F, 0x8F, 0x80, 0x00, 0x00, 0x10, 0x23, 0x1F, 0x80, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xC7, 0x00, 0x00, 0x00, 0x00, 0x78, 0xC7, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xF7, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x7F, 0x00, 0x00, 0x00, 0x01, 0xC0, 0x3F, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x1E, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x1E, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x3F, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x7F, 0xF3, 0x86, 0x48, 0x00, 0x00, 0x3F, 0xE1, 0xC6, 0x6C, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
float Acumulado, Subtotal, Total; //Declara variables flotantes
const int VoltajeEntrada = A6; //Declara pin analogo A6
const float VoltajeArduino = 5; //Declara el voltaje al que trabaja arduino como constante
/*Variables para el sensor de alcohol
Constante "a" y "b"de la ecuación de la grafica potencial
Conversion del valor del potenciometro al mg/L para valor de densidad de niebla
Valor analogo obtenido del potenciometro
Banderas para condicionar el proceso de nebulizacion*/
float a = 0.3934, b = -1.504, Alcohol, Temperatura, Ambiente, ndens;
long Densidad;
bool flag, botond;
//Proceso realizado unicamente la primera vez que se inicia el arduino
void setup()
{
/*Inicializa el programa a 9600 baudios
Inicializa el objeto del sensor de temperatura
Inicialzar los pines de las variables como salidas
Inicializar el pin del boton como una entrada con una resistencia interna*/
Serial.begin(9600);
Melexis.begin();
display.begin();
pinMode(LedRojo, OUTPUT);
pinMode(LedAmarillo, OUTPUT);
pinMode(LedVerde, OUTPUT);
pinMode(Relevador, OUTPUT);
pinMode(Buzzer, OUTPUT);
pinMode(Boton, INPUT_PULLUP);
pinMode(Nivel, INPUT_PULLUP);
pinMode(Presencia, INPUT);
digitalWrite(Relevador, HIGH);
digitalWrite(Buzzer, LOW);
Icono_MeAnd(); //Inicia la función
display.display();
display.clearDisplay(); //Limpia la memoria de la OLED
/*Parpadeo de leds para verificar el correcto funcionamiento del programa.
Se encienden los LEDs rojo, amarillo y verde.
se declara una demora de tiempo para evitar que el parpadeo sea muy rapido
Se apagan los LEDs rojo,amarillo y verde.*/
for(int i = 0; i<=3;i++)
{
digitalWrite(LedRojo, HIGH);
digitalWrite(LedAmarillo, HIGH);
digitalWrite(LedVerde, HIGH);
delay(500);
digitalWrite(LedRojo, LOW);
digitalWrite(LedAmarillo, LOW);
digitalWrite(LedVerde, LOW);
delay(500);
}
}
void loop()
{
//Se escriben los valores principales para la cabina en estado de espera
digitalWrite(LedVerde, HIGH);
digitalWrite(LedAmarillo, LOW);
digitalWrite(LedRojo, LOW);
/*Verifica los valores del nivel de liquido sanitizante y en caso de ser 0 entra en la función
de nombre "Error_cabina"*/
if(digitalRead(Nivel) == 1) { Error_Cabina(); }
else
{
/*Se le da un valor de falso a la primera bandera para comenzar los procesos
//Leemos la salida analógica del MQ
//Convertimos la lectura en un valor de voltaje
//Calculamos Rs con un RL de 1k
//Calculamos la concentración de alcohol con la ecuación obtenida.*/
flag = false;
int adc_MQ = analogRead(A0);
float Voltaje = adc_MQ * (5.0 / 1023.0);
float Rs= 1000*((5-Voltaje)/Voltaje);
Alcohol=a*pow(Rs/1545, b);
//Proceso del potenciometro y obtencion de valor de densidad de niebla
//Lee el valor de entrada del potenciometro
Densidad = analogRead(A1);
//Poceso de asigancion de valor de densidad deseado
//Se declara el valor del nivel 0 y se repite lo mismo para los otro 10
ndens = map(Densidad,0,1023,0,10);
//Decisión en la cual dependiendo del sensor de presencia entra la funcion
//de temperatura o la función de la densidad de cabina
if(digitalRead(Presencia) == 0){ Leer_Temperatura(); }
else { Densidad_Cabina(Alcohol,ndens); }
/*Comprobacion de si el boton fue presionado o no
En caso de presionar el boton, se cambia le valor de bandera para dar inicio al proceso de sanitizado*/
if(digitalRead(Boton) == LOW && flag == false){flag = true;}
if(flag == true && ndens >= Alcohol)
{
Ocupado();
digitalWrite(LedRojo, HIGH);
digitalWrite(LedAmarillo, HIGH);
digitalWrite(LedVerde, LOW);
digitalWrite(Relevador, LOW);
delay(5500);
digitalWrite(Relevador, HIGH);
delay(9500);
digitalWrite(Buzzer, HIGH);
delay(2000);
botond = true;
Alto();
}
if(flag == true && ndens <= Alcohol){
//Segundo ciclo de sanitizacion sin la activacion de la nebulizadora
Ocupado();
digitalWrite(LedRojo, HIGH);
digitalWrite(LedAmarillo, HIGH);
digitalWrite(LedVerde, LOW);
digitalWrite(Relevador, HIGH);
delay(15000);
digitalWrite(Buzzer, HIGH);
delay(2000);
botond = true;
Alto();
}
if(flag == true && botond == true)
{
//Secuencia de reinicio de varibales, al cual solo entra despues de haber hecho uno de los 2 procesos anteriores
flag = false;
digitalWrite(LedRojo, LOW);
digitalWrite(LedAmarillo, LOW);
digitalWrite(LedVerde, HIGH);
digitalWrite(Buzzer, LOW);
}
delay(100);//Retardo de un segundo para la impresion de los primeros datos
}
}
void Densidad_Cabina(float Alcohol,int ndens)
{
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(SSD1306_WHITE);
display.setCursor(0, 0);
display.print("DENSIDAD: SETUP:");
display.setTextSize(2);
display.setCursor(0, 15);
//Imprime las variables de densidad y setup
display.print(Alcohol);
display.write(" ");
display.print(ndens);
display.display();
delay(100); //Retardo de medio segundo
}
void Ocupado (void) //Rutina que se encarga del scroll del mensaje "Cabina en uso"
{
display.clearDisplay();//Limpia la memoria de la OLED
//Configura la posición de lo que se vaya a imprimir
display.display();
//Imprime a manera de scroll a la izquierda el texto
display.setCursor(0, 0);
display.write("CABINA EN USO");
display.startscrollleft(0x00, 0x0F);
display.display();
}
void Alto (void) //Función que detiene el scroll
{
display.stopscroll();//Detiene el scroll
delay(500); //Retardo de medio segundo
display.clearDisplay(); //Limpia la memoria de la OLED
display.display();
}
void Icono_MeAnd (void) //Funcion que limpia la OLED e imprime el logo de la empresa
{
display.clearDisplay(); //Limpia display OLED
display.drawBitmap(xx, yy,Mueblares0,48,32, 1); //Dibuja el Logo en OLED
display.display(); //Imprime el logo en la OLED
delay(tt); //Retardo en el cual la imagen se queda en la OLED
}
void Error_Cabina()//Esta función se encarga de indicar que el nivel de liquido es bajo
{//Enciende el LED rojo y apaga los otros dos LED's
digitalWrite(LedRojo, HIGH);
digitalWrite(LedAmarillo, LOW);
digitalWrite(LedVerde, LOW);
display.clearDisplay();//Limpia la memoria de la OLED
//Comandos de configuración de letra de OLED
display.setTextSize(1);
display.setTextColor(SSD1306_WHITE);
display.setCursor(20, 10);
//Imprime en la pantalla OLED las palabras entre comillas y sobre las coordenadas indicadas en el cursor
display.write("FALTA LIQUIDO");
display.setCursor(20, 20);
display.write(" SANITIZANTE");
display.display();
//Subrutina de pitido del buzzer en caso de no haber liquido sanitizante
for(int i = 0; i <=8; i++)
{
digitalWrite(Buzzer,HIGH);
delay(100);
digitalWrite(Buzzer,LOW);
delay(100);
}
//Subrutina de lectura del nivel de liquido sanitizante
for(int i =0;i <=8; i++)
{
if(digitalRead(Nivel)==0)
{
break;
}
}
delay(1000); //retardo de 1 segundo
}
void Leer_Temperatura(void) //Funcion que se encarga del uso del sensor de temperatura
{ //Se limpian las variables que se utilizaran
Total = 0;
//SubRutina para acomular 5 muestras de temperatura y promediarlas
Temperatura = (Melexis.readObjectTempC());
int Valor = analogRead(VoltajeEntrada);
float Voltaje = Valor * (VoltajeArduino / 1023.0);
Total = Temperatura - (Voltaje -3) * 0.4;
if (Total < 35.5 )
{
int secunda = Total;
Total = (Total - secunda) + 36;
}
Ambiente = (Melexis.readAmbientTempC());
if(Total > Ambiente)
{ //El buzzer pita indicando que la temperatura tomada es mayor que la del ambiente
digitalWrite(Buzzer,HIGH);
delay(300);
digitalWrite(Buzzer,LOW);
delay(250);
//Impresion de la información dentro de la OLED
display.clearDisplay();
display.setCursor(10, 10);
display.setTextSize(2);
display.print(Total);
display.print((char)167);
display.write(" C");
display.display();
}
delay(100);//Retardo de 100 milisegundos
//Subrutina para la detección de temperaturas altas mayores a 37
if(Total >= 37.0)
{ //Se enciende unicamente el LED rojo
digitalWrite(LedRojo, HIGH);
digitalWrite(LedAmarillo, LOW);
digitalWrite(LedVerde, LOW);
//Hace pitar el buzzer 4 veces
for(int i =0;i <=4; i++)
{
digitalWrite(Buzzer,HIGH);
delay(300);
digitalWrite(Buzzer,LOW);
delay(100);
}
delay(2000);//Retardo de 2 segundos donde cuales es visible el valor de temperatura
//Configuración del texto para la OLED
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(SSD1306_WHITE);
//Impresión de texto en la OLED
display.setCursor(30, 10);
display.write("TEMPERATURA");
display.setCursor(50, 20);
display.write("ALTA");
display.display();
Temperatura = 0; //Limpia el valor de temperatura
delay(3000); //Retardo de 3 segundos
digitalWrite(LedRojo, LOW);//Apaga el LED rojo
}
//Subrutina en caso de no detectar temperatura alta
else
{
delay(3000);//Retardo de 5 segundos donde muestra el valor de temepratura
}
}