Skip to content

Commit 6a44371

Browse files
committed
Improved HCSR04 getUSDistanceAsCentimeterWithCentimeterTimeoutPeriodicallyAndPrintIfChanged()
1 parent a6c8cb0 commit 6a44371

File tree

8 files changed

+238
-22
lines changed

8 files changed

+238
-22
lines changed

.github/workflows/LibraryBuild.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ jobs:
5151
sketches-exclude: 50Hz # Comma separated list of example names to exclude in build
5252

5353
# - arduino-boards-fqbn: ATTinyCore:avr:attinyx5:chip=85,clock=1internal
54-
# platform-url: http://drazzy.com/package_drazzy.com_index.json
54+
# platform-url: https://felias-fogg.github.io/downloads/package_debug_enabled_index.json
5555
# sketches-exclude: TraceTest,InterruptsTimings,EMAFilterTest,AVRUtilsDemo # Comma separated list of example names to exclude in build
5656

5757
# Do not cancel all jobs / architectures if one job fails

src/ADCUtils.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,8 @@
3030
#define ADC_UTILS_ARE_AVAILABLE
3131

3232
// External Reference Current is 150 uA for 5 V and 100 uA for 3.5 V
33-
#define READING_FOR_AREF 1024L // Datasheet 24.2: The minimum value represents GND and the maximum value represents the voltage on the AREF pin minus 1 LSB
34-
#define MAX_ADC_VALUE 1023L
33+
#define READING_FOR_AREF 1024 // Datasheet 24.2: The minimum value represents GND and the maximum value represents the voltage on the AREF pin minus 1 LSB
34+
#define MAX_ADC_VALUE 1023
3535

3636
// PRESCALE4 => 13 * 4 = 52 microseconds per ADC conversion at 1 MHz Clock => 19,2 kHz
3737
#define ADC_PRESCALE2 1 // 26 microseconds per ADC conversion at 1 MHz
@@ -228,7 +228,7 @@ bool isVCCTooHighSimple(); // Version not using readVCCVoltageMillivoltSimp
228228
#endif // defined(__AVR__) ...
229229

230230
/*
231-
* Variables and functions defined as dummies to allow for seamless compiling on non AVR platforms
231+
* The next variables and functions are defined as stubs on non-AVR platforms to allow for seamless compiling
232232
*/
233233
extern float sVCCVoltage;
234234
extern uint16_t sVCCVoltageMillivolt;

src/ADCUtils.hpp

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@
4343
* with INTERNAL you can calibrate your ADC readout. For my Nanos I measured e.g. 1060 mV and 1093 mV.
4444
*/
4545
#if !defined(ADC_INTERNAL_REFERENCE_MILLIVOLT)
46-
#define ADC_INTERNAL_REFERENCE_MILLIVOLT 1100UL // Change to value measured at the AREF pin. If value > real AREF voltage, measured values are > real values
46+
#define ADC_INTERNAL_REFERENCE_MILLIVOLT 1100 // Change to value measured at the AREF pin. If value > real AREF voltage, measured values are > real values
4747
#endif
4848

4949
// Union to speed up the combination of low and high bytes to a word
@@ -542,7 +542,7 @@ float getVCCVoltageSimple(void) {
542542
uint16_t getVCCVoltageMillivoltSimple(void) {
543543
// use AVCC with external capacitor at AREF pin as reference
544544
uint16_t tVCC = readADCChannelMultiSamplesWithReference(ADC_1_1_VOLT_CHANNEL_MUX, DEFAULT, 4);
545-
return ((READING_FOR_AREF * ADC_INTERNAL_REFERENCE_MILLIVOLT * 4) / tVCC);
545+
return (((uint32_t)READING_FOR_AREF * ADC_INTERNAL_REFERENCE_MILLIVOLT * 4) / tVCC);
546546
}
547547

548548
/*
@@ -554,7 +554,7 @@ uint16_t getVCCVoltageReadingFor1_1VoltReference(void) {
554554
/*
555555
* Do not switch back ADMUX to enable checkAndWaitForReferenceAndChannelToSwitch() to work correctly for the next measurement
556556
*/
557-
return ((READING_FOR_AREF * READING_FOR_AREF) / tVCC);
557+
return (((uint32_t)READING_FOR_AREF * READING_FOR_AREF) / tVCC);
558558
}
559559

560560
/*
@@ -578,7 +578,7 @@ uint16_t getVCCVoltageMillivolt(void) {
578578
/*
579579
* Do not switch back ADMUX to enable checkAndWaitForReferenceAndChannelToSwitch() to work correctly for the next measurement
580580
*/
581-
return ((READING_FOR_AREF * ADC_INTERNAL_REFERENCE_MILLIVOLT) / tVCC);
581+
return (((uint32_t)READING_FOR_AREF * ADC_INTERNAL_REFERENCE_MILLIVOLT) / tVCC);
582582
}
583583

584584
/*
@@ -617,7 +617,7 @@ void readVCCVoltageSimple(void) {
617617
void readVCCVoltageMillivoltSimple(void) {
618618
// use AVCC with external capacitor at AREF pin as reference
619619
uint16_t tVCCVoltageMillivoltRaw = readADCChannelMultiSamplesWithReference(ADC_1_1_VOLT_CHANNEL_MUX, DEFAULT, 4);
620-
sVCCVoltageMillivolt = (READING_FOR_AREF * ADC_INTERNAL_REFERENCE_MILLIVOLT * 4) / tVCCVoltageMillivoltRaw;
620+
sVCCVoltageMillivolt = ((uint32_t)READING_FOR_AREF * ADC_INTERNAL_REFERENCE_MILLIVOLT * 4) / tVCCVoltageMillivoltRaw;
621621
}
622622

623623
/*
@@ -638,7 +638,7 @@ void readVCCVoltageMillivolt(void) {
638638
/*
639639
* Do not switch back ADMUX to enable checkAndWaitForReferenceAndChannelToSwitch() to work correctly for the next measurement
640640
*/
641-
sVCCVoltageMillivolt = (READING_FOR_AREF * ADC_INTERNAL_REFERENCE_MILLIVOLT) / tVCCVoltageMillivoltRaw;
641+
sVCCVoltageMillivolt = ((uint32_t)READING_FOR_AREF * ADC_INTERNAL_REFERENCE_MILLIVOLT) / tVCCVoltageMillivoltRaw;
642642
}
643643

644644
/*
@@ -700,7 +700,7 @@ bool isVCCUSBPowered(Print *aSerial) {
700700
*/
701701
bool isVCCUndervoltageMultipleTimes() {
702702
/*
703-
* Check VCC every VCC_CHECK_PERIOD_MILLIS (10) seconds
703+
* Check VCC every VCC_CHECK_PERIOD_MILLIS - default is 10 seconds
704704
*/
705705
if (millis() - sLastVCCCheckMillis >= VCC_CHECK_PERIOD_MILLIS) {
706706
sLastVCCCheckMillis = millis();

src/HCSR04.h

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,11 @@
4242
#define US_DISTANCE_TIMEOUT_MICROS_FOR_2_METER 11650 // Timeout of 11650 is 2 meter
4343
#define US_DISTANCE_TIMEOUT_MICROS_FOR_3_METER 17475 // Timeout of 17475 is 3 meter
4444

45+
// Return values for getUSDistanceAsCentimeterWithCentimeterTimeoutPeriodicallyAndPrintIfChanged()
46+
#define HCSR04_DISTANCE_NO_MEASUREMENT 0
47+
#define HCSR04_MEASUREMENT_AND_DISTANCE_HAS_CHANGED 1
48+
#define HCSR04_MEASUREMENT_AND_DISTANCE_HAS_NOT_CHANGED 2
49+
4550
void initUSDistancePins(uint8_t aTriggerOutPin, uint8_t aEchoInPin = 0);
4651
void initUSDistancePin(uint8_t aTriggerOutEchoInPin); // Using this determines one pin mode
4752
void setHCSR04OnePinMode(bool aUseOnePinMode);
@@ -50,7 +55,7 @@ unsigned int getCentimeterFromUSMicroSeconds(unsigned int aDistanceMicros);
5055
uint8_t getMillisFromUSCentimeter(unsigned int aDistanceCentimeter);
5156
unsigned int getUSDistanceAsCentimeter(unsigned int aTimeoutMicros = US_DISTANCE_DEFAULT_TIMEOUT_MICROS);
5257
unsigned int getUSDistanceAsCentimeterWithCentimeterTimeout(unsigned int aTimeoutCentimeter);
53-
bool getUSDistanceAsCentimeterWithCentimeterTimeoutPeriodicallyAndPrintIfChanged(unsigned int aTimeoutCentimeter,
58+
uint8_t getUSDistanceAsCentimeterWithCentimeterTimeoutPeriodicallyAndPrintIfChanged(unsigned int aTimeoutCentimeter,
5459
unsigned int aMillisBetweenMeasurements, Print *aSerial);
5560
void testUSSensor(uint16_t aSecondsToTest);
5661

@@ -72,6 +77,6 @@ extern unsigned long sLastUSDistanceMeasurementMillis; // Only written by getUSD
7277
extern unsigned int sLastUSDistanceCentimeter; // Only written by getUSDistanceAsCentimeterWithCentimeterTimeoutPeriodicallyAndPrintIfChanged()
7378
extern unsigned int sUSDistanceMicroseconds;
7479
extern unsigned int sUSDistanceCentimeter;
75-
extern uint8_t sUsedMillisForMeasurement; // is optimized out if not used
80+
extern uint8_t sUsedMillisForUSDistanceMeasurement; // is optimized out if not used
7681

7782
#endif // _HCSR04_H

src/HCSR04.hpp

Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ unsigned long sLastUSDistanceMeasurementMillis; // Only written by getUSDistance
103103
unsigned int sLastUSDistanceCentimeter; // Only written by getUSDistanceAsCentimeterWithCentimeterTimeoutPeriodicallyAndPrintIfChanged()
104104
unsigned int sUSDistanceMicroseconds;
105105
unsigned int sUSDistanceCentimeter;
106-
uint8_t sUsedMillisForMeasurement; // is optimized out if not used
106+
uint8_t sUsedMillisForUSDistanceMeasurement;
107107

108108
/*
109109
* @param aEchoInPin - If aEchoInPin == 0 then assume 1 pin mode
@@ -199,8 +199,8 @@ unsigned int getUSDistance(unsigned int aTimeoutMicros) {
199199
#else
200200
sUSDistanceMicroseconds = pulseInLong(tEchoInPin, HIGH, aTimeoutMicros); // returns 0 (DISTANCE_TIMEOUT_RESULT) for timeout
201201
#endif
202-
// Division takes 48 us and adds 50 bytes program space. Statement is optimized out if sUsedMillisForMeasurement is not used
203-
sUsedMillisForMeasurement = (sUSDistanceMicroseconds + 550) / MICROS_IN_ONE_MILLI;
202+
// Division takes 48 us and adds 50 bytes program space. Statement is optimized out if sUsedMillisForUSDistanceMeasurement is not used
203+
sUsedMillisForUSDistanceMeasurement = (sUSDistanceMicroseconds + 550) / MICROS_IN_ONE_MILLI;
204204
return sUSDistanceMicroseconds;
205205
}
206206

@@ -235,25 +235,37 @@ unsigned int getUSDistanceAsCentimeterWithCentimeterTimeout(unsigned int aTimeou
235235
}
236236

237237
/**
238-
* @return true, if US distance has changed
238+
* @return HCSR04_DISTANCE_NO_MEASUREMENT, HCSR04_MEASUREMENT_AND_DISTANCE_HAS_CHANGED or HCSR04_MEASUREMENT_AND_DISTANCE_HAS_NOT_CHANGED
239239
*/
240-
bool getUSDistanceAsCentimeterWithCentimeterTimeoutPeriodicallyAndPrintIfChanged(unsigned int aTimeoutCentimeter,
240+
uint8_t getUSDistanceAsCentimeterWithCentimeterTimeoutPeriodicallyAndPrintIfChanged(unsigned int aTimeoutCentimeter,
241241
unsigned int aMillisBetweenMeasurements, Print *aSerial) {
242242
if ((millis() - sLastUSDistanceMeasurementMillis) >= aMillisBetweenMeasurements) {
243+
sLastUSDistanceMeasurementMillis = millis();
243244
getUSDistanceAsCentimeterWithCentimeterTimeout(aTimeoutCentimeter);
244-
if (sLastUSDistanceCentimeter != sUSDistanceCentimeter) {
245+
unsigned int tDeltaDistance;
246+
if (sLastUSDistanceCentimeter > sUSDistanceCentimeter) {
247+
tDeltaDistance = sLastUSDistanceCentimeter - sUSDistanceCentimeter;
248+
} else {
249+
tDeltaDistance = sUSDistanceCentimeter - sLastUSDistanceCentimeter;
250+
}
251+
/*
252+
* Suppress printing on 1 cm difference for each 30 cm distance.
253+
* E.g. if we have 75 cm the margin is 2 cm -> do not print distances from 73 to 77
254+
*/
255+
if (tDeltaDistance > (sLastUSDistanceCentimeter / 30)) {
245256
sLastUSDistanceCentimeter = sUSDistanceCentimeter;
246257
if (sUSDistanceCentimeter == 0) {
247-
aSerial->println(F("Timeout"));
258+
aSerial->println(F("Distance timeout"));
248259
} else {
249260
aSerial->print(F("Distance="));
250261
aSerial->print(sUSDistanceCentimeter);
251262
aSerial->println(F("cm"));
252263
}
253-
return true;
264+
return HCSR04_MEASUREMENT_AND_DISTANCE_HAS_CHANGED;
254265
}
266+
return HCSR04_MEASUREMENT_AND_DISTANCE_HAS_NOT_CHANGED;
255267
}
256-
return false;
268+
return HCSR04_DISTANCE_NO_MEASUREMENT;
257269
}
258270

259271
/*

src/LocalDebugLevelCheck.h

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
/*
2+
* LocalDebugLevelCheck.h
3+
* Throw error if LOCAL_TRACE, LOCAL_DEBUG or LOCAL_INFO is defined, which should not be at the start of any hpp file.
4+
* Each LOCAL_* definition must be undefined at the end of the file which defined it using #include "LocalDebugLevelEnd.h".
5+
*
6+
* LOCAL_TRACE // Information you need to understand details of a function or if you hunt a bug.
7+
* LOCAL_DEBUG // Information need to understand the operating of your program. E.g. function calls and values of control variables.
8+
* LOCAL_INFO // Information you want to see in regular operation to see what the program is doing. E.g. "Now playing Muppets melody".
9+
* LOCAL_WARN // Information that the program may encounter problems, like small Heap/Stack area.
10+
* LOCAL_ERROR // Informations to explain why the program will not run. E.g. not enough Ram for all created objects.
11+
*
12+
* Copyright (C) 2025 Armin Joachimsmeyer
13+
* Email: armin.joachimsmeyer@gmail.com
14+
*
15+
* This file is part of Arduino-Utils https://github.com/ArminJo/Arduino-Utils.
16+
*
17+
* Arduino-Utils is free software: you can redistribute it and/or modify
18+
* it under the terms of the GNU General Public License as published by
19+
* the Free Software Foundation, either version 3 of the License, or
20+
* (at your option) any later version.
21+
*
22+
* This program is distributed in the hope that it will be useful,
23+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
24+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
25+
* See the GNU General Public INFOse for more details.
26+
*
27+
* You should have received a copy of the GNU General Public License
28+
* along with this program. If not, see <http://www.gnu.org/licenses/gpl.html>.
29+
*
30+
*/
31+
32+
/*
33+
* Check LOCAL_* macros
34+
*/
35+
#if defined(LOCAL_TRACE)
36+
#error "LOCAL_TRACE is enabled at top of included file. Maybe because of missing include of LocalDebugLevelEnd.h at end of previous included file."
37+
#endif
38+
39+
#if defined(LOCAL_DEBUG)
40+
#error "LOCAL_DEBUG is enabled at top of included file. Maybe because of missing include of LocalDebugLevelEnd.h at end of previous included file."
41+
#endif
42+
43+
#if defined(LOCAL_INFO)
44+
#error "LOCAL_INFO is enabled at top of included file. Maybe because of missing include of LocalDebugLevelEnd.h at end of previous included file."
45+
#endif
46+
47+
/*
48+
* Check *_PRINT macros
49+
*/
50+
#if defined(TRACE_PRINT)
51+
#error "TRACE_PRINT is enabled at top of included file. Maybe because of missing include of LocalDebugLevelEnd.h at end of previous included file."
52+
#endif
53+
54+
#if defined(DEBUG_PRINT)
55+
#error "DEBUG_PRINT is enabled at top of included file. Maybe because of missing include of LocalDebugLevelEnd.h at end of previous included file."
56+
#endif
57+
58+
#if defined(INFO_PRINT)
59+
#error "INFO_PRINT is enabled at top of included file. Maybe because of missing include of LocalDebugLevelEnd.h at end of previous included file."
60+
#endif

src/LocalDebugLevelEnd.h

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
/*
2+
* LocalDebugLevelEnd.h
3+
* Undefine local macros at the end of an included (.hpp) file
4+
*
5+
* Copyright (C) 2024 Armin Joachimsmeyer
6+
* Email: armin.joachimsmeyer@gmail.com
7+
*
8+
* This file is part of Arduino-Utils https://github.com/ArminJo/Arduino-Utils.
9+
*
10+
* Arduino-Utils is free software: you can redistribute it and/or modify
11+
* it under the terms of the GNU General Public License as published by
12+
* the Free Software Foundation, either version 3 of the License, or
13+
* (at your option) any later version.
14+
*
15+
* This program is distributed in the hope that it will be useful,
16+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
17+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
18+
* See the GNU General Public INFOse for more details.
19+
*
20+
* You should have received a copy of the GNU General Public License
21+
* along with this program. If not, see <http://www.gnu.org/licenses/gpl.html>.
22+
*
23+
*/
24+
25+
/*
26+
* Undefine local macros at the end of an included (.hpp) file
27+
*/
28+
#if defined(LOCAL_TRACE)
29+
#undef LOCAL_TRACE
30+
#endif
31+
#undef TRACE_PRINT
32+
#undef TRACE_PRINTLN
33+
#undef TRACE_FLUSH
34+
#if defined(LOCAL_DEBUG)
35+
#undef LOCAL_DEBUG
36+
#endif
37+
#undef DEBUG_PRINT
38+
#undef DEBUG_PRINTLN
39+
#undef DEBUG_FLUSH
40+
#if defined(LOCAL_INFO)
41+
#undef LOCAL_INFO
42+
#endif
43+
#undef INFO_PRINT
44+
#undef INFO_PRINTLN
45+
#undef INFO_FLUSH

src/LocalDebugLevelStart.h

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
/*
2+
* LocalDebugLevelStart.h
3+
* Include to propagate global debug levels to file local ones and to define appropriate print macros.
4+
* !!! If used in included (.hpp) files, #include "LocalDebugLevelEnd.h" must be used at end of file to undefine local macros.
5+
* If, for example, #define LOCAL_TRACE is placed before this include, it will not be propagated. This enables TRACE-level output to be selected only.
6+
*
7+
* LOCAL_TRACE // Information you need to understand details of a function or if you hunt a bug.
8+
* LOCAL_DEBUG // Information need to understand the operating of your program. E.g. function calls and values of control variables.
9+
* LOCAL_INFO // Information you want to see in regular operation to see what the program is doing. E.g. "Now playing Muppets melody".
10+
* LOCAL_WARN // Information that the program may encounter problems, like small Heap/Stack area.
11+
* LOCAL_ERROR // Informations to explain why the program will not run. E.g. not enough Ram for all created objects.
12+
*
13+
* Copyright (C) 2024-2026 Armin Joachimsmeyer
14+
* Email: armin.joachimsmeyer@gmail.com
15+
*
16+
* This file is part of Arduino-Utils https://github.com/ArminJo/Arduino-Utils.
17+
*
18+
* Arduino-Utils is free software: you can redistribute it and/or modify
19+
* it under the terms of the GNU General Public License as published by
20+
* the Free Software Foundation, either version 3 of the License, or
21+
* (at your option) any later version.
22+
*
23+
* This program is distributed in the hope that it will be useful,
24+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
25+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
26+
* See the GNU General Public INFOse for more details.
27+
*
28+
* You should have received a copy of the GNU General Public License
29+
* along with this program. If not, see <http://www.gnu.org/licenses/gpl.html>.
30+
*
31+
*/
32+
33+
/////////////// put this before the include /////////////////////////
34+
// This block must be located after the includes of other *.hpp files
35+
//#define LOCAL_INFO // This enables info output only for this file
36+
//#define LOCAL_DEBUG // This enables debug output only for this file - only for development
37+
//#define LOCAL_TRACE // This enables trace output only for this file - only for development
38+
39+
/*
40+
* Propagate debug level to local ones but at first not to each other, i.e. enabling TRACE does not enable DEBUG and INFO
41+
*/
42+
#if defined(TRACE) // Information you need to understand details of a function or if you hunt a bug.
43+
#define LOCAL_TRACE
44+
# if !defined(DO_NOT_PROPAGATE_DEBUG_LEVELS) // Propagate levels by default i.e. enabling TRACE does enable DEBUG and INFO
45+
#define LOCAL_DEBUG
46+
#define LOCAL_INFO
47+
# endif
48+
#endif
49+
50+
#if defined(DEBUG) // Information need to understand the operating of your program. E.g. function calls and values of control variables.
51+
#define LOCAL_DEBUG
52+
# if !defined(DO_NOT_PROPAGATE_DEBUG_LEVELS)
53+
#define LOCAL_INFO
54+
# endif
55+
#endif
56+
57+
#if defined(INFO) // Information you want to see in regular operation to see what the program is doing. E.g. "START ../src/LightToTone.cpp Version 1.2 from Dec 31 2019" or "Now playing Muppets melody".
58+
#define LOCAL_INFO
59+
#endif
60+
61+
/*
62+
* Define appropriate print macros
63+
*/
64+
#if defined(LOCAL_TRACE)
65+
#define TRACE_PRINT(...) Serial.print(__VA_ARGS__)
66+
#define TRACE_PRINTLN(...) Serial.println(__VA_ARGS__)
67+
#define TRACE_FLUSH() Serial.flush()
68+
#else
69+
#define TRACE_PRINT(...) void()
70+
#define TRACE_PRINTLN(...) void()
71+
#define TRACE_FLUSH() void()
72+
#endif
73+
74+
#if defined(LOCAL_DEBUG)
75+
#define DEBUG_PRINT(...) Serial.print(__VA_ARGS__)
76+
#define DEBUG_PRINTLN(...) Serial.println(__VA_ARGS__)
77+
#define DEBUG_FLUSH() Serial.flush()
78+
#else
79+
#define DEBUG_PRINT(...) void()
80+
#define DEBUG_PRINTLN(...) void()
81+
#define DEBUG_FLUSH() void()
82+
83+
#endif
84+
85+
#if defined(LOCAL_INFO)
86+
#define INFO_PRINT(...) Serial.print(__VA_ARGS__)
87+
#define INFO_PRINTLN(...) Serial.println(__VA_ARGS__)
88+
#define INFO_FLUSH() Serial.flush()
89+
#else
90+
#define INFO_PRINT(...) void()
91+
#define INFO_PRINTLN(...) void()
92+
#define INFO_FLUSH() void()
93+
#endif
94+

0 commit comments

Comments
 (0)