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

// 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);

// 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 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;

}

// 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);
}

}

}
``````