アマゾンで安く売られていたので中華製のチップかなと思いつつも駄目元で購入したのだが調べたところ型番だけ見ると日本の有名な会社であるローム社のチップらしい。但し、本物かどうかは不明。(-_-;)
HiLetgo 3個セット BH1750FVI BH1750 GY-302 3V-5V デジタル 光量センサモジュール AVR Arduinoに対応 [並行輸入品]
とりあえずArduinoのライブラリリストで紹介されていた物を使ってみて問題なく動作はしたものの若干気になる部分もあったので新たに作ってみることにした。データシートではイマイチ詳細不明な部分もあったがとりあえず完成。手持ちの照度計との比較ではそれなりに誤差はあるものの十分使えるレベルかと思う。但し、10ルクス以下は高分解能モードでなんとか認識できる程度だ。
で、なんで新たに作ってみることにしたのかと言うと、
1.浮動小数点演算を使っている。
2.コードが若干わかりづらく少し大きめ。
くらいなもので問題ないと言えば問題ないのだが...だいぶ、昔に作った感のあるコードでもあったし、比較的単純なコードという感じでもあったことから、参考にさせて頂いた上で自分の理解を深めるためにも独自のコードを作ってみることにした。不必要なクラスも含まれているが今までに紹介したクラスを改良したものなのでセット物として理解してもらいたい。
【概要】
1 2 |
template<typename IOBUS_T = TWIBUS<BH1750_DEFAULT_SLAVE_ADDRESS>> class BH1750 |
テンプレート・クラス。IOBUS_TにはPBUSIFクラスを継承したクラスを指定する。規定ではArduino標準のTwoWire(Wire)クラスを利用するインターフェースを使用する。
1 |
void begin(void) |
I2C初期処理を行う。
1 |
void end(void) |
I2C終了処理を行う。
1 |
bool reset(void) |
BH1750のリセット処理を実行する。呼び出し後はPOWER_ONモードに移行する。MTregの値は初期化されないことに注意すべし。
1 |
void mtreg(int val = 0) |
Measurement Time Registerの値を設定する。規定値(BH1750_DEFAULT_MTREG_VALUE) からの+-相対値を指定する。この呼出し後のstart()呼び出しにより実行されることに注意。
1 |
bool start(BH1750_MODE mode = BH1750_CONTINUOUSLY_H_RESOLUTION_MODE2) |
計測を開始する。One Timeモードを指定した場合は計測完了まで待ってからリターンし、Continuouslyモードを指定した場合は即座にリターンする。
10ルクス未満を計測する場合は規定値のBH1750_CONTINUOUSLY_H_RESOLUTION_MODE2を指定する必要がある。
1 |
bool stop(void) |
Continuouslyモードの計測を停止しPOWER_DOWN(省電力)モードに移行する。One Timeモードでは計測完了後にPOWER_DOWNモードに自動的に移行するのでこの呼出しは必要ではない。
1 |
uint32_t lux(uint8_t accuracy = BH1750_DEFAULT_ACCURACY) |
直前の計測値(固定小数点形式)を取得する。小数点以下が必要でなければ4ビット右シフトするだけで良い。四捨五入するには8を足してから右シフトする。オプションとして変換精度値を変更することが出来る。が、役に立つかどうかは不明。詳しくはデータシート参照してほしい。
1 |
bool handle(void) |
Continuouslyモードをハンドリングする。戻り値として計測が完了するとtrue、計測中であればfalseが返される。
【サンプル・スケッチ】
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 |
#include "BH1750.h" BH1750<> bh1750; uint32_t start; void setup(void) { Serial.begin(115200); bh1750.begin(); bh1750.start(); start = millis(); } void loop(void) { static bool ready = false; if (millis() - start >= 1000) { start += 1000; if (ready) Serial.println((float)bh1750.lux() / _BV(BH1750_FIXED_POINT_NBITS)); } if (bh1750.handle()) ready = true; } |
【ライブラリ】
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 |
/* BH1750.h - Light Sensor Library for Rohme BH1750 Copyright (c) 2021 Sasapea's Lab. All right reserved. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef _BH1750_H #define _BH1750_H #include <stdint.h> #include <stdbool.h> #include "twibus.h" typedef enum { BH1750_CONTINUOUSLY_H_RESOLUTION_MODE, BH1750_CONTINUOUSLY_H_RESOLUTION_MODE2, BH1750_CONTINUOUSLY_L_RESOLUTION_MODE, BH1750_ONE_TIME_H_RESOLUTION_MODE, BH1750_ONE_TIME_H_RESOLUTION_MODE2, BH1750_ONE_TIME_L_RESOLUTION_MODE, } BH1750_MODE; #define BH1750_DEFAULT_SLAVE_ADDRESS 0x23 #define BH1750_DEFAULT_MTREG_VALUE 69 // this value range (31 - 254) #define BH1750_DEFAULT_ACCURACY 120 // this value range (96 - 144) #define BH1750_FIXED_POINT_NBITS 4 template<typename IOBUS_T = TWIBUS<BH1750_DEFAULT_SLAVE_ADDRESS>> class BH1750 { private: typedef enum : uint8_t { POWER_DOWN = 0x00, POWER_ON = 0x01, RESET = 0x07, CONTINUOUSLY_H_RESOLUTION_MODE = 0x10, CONTINUOUSLY_H_RESOLUTION_MODE2 = 0x11, CONTINUOUSLY_L_RESOLUTION_MODE = 0x13, ONE_TIME_H_RESOLUTION_MODE = 0x20, ONE_TIME_H_RESOLUTION_MODE2 = 0x21, ONE_TIME_L_RESOLUTION_MODE = 0x23, CHANGE_MEASUREMENT_TIME_H_BIT = 0x40, CHANGE_MEASUREMENT_TIME_L_BIT = 0x60, } INSTRUCTIONS; IOBUS_T _iobus; INSTRUCTIONS _cmode; uint8_t _fppos; uint8_t _mtreg; uint16_t _ctime; uint16_t _dtime; uint16_t _start; uint16_t _result; bool write(INSTRUCTIONS inst) { return _iobus.write((uint8_t *)&inst, sizeof(inst)) == sizeof(inst); } bool read(void) { uint8_t data[2]; if (_iobus.read(data, sizeof(data)) != sizeof(data)) return false; _result = ((uint16_t)data[0] << 8) | data[1]; _fppos = ((_cmode & 0x03) == 0x01 ? 1 : 0); return true; } bool measurement(INSTRUCTIONS mode) { // Change Measurement Time if (_mtreg) { if (!write((INSTRUCTIONS)(CHANGE_MEASUREMENT_TIME_H_BIT | ((_mtreg >> 5) & 0x07)))) return false; if (!write((INSTRUCTIONS)(CHANGE_MEASUREMENT_TIME_L_BIT | (_mtreg & 0x1F)))) return false; } // Start Measurement if (!write(mode)) return false; _start = millis(); _cmode = mode; _dtime = (mode & 0x02 ? 24 : 180); // TYP 16 : 120, MAX 24 : 180 _ctime = (_mtreg ? _dtime << 1 : _dtime); _mtreg = 0; // One Time Measurement mode ? if (mode & ONE_TIME_H_RESOLUTION_MODE) { delay(_ctime); if (!read()) return false; // NACK ? } return true; } bool power(bool on) { return write(on ? POWER_ON : POWER_DOWN); } public: BH1750(void) : _cmode(POWER_DOWN) , _fppos(0) , _mtreg(BH1750_DEFAULT_MTREG_VALUE) , _ctime(0) , _dtime(0) , _start(0) , _result(0) { } virtual ~BH1750(void) { } void begin(void) { _iobus.begin(); } void end(void) { stop(); _iobus.end(); } bool reset(void) { return power(true) ? write(RESET) : false; } void mtreg(int val = 0) { val += BH1750_DEFAULT_MTREG_VALUE; if (val < 31) val = 31; else if (val > 254) val = 254; _mtreg = val; } bool start(BH1750_MODE mode = BH1750_CONTINUOUSLY_H_RESOLUTION_MODE2) { const INSTRUCTIONS MODES[] = { CONTINUOUSLY_H_RESOLUTION_MODE, CONTINUOUSLY_H_RESOLUTION_MODE2, CONTINUOUSLY_L_RESOLUTION_MODE, ONE_TIME_H_RESOLUTION_MODE, ONE_TIME_H_RESOLUTION_MODE2, ONE_TIME_L_RESOLUTION_MODE, }; return measurement(MODES[mode]); } bool stop(void) { return power(false); } uint32_t lux(uint8_t accuracy = BH1750_DEFAULT_ACCURACY) { if (accuracy < 96) accuracy = 96; else if (accuracy > 144) accuracy = 144; if (BH1750_FIXED_POINT_NBITS > 0) return ((uint32_t)_result << (+ BH1750_FIXED_POINT_NBITS - _fppos)) * 100 / accuracy; else return ((uint32_t)_result >> (- BH1750_FIXED_POINT_NBITS + _fppos)) * 100 / accuracy; } bool handle(void) { // Continuously Measurement mode ? if (_cmode & CONTINUOUSLY_H_RESOLUTION_MODE) { if ((uint16_t)((uint16_t)millis() - _start) >= _ctime) { _start += _ctime; _ctime = _dtime; return read(); } } return false; } }; #endif |
【IOインターフェース・クラス】
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 |
/* pbusif.h - Peripheral I/O BUS Interface Class Copyright (c) 2021 Sasapea's Lab. All right reserved. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef __PBUSIF_H #define __PBUSIF_H #include <stdint.h> #include <stdbool.h> #ifdef ARDUINO #include "Arduino.h" #endif class PBUSIF { private: int _error; public: PBUSIF(void) : _error(0) { } virtual ~PBUSIF(void) { } virtual int error(int err) { #ifdef ARDUINO #if ARDUINO_DEBUG if (err) { Serial.print("error = "); Serial.println(err); } #endif #endif return _error = err; } virtual int error(void) { return _error; } virtual void begin(void) { } virtual void end(void) { } virtual uint8_t write(const uint8_t *buf, uint8_t len) { return writeAndRead(buf, len, 0, 0); } virtual uint8_t read(uint8_t *buf, uint8_t len) { return writeAndRead(0, 0, buf, len); } virtual uint8_t writeAndRead(const uint8_t *wbuf, uint8_t wlen, uint8_t *rbuf, uint8_t rlen) = 0; }; #endif |
【TWI実装クラス】
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 |
/* twibus.h - TWI Implementation Class for Arduino Wire Copyright (c) 2021 Sasapea's Lab. All right reserved. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef __TWIBUS_H #define __TWIBUS_H #include "pbusif.h" #include "Wire.h" extern uint8_t TWIBUS_device_count; extern uint32_t TWIBUS_device_clock; template<uint8_t SLAVE, uint32_t CLOCK = 1000000> class TWIBUS : public PBUSIF { public: TWIBUS(void) { } virtual ~TWIBUS(void) { } virtual void begin(void) override { if (++TWIBUS_device_count == 1) Wire.begin(); if (TWIBUS_device_clock > CLOCK) Wire.setClock(TWIBUS_device_clock = CLOCK); } virtual void end(void) override { if (TWIBUS_device_count && (--TWIBUS_device_count == 0)) Wire.end(); } virtual uint8_t writeAndRead(const uint8_t *wbuf, uint8_t wlen, uint8_t *rbuf, uint8_t rlen) override { uint8_t cnt = 0; error(0); if (wbuf && wlen) { Wire.beginTransmission(SLAVE); Wire.write(wbuf, wlen); if (error(Wire.endTransmission(!(rbuf && rlen))) != 0) return 0; // transmit failed. cnt = wlen; } if (rbuf && rlen) { Wire.requestFrom(SLAVE, rlen); cnt = Wire.readBytes(rbuf, rlen); } return cnt; } }; #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 |
/* twibus.cpp - TWI Implementation Class for Arduino Wire Copyright (c) 2021 Sasapea's Lab. All right reserved. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include <stdint.h> uint8_t TWIBUS_device_count = 0; uint32_t TWIBUS_device_clock = UINT32_MAX; |
【SPI実装クラス。今回は使っていないので必要ない】
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 |
/* spibus.h - SPI Implementation Class for Arduino SPI Copyright (c) 2021 Sasapea's Lab. All right reserved. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef __SPIBUS_H #define __SPIBUS_H #include "pbusif.h" #include "SPI.h" extern uint8_t SPIBUS_device_count; template<uint8_t CS, uint32_t CLOCK = 4000000, uint8_t MODE = SPI_MODE3, uint8_t BITORDER = MSBFIRST> class SPIBUS : public PBUSIF { private: SPISettings _mode; public: SPIBUS(void) { _mode = SPISettings(CLOCK, BITORDER, MODE); } virtual ~SPIBUS(void) { } virtual void begin(void) override { digitalWrite(CS, HIGH); pinMode(CS, OUTPUT); if (++SPIBUS_device_count == 1) SPI.begin(); } virtual void end(void) override { if (SPIBUS_device_count && (--SPIBUS_device_count == 0)) SPI.end(); pinMode(CS, INPUT); } virtual uint8_t writeAndRead(const uint8_t *wbuf, uint8_t wlen, uint8_t *rbuf, uint8_t rlen) override { uint8_t cnt = 0; SPI.beginTransaction(_mode); digitalWrite(CS, LOW); if (wbuf) { while (wlen--) SPI.transfer(wbuf[cnt++]); } if (rbuf) { cnt = 0; while (rlen--) rbuf[cnt++] = SPI.transfer(0xFF); } digitalWrite(CS, HIGH); SPI.endTransaction(); return cnt; } }; #endif |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
/* spibus.h - SPI Implementation Class for Arduino SPI Copyright (c) 2021 Sasapea's Lab. All right reserved. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include <stdint.h> uint8_t SPIBUS_device_count = 0; |