{"id":79,"date":"2014-09-21T16:41:59","date_gmt":"2014-09-21T23:41:59","guid":{"rendered":"http:\/\/www.orangemoose.com\/blog\/?p=79"},"modified":"2019-06-30T12:14:26","modified_gmt":"2019-06-30T19:14:26","slug":"exploring-arduino-interrupts","status":"publish","type":"post","link":"https:\/\/orangemoose.com\/blog\/2014\/09\/21\/exploring-arduino-interrupts\/","title":{"rendered":"Exploring Arduino Interrupts"},"content":{"rendered":"<div class=\"entry-content e-content\">I&#8217;ve been wanting to add wind &amp; rain sensors to my home-built Arduino-powered weather station and thanks to a recent sale at Sparkfun have acquired their nicely-built <a title=\"Sparkfun - Weather Meters\" href=\"https:\/\/www.sparkfun.com\/products\/8942\" target=\"_blank\" rel=\"noopener noreferrer\">set<\/a>. \u00a0As a result, though, I have two interesting problems to solve in getting those sensors integrated to the temperature and barometric pressure ones I have deployed today. \u00a0First, I need to work out where and how to install the wind\/rain sensors as placement is critical in getting good readings \u00a0Of more immediate concern, however, is that I need to rethink my weather station application in order to properly integrate the new sensors, especially the anemometer and rain gauge.<\/p>\n<p>At the moment my weather station code uses basic clock timing to read temperature and barometric pressure sensors periodically, average their values, and display the readings on a small attached OLED. Temperature and pressure sensors are continuous so their values are always available and can be read whenever desired\u00a0just based on the Arduino&#8217;s internal clock. While my new wind vane sensor also provides a continuous reading, the new anemometer and rain gauge don&#8217;t work that way. \u00a0Instead they report data discontinuously whenever they have something to share.<\/p>\n<p>In the case of the anemometer it closes an internal switch every time the cups rotate through one revolution. \u00a0Deriving wind speed from the anemometer means counting the number of revolutions over some specific period of time and calculating the number of revolutions per second. Multiplying revolutions-per-second by a fixed factor based on the size and geometry of the anemometer lets you determine average wind speed over that period of time. \u00a0You can&#8217;t simply poll the anemometer and ask it to tell you what it is observing as you can with temperature, pressure, or wind direction sensors.<\/p>\n<p>Similarly the rain gauge can&#8217;t provide a continuously-available reading, but instead closes a switch every time its internal self-emptying bucket fills and dumps. \u00a0The volume of the tiny bucket is known, so keeping track of how many times it has emptied over a specific period of time lets you figure out how much rain has fallen.<\/p>\n<p>Therefore a different approach is needed to read sporadic sensors like the anemometer and rain gauge and\u00a0keep track of every time their internal switches close, whenever that turns out to be and no matter how often. \u00a0The asynchronous, switch-closing nature of those sensors is a perfect case for interrupt-driven data gathering.<\/p>\n<p>A good overview on interrupts and how they work on Arduino is available over at <a title=\"Overview of Arduino interrupts\" href=\"http:\/\/www.engblaze.com\/we-interrupt-this-program-to-bring-you-a-tutorial-on-arduino-interrupts\/\" target=\"_blank\" rel=\"noopener noreferrer\">EngBlaze<\/a>. In my case I need to modify my weather station code to add logic to\u00a0handle the calculations to be done whenever either the anemometer or rain gauge closes their internal switch. Just as with reading my other sensors, I need to devote an Arduino pin to each of the anemometer and rain gauge so I can detect their respective switch closures. \u00a0This turns out to be pretty easy as Arduino has already set aside pins to handle two external interrupts: interrupt number 0 (or INT0) on digital pin 2 and interrupt number 1 (or INT1) on digital pin 3. \u00a0All you need to do is connect the interrupt-generating device to one of those two pins, write a simple handler function\u00a0you want to be called every time an interrupt occurs, and use the special built-in <a title=\"Arduino attachInterrupt() function\" href=\"http:\/\/arduino.cc\/en\/Reference\/attachInterrupt\" target=\"_blank\" rel=\"noopener noreferrer\">attachInterrupt<\/a> function to associate your handler with the chosen pin.<\/p>\n<p>A simple example is provided in the Arduino reference for\u00a0<a title=\"Arduino - attachInterrupt()\" href=\"http:\/\/arduino.cc\/en\/Reference\/attachInterrupt\" target=\"_blank\" rel=\"noopener noreferrer\">attachInterrupt()<\/a>. Here&#8217;s another one aligned with my intent to use interrupts to read my anemometer and calculate wind speed:<\/p>\n<pre class=\"brush: cpp; title: ; notranslate\" title=\"\">\r\n\/*\r\n * Example program for Arduino external interrupts, in this case to read\r\n * an anemometer connected to digital pin 2 (which is INT0).\r\n *\r\n * Author: David Bryant (david@orangemoose.com)\r\n *\/\r\n\r\nvolatile int interruptCnt = 0;  \/\/ Counts anemometer interrupts\r\n\r\nunsigned long sampleDelayMs = 30*1000; \/\/ Sample interval, milliseconds\r\nunsigned long prevSampleMs = 0;        \/\/ Timestamp for previous sample\r\n\r\nvoid setup()\r\n{\r\n  Serial.begin(9600);\r\n  Serial.println(&quot;Gathering data...&quot;);\r\n\r\n  \/\/ Attach our interrupt service routine to INT0\r\n  attachInterrupt(0,anemom_cnt,RISING);\r\n}\r\n\r\nvoid loop()\r\n{\r\n  unsigned long currentMillis = millis();    \/\/ Get current timer value\r\n  \/* See if it is time to calculate wind speed *\/\r\n  if( (currentMillis - prevSampleMs) &gt;= sampleDelayMs) {\r\n    Serial.print(&quot;Anemometer count: &quot;);\r\n    Serial.println(interruptCnt);\r\n\r\n    prevSampleMs = currentMillis;   \/\/ Remember clock time\r\n    interruptCnt = 0;               \/\/ Reset counter\r\n  }\r\n}\r\n\r\n\/*\r\n * Interrupt service routine called when the anemometer switch closes.\r\n * All it needs to do is increment the interrupt counter.\r\n *\/\r\nvoid anemom_cnt()\r\n{\r\n  interruptCnt++;\r\n}\r\n<\/pre>\n<p>This works well enough and is quite straightforward, but I&#8217;m not completely happy with it. \u00a0To add my anemometer and rain gauge I need two interrupts, but I&#8217;d like to make broader use of interrupts in my weather station code. For example, I&#8217;m currently using a push button to step through a series of screens\u00a0on an attached OLED so a user can browse a variety of information from the sensor including maximum and minimum readings, system statistics, etc. \u00a0At the moment that push button is read periodically as part of the sensor timing loop but it&#8217;d make more sense to have\u00a0it\u00a0generate an interrupt to\u00a0trigger stepping to the next screen. \u00a0It may also make sense to use interrupts to handle other sensors I could add, or support other system functions. Using all the available external interrupts just for the anemometer and rain gauge seems short sighted.<\/p>\n<p>Happily the Arduino supports handling interrupts on every pin, both analog and digital, through a different mechanism than INT0\/INT1 and their attachInterrupt function. \u00a0That means there&#8217;s lots of room for expansion, but it requires a bit more low-level knowledge and coding. \u00a0That&#8217;s a good subject for another blog post&#8230;<\/p><\/div>\n","protected":false},"excerpt":{"rendered":"<p>I&#8217;ve been wanting to add wind &amp; rain sensors to my home-built Arduino-powered weather station and thanks to a recent sale at Sparkfun have acquired their nicely-built set. \u00a0As a result, though, I have two interesting problems to solve in getting those sensors integrated to the temperature and barometric pressure ones I have deployed today.&hellip;<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"mf2_syndication":[],"webmentions_disabled_pings":false,"webmentions_disabled":false,"footnotes":""},"categories":[4],"tags":[9,10],"class_list":{"0":"post-79","1":"post","2":"type-post","3":"status-publish","4":"format-standard","6":"category-projects","7":"tag-arduino","8":"tag-sensors","9":"kind-article","10":"h-entry","11":"hentry"},"kind":false,"_links":{"self":[{"href":"https:\/\/orangemoose.com\/blog\/wp-json\/wp\/v2\/posts\/79","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/orangemoose.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/orangemoose.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/orangemoose.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/orangemoose.com\/blog\/wp-json\/wp\/v2\/comments?post=79"}],"version-history":[{"count":10,"href":"https:\/\/orangemoose.com\/blog\/wp-json\/wp\/v2\/posts\/79\/revisions"}],"predecessor-version":[{"id":151,"href":"https:\/\/orangemoose.com\/blog\/wp-json\/wp\/v2\/posts\/79\/revisions\/151"}],"wp:attachment":[{"href":"https:\/\/orangemoose.com\/blog\/wp-json\/wp\/v2\/media?parent=79"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/orangemoose.com\/blog\/wp-json\/wp\/v2\/categories?post=79"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/orangemoose.com\/blog\/wp-json\/wp\/v2\/tags?post=79"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}