{"id":34,"date":"2013-08-20T12:30:11","date_gmt":"2013-08-20T11:30:11","guid":{"rendered":"http:\/\/www.sarbyn.com\/tech\/?p=34"},"modified":"2014-01-01T16:11:37","modified_gmt":"2014-01-01T15:11:37","slug":"thermistor-sample-code-for-arduino-raspberry","status":"publish","type":"post","link":"https:\/\/www.sarbyn.com\/blog\/2013\/08\/20\/thermistor-sample-code-for-arduino-raspberry\/","title":{"rendered":"Thermistor sample code for Arduino &#8211; Raspberry"},"content":{"rendered":"<p>This is a C++ class for a simple NTC thermistor. I used the thermistor included in the cooking-hacks.com starter kit (<a href=\"http:\/\/www.cooking-hacks.com\/skin\/frontend\/default\/cooking\/pdf\/159-282-86001.pdf\">datasheet<\/a>) and the cooking-hacks.com Raspebby to Arduino shield, but this sample is easily adaptable for any NTC thermistor or also for Arduino platform. It can be used with another NTC thermistor: simply change the BasicThermistor.h values:<\/p>\n<ul>\n<li>BETA (o B-Value) : the beta value of thermistor<\/li>\n<li>THERMISTOR: zero power resistance at 25\u00b0 C<\/li>\n<\/ul>\n<div id=\"attachment_56\" style=\"width: 310px\" class=\"wp-caption aligncenter\"><a href=\"https:\/\/i0.wp.com\/www.sarbyn.com\/tech\/wp-content\/uploads\/2013\/08\/basicThermistor.png\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" aria-describedby=\"caption-attachment-56\" class=\"size-medium wp-image-56\" alt=\"BasicThermistor schema\" src=\"https:\/\/i0.wp.com\/www.sarbyn.com\/tech\/wp-content\/uploads\/2013\/08\/basicThermistor-300x87.png?resize=300%2C87\" width=\"300\" height=\"87\" srcset=\"https:\/\/i0.wp.com\/www.sarbyn.com\/blog\/wp-content\/uploads\/2013\/08\/basicThermistor.png?resize=300%2C87&amp;ssl=1 300w, https:\/\/i0.wp.com\/www.sarbyn.com\/blog\/wp-content\/uploads\/2013\/08\/basicThermistor.png?w=500&amp;ssl=1 500w\" sizes=\"(max-width: 300px) 100vw, 300px\" \/><\/a><p id=\"caption-attachment-56\" class=\"wp-caption-text\">BasicThermistor schema<\/p><\/div>\n<p>Some notes:<\/p>\n<ul>\n<li>This class is designed for a read every 10 seconds.<\/li>\n<li>Check the real value of 10k resistance with a multimeter! The 10% tollerance changes the value of about \u00b1\u00a01\u00b0 C!. In my example I use 9840 <b>\u03a9\u00a0<\/b>instead of 10000\u00a0<b>\u03a9<\/b><\/li>\n<li>I use a arithmetic mean over 12 readings (2 minutes) in order to normalize the temperature value and discard read errors<\/li>\n<li>I use a simple &#8220;is_valid_value&#8221; function that discard a macroscopic read error. A &#8220;digital&#8221; read error of \u00b1 20 is converted to an error of\u00a0\u00b1 14\u00b0 C ! So if the previous valueis too big or too small, discard the current value<\/li>\n<\/ul>\n<p>Header file &#8211; BasicThermistor.h<\/p>\n<pre class=\"brush: cpp; collapse: true; light: false; title: BasicThermistor.h - click to expand; toolbar: true; notranslate\" title=\"BasicThermistor.h - click to expand\">\r\n\/*\r\n * BasicThermistor.h\r\n *\r\n * Created on: 07\/ago\/2013\r\n * Author: sarbyn\r\n * Website: http:\/\/www.sarbyn.com\r\n *\/\r\n#ifndef BASICTHERMISTOR_H_\r\n#define BASICTHERMISTOR_H_\r\n\r\n#include &amp;quot;arduPi.h&amp;quot;\r\n#include\r\n\r\n\/**\r\n * Based on cooking-hacks NTC thermistor - datasheet available at\r\n * http:\/\/www.cooking-hacks.com\/skin\/frontend\/default\/cooking\/pdf\/159-282-86001.pdf\r\n *\/\r\n\r\n\/\/ The real 10k resistor value\r\n#define TENKRESISTOR 9840.0f\r\n\/\/ Thermistor beta value (from datasheet)\r\n#define BETA 3950.0f\r\n\/\/ The thermistor value at room temp (25 C)\r\n\/\/ the original value was 2800 ohm\r\n#define THERMISTOR 2700.0f\r\n\/\/ The room temperature (25 C) in kelvin\r\n#define ROOMTEMPK 298.15f\r\n\r\n\/\/ Number of readings over which calculate\r\n\/\/ the temperature\r\n#define READINGS 12\r\n\/\/ Delay (in ms) between Wire operations\r\n#define DELAY_BETWEEN_OPERATION 20\r\n\r\n\/\/ The digital value readed from ADC\r\n\/\/ must be lower than DIGITAL_TOLLERANCE\r\n\/\/ Otherwise it is treaded as a read error\r\n#define DIGITAL_TOLLERANCE 20\r\n\/\/ If the digital value readed from ADC is wrong for\r\n\/\/ more than DIGITAL_TOLLERANCE_COUNTER, it is a correct value\r\n\/\/ and so use it. This is used in case of sudden\r\n\/\/ temperature change. If the temperature changes suddenly,\r\n\/\/ the value is discarded for DIGITAL_TOLLERANCE_COUNTER reads. After that\r\n\/\/ the value is accepted\r\n#define DIGITAL_TOLLERANCE_COUNTER 6\r\n\r\n#define ADC_I2C_ADDRESS 8\r\n\r\nclass BasicThermistor {\r\npublic:\r\n   BasicThermistor(byte i2c_address, boolean debug_flag);\r\n   float read_temperature();\r\nprivate:\r\n   byte address;\r\n   boolean debug;\r\n   int digital_value;\r\n   float read_buffer&#x5B;READINGS];\r\n   unsigned int cached_digital_value;\r\n   float temperature;\r\n   int invalid_read_counter;\r\n   int buffer_pointer;\r\n\r\n   int read_digital_value();\r\n   int is_valid_value(int value);\r\n   float calc_temperature(int value);\r\n};\r\n\r\n#endif \/* BASICTHERMISTOR_H_ *\/\r\n<\/pre>\n<p>Class file &#8211; BasicThermistor.cpp<\/p>\n<pre class=\"brush: cpp; collapse: true; light: false; title: BasicThermistor.cpp - Click to expand; toolbar: true; notranslate\" title=\"BasicThermistor.cpp - Click to expand\">\r\n\/*\r\n * BasicThermistor.cpp\r\n *\r\n * Created on: 07\/ago\/2013\r\n * Author: sarbyn\r\n * Website: http:\/\/www.sarbyn.com\r\n *\r\n *\/\r\n\r\n\/**\r\n * Based on cooking-hacks NTC thermistor - datasheet available at\r\n * http:\/\/www.cooking-hacks.com\/skin\/frontend\/default\/cooking\/pdf\/159-282-86001.pdf\r\n *\/\r\n\r\n#include &amp;quot;BasicThermistor.h&amp;quot;\r\n\r\n\/\/ Costructor\r\nBasicThermistor::BasicThermistor(byte i2c_address, boolean debug_flag) {\r\n  address = i2c_address;\r\n  debug = debug_flag;\r\n  temperature = 0.0;\r\n  cached_digital_value = 0;\r\n  digital_value = 0;\r\n  invalid_read_counter = 0;\r\n  buffer_pointer = 0;\r\n\r\n  for (int i = 0; i &amp;lt; READINGS; i++) {\r\n    read_buffer&#x5B;i] = -1.0f;\r\n  }\r\n}\r\n\/\/ Read the digital value from ADC using Wire class\r\nint BasicThermistor::read_digital_value() {\r\n  unsigned char val_0 = 0;\r\n  unsigned char val_1 = 0;\r\n  unsigned int digital_value;\r\n  Wire.beginTransmission(ADC_I2C_ADDRESS);\r\n  Wire.write(address);\r\n  \/\/ sleep in order to reduce read error\r\n  delay(DELAY_BETWEEN_OPERATION);\r\n  Wire.requestFrom(ADC_I2C_ADDRESS, 2);\r\n  \/\/ sleep in order to reduce read error\r\n  delay(DELAY_BETWEEN_OPERATION);\r\n  val_0 = Wire.read();\r\n  \/\/ sleep in order to reduce read error\r\n  delay(DELAY_BETWEEN_OPERATION);\r\n  val_1 = Wire.read();\r\n  \/\/ sleep in order to reduce read error\r\n  delay(DELAY_BETWEEN_OPERATION);\r\n  digital_value = int(val_0)*16 + int(val_1&amp;gt;&amp;gt;4);\r\n\r\n  if (debug) {\r\n    printf(&amp;quot;&#x5B;BT] val &#x5B;%2x,%2x]\\n&amp;quot;, val_0, val_1);\r\n    printf(&amp;quot;&#x5B;BT] Read digital value %d\\n&amp;quot;, digital_value);\r\n  }\r\n  return digital_value;\r\n}\r\n\r\n\/\/ Check if the readed value is valid\r\nint BasicThermistor::is_valid_value(int value) {\r\n  if (cached_digital_value == 0) {\r\n    cached_digital_value = value;\r\n    return 1;\r\n  }\r\n\r\n  \/\/ check against DIGITAL_TOLLERANCE\r\n  if (abs(cached_digital_value - value) &amp;lt; DIGITAL_TOLLERANCE) {\r\n    if (debug) printf(&amp;quot;&#x5B;BT] Valid digital value %d\\n&amp;quot;, value);\r\n    cached_digital_value = value;\r\n    invalid_read_counter = 0;\r\n    return 1;\r\n  }\r\n  if (invalid_read_counter &amp;gt; DIGITAL_TOLLERANCE_COUNTER) {\r\n    \/\/ too many invalid readings ---&amp;gt; this is a valid read\r\n   if (debug) printf(&amp;quot;&#x5B;BT] Too many invalid digital value %d..so use it\\n&amp;quot;, value);\r\n   cached_digital_value = value;\r\n   invalid_read_counter = 0;\r\n   return 1;\r\n }\r\n\r\n  \/\/ throw away invalid reading\r\n  invalid_read_counter++;\r\n  if (debug) printf(&amp;quot;&#x5B;BT] Invalid digital value %d\\n&amp;quot;, value);\r\n  return 0;\r\n}\r\n\r\n\/\/ Convert the ADC value to Celsius Temperature\r\nfloat BasicThermistor::calc_temperature(int value) {\r\n  \/\/ convert value\r\n  float analog_value = value * 1023.0 \/ 4095.0;\r\n\r\n  analog_value = (1023 \/ analog_value) - 1;\r\n  analog_value = TENKRESISTOR \/ analog_value;\r\n  analog_value = analog_value \/ THERMISTOR;\r\n\r\n  if (debug) printf(&amp;quot;&#x5B;BT] Analog value %f\\n&amp;quot;, analog_value);\r\n\r\n  float kelvin = log(analog_value);\r\n  kelvin \/= BETA;\r\n  kelvin += 1.0 \/ ROOMTEMPK;\r\n  kelvin = 1.0 \/ kelvin;\r\n\r\n  return kelvin - 273.15;\r\n}\r\n\r\n\/\/ Main read function: read the current temperature and return it.\r\n\/\/ This is designed for a read every 10 seconds: it collects 12 readings\r\n\/\/ (READINGS macro value, 2 minutes) and calculate mean over all the values.\r\n\/\/ In this way the temperature value does not change suddenly and\r\n\/\/ become more stable\r\nfloat BasicThermistor::read_temperature() {\r\n  digital_value = read_digital_value();\r\n  float single_temperature;\r\n  if (is_valid_value(digital_value)) {\r\n    single_temperature = calc_temperature(digital_value);\r\n    if (debug) printf(&amp;quot;&#x5B;BT] Single current temperature is %f\\n&amp;quot;, single_temperature);\r\n  } else {\r\n    single_temperature = calc_temperature(cached_digital_value);\r\n    if (debug) printf(&amp;quot;&#x5B;BT] Invalid temp, using cached value %f\\n&amp;quot;, single_temperature);\r\n  }\r\n\r\n  if (debug)\r\n    printf(&amp;quot;&#x5B;BT] Storing the temp at pointer %d\\n&amp;quot;, buffer_pointer);\r\n\r\n  read_buffer&#x5B;buffer_pointer] = single_temperature;\r\n  buffer_pointer++;\r\n\r\n  if (read_buffer&#x5B;buffer_pointer] == -1.0f) {\r\n    \/\/ this is the first reading....init the buffer\r\n    for (int i = buffer_pointer; i &amp;lt; READINGS; i++) {\r\n      read_buffer&#x5B;i] = single_temperature;\r\n    }\r\n  }\r\n\r\n  \/\/ reset the pointer\r\n  if (buffer_pointer == READINGS) buffer_pointer = 0;\r\n\r\n  temperature = 0;\r\n\r\n  if (debug) {\r\n    printf(&amp;quot;&#x5B;BT] Temp. buffer&#x5B;&amp;quot;);\r\n    for (int i = 0; i &amp;lt; READINGS; i++) {\r\n      printf(&amp;quot;%0.1f,&amp;quot;, read_buffer&#x5B;i]);\r\n    }\r\n    printf(&amp;quot;]\\n&amp;quot;);\r\n  }\r\n\r\n  for (int i = 0; i &amp;lt; READINGS; i++) {\r\n    temperature += read_buffer&#x5B;i];\r\n  }\r\n\r\n  temperature \/= READINGS;\r\n\r\n  return temperature;\r\n}\r\n<\/pre>\n","protected":false},"excerpt":{"rendered":"<p>This is a C++ class for a simple NTC thermistor. I used the thermistor included in the cooking-hacks.com starter kit (datasheet) and the cooking-hacks.com Raspebby to Arduino shield, but this sample is easily adaptable for any NTC thermistor or also for Arduino platform. It can be used with another NTC thermistor: simply change the BasicThermistor.h <a class=\"read-more\" href=\"https:\/\/www.sarbyn.com\/blog\/2013\/08\/20\/thermistor-sample-code-for-arduino-raspberry\/\">&hellip;&nbsp;<span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"jetpack_post_was_ever_published":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":true,"jetpack_social_options":{"image_generator_settings":{"template":"highway","enabled":false},"version":2}},"categories":[10],"tags":[21,32,31],"class_list":["post-34","post","type-post","status-publish","format-standard","hentry","category-examples","tag-arduino","tag-raspberry","tag-thermistor"],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","jetpack_shortlink":"https:\/\/wp.me\/p3JApm-y","jetpack_likes_enabled":true,"jetpack-related-posts":[],"jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/www.sarbyn.com\/blog\/wp-json\/wp\/v2\/posts\/34"}],"collection":[{"href":"https:\/\/www.sarbyn.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.sarbyn.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.sarbyn.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.sarbyn.com\/blog\/wp-json\/wp\/v2\/comments?post=34"}],"version-history":[{"count":23,"href":"https:\/\/www.sarbyn.com\/blog\/wp-json\/wp\/v2\/posts\/34\/revisions"}],"predecessor-version":[{"id":57,"href":"https:\/\/www.sarbyn.com\/blog\/wp-json\/wp\/v2\/posts\/34\/revisions\/57"}],"wp:attachment":[{"href":"https:\/\/www.sarbyn.com\/blog\/wp-json\/wp\/v2\/media?parent=34"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.sarbyn.com\/blog\/wp-json\/wp\/v2\/categories?post=34"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.sarbyn.com\/blog\/wp-json\/wp\/v2\/tags?post=34"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}