0.1.2 RAIN

This commit is contained in:
rob tillaart 2022-12-06 16:57:55 +01:00
parent f336566e4c
commit 0423bd1512
13 changed files with 332 additions and 56 deletions

View File

@ -6,6 +6,18 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/)
and this project adheres to [Semantic Versioning](http://semver.org/).
## [0.1.2] - 2022-12-06
- add powerPin to constructor. Optional.
- add powerPin example
- add interrupt example (using DO = digital Out)
- add digital out polling example
- update readme.md (lower voltage == wetter)
- fix version number
- fix percentage() => 0% == DRY and 100% == WET
- add get- and setDryReference() for better percentage() behaviour.
- update keywords.txt
## [0.1.1] - 2022-12-03
- change levels to milliVolts (uint16_t).
- rewrite setLevel(milliVolts) and getLevel().
@ -14,7 +26,6 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
- update keywords.txt
- add delta() => delta with previous read().
## [0.1.0] - 2022-12-03
- initial version

View File

@ -13,45 +13,85 @@ RAIN is an Arduino library for a rain sensor (analog).
## Description
A rain sensor is a relative simple device.
A rain sensor (FC-37, YL-83, HM-RD) is a relative simple device.
It measures the resistance of a number of wires when these are put in a liquid (water)
The device converts the resistance to a voltage typical 0 .. 5 Volt.
The more the wires are covered by the liquid, the higher the voltage.
The more the wires are covered by the liquid, the lower the voltage.
0.0 Volt is WET, and a high voltage is DRY.
The breakout I used to test also has a digital output, which goes HIGH if a certain
threshold (to be set with a potentiometer on the breakout) is reached.
The meaning / potential of this digital-out for the library needs to be investigated.
The breakout (LM393 comparator) I used to test also has a digital output,
which goes LOW if a threshold (to be set with a potentiometer on the breakout) is reached.
The library is EXPERIMENTAL as it needs more testing.
(changes of the interface are definitely possible).
## Hardware connection
Typical connection
```
Processor LM393 SENSOR FC-37
+-------------+ +----------+ +---------------------+
| | | | | |
| GND |----->| GND | | |
| powerPin |----->| 5V |-----| |
| analogIn |<-----| AO | | |
| | | |-----| |
| digital in |<-----| DO | | |
| | | | | |
+-------------+ +----------+ +---------------------+
```
## Interface
- **RAIN(uint8_t port)** constructor.
- **RAIN(uint8_t port, uint8_t powerPin = 255)** constructor.
port is the internal analog port to use.
powerPin is optional, but recommended.
- **bool begin(float maxVoltage, uint16_t maxSteps)** sets the ADC parameters.
Allows to be changed runtime, e.g. if voltage fluctuates the math can be adapted by calling **begin()** again.
Might be a separate **setVoltage()** is more efficient.
- **float raw(uint8_t times = 1)** makes 1 or more measurements and averages them.
returned value is the average number of ADC steps.
- **float read(uint8_t times = 1)** makes 1 or more measurements, averages them and convert the average to a voltage.
THis voltage is returned, and also cached for **percentage()** and **getLevel()**.
This voltage is returned, and also cached for **percentage()** and **getLevel()**.
#### powerControl
Will only work if the **powerPin** is set in the constructor.
- **void powerOn()** switch the sensor on.
- **void powerOff()** switch the sensor off.
The powerPin is used to switch the LM393 ON and OFF so the sensor is powered
only when the sensor is read. That reduces corrosion and energy usage.
Note: when the power is OFF, the digital-out cannot be used e.g. for interrupts.
So check what your project needs.
Note: the powerOn() delays for 100us to give the LM393 time to stabilize.
Adjust this if needed.
#### Analysis
- **void setDryReference(float dryRef)** used to calibrate the voltage when the sensor is dry.
Use **read()** to read / calibrate the voltage when the sensor is dry.
If not explicitly set, the max ADC voltage os used.
- **void getDryReference()** returns the set value.
- **float percentage()** returns the last **read()** to a percentage.
Note one needs to call read() again to get a new value as this uses a cached value.
- **float delta()** returns the delta voltage compared to previous read.
It give the first derivative of the signal. How fast does it rise.
- **bool setLevel(uint8_t nr, uint16_t millivolts)** allows a user to set 5 voltage levels in milliVolts.
- **bool setLevel(uint8_t nr, uint16_t millivolts)** allows a user to set 4 voltage levels in milliVolts.
- **uint8_t getLevel()**
Returns the level of the current cached voltage.
See example.
The library allows the user to set 5 thresholds or levels for the **getLevel()** function.
These 5 levels can help to control behaviour at a certain level.
Typical levels are almost empty, to almost full and full.
The library allows the user to set 4 thresholds or levels for the **getLevel()** function.
These 4 levels + 1 zero level can help to control behaviour of a system at a certain level.
Typical levels are almost empty, almost full and full.
The level do not need to be on a linear mapping like 20% steps, if your project need
other levels you can define these.
@ -68,7 +108,18 @@ See https://github.com/RobTillaart/MultiMap
## Operation
The examples show the basic working of the functions.
The examples show the basic working of the functions of the library.
The rain sensor can be used in different types of projects.
Every project has a typical orientation of the sensor.
| project | orientation | measurement |
|:-----------------|:----------------:|:-------------:|
| rain sensor | angle e.g. 45° | polling
| leak detection | horizontal | interrupt - digital OUT
| water level | vertical | polling
For other applications it depends.
## Future
@ -76,19 +127,11 @@ The examples show the basic working of the functions.
#### Must
- update documentation
- links etc.
- add interrupt example for digital output capture.
#### Should
- optimizations
- a lot of floats...==> more uint16_t millivolts?
- add examples.
- investigate possibilities of the digital output
- how to include
- example (see above)
- improve the **percentage()** maxVoltage setter?
- 2 different meanings of maxVoltage. For ADC and sensor out.
- is the device linear? does percentage make sense if it is not?
- a lot of floats...==> more uint16_t millivolts? (0.2.0)
#### Could
@ -104,10 +147,11 @@ The examples show the basic working of the functions.
- different salinity
- different liquids? which?
- how linear is the device?
#### Won't (unless requested)
- example with multiMap
- see multiMap library.
- **incrLevel(nr, amount = 1)** + **decrLevel(nr, amount = 1)**
to allow easier runtime tuning
#### Won't
- example with multiMap
- see multiMap library.

View File

@ -3,6 +3,8 @@
// AUTHOR: Rob Tillaart
// PURPOSE: demo read + delta
// URL: https://github.com/RobTillaart/RAIN
//
// e.g. use with Arduino IDE plotter tool.
#include "rain.h"

View File

@ -19,6 +19,9 @@ void setup()
Serial.println("EXPERIMENTAL:");
RS.begin(5.000, 1023);
// measured in an earlier run, adjust to your calibration.
RS.setDryReference(3.5);
}
@ -33,3 +36,4 @@ void loop()
// -- END OF FILE --

View File

@ -0,0 +1,38 @@
//
// FILE: rain_demo_powerpin.ino
// AUTHOR: Rob Tillaart
// PURPOSE: demo read power pin
// URL: https://github.com/RobTillaart/RAIN
#include "rain.h"
#define ANALOGPIN A0
#define POWERPIN 7
RAIN RS(ANALOGPIN, POWERPIN);
void setup()
{
Serial.begin(115200);
while (!Serial);
Serial.println(__FILE__);
Serial.print("RAIN_LIB_VERSION: ");
Serial.println(RAIN_LIB_VERSION);
Serial.println("EXPERIMENTAL:");
RS.begin(5.000, 1023);
}
void loop()
{
Serial.print(RS.read(), 3);
Serial.print('\t');
Serial.print(RS.percentage(), 1);
Serial.print('\n');
delay(100);
}
// -- END OF FILE --

View File

@ -0,0 +1,48 @@
//
// FILE: rain_digital_out.ino
// AUTHOR: Rob Tillaart
// PURPOSE: demo digital out DO pin
// URL: https://github.com/RobTillaart/RAIN
#include "rain.h"
#define ANALOGPIN A0
#define POWERPIN 7
#define DIGIOUT 8
RAIN RS(ANALOGPIN, POWERPIN);
void setup()
{
Serial.begin(115200);
while (!Serial);
Serial.println(__FILE__);
Serial.print("RAIN_LIB_VERSION: ");
Serial.println(RAIN_LIB_VERSION);
Serial.println("EXPERIMENTAL:");
RS.begin(5.000, 1023);
pinMode(DIGIOUT, INPUT_PULLUP);
}
void loop()
{
if (digitalRead(DIGIOUT) == LOW)
{
Serial.print(millis());
Serial.print('\t');
Serial.print(RS.read(), 3);
Serial.print('\t');
Serial.print(RS.getLevel());
Serial.print('\n');
}
delay(100);
// other code here
}
// -- END OF FILE --

View File

@ -0,0 +1,57 @@
//
// FILE: rain_interrupt.ino
// AUTHOR: Rob Tillaart
// PURPOSE: demo rain_interrupt digital out
// URL: https://github.com/RobTillaart/RAIN
#include "rain.h"
#define ANALOGPIN A0
#define POWERPIN 7
#define DIGIOUT_IRQ 2
RAIN RS(ANALOGPIN, POWERPIN);
volatile bool waterDetected = false;
void setup()
{
Serial.begin(115200);
while (!Serial);
Serial.println(__FILE__);
Serial.print("RAIN_LIB_VERSION: ");
Serial.println(RAIN_LIB_VERSION);
Serial.println("EXPERIMENTAL:");
RS.begin(5.000, 1023);
attachInterrupt(digitalPinToInterrupt(DIGIOUT_IRQ), isr, FALLING);
}
void loop()
{
if (waterDetected)
{
Serial.print(millis());
Serial.print('\t');
Serial.print(RS.read(), 3);
Serial.print('\t');
Serial.print(RS.getLevel());
Serial.print('\n');
waterDetected = false;
}
delay(100);
// other code here
}
void isr()
{
waterDetected = true;
}
// -- END OF FILE --

View File

@ -46,14 +46,14 @@ void loop()
int level = RS.getLevel();
switch (level)
{
case 4:
case 0: // max WET
if (prevLevel != level)
{
Serial.println("Pump speed 100%");
}
analogWrite(PUMP_PIN, 255);
break;
case 3:
case 1:
if (prevLevel != level)
{
Serial.println("Pump speed 90%");
@ -65,20 +65,20 @@ void loop()
{
Serial.println("Pump speed 75%");
}
analogWrite(PUMP_PIN, 195); // ~75%
analogWrite(PUMP_PIN, 195);
break;
case 1:
case 3:
if (prevLevel != level)
{
Serial.println("Start pumping");
Serial.println("Pump speed 50%");
}
analogWrite(PUMP_PIN, 130); // ~50%
analogWrite(PUMP_PIN, 130);
break;
case 0:
case 4: // DRY
default:
if (prevLevel != level)
{
Serial.println("Stop pumping");
Serial.println("Stopped pumping");
}
analogWrite(PUMP_PIN, 0);
break;

View File

@ -8,10 +8,18 @@ begin KEYWORD2
raw KEYWORD2
read KEYWORD2
setDryReference KEYWORD2
getDryReference KEYWORD2
percentage KEYWORD2
delta KEYWORD2
setLevel KEYWORD2
getLevel KEYWORD2
powerOn KEYWORD2
powerOff KEYWORD2
# Constants (LITERAL1)
RAIN_LIB_VERSION LITERAL1

View File

@ -1,7 +1,7 @@
{
"name": "RAIN",
"keywords": "RAIN, wet",
"description": "Arduino library for rain sensor. (analog)",
"keywords": "RAIN, wet, FC-37, YL-83, HM-RD, LM393",
"description": "Arduino library for FC-37 analog rain sensor and compatibles.",
"authors":
[
{
@ -15,7 +15,7 @@
"type": "git",
"url": "https://github.com/RobTillaart/RAIN.git"
},
"version": "0.1.1",
"version": "0.1.2",
"license": "MIT",
"frameworks": "arduino",
"platforms": "*",

View File

@ -1,10 +1,10 @@
name=RAIN
version=0.1.1
version=0.1.2
author=Rob Tillaart <rob.tillaart@gmail.com>
maintainer=Rob Tillaart <rob.tillaart@gmail.com>
sentence=Arduino library for rain sensor (analog).
paragraph=wet, wetness.
category=Signal Input/Output
sentence=Arduino library for FC-37 analog rain sensor and compatibles.
paragraph=wet, wetness, FC-37, YL-83, HM-RD, LM393.
category=Sensors
url=https://github.com/RobTillaart/RAIN
architectures=*
includes=rain.h

View File

@ -1,7 +1,7 @@
//
// FILE: rain.cpp
// AUTHOR: Rob Tillaart
// VERSION: 0.1.1
// VERSION: 0.1.2
// DATE: 2021-12-03
// PURPOSE: Arduino library for a rain sensor
// URL: https://github.com/RobTillaart/RAIN
@ -10,11 +10,13 @@
#include "rain.h"
RAIN::RAIN(uint8_t port)
RAIN::RAIN(uint8_t port, uint8_t powerPin)
{
_port = port;
_powerPin = powerPin;
_maxVoltage = 5;
_maxSteps = 1023;
_dryRefVoltage = _maxVoltage;
}
@ -23,6 +25,13 @@ bool RAIN::begin(float maxVoltage, uint16_t maxSteps)
_maxVoltage = maxVoltage;
_maxSteps = maxSteps;
_mVstep = _maxVoltage / _maxSteps;
_dryRefVoltage = _maxVoltage;
if (_powerPin != 255)
{
pinMode(_powerPin, OUTPUT);
powerOn();
}
read();
return true;
}
@ -32,10 +41,14 @@ float RAIN::raw(uint8_t times)
{
if (times == 0) times = 1;
float sum = 0;
powerOn();
for (int i = 0; i < times; i++)
{
sum += analogRead(_port);
}
powerOff();
if (times > 1) sum /= times;
return sum;
}
@ -49,9 +62,23 @@ float RAIN::read(uint8_t times)
}
void RAIN::setDryReference(float dryRef)
{
_dryRefVoltage = dryRef;
}
float RAIN::getDryReference()
{
return _dryRefVoltage;
}
float RAIN::percentage()
{
return _voltage * 100.0 / _maxVoltage;
float p = 100.0 - (_voltage * 100.0 / _dryRefVoltage);
if (p < 0) p = 0;
return p;
}
@ -81,5 +108,24 @@ uint8_t RAIN::getLevel()
}
void RAIN::powerOn()
{
if (_powerPin != 255)
{
digitalWrite(_powerPin, HIGH);
delayMicroseconds(100); // time to stabilize, adjust if needed.
}
}
void RAIN::powerOff()
{
if (_powerPin != 255)
{
digitalWrite(_powerPin, LOW);
}
}
// -- END OF FILE --

View File

@ -2,7 +2,7 @@
//
// FILE: rain.h
// AUTHOR: Rob Tillaart
// VERSION: 0.1.0
// VERSION: 0.1.2
// DATE: 2022-11-23
// PURPOSE: Arduino library for rain sensor (analog).
// URL: https://github.com/RobTillaart/RAIN
@ -12,13 +12,15 @@
#include "Arduino.h"
#define RAIN_LIB_VERSION (F("0.1.0"))
#define RAIN_LIB_VERSION (F("0.1.2"))
class RAIN
{
public:
RAIN(uint8_t port);
// port = analogPort,
// powerPin is optional, 255 == not used => see readme.md
RAIN(uint8_t port, uint8_t powerPin = 255);
// set the ADC parameters
// can be changed runtime, e.g if voltage fluctuates.
@ -27,29 +29,45 @@ public:
// returns steps
float raw(uint8_t times = 1);
// returns voltage
// the lower the voltage the wetter.
float read(uint8_t times = 1);
// ANALYSIS
// returns last read value as percentage of maxVoltage.
// indicating wetness?
// it assumes / implies linear behaviour
// read the sensor when it is dry to get a reference (calibration).
// will be used by percentage(), can be used to setLevel().
void setDryReference(float dryRef);
float getDryReference();
// returns last read value as percentage of DryReference (if set).
// indicating wetness 0 == DRY 100 == WET
// percentage assumes / implies "linear" behaviour
float percentage();
// delta with respect to previous read().
float delta();
// level = 1..4 (level 0 == 0 Volt)
// level = 1..4
// level 0 == 0 Volt ==> WET)
// level 4 ==> DRY
// user is responsible that values are increasing voltages.
bool setLevel(uint8_t nr, uint16_t milliVolts);
uint8_t getLevel();
// will only work when set in constructor.
void powerOn();
void powerOff();
private:
uint8_t _port;
uint8_t _powerPin = 255; // 255 means not set.
float _maxVoltage;
uint16_t _maxSteps;
float _mVstep;
float _voltage;
float _dryRefVoltage;
float _previous;
uint16_t _level[5] = { 0, 1000, 2000, 3000, 4000 }; // millivolts
};