/*
Forum: https://forum.arduino.cc/t/sample-and-hold/1416316
Wokwi: https://wokwi.com/projects/448687801988618241
Sample and Hold using a finite state machine
2025/11/26
ec2021
*/
constexpr byte buttonPin {2}; // The digital pin for the button
constexpr byte analogInPin {A0}; // The analog input pin
constexpr byte ledPin {3};
constexpr byte noOfSamples {10};
constexpr unsigned long holdDuration {5000}; // Hold time in milliseconds
constexpr unsigned long sampleInterval {10}; // Time between two samples in ms
constexpr unsigned long printInterval {100}; // Interval between Serial printings
uint16_t sampleValue = 0; // Variable to store the "held" analog value
enum class State {IDLE, SAMPLE, HOLD};
State state = State::IDLE;
void setup() {
Serial.begin(115200);
pinMode(buttonPin, INPUT_PULLUP); // Use internal pull-up resistor
pinMode(ledPin, OUTPUT);
}
void loop() {
StateMachine();
printSampleValue();
}
void StateMachine() {
static unsigned long sum = 0;
static uint16_t count = 0;
static unsigned long startTime = 0;
switch (state) {
case (State::IDLE): // Waits for pressing the button
if (buttonPressed()) {
startTime = millis(); // Prepare the SAMPLE state
count = 0;
sum = 0;
state = State::SAMPLE; // Start sampling
}
break;
case (State::SAMPLE):
if (millis() - startTime >= sampleInterval) { // Samples until noOfSamples have been reached
startTime = millis();
sum += analogRead(analogInPin);
count++;
if (count >= noOfSamples) {
startTime = millis();
sampleValue = (count > 0) ? sum / count : sampleValue; // Calculate the average
digitalWrite(ledPin, HIGH); // Switch led on
state = State::HOLD; // Go to HOLD
}
}
break;
case (State::HOLD): // Holds sampleValue for holdDuration
if (millis() - startTime >= holdDuration) { // Does not do anything else
digitalWrite(ledPin, LOW); // After the time has expired switch led off
sampleValue = 0; // sampleValue is reset
state = State::IDLE; // Go on with IDLE
}
break;
}
}
boolean buttonPressed() {
return (!digitalRead(buttonPin)); // No debouncing required as the following processes require several seconds
}
void printSampleValue() { // prints the sampled value everytime when printInterval has exceeded
static unsigned long lastTime = 0;
if (millis() - lastTime > printInterval) {
lastTime = millis();
Serial.println(sampleValue);
}
}