PulseIn incorrect values on low frequency

Hi guys, I’ve been working on a project for a few weeks and here’s the basic rundown of it: I have a car’s velocity sensor in hand and whenever the sensor’s axis rotates it’ll send x amount of pulses through its signal output, where x depends on the sensor’s model. So I’ve attached it to a stepping motor and have build a circuit with arduino and a driver.

The arduino is sending pulse signals to the driver, rotating the motor at 4 different speeds (2, 4, 8 and 16Hz - or 120, 240, 480 and 960 RPM) and during each speed I’m reading the pulse signal with PulseIn, calculating the frequency and comparing to the motor’s frequency so I can find out how many pulses the sensor’s outputting during one revolution.

Everything’s working as it should, except when I swapped the driver for a more robust one when I get to the 8 and 16 Hz frequencies, the measurements from PulseIn stop matching what I’m reading with an osciloscope, and I don’t really know why. I’ve included the code below (sorry, the comments are in Portuguese) if any of you want to take a look.

I’ve also considered using interrupts, but I’m unfortunately already using pins 2 and 3 on my uno for the LCD display, as it was working properly with my previous driver. In any case, the frequency of the signal is getting to my pin correctly, it’s just that the PulseIn is somehow reading an incorrect value and I have no clue as to why.

Any help would be greatly appreciated <3

#include <LiquidCrystal.h>
int input = 12;
int freq_pin = 8;
float PPR = 20 * 200;
int start = 13;


// Definição das Rampas de Rotação

float ramp1 = PPR;
float ramp2 = PPR * 2;
float ramp3 = PPR * 4;
float ramp4 = PPR * 8;
float ramp5 = PPR * 16;

// Definição de Variáveis

unsigned long  high_time;
unsigned long  low_time;
float time_period;
float frequency;
LiquidCrystal lcd(7, 6, 5, 4, 3, 2);

void setup()
{

  // Inicia comunicação Serial e Limpa dados do Excell
  
  Serial.begin(9600);
  Serial.println("CLEARDATA");

  // Seta pinos do sistema e inicia o display LCD
  
  pinMode(input, INPUT);
  pinMode(freq_pin, OUTPUT);
  pinMode(start, INPUT);
  lcd.begin(16, 4);

  // Mensagem inicial no display LCD
  
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("MTE-THOMSON");
  lcd.setCursor(0, 2);
  lcd.print("Teste Sensor Vel");
  delay(1000);


}

void loop()
{

  // Loop principal, inicia dados caso a chave do sistema esteja em LIGADO
  
  if (digitalRead(start) == LOW) {

    // Inicia as tabelas no Excell
    
    Serial.println("CLEARDATA");
    Serial.println("LABEL,ROTAÇÃO(RPM),PULSOS POR REVOLUÇÃO");

    // Escreve a mensagem de display no LCD
    
    lcd.clear();
    lcd.setCursor(0, 0);
    lcd.print("Pulsos Por Rev");
    lcd.setCursor(0, 2);
    lcd.print("Velocidade");

    // Realiza primeira rampa na rotação do motor
    
    Rampa_Motor(ramp1, ramp2, 1);
    delay(500);

    // Chama a subrotina que realiza leitura do número de pulsos do sensor
    
    Leitura_Pulsos(ramp2, 1);
    delay(500);

    // Realiza a segunda rampa na rotação
    
    Rampa_Motor(ramp2, ramp3, 1);
    delay(500);

    // Chama a subrotina para realização da segunda leitura de pulsos
    
    Leitura_Pulsos(ramp3, 1);
    delay(500);

    // Realiza a terceira rampa na rotação

    Rampa_Motor(ramp3, ramp4, 1);
    delay(500);

    // Chama a subrotina para realização da terceira leitura de pulsos
    
    Leitura_Pulsos(ramp4, 1);
    delay(500);

    // Realiza a rampa de redução da rotação do motor para um novo ciclo de testes
    
    Rampa_Motor(ramp4, ramp5, 1);

    // Chama a subrotina para realização da terceira leitura de pulsos
    
    Leitura_Pulsos(ramp5, 1);
    delay(500);

    Rampa_Motor(ramp5, ramp1, 0);

  }

  // Caso o switch esteja desativado, o sinal de pulsos emitido para o motor é nulo

  else if (digitalRead(start) == HIGH) {
    noTone(freq_pin);
  }

}


// Subrotina de Leitura do número de pulsos do sensor

void Leitura_Pulsos(float rota, float fator) {

  // Definição de variáveis

  int pulso = 0;
  float contador = 0;
  float freq_Hz = rota / PPR;

  // Prints na Serial (para teste)

  Serial.print("Rotacao: ");
  Serial.println(rota);
  Serial.print("PPR: ");
  Serial.println(PPR);
  Serial.print("Freq Hz: ");
  Serial.println(freq_Hz);

  delay(200);

  // Loop de aquisição de pulsos

  for (int i = 0; i < 10; i++) {

    // A função pulseIn calcula o tempo que o sensor leva nas posições HIGH e LOW

    high_time = pulseIn(input, HIGH,2000000)*fator;
    delay(250);
    low_time = pulseIn(input, LOW,2000000)*fator;

    // Print na Serial (para testes)

    Serial.print("High Time: ");
    Serial.println(high_time);
    Serial.print("Low Time: ");
    Serial.println(low_time);

    // Caso os tempos em HIGH e LOW não sejam nulos (existe pulso), calculamos a frequência dos pulsos

    if (high_time && low_time != 0) {

      // Cálculo da frequência dos pulsos do sensor baseado nos tempos em HIGH e em LOW
      
      time_period = high_time + low_time;
      frequency = 1000000 / time_period;
      Serial.print("Frequency: ");
      Serial.println(frequency);
      pulso = pulso + frequency;
      contador = contador + 1;

    }

    // Caso os tempos em HIGH ou LOW sejam nulos (não há pulso ou há erro de leitura) saimos da subrotina e imprimimos mensagem de erro
    
    else if (high_time || low_time == 0) {
      lcd.setCursor(0, 1);
      lcd.print("Sem Leitura");
      Serial.println("SEM LEITURA,SEM LEITURA");
      return;
    }
  }

  // Cálculo do número de pulsos no sensor baseado na relação da frequência de seu sinal e na rotação do motor

  pulso = pulso / (freq_Hz * contador);

  // Display do número de pulsos e da rotação de testes do motor no display LCD

  lcd.setCursor(0, 1);
  lcd.print(pulso);
  lcd.print(" Pulsos");
  lcd.setCursor(0, 3);
  lcd.print(60 * freq_Hz);
  lcd.print(" RPM");

  // Prints em Serial (para testes)

  Serial.print("RPM: ");
  Serial.println(60 * freq_Hz);
  Serial.print("Pulsos: ");
  Serial.println(pulso);

  delay(500);
}

// Subrotina que realiza a rampa de aceleração do motor de passos

void Rampa_Motor(float freq_min, float freq_max, float sinal) {

  // Definição de variáveis

  float dfreq = ramp1 / 2;
  float dfreq_step = ramp1 / 2;
  float x_steps = abs(freq_max - freq_min) / dfreq_step;

  // Envio da frequência inicial

  tone(freq_pin, freq_min);

  // Caso o bit de sinal enviado seja 1, realizamos uma rampa de aceleração

  if (sinal == 1) {
    for (int i = 0; i < x_steps; i++) {
      tone(freq_pin, freq_min + dfreq);
      dfreq = dfreq + dfreq_step;
      delay(1);
    }

    Serial.print("Tone: ");
    Serial.println(freq_min + dfreq - dfreq_step);
  }

  // Caso o bit de sinal enviado seja 0, realizamos uma rampa de desaceleração

  else if (sinal == 0) {
    for (int i = 0; i < x_steps; i++) {
      tone(freq_pin, freq_min - dfreq);
      dfreq = dfreq + dfreq_step;
      delay(1);
    }

  }


}