/**
* Author: Pawel Wanat
* Not for commercial use. Allowed for educational usage.
* For licensing, contact wanatpj arobase gmail point com.
*/
// pins
const int piezo = A2;
const int greenDiode = 2;
const int redDiode = 4;
// thresholds
const unsigned long longThreshold = 100; // ms
const unsigned long shortThreshold = 45; // ms
// Indicates moment and value of a last sound peak.
int maxPiezo = 0;
unsigned long maxMillis = 0;
// Indicates moment and value of a last sound.
int lastPiezo = 0;
unsigned long lastMillis = 0;
// Indicates moment and value of a sound when starts the loop.
int currentPiezo;
unsigned long currentMillis;
unsigned long millisPeriods[] = {0, 0, 0, 0, 0, 0};
int millisPeriodsIndex = 0;
const int millisPeriodsCount = sizeof(millisPeriods) / sizeof(millisPeriods[0]);
const unsigned long properPeriods[] = {2, 1, 1, 2, 4, 2};
const float tolerance = .3;
void setup() {
pinMode(piezo, INPUT);
pinMode(greenDiode, OUTPUT);
pinMode(redDiode, OUTPUT);
Serial.begin(9600);
setOpen(false);
}
void loop() {
/*Serial.print("millisPeriodsCount: ");
Serial.println(millisPeriodsCount);*/
currentPiezo = analogRead(piezo);
currentMillis = millis();
// We set up lower threshold, bigger than 0, because bluetooth
// component (used for debug) interacts with piezo.
if (currentPiezo > 8) {
Serial.print("currentPiezo: ");
Serial.println(currentPiezo);
//Serial.print("currentMillis: ");
//Serial.println(currentMillis);
if (updatePredicate()) {
processUpdate();
}
else if (newPredicate()) {
processNew();
}
lastPiezo = currentPiezo;
lastMillis = currentMillis;
}
if (donePredicate()) {
processDone();
}
if (properSequence()) {
setOpen(true);
}
}
void setOpen(boolean opened) {
digitalWrite(greenDiode, (opened ? HIGH : LOW));
digitalWrite(redDiode, (opened ? LOW : HIGH));
}
/**
* Queue methods.
*/
boolean properSequence() {
static unsigned long lastActualSum = 0;
unsigned long properSum = 0, actualSum = 0;
for (int i=0; i < millisPeriodsCount; ++i) {
properSum += properPeriods[i];
actualSum += millisPeriods[i];
}
if (actualSum == 0) {
return false;
}
boolean showDebug = false;
/*if (lastActualSum != actualSum) {
lastActualSum = actualSum;
showDebug = true;
}*/
if(showDebug) {
Serial.print("actualSum: ");
Serial.println(actualSum);
Serial.print("seq: ");
for(int i=0; i<millisPeriodsCount; ++i) {
int index = (i + millisPeriodsIndex) % millisPeriodsCount;
Serial.print(millisPeriods[index]);
Serial.print(", ");
}
Serial.println();
}
for(int i=0; i<millisPeriodsCount; ++i) {
int index = (i + millisPeriodsIndex) % millisPeriodsCount;
if (((properPeriods[i] * actualSum * (1 - tolerance)) > (properSum * millisPeriods[index]))
|| ((properSum * millisPeriods[index]) > (properPeriods[i] * actualSum * (1 + tolerance)))) {
if(showDebug) {
Serial.print("Failed on index: ");
Serial.println(index);
}
return false;
}
}
return true;
}
void saveOnQueue() {
millisPeriods[millisPeriodsIndex] = currentMillis - maxMillis; // Save a difference between now and a peak.
millisPeriodsIndex = (millisPeriodsIndex + 1) % millisPeriodsCount;
}
/**
* Checking and processing a new sound.
*/
boolean newPredicate() {
if (currentMillis - maxMillis < shortThreshold) {
return false;
}
if (currentMillis - maxMillis >= longThreshold) {
return true;
}
/** shortThreshold <= currentMillis - lastMillis < longThreshold */
/**
* This might be improved. Right now in processNew we don't save
* time distance between peaks, but time distance between a peak and
* a next moment, when piezo value started to increase. A proper
* peak should appeart just after it started to raise.
*/
return currentPiezo > lastPiezo;
}
void processNew() {
if (maxMillis != 0) {
saveOnQueue();
}
maxPiezo = currentPiezo;
maxMillis = currentMillis;
}
/**
* Checking and processing a current sound.
*/
boolean updatePredicate() {
return (currentMillis - maxMillis < shortThreshold)
|| ((currentMillis - maxMillis < longThreshold) && (currentPiezo < lastPiezo));
}
void processUpdate() {
if (currentPiezo > maxPiezo) {
maxPiezo = currentPiezo;
maxMillis = currentMillis;
}
}
/**
* Checking and processing an old sound.
*/
boolean donePredicate() {
return currentMillis - lastMillis >= 2000;
}
void processDone() {
lastPiezo = 0;
lastMillis = 0;
maxPiezo = 0;
maxMillis = 0;
}
Program zmienia zaświetloną diodę w zależności od tego czy wypukamy(wyklaskamy) prawidłowy kod.