{"id":147,"date":"2017-08-07T00:24:59","date_gmt":"2017-08-07T07:24:59","guid":{"rendered":"http:\/\/eequalspi.com\/?p=147"},"modified":"2017-08-07T00:24:59","modified_gmt":"2017-08-07T07:24:59","slug":"iv-11-thermometer-software","status":"publish","type":"post","link":"https:\/\/eequalspi.com\/index.php\/2017\/08\/07\/iv-11-thermometer-software\/","title":{"rendered":"IV-11 Thermometer Software"},"content":{"rendered":"<p>&nbsp;<\/p>\n<h1>Processor<\/h1>\n<p>Okay, so the one piece of hardware that hasn&#8217;t been much discussed in this chain is the processor. I chose an atmega 328p for a couple of reasons:<\/p>\n<ol>\n<li>I can use the massive stock of Arduino libraries and IDE. For a simple project like this, where the complexity management of &#8220;adult&#8221; IDEs won&#8217;t be very useful, it&#8217;s the right tool for the job.<\/li>\n<li>I happen to have a USBTiny ISP board for in circuit programming. By dropping the atmega into the socket on an Arduino UNO and using its ISP port, I can program the micro without assembling ISP pins on my breadboard.<\/li>\n<li>I had a drawer full of atmega 328Ps.<\/li>\n<\/ol>\n<p>With the decision made, I set out to use the atmega on a breadboard, as laid out <a href=\"https:\/\/www.arduino.cc\/en\/Tutorial\/ArduinoToBreadboard\">here<\/a>. Since I&#8217;m lazy and didn&#8217;t want to lay down a crystal or capacitors, and I need next to no performance, I opted to use the internal 8MHz oscillator.<\/p>\n<p>Unlike the tutorial, I simply socketed the atmega into an unused UNO and plugged it in to my <a href=\"https:\/\/www.sparkfun.com\/products\/9825\">Sparkfun AVR Programmer<\/a>. After burning the bootloader and program, I dropped it in to my breadboard and went with it. This is the first time I&#8217;ve used the 8MHz oscillator and it did exactly what it said on the tin.<\/p>\n<h1>VFD Support<\/h1>\n<p>To drive the VFD, I initially tried to use a pre-made seven segment library, SevenSeg. Despite the fact that it looks like it should work, I couldn&#8217;t get it to turn on the display. Given that I wasn&#8217;t using any of the complex features, like multiplexing, I decided to save time bit-bang the pins myself.<\/p>\n<p>The resulting functions were as follows:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"cpp\">#define SEG_A 0\r\n#define SEG_B 1\r\n#define SEG_C 2\r\n#define SEG_D 3\r\n#define SEG_E 4\r\n#define SEG_F 5\r\n#define SEG_G 6\r\n#define SEG_DP 7\r\n#define PWR 12\r\nint pinDefinitions[8] = {SEG_A, SEG_B, SEG_C, SEG_D, SEG_E, SEG_F, SEG_G, SEG_DP}; \/\/array of pin segments\r\nbyte charArray[10] = { \/\/array of segments to light up for each digit 0-9\r\n  0b11111100,\r\n  0b01100000,\r\n  0b11011010,\r\n  0b11110010,\r\n  0b01100110,\r\n  0b10110110,\r\n  0b10111110,\r\n  0b11100000,\r\n  0b11111110,\r\n  0b11100110\r\n};\r\nvoid initSegPins(int* pins) \/\/initialize the pins\r\n{\r\n  for(int i = 0; i &lt; 8; i++)\r\n  {\r\n    pinMode(pins[i], OUTPUT);\r\n  }\r\n}\r\n\r\nvoid setDisplay(int num, int* pins) \/\/draw a digit 0-9 on pins\r\n{\r\n  num = num % 10;\r\n  byte segments = 0x00;\r\n  writeArb(charArray[num], pins);\r\n\r\n}\r\n\r\nvoid writeArb(byte segments, int* pins) \/\/draw an arbitrary byte on pins\r\n{\r\n  for(int i = 0; i &lt; 8; i++)\r\n  {\r\n    digitalWrite(pins[i], (segments&gt;&gt;(7-i))&amp;0x01);\r\n  }\r\n}\r\nvoid setDisplay(char c, int* pins) \/\/draw a character on the pins\r\n{\r\n  if((c &gt; 0x2F) &amp;&amp; (c &lt; 0x3A)) \/\/digit 0-9\r\n  {\r\n    setDisplay((int) c - 0x30, pins);\r\n  }\r\n  else\r\n  {\r\n    switch(c) {\r\n      case 'f':\r\n      case 'F':\r\n        writeArb(0b10001110, pins);\r\n        break;\r\n      case 'c':\r\n        writeArb(0b00011010, pins);\r\n        break;\r\n      case 'C':\r\n        writeArb(0b10011100, pins);\r\n        break;\r\n      case 'd':\r\n        writeArb(0b01111010, pins);\r\n        break;\r\n      case 'D':\r\n        writeArb(0b11000110, pins);\r\n        break;\r\n      case 'h':\r\n        writeArb(0b00101110, pins);\r\n        break;\r\n      case 'H':\r\n        writeArb(0b01101110, pins);\r\n        break;\r\n      case 'b':\r\n        writeArb(0b00000000, pins);\r\n        break;\r\n    };\r\n  }\r\n}\r\nvoid printNum(float num, int* pins, int delayLen = 500) \/\/print a number up to 999, rounded to nearest int\r\n{\r\n  num = round(num);\r\n  if(num &gt; 100)\r\n  {\r\n    setDisplay(int(floor(num\/100))%1000, pins);\r\n    delay(delayLen);\r\n  }\r\n  if(num &gt; 10)\r\n  {\r\n    setDisplay(int(floor(num\/10))%100, pins);\r\n    delay(delayLen);\r\n  }\r\n  setDisplay(int(floor(num))%10, pins);\r\n  delay(delayLen);\r\n}<\/pre>\n<h1>Temperature Sensor<\/h1>\n<p>The final piece of the puzzle was the DHT11 temperature sensor. Since I didn&#8217;t have one on hand, this represented the only cash expenditure for this project &#8212; $10 at Fry&#8217;s. I grabbed on OSEPP DHT11 breakout board, since it was what they had. It had the advantage of getting humidity as well, so I made the program report that in addition to temperature. Fortunately, Adafruit also sells DHT11s, so I was able to use <a href=\"https:\/\/github.com\/adafruit\/DHT-sensor-library\">their library<\/a>, although I did need to also install their <a href=\"https:\/\/github.com\/adafruit\/Adafruit_Sensor\">general sensor library<\/a>. These libraries are the real perk of using the Arduino environment, admittedly.<\/p>\n<p>The final code for the entire program is here:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"null\">#include \"DHT.h\"\r\n\r\n#define DHTPIN 13     \/\/ what digital pin we're connected to\r\n\r\n\/\/ Uncomment whatever type you're using!\r\n#define DHTTYPE DHT11   \/\/ DHT 11\r\n\r\n\/\/ Initialize DHT sensor.\r\n\/\/ Note that older versions of this library took an optional third parameter to\r\n\/\/ tweak the timings for faster processors.  This parameter is no longer needed\r\n\/\/ as the current DHT reading algorithm adjusts itself to work on faster procs.\r\nDHT dht(DHTPIN, DHTTYPE);\r\n\r\n\r\n#define SEG_A 0\r\n#define SEG_B 1\r\n#define SEG_C 2\r\n#define SEG_D 3\r\n#define SEG_E 4\r\n#define SEG_F 5\r\n#define SEG_G 6\r\n#define SEG_DP 7\r\n#define PWR 12\r\nint pinDefinitions[8] = {SEG_A, SEG_B, SEG_C, SEG_D, SEG_E, SEG_F, SEG_G, SEG_DP}; \/\/array of pin segments\r\nbyte charArray[10] = { \/\/array of segments to light up for each digit 0-9\r\n  0b11111100,\r\n  0b01100000,\r\n  0b11011010,\r\n  0b11110010,\r\n  0b01100110,\r\n  0b10110110,\r\n  0b10111110,\r\n  0b11100000,\r\n  0b11111110,\r\n  0b11100110\r\n};\r\nvoid initSegPins(int* pins) \/\/initialize the pins\r\n{\r\n  for(int i = 0; i &lt; 8; i++)\r\n  {\r\n    pinMode(pins[i], OUTPUT);\r\n  }\r\n}\r\n\r\nvoid setDisplay(int num, int* pins) \/\/draw a digit 0-9 on pins\r\n{\r\n  num = num % 10;\r\n  byte segments = 0x00;\r\n  writeArb(charArray[num], pins);\r\n\r\n}\r\n\r\nvoid writeArb(byte segments, int* pins) \/\/draw an arbitrary byte on pins\r\n{\r\n  for(int i = 0; i &lt; 8; i++)\r\n  {\r\n    digitalWrite(pins[i], (segments&gt;&gt;(7-i))&amp;0x01);\r\n  }\r\n}\r\nvoid setDisplay(char c, int* pins) \/\/draw a character on the pins\r\n{\r\n  if((c &gt; 0x2F) &amp;&amp; (c &lt; 0x3A)) \/\/digit 0-9\r\n  {\r\n    setDisplay((int) c - 0x30, pins);\r\n  }\r\n  else\r\n  {\r\n    switch(c) {\r\n      case 'f':\r\n      case 'F':\r\n        writeArb(0b10001110, pins);\r\n        break;\r\n      case 'c':\r\n        writeArb(0b00011010, pins);\r\n        break;\r\n      case 'C':\r\n        writeArb(0b10011100, pins);\r\n        break;\r\n      case 'd':\r\n        writeArb(0b01111010, pins);\r\n        break;\r\n      case 'D':\r\n        writeArb(0b11000110, pins);\r\n        break;\r\n      case 'h':\r\n        writeArb(0b00101110, pins);\r\n        break;\r\n      case 'H':\r\n        writeArb(0b01101110, pins);\r\n        break;\r\n      case 'b':\r\n        writeArb(0b00000000, pins);\r\n        break;\r\n    };\r\n  }\r\n}\r\nvoid printNum(float num, int* pins, int delayLen = 500) \/\/print a number up to 999, rounded to nearest int\r\n{\r\n  num = round(num);\r\n  if(num &gt; 100)\r\n  {\r\n    setDisplay(int(floor(num\/100))%1000, pins);\r\n    delay(delayLen);\r\n  }\r\n  if(num &gt; 10)\r\n  {\r\n    setDisplay(int(floor(num\/10))%100, pins);\r\n    delay(delayLen);\r\n  }\r\n  setDisplay(int(floor(num))%10, pins);\r\n  delay(delayLen);\r\n}\r\nvoid setup() {\r\n  \/\/ put your setup code here, to run once:\r\n  initSegPins(pinDefinitions);\r\n  digitalWrite(PWR, HIGH);\r\n  pinMode(PWR, OUTPUT);\r\n  dht.begin();\r\n  delay(500);\r\n\r\n\/\/ Read temperature as Fahrenheit (isFahrenheit = true)\r\n  float f = dht.readTemperature(true);\r\n  printNum(f, pinDefinitions);\r\n  \/\/print degree symbol and F\r\n  setDisplay('D', pinDefinitions);\r\n  delay(500);\r\n  setDisplay('f', pinDefinitions);\r\n  delay(500);\r\n\r\n  \/\/blank display\r\n  setDisplay('b', pinDefinitions);\r\n  delay(500);\r\n  \r\n  float h = dht.readHumidity(); \/\/humidity\r\n  printNum(h, pinDefinitions);\r\n  setDisplay('H', pinDefinitions);\r\n  delay(500);\r\n  \r\n  \/\/turn off system\r\n  digitalWrite(PWR, LOW);\r\n  \r\n}\r\n\r\n\r\nvoid loop() {\r\n\r\n}\r\n<\/pre>\n<h1>Conclusion<\/h1>\n<p>So, what does the final project look like? Like this!<\/p>\n<p><iframe loading=\"lazy\" src=\"https:\/\/www.youtube.com\/embed\/zJk6X0bg1ow\" width=\"560\" height=\"315\" frameborder=\"0\" allowfullscreen=\"allowfullscreen\"><\/iframe><\/p>\n<p>What is it showing? The temperature (two digits), then the degrees symbol and F. This is followed by a pause, then it reports percent humidity and the letter H (for humidity).<\/p>\n<p>That&#8217;s all folks! Hope you enjoyed the read. On to the next project.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>&nbsp; Processor Okay, so the one piece of hardware that hasn&#8217;t been much discussed in this chain is the processor. I chose an atmega 328p for a couple of reasons: I can use the massive stock of Arduino libraries and IDE. For a simple project like this, where the complexity management of &#8220;adult&#8221; IDEs won&#8217;t &hellip; <a href=\"https:\/\/eequalspi.com\/index.php\/2017\/08\/07\/iv-11-thermometer-software\/\" class=\"more-link\">Continue reading<span class=\"screen-reader-text\"> &#8220;IV-11 Thermometer Software&#8221;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[9],"tags":[],"class_list":["post-147","post","type-post","status-publish","format-standard","hentry","category-vfd"],"_links":{"self":[{"href":"https:\/\/eequalspi.com\/index.php\/wp-json\/wp\/v2\/posts\/147","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/eequalspi.com\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/eequalspi.com\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/eequalspi.com\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/eequalspi.com\/index.php\/wp-json\/wp\/v2\/comments?post=147"}],"version-history":[{"count":2,"href":"https:\/\/eequalspi.com\/index.php\/wp-json\/wp\/v2\/posts\/147\/revisions"}],"predecessor-version":[{"id":152,"href":"https:\/\/eequalspi.com\/index.php\/wp-json\/wp\/v2\/posts\/147\/revisions\/152"}],"wp:attachment":[{"href":"https:\/\/eequalspi.com\/index.php\/wp-json\/wp\/v2\/media?parent=147"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/eequalspi.com\/index.php\/wp-json\/wp\/v2\/categories?post=147"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/eequalspi.com\/index.php\/wp-json\/wp\/v2\/tags?post=147"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}