Analog read, followed by serial print, do it once until the value changes

Hi,

I have a potentiometer I want to use as an input for Photoshop to adjust brush hardness. The value can be between 0 and 100%. The program accepts keyboard presses of 1 to 10 to represent these levels, which is what I want to replicate using a leonardo.

The following code is what I have with some smoothing, using Serial.print for debugging before I implement Keyboard press / release.

Is it possible to Serial.print once, and only do it again if the analog read value changes (with some hysteresis say +/- 100 counts)?

void Potentiometer() {
  total = total - readings[readIndex];
  readings[readIndex] = analogRead(inputPin);
  total = total + readings[readIndex];
  // advance to the next position in the array:
  readIndex = readIndex + 1;
  if (readIndex >= numReadings) {
    // ...wrap around to the beginning:
    readIndex = 0;
  }
  // calculate the average:
  average = total / numReadings;
  // send it to the computer as ASCII digits
  Serial.println(average);
  if ((average > 0) && (average <= 100)) {
    Serial.println("10");
  } else {
    if ((average > 100) && (average <= 200)) {
      Serial.println("20");
    } else {
      if ((average > 200) && (average <= 300)) {
        Serial.println("30");
      } else {
        if ((average > 300) && (average <= 400)) {
          Serial.println("40");
        } else {
          if ((average > 400) && (average <= 500)) {
            Serial.println("50");
          } else {
            if ((average > 500) && (average <= 600)) {
              Serial.println("60");
            } else {
              if ((average > 600) && (average <= 700)) {
                Serial.println("70");
              } else {
                if ((average > 700) && (average <= 800)) {
                  Serial.println("80");
                } else {
                  if ((average > 800) && (average <= 900)) {
                    Serial.println("90");
                  } else {
                    if ((average > 900) && (average <= 1024)) {
                      Serial.println("100");
                    }
                    delay(1);        // delay in between reads for stability
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}

Keep a history of the last setting to compare to the new setting. If there is enough of a change take action and replace the history value with the newest one. See the state change detection example in the IDE Digital examples for an idea of the process.

Thanks,

Ok, I have tried the attached, but I am still getting multiple Serial.prints even if the pot is left alone. I have increased the numReadings to 100 in an effort to average out the noise, to no effect.

void Potentiometer() {
  total = total - readings[readIndex];
  readings[readIndex] = analogRead(inputPin);
  total = total + readings[readIndex];
  // advance to the next position in the array:
  readIndex = readIndex + 1;
  if (readIndex >= numReadings) {
    // ...wrap around to the beginning:
    readIndex = 0;
  }
  // calculate the average:
  average = total / numReadings;
  // send it to the computer as ASCII digits
  //Serial.println(average);
  if ((lastreading != average)) {
    if ((average > 0) && (average <= 100)) {
      Serial.println("10");
    } else {
      if ((average > 100) && (average <= 200)) {
        Serial.println("20");
      } else {
        if ((average > 200) && (average <= 300)) {
          Serial.println("30");
        } else {
          if ((average > 300) && (average <= 400)) {
            Serial.println("40");
          } else {
            if ((average > 400) && (average <= 500)) {
              Serial.println("50");
            } else {
              if ((average > 500) && (average <= 600)) {
                Serial.println("60");
              } else {
                if ((average > 600) && (average <= 700)) {
                  Serial.println("70");
                } else {
                  if ((average > 700) && (average <= 800)) {
                    Serial.println("80");
                  } else {
                    if ((average > 800) && (average <= 900)) {
                      Serial.println("90");
                    } else {
                      if ((average > 900) && (average <= 1024)) {
                        Serial.println("100");
                      }
                      lastreading = average;
                      delay(10);        // delay in between reads for stability
                    }
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}

Ok, I had the [lastReading = average] in the wrong place.

It now works well but still gives me multiple prints when moving the pot even a touch.

Any recommendations as to how to implement some hysteresis?

void Potentiometer() {
  total = total - readings[readIndex];
  readings[readIndex] = analogRead(inputPin);
  total = total + readings[readIndex];
  // advance to the next position in the array:
  readIndex = readIndex + 1;
  if (readIndex >= numReadings) {
    // ...wrap around to the beginning:
    readIndex = 0;
  }
  // calculate the average:
  average = total / numReadings;
  // send it to the computer as ASCII digits
  //Serial.println(average);
  if ((lastreading != average)) {
    if ((average > 0) && (average <= 100)) {
      Serial.println("10");
    } else {
      if ((average > 100) && (average <= 200)) {
        Serial.println("20");
      } else {
        if ((average > 200) && (average <= 300)) {
          Serial.println("30");
        } else {
          if ((average > 300) && (average <= 400)) {
            Serial.println("40");
          } else {
            if ((average > 400) && (average <= 500)) {
              Serial.println("50");
            } else {
              if ((average > 500) && (average <= 600)) {
                Serial.println("60");
              } else {
                if ((average > 600) && (average <= 700)) {
                  Serial.println("70");
                } else {
                  if ((average > 700) && (average <= 800)) {
                    Serial.println("80");
                  } else {
                    if ((average > 800) && (average <= 900)) {
                      Serial.println("90");
                    } else {
                      if ((average > 900) && (average <= 1024)) {
                        Serial.println("100");
                      }
                      
                      delay(10);        // delay in between reads for stability
                    }
                  }
                }
              }
            }
          }
        }
      }
    }
  }
  lastreading = average;
}

Something like:

if ((average <= lastReading - hysteresis || average >= lastReading + hysteresis)) {

Untested.

All but the last of those if and else statements should be else if.

Hi,

Modified as per your suggestion, added the hysteresis variable and I have tweaked it so I get a single key press as the value increases.

Thanks for your very valuable and prompt advice.

void Potentiometer() {
  total = total - readings[readIndex];
  readings[readIndex] = analogRead(inputPin);
  total = total + readings[readIndex];
  readIndex = readIndex + 1;
  if (readIndex >= numReadings) {
    readIndex = 0;
  }
  // calculate the average:
  average = total / numReadings;
  //Serial.println(average);
  if ((average <= lastreading - hysteresis || average >= lastreading + hysteresis)) {
    if ((average > 0) && (average <= 100)) {
      //Serial.println("10");
      Keyboard.press('1');
      Keyboard.press('0');
    } else if ((average > 100) && (average <= 200)) {
      //Serial.println("20");
      Keyboard.press('2');
      Keyboard.press('0');
    } else if ((average > 200) && (average <= 300)) {
      //Serial.println("30");
      Keyboard.press('3');
      Keyboard.press('0');
    } else if ((average > 300) && (average <= 400)) {
      //Serial.println("40");
      Keyboard.press('4');
      Keyboard.press('0');
    } else if ((average > 400) && (average <= 500)) {
      //Serial.println("50");
      Keyboard.press('5');
      Keyboard.press('0');
    } else if ((average > 500) && (average <= 600)) {
      //Serial.println("60");
      Keyboard.press('6');
      Keyboard.press('0');
    } else if ((average > 600) && (average <= 700)) {
      //Serial.println("70");
      Keyboard.press('7');
      Keyboard.press('0');
    } else if ((average > 700) && (average <= 800)) {
      Serial.println("80");
      Keyboard.press('8');
      Keyboard.press('0');
    } else if ((average > 800) && (average <= 900)) {
      //Serial.println("90");
      Keyboard.press('9');
      Keyboard.press('0');
    } else {
      if ((average > 900) && (average <= 1024)) {
        //Serial.println("100");
        Keyboard.press('0');
      }
      delay(10);        // delay in between reads for stability
    }
    lastreading = average;
    Keyboard.releaseAll();
  }
}

Using the map function might come in handy to reduce your code size.

int hardness = map(average, 0, 1023, 0, 100);
char buf[4];
itoa (hardness , buf, 10 );
for (int i = 0; i < strlen(buf); i++) Keyboard.press(buf[i]);

ToddL1962:
Using the map function might come in handy to reduce your code size.

int hardness = map(average, 0, 1023, 0, 100);

Interesting... how could the resulting integers be linked directly to multiple key presses?

e.g. 68 would require;
Keyboard.press('6');
Keyboard.press('8');
Keyboard.releaseAll();

negativ3:
Interesting... how could the resulting integers be linked directly to multiple key presses?

e.g. 68 would require;
Keyboard.press('6');
Keyboard.press('8');
Keyboard.releaseAll();

Added that code to my earlier response.

ToddL1962:
Added that code to my earlier response.

Ok, that works well but ps needs a leading zero for each single digit (from zero to 9%) … is it possible?

void Potentiometer() {
  total = total - readings[readIndex];
  readings[readIndex] = analogRead(inputPin);
  total = total + readings[readIndex];
  readIndex = readIndex + 1;
  if (readIndex >= numReadings) {
    readIndex = 0;
  }
  // calculate the average:
  average = total / numReadings;
  //Serial.println(average);
  if ((average <= lastreading - hysteresis || average >= lastreading + hysteresis)) {
    int hardness = map(average, 0, 1023, 0, 100);
    char buf[4];
    itoa (hardness , buf, 10 );
    for (int i = 0; i < strlen(buf); i++) Keyboard.press(buf[i]);
    lastreading = average;
    Keyboard.releaseAll();
  }
}
void Potentiometer() {
  total = total - readings[readIndex];
  readings[readIndex] = analogRead(inputPin);
  total = total + readings[readIndex];
  readIndex = readIndex + 1;
  if (readIndex >= numReadings) {
    readIndex = 0;
  }
  // calculate the average:
  average = total / numReadings;
  //Serial.println(average);
  if ((average <= lastreading - hysteresis || average >= lastreading + hysteresis)) {
    int hardness = map(average, 0, 1023, 0, 100);
    char buf[4];
    itoa (hardness , buf, 10 );
    if (hardness < 10) Keyboard.press('0');
    for (int i = 0; i < strlen(buf); i++) Keyboard.press(buf[i]);
    lastreading = average;
    Keyboard.releaseAll();
  }
}

ToddL1962:

void Potentiometer() {

total = total - readings[readIndex];
 readings[readIndex] = analogRead(inputPin);
 total = total + readings[readIndex];
 readIndex = readIndex + 1;
 if (readIndex >= numReadings) {
   readIndex = 0;
 }
 // calculate the average:
 average = total / numReadings;
 //Serial.println(average);
 if ((average <= lastreading - hysteresis || average >= lastreading + hysteresis)) {
   int hardness = map(average, 0, 1023, 0, 100);
   char buf[4];
   itoa (hardness , buf, 10 );
   if (hardness < 10) Keyboard.press(‘0’);
   for (int i = 0; i < strlen(buf); i++) Keyboard.press(buf[i]);
   lastreading = average;
   Keyboard.releaseAll();
 }

ToddL1962, for a person of few words, you certainly provide straightforward replies!
Thank you for your time and elegant solution.

negativ3:
ToddL1962, for a person of few words, you certainly provide straightforward replies!
Thank you for your time and elegant solution.

You are welcome. Glad it worked for you!