How to count millisecond between two digital input spike

I'm creating a program to detect the BPM of the sync output of a synthesizer.
This sync signal is a digital HIGH spike every step.
I need to know how to measure the time between 2 spikes.

I've already tried to do this with a heart rate sensor library but it doesn't work well.

This is my current program.
It is capable of creating a sync signal from a BPM chosen with a sliding linear potentiometer.
It also has an LCD screen to display the sent BPM and the received BPM.

#include <LiquidCrystal.h>

//  Variables
#define OUTPUT 12
#define INPUT = 10;                   // Digital PIN 0
const int LED = LED_BUILTIN;          // The on-board Arduino LED, close to PIN 13.
const int LED2 = 4;
int BPMOUT = 120;

//Potentiometer
int potPin = 5;              
int potVal = 0;

const int rs = 2, 
          en = 3, 
          d4 = 6, 
          d5 = 7, 
          d6 = 8, 
          d7 = 9;

LiquidCrystal lcd(rs, en, d4, d5, d6, d7);   //Set the LCD PINS

void setup() {
  
  lcd.begin(16, 2);      // Setup Interface
  lcd.setCursor(0, 0);
  lcd.print("IN: ");
  lcd.setCursor(0, 1);
  lcd.print("OUT: ");
  lcd.setCursor(8, 0);
  lcd.print("|");
  lcd.setCursor(8, 1);
  lcd.print("|");

  Serial.begin(9600);          // For Serial Monitor
  
  pinMode(OUTPUT, OUTPUT);

}

void loop() {

  SendBPM();
 
}

void SendBPM() {

  potVal = analogRead(potPin);
  int BPMOUT = (potVal/6.6) + 50;
  
  lcd.setCursor(0, 1);
  lcd.print("OUT: ");
  lcd.print(BPMOUT);
 
  float ms = 60000/BPMOUT/4;
  digitalWrite(OUTPUT, HIGH);
  delay(0.2*ms);
  digitalWrite(OUTPUT, LOW);
  delay(0.8*ms);

  lcd.setCursor(0, 1);
  lcd.print("OUT: ");
  lcd.print("   ");

}

Explain! What is the signal with NO spike? Are you sure it is a "spike" and not a pulse with square corners?

I tried to plug it to a analog plotter and it looked like a short spike.
No spike is a Low digital signal.
I could really be a short square corner pulse.
English is not my first language.
I'm a beginner in Arduino.

Hmm. Capture millis() on first spike, capture millis() on second spike, subtract 1st value from second value, answer is in... milliseconds.

1 Like

is there some other device actually measuring the heart rates that can be read as an analog voltages?

surprising challenging, assuming the pulse needs to be read from a pressure sensor

picked a threshold of 200, but have no idea what the range of values is

#include <LiquidCrystal.h>

const int rs = 2,
en = 3,
d4 = 6,
d5 = 7,
d6 = 8,
d7 = 9;

LiquidCrystal lcd(rs, en, d4, d5, d6, d7);   //Set the LCD PINS

const byte PinLed  = LED_BUILTIN;       // Capitalize constants
const byte PinAnlg = A5;
int        thresh  = 200;       // ????
int        armed;

unsigned long msecLed;
unsigned long msecLast;
unsigned long msec;

enum { Off = HIGH, On = LOW };

char s [90];

// -----------------------------------------------------------------------------
void sendBPM ()
{
    int potVal = analogRead (PinAnlg);

    // wait for level to drop to re-arm
    if (! armed)  {
        if (0.2 * thresh > potVal)
            armed = 1;
        return;
    }

    // wait for spike
    if (armed && 0.8 * thresh >= potVal)
        return;

    // capture max
    if (thresh < potVal)
        thresh = potVal;

    // compute bpm
    unsigned long dMsec = msec - msecLast;
    int           bpm   = 60 / (dMsec / 1000.0); 
    msecLast = msec;

    sprintf (s, " armed %d, thresh %6d, potVal %6d, dMsec %6lu, bpm %d",
                  armed, thresh, potVal, dMsec, bpm);
    Serial.println (s);

    // flash LED
    msecLed = msec;
    digitalWrite (PinLed, On);

    armed = 0;
}

// ---------------------------------------------------------
void loop()
{
    msec = millis ();

    // turn off LED
    if (0 < msecLed && msec - msecLed >= 100)  {
        digitalWrite (PinLed, Off);
    }

    sendBPM();
}

// ---------------------------------------------------------
void setup()
{
    lcd.begin(16, 2);      // Setup Interface
    lcd.setCursor(0, 0);
    lcd.print("IN: ");
    lcd.setCursor(0, 1);
    lcd.print("OUT: ");
    lcd.setCursor(8, 0);
    lcd.print("|");
    lcd.setCursor(8, 1);
    lcd.print("|");

    pinMode      (PinLed, OUTPUT);
    digitalWrite (PinLed, Off);

    Serial.begin(9600);          // For Serial Monitor
}

If I understand right you just need to get the frequency of a signal pulse in one arduino pin.
For that arduino has the " Input capture unit". It will do most of the work for you.

Arduino Input Capture Unit Interrupt Pin Tutorial & Examples
The ICU mode is typically used to get time stamps of a free running timer module at certain events on an external pin (ICPx). Which can be very useful for applications like frequency measurement.

You can also check this library and examples.

Sounds perfect. Share your attempt and describe how it does not work well, which is as good as not at all, but sounds like it is doing something.

Post your code using the <CODE/> button in the message composition window toolbar.

a7

which is further explained as

So I think we are dealing with a straight ahead digital signal.

@h3nr1_code what is the frequency range for the BPM sync signal? Do you have any idea how long the pulse ("spike") is? In milliseconds or other units of time?

Can you measure it, or find it in any documentation? Chances are it is plenty wide enough to be caught by polling.

It may be necessary for accuracy purposes to go to some extra trouble. You can get a crude version going first.

I suggest that whilst doing you just forget about the LCD and just print to the serial monitor. This will make it clearer and easier for those of us who might to build your project and test it.

a7

void loop() {

  if(digitalRead(INPUT) == HIGH){
    Serial.println("");
    Step ++;
  }

  if(Step == 2){
    Serial.println("-");
    float Time = millis();
    float Diff = Time-LastMS;
    LastMS = Time;
    int Tempo = 60000/Diff/2;
    Serial.println(Tempo);
    lcd.setCursor(4, 0);
    lcd.print(Tempo);
    lcd.print(" ");
    Step = 0;
    delay(10);
  }
  
 
}

This work.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.