Sensor de Radiación Ultravioleta Con Arduino



Comments



Description

Sensor de radiación ultravioleta con Arduinohttps://polaridad.es/sensor-radiacion-ultravioleta-arduino-indice-uv-uvm30a-guva-s12sd/ por Víctor Ventura | publicado en: Portada | 36 Radiación ultravioleta (UV) Además de la radiación electromagnética que los humanos somos capaces de ver, existen rangos con longitudes de onda más larga, infrarrojo, y más corta, ultravioleta. Una parte de esta radiación, la de longitud más corta, tiene efectos ionizantes, es decir, es capaz de desplazar electrones de los átomos modificando su estado. Mientras que la zona visible se encuentra aproximadamente en el rango comprendido entre los 400 nm y los 700 nm, la ultravioleta comienza en los 10 nm (ultravioleta extremo) y termina en los 400 nm (UVA, onda larga) donde comienza la parte visible del espectro. La radiación ultravioleta se utiliza para diversos fines prácticos, desde matar bacterias hasta revelar las placas de los circuitos impresos que fabricas en casa pero además de útil puede ser también peligrosa para la salud. La capa de ozono que rodea la tierra nos defiende de buena parte de la radiación ultravioleta más ionizante de la que nos llega desde el sol: la de longitud de onda más corta, los «rayos UVC», que se encuentran entre los 100 nm y 280 nm. Pero aún queda la UVB, entre 280 nm y 315 nm, también en parte ionizante y la UVB, entre 315 nm y 400 nm, que es menos agresiva. Precisamente es la radiación ultravioleta la que produce la capa de ozono en la estratosfera al disociar las moléculas de oxígeno O2 en dos átomos O, muy reactivos, que forman el ozono O 3 al reaccionar cada uno con otra molécula de O2. Índice UV (ultravioleta) El índice UV es un sistema estándar sencillo para medir la radiación ultravioleta que llega desde el sol a la tierra que sirve como orientación para determinar el riesgo potencial para la salud. La Organización Mundial de la Salud publica una guía práctica sobre el índice UV en la que explica los riesgos para la salud de la radiación ultravioleta y propone algunas medidas de protección en función de su intensidad. Esta guía práctica sobre el Índice Solar Mundial es una recomendación conjunta de la Organización Mundial de la Salud, la Organización Meteorológica Mundial, el Programa de las Naciones Unidas para el Medio Ambiente y la Comisión Internacional de Protección contra la Radiación no Ionizante. Para hacer su uso más sencillo establece un código de colores que asocia a los diferentes niveles: verde para el nivel bajo (índices 1 y 2), amarillo para el moderado (índices del 3 al 5), naranja para el alto (índices 6 y 7), rojo para el nivel muy alto (índices del 8 al 10) y morado para el nivel extremadamente alto (índices 11 en adelante) En función de estos índices y del fototipo de cada persona recomienda unos tiempos máximos de exposición y unas recomendaciones preventivas. Medida de la radiación ultravioleta y cálculo del índice UV Para medir con precisión la radiación ultravioleta, no solo la que llega del sol, también la que producen ciertos equipos, como las lámparas o LED con este tipo de luz, se utilizan espectrorradiómetros. Calibrados con los anteriores dispositivos, se pueden usar otros más sencillos (y económicos) como fotodiodos, que suelen ser de tipo Schottky. El «truco» consiste en medir la luz de cierta longitud de onda (del entorno de los UVA, normalmente) y presumir que corresponde, más o menos proporcionalmente, con la irradiancia ultravioleta; puede parecer poco preciso, pero es razonablemente funcional como para estimar el UVi. Existen componentes que incorporan sólo la función de medida de la radiación ultravioleta o, más exactamente la del índice UV, como el GUVA-S12SD, que incorporan amplificación, como el ML8511, ambos analógicos, o digitales, como el VEML6070, que comunican por I²C el resultado de la medición. También están presentes como una función secundaria en algunos sensores de iluminación y proximidad, como el Si1145, que también utiliza el protocolo I²C. Ninguno de los anteriores componentes es especialmente caro ni adquirido en series pequeñas y existen versiones de todos ellos en módulos que se pueden usar para prototipar o para realizar pruebas. Para usarlo como ejemplo en este artículo he elegido el GUVA-S12SD que es muy popular (seguramente tienes uno en tu insoladora ultravioleta de circuitos) y que se puede encontrar en módulos UVM30A que pueden usarse fácilmente con Arduino. El rango de longitudes de onda que mide el GUVA-S12SD se sitúa entre los 240 nm y los (aproximadamente) 380 nm, muy adecuado para determinar la radiación ultravioleta más peligrosa. con unos márgenes relativamente grandes. En cualquier caso. Según puede verse en la gráfica anterior. Puede alimentarse con tensiones entre 3 V y 5 V y puede entregar a la salida entre 0 y 1200 mV (aunque de hecho no supere el voltio). el fabricante del módulo proporciona una tabla con los valores de salida con los que se alcanzan los diferentes niveles del índice UV. basta con alimentarlo y leer el voltaje con el que representa el nivel de radiación ultravioleta que detecta. Como por encima de 1100 mV de salida corresponde a un índice UV extremadamente alto (un índice mayor que 10) se puede usar la referencia interna de 1100 mV para distribuir mejor la . en los programas de ejemplo para Arduino que he desarrollado como ejemplo se usa la tabla de valores del fabricante. Usar el fotodiodo Schottky GUVA-S12SD del módulo UVM30A con Arduino Usar el módulo UVM30A no puede ser más sencillo. el comportamiento no es completamente lineal aunque a efectos de establecer el índice UV.Como la fórmula para calcular el índice UV. no se cometería un gran error al considerarlo como lineal para ahorrar unos bytes de memoria o simplificar la programación. que puede consultarse en la guía práctica sobre el índice UV es muy compleja como para actualizar el resultado frecuentemente con un microcontrolador. especialmente para radiaciones bajas. sensibilidad aunque renunciando a la posibilidad de determinar cuánto se supera el índice 10. al rango que va de 0 a 1100. aunque resulta más que aceptable para medir el índice UV y es de esperar que en un prototipo montado en un circuito impreso incluso mejore. El siguiente programa de ejemplo lee el sensor de radiación ultravioleta GUVA-S12SD del módulo UVM30A cada cierto intervalo ESPERA_ENTRE_LECTURAS y va calculando la media de las lecturas que muestra cada cierto tiempo ESPERA_ENTRE_PRESENTACIONES junto con el valor correspondiente en mV . En los montajes de prueba. que devuelve la función. En cualquier caso. Para realizar la conversión hay que multiplicar por 1100 y dividir por 1023. la lectura analógica que se realiza del módulo UVM30A desde Arduino. Puesto que la lectura analógica con analogRead() tiene una resolución de 10 bits (excepto en Arduino Due y en Arduino Zero. Para trabajar con la referencia interna de 1100 mV en las placas Arduino basadas en el microcontroladorATmega168 o en el ATmega328 (como Arduino Uno) se usa analogReference(INTERNAL) y se usa analogReference(INTERNAL1V1) para las placas Arduino Mega. pero ahorrando un divisor de tensión para usar como referencia de entrada analógica en Arduino. seguramente por la disposición de los cables. sólo estimando que se alcanzado el 11. En el primer programa de ejemplo se usa como una constante para hacerlo en una única operación y facilitar la lectura. que son los milivoltios que se han establecido como referencia con analogReference(). tantas como sea posible en cierto periodo de tiempo. El tiempo de lectura del GUVA-S12SD es bastante rápido y la respuesta razonablemente estable. no es tan buena como la que da el osciloscopio. en los que puede configurarse a 12 bits) para obtener la tensión entregada por el módulo UVM30A hay que convertir el rango de 0 a 1023. y las promedia para establecer un valor que compara con los de la tabla del fabricante para calcular el índice UV. el programa realiza varias mediciones. para tratar de eliminar las desviaciones de posibles interferencias. begin(9600). // Referencia interna de 1100 mV El GUVA-S12SD mide de 0 18 a 1170 mV que corresponde con el índice UV 11 19 //pinMode(PIN_GUVAS12SD.07526881720430107527 // 4 1100/1023≃1. // La primera lectura es incorrecta 25 (normalmente cero) y necesita unos 100 µs para cada lectura analógica 26 cronometro_lecturas=millis(). 14 15 void setup() 16 { 17 analogReference(INTERNAL). . 29 } 30 void loop() 31 { 32 tiempo_transcurrido=millis()-cronometro_lecturas.DEC)+")").print("Lectura sensor: "+String(media_lecturas. // Esperar un ciclo de lectura para estabilizar el sensor y la 27 entrada analógica 28 cronometro_presentaciones=millis(). 8 unsigned int contador_lecturas=1. 36 lectura_sensor=analogRead(PIN_GUVAS12SD).07526881720430107527 La lectura máxima es de 1023 que corresponde a 1100 5 mV 6 7 unsigned int lectura_sensor. 9 float total_lecturas=0. Necesita unos 100 µs para 1 cada lectura analógica 2 #define ESPERA_ENTRE_PRESENTACIONES 60000 // Mostrar la lectura cada minuto 3 #define COEFICIENTE_VOLTAJE 1.print(" (media de "+String(contador_lecturas. 33 if(tiempo_transcurrido>ESPERA_ENTRE_LECTURAS) 34 { 35 cronometro_lecturas=millis().print(" Tensión (mV): "+String(media_lecturas*COEFICIENTE_VOLTAJE. 39 } 40 tiempo_transcurrido=millis()-cronometro_presentaciones. // La lectura analógica no necesita inicialización 20 Serial. 38 media_lecturas=total_lecturas/contador_lecturas++.// Esperar a Arduino Leonardo 23 #endif 24 lectura_sensor=analogRead(PIN_GUVAS12SD).0. 45 Serial. 44 Serial. #define PIN_GUVAS12SD A0 // Pin al que se conecta el módulo con el UVM30A #define ESPERA_ENTRE_LECTURAS 100 // Leer cada 100 ms. contador_lecturas=1. 10 float media_lecturas. 41 if(tiempo_transcurrido>ESPERA_ENTRE_PRESENTACIONES) 42 { 43 cronometro_presentaciones=millis().DEC)+"\n\n"). 11 long cronometro_lecturas. 37 total_lecturas+=lectura_sensor. 13 long tiempo_transcurrido.DEC)). 21 #if defined (__AVR_ATmega32U4__) 22 while(!Serial). 12 long cronometro_presentaciones.INPUT). 46 Serial. 33 } 34 void loop() 35 { 36 tiempo_transcurrido=millis()-cronometro_lecturas. 33 if(tiempo_transcurrido>ESPERA_ENTRE_LECTURAS) 8 { 39 cronometro_lecturas=millis(). 15 long cronometro_lecturas.467.907. 8 float total_lecturas=0.646. En lugar de comparar la lectura analógica con el valor de la hoja de datos del UVM30A se puede crear un vector que contenga los datos convertidos al rango de 0 a 1023 realizando la operación inversa a la descrita antes. // De 1 a 11 13 byte indice.0.begin(9600). 9 float media_lecturas. Ya no será necesario calcular la tensión a cada lectura puesto que la tabla de índices está modificada.818. total_lecturas=0. 1 #define PIN_GUVAS12SD A0 // Pin al que se conecta el módulo con el UVM30A 2 #define ESPERA_ENTRE_LECTURAS 100 // Leer cada 100 ms 3 #define ESPERA_ENTRE_PRESENTACIONES 30000 // Mostrar el índice cada 30 s 4 #define CANTIDAD_INDICES_UV 11 5 6 unsigned int lectura_sensor.378. 14 boolean buscando_indice_uv.INPUT). 16 long cronometro_presentaciones. . 40 lectura_sensor=analogRead(PIN_GUVAS12SD). } } Del mismo modo.738.10 12 22}. // La lectura analógica no necesita inicialización 24 Serial. 17 long tiempo_transcurrido.// Esperar a Arduino Leonardo 27 #endif 28 lectura_sensor=analogRead(PIN_GUVAS12SD). 10 int 11 valor_indice_uv[CANTIDAD_INDICES_UV]={210. // Referencia interna de 1100 mV El GUVA-S12SD mide de 0 22 a 1170 mV que corresponde con el índice UV 11 23 //pinMode(PIN_GUVAS12SD.295. para ahorrar un poco de proceso se pueden calcular los valores compensados para la tabla de índices. 41 total_lecturas+=lectura_sensor. 18 19 void setup() 20 { 21 analogReference(INTERNAL).0.563. 25 #if defined (__AVR_ATmega32U4__) 26 while(!Serial).1003. // La primera lectura es incorrecta 29 (normalmente cero) 30 cronometro_lecturas=millis(). // Esperar un ciclo de lectura para estabilizar el sensor y la 31 entrada analógica 32 cronometro_presentaciones=millis(). 7 unsigned int contador_lecturas=1. Arduino Nano…) que encienda el LED del color correspondiente al índice UV detectado por el GUVA-S12SD de un módulo UVM30A. contador_lecturas=1. total_lecturas=0. 43 } 44 tiempo_transcurrido=millis()-cronometro_presentaciones. 49 indice=CANTIDAD_INDICES_UV. rotulado como 220 Ω en el esquema. se sustituirá por el que corresponda a la tensión a la que deban trabajar los LED (dependiendo del propio LED y de la relación entre . 59 Serial.print(" (media de "+String(contador_lecturas. 56 } 57 } 58 Serial. El valor de las resistencias. Serial.DEC)+")"). 45 if(tiempo_transcurrido>ESPERA_ENTRE_PRESENTACIONES) 46 { 47 cronometro_presentaciones=millis(). 50 while(buscando_indice_uv&&indice>0) 51 { 52 indice--.print("Lectura sensor: "+String(media_lecturas. 53 if(media_lecturas>valor_indice_uv[indice]) 54 { 55 buscando_indice_uv=false. 48 buscando_indice_uv=true. } } Implementar el método en un semáforo de índice UV Utilizando el código de colores que publica la Organización Mundial de la Salud en la guía práctica sobre el índice UV se puede construir un sencillo montaje basado en Arduino (que puede ser muy portátil si se usa una placa Arduino Mini.print(" Índice UV: "+String(indice.0.42 media_lecturas=total_lecturas/contador_lecturas++.DEC)). En el diagrama se muestra la conexión usada para el código del ejemplo del «solmáforo». Arduino Micro.DEC)). PIN_VERDE. 1 #define PIN_VERDE 2 2 #define PIN_AMARILLO 4 3 #define PIN_NARANJA 7 4 #define PIN_ROJO 8 5 #define PIN_MORADO 12 6 #define PIN_GUVAS12SD A0 // Pin al que se conecta el módulo con el UVM30A 7 #define ESPERA_ENTRE_LECTURAS 100 // Tomar una lectura del sensor de ultravioleta cada 8 100 ms 9 #define ESPERA_ENTRE_PRESENTACIONES 10000 // Cambiar el color del semáforo cada 10 1 segundos 0 #define CANTIDAD_INDICES_UV 11 1 #define CANTIDAD_COLORES_UV 5 1 1 unsigned int lectura_sensor. // La lectura analógica no necesita inicialización 2 for(indice=0.PIN_AMARILLO.PIN_ROJO.907. 2 lectura_sensor=analogRead(PIN_GUVAS12SD).PIN_AMARILLO. 2 unsigned int contador_lecturas=1.HIGH).378. 1 long tiempo_transcurrido. No es especialmente importante utilizar ni la misma entrada analógica A0 ni las mismas salidas digitales.PIN_AMARILLO.0.INPUT).PIN_MORADO}. 2 2 void setup() 2{ 3 analogReference(INTERNAL).PIN_NARANJA.indice<CANTIDAD_COLORES_UV.PIN_NARANJA. // De 1 a 11 5 byte 1 color[CANTIDAD_INDICES_UV+1]={PIN_VERDE.indice++) 5 { 2 pinMode(pin_color[indice]. 1 float total_lecturas=0. // Referencia interna de 1100 mV El GUVA-S12SD mide de 0 a 2 1170 mV que corresponde con el índice UV 11 4 //pinMode(PIN_GUVAS12SD. 6 digitalWrite(pin_color[indice].738.1022} 1 .563.PIN_NARANJA. // La primera lectura es incorrecta .luminosidad y vida útil deseada.LOW). pero hay que recordar sustituirlas en el programa.467.OUTPUT).1003. 2 boolean buscando_indice_uv.818. 2 } 7 digitalWrite(pin_color[0]. 1 int 4 valor_indice_uv[CANTIDAD_INDICES_UV]={210.PI 6 N_AMARILLO.646. 0 long cronometro_lecturas. // De 0 a 11 7 byte 1 pin_color[CANTIDAD_COLORES_UV]={PIN_VERDE.PIN_RO 1 JO.PIN_ROJO.PIN_MORADO}. seguramente entre 100 Ω y 330 Ω). 2 long cronometro_presentaciones. 9 byte indice_anterior=0. 3 float media_lecturas.PIN_RO 8 JO.PIN_VERDE.295. 1 byte indice. // Esperar un ciclo de lectura para estabilizar el sensor y la 9 entrada analógica 3 cronometro_presentaciones=millis(). 4 } 4 } if(indice_anterior!=indice) { digitalWrite(color[indice_anterior]. 4 total_lecturas+=lectura_sensor. Además de poner el sensor a 90° o mejor en el lado contrario a los LED (el semáforo sirve para el exterior y se puede usar en condiciones de mucha luz) puede ser útil añadir a la caja un resalte que haga de visera para distinguir mejor el color. 5 } 3 tiempo_transcurrido=millis()-cronometro_presentaciones. 3 media_lecturas=total_lecturas/contador_lecturas++.8 (normalmente cero) 2 cronometro_lecturas=millis(). . indice_anterior=indice. 3 lectura_sensor=analogRead(PIN_GUVAS12SD).HIGH). 0 if(media_lecturas>valor_indice_uv[indice]) 4 { 1 buscando_indice_uv=false. total_lecturas=0. } } Para la versión portátil se puede usar una batería LiPo y un cargador para USB (el módulo más a la derecha de la imagen).LOW). Yo he utilizado dos interruptores. digitalWrite(color[indice].0. uno para cargar la batería y otro para encender el dispositivo. 3 while(buscando_indice_uv&&indice>0) 9 { 4 indice--. } contador_lecturas=1. 0} 3 void loop() 1{ 3 tiempo_transcurrido=millis()-cronometro_lecturas. 3 buscando_indice_uv=true. 2 if(tiempo_transcurrido>ESPERA_ENTRE_LECTURAS) 3 { 3 cronometro_lecturas=millis(). claro. no interruptores. 6 if(tiempo_transcurrido>ESPERA_ENTRE_PRESENTACIONES) 3 { 7 cronometro_presentaciones=millis(). será necesario usar conmutadores. pero es posible hacerlo solamente con uno y hacer una u otra operación en función de la posición en la que conmute. 8 indice=CANTIDAD_INDICES_UV. unsigned int contador_lecturas=1. long cronometro_presentaciones. // Referencia interna de 1100 mV El GUVA-S12SD mide de 0 a 1170 mV que corresponde con el índice UV 11 //pinMode(PIN_GUVAS12SD. float total_lecturas=0. GUVA-S12SD. } void loop() { tiempo_transcurrido=millis()-cronometro_lecturas. Índice UV. float media_lecturas. long cronometro_lecturas.07526881720430107527 La lectura máxima es de 1023 que corresponde a 1100 mV unsigned int lectura_sensor.07526881720430107527 // 1100/1023≃1. Módulo. // Esperar un ciclo de lectura para estabilizar el sensor y la entrada analógica cronometro_presentaciones=millis(). Otra alternativa es usar un único LED RGB que establezca el color en función del índice UV. long tiempo_transcurrido.// Esperar a Arduino Leonardo #endif lectura_sensor=analogRead(PIN_GUVAS12SD).begin(9600).Si usas una placa Arduino Uno se puede alimentar con una pila de 9 V (recuerda que la tensión de salida de Arduino determinará el cálculo de las resistencias de los LED).0. #if defined (__AVR_ATmega32U4__) while(!Serial). U #define PIN_GUVAS12SD A0 // Pin al que se conecta el módulo con el UVM30A #define ESPERA_ENTRE_LECTURAS 100 // Leer cada 100 ms.INPUT). Seguro que habrá ocasión de tratar estas alternativas en próximos artículos ¡no te los pierdas! Arduino. // La lectura analógica no necesita inicialización Serial. Necesita unos 100 µs para cada lectura analógica #define ESPERA_ENTRE_PRESENTACIONES 60000 // Mostrar la lectura cada minuto #define COEFICIENTE_VOLTAJE 1. . // La primera lectura es incorrecta (normalmente cero) y necesita unos 100 µs para cada lectura analógica cronometro_lecturas=millis(). void setup() { analogReference(INTERNAL). print(" (media de "+String(contador_lecturas. // La primera lectura es incorrecta (normalmente cero) 27 cronometro_lecturas=millis(). 45 indice=CANTIDAD_INDICES_UV. if(tiempo_transcurrido>ESPERA_ENTRE_LECTURAS) { cronometro_lecturas=millis(). 23 #if defined (__AVR_ATmega32U4__) 24 while(!Serial).295. 39 } 40 tiempo_transcurrido=millis()-cronometro_presentaciones. . } tiempo_transcurrido=millis()-cronometro_presentaciones. if(tiempo_transcurrido>ESPERA_ENTRE_PRESENTACIONES) { cronometro_presentaciones=millis().DEC)). // La lectura analógica no necesita inicialización 22 Serial.DEC)+")"). // Esperar un ciclo de lectura para estabilizar el sensor y la entrada analógica 28 cronometro_presentaciones=millis(). 13 long cronometro_lecturas. Serial. 36 lectura_sensor=analogRead(PIN_GUVAS12SD).// Esperar a Arduino Leonardo 25 #endif 26 lectura_sensor=analogRead(PIN_GUVAS12SD). 16 17 void setup() 18 { 19 analogReference(INTERNAL). 44 buscando_indice_uv=true.begin(9600). 10 int valor_indice_uv[CANTIDAD_INDICES_UV]={210.1003.print("Lectura sensor: "+String(media_lecturas. 29 } 30 void loop() 31 { 32 tiempo_transcurrido=millis()-cronometro_lecturas.378. total_lecturas=0.1022}.0. 38 media_lecturas=total_lecturas/contador_lecturas++.907. 12 boolean buscando_indice_uv.646.738.467.563. // Referencia interna de 1100 mV El GUVA-S12SD mide de 0 a 1170 mV que corresponde con el índice 20 UV 11 21 //pinMode(PIN_GUVAS12SD. contador_lecturas=1.818. Serial.INPUT). // De 1 a 11 11 byte indice. } } 1 #define PIN_GUVAS12SD A0 // Pin al que se conecta el módulo con el UVM30A 2 #define ESPERA_ENTRE_LECTURAS 100 // Leer cada 100 ms 3 #define ESPERA_ENTRE_PRESENTACIONES 30000 // Mostrar el índice cada 30 s 4 #define CANTIDAD_INDICES_UV 11 5 6 unsigned int lectura_sensor. 9 float media_lecturas. total_lecturas+=lectura_sensor. media_lecturas=total_lecturas/contador_lecturas++. 7 unsigned int contador_lecturas=1. 8 float total_lecturas=0.print(" Tensión (mV): "+String(media_lecturas*COEFICIENTE_VOLTAJE. 41 if(tiempo_transcurrido>ESPERA_ENTRE_PRESENTACIONES) 42 { 43 cronometro_presentaciones=millis(). Serial.0. lectura_sensor=analogRead(PIN_GUVAS12SD). 33 if(tiempo_transcurrido>ESPERA_ENTRE_LECTURAS) 34 { 35 cronometro_lecturas=millis(). 14 long cronometro_presentaciones. 37 total_lecturas+=lectura_sensor.DEC)+"\n\n"). 15 long tiempo_transcurrido. 56 Serial.PIN_AMARILLO. 57 contador_lecturas=1.PIN_NARANJA. 55 Serial.PIN_NARANJA.46 while(buscando_indice_uv&&indice>0) 47 { 48 indice--.1022}.print(" (media de "+String(contador_lecturas.907.PIN_VERDE. // Referencia interna de 1100 mV El GUVA-S12SD mide de 0 a 1170 mV que corresponde con el índice UV 11 //pinMode(PIN_GUVAS12SD. void setup() { analogReference(INTERNAL).DEC)+")").467.PIN_AMARILLO. 49 if(media_lecturas>valor_indice_uv[indice]) 50 { 51 buscando_indice_uv=false. float total_lecturas=0. byte indice_anterior=0. // De 1 a 11 byte color[CANTIDAD_INDICES_UV+1]={PIN_VERDE.0. 52 } 53 } 54 Serial.PIN_ROJO.print(" Índice UV: "+String(indice.print("Lectura sensor: "+String(media_lecturas. 59 } } #define PIN_VERDE 2 #define PIN_AMARILLO 4 #define PIN_NARANJA 7 #define PIN_ROJO 8 #define PIN_MORADO 12 #define PIN_GUVAS12SD A0 // Pin al que se conecta el módulo con el UVM30A #define ESPERA_ENTRE_LECTURAS 100 // Tomar una lectura del sensor de ultravioleta cada 100 ms #define ESPERA_ENTRE_PRESENTACIONES 10000 // Cambiar el color del semáforo cada 10 segundos #define CANTIDAD_INDICES_UV 11 #define CANTIDAD_COLORES_UV 5 unsigned int lectura_sensor. byte indice.INPUT). // La lectura analógica no necesita inicialización . float media_lecturas. long cronometro_presentaciones.0.295.DEC)).738. long tiempo_transcurrido.PIN_ROJO .PIN_VERDE.PIN_NARANJA.818. long cronometro_lecturas.DEC)). unsigned int contador_lecturas=1.646.PIN_MORADO}.PIN_ROJO. // De 0 a 11 byte pin_color[CANTIDAD_COLORES_UV]={PIN_VERDE.PIN_MORADO}.PIN_AMARILLO.563.1003.PIN_ROJ O. boolean buscando_indice_uv. 58 total_lecturas=0.378.PIN _AMARILLO. int valor_indice_uv[CANTIDAD_INDICES_UV]={210. LOW). media_lecturas=total_lecturas/contador_lecturas++. for(indice=0. indice_anterior=indice. // Esperar un ciclo de lectura para estabilizar el sensor y la entrada analógica cronometro_presentaciones=millis(). digitalWrite(color[indice].0.LOW). lectura_sensor=analogRead(PIN_GUVAS12SD). .indice<CANTIDAD_COLORES_UV. total_lecturas=0. } void loop() { tiempo_transcurrido=millis()-cronometro_lecturas. // La primera lectura es incorrecta (normalmente cero) cronometro_lecturas=millis(). digitalWrite(pin_color[indice]. } } He preparado un sencillo programa que graba cada 4 minutos los valores que se han ido promediando al leer el sensor de ultravioleta.HIGH). buscando_indice_uv=true.OUTPUT).indice++) { pinMode(pin_color[indice]. } tiempo_transcurrido=millis()-cronometro_presentaciones. } digitalWrite(pin_color[0]. if(tiempo_transcurrido>ESPERA_ENTRE_LECTURAS) { cronometro_lecturas=millis(). total_lecturas+=lectura_sensor. } contador_lecturas=1. lectura_sensor=analogRead(PIN_GUVAS12SD). if(media_lecturas>valor_indice_uv[indice]) { buscando_indice_uv=false. } } if(indice_anterior!=indice) { digitalWrite(color[indice_anterior]. indice=CANTIDAD_INDICES_UV.HIGH). if(tiempo_transcurrido>ESPERA_ENTRE_PRESENTACIONES) { cronometro_presentaciones=millis(). while(buscando_indice_uv&&indice>0) { indice--. h> // La librería SD estándar de Arduino File informe_uvi. Como el código está muy comentado. // buffer con el número (sufijo) del documento . según qué placa uses) para activar y desactivar la grabación (y así no tener errores al crear-cerrar el documento) y un LED para indicar que se están grabando datos. no te aburro con más charla.07526881720430107527 La lectura máxima es de 1023 que corresponde a 1100 mV #include <SD.es! #define MODO_PRUEBAS // Borrar esta definición para que no se envíen a la consola datos de informe en modo prueba #define PREFIJO_ARCHIVO "UVI" // Los nombres de los documentos tienen el formato UVIn.CSV siendo n el número (correlativo) de archivo #define EXTENSION_ARCHIVO ".07526881720430107527 // 1100/1023≃1. así como una librería para manejar la fecha y la hora usando un RTCDS3231 con Arduino. debes usar los números de pin de los #define para las conexiones o cambiarlos según tu hardware.Además del lector SD utiliza un conmutador que cambia entre GND y nivel alto (3 V o 5 V. espacio. Espero que te sirva. valores expresados como texto y separados por comas (también puede usarse punto y coma. // buffer para el nombre del documento con el informe UVi char buffer_numero_archivo[4]." // El separador usado para el formato CSV #define PIN_GUVAS12SD A0 // Pin al que se conecta el módulo con el UVM30A #define PIN_CS_SD 4 // Pin usado para activar (CS/SS) la tarjeta #define PIN_CS_CONVENCIONAL 10 // Pin usado normalmente para activar dispositivos SPI #define PIN_INFORME_ACTIVO 8 // LED que indica que la tarjeta SD está preparada para grabar datos #define PIN_CONMUTADOR_SD 9 // Pin que le indica al programa que debe preparar la tarjeta SD y grabar datos (nivel alto) o que debe vaciar el buffer y dejar de usar la tarjeta SD (nivel bajo) #define ESPERA_REINTENTO_ERROR 3000 // Esperar unos segundos antes de reintentar después de detectar un error #define ESPERA_MUESTREO_UVI 240000 // Intervalo entre grabaciones del valor del UVi (4 minutos a petición de Juan 4*60*1000 ms) #define COEFICIENTE_VOLTAJE 1. como el RTC DS3231. Puedes encontrar algún artículo en el blog sobre cómo gestionar el DS3231 desde Arduino usando las comunicaciones I2C. char nombre_archivo[13]. Una posible mejora incluiría un reloj en tiempo real. ¡Vuelve pronto por polaridad.CSV" // Se usa el formato CSV. tabulador…) #define SEPARADOR_CSV ". Lógicamente. println(" ms. // Desactivar el dispositivo en el bus SPI habitual while(!SD. no hay razón para seguir el programa) { #ifdef MODO_PRUEBAS Serial. // Puede que sea necesario usar como salida (o simplemente reservar) el pin que normalmente se utiliza para SPI por seguridad (si el verdadero no es el 10) digitalWrite(PIN_CS_SD. Serial.LOW).OUTPUT).valor calculado.HIGH). // Número de archivo que se busca para. Serial. // Pin del LED de aviso de SD activada digitalWrite(PIN_INFORME_ACTIVO.HIGH). // Apagar el LED que informa de que se pueden estar grabando datos en la tarjeta pinMode(PIN_CONMUTADOR_SD.OUTPUT).begin(9600). usarlo como sufijo del nombre boolean informe_activo=false. // Referencia interna de 1100 mV El GUVA-S12SD mide de 0 a 1170 mV que corresponde con el índice UV 11 lectura_sensor=analogRead(PIN_GUVAS12SD).0. // Esperar antes de reintentar } #ifdef MODO_PRUEBAS Serial. #endif pinMode(PIN_INFORME_ACTIVO.begin(PIN_CS_SD)) // Reintentar hasta activar el lector de tarjetas SD (si no se consigue. // Datos que se graban en una línea del documento CSV (milisegundos (desde encendido) .// Esperar a Arduino Leonardo #endif #endif analogReference(INTERNAL). // El pin al que realmente se conecta la tarjeta SD debe ser de salida para activarla (nivel bajo) o desactivarla (nivel alto) digitalWrite(PIN_CS_SD.print(ESPERA_REINTENTO_ERROR). // Preparar el puerto serie #ifdef __AVR_ATmega32U4__ while(!Serial). // Valor entregado por el sensor GUVAS12SD float total_lecturas=0. if(nuevo_estado_informe!=informe_activo) // Si ha cambiado el estado (ha cambiado la posición .println("Lector de tarjetas SD inicializado").INPUT).print("Error al inicializar el lector de tarjetas SD. // Lectura actual del conmutador de la tarjeta SD unsigned long cronometro. // Valor intermedio de los valores muestreados entre grabaciones String registro_csv.unsigned int numero_archivo=0. } void loop() { nuevo_estado_informe=digitalRead(PIN_CONMUTADOR_SD). // La primera lectura es incorrecta (normalmente cero) pinMode(PIN_CS_SD. // Desactivar la tarjeta SD pinMode(PIN_CS_CONVENCIONAL. // Suma de los valores muestreados en una sesión float media_lecturas. si no existe. // Número de lecturas tomadas entre grabaciones (para calcular el valor intermedio) unsigned int lectura_sensor. // Tiempo entre grabaciones del índice UVi en la tarjeta SD unsigned long contador_lecturas. lecturas promediadas) void setup() { #ifdef MODO_PRUEBAS Serial.OUTPUT). // No se están grabando datos en la tarjeta SD boolean nuevo_estado_informe. Se reintenta en "). #endif delay(ESPERA_REINTENTO_ERROR)."). // Cerrar el archivo informe_activo=false.HIGH). // Empezar a contar lecturas entre grabaciones (para calcular el valor intermedio) #ifdef MODO_PRUEBAS Serial.exists(nombre_archivo)). // Cambiar el estado a inactivo (no se graban datos en la tarjeta SD) digitalWrite(PIN_INFORME_ACTIVO.print(ESPERA_REINTENTO_ERROR). #endif } while(SD.close().PREFIJO_ARCHIVO).println("Informe UVi desactivado").").println("Probando a usar el documento "+String(nombre_archivo)). if(informe_uvi) // Si se ha conseguido preparar el documento… { informe_activo=true.println(" ms. Serial.open(nombre_archivo. informe_uvi=SD.FILE_WRITE). strcpy(nombre_archivo.buffer_numero_archivo). #endif cronometro=millis().del conmutador) { if(nuevo_estado_informe) // Si el conmutador está en modo grabar (y antes no lo estaba) { do { itoa(numero_archivo++. #endif delay(ESPERA_REINTENTO_ERROR).buffer_numero_archivo.println("Informe UVi activo"). // Esperar antes de reintentar } } else // Si el conmutador está en modo NO grabar (y antes no lo estaba) { informe_uvi. #endif } } if(informe_activo) // Si la grabación está activa { if((unsigned long)(millis()-cronometro)>ESPERA_MUESTREO_UVI) // Si la grabación está . // (re)Iniciar el cronómetro para saber si ha pasado el tiempo entre grabaciones } else { #ifdef MODO_PRUEBAS Serial.println("Se ha producido un error al tratar de crear el documento. #ifdef MODO_PRUEBAS Serial.LOW). // Vaciar el buffer informe_uvi. // …cambiar el estado a activo digitalWrite(PIN_INFORME_ACTIVO.10)."). // Apagar el LED que informa de grabación activa #ifdef MODO_PRUEBAS Serial.EXTENSION_ARCHIVO). strcat(nombre_archivo.print("Se reintentará dentro de "). Serial.flush(). // Encender el LED para informar de que se pueden estar grabando datos en la tarjeta SD contador_lecturas=0. strcat(nombre_archivo. Serial. que es para exteriores)  Entre 100 Ω y 330 Ω y un cuarto de vatio. media_lecturas=total_lecturas/contador_lecturas. // Corregir los valores tomados para que trabaje con el voltaje (más o menos coincide con un UVi decimal) #ifdef MODO_PRUEBAS Serial. // leer el sensor contador_lecturas++. Serial. } } } Si quieres hacer el montaje del artículo. que incluye junto al sensor otros compoentes pasivos que puedas necesitar. // incrementar el número de lecturas realizadas total_lecturas+=lectura_sensor. Menor tensión menor resistencia. registro_csv+=String(SEPARADOR_CSV). Serial.print(" ms ("). pero con luz de color)  5 resistencias que correspondan a la tensión y corriente de salida de la placa Arduinoelegida y de la intensidad de luz deseada (alta. // Grabar la línea CSV (el registro) contador_lecturas=0.DEC).activa y ha pasado el tiempo entre grabaciones sucesivas… { cronometro=millis(). Serial. Mejor pequeña. registro_csv+=String(SEPARADOR_CSV).print(cronometro).print(contador_lecturas).DEC).DEC). // (re)Iniciar el cronómetro para saber si ha pasado el tiempo entre grabaciones media_lecturas*=COEFICIENTE_VOLTAJE. un lector de tarjetas SD para el programa del ejemplo y un reloj en tiempo real para la «mejora» (almacenar la fecha y la hora de la medida)  El sensor de ultravioleta. // un separador.println(" muestras)").print(" en "). mayor iluminación menor resistencia . // y el número de muestras tomadas para calcular el valor intermedio (más de 1100000 en un Arduino Uno con intervalos de 4 minutos) informe_uvi. // otro separador registro_csv+=String(contador_lecturas. // Valor intermedio de las lecturas hasta el momento.print("Guardado el valor "). registro_csv+=String(media_lecturas. // Componer la línea CSV (registro) con el tiempo.  Una placa (compatible) Arduino. Mejor un módulo. tomar una medida y actualizar el cálculo del valor intermedio { lectura_sensor=analogRead(PIN_GUVAS12SD). básicamente necesitas los componentes de la foto. Serial.print(media_lecturas).  5 LED de los colores correspondientes (mejor todos teñidos o todos transparentes.println(registro_csv). #endif registro_csv=String(cronometro. Serial. // Empezar a contar lecturas entre grabaciones (para calcular el nuevo valor intermedio) } else // Si no toca grabar. Serial. Espero que os dé una idea para hacer vuestro proyecto ¡Suerte! . que suele incluir espacio para su propia batería que durará más que la del montaje. En el blog hay varios artículos sobre cómo controlar desde Arduino el RTCDS3231 Si no te ves muy suelto con esto. No sé en tu país. en tal caso te recomiendo que uses un módulo de los que incluyen ambas cosas (y además protegen la batería) que cuesta igual (más o menos) y minimiza el montaje.168. uno común que el conmutador conecta con uno u otro de los restantes según cambie su posición)  Si quieres hacer el montaje del ejemplo del comentario necesitas añadir un módulo lector de tarjetas SD para Arduino (mejor MicroSD) y la correspondiente tarjeta. necesitarás el módulo correspondiente.168.7 V (seguro que tienes alguna muerta de risa en un cajón)  Un cargador de batería. pedirlos fuera te va a ahorrar poco y un pedido al extranjero en agosto (siempre refiriéndome a España) puede significar que llegue a final de septiembre. os he preparado un ejemplo de cómo se podría mostrar el índice UV usando un servidor web basado en Arduino con una conexión Ethernet. puedes necesitar también aumentar la tensión entregada por la batería. Dependiendo de la alimentación de la placa Arduino. en el blog hay un artículo que explica cómo almacenar datos desde Arduino hasta una tarjeta SD  Si quieres añadir un RTC. Te recomiendo el reloj en tiempo real DS3231. hay que usar un navegador web en un PC que esté en la misma red que la conexión Ethernet de Arduino y escribir en la barra de direcciones 192. te aconsejo que pidas ayuda en una tienda de electrónica cercana. Por si necesitas más información que la del ejemplo.  Una batería.252 Si la red no es la del ejemplo (192.1. Como parece que hay muchos lectores interesados.  Te recomiendo un par de interruptores o conmutadores para el encendido y la carga. Después conectar todo y alimentarlo (mostrar también la consola serie es de ayuda para monitorizar el funcionamiento). mi experiencia en España es que están muy preparados y encantados de ayudar. aunque puedes hacerlo con un conmutador de dos posiciones (tres terminales. Son pocos componentes.1. Si optas por un módulo (es mi consejo para ti) incluirá los componentes que necesite para conectar directamente a la placa Arduino (debes buscar que la alimentación de uno y otro sean compatibles).X) habrá que cambiar el valor de la variable ip. Te recomiendo una de las de teléfono móvil que entregan 3. suele ser una ocasión para aprender un montón. 0x56. 14 char lectura_anterior. // El texto del HTML está en español 53 cliente_web.168.begin(115200).252). // La primera lectura es incorrecta (normalmente cero) 27 } 28 29 void loop() 30 { 31 cliente_web=servidor_web. // Cabecera de tipo de respuesta enviada (texto en formato HTML) 49 cliente_web."F11".0.available()) // Si llegan datos desde el cliente (el navegador web) 41 { 42 lectura_ethernet=cliente_web.ip). // Monitorizar la información que envía el cliente (el navegador web) 37 while(cliente_web. 11 EthernetServer servidor_web(80). 23 Serial. // Al terminar.print(lectura_ethernet)."1C0".h> 8 9 byte mac[]={0x12."FE0"."F11".user- 57 scalable=no."F11". 66 cliente_web.\">")).0.print(F("<meta name=\"viewport\" content=\"width=device-width. .h> 7 #include <Ethernet.println(F("Connection: close")). // Leer una letra del texto enviado por el cliente 43 Serial.println(F("Datos enviados por el cliente:\n")).0xBC}.println().maximum-scale=1. 65 cliente_web. 54 cliente_web.print(F("display:table. 67 cliente_web. 13 char lectura_ethernet.minimum-scale=1.1. // Cabecera de petición aceptada correctamente 48 cliente_web.0x34. // Monitorizar que el cuando se conecta el cliente (el navegador web) 36 Serial."FE0".begin(mac. 16 17 void setup() 18 { 19 Serial. // Título de la página (para la ventana del navegador) 60 cliente_web.168.print(F("<head>")).0x9A.println(F("HTTP/1.print(F("<div style=\"")).print(F("<html lang=\"es\">")). // Dirección MAC inventada 10 IPAddress ip(192. cerrar la conexión para liberar al servidor lo antes posible 50 cliente_web.print(F("width:100%.print(F("</head>")).print(F(".available(). // 4 Colores de los índices para el fondo de la página web 5 6 #include <SPI.read(). // Dirección IP arbitraria en el rango 192. 32 if(cliente_web) 33 { 34 lectura_anterior=0. // Una línea en blanco para indicar el final de las cabeceras y el comienzo del código HMTML 51 cliente_web. 22 servidor_web. // Referencia interna de 1100 mV El GUVA-S12SD mide de 0 a 1170 mV que corresponde con el índice 25 UV 11 26 analogRead(PIN_GUVAS12SD). // Es un documento HTML 52 cliente_web.print(F("<body style=\"")).begin().0x78. // Como la línea en blanco marca el final de la petición HTTP ignorar el resto del texto que mande el cliente 47 cliente_web. // Mostrar la letra recibida del cliente para monitorizar el funcionamiento 44 if(lectura_ethernet=='\r'&&lectura_anterior=='\n') // Si llega CR y antes había llegado LF se interpreta como una línea en blanco 45 { 46 cliente_web. // El puerto por defecto del HTTP es el 80 12 EthernetClient cliente_web.println(F("Se ha conectado un cliente"))."1C0". 20 while(!Serial)."FA0".initial-scale=1.1 #define PIN_GUVAS12SD A0 // Pin al que se conecta el módulo con el UVM30A 2 #define CANTIDAD_INDICES_UV 11 3 String color[CANTIDAD_INDICES_UV+1]={"1C0".print(F("<DOCTYPE html>"))."E1B"}. // Cualquier carácter que no sea \n para evitar malinterpretar el final del texto 35 Serial.flush(). 64 cliente_web. 62 cliente_web. 24 analogReference(INTERNAL). // La codificación del texto es UTF-8 (importante para los caracteres no-ASCII 55 como las tildes) 56 cliente_web.println(F("Servidor web iniciado")).print(F("<meta charset=\"utf-8\">")).println(F("Content-Type: text/html")).0\">")). // Color de fondo de la página (el que corresponde con el índice UV) 63 cliente_web.")). // ventana para que se muestre al tamaño correspondiente en un dispositivo 58 móvil y la escala sea fija 59 cliente_web.1 200 OK")). 61 cliente_web.print(F("<title>Índice UV</title>"))."FE0".height=device-height. 15 byte indice. 21 Ethernet.connected()) // Cuando el cliente (el navegador web) se conecte 38 { 39 indice=indice_uv().1. // Leer el sensor 40 if(cliente_web.")).print(F("background-color:#")).print(color[indice])."FA0". 77 cliente_web.")).println(F("\nEl cliente se ha desconectado")). 81 cliente_web. // Centrar el texto 74 cliente_web.stop().print(indice).print(F("text-align:center. // Avisar de que se ha cerrado la conexión para monitorizarla 89 } 90 } 91 92 byte indice_uv() 93 { 94 static const int valor_indice_uv[CANTIDAD_INDICES_UV]={210. 97 byte indice=CANTIDAD_INDICES_UV.print(F("</body>")). 80 cliente_web. 82 cliente_web.print(F("El índice UV es ")).")). } } return indice.print(F("</div>")).print(F("height:100%. 70 cliente_web.print(F("font-size:24px.print(F("\">")).646. // Cerrar la conexión para liberar al servidor 83 } 84 lectura_anterior=lectura_ethernet.467. 101 if(lectura_sensor>valor_indice_uv[indice]) { buscando_indice_uv=false. 75 cliente_web. 69 cliente_web.")). 72 cliente_web.563.378.print(F("display:table-cell.print(F("\">")). } . 73 cliente_web.")).print(F("</div>")). // De 1 a 11 95 unsigned int lectura_sensor=analogRead(PIN_GUVAS12SD).818.295.68 cliente_web. // Recordar la lectura anterior para detectar una línea en blanco y saber cuándo termina la petición 85 HTTP 86 } 87 } 88 Serial.print(F("vertical-align:middle. // Valor numérico del índice UV 78 cliente_web. 71 cliente_web.")). 76 cliente_web.1022}.738. 98 while(buscando_indice_uv&&indice>0) 99 { 100 indice--.1003. 96 boolean buscando_indice_uv=true.print(F("<div style=\"")).print(F("</html>")). 79 cliente_web.907.
Copyright © 2024 DOKUMEN.SITE Inc.