//Proyecto monitor/controlador para FORD FOCUS 04
//Los datos de ajustes, calibración y diagramas son de mi autoria EV
//El modelado grafico toma referencia a recopilación de información en la web
#include <math.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <EasyBuzzer.h>
Adafruit_SSD1306 display(128, 64, &Wire, -1); //SDA 19, SCL 23 wemos lolin es32 lite
#define RL1 25 //RELÉ 1
#define RL2 32 //RELÉ 2
#define buzzer 26 //Buzzer
#define ni 15 //entrada nivel +
#define te 2 //entrada termistor
#define vo 4 //entrada voltimetro
#define Vref 3.3 //voltaje referencia vcc 4.96
#define ADC 2048 // Multiplo de entrada ADC
#define NUM_SAMPLES 5 // NUMERO DE MUESTRAS TOMADAS Voltaje
#define THERMISTOR 992 // VALOR OHM DEL SENSOR 25 °C(992 spark)(2500 optra)
#define NUMSAMPLES 10 // NUMERO DE MUESTRAS TOMADAS NTC
#define BCOEFFICIENT 3680 // beta coefficient 3000-4000 (3680 spark)
#define SERIESRESISTOR 974 // resistor en serie 10k (974 para spark)
#define RV1 98700 //RV1=100000 ohms
#define RV2 9780 //RV2=10000 ohms
#define DEG2RAD 0.0174532925
#define niMin 0.72 // Voltaje nivel minimo
#define niMax 3.0 // Voltaje nivel maximo
#define correccion 5 // - 5°C de correción de la temperatura
unsigned char sample_count=0, m, V, simbol;
int samples[NUMSAMPLES], sum=0, Nivel1, temp;
float steinhart, p, p3, Volt, ba, Nivel;
unsigned long timer, timer2, timer3, timer4;
boolean indicador, RL1s, RL2s;
const unsigned char advert [] PROGMEM =
{
0x01, 0x00, 0x03, 0x80, 0x02, 0x40, 0x04, 0x40, 0x05, 0x20, 0x09, 0x10, 0x09, 0x30, 0x39, 0x38,
0x31, 0x18, 0x61, 0x0c, 0x40, 0x04, 0xc1, 0x06, 0xc0, 0x06, 0xff, 0xfe, 0x00, 0x00,
};
const unsigned char gasolina [] PROGMEM =
{
0x1f, 0xfc, 0x00, 0x3f, 0xfe, 0x00, 0x3f, 0xff, 0xc0, 0x30, 0x07, 0xe0, 0x30, 0x06, 0xf0, 0x30,
0x06, 0x78, 0x30, 0x06, 0x3c, 0x30, 0x06, 0x3c, 0x3f, 0xfe, 0x3c, 0x3f, 0xfe, 0x3c, 0x3f, 0xfe,
0x3c, 0x3f, 0xff, 0xdc, 0x3f, 0xff, 0xcc, 0x3f, 0xff, 0xec, 0x3f, 0xfe, 0xec, 0x3f, 0xfe, 0xec,
0x3f, 0xfe, 0xec, 0x3f, 0xfe, 0xec, 0x3f, 0xfe, 0xfc, 0x3f, 0xfe, 0x7c, 0xff, 0xff, 0xfc, 0xff,
0xff, 0x80
};
const unsigned char helice1 [] PROGMEM =
{
0x00, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x01, 0xfe, 0x00, 0x01, 0xfe, 0x00, 0x01, 0xfc, 0x00, 0x01,
0xf0, 0x00, 0x78, 0xf0, 0x00, 0x78, 0xf3, 0xc0, 0x7c, 0xff, 0xe0, 0x7f, 0xff, 0xf0, 0x7f, 0xdf,
0xf0, 0x7f, 0xff, 0xf0, 0x3c, 0x71, 0xf0, 0x00, 0x70, 0xe0, 0x00, 0xf8, 0xc0, 0x01, 0xf8, 0x00,
0x03, 0xf8, 0x00, 0x03, 0xf8, 0x00, 0x03, 0xf0, 0x00, 0x01, 0xf0, 0x00
};
const unsigned char helice2 [] PROGMEM =
{
0x00, 0x00, 0x00, 0x0c, 0x0f, 0x80, 0x3c, 0x1f, 0xc0, 0x3e, 0x3f, 0xe0, 0x7e, 0x3f, 0xf0, 0x7e,
0x3f, 0xf0, 0x7f, 0x3f, 0xe0, 0x7f, 0xff, 0x00, 0x7f, 0xfc, 0x00, 0x3f, 0xfc, 0x00, 0x1f, 0xdf,
0x80, 0x01, 0xff, 0xe0, 0x01, 0xff, 0xf0, 0x07, 0xff, 0xf0, 0x3f, 0xe7, 0xf0, 0x7f, 0xe7, 0xf0,
0x7f, 0xe7, 0xf0, 0x7f, 0xc3, 0xe0, 0x3f, 0xc3, 0xe0, 0x0f, 0x81, 0xc0
};
const unsigned char helice3 [] PROGMEM =
{
0x00, 0x00, 0x00, 0x07, 0x80, 0x00, 0x0f, 0x80, 0x00, 0x1f, 0x80, 0x00, 0x1f, 0x87, 0x00, 0x1f,
0x8f, 0x80, 0x1f, 0xbf, 0xe0, 0x0f, 0xff, 0xe0, 0x07, 0xff, 0xe0, 0x07, 0xff, 0xe0, 0x03, 0xb8,
0xc0, 0xff, 0xf8, 0x00, 0xff, 0xfc, 0x00, 0xff, 0xfc, 0x00, 0xff, 0x7f, 0x00, 0x7c, 0x3f, 0x00,
0x3c, 0x7f, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x7c, 0x00
};
const unsigned char logo [] PROGMEM =
{
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,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xf8, 0x00, 0x00, 0x3f, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x01, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x07, 0xff, 0x80, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x1f, 0xf0, 0x00, 0x1f, 0xff, 0xff, 0xf0, 0x00, 0x1f, 0xf8, 0x00, 0x00, 0x00,
0x00, 0x00, 0x01, 0xfe, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0xff, 0x00, 0x00, 0x00,
0x00, 0x00, 0x07, 0xf0, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x0f, 0xe0, 0x00, 0x00,
0x00, 0x00, 0x3f, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, 0xf8, 0x00, 0x00,
0x00, 0x01, 0xf8, 0x1f, 0xff, 0xe0, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x3f, 0x00, 0x00,
0x00, 0x03, 0xc0, 0xff, 0xff, 0x03, 0xfc, 0x00, 0xff, 0xfe, 0x7f, 0xff, 0xff, 0x07, 0xc0, 0x00,
0x00, 0x0f, 0x07, 0xff, 0xfe, 0x3f, 0xff, 0x80, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xc1, 0xe0, 0x00,
0x00, 0x3c, 0x3f, 0xff, 0xfc, 0x7f, 0xff, 0x38, 0x00, 0x00, 0xff, 0xff, 0xff, 0xf8, 0x78, 0x00,
0x00, 0x70, 0xff, 0xff, 0xf8, 0xff, 0xfe, 0x7f, 0x80, 0x03, 0xff, 0xff, 0xff, 0xfe, 0x1e, 0x00,
0x01, 0xe3, 0xff, 0xff, 0xf1, 0xff, 0xfc, 0xff, 0xf0, 0x0f, 0xff, 0xff, 0xff, 0xff, 0x87, 0x00,
0x03, 0x8f, 0xff, 0xff, 0xf1, 0xfb, 0xf9, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe3, 0x80,
0x07, 0x1f, 0xff, 0xff, 0xf1, 0xf3, 0xf3, 0x8f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf1, 0xc0,
0x0e, 0x3f, 0xff, 0xff, 0xf1, 0xe3, 0xe7, 0xaf, 0xff, 0xff, 0xff, 0xfe, 0x1f, 0xff, 0xfc, 0xe0,
0x1c, 0x7f, 0xff, 0xff, 0xf0, 0x07, 0xc7, 0x2f, 0xff, 0xff, 0xff, 0xfe, 0x3f, 0xff, 0xfe, 0x70,
0x18, 0xff, 0xff, 0xff, 0xf0, 0x0f, 0x8f, 0x1f, 0xff, 0xff, 0xff, 0xfc, 0x3f, 0xff, 0xff, 0x30,
0x39, 0xff, 0xff, 0xff, 0xf8, 0x1e, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xfc, 0x7f, 0xff, 0xff, 0x18,
0x33, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x1f, 0xdf, 0xff, 0xff, 0xff, 0xf8, 0xff, 0xff, 0xff, 0x98,
0x33, 0xff, 0xff, 0xff, 0xff, 0xee, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xff, 0xff, 0xff, 0x9c,
0x73, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x7f, 0x9f, 0xf1, 0xc7, 0xf8, 0xf1, 0xff, 0xff, 0xff, 0xcc,
0x73, 0xff, 0xff, 0xff, 0x1f, 0xfc, 0x7e, 0x13, 0xc0, 0x83, 0xe0, 0x21, 0xff, 0xff, 0xff, 0xcc,
0x73, 0xff, 0xff, 0xfe, 0x7f, 0xf8, 0xfc, 0x79, 0x88, 0x03, 0xc3, 0x03, 0xff, 0xff, 0xff, 0xcc,
0x73, 0xff, 0xff, 0xfc, 0xff, 0xf1, 0xf8, 0xf9, 0x18, 0x03, 0x8f, 0x83, 0xff, 0xff, 0xff, 0x9c,
0x33, 0xff, 0xff, 0xf8, 0xff, 0xe1, 0xf1, 0xf8, 0x38, 0x67, 0x1f, 0x87, 0xff, 0xff, 0xff, 0x98,
0x39, 0xff, 0xff, 0xf9, 0xff, 0xc3, 0xe3, 0xf8, 0x70, 0x7e, 0x3f, 0x07, 0xff, 0xff, 0xff, 0x98,
0x19, 0xff, 0xff, 0xf9, 0xff, 0x87, 0xe3, 0xf8, 0xf0, 0x7c, 0x3f, 0x0f, 0xff, 0xff, 0xff, 0x38,
0x1c, 0xff, 0xff, 0xf0, 0xff, 0x07, 0xc7, 0xf9, 0xe1, 0x00, 0x7e, 0x1f, 0x7f, 0xff, 0xfe, 0x70,
0x0e, 0x7f, 0xff, 0xf8, 0xfe, 0x0f, 0xc7, 0xf3, 0xe3, 0x80, 0x7e, 0x1e, 0xff, 0xff, 0xfc, 0x60,
0x07, 0x3f, 0xff, 0xf8, 0x70, 0x1f, 0x87, 0xe3, 0xc3, 0xfc, 0x7c, 0x3c, 0xff, 0xff, 0xf8, 0xc0,
0x03, 0x8f, 0xff, 0xf8, 0x00, 0x3f, 0x07, 0xc7, 0xc7, 0xfc, 0x78, 0x31, 0xff, 0xff, 0xe3, 0x80,
0x01, 0xc7, 0xff, 0xfc, 0x00, 0x7e, 0x60, 0x0f, 0x8f, 0xfc, 0x00, 0x03, 0xff, 0xff, 0xc7, 0x00,
0x00, 0xf1, 0xff, 0xfe, 0x00, 0xff, 0xf0, 0x1f, 0x0f, 0xfe, 0x02, 0x0f, 0xff, 0xff, 0x1e, 0x00,
0x00, 0x3c, 0x3f, 0xff, 0x83, 0xff, 0xfc, 0x7f, 0x1f, 0xff, 0xff, 0x3f, 0xff, 0xfc, 0x3c, 0x00,
0x00, 0x1e, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0xf0, 0x00,
0x00, 0x07, 0xc1, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x83, 0xc0, 0x00,
0x00, 0x01, 0xf0, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x1f, 0x00, 0x00,
0x00, 0x00, 0x7e, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0xfc, 0x00, 0x00,
0x00, 0x00, 0x0f, 0xc0, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x07, 0xe0, 0x00, 0x00,
0x00, 0x00, 0x01, 0xfc, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x7f, 0x80, 0x00, 0x00,
0x00, 0x00, 0x00, 0x3f, 0xe0, 0x00, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x0f, 0xf8, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x03, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x03, 0xff, 0xc0, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x3f, 0xff, 0x80, 0x00, 0x00, 0x03, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 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, 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, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
void termistor()
{
float Rth, average=0; char i;
for (i=0; i< NUMSAMPLES; i++) { samples[i] = analogRead(te); }
for (i=0; i< NUMSAMPLES; i++) { average += samples[i]; }
average /= NUMSAMPLES;
Rth = (ADC * float(THERMISTOR)/average)-float(THERMISTOR); //Valor de Rth en funcion del conexionado de nuestro termistor
steinhart = ((1/((1/298.15)+(1/float(BCOEFFICIENT))*log(SERIESRESISTOR/Rth)))-273.15)-correccion; //Aplicamos directamente Steinhart-hart para NTC
/* el circuito Analog pin A2
* |
* GND |-----/\/\/\-----+-----/\/\/\-----| 5V
* ^ ^
* R termistor SERIESRESISTOR */
}
int fillArc2(int x, int y, int start_angle, int seg_count, int rx, int ry, int w, unsigned int colour)
{
// x,y == coordenadas del centro del arco
// start_angle = 0 - 359
// seg_count = número de segmentos de 3 grados para dibujar (120 = arco de 360 grados)
// rx = radio del eje x
// yx = radio del eje y
// w = ancho (grosor) del arco en píxeles
// color = valor de color de 8 bits "WHITE"
byte seg = 3; // Los segmentos tienen 3 grados de ancho = 120 segmentos para 360 grados
byte inc = 3; // Dibuje segmentos cada 3 grados, aumente a 6 para el anillo segmentado
// Calcular el primer par de coordenadas para el inicio del segmento
float sx = cos((start_angle - 90) * DEG2RAD);
float sy = sin((start_angle - 90) * DEG2RAD);
uint16_t x0 = sx * (rx - w) + x;
uint16_t y0 = sy * (ry - w) + y;
uint16_t x1 = sx * rx + x;
uint16_t y1 = sy * ry + y;
// Dibuja bloques de color cada grado inc.
for (int i = start_angle; i < start_angle + seg * seg_count; i += inc) {
// Calcular par de coordenadas para el final del segmento
float sx2 = cos((i + seg - 90) * DEG2RAD);
float sy2 = sin((i + seg - 90) * DEG2RAD);
int x2 = sx2 * (rx - w) + x;
int y2 = sy2 * (ry - w) + y;
int x3 = sx2 * rx + x;
int y3 = sy2 * ry + y;
display.fillTriangle(x0, y0, x1, y1, x2, y2, colour);
display.fillTriangle(x1, y1, x2, y2, x3, y3, colour);
// Copie el final del segmento al inicio del segmento para el siguiente segmento
x0 = x2;
y0 = y2;
x1 = x3;
y1 = y3;
}
}
void voltimetro(int volt)
{
/* circuito divisor de voltaje:
* Analog pin A1
* |
* GND |-----/\/\/\-----+-----/\/\/\-----| 12V
* ^ ^
* 10k resistencia 100K resistencia */
display.setTextSize(2); display.setCursor(40,0);
display.print(Volt,1); display.print("V");
}
void helice()
{
static uint8_t frame = 0 ;
if(frame==0){display.drawBitmap(53,V,helice1,20,20,WHITE);}
if(frame==1){display.drawBitmap(53,V,helice2,20,20,WHITE);}
if(frame==2){display.drawBitmap(53,V,helice3,20,20,WHITE);}
frame++;
if(frame>2){ frame = 0; }
}
void ventilador()
{
if (RL1s==true ) { V=22; helice();}
if (RL2s==true ) { V=42; helice();}
}
void setup()
{
Serial.begin(115200);
pinMode(ni, INPUT);
pinMode(te, INPUT); pinMode(vo, INPUT); //Configurados entradas analogicas
pinMode(RL1, OUTPUT); pinMode(RL2, OUTPUT); //Configurados como salidas digitales
digitalWrite(RL1, LOW); digitalWrite(RL2, LOW);
//analogReadResolution(12); //set the resolution to 12 bits (0-4096)
EasyBuzzer.setPin(buzzer); //Selecciona el pin de salida
EasyBuzzer.beep( 2000, 1000); //Frecuencia en Hz, Duración beep ms ,pausa silencio ms
EasyBuzzer.stopBeep(); //Inicia buzzer en modo off
timer = millis(); timer2 = millis(); //tiempos igualados al contador millis
timer3 = millis(); timer4 = millis();
if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { // Address 0x3D for 128x64
Serial.println(F("SSD1306 falla de ubicacion"));
for(;;); }
display.clearDisplay(); //Borrar buffer display
display.setTextColor(WHITE); //Texto color blanco
display.setTextSize(1);
display.setCursor(54,1);
display.println("FOCUS");
display.startscrollright(0x00, 0x07);
display.drawBitmap(0,16,logo,128,53,WHITE); //carga grafico logo ford
display.display(); //muestra datos cargados
delay(2000); //pausa de 1 seg
display.stopscroll();
display.startscrollleft(0x00, 0x07);
delay(2000);
display.stopscroll();
display.clearDisplay(); //Borrar buffer display
}
void loop()
{
if (millis() > timer)
{
while (sample_count < NUM_SAMPLES){sum += analogRead(ni); sample_count++;}
p =((float)sum / (float)NUM_SAMPLES * Vref)/ADC; // Promedio de muestras tomadas
m = constrain(p, 0.72, 3.0)*10; //rango de voltaje y multiplica rango x10
Nivel=map(m,7.2, 30, 1,100);
Nivel1=map(Nivel,1,100,15,55);
sample_count = 0; sum = 0; // Reestablece los contadores
timer = millis() + 10000UL; // Refresco de muestras cada 10s
}
//****************************************************************************************///
if (millis() > timer2)
{
while (sample_count < NUM_SAMPLES){sum += analogRead(vo); sample_count++;}
p3 =((float)sum / (float)NUM_SAMPLES * Vref)/ADC; // Promedio de muestras tomadas
Volt = p3/((float)RV2/(RV1+RV2)); // Lectura Voltaje final
sample_count = 0; sum = 0; // Reestablece los contadores
termistor(); // Activa la función void termistor
timer2 = millis() + 3000UL; // Refresco cada 3s
}
//****************************************************************************************
if (millis() > timer3)
{
ventilador();
voltimetro(vo);
fillArc2(26,44,200,Nivel,25,25,2,WHITE); // Nivel
temp= map(steinhart,30,115,1,100);
fillArc2(101,44,200,temp,25,25,2,WHITE); // Tempertura
display.setTextSize(2); display.setCursor(9,36); display.print(Nivel1); display.print("L");
if (steinhart>99.99){simbol=80;} else{simbol=85;}
display.setTextSize(2); display.setCursor(simbol,36); display.print(steinhart,0);
display.setTextSize(1); display.println("o"); // simbolo de grado
if (indicador==true) {display.drawBitmap(113,0,advert,15,15,WHITE);}
if (Nivel1 < 22 ) {display.drawBitmap(0,0,gasolina,22,22,WHITE);}
display.display(); // Actualiza la pantalla
timer3 = millis() + 250UL; // Refresco cada 500ms
display.clearDisplay();
}
//****************************************************************************************
if (steinhart>=96) {RL1s=true; digitalWrite(RL1,HIGH); timer4=millis();} // //Vent 1 97°C
if (steinhart<=90 && (millis()-timer4>=8000)) {RL1s=false; digitalWrite(RL1,LOW);} //
if (steinhart>=103){RL1s=true; digitalWrite(RL2,HIGH); } // //Vent 2 104°C
if (steinhart<=98){RL2s=false; digitalWrite(RL2,LOW); } //
if (steinhart>=110){EasyBuzzer.update(); indicador=true;}
else {EasyBuzzer.stopBeep(); indicador=false;} // Alarma Alta temperatura 110
}