{"id":3737,"date":"2015-12-12T21:16:58","date_gmt":"2015-12-12T20:16:58","guid":{"rendered":"http:\/\/bitacora.eniac2000.com\/?p=3737"},"modified":"2015-12-12T21:16:58","modified_gmt":"2015-12-12T20:16:58","slug":"attiny85-modulo-rf-a-433-mhz-modo-de-bajo-consumo-y-como-despertarlo-con-interrupciones","status":"publish","type":"post","link":"https:\/\/bitacora.eniac2000.com\/?p=3737","title":{"rendered":"Attiny85: m\u00f3dulo RF a 433 MHz, modo de bajo consumo, y c\u00f3mo despertarlo con interrupciones"},"content":{"rendered":"<p>Hace ya bastante tiempo escrib\u00ed algo acerca de un <a href=\"http:\/\/bitacora.eniac2000.com\/?p=3541\" target=\"_blank\">sistema de riego controlado por WhatsApp<\/a> que estuve desarrollando. Se basaba en el uso de una Raspberry Pi que actuaba como cerebro del sistema de riego y de comunicaciones, permitiendo el control de todo el sistema mediante mensajer\u00eda por WhatsApp. La Raspberry, a su vez, se comunicaba con los los relojes de riego mediante m\u00f3dulos de radiofrecuencia a 433 MHz, un sistema de comunicaci\u00f3n barato y razonablemente efectivo. En el otro lado, como se coment\u00f3 en su momento, la v\u00e1lvula de riego se controlaba con un chip Attiny85, programado mediante Arduino.<\/p>\n<p>Como se vio en su momento, el sistema funcionaba <em>razonablemente<\/em> bien. Sin embargo, varios problemas me llevaron a un callej\u00f3n sin salida. El principal de ellos, y del que hablaremos hoy, era el consumo del receptor Attiny85. Sobre el papel es un sistema de muy bajo consumo, \u00f3ptimo para este tipo de funciones. Sin embargo, el sistema de control de la v\u00e1lvula de riego no dejaba demasiado espacio para una bater\u00eda, as\u00ed que la alimentaci\u00f3n disponible era, como poco, reducida. Pronto se demostr\u00f3 el que el Attiny con el sistema de radiofrecuenca devoraba la bater\u00eda. \u00c9sta apenas duraba unas 48-72 horas. Y esto, en un sistema que se supone que ha de ser aut\u00f3nomo y con un bajo mantenimiento, era sencillamente inaceptable, sobre todo si lo comparamos con relojes de riego de jard\u00f3n convencionales, que con un par de pilas AA o una pila cuadrada de 9v pueden funcionar de manera ininterrupida durante meses.<\/p>\n<p>Prob\u00e9 varias soluciones, desde el uso inicial de una bater\u00eda recargable de 9v hasta el uso de un panel solar con una bater\u00eda de m\u00f3vil incorporada. \u00c9ste \u00faltimo caso consigui\u00f3 producir mejoras, llegando el sistema a funcionar durante una semana de manera ininterrumpida. Pero en cualquier caso, no era una gran mejora. Tocaba afrontar el problema de base: un exceso de consumo.<\/p>\n<figure id=\"attachment_3740\" aria-describedby=\"caption-attachment-3740\" style=\"width: 400px\" class=\"wp-caption aligncenter\"><a href=\"http:\/\/bitacora.eniac2000.com\/wp-content\/uploads\/2015\/12\/IMAG1166.jpg\"><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/bitacora.eniac2000.com\/wp-content\/uploads\/2015\/12\/IMAG1166-400x373.jpg\" alt=\"Bater\u00eda cuadrada de 9v y panel solar con regulador\" title=\"Bater\u00eda cuadrada de 9v y panel solar con regulador\" width=\"400\" height=\"373\" class=\"size-medium wp-image-3740\" \/><\/a><figcaption id=\"caption-attachment-3740\" class=\"wp-caption-text\">Bater\u00eda cuadrada de 9v y panel solar con regulador<\/figcaption><\/figure>\n<p>En efecto, el problema estaba provocado por un exceso de consumo. Tal y como estaba dise\u00f1ado, el sistema estaba permanentemente a la escucha de se\u00f1ales por RF, en un bucle sin fin, dado que la se\u00f1al de encender o apagar la v\u00e1lvula de riego pod\u00eda darse en cualquier momento. Esta aproximaci\u00f3n era, como poco, inadecuada desde el punto de vista del consumo.<\/p>\n<p>Para mejorar esto, prob\u00e9 varias alternativas: desde emitir s\u00f3lo en determinadas ventanas de tiempo, hasta desconectar la alimentaci\u00f3n al m\u00f3dulo de radiofrencuencia y activarlo s\u00f3lo durante varios segundos cada minuto. Opciones bastante malas, la verdad, ya que se basaban en la precisi\u00f3n de un reloj interno que, como es conocido, no es un prodigio de la precisi\u00f3n.<\/p>\n<p>Otra posibilidad hubiera podido ser un m\u00e9todo en el que el Attiny consultara a la Raspberry si hab\u00eda alg\u00fan comando por ejecutar. Pero por desgracia, los m\u00f3dulos RF de 433 MHz son unidireccionales, por lo que hubiera sido preciso incorporar un emisor al Attiny y un receptor a la Raspberry, complicando de manera innecesaria todo el sistema. Finalmente, la soluci\u00f3n vino de mano de dos elementos presentes en el Attiny. El modo sleep y el uso de interrupciones. <\/p>\n<p>El Attiny85 dispone de varios modos de bajo consumo (<a href=\"http:\/\/www.re-innovation.co.uk\/web12\/index.php\/en\/blog-75\/306-sleep-modes-on-attiny85\" target=\"_blank\">sleep mode<\/a>) que sirven para reducir el consumo del chip cuando est\u00e1 a la espera de alg\u00fan evento. En el caso del Attiny85, puede reducir el consumo hasta en un 90%. Pero no se trataba s\u00f3lo de dormir al chip, sino de ser capaz de despertarlo cuando se recibiera una recepci\u00f3n de datos en el m\u00f3dulo de RF. Y para ello, nos encontramos con las interrupciones.<\/p>\n<p>Las <a href=\"http:\/\/thewanderingengineer.com\/2014\/08\/11\/arduino-pin-change-interrupts\/\" target=\"_blank\">interrupciones<\/a> son eventos que provocan un cambio en el estado de reposo o ejecuci\u00f3n de un programa -en este caso, un programa cargado en el Attiny85-. Hay interrupciones tanto hardware como software, siendo las hardware las provocadas por un evento externo al programa en s\u00ed. Dentro de las interrupciones hardware, en el caso de Arduino, podemos distinguir las interrupciones Externas, y las provocadas por un Cambio en el Pin. El nombre es un poco confuso, pues ambas son externas al chip en s\u00ed, pero mientras las Externas est\u00e1n limitadas a un n\u00famero concreto de patillas en el chip, las de Cambio en Pin pueden ocurrir en cualquiera de las patillas. En el <a href=\"http:\/\/thewanderingengineer.com\/2014\/08\/11\/pin-change-interrupts-on-attiny85\/\" target=\"_blank\">caso concreto del Attiny85<\/a>, las Externas s\u00f3lo se producen en el Pin2 (INT0, patilla 7), mientras que las de Cambio en Chip se pueden producir en cualquier otra patilla.<\/p>\n<p>De hecho, es factible <a href=\"https:\/\/bigdanzblog.wordpress.com\/2014\/08\/10\/attiny85-wake-from-sleep-on-pin-state-change-code-example\/\" target=\"_blank\">despertar al Attiny85 del modo de bajo consumo mediante el uso de interrupciones<\/a>. En el caso concreto del art\u00edculo enlazado, se usa el Pin3 (patilla 7) -luego se usa el modo de Cambio de Pin- para despertar al chip del modo de bajo consumo, como he podido comprobar personalmente (el ejemplo se basa en el uso de un <a href=\"https:\/\/www.arduino.cc\/en\/Tutorial\/Button\" target=\"_blank\">bot\u00f3n conectado a 5v<\/a>). Sin embargo, a la hora de probarlo con el m\u00f3dulo de RF a 433 MHz el sistema no funcionaba. No era capaz de realizar cambios en el sistema.<\/p>\n<p>A modo de recordatorio, el sistema de control de la v\u00e1lvula consiste b\u00e1sicamente en un rel\u00e9 que activa o desactiva la v\u00e1lvula en funci\u00f3n del tiempo que se desea mantener activo el riego. Este rel\u00e9 est\u00e1 controlado por una de las patillas del Attiny, protegida mediante un optoacoplador.<\/p>\n<p>Tras varias pruebas, pude averiguar que el problema estaba causado por una particularidad en el receptor del m\u00f3dulo RF. S\u00f3lo he sido capaz de hacerlo comunicar con el chip Attiny a trav\u00e9s del del pin de Interrupci\u00f3n Externa (Pin2, INT0), por lo que el ejemplo referenciado anteriormente no resultaba v\u00e1lido. En mi caso, ha sido necesario hacer uso de la patilla INT0:<\/p>\n<p><code>#include <rcswitch .h><br \/>\n#include <avr \/sleep.h><br \/>\n#include <\/avr><avr \/interrupt.h><\/p>\n<p>RCSwitch mySwitch = RCSwitch();<br \/>\nconst int rele = 4;<br \/>\nconst int dataPin = 0; \/\/INT0, PCINT2<br \/>\nvoid setup() {<br \/>\n  pinMode(dataPin, INPUT);<br \/>\n  digitalWrite(dataPin, HIGH);<br \/>\n  pinMode(rele, INPUT);<br \/>\n  mySwitch.enableReceive(dataPin); <\/p>\n<p>    \/\/ Flash quick sequence so we know setup has started<br \/>\n    for (int k = 0; k < 10; k = k + 1) {\n        if (k % 2 == 0) {\n            pinMode(rele, OUTPUT);\n            }\n        else {\n            pinMode(rele, INPUT);\n            }\n        delay(250);\n        } \/\/ for\n }\n\nvoid sleep() {\n\n    GIMSK |= _BV(PCIE);                     \/\/ Enable Pin Change Interrupts\n    PCMSK |= _BV(PCINT2);                   \/\/ Use PB3 as interrupt pin\n    ADCSRA &#038;= ~_BV(ADEN);                   \/\/ ADC off\n    set_sleep_mode(SLEEP_MODE_PWR_DOWN);    \/\/ replaces above statement\n\n    sleep_enable();                         \/\/ Sets the Sleep Enable bit in the MCUCR Register (SE BIT)\n    sei();                                  \/\/ Enable interrupts\n    sleep_cpu();                            \/\/ sleep\n\n    cli();                                  \/\/ Disable interrupts\n    PCMSK &#038;= ~_BV(PCINT2);                  \/\/ Turn off PB2 as interrupt pin\n    sleep_disable();                        \/\/ Clear SE bit\n    ADCSRA |= _BV(ADEN);                    \/\/ ADC on\n\n    sei();                                  \/\/ Enable interrupts\n    } \/\/ sleep\n\nISR(PCINT0_vect) {\n    \/\/ This is called when the interrupt occurs, but I don't need to do anything in it\n    }\n\n\nvoid loop() {\n\n  if (mySwitch.available()) {\n\n    sleep();\n    int value = mySwitch.getReceivedValue();\n    \n    if (value == 0) {\n\/\/      Serial.print(\"Unknown encoding\");\n    } else {\n\n        pinMode(rele,OUTPUT);\n        delay(10000);\n        pinMode(rele,INPUT);\n    }\n    mySwitch.resetAvailable();\n  }\n}<\/code><\/p>\n<p>(Explicaci\u00f3n r\u00e1pida del ejemplo: Se declaran INT0 como receptor de RF, y el Pin4 como control del rel\u00e9. Se realiza un ciclo de encendido y apagado del rel\u00e9 al inicio para mostrar que el programa ha iniciado, se declara la interrupci\u00f3n del modo de bajo consumo con INT0, y se pasa al bucle principal. Se espera a una interrupci\u00f3n, se comprueba que la se\u00f1al RF recibida es correcta, y se enciende el rel\u00e9 durante 10 segundos)<\/p>\n<p>Resultado: \u00a1\u00e9xito! No s\u00f3lo el sistema funciona, sino que he podido comprobar una gran mejora en el consumo del sistema. Durante la fase activa del programa, en la que el rel\u00e9 est\u00e1 activo y se ha recibido la se\u00f1al de radiofrecuencia, todo el sistema consume unos 9 mA. Cuando est\u00e1 en modo de bajo consumo, a la espera de recibir la se\u00f1al, baja a niveles inferiores a 1 mA.<\/avr><\/rcswitch><\/code><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Hace ya bastante tiempo escrib\u00ed algo acerca de un sistema<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"advanced_seo_description":"","jetpack_seo_html_title":"","jetpack_seo_noindex":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":false,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"font":"","enabled":false},"version":2}},"categories":[13],"tags":[31,133,168,1381,1421],"series":[],"class_list":["post-3737","post","type-post","status-publish","format-standard","hentry","category-informatica","tag-433-mhz","tag-arduino","tag-attiny85","tag-raspberry-pi","tag-rf"],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/bitacora.eniac2000.com\/index.php?rest_route=\/wp\/v2\/posts\/3737","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/bitacora.eniac2000.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/bitacora.eniac2000.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/bitacora.eniac2000.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/bitacora.eniac2000.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=3737"}],"version-history":[{"count":0,"href":"https:\/\/bitacora.eniac2000.com\/index.php?rest_route=\/wp\/v2\/posts\/3737\/revisions"}],"wp:attachment":[{"href":"https:\/\/bitacora.eniac2000.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=3737"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/bitacora.eniac2000.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=3737"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/bitacora.eniac2000.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=3737"},{"taxonomy":"series","embeddable":true,"href":"https:\/\/bitacora.eniac2000.com\/index.php?rest_route=%2Fwp%2Fv2%2Fseries&post=3737"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}