Skip to content

Commit a78d522

Browse files
committed
Improved MeasureVoltageAndResistance and other files and examples
1 parent 87f174a commit a78d522

File tree

10 files changed

+15345
-8296
lines changed

10 files changed

+15345
-8296
lines changed

.github/workflows/LibraryBuild.yml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ jobs:
4141
#############################################################################################################
4242
arduino-boards-fqbn:
4343
- arduino:avr:uno
44-
- ATTinyCore:avr:attinyx5:chip=85,clock=1internal
44+
# - ATTinyCore:avr:attinyx5:chip=85,clock=1internal
4545

4646
# Specify parameters for each board.
4747
# With sketches-exclude you may exclude specific examples for a board. Use a comma separated list.
@@ -50,9 +50,9 @@ jobs:
5050
- arduino-boards-fqbn: arduino:avr:uno
5151
sketches-exclude: 50Hz # Comma separated list of example names to exclude in build
5252

53-
- arduino-boards-fqbn: ATTinyCore:avr:attinyx5:chip=85,clock=1internal
54-
platform-url: http://drazzy.com/package_drazzy.com_index.json
55-
sketches-exclude: TraceTest,InterruptsTimings,EMAFilterTest,AVRUtilsDemo # Comma separated list of example names to exclude in build
53+
# - arduino-boards-fqbn: ATTinyCore:avr:attinyx5:chip=85,clock=1internal
54+
# platform-url: http://drazzy.com/package_drazzy.com_index.json
55+
# 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
5858
fail-fast: false

Optiboot_8_1/0_Burn_avrdude-optiboot_P81_to_328P.cmd

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,5 @@ rem unlock bootloader 0x3x No restrictions for SPM or LPM accessing the boot loa
33
rem lfuse 0xFF is low power crystal 8 to 16 Mhz, 0xF7 is full swing crystal. Both with slowly rising power.
44
avrdude -v -patmega328p -cstk500v1 -PCOM6 -b19200 -e -Ulock:w:0x3F:m -Uefuse:w:0xFD:m -Uhfuse:w:0xDE:m -Ulfuse:w:0xFF:m
55
rem lock bootloader against overwriting, but allow reading for do_spm() feature with: lock=0x2x. No access to bootloader with 0x0x.
6-
avrdude -v -patmega328p -cstk500v1 -PCOM6 -b19200 -u -Uflash:w:optiboot_atmega328P_81.hex:a -Ulock:w:0x0F:m
6+
avrdude -v -patmega328p -cstk500v1 -PCOM6 -b19200 -Uflash:w:optiboot_atmega328P_81.hex:a -Ulock:w:0x0F:m
77
pause

Optiboot_8_1/avrdude.conf

Lines changed: 15003 additions & 8089 deletions
Large diffs are not rendered by default.

Optiboot_8_1/avrdude.exe

4.61 MB
Binary file not shown.

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ Not yet available as Arduino library.
3636
* [SimpleEMAFilters](https://github.com/ArminJo/Arduino-Utils?tab=readme-ov-file#simpleemafilters)
3737
* [ADCUtils](https://github.com/ArminJo/Arduino-Utils?tab=readme-ov-file#adcutils)
3838
* [HCSR04](https://github.com/ArminJo/Arduino-Utils?tab=readme-ov-file#hcsr04)
39-
* [MeasureVoltageAndResistance](https://github.com/ArminJo/Arduino-Utils?tab=readme-ov-file#measurevoltageandresistancehpp)
39+
* [MeasureVoltageAndResistance](https://github.com/ArminJo/Arduino-Utils?tab=readme-ov-file#measurevoltageandresistance)
4040
* [BlinkLed](https://github.com/ArminJo/Arduino-Utils?tab=readme-ov-file#blinkled)
4141
* [ShowInfo](https://github.com/ArminJo/Arduino-Utils?tab=readme-ov-file#showinfo)
4242
* [HexDump](https://github.com/ArminJo/Arduino-Utils?tab=readme-ov-file#hexdump)

examples/AVRUtilsDemo/AVRUtilsDemo.ino

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,9 @@
5757

5858
#if defined(CODE_FOR_ATTINY)
5959
#include "ATtinySerialOut.hpp" // Available as Arduino library "ATtinySerialOut"
60+
61+
#define SIZE_OF_DUMMY_ARRAY 0x100 // small heap is available
62+
6063
#define LED_PIN PB1
6164
// Pin 1 has an LED connected on my Digispark board.
6265
# if (LED_PIN == TX_PIN)
@@ -68,10 +71,10 @@
6871
//#define SIZE_OF_DUMMY_ARRAY 1800 // Stack runs into data
6972
//#define SIZE_OF_DUMMY_ARRAY 1700 // Stack is OK, but no heap is available
7073
#define SIZE_OF_DUMMY_ARRAY 0x600 // 1536 Stack is OK, and small heap is available
71-
uint8_t sDummyArray[SIZE_OF_DUMMY_ARRAY] __attribute__((section(".noinit"))); // Place it at end of BSS to be first overwritten by stack.
7274

7375
#define LED_PIN LED_BUILTIN
7476
#endif
77+
uint8_t sDummyArray[SIZE_OF_DUMMY_ARRAY] __attribute__((section(".noinit"))); // Place it at end of BSS to be first overwritten by stack.
7578

7679
uint8_t sMCUSRStored; // content of MCUSR register at startup
7780

@@ -185,6 +188,7 @@ void setup() {
185188

186189
Serial.println();
187190

191+
#if !defined(CODE_FOR_ATTINY)
188192
printRAMInfo(&Serial);
189193
printStackMaxUsedAndUnusedSizes(&Serial);
190194

@@ -202,12 +206,13 @@ void setup() {
202206
printBaseRAMData(&Serial);
203207
printRAMInfo(&Serial);
204208
printStackMaxUsedAndUnusedSizes(&Serial); // test this function, it works different from function used in printRAMInfo
209+
#endif
205210

206211
Serial.println(F("Dump current stack"));
207212
printStackDump();
208213

209214
Serial.println(F("Show return address for current function \"setup()\""));
210-
Serial.println((uint16_t)__builtin_return_address(0), HEX);
215+
Serial.println((uint16_t) __builtin_return_address(0), HEX);
211216

212217
/*
213218
* init sleep mode and wakeup period

examples/VoltAndOhmmeter/VoltAndOhmmeter.ino

Lines changed: 11 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
* First voltage is measured.
66
* If voltage is zero, then resistance to ground is measured using 5 volt (VCC) and 10 kOhm or 100 kOhm supply.
77
*
8-
* Copyright (C) 2021 Armin Joachimsmeyer
8+
* Copyright (C) 2021-2025 Armin Joachimsmeyer
99
1010
*
1111
* This file is part of Arduino-Utils https://github.com/ArminJo/Arduino-Utils.
@@ -25,43 +25,9 @@
2525
*
2626
*/
2727

28-
/*
29-
* SCHEMATIC
30-
* +----o A3 open/VCC (for R measurement) | open (for U measurement)
31-
* |
32-
* -
33-
* | |
34-
* | | R3 (10 kOhm)
35-
* | |
36-
* -
37-
* | _____
38-
* Input <----+----|_____|---o A1 input (for R measurement) | open (for U measurement)
39-
* ^ | 100 k - just to protect the pin
40-
* | -
41-
* | | |
42-
* | | | R1 (100 kOhm)
43-
* | | |
44-
* - -
45-
* | | |
46-
* | | Rx +---o A0 VCC(R) | input(U)
47-
* | | |
48-
* - -
49-
* | | |
50-
* o GND | | R2 (22k)
51-
* | |
52-
* -
53-
* |
54-
* +---o A2 open(R) | GND(U)
55-
*
56-
* The ratio of R1 to Rx is equal the Ratio of (1023 - x) to x
57-
*
58-
* => The formula is: Rx/R1 = x / (1023-x)
59-
* Rx = R1 * x / (1023-x)
60-
*
61-
*/
6228
#include <Arduino.h>
6329

64-
#define VERSION_EXAMPLE "1.2"
30+
#define VERSION_EXAMPLE "2.0"
6531

6632
//#define NO_PRINT_OF_RESISTOR_MEASURMENT_VOLTAGE
6733

@@ -80,16 +46,10 @@
8046
* Imports and definitions for LCD
8147
*/
8248
#if defined(USE_SERIAL_LCD)
83-
# if defined(USE_SOFT_I2C_MASTER) // Must be declared globally. Saves 440 bytes
84-
#define I2C_HARDWARE 1 // use I2C Hardware
85-
#define I2C_PULLUP 1
86-
#define I2C_FASTMODE 1
87-
#include "SoftI2CMaster.h"
88-
# endif
89-
#include <LiquidCrystal_I2C.h> // Use an up to date library version which has the init method
49+
#include "LiquidCrystal_I2C.hpp" // Here we use an enhanced version, which supports SoftI2CMaster
9050
#endif
9151
#if defined(USE_PARALLEL_LCD)
92-
#include <LiquidCrystal.h>
52+
#include "LiquidCrystal.h"
9353
#endif
9454

9555
#if defined(USE_1602_LCD)
@@ -117,7 +77,9 @@ LiquidCrystal_I2C myLCD(0x27, LCD_COLUMNS, LCD_ROWS); // set the LCD address to
11777
LiquidCrystal myLCD(4, 5, 6, 7, 8, 9);
11878
#endif
11979

120-
// Include it after LCD settings, it requires the macros USE_LCD and USE_2004_LCD to be set
80+
// Include it after LCD settings, it requires the macros below and the macros USE_LCD and USE_2004_LCD to be set
81+
#define PRINT_OF_RESISTOR_MEASURMENT_VOLTAGE
82+
#define PRINT_OF_VCC
12183
#include "MeasureVoltageAndResistance.hpp"
12284

12385
#define STR_HELPER(x) #x
@@ -137,10 +99,8 @@ void setup() {
13799
// Just to know which program is running on my Arduino
138100
Serial.println(F("START " __FILE__ "\r\nVersion " VERSION_EXAMPLE " from " __DATE__));
139101

140-
printVoltageAndResistanceUsage();
141-
142102
/*
143-
* LCD initialization
103+
* LCD initialization, which may reduce VCC
144104
*/
145105
#if defined(USE_SERIAL_LCD)
146106
myLCD.init();
@@ -151,11 +111,14 @@ void setup() {
151111
myLCD.begin(LCD_COLUMNS, LCD_ROWS);
152112
#endif
153113

114+
printVoltageAndResistanceUsage();
115+
154116
#if defined(USE_SERIAL_LCD) || defined(USE_PARALLEL_LCD)
155117
myLCD.print(F("Volt+Ohm meter"));
156118
myLCD.setCursor(0, 1);
157119
myLCD.print(F(VERSION_EXAMPLE " " __DATE__));
158120
delay(2000);
121+
myLCD.clear();
159122
#endif
160123

161124
}

src/ADCUtils.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131

3232
// External Reference Current is 150 uA for 5 V and 100 uA for 3.5 V
3333
#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
3435

3536
// PRESCALE4 => 13 * 4 = 52 microseconds per ADC conversion at 1 MHz Clock => 19,2 kHz
3637
#define ADC_PRESCALE2 1 // 26 microseconds per ADC conversion at 1 MHz
@@ -172,8 +173,10 @@
172173
extern long sLastVCCCheckMillis;
173174
extern uint8_t sVCCTooLowCounter;
174175

176+
uint16_t readADCChannel();
175177
uint16_t readADCChannel(uint8_t aADCChannelNumber);
176178
uint16_t readADCChannelWithReference(uint8_t aADCChannelNumber, uint8_t aReference);
179+
uint16_t readADCChannelWithReferenceUsingInternalReference(uint8_t aADCChannelNumber);
177180
uint16_t waitAndReadADCChannelWithReference(uint8_t aADCChannelNumber, uint8_t aReference);
178181
uint16_t waitAndReadADCChannelWithReferenceAndRestoreADMUXAndReference(uint8_t aADCChannelNumber, uint8_t aReference);
179182
uint16_t readADCChannelWithOversample(uint8_t aADCChannelNumber, uint8_t aOversampleExponent);
@@ -188,6 +191,8 @@ uint16_t readADCChannelWithReferenceMaxMicros(uint8_t aADCChannelNumber, uint8_t
188191
uint16_t readUntil4ConsecutiveValuesAreEqual(uint8_t aADCChannelNumber, uint8_t aReference, uint8_t aDelay,
189192
uint8_t aAllowedDifference, uint8_t aMaxRetries);
190193

194+
void setADCChannelForNextConversionAndWaitUsingInternalReference(uint8_t aADCChannelNumber);
195+
void setADCChannelForNextConversionAndWaitUsingDefaultReference(uint8_t aADCChannelNumber);
191196
uint8_t checkAndWaitForReferenceAndChannelToSwitch(uint8_t aADCChannelNumber, uint8_t aReference);
192197

193198
/*

src/ADCUtils.hpp

Lines changed: 73 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727

2828
#include "ADCUtils.h"
2929
#if defined(ADC_UTILS_ARE_AVAILABLE) // set in ADCUtils.h, if supported architecture was detected
30+
#define ADC_UTILS_ARE_INCLUDED
3031

3132
#if !defined(STR)
3233
#define STR_HELPER(x) #x
@@ -41,7 +42,7 @@
4142
* with INTERNAL you can calibrate your ADC readout. For my Nanos I measured e.g. 1060 mV and 1093 mV.
4243
*/
4344
#if !defined(ADC_INTERNAL_REFERENCE_MILLIVOLT)
44-
#define ADC_INTERNAL_REFERENCE_MILLIVOLT 1100L // Change to value measured at the AREF pin. If value > real AREF voltage, measured values are > real values
45+
#define ADC_INTERNAL_REFERENCE_MILLIVOLT 1100UL // Change to value measured at the AREF pin. If value > real AREF voltage, measured values are > real values
4546
#endif
4647

4748
// Union to speed up the combination of low and high bytes to a word
@@ -66,6 +67,11 @@ union WordUnionForADCUtils {
6667
#else
6768
//#define LOCAL_DEBUG // This enables debug output only for this file
6869
#endif
70+
#if defined(INFO)
71+
#define LOCAL_INFO
72+
#else
73+
//#define LOCAL_INFO // This enables debug output only for this file
74+
#endif
6975

7076
/*
7177
* Persistent storage for VCC value
@@ -79,6 +85,27 @@ uint8_t sVCCTooLowCounter = 0;
7985

8086
/*
8187
* Conversion time is defined as 0.104 milliseconds by ADC_PRESCALE in ADCUtils.h.
88+
* Use previous settings
89+
*/
90+
uint16_t readADCChannel() {
91+
WordUnionForADCUtils tUValue;
92+
93+
// ADCSRB = 0; // Only active if ADATE is set to 1.
94+
// ADSC-StartConversion ADIF-Reset Interrupt Flag - NOT free running mode
95+
ADCSRA = (_BV(ADEN) | _BV(ADSC) | _BV(ADIF) | ADC_PRESCALE);
96+
97+
// wait for single conversion to finish
98+
loop_until_bit_is_clear(ADCSRA, ADSC);
99+
100+
// Get value
101+
tUValue.UByte.LowByte = ADCL;
102+
tUValue.UByte.HighByte = ADCH;
103+
return tUValue.UWord;
104+
// return ADCL | (ADCH <<8); // needs 4 bytes more
105+
}
106+
107+
/*
108+
* Use new channel aADCChannelNumber, but do not wait for channel switching
82109
*/
83110
uint16_t readADCChannel(uint8_t aADCChannelNumber) {
84111
WordUnionForADCUtils tUValue;
@@ -97,7 +124,6 @@ uint16_t readADCChannel(uint8_t aADCChannelNumber) {
97124
return tUValue.UWord;
98125
// return ADCL | (ADCH <<8); // needs 4 bytes more
99126
}
100-
101127
/*
102128
* Conversion time is defined as 0.104 milliseconds by ADC_PRESCALE in ADCUtils.h.
103129
*/
@@ -118,6 +144,22 @@ uint16_t readADCChannelWithReference(uint8_t aADCChannelNumber, uint8_t aReferen
118144
return tUValue.UWord;
119145
}
120146

147+
uint16_t readADCChannelWithReferenceUsingInternalReference(uint8_t aADCChannelNumber) {
148+
WordUnionForADCUtils tUValue;
149+
ADMUX = aADCChannelNumber | (INTERNAL << SHIFT_VALUE_FOR_REFERENCE);
150+
151+
// ADCSRB = 0; // Only active if ADATE is set to 1.
152+
// ADSC-StartConversion ADIF-Reset Interrupt Flag - NOT free running mode
153+
ADCSRA = (_BV(ADEN) | _BV(ADSC) | _BV(ADIF) | ADC_PRESCALE);
154+
155+
// wait for single conversion to finish
156+
loop_until_bit_is_clear(ADCSRA, ADSC);
157+
158+
// Get value
159+
tUValue.UByte.LowByte = ADCL;
160+
tUValue.UByte.HighByte = ADCH;
161+
return tUValue.UWord;
162+
}
121163
/*
122164
* Conversion time is defined as 0.104 milliseconds by ADC_PRESCALE in ADCUtils.h.
123165
* Does NOT restore ADMUX after reading
@@ -145,6 +187,19 @@ void setADCChannelAndReferenceForNextConversion(uint8_t aADCChannelNumber, uint8
145187
ADMUX = aADCChannelNumber | (aReference << SHIFT_VALUE_FOR_REFERENCE);
146188
}
147189

190+
/*
191+
* 100 kOhm requires < 100 us, 1 MOhm requires 120 us S&H switching time
192+
*/
193+
void setADCChannelForNextConversionAndWaitUsingInternalReference(uint8_t aADCChannelNumber) {
194+
ADMUX = aADCChannelNumber | (INTERNAL << SHIFT_VALUE_FOR_REFERENCE);
195+
delayMicroseconds(120); // experimental value is <= 1100 us for Nano board
196+
}
197+
198+
void setADCChannelForNextConversionAndWaitUsingDefaultReference(uint8_t aADCChannelNumber) {
199+
ADMUX = aADCChannelNumber | (DEFAULT << SHIFT_VALUE_FOR_REFERENCE);
200+
delayMicroseconds(120); // experimental value is <= 1100 us for Nano board
201+
}
202+
148203
/*
149204
* @return original ADMUX register content for optional later restoring values
150205
* All experimental values are acquired by using the ADCSwitchingTest example from this library
@@ -639,13 +694,13 @@ bool isVCCUSBPowered(Print *aSerial) {
639694
}
640695

641696
/*
697+
* It checks every 10 seconds for 6 times, and then returns true if the undervoltage condition ( <3.4V ) still applies.
642698
* @ return true only once, when VCC_UNDERVOLTAGE_CHECKS_BEFORE_STOP (6) times voltage too low -> shutdown
643699
*/
644700
bool isVCCUndervoltageMultipleTimes() {
645701
/*
646702
* Check VCC every VCC_CHECK_PERIOD_MILLIS (10) seconds
647703
*/
648-
649704
if (millis() - sLastVCCCheckMillis >= VCC_CHECK_PERIOD_MILLIS) {
650705
sLastVCCCheckMillis = millis();
651706

@@ -655,30 +710,32 @@ bool isVCCUndervoltageMultipleTimes() {
655710
readVCCVoltageMillivolt();
656711
# endif
657712

658-
if (sVCCTooLowCounter < VCC_UNDERVOLTAGE_CHECKS_BEFORE_STOP) {
659-
/*
660-
* Do not check again if shutdown has happened
661-
*/
713+
/*
714+
* Do not check again if shutdown signaling (sVCCTooLowCounter >= 6) has happened
715+
*/
716+
if (sVCCTooLowCounter < VCC_UNDERVOLTAGE_CHECKS_BEFORE_STOP) { // VCC_UNDERVOLTAGE_CHECKS_BEFORE_STOP = 6
662717
if (sVCCVoltageMillivolt > VCC_UNDERVOLTAGE_THRESHOLD_MILLIVOLT) {
663718
sVCCTooLowCounter = 0; // reset counter
664719
} else {
665720
/*
666-
* Voltage too low, wait VCC_UNDERVOLTAGE_CHECKS_BEFORE_STOP (6) times and then shut down.
721+
* Voltage too low, wait VCC_UNDERVOLTAGE_CHECKS_BEFORE_STOP (6) times and then signal shut down.
667722
*/
668723
if (sVCCVoltageMillivolt < VCC_EMERGENCY_UNDERVOLTAGE_THRESHOLD_MILLIVOLT) {
669724
// emergency shutdown
670725
sVCCTooLowCounter = VCC_UNDERVOLTAGE_CHECKS_BEFORE_STOP;
671-
# if defined(INFO)
726+
# if defined(LOCAL_INFO)
672727
Serial.println(
673728
F(
674-
"Voltage < " STR(VCC_EMERGENCY_UNDERVOLTAGE_THRESHOLD_MILLIVOLT) " mV detected -> emergency shutdown"));
729+
"Undervoltage < " STR(VCC_EMERGENCY_UNDERVOLTAGE_THRESHOLD_MILLIVOLT) " mV detected -> emergency shutdown"));
675730
# endif
676731
} else {
677732
sVCCTooLowCounter++;
678-
# if defined(INFO)
679-
Serial.print(F("Voltage < " STR(VCC_UNDERVOLTAGE_THRESHOLD_MILLIVOLT) " mV detected: "));
733+
# if defined(LOCAL_INFO)
734+
Serial.print(sVCCVoltageMillivolt);
735+
Serial.print(F(" mV < " STR(VCC_UNDERVOLTAGE_THRESHOLD_MILLIVOLT) " mV undervoltage detected: "));
736+
680737
Serial.print(VCC_UNDERVOLTAGE_CHECKS_BEFORE_STOP - sVCCTooLowCounter);
681-
Serial.println(F(" tries left"));
738+
Serial.println(F(" attempts left"));
682739
# endif
683740
}
684741
if (sVCCTooLowCounter == VCC_UNDERVOLTAGE_CHECKS_BEFORE_STOP) {
@@ -820,4 +877,7 @@ float getVCCVoltage() {
820877
#if defined(LOCAL_DEBUG)
821878
#undef LOCAL_DEBUG
822879
#endif
880+
#if defined(LOCAL_INFO)
881+
#undef LOCAL_INFO
882+
#endif
823883
#endif // _ADC_UTILS_HPP

0 commit comments

Comments
 (0)