// This simulates a pulse train on simPin,
// detects the pulses on pinIn,
// runs a PLL at pll_div * the speed of the pulses,
// Runs a bresenham algorithm on the ratio of dy/dx for outpin pulses of out_interval us
// if dy is faster than dx, you should use a bigger pll_div than 1 to provide
// distinct intervals between double-steps and reduced jitter.
// if dy < dx, a pll_div of 1 is OK
//
// https://wokwi.com/projects/355885955385104385
// for https://forum.arduino.cc/t/how-to-slow-down-the-signal-from-a-hall-effect-sensor/1086525/3
//
// https://www.romanblack.com/one_sec.htm is good reading.
// Look at the sections on the sinewave inverter
int32_t bresenham = 0;
int32_t bres_pll = 0;
int dy = 4000;
int dx = 4500;
const int pll_div = 4; // how many sub-pulses per input pulse
const int debug = 2; // level of serial output
unsigned long out_interval = 1000;
uint32_t last_pulse = 0;
const int pinIn = 3;
const int simPin = pinIn;
const int outpin = LED_BUILTIN;
void setup() {
// put your setup code here, to run once:
Serial.begin(115200);
pinMode(outpin, OUTPUT);
pinMode(pinIn, INPUT_PULLUP);
pinMode(simPin, OUTPUT); // same pin used to simulate input
}
uint32_t now = 0;
void simpulses(void) { // read the slide potentiometer and simulate a variable pulse train
int simState = digitalRead(simPin);
static uint32_t lastSim = 0;
static unsigned long last = 0;
// 4000/mi / (X mi/hr 1hr/3600s * 1s/1000us)
// 1/(4000 pulse/mile * 60 mi/hr /(3600s/hr*1000ms/s))) gives
static uint32_t interval = 3600UL * 1000 * 1000 / 4000 / 10 * 0 + 1000000UL ; // mph to ms/pulsein
static int32_t lastRead = -2500000UL;
static int lastA0 = 0;
if ( now - lastRead > 250000UL && abs((int)analogRead(A0) - lastA0) > 0 ) {
lastA0 = analogRead(A0);
//interval = 6000UL + 1000UL * lastA0;
interval = 3600UL * 1e6 * 1024 / 4000 / (0 + lastA0) / 15;
if (debug > 0) {
Serial.print("mph:");
Serial.print(interval ? 3600.0 * 1e6 / 4000 / interval : 0.0);
}
lastRead = now;
}
if (now - last >= interval ) { // simulate pulse
last = now;
digitalWrite(simPin, HIGH);
lastSim = now;
//Serial.print('^');
}
if (simState == HIGH && now - lastSim >= out_interval) {
// turn off simulated pulse
digitalWrite(simPin, LOW);
}
}
void loop() {
int inState = digitalRead(pinIn);
uint32_t lastInterval = 0;
static int lastin = HIGH;
static uint32_t lastFall = 0;
static uint32_t dt = 1;
static uint32_t lastpll = 0;
int simState = digitalRead(simPin);
static uint32_t lastSim = 0;
static uint32_t pllSteps = 0;
now = micros();
simpulses();
if (inState != lastin) { // check input pulse
if ( inState == LOW) { //falling edge
lastInterval = now - lastFall;
bres_pll = lastInterval; // += sensitive to wide swings near zero
dt = max(1, lastInterval / pll_div); //
lastFall = now;
if (debug > 0)Serial.print('\\'); // falling edge
//Serial.print(bres_pll);
//Serial.print(dt);
//Serial.print(pllSteps);
} else {
if (debug > 2) Serial.print('/'); // rising edge
}
lastin = inState;
}
// Run PLL at input freq * pll_div
if (now - lastpll >= dt && bres_pll +dt > 0) {
lastpll += dt;
if (bres_pll > 0) { //
bres_pll -= dt;
bresenham += dy;
if (debug > 1)Serial.print('.');
if (debug > 3) Serial.print(bresenham);
}
}
if (now - last_pulse > 6000 && bresenham > (int32_t)dx * pll_div) { //
bresenham -= (int32_t)dx * pll_div;
digitalWrite(LED_BUILTIN, HIGH);
if (debug > 0)Serial.print('*');
if (debug > 3)Serial.print(bresenham);
last_pulse = now;
}
if (digitalRead(LED_BUILTIN) && now - last_pulse > out_interval)
{ // turn off outpulse
digitalWrite(LED_BUILTIN, LOW);
if (debug > 2) Serial.print('_');
}
}