第一次
This commit is contained in:
5
.gitignore
vendored
Normal file
5
.gitignore
vendored
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
.pio
|
||||||
|
.vscode/.browse.c_cpp.db*
|
||||||
|
.vscode/c_cpp_properties.json
|
||||||
|
.vscode/launch.json
|
||||||
|
.vscode/ipch
|
||||||
10
.vscode/extensions.json
vendored
Normal file
10
.vscode/extensions.json
vendored
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
// See http://go.microsoft.com/fwlink/?LinkId=827846
|
||||||
|
// for the documentation about the extensions.json format
|
||||||
|
"recommendations": [
|
||||||
|
"platformio.platformio-ide"
|
||||||
|
],
|
||||||
|
"unwantedRecommendations": [
|
||||||
|
"ms-vscode.cpptools-extension-pack"
|
||||||
|
]
|
||||||
|
}
|
||||||
39
include/README
Normal file
39
include/README
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
|
||||||
|
This directory is intended for project header files.
|
||||||
|
|
||||||
|
A header file is a file containing C declarations and macro definitions
|
||||||
|
to be shared between several project source files. You request the use of a
|
||||||
|
header file in your project source file (C, C++, etc) located in `src` folder
|
||||||
|
by including it, with the C preprocessing directive `#include'.
|
||||||
|
|
||||||
|
```src/main.c
|
||||||
|
|
||||||
|
#include "header.h"
|
||||||
|
|
||||||
|
int main (void)
|
||||||
|
{
|
||||||
|
...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Including a header file produces the same results as copying the header file
|
||||||
|
into each source file that needs it. Such copying would be time-consuming
|
||||||
|
and error-prone. With a header file, the related declarations appear
|
||||||
|
in only one place. If they need to be changed, they can be changed in one
|
||||||
|
place, and programs that include the header file will automatically use the
|
||||||
|
new version when next recompiled. The header file eliminates the labor of
|
||||||
|
finding and changing all the copies as well as the risk that a failure to
|
||||||
|
find one copy will result in inconsistencies within a program.
|
||||||
|
|
||||||
|
In C, the usual convention is to give header files names that end with `.h'.
|
||||||
|
It is most portable to use only letters, digits, dashes, and underscores in
|
||||||
|
header file names, and at most one dot.
|
||||||
|
|
||||||
|
Read more about using header files in official GCC documentation:
|
||||||
|
|
||||||
|
* Include Syntax
|
||||||
|
* Include Operation
|
||||||
|
* Once-Only Headers
|
||||||
|
* Computed Includes
|
||||||
|
|
||||||
|
https://gcc.gnu.org/onlinedocs/cpp/Header-Files.html
|
||||||
46
lib/README
Normal file
46
lib/README
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
|
||||||
|
This directory is intended for project specific (private) libraries.
|
||||||
|
PlatformIO will compile them to static libraries and link into executable file.
|
||||||
|
|
||||||
|
The source code of each library should be placed in an own separate directory
|
||||||
|
("lib/your_library_name/[here are source files]").
|
||||||
|
|
||||||
|
For example, see a structure of the following two libraries `Foo` and `Bar`:
|
||||||
|
|
||||||
|
|--lib
|
||||||
|
| |
|
||||||
|
| |--Bar
|
||||||
|
| | |--docs
|
||||||
|
| | |--examples
|
||||||
|
| | |--src
|
||||||
|
| | |- Bar.c
|
||||||
|
| | |- Bar.h
|
||||||
|
| | |- library.json (optional, custom build options, etc) https://docs.platformio.org/page/librarymanager/config.html
|
||||||
|
| |
|
||||||
|
| |--Foo
|
||||||
|
| | |- Foo.c
|
||||||
|
| | |- Foo.h
|
||||||
|
| |
|
||||||
|
| |- README --> THIS FILE
|
||||||
|
|
|
||||||
|
|- platformio.ini
|
||||||
|
|--src
|
||||||
|
|- main.c
|
||||||
|
|
||||||
|
and a contents of `src/main.c`:
|
||||||
|
```
|
||||||
|
#include <Foo.h>
|
||||||
|
#include <Bar.h>
|
||||||
|
|
||||||
|
int main (void)
|
||||||
|
{
|
||||||
|
...
|
||||||
|
}
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
PlatformIO Library Dependency Finder will find automatically dependent
|
||||||
|
libraries scanning project source files.
|
||||||
|
|
||||||
|
More information about PlatformIO Library Dependency Finder
|
||||||
|
- https://docs.platformio.org/page/librarymanager/ldf.html
|
||||||
17
platformio.ini
Normal file
17
platformio.ini
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
; PlatformIO Project Configuration File
|
||||||
|
;
|
||||||
|
; Build options: build flags, source filter
|
||||||
|
; Upload options: custom upload port, speed and extra flags
|
||||||
|
; Library options: dependencies, extra library storages
|
||||||
|
; Advanced options: extra scripting
|
||||||
|
;
|
||||||
|
; Please visit documentation for the other options and examples
|
||||||
|
; https://docs.platformio.org/page/projectconf.html
|
||||||
|
|
||||||
|
[env:esp32s3box]
|
||||||
|
platform = http://111.198.24.44:11080/v6.5.0.zip
|
||||||
|
board = esp32-s3-devkitc-1
|
||||||
|
framework = arduino
|
||||||
|
lib_deps =
|
||||||
|
robtillaart/DS18B20@^0.2.4
|
||||||
|
esphome/ESPAsyncWebServer-esphome@^3.3.0
|
||||||
317
src/BH1750.cpp
Normal file
317
src/BH1750.cpp
Normal file
@ -0,0 +1,317 @@
|
|||||||
|
/*
|
||||||
|
|
||||||
|
This is a library for the BH1750FVI Digital Light Sensor breakout board.
|
||||||
|
|
||||||
|
The BH1750 board uses I2C for communication. Two pins are required to
|
||||||
|
interface to the device. Configuring the I2C bus is expected to be done
|
||||||
|
in user code. The BH1750 library doesn't do this automatically.
|
||||||
|
|
||||||
|
Written by Christopher Laws, March, 2013.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "BH1750.h"
|
||||||
|
|
||||||
|
// Define milliseconds delay for ESP8266 platform
|
||||||
|
#if defined(ESP8266)
|
||||||
|
|
||||||
|
# include <pgmspace.h>
|
||||||
|
# define _delay_ms(ms) delayMicroseconds((ms)*1000)
|
||||||
|
|
||||||
|
// Use _delay_ms from utils for AVR-based platforms
|
||||||
|
#elif defined(__avr__)
|
||||||
|
# include <util/delay.h>
|
||||||
|
|
||||||
|
// Use Wiring's delay for compability with another platforms
|
||||||
|
#else
|
||||||
|
# define _delay_ms(ms) delay(ms)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Legacy Wire.write() function fix
|
||||||
|
#if (ARDUINO >= 100)
|
||||||
|
# define __wire_write(d) I2C->write(d)
|
||||||
|
#else
|
||||||
|
# define __wire_write(d) I2C->send(d)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Legacy Wire.read() function fix
|
||||||
|
#if (ARDUINO >= 100)
|
||||||
|
# define __wire_read() I2C->read()
|
||||||
|
#else
|
||||||
|
# define __wire_read() I2C->receive()
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor
|
||||||
|
* @params addr Sensor address (0x76 or 0x72, see datasheet)
|
||||||
|
*
|
||||||
|
* On most sensor boards, it was 0x76
|
||||||
|
*/
|
||||||
|
BH1750::BH1750(byte addr) {
|
||||||
|
|
||||||
|
BH1750_I2CADDR = addr;
|
||||||
|
// Allows user to change TwoWire instance
|
||||||
|
I2C = &Wire;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configure sensor
|
||||||
|
* @param mode Measurement mode
|
||||||
|
* @param addr Address of the sensor
|
||||||
|
* @param i2c TwoWire instance connected to I2C bus
|
||||||
|
*/
|
||||||
|
bool BH1750::begin(Mode mode, byte addr, TwoWire* i2c) {
|
||||||
|
|
||||||
|
// I2C is expected to be initialized outside this library
|
||||||
|
// But, allows a different address and TwoWire instance to be used
|
||||||
|
if (i2c) {
|
||||||
|
I2C = i2c;
|
||||||
|
}
|
||||||
|
if (addr) {
|
||||||
|
BH1750_I2CADDR = addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Configure sensor in specified mode and set default MTreg
|
||||||
|
return (configure(mode) && setMTreg(BH1750_DEFAULT_MTREG));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configure BH1750 with specified mode
|
||||||
|
* @param mode Measurement mode
|
||||||
|
*/
|
||||||
|
bool BH1750::configure(Mode mode) {
|
||||||
|
|
||||||
|
// default transmission result to a value out of normal range
|
||||||
|
byte ack = 5;
|
||||||
|
|
||||||
|
// Check measurement mode is valid
|
||||||
|
switch (mode) {
|
||||||
|
|
||||||
|
case BH1750::CONTINUOUS_HIGH_RES_MODE:
|
||||||
|
case BH1750::CONTINUOUS_HIGH_RES_MODE_2:
|
||||||
|
case BH1750::CONTINUOUS_LOW_RES_MODE:
|
||||||
|
case BH1750::ONE_TIME_HIGH_RES_MODE:
|
||||||
|
case BH1750::ONE_TIME_HIGH_RES_MODE_2:
|
||||||
|
case BH1750::ONE_TIME_LOW_RES_MODE:
|
||||||
|
|
||||||
|
// Send mode to sensor
|
||||||
|
I2C->beginTransmission(BH1750_I2CADDR);
|
||||||
|
__wire_write((uint8_t)mode);
|
||||||
|
ack = I2C->endTransmission();
|
||||||
|
|
||||||
|
// Wait a few moments to wake up
|
||||||
|
_delay_ms(10);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
// Invalid measurement mode
|
||||||
|
Serial.println(F("[BH1750] ERROR: Invalid mode"));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check result code
|
||||||
|
switch (ack) {
|
||||||
|
case 0:
|
||||||
|
BH1750_MODE = mode;
|
||||||
|
lastReadTimestamp = millis();
|
||||||
|
return true;
|
||||||
|
case 1: // too long for transmit buffer
|
||||||
|
Serial.println(F("[BH1750] ERROR: too long for transmit buffer"));
|
||||||
|
break;
|
||||||
|
case 2: // received NACK on transmit of address
|
||||||
|
Serial.println(F("[BH1750] ERROR: received NACK on transmit of address"));
|
||||||
|
break;
|
||||||
|
case 3: // received NACK on transmit of data
|
||||||
|
Serial.println(F("[BH1750] ERROR: received NACK on transmit of data"));
|
||||||
|
break;
|
||||||
|
case 4: // other error
|
||||||
|
Serial.println(F("[BH1750] ERROR: other error"));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
Serial.println(F("[BH1750] ERROR: undefined error"));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configure BH1750 MTreg value
|
||||||
|
* MT reg = Measurement Time register
|
||||||
|
* @param MTreg a value between 31 and 254. Default: 69
|
||||||
|
* @return bool true if MTReg successful set
|
||||||
|
* false if MTreg not changed or parameter out of range
|
||||||
|
*/
|
||||||
|
bool BH1750::setMTreg(byte MTreg) {
|
||||||
|
if (MTreg < BH1750_MTREG_MIN || MTreg > BH1750_MTREG_MAX) {
|
||||||
|
Serial.println(F("[BH1750] ERROR: MTreg out of range"));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
byte ack = 5;
|
||||||
|
// Send MTreg and the current mode to the sensor
|
||||||
|
// High bit: 01000_MT[7,6,5]
|
||||||
|
// Low bit: 011_MT[4,3,2,1,0]
|
||||||
|
I2C->beginTransmission(BH1750_I2CADDR);
|
||||||
|
__wire_write((0b01000 << 3) | (MTreg >> 5));
|
||||||
|
ack = I2C->endTransmission();
|
||||||
|
I2C->beginTransmission(BH1750_I2CADDR);
|
||||||
|
__wire_write((0b011 << 5) | (MTreg & 0b11111));
|
||||||
|
ack = ack | I2C->endTransmission();
|
||||||
|
I2C->beginTransmission(BH1750_I2CADDR);
|
||||||
|
__wire_write(BH1750_MODE);
|
||||||
|
ack = ack | I2C->endTransmission();
|
||||||
|
|
||||||
|
// Wait a few moments to wake up
|
||||||
|
_delay_ms(10);
|
||||||
|
|
||||||
|
// Check result code
|
||||||
|
switch (ack) {
|
||||||
|
case 0:
|
||||||
|
BH1750_MTreg = MTreg;
|
||||||
|
return true;
|
||||||
|
case 1: // too long for transmit buffer
|
||||||
|
Serial.println(F("[BH1750] ERROR: too long for transmit buffer"));
|
||||||
|
break;
|
||||||
|
case 2: // received NACK on transmit of address
|
||||||
|
Serial.println(F("[BH1750] ERROR: received NACK on transmit of address"));
|
||||||
|
break;
|
||||||
|
case 3: // received NACK on transmit of data
|
||||||
|
Serial.println(F("[BH1750] ERROR: received NACK on transmit of data"));
|
||||||
|
break;
|
||||||
|
case 4: // other error
|
||||||
|
Serial.println(F("[BH1750] ERROR: other error"));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
Serial.println(F("[BH1750] ERROR: undefined error"));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks whether enough time has gone to read a new value
|
||||||
|
* @param maxWait a boolean if to wait for typical or maximum delay
|
||||||
|
* @return a boolean if a new measurement is possible
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
bool BH1750::measurementReady(bool maxWait) {
|
||||||
|
unsigned long delaytime = 0;
|
||||||
|
switch (BH1750_MODE) {
|
||||||
|
case BH1750::CONTINUOUS_HIGH_RES_MODE:
|
||||||
|
case BH1750::CONTINUOUS_HIGH_RES_MODE_2:
|
||||||
|
case BH1750::ONE_TIME_HIGH_RES_MODE:
|
||||||
|
case BH1750::ONE_TIME_HIGH_RES_MODE_2:
|
||||||
|
maxWait ? delaytime = (180 * BH1750_MTreg / (byte)BH1750_DEFAULT_MTREG)
|
||||||
|
: delaytime = (120 * BH1750_MTreg / (byte)BH1750_DEFAULT_MTREG);
|
||||||
|
break;
|
||||||
|
case BH1750::CONTINUOUS_LOW_RES_MODE:
|
||||||
|
case BH1750::ONE_TIME_LOW_RES_MODE:
|
||||||
|
// Send mode to sensor
|
||||||
|
maxWait ? delaytime = (24 * BH1750_MTreg / (byte)BH1750_DEFAULT_MTREG)
|
||||||
|
: delaytime = (16 * BH1750_MTreg / (byte)BH1750_DEFAULT_MTREG);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// Wait for new measurement to be possible.
|
||||||
|
// Measurements have a maximum measurement time and a typical measurement
|
||||||
|
// time. The maxWait argument determines which measurement wait time is
|
||||||
|
// used when a one-time mode is being used. The typical (shorter)
|
||||||
|
// measurement time is used by default and if maxWait is set to True then
|
||||||
|
// the maximum measurement time will be used. See data sheet pages 2, 5
|
||||||
|
// and 7 for more details.
|
||||||
|
unsigned long currentTimestamp = millis();
|
||||||
|
if (currentTimestamp - lastReadTimestamp >= delaytime) {
|
||||||
|
return true;
|
||||||
|
} else
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read light level from sensor
|
||||||
|
* The return value range differs if the MTreg value is changed. The global
|
||||||
|
* maximum value is noted in the square brackets.
|
||||||
|
* @return Light level in lux (0.0 ~ 54612,5 [117758,203])
|
||||||
|
* -1 : no valid return value
|
||||||
|
* -2 : sensor not configured
|
||||||
|
*/
|
||||||
|
float BH1750::readLightLevel() {
|
||||||
|
|
||||||
|
if (BH1750_MODE == UNCONFIGURED) {
|
||||||
|
Serial.println(F("[BH1750] Device is not configured!"));
|
||||||
|
return -2.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Measurement result will be stored here
|
||||||
|
float level = -1.0;
|
||||||
|
|
||||||
|
// Read two bytes from the sensor, which are low and high parts of the sensor
|
||||||
|
// value
|
||||||
|
if (2 == I2C->requestFrom((int)BH1750_I2CADDR, (int)2)) {
|
||||||
|
unsigned int tmp = 0;
|
||||||
|
tmp = __wire_read();
|
||||||
|
tmp <<= 8;
|
||||||
|
tmp |= __wire_read();
|
||||||
|
level = tmp;
|
||||||
|
}
|
||||||
|
lastReadTimestamp = millis();
|
||||||
|
|
||||||
|
if (level != -1.0) {
|
||||||
|
// Print raw value if debug enabled
|
||||||
|
#ifdef BH1750_DEBUG
|
||||||
|
Serial.print(F("[BH1750] Raw value: "));
|
||||||
|
Serial.println(level);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (BH1750_MTreg != BH1750_DEFAULT_MTREG) {
|
||||||
|
level *= (float)((byte)BH1750_DEFAULT_MTREG / (float)BH1750_MTreg);
|
||||||
|
// Print MTreg factor if debug enabled
|
||||||
|
#ifdef BH1750_DEBUG
|
||||||
|
Serial.print(F("[BH1750] MTreg factor: "));
|
||||||
|
Serial.println(
|
||||||
|
String((float)((byte)BH1750_DEFAULT_MTREG / (float)BH1750_MTreg)));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
if (BH1750_MODE == BH1750::ONE_TIME_HIGH_RES_MODE_2 ||
|
||||||
|
BH1750_MODE == BH1750::CONTINUOUS_HIGH_RES_MODE_2) {
|
||||||
|
level /= 2;
|
||||||
|
}
|
||||||
|
// Convert raw value to lux
|
||||||
|
level /= BH1750_CONV_FACTOR;
|
||||||
|
|
||||||
|
// Print converted value if debug enabled
|
||||||
|
#ifdef BH1750_DEBUG
|
||||||
|
Serial.print(F("[BH1750] Converted float value: "));
|
||||||
|
Serial.println(level);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
return level;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void bh1750_init(BH1750& sensorA, BH1750& sensorB, int sdaA, int sclA, int sdaB, int sclB) {
|
||||||
|
Wire.begin(sdaA, sclA); // 初始化 Wire 总线
|
||||||
|
Wire1.begin(sdaB, sclB); // 初始化 Wire1 总线
|
||||||
|
sensorA.begin(BH1750::CONTINUOUS_HIGH_RES_MODE, 0x23, &Wire);
|
||||||
|
sensorB.begin(BH1750::CONTINUOUS_HIGH_RES_MODE, 0x23, &Wire1);
|
||||||
|
}
|
||||||
|
|
||||||
|
float getLightLevel(BH1750& sensor, const char* sensorName) {
|
||||||
|
if (sensor.measurementReady()) {
|
||||||
|
float lightLevel = sensor.readLightLevel();
|
||||||
|
if (lightLevel >= 0) {
|
||||||
|
return lightLevel; // 正常返回光照强度
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void printLightLevels(BH1750& sensorA, BH1750& sensorB) {
|
||||||
|
float lightA = getLightLevel(sensorA, "Sensor A");
|
||||||
|
float lightB = getLightLevel(sensorB, "Sensor B");
|
||||||
|
|
||||||
|
// 打印光照强度信息
|
||||||
|
Serial.printf("A: %.0f lux :: B: %.0f lux\n", lightA, lightB);
|
||||||
|
}
|
||||||
89
src/BH1750.h
Normal file
89
src/BH1750.h
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
/*
|
||||||
|
|
||||||
|
This is a library for the BH1750FVI Digital Light Sensor breakout board.
|
||||||
|
|
||||||
|
The BH1750 board uses I2C for communication. Two pins are required to
|
||||||
|
interface to the device. Configuring the I2C bus is expected to be done
|
||||||
|
in user code. The BH1750 library doesn't do this automatically.
|
||||||
|
|
||||||
|
Datasheet:
|
||||||
|
http://www.elechouse.com/elechouse/images/product/Digital%20light%20Sensor/bh1750fvi-e.pdf
|
||||||
|
|
||||||
|
Written by Christopher Laws, March, 2013.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef BH1750_h
|
||||||
|
#define BH1750_h
|
||||||
|
|
||||||
|
#if (ARDUINO >= 100)
|
||||||
|
# include <Arduino.h>
|
||||||
|
#else
|
||||||
|
# include <WProgram.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "Wire.h"
|
||||||
|
|
||||||
|
// Uncomment, to enable debug messages
|
||||||
|
// #define BH1750_DEBUG
|
||||||
|
|
||||||
|
// No active state
|
||||||
|
#define BH1750_POWER_DOWN 0x00
|
||||||
|
|
||||||
|
// Waiting for measurement command
|
||||||
|
#define BH1750_POWER_ON 0x01
|
||||||
|
|
||||||
|
// Reset data register value - not accepted in POWER_DOWN mode
|
||||||
|
#define BH1750_RESET 0x07
|
||||||
|
|
||||||
|
// Default MTreg value
|
||||||
|
#define BH1750_DEFAULT_MTREG 69
|
||||||
|
#define BH1750_MTREG_MIN 31
|
||||||
|
#define BH1750_MTREG_MAX 254
|
||||||
|
|
||||||
|
class BH1750 {
|
||||||
|
|
||||||
|
public:
|
||||||
|
enum Mode {
|
||||||
|
// same as Power Down
|
||||||
|
UNCONFIGURED = 0,
|
||||||
|
// Measurement at 1 lux resolution. Measurement time is approx 120ms.
|
||||||
|
CONTINUOUS_HIGH_RES_MODE = 0x10,
|
||||||
|
// Measurement at 0.5 lux resolution. Measurement time is approx 120ms.
|
||||||
|
CONTINUOUS_HIGH_RES_MODE_2 = 0x11,
|
||||||
|
// Measurement at 4 lux resolution. Measurement time is approx 16ms.
|
||||||
|
CONTINUOUS_LOW_RES_MODE = 0x13,
|
||||||
|
// Measurement at 1 lux resolution. Measurement time is approx 120ms.
|
||||||
|
ONE_TIME_HIGH_RES_MODE = 0x20,
|
||||||
|
// Measurement at 0.5 lux resolution. Measurement time is approx 120ms.
|
||||||
|
ONE_TIME_HIGH_RES_MODE_2 = 0x21,
|
||||||
|
// Measurement at 4 lux resolution. Measurement time is approx 16ms.
|
||||||
|
ONE_TIME_LOW_RES_MODE = 0x23
|
||||||
|
};
|
||||||
|
|
||||||
|
BH1750(byte addr = 0x23);
|
||||||
|
bool begin(Mode mode = CONTINUOUS_HIGH_RES_MODE, byte addr = 0x23,
|
||||||
|
TwoWire* i2c = nullptr);
|
||||||
|
bool configure(Mode mode);
|
||||||
|
bool setMTreg(byte MTreg);
|
||||||
|
bool measurementReady(bool maxWait = false);
|
||||||
|
float readLightLevel();
|
||||||
|
|
||||||
|
|
||||||
|
private:
|
||||||
|
byte BH1750_I2CADDR;
|
||||||
|
byte BH1750_MTreg = (byte)BH1750_DEFAULT_MTREG;
|
||||||
|
// Correction factor used to calculate lux. Typical value is 1.2 but can
|
||||||
|
// range from 0.96 to 1.44. See the data sheet (p.2, Measurement Accuracy)
|
||||||
|
// for more information.
|
||||||
|
const float BH1750_CONV_FACTOR = 1.2;
|
||||||
|
Mode BH1750_MODE = UNCONFIGURED;
|
||||||
|
TwoWire* I2C;
|
||||||
|
unsigned long lastReadTimestamp;
|
||||||
|
};
|
||||||
|
|
||||||
|
void bh1750_init(BH1750& sensorA, BH1750& sensorB, int sdaA, int sclA, int sdaB, int sclB);
|
||||||
|
float getLightLevel(BH1750& sensor, const char* sensorName);
|
||||||
|
void printLightLevels(BH1750& sensorA, BH1750& sensorB);
|
||||||
|
|
||||||
|
#endif
|
||||||
238
src/DS18B20.cpp
Normal file
238
src/DS18B20.cpp
Normal file
@ -0,0 +1,238 @@
|
|||||||
|
//
|
||||||
|
// FILE: DS18B20.cpp
|
||||||
|
// AUTHOR: Rob.Tillaart
|
||||||
|
// VERSION: 0.2.4
|
||||||
|
// DATE: 2017-07-25
|
||||||
|
// PURPOSE: library for DS18B20 temperature sensor with minimal footprint
|
||||||
|
// URL: https://github.com/RobTillaart/DS18B20_RT
|
||||||
|
// https://github.com/RobTillaart/DS18B20_INT
|
||||||
|
|
||||||
|
|
||||||
|
#include "DS18B20.h"
|
||||||
|
|
||||||
|
|
||||||
|
// OneWire commands
|
||||||
|
#define STARTCONVO 0x44
|
||||||
|
#define READSCRATCH 0xBE
|
||||||
|
#define WRITESCRATCH 0x4E
|
||||||
|
|
||||||
|
|
||||||
|
// Scratchpad locations
|
||||||
|
#define TEMP_LSB 0
|
||||||
|
#define TEMP_MSB 1
|
||||||
|
#define HIGH_ALARM_TEMP 2
|
||||||
|
#define LOW_ALARM_TEMP 3
|
||||||
|
#define CONFIGURATION 4
|
||||||
|
#define INTERNAL_BYTE 5
|
||||||
|
#define COUNT_REMAIN 6
|
||||||
|
#define COUNT_PER_C 7
|
||||||
|
#define SCRATCHPAD_CRC 8
|
||||||
|
|
||||||
|
|
||||||
|
// Device resolution
|
||||||
|
#define TEMP_9_BIT 0x1F // 9 bit
|
||||||
|
#define TEMP_10_BIT 0x3F // 10 bit
|
||||||
|
#define TEMP_11_BIT 0x5F // 11 bit
|
||||||
|
#define TEMP_12_BIT 0x7F // 12 bit
|
||||||
|
|
||||||
|
|
||||||
|
DS18B20::DS18B20(OneWire* ow, uint8_t resolution)
|
||||||
|
{
|
||||||
|
_oneWire = ow;
|
||||||
|
_addressFound = false;
|
||||||
|
_resolution = resolution;
|
||||||
|
_config = DS18B20_CLEAR;
|
||||||
|
_offset = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool DS18B20::begin(uint8_t retries)
|
||||||
|
{
|
||||||
|
_config = DS18B20_CLEAR;
|
||||||
|
if (isConnected(retries))
|
||||||
|
{
|
||||||
|
_setResolution();
|
||||||
|
}
|
||||||
|
return _addressFound;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool DS18B20::isConnected(uint8_t retries)
|
||||||
|
{
|
||||||
|
_addressFound = false;
|
||||||
|
for (uint8_t rtr = retries; (rtr > 0) && (_addressFound == false); rtr--)
|
||||||
|
{
|
||||||
|
_oneWire->reset();
|
||||||
|
_oneWire->reset_search();
|
||||||
|
_deviceAddress[0] = 0x00;
|
||||||
|
_oneWire->search(_deviceAddress);
|
||||||
|
_addressFound = (_deviceAddress[0] != 0x00) &&
|
||||||
|
(_oneWire->crc8(_deviceAddress, 7) == _deviceAddress[7]);
|
||||||
|
}
|
||||||
|
return _addressFound;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void DS18B20::requestTemperatures(void)
|
||||||
|
{
|
||||||
|
_oneWire->reset();
|
||||||
|
_oneWire->skip();
|
||||||
|
_oneWire->write(STARTCONVO, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool DS18B20::isConversionComplete(void)
|
||||||
|
{
|
||||||
|
return (_oneWire->read_bit() == 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
float DS18B20::getTempC(bool checkConnect)
|
||||||
|
{
|
||||||
|
ScratchPad scratchPad;
|
||||||
|
if (checkConnect)
|
||||||
|
{
|
||||||
|
if (isConnected(3) == false)
|
||||||
|
{
|
||||||
|
return DEVICE_DISCONNECTED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_config & DS18B20_CRC)
|
||||||
|
{
|
||||||
|
readScratchPad(scratchPad, 9);
|
||||||
|
if (_oneWire->crc8(scratchPad, 8) != scratchPad[SCRATCHPAD_CRC])
|
||||||
|
{
|
||||||
|
return DEVICE_CRC_ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
readScratchPad(scratchPad, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
int16_t rawTemperature = (((int16_t)scratchPad[TEMP_MSB]) << 8) | scratchPad[TEMP_LSB];
|
||||||
|
float temp = 0.0625 * rawTemperature;
|
||||||
|
if (temp < -55)
|
||||||
|
{
|
||||||
|
return DEVICE_DISCONNECTED;
|
||||||
|
}
|
||||||
|
if (_offset != 0)
|
||||||
|
{
|
||||||
|
temp += _offset;
|
||||||
|
}
|
||||||
|
return temp;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void DS18B20::setOffset(float offset)
|
||||||
|
{
|
||||||
|
_offset = offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
float DS18B20::getOffset()
|
||||||
|
{
|
||||||
|
return _offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool DS18B20::getAddress(uint8_t* buf)
|
||||||
|
{
|
||||||
|
if (_addressFound)
|
||||||
|
{
|
||||||
|
for (uint8_t i = 0; i < 8; i++)
|
||||||
|
{
|
||||||
|
buf[i] = _deviceAddress[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return _addressFound;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool DS18B20::setResolution(uint8_t resolution)
|
||||||
|
{
|
||||||
|
if (isConnected())
|
||||||
|
{
|
||||||
|
_resolution = resolution;
|
||||||
|
_setResolution();
|
||||||
|
}
|
||||||
|
return _addressFound;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
uint8_t DS18B20::getResolution()
|
||||||
|
{
|
||||||
|
return _resolution;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void DS18B20::setConfig(uint8_t config)
|
||||||
|
{
|
||||||
|
_config = config;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
uint8_t DS18B20::getConfig()
|
||||||
|
{
|
||||||
|
return _config;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// PRIVATE
|
||||||
|
//
|
||||||
|
void DS18B20::readScratchPad(uint8_t *scratchPad, uint8_t fields)
|
||||||
|
{
|
||||||
|
_oneWire->reset();
|
||||||
|
_oneWire->select(_deviceAddress);
|
||||||
|
_oneWire->write(READSCRATCH);
|
||||||
|
|
||||||
|
for (uint8_t i = 0; i < fields; i++)
|
||||||
|
{
|
||||||
|
scratchPad[i] = _oneWire->read();
|
||||||
|
}
|
||||||
|
_oneWire->reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void DS18B20::_setResolution()
|
||||||
|
{
|
||||||
|
uint8_t res;
|
||||||
|
switch (_resolution)
|
||||||
|
{
|
||||||
|
case 12: res = TEMP_12_BIT; break;
|
||||||
|
case 11: res = TEMP_11_BIT; break;
|
||||||
|
case 10: res = TEMP_10_BIT; break;
|
||||||
|
// lowest as default as we do only integer math.
|
||||||
|
default: res = TEMP_9_BIT; break;
|
||||||
|
}
|
||||||
|
|
||||||
|
_oneWire->reset();
|
||||||
|
_oneWire->select(_deviceAddress);
|
||||||
|
_oneWire->write(WRITESCRATCH);
|
||||||
|
// two dummy values for LOW & HIGH ALARM
|
||||||
|
_oneWire->write(0);
|
||||||
|
_oneWire->write(100);
|
||||||
|
_oneWire->write(res);
|
||||||
|
_oneWire->reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void DS18B20::printTemperature()
|
||||||
|
{
|
||||||
|
requestTemperatures(); // 发送请求以开始温度转换
|
||||||
|
//float temperature = getTempC(); // 获取温度(摄氏度)
|
||||||
|
//Serial.print("Temp: ");
|
||||||
|
Serial.print(getTempC());
|
||||||
|
Serial.print("℃ ");
|
||||||
|
//Serial.printf("t0.txt=\"%.2f\"\xff\xff\xff", temperature);
|
||||||
|
//printf("t1.txt=\"%s\"\xff\xff\xff",buf);
|
||||||
|
//Serial.println("\xff\xff\xff");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// -- END OF FILE --
|
||||||
|
|
||||||
63
src/DS18B20.h
Normal file
63
src/DS18B20.h
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
#include "OneWire.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#define DS18B20_LIB_VERSION (F("0.2.4"))
|
||||||
|
|
||||||
|
// Error Code
|
||||||
|
#define DEVICE_DISCONNECTED -127
|
||||||
|
#define DEVICE_CRC_ERROR -128
|
||||||
|
|
||||||
|
// configuration codes
|
||||||
|
#define DS18B20_CLEAR 0x00
|
||||||
|
#define DS18B20_CRC 0x01
|
||||||
|
|
||||||
|
|
||||||
|
typedef uint8_t DeviceAddress[8];
|
||||||
|
typedef uint8_t ScratchPad[9];
|
||||||
|
|
||||||
|
|
||||||
|
class DS18B20
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void printTemperature();
|
||||||
|
explicit DS18B20(OneWire * ow, uint8_t resolution = 9);
|
||||||
|
bool begin(uint8_t retries = 3);
|
||||||
|
bool isConnected(uint8_t retries = 3);
|
||||||
|
|
||||||
|
void requestTemperatures(void);
|
||||||
|
bool isConversionComplete(void);
|
||||||
|
// backwards compatible
|
||||||
|
float getTempC(bool checkConnect = true);
|
||||||
|
// conversion wrapper Fahrenheit
|
||||||
|
// (keep in .h for footprint)
|
||||||
|
float getTempF() { return 32.0 + getTempC() * 1.8; };
|
||||||
|
|
||||||
|
void setOffset(float offset = 0);
|
||||||
|
float getOffset();
|
||||||
|
|
||||||
|
bool getAddress(uint8_t * buf);
|
||||||
|
|
||||||
|
bool setResolution(uint8_t resolution = 9);
|
||||||
|
uint8_t getResolution(); // returns cached value
|
||||||
|
|
||||||
|
void setConfig(uint8_t config);
|
||||||
|
uint8_t getConfig();
|
||||||
|
|
||||||
|
|
||||||
|
private:
|
||||||
|
void readScratchPad(uint8_t *, uint8_t);
|
||||||
|
void _setResolution();
|
||||||
|
|
||||||
|
DeviceAddress _deviceAddress;
|
||||||
|
OneWire* _oneWire;
|
||||||
|
bool _addressFound;
|
||||||
|
|
||||||
|
uint8_t _resolution;
|
||||||
|
uint8_t _config;
|
||||||
|
float _offset;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// -- END OF FILE --
|
||||||
|
|
||||||
0
src/TJC_Show.cpp
Normal file
0
src/TJC_Show.cpp
Normal file
0
src/TJC_Show.h
Normal file
0
src/TJC_Show.h
Normal file
153
src/main.cpp
Normal file
153
src/main.cpp
Normal file
@ -0,0 +1,153 @@
|
|||||||
|
#include "DS18B20.h"
|
||||||
|
|
||||||
|
#include "BH1750.h"
|
||||||
|
#include "Wire.h"
|
||||||
|
|
||||||
|
#include <WiFi.h>
|
||||||
|
#include <ESPAsyncWebServer.h>
|
||||||
|
//#include "TCJ_Show.h"
|
||||||
|
//#include "ESP32_WebServer.h"
|
||||||
|
|
||||||
|
AsyncWebServer server(80);
|
||||||
|
|
||||||
|
const char* ssid = "SERVIRST-CT";
|
||||||
|
const char* password = "servirst8888";
|
||||||
|
|
||||||
|
|
||||||
|
#define ONE_WIRE_BUS 4
|
||||||
|
OneWire oneWire(ONE_WIRE_BUS);
|
||||||
|
DS18B20 sensor(&oneWire);
|
||||||
|
|
||||||
|
BH1750 bh1750_a;
|
||||||
|
BH1750 bh1750_b;
|
||||||
|
|
||||||
|
#define TJC Serial1
|
||||||
|
#define TJC_TX_Pin 42
|
||||||
|
#define TJC_RX_Pin 41
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// HTML 页面内容
|
||||||
|
const char index_html[] PROGMEM = R"rawliteral(
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>ESP32 Data Display</title>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<script>
|
||||||
|
async function fetchData() {
|
||||||
|
const tempResponse = await fetch('/temperature');
|
||||||
|
const tempText = await tempResponse.text();
|
||||||
|
document.getElementById('temperature').innerText = tempText;
|
||||||
|
|
||||||
|
const lightAResponse = await fetch('/lightA');
|
||||||
|
const lightAText = await lightAResponse.text();
|
||||||
|
document.getElementById('lightA').innerText = lightAText;
|
||||||
|
|
||||||
|
const lightBResponse = await fetch('/lightB');
|
||||||
|
const lightBText = await lightBResponse.text();
|
||||||
|
document.getElementById('lightB').innerText = lightBText;
|
||||||
|
}
|
||||||
|
setInterval(fetchData, 1000);
|
||||||
|
</script>
|
||||||
|
</head>
|
||||||
|
<body onload="fetchData()">
|
||||||
|
<h1>实时数据显示</h1>
|
||||||
|
<p>温度: <span id="temperature">加载中...</span> °C</p>
|
||||||
|
<p>光照强度(A): <span id="lightA">加载中...</span> lx</p>
|
||||||
|
<p>光照强度(B): <span id="lightB">加载中...</span> lx</p>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
)rawliteral";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void WebServer_Init(const char* ssid, const char* password) // 初始化Web
|
||||||
|
{
|
||||||
|
WiFi.begin(ssid, password); // WiFi
|
||||||
|
while (WiFi.status() != WL_CONNECTED)
|
||||||
|
{
|
||||||
|
delay(1000);
|
||||||
|
Serial.println("Connecting to WiFi...");
|
||||||
|
}
|
||||||
|
Serial.println("Connected to WiFi");
|
||||||
|
Serial.println(WiFi.localIP());
|
||||||
|
|
||||||
|
// 根路径的页面
|
||||||
|
server.on("/", HTTP_GET, [](AsyncWebServerRequest *request)
|
||||||
|
{
|
||||||
|
request->send_P(200, "text/html", index_html);
|
||||||
|
});
|
||||||
|
|
||||||
|
// 温度接口
|
||||||
|
server.on("/temperature", HTTP_GET, [](AsyncWebServerRequest *request)
|
||||||
|
{
|
||||||
|
String temp = String(sensor.getTempC());
|
||||||
|
request->send(200, "text/plain", temp);
|
||||||
|
});
|
||||||
|
|
||||||
|
// 光照强度(传感器A)
|
||||||
|
server.on("/lightA", HTTP_GET, [](AsyncWebServerRequest *request)
|
||||||
|
{
|
||||||
|
String lightA = String(bh1750_a.readLightLevel());
|
||||||
|
request->send(200, "text/plain", lightA);
|
||||||
|
});
|
||||||
|
|
||||||
|
// 光照(传感器B)
|
||||||
|
server.on("/lightB", HTTP_GET, [](AsyncWebServerRequest *request)
|
||||||
|
{
|
||||||
|
String lightB = String(bh1750_b.readLightLevel());
|
||||||
|
request->send(200, "text/plain", lightB);
|
||||||
|
});
|
||||||
|
|
||||||
|
server.begin();
|
||||||
|
Serial.println("Web server started");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//陶晶池串口屏发送
|
||||||
|
void TJC_Show(void)
|
||||||
|
{
|
||||||
|
char str[64];
|
||||||
|
sprintf(str, "t0.txt=\"%.2f\"\xff\xff\xff", sensor.getTempC());//用sprintf来格式化字符串,给t0的txt属性赋值
|
||||||
|
TJC.print(str); //把字符串发送出去
|
||||||
|
|
||||||
|
sprintf(str, "t1.txt=\"%.f\"\xff\xff\xff", bh1750_a.readLightLevel());
|
||||||
|
TJC.print(str);
|
||||||
|
sprintf(str, "t2.txt=\"%.f\"\xff\xff\xff", bh1750_b.readLightLevel());
|
||||||
|
TJC.print(str);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setup(void)
|
||||||
|
{
|
||||||
|
Serial.begin(115200);
|
||||||
|
|
||||||
|
TJC.begin(115200, SERIAL_8N1, TJC_RX_Pin, TJC_TX_Pin); //串口屏
|
||||||
|
while (TJC.read() >= 0); //因为串口屏开机会发送88 ff ff ff,所以要清空串口缓冲区
|
||||||
|
TJC.print("page main\xff\xff\xff"); //发送命令让屏幕跳转到main页面
|
||||||
|
|
||||||
|
//sensor.begin();
|
||||||
|
|
||||||
|
bh1750_init(bh1750_a, bh1750_b, 19, 18, 21, 20); //1750初始化。sda, scl
|
||||||
|
|
||||||
|
WebServer_Init(ssid, password);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void loop(void)
|
||||||
|
{// put your main code here, to run repeatedly:
|
||||||
|
sensor.printTemperature(); //ds18b20温度
|
||||||
|
|
||||||
|
//printLightLevels(bh1750_a, bh1750_b); //bh1750照度
|
||||||
|
Serial.printf("A: %.0f lux :: B: %.0f lux \n",
|
||||||
|
bh1750_a.readLightLevel(),
|
||||||
|
bh1750_b.readLightLevel());
|
||||||
|
|
||||||
|
TJC_Show(); //串口屏
|
||||||
|
|
||||||
|
delay(1000);
|
||||||
|
}
|
||||||
11
test/README
Normal file
11
test/README
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
|
||||||
|
This directory is intended for PlatformIO Test Runner and project tests.
|
||||||
|
|
||||||
|
Unit Testing is a software testing method by which individual units of
|
||||||
|
source code, sets of one or more MCU program modules together with associated
|
||||||
|
control data, usage procedures, and operating procedures, are tested to
|
||||||
|
determine whether they are fit for use. Unit testing finds problems early
|
||||||
|
in the development cycle.
|
||||||
|
|
||||||
|
More information about PlatformIO Unit Testing:
|
||||||
|
- https://docs.platformio.org/en/latest/advanced/unit-testing/index.html
|
||||||
Reference in New Issue
Block a user