Skip to content

Commit

Permalink
Initial
Browse files Browse the repository at this point in the history
  • Loading branch information
zvonler committed Nov 16, 2023
0 parents commit e1b292e
Show file tree
Hide file tree
Showing 10 changed files with 1,113 additions and 0 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
tests/build/
674 changes: 674 additions & 0 deletions LICENSE

Large diffs are not rendered by default.

37 changes: 37 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@

# DebouncedLDR

This library implements a class that applies quantization and hysteresis to the
analog readings of a Light Dependent Resistor (LDR) so that applications can
work with logical light levels instead of physical light readings. Using this
library, applications can easily avoid the flickering effects that can happen
with simple thresholding.

## Theory of operation

The `DebouncedLDR` class does not do any of the actual GPIO manipulation. The
client application is expected to call `DebouncedLDR::update` frequently
(i.e. every few milliseconds) with the latest reading from the analog pin. The
`update` method returns the current logical light level.

The light level value returned by `update` represents a logical light level
between zero and the maximum level passed to the instance's constructor. The
`noise` parameter to the constructor is used to define "meaningful" changes in
the LDR reading, a higher `noise` value requires a larger change in the readings
to cause a change in the reported light level, and a `noise` value of zero will
do no debouncing of the readings.

## Testing

This library includes unit tests that can be run on a host system (not on the
Arduino) using CMake. From the top-level of the library repo, these commands
should run the tests:

```
cd tests
cmake -S . -B build
cmake --build build && (cd build; ctest --output-on-failure)
```

The first `cmake` command above only needs to be run once, the second command
can be run each time the source is changed to check the test status.
40 changes: 40 additions & 0 deletions examples/SerialLDRTester/SerialLDRTester.ino
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/*
SerialLDRTester
Reads an LDR attached to an analog input pin and prints the current light
level to the serial port.
This example code is in the public domain.
*/


#include <DebouncedLDR.h>

constexpr static int LDR_PIN = A0;

// An LDR with readings between [0, 1023] that will return ten light levels
// and will consider readings within 100 of each other to be the same level.
DebouncedLDR ldr(1023, 9, 100);

void setup()
{
Serial.begin(115200);

pinMode(LDR_PIN, INPUT);
}

void loop()
{
static DebouncedLDR::Level prev_level = 0;

auto level = ldr.update(analogRead(LDR_PIN));

if (level != prev_level) {
Serial.print("Light level now ");
Serial.println(level);
prev_level = level;
}

delay(50);
}

1 change: 1 addition & 0 deletions keywords.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
DebouncedLDR KEYWORD1
9 changes: 9 additions & 0 deletions library.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
name=DebouncedLDR
version=1.0.0
author=Zach Vonler
maintainer=Zach Vonler <zvonler@gmail.com>
sentence=Library for debouncing a light-dependent resistor.
paragraph=Applies hysteresis to analog readings to prevent flicker.
category=Sensors
url=https://github.com/zvonler/DebouncedLDR
architectures=*
53 changes: 53 additions & 0 deletions src/DebouncedLDR.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/*
Copyright 2023 Zach Vonler <zvonler@gmail.com>
This file is part of DebouncedLDR.
DebouncedLDR is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the Free
Software Foundation, either version 3 of the License, or (at your option)
any later version.
DebouncedLDR 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 General Public License for
more details.
You should have received a copy of the GNU General Public License along with
DebouncedLDR. If not, see <https://www.gnu.org/licenses/>.
*/

#include "DebouncedLDR.h"

/*---------------------------------------------------------------------------*/

DebouncedLDR::DebouncedLDR(Reading max_reading, Level max_level, Reading noise)
: _max_reading(max_reading)
, _max_level(max_level)
, _noise(noise)
, _level_width(_max_reading / (_max_level + 1.0f))
{
}

DebouncedLDR::Level
DebouncedLDR::update(Reading reading)
{
Level new_level;
if (reading >= _max_reading) {
new_level = _max_level;
} else {
new_level = floor(reading / _level_width);
}

if (new_level != _level) {
Reading diff = max(reading, _last_reading_on_change) - min(reading, _last_reading_on_change);
if (diff > _noise) {
_level = new_level;
_last_reading_on_change = reading;
}
}

return _level;
}

/*---------------------------------------------------------------------------*/
73 changes: 73 additions & 0 deletions src/DebouncedLDR.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
/*
Copyright 2023 Zach Vonler <zvonler@gmail.com>
This file is part of DebouncedLDR.
DebouncedLDR is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the Free
Software Foundation, either version 3 of the License, or (at your option)
any later version.
DebouncedLDR 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 General Public License for
more details.
You should have received a copy of the GNU General Public License along with
DebouncedLDR. If not, see <https://www.gnu.org/licenses/>.
*/

#ifndef debounced_ldr_h
#define debounced_ldr_h

#ifdef UNIT_TESTING
#include <algorithm>
#include <cmath>
#include <cstdint>
#define floor std::floor
#define min std::min
#define max std::max
#else
#include <Arduino.h>
#endif

/*---------------------------------------------------------------------------*/

/**
* Represents an LDR with latching light levels to prevent flicker.
*/
class DebouncedLDR {
public:
using Reading = uint16_t;
using Level = uint16_t;

/**
* Creates an instance that will map readings in the range [0, max_reading]
* to light level values in the range [0, max_level], and will require the
* reading to change by more than noise to cause a light level change.
*/
DebouncedLDR(Reading max_reading, Level max_level, Reading noise);

/**
* Adds the reading and returns the current level.
*/
Level update(Reading reading);

Level light_level() const { return _level; }

Reading max_reading() const { return _max_reading; }
Level max_level() const { return _max_level; }
Reading noise() const { return _noise; }

private:
Reading _max_reading;
Level _max_level;
Reading _noise;
float _level_width;
Level _level = 0;
Reading _last_reading_on_change = 0;
};

/*---------------------------------------------------------------------------*/

#endif
32 changes: 32 additions & 0 deletions tests/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
cmake_minimum_required(VERSION 3.14)
project(my_project)

# GoogleTest requires at least C++14
set(CMAKE_CXX_STANDARD 14)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

include(FetchContent)
FetchContent_Declare(
googletest
URL https://github.com/google/googletest/archive/03597a01ee50ed33e9dfd640b249b4be3799d395.zip
)
# For Windows: Prevent overriding the parent project's compiler/linker settings
set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
FetchContent_MakeAvailable(googletest)

enable_testing()

add_compile_definitions(UNIT_TESTING)

add_executable(
test_debounced_ldr
test_debounced_ldr.cpp
../src/DebouncedLDR.cpp
)
target_link_libraries(
test_debounced_ldr
GTest::gtest_main
)

include(GoogleTest)
gtest_discover_tests(test_debounced_ldr)
Loading

0 comments on commit e1b292e

Please sign in to comment.