This commit is contained in:
2025-06-23 11:51:54 +02:00
commit 8108b800da
13 changed files with 1030 additions and 0 deletions

View File

@@ -0,0 +1,141 @@
int portLeft = 4;
int portRight = 3;
long sampleMetro = 10;
long printMetro = 100;
int16_t stateLeft = 0;
int16_t stateRight = 0;
int16_t minLeft = 1024;
int16_t maxLeft = 0;
int16_t nextMinLeft = 1024;
int16_t nextMaxLeft = 0;
int16_t minRight = 1024;
int16_t maxRight = 0;
int16_t nextMinRight = 1024;
int16_t nextMaxRight = 0;
int16_t margin = 5;
int16_t rotation = 1; // right = 1, normal, -1 is reverse
int16_t lightLeft = 0; // latest reading
int16_t lightRight = 0;
double prevMs = 0; // timestamp of last peak
long previousSample = 0;
long previousPrint = 0;
double len = 0; // delay between the last two peaks
void setup() {
Serial.begin(57600);
Serial.println("\n[Monitoring a Ferraris Meter]");
//portLeft.mode(INPUT);
//portRight.mode(INPUT);
}
void loop() {
unsigned long currentMillis = millis();
// take a reading from both sensors
if(currentMillis - previousSample > sampleMetro) {
previousSample = currentMillis;
// read sensors
lightLeft = analogRead(portLeft);
lightRight = analogRead(portRight);
// to take into account changing peak sizes, we follow the peak size continuously
// the found peak size serves as the target (minus a small margin) for the next peak detection
// update minimum and maximum for the left sensor
if ( lightLeft > nextMaxLeft ) {
nextMaxLeft = lightLeft;
}
// we also do this for the valley
if ( lightLeft < nextMinLeft ) {
nextMinLeft = lightLeft;
}
// and the same for the right sensor
// update minimum and maximum for the right sensor
if ( lightRight > nextMaxRight ) {
nextMaxRight = lightRight;
}
if ( lightRight < nextMinRight ) {
nextMinRight = lightRight;
}
if (( stateLeft == 0 ) && (lightLeft > maxLeft - margin )) {
// make state = 1 when light above threshold and state == 0
stateLeft = 1;
// we are now going to a minimum, reset the minimum value of the left sensor
minLeft = nextMinLeft;
nextMinLeft = 1024;
// calculate rotation direction
if (( stateRight == 0 ) && (rotation < 1)) {
rotation++;
} else if ((stateRight == 1 ) && (rotation > -1)) {
rotation--;
}
// calculate delay between the last two peaks, now and prevMs
double ms = millis();
len = ms - prevMs;
prevMs = ms;
} else if ((stateLeft == 1 ) && (lightLeft < minLeft + margin)) {
// make state = 0 when light below threshold and state == 1
stateLeft = 0;
// we are now going to a maximum, reset the maximum value of the left sensor
maxLeft = nextMaxLeft;
nextMaxLeft = 0;
}
if (( stateRight == 0 ) && (lightRight > maxRight - margin )) {
// make state = 1 when light above threshold and state == 0
stateRight = 1;
// we are now going to a minimum, reset the minimum value of the right sensor
minRight = nextMinRight;
nextMinRight = 1024;
} else if ((stateRight == 1 ) && (lightRight < minRight + margin)) {
// make state = 0 when light below threshold and state == 1
stateRight = 0;
// we are now going to a maximum, reset the maximum value of the right sensor
maxRight = nextMaxRight;
nextMaxRight = 0;
}
}
// print current status
if(currentMillis - previousPrint > printMetro) {
previousPrint = currentMillis;
// calculate new delay between now and the previous peak (prevMs)
double ms = millis();
double tempDelay = ms - prevMs;
// if 'tempDelay' is larger than the delay between the last two peaks 'len' it means that the disc is spinning slower and power usage is decreasing
// so max power consumption at this moment is not len, but tempDelay.
if ( len > tempDelay ) {
tempDelay = len;
}
int watt = rotation * 4800000 / tempDelay; // my kwh meter says 600 rotations per kwh
Serial.print(watt);
Serial.print(" | ");
Serial.print(rotation);
Serial.print(" | ");
Serial.print(lightLeft);
Serial.print(" | ");
Serial.println(lightRight);
}
}