PIC16F1454用に作成した温度センサー(DS18B20/AM2301)ライブラリをArduinoに移殖してみた。
DS18B20は”OneWire+DallasTemperature”、AM2301は”DHT_sensor_library”などが知られているが仕様的に若干気になることもある。
【DallasTemperature】
1.温度データ型と内部演算にfloat型を使っている。非力なCPUには辛い。
2.デバイスの全機能を実装しただけとも言える。使いやすいとは言えない。
3.単体接続時であってもデバイス・アドレス指定を行なうので遅い。単体接続の場合、デバイス・アドレスをスキップするだけでかなり早く処理(数ミリ秒程度)できるようになるのだが...
【DHT_sensor_library】
1.温度データ型と内部演算にfloat型を使っている。非力なCPUには辛い。
2.デバイスとの通信時、(6-7ミリ秒程度)割り込み禁止にしないと誤動作することがある。
ということで、本ライブラリはfloat型を使わない単体接続仕様となっている。得られる温湿度データは小数点以下が必要なければ右に4ビットシフトするだけで良い。参考まで。
【サンプル・コード】
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 |
#include <OneWire.h> #include "DSTSensor.h" #include "DHTSensor.h" #define ONE_WIRE_BUS 10 // データ・ポートに合わせて変更するべし! OneWire oneWire(ONE_WIRE_BUS); DSTSensor dst(&oneWire); DHTSensor dht(ONE_WIRE_BUS, DHTSENSOR_AM2301); uint8_t _sensor = 0; void setup() { Serial.begin(115200); } void loop() { switch(_sensor) { default: if (dht.handle()) { Serial.println("detect AM2301 Sensor"); _sensor = 2; } else if (dst.handle()) { Serial.println("detect DS18B20 Sensor"); _sensor = 1; } else if (_sensor == 0) { Serial.println("no device..."); _sensor = 0xFF; } break; // // DS18B20 // case 1: switch (dst.handle()) { case DSTSENSOR_NO_DEVICE: _sensor = 0; break; case DSTSENSOR_READY: Serial.print(dst.getTemperature() / 16.0); Serial.println("C"); break; } break; // // AM2301 // case 2: switch (dht.handle()) { case DHTSENSOR_NO_DEVICE: _sensor = 0; break; case DHTSENSOR_READY: Serial.print(dht.getTemperature() / 16.0); Serial.print("C, "); Serial.print(dht.getHumidity() / 16.0); Serial.println("%"); break; } break; } } |
【ライブラリ】
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 |
#ifndef _DSTSENSOR_H #define _DSTSENSOR_H #include <string.h> #include <OneWire.h> // // Option Settings // #define DSTSENSOR_PARASITE_POWER 0 #define DSTSENSOR_CONVERSION_RESPONSE 0 // // Status // #define DSTSENSOR_NO_DEVICE 0 #define DSTSENSOR_BUSY 1 #define DSTSENSOR_READY 2 // // Device resolution // #define DSTSENSOR_9BIT 0x00 #define DSTSENSOR_10BIT 0x20 #define DSTSENSOR_11BIT 0x40 #define DSTSENSOR_12BIT 0x60 // // Model IDs // #define DSTSENSOR_DS18S20 0x10 // also DS1820 #define DSTSENSOR_DS18B20 0x28 #define DSTSENSOR_DS1822 0x22 #define DSTSENSOR_DS1825 0x3B #define DSTSENSOR_DS28EA00 0x42 // // OneWire commands // #define DSTSENSOR_READROM 0x33 #define DSTSENSOR_STARTCONV 0x44 #define DSTSENSOR_WRITESCRATCH 0x4E #define DSTSENSOR_READSCRATCH 0xBE #define DSTSENSOR_COPYSCRATCH 0x48 #define DSTSENSOR_READPOWERSUPPLY 0xB4 // // Sensor Sampling Interval // #define DSTSENSOR_SAMPLING_PERIOD 2000 typedef struct { uint8_t family_code; uint8_t searial[6]; uint8_t crc; } DSTRomAddress; typedef struct { uint8_t temp_lsb; uint8_t temp_msb; uint8_t th_reg_or_ub1; uint8_t tl_reg_or_ub2; uint8_t configuration; uint8_t internal_byte; uint8_t count_remain; uint8_t count_per_c; uint8_t crc; } DSTScratchPad; typedef struct { int8_t th_reg_or_ub1; int8_t tl_reg_or_ub2; int8_t configuration; } DSTConfig; class DSTSensor { private: OneWire *_oneWire; DSTRomAddress _romAddress; DSTScratchPad _scratchPad; bool _parasite; uint8_t _status; int16_t _temperature; uint16_t _convertTime; uint16_t _cvDelayTime; uint16_t _cvStartTime; uint16_t _nextSampling; bool isDS18S20() { return (_romAddress.family_code == DSTSENSOR_DS18S20); } int8_t getResolution() { return (isDS18S20() ? DSTSENSOR_12BIT : _scratchPad.configuration); } void setup() { switch (getResolution() & DSTSENSOR_12BIT) { case DSTSENSOR_9BIT: _convertTime = 94 + 1; break; case DSTSENSOR_10BIT: _convertTime = 188 + 1; break; case DSTSENSOR_11BIT: _convertTime = 375 + 1; break; case DSTSENSOR_12BIT: default: _convertTime = 750 + 1; break; } } bool readRomAddress() { if (_oneWire->reset()) { _oneWire->write(DSTSENSOR_READROM); _oneWire->read_bytes((uint8_t *)&_romAddress, sizeof(_romAddress)); if (_oneWire->crc8((uint8_t *)&_romAddress, sizeof(_romAddress) - sizeof(_romAddress.crc)) == _romAddress.crc) { switch (_romAddress.family_code) { case DSTSENSOR_DS18S20: case DSTSENSOR_DS18B20: case DSTSENSOR_DS1822: case DSTSENSOR_DS1825: case DSTSENSOR_DS28EA00: return true; } } } return false; } bool readPowerSupply() { if (_oneWire->reset()) { _oneWire->skip(); _oneWire->write(DSTSENSOR_READPOWERSUPPLY); _parasite = (_oneWire->read_bit() == 0); #if DSTSENSOR_PARASITE_POWER return true; #else return !_parasite; #endif } return false; } bool readScratchPad() { if (_oneWire->reset()) { _oneWire->skip(); _oneWire->write(DSTSENSOR_READSCRATCH); _oneWire->read_bytes((uint8_t *)&_scratchPad, sizeof(_scratchPad)); if (_oneWire->crc8((uint8_t *)&_scratchPad, sizeof(_scratchPad) - sizeof(_scratchPad.crc)) == _scratchPad.crc) { setup(); return true; } } return false; } bool writeScratchPad() { if (_oneWire->reset()) { _oneWire->skip(); _oneWire->write(DSTSENSOR_WRITESCRATCH); _oneWire->write(_scratchPad.th_reg_or_ub1); _oneWire->write(_scratchPad.tl_reg_or_ub2); if (!isDS18S20()) _oneWire->write(_scratchPad.configuration); setup(); return true; } return false; } bool copyScratchPad() { if (_oneWire->reset()) { _oneWire->skip(); _oneWire->write(DSTSENSOR_COPYSCRATCH, _parasite); if (_parasite) delay(10); } return false; } bool startConversion() { if (_oneWire->reset()) { _oneWire->skip(); _oneWire->write(DSTSENSOR_STARTCONV, _parasite); return true; } return false; } bool connect() { if (_status == DSTSENSOR_NO_DEVICE) { if (!readRomAddress()) return false; if (!readPowerSupply()) return false; if (!readScratchPad()) return false; _status = DSTSENSOR_BUSY; _cvDelayTime = 0; } return true; } #if DSTSENSOR_CONVERSION_RESPONSE bool isConversionComplete() { return _parasite ? false : _oneWire->read_bit(); } #endif public: DSTSensor(OneWire *oneWire) : _oneWire(oneWire) , _status(DSTSENSOR_NO_DEVICE) { _nextSampling = millis() - (DSTSENSOR_SAMPLING_PERIOD >> 1); } bool getConfig(DSTConfig& config) { if (connect()) { config.th_reg_or_ub1 = _scratchPad.th_reg_or_ub1; config.tl_reg_or_ub2 = _scratchPad.tl_reg_or_ub2; config.configuration = getResolution(); return true; } return false; } bool setConfig(DSTConfig& config, bool update = true) { DSTConfig save; if (getConfig(save)) { if (isDS18S20()) { if (config.configuration != DSTSENSOR_12BIT) return false; } else { if ((config.configuration < DSTSENSOR_9BIT) || (config.configuration > DSTSENSOR_12BIT)) return false; } if (memcmp(&config, &save, sizeof(save)) == 0) return true; _scratchPad.th_reg_or_ub1 = config.th_reg_or_ub1; _scratchPad.tl_reg_or_ub2 = config.tl_reg_or_ub2; _scratchPad.configuration = config.configuration | (_scratchPad.configuration & ~DSTSENSOR_12BIT); if (writeScratchPad()) return (update ? copyScratchPad() : true); _scratchPad.th_reg_or_ub1 = save.th_reg_or_ub1; _scratchPad.tl_reg_or_ub2 = save.tl_reg_or_ub2; _scratchPad.configuration = save.configuration; } return false; } int16_t getTemperature() { return _temperature; } uint8_t handle() { if ((_status == DSTSENSOR_BUSY) && _cvDelayTime) { #if DSTSENSOR_CONVERSION_RESPONSE if ((((uint16_t)millis() - _cvStartTime) >= _cvDelayTime) || isConversionComplete()) #else if (((uint16_t)millis() - _cvStartTime) >= _cvDelayTime) #endif { _cvDelayTime = 0; if (!readScratchPad()) return _status = DSTSENSOR_NO_DEVICE; _temperature = ((int16_t)_scratchPad.temp_msb << 8) | _scratchPad.temp_lsb; if (isDS18S20()) _temperature = ((_temperature & 0xFFFE) << 3) - 2 + ((_scratchPad.count_per_c - _scratchPad.count_remain) << 4) / _scratchPad.count_per_c; _status = DSTSENSOR_READY; } } else if ((uint16_t)((uint16_t)millis() - _nextSampling) >= DSTSENSOR_SAMPLING_PERIOD) { _nextSampling += DSTSENSOR_SAMPLING_PERIOD; if (connect()) { if (!startConversion()) return _status = DSTSENSOR_NO_DEVICE; _cvDelayTime = _convertTime; _cvStartTime = millis(); _status = DSTSENSOR_BUSY; } } else if (_status == DSTSENSOR_READY) _status = DSTSENSOR_BUSY; return _status; } }; #endif |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 |
#ifndef _DHTSENSOR_H #define _DHTSENSOR_H // // Status // #define DHTSENSOR_NO_DEVICE 0 #define DHTSENSOR_BUSY 1 #define DHTSENSOR_READY 2 // // Sensor Type // #define DHTSENSOR_DHT11 0 #define DHTSENSOR_DHT21 1 #define DHTSENSOR_DHT22 2 #define DHTSENSOR_AM2301 DHTSENSOR_DHT21 #define DHTSENSOR_AM2302 DHTSENSOR_DHT22 // // Sensor Sampling Interval // #define DHTSENSOR_SAMPLING_PERIOD 2000 class DHTSensor { private: uint8_t _pin; uint8_t _type; uint8_t _status; uint16_t _humidity; uint16_t _temperature; uint16_t _nextSempling; uint8_t _data[5]; uint8_t waitSignal(uint8_t state) { for (uint8_t i = 0; i < 255; ++i) { if (digitalRead(_pin) == state) return i; } return 0xFF; } bool readResponse() { uint8_t lo, hi, off; // // Wait Sensor responce // if (waitSignal(LOW) == 0xFF) return false; sei(); cli(); if (waitSignal(HIGH) == 0xFF) return false; if ((lo = waitSignal(LOW)) == 0xFF) return false; lo = (lo >> 1) + (lo >> 3); // // Recieve bit data // for (uint8_t i = 0; i < sizeof(_data) << 3; ++i) { sei(); cli(); if (waitSignal(HIGH) == 0xFF) return false; if ((hi = waitSignal(LOW)) == 0xFF) return false; off = i >> 3; _data[off] <<= 1; if (lo < hi) _data[off] |= 1; } return true; } bool read() { bool rv; // // Start signal // digitalWrite(_pin, LOW); pinMode(_pin, OUTPUT); delay(1); // // Read response // cli(); pinMode(_pin, INPUT); digitalWrite(_pin, HIGH); rv = readResponse(); sei(); // // Check SUM // if (!rv || ((uint8_t)(_data[0] + _data[1] + _data[2] + _data[3]) != _data[4])) return false; // // Temperature (x16) and Humidity (x16) // switch (_type) { case DHTSENSOR_DHT11: _humidity = (uint16_t)_data[0] << 4; _temperature = (uint16_t)_data[2] << 4; break; case DHTSENSOR_DHT22: case DHTSENSOR_DHT21: _humidity = ((((uint16_t) _data[0] << 8) | _data[1]) << 4) / 10; _temperature = ((((uint16_t)(_data[2] & 0x7F) << 8) | _data[3]) << 4) / 10; if (_data[2] & 0x80) _temperature = - _temperature; break; } return true; } public: DHTSensor(uint8_t pin, uint8_t type) : _pin(pin) , _type(type) , _status(DHTSENSOR_NO_DEVICE) { pinMode(_pin, INPUT_PULLUP); _nextSempling = millis(); } int16_t getTemperature() { return _temperature; } int16_t getHumidity() { return _humidity; } uint8_t handle() { if ((uint16_t)((uint16_t)millis() - _nextSempling) >= DHTSENSOR_SAMPLING_PERIOD) { _nextSempling += DHTSENSOR_SAMPLING_PERIOD; _status = read() ? DHTSENSOR_READY : DHTSENSOR_NO_DEVICE; } else if (_status == DHTSENSOR_READY) _status = DHTSENSOR_BUSY; return _status; } }; #endif |