Incrementing When Hall Effect Sensor Crosses Threshold (Solved)

I feel like I am somehow overcomplicating this, but I am making a fairly basic weather station and am using an analog Hall Effect sensor (Specifically the DRV5056-Q1, as it is what I currently have) to make an anemometer, and I want it to trigger only once when the value detected is over 350 (RP2040 board, but it appears to be reading in 10 bit?) and not be able to be triggered until 20ms after it is turned off, so able to detect ~50mph max, which the 3D printed parts probably will fail before sensor. I have tried a few different methods, and even tried asking ChatGPT for help but nothing works, the best I have got is either it triggers every 20ms while above the threshold, or triggering a few times once it is past, and a then again after it is below the threshold. Can someone help me with this? Thanks!

Here is my code (sorry for not commenting it, HE means Hall Effect and everything else should be somewhat legible.):

#include <SPI.h>
#include <RH_ASK.h>
#include <DHT.h>
#include <DHT_U.h>
#include <OneWire.h>
#include <DallasTemperature.h>


#define POWER_LED 0
#define TEMP_PIN 1
#define DHT11_PIN 2
#define TX_PIN 3
#define TX_EN_PIN 4

unsigned long int blinkTimer = millis();
unsigned long int readTimer = millis();
unsigned long int transmitTimer = millis();
unsigned long int HEtimer = millis();

OneWire oneWirePin(TEMP_PIN);
DallasTemperature tempSense(&oneWirePin);

RH_ASK transmitter(2000, -1, 3, 4, false);

DHT DHT_SENSE(DHT11_PIN, DHT11);

int count;
float sumTemp;
float sumRH;
int sumLA;
int HEcount; // Marking related things with a comment
float avgTemp;
float avgRH;
int avgLA;

bool HEBool = false;

char msg[27];

void setup() {
  pinMode(POWER_LED, OUTPUT);
  
  tempSense.begin();
  tempSense.setResolution(12);

  DHT_SENSE.begin();

  transmitter.init();

  Serial.begin(115200);
}

void loop() {
  if (analogRead(28) >= 400 && !HEBool && HEtimer >= 20) { //
    HEcount++; //
    HEBool = true; //
  } else { // 
    HEBool = false; //
    HEtimer = millis(); //
  } //

  if (millis() - readTimer >= 5000) {
    tempSense.requestTemperatures();

    count++;

    sumTemp += tempSense.getTempCByIndex(0);
    sumRH += DHT_SENSE.readHumidity(0);
    sumLA += map(analogRead(29), 0, 1023, 0, 100);

    readTimer = millis();
  }

  if (millis() - transmitTimer >= 60000) {
    avgTemp = sumTemp / (float)count;
    avgRH = sumRH / (float)count;
    avgLA = sumLA / (float)count;
  
    char tempStr[6], rhStr[6];
    dtostrf(avgTemp, 4, 2, tempStr);
    dtostrf(avgRH, 4, 2, rhStr);
    char laStr[6], heStr[6];
    itoa(avgLA, laStr, 10);
    itoa(HEcount, heStr, 10); //

    snprintf(msg, sizeof(msg), "T%sH%sL%sW%s", tempStr, rhStr, laStr, heStr);

    size_t len = strlen(msg);

    if (len < 27) {
      for (size_t i = len; i < 27; i++) {
        msg[i] = ' ';
      }
    }

    Serial.println(msg);

    transmitter.send((uint8_t *)msg, 27);
    transmitter.waitPacketSent();

    count = 0;
    sumTemp = 0;
    sumRH = 0;
    sumLA = 0;
    HEcount = 0; //
    transmitTimer = millis();
  }

  if (millis() - blinkTimer >= 1000) {
    blinkTimer = millis();
    digitalWrite(POWER_LED, !digitalRead(POWER_LED));
    Serial.println(HEcount); // Debugging purposes
    Serial.println(analogRead(28)); // Debugging purposes
  }
}

Other parts I am using:
Knockoff WaveShare RP2040 Zero
DHT11 Module
Dallas 18B20
Photoresistor (cloud cover)
433Mhz ASK transmitter
Power LED

Reading the sensor digitally, not analog fixed it, thanks! I am pretty sure an interrupt would work just fine too but this was simpler.

Consider using a digital input pin. I know the Hall sensor is linear but assuming there is only one magnet in a revolution, when the Hall reaches the magnet the output will rise quickly. This will trigger a digital pin. You could even use an interrupt.

takes 750 milliseconds to finish.

this

will need some time too.

Measuring a frequency - this is what you are basically doing is best done with an interrupt or with hardware counters

As you are using a RP2040 which has quite a lot of internal hardware that can be used in various ways you should search on github for a interrupt driven frequency measuring library that is written especially for the RP2040

My experience with AI is:

you have to define very detailed what you want to have. To be able to define the requirements detailed enough to get working code requires profound knowledge about the microcontroller and pretty profound knowledge how to describe it precisely.

This is what GPT came up with

#include "Arduino.h"
#include "hardware/pio.h"
#include "hardware/clocks.h"
#include "pico/stdlib.h"

// PIO assembly program to count pulses
static const uint16_t pulse_counter_program[] = {
    0x2020, // wait 1 pin, 0  (Wait for rising edge)
    0x20a0, // wait 0 pin, 0  (Wait for falling edge)
    0x4800, // in pins, 1     (Shift in a '1' for counting)
    0x0000  // jmp 0          (Loop back)
};

#define INPUT_PIN 15  // Change as needed
#define PIO_INSTANCE pio0
#define STATE_MACHINE 0

PIO pio = PIO_INSTANCE;
uint sm = STATE_MACHINE;

void setup() {
    Serial.begin(115200);
    while (!Serial);

    // Load PIO program
    uint offset = pio_add_program(pio, (const pio_program_t){
        .instructions = pulse_counter_program,
        .length = sizeof(pulse_counter_program) / sizeof(pulse_counter_program[0]),
        .origin = -1
    });

    // Configure state machine
    pio_sm_config c = pio_get_default_sm_config();
    sm_config_set_wrap(&c, offset, offset + 3);
    sm_config_set_clkdiv(&c, 1.0f);
    sm_config_set_in_pins(&c, INPUT_PIN);
    pio_gpio_init(pio, INPUT_PIN);
    pio_sm_set_consecutive_pindirs(pio, sm, INPUT_PIN, 1, false);
    pio_sm_init(pio, sm, offset, &c);
    pio_sm_set_enabled(pio, sm, true);
}

uint32_t measure_frequency(float duration = 1.0) {
    pio_sm_clear_fifos(pio, sm);
    delay(duration * 1000);
    return pio_sm_get(pio, sm) / duration;
}

void loop() {
    uint32_t freq = measure_frequency();
    Serial.printf("Frequency: %lu Hz\n", freq);
    delay(1000);
}

before asking gpt I googled for ready to use libraries for RP2040 but did not really find something useful. I am astonished. I would have expected to find at least half a dozen of libraries that do frequency measuring on a RP2040

deepseek came up with this code

#include <Arduino.h>
#include <pico/stdlib.h>
#include <hardware/pio.h>

// PIO program to count rising edges
static const uint16_t freq_counter_program_instructions[] = {
    0x20A0, //  0: wait   1 pin, 0         ; Wait for rising edge on GPIO0
    0xA046, //  1: mov    x, x + 1         ; Increment X register
    0x0000  //  2: jmp    0                ; Loop back to start
};

static const struct pio_program freq_counter_program = {
    .instructions = freq_counter_program_instructions,
    .length = 3,
    .origin = -1,
};

PIO pio = pio0;
uint sm = 0;
uint offset = 0;

void setup() {
    Serial.begin(115200);
    while (!Serial); // Wait for serial connection

    // Load PIO program
    offset = pio_add_program(pio, &freq_counter_program);
    
    // Configure state machine
    sm = pio_claim_unused_sm(pio, true);
    pio_sm_config cfg = pio_get_default_sm_config();
    
    sm_config_set_wrap(&cfg, offset, offset + 2);
    sm_config_set_in_pins(&cfg, 0); // Use GPIO0 as input
    sm_config_set_in_shift(&cfg, false, false, 0); // No shifting
    sm_config_set_fifo_join(&cfg, PIO_FIFO_JOIN_NONE);
    
    pio_sm_init(pio, sm, offset, &cfg);
    pio_sm_set_enabled(pio, sm, true);
}

void loop() {
    static uint32_t last_count = 0;
    static uint32_t last_micros = 0;
    
    // Read current state
    uint32_t current_count = pio_sm_get(pio, sm);
    uint32_t current_micros = micros();
    
    // Calculate elapsed time and counts
    uint32_t elapsed = current_micros - last_micros;
    uint32_t counts = current_count - last_count;
    
    if (elapsed > 0) {
        float frequency = (counts * 1000000.0f) / elapsed;
        Serial.print(frequency);
        Serial.println(" Hz");
    }
    
    // Update previous values
    last_count = current_count;
    last_micros = current_micros;
    
    delay(100); // Measurement window
}

no idea if this interferes the various other libraries that you are using.

A classical approach would be to setup a interrupt that increments a variables on each rising edge of the IO-pin.
For using this you should use a small circuitry called schmidt-trigger with hysteresis to obtain a clear digital signal from your analog hall-effect sensor. Though it might be easier to change to a digital hallsensor

finally found a RP2040 frequency measuring library on github

Seems to be an odd approach but seems to work

Not the right choice for an anemometer. It's an analog hall sensor, a digital hall sensor would be appropriate for an anemometer. As mentioned, one with some hysteresis (like a Schmitt Trigger logic input has) would be even better, because then you don't have to worry about the 20ms thing.

You might use analog hall effect sensors in a wind direction vane, possibly 2 in fact. But I would probably look at a magnetometer for that.

But since you are using an analog hall sensor, it would probably be easier to implement some hysteresis in your code than to implement those 20ms timings. All you need to do is have 2 thresholds instead of 1. One threshold at 350 for the rising signal, the other at maybe 300 or 250 for the falling signal.

This isn't going to work because HTtimer will always be greater than 20:

  if (analogRead(28) >= 400 && !HEBool && HEtimer >= 20) { //
    HEcount++; //
    HEBool = true; //
  } else { // 
    HEBool = false; //
    HEtimer = millis(); //
  } //

Maybe what you meant to write was:

  if (analogRead(28) >= 400 && !HEBool && millis() - HEtimer >= 20) { //
    HEcount++; //
    HEBool = true; //
  } else { // 
    HEBool = false; //
    HEtimer = millis(); //
  } //

But to me this seems much easier:

  int HEread = analogRead(HEpin);
  if (HEread >= 400 && !HEhigh) {
    HEcount++;
    HEhigh = true;
  } else if (HEread < 250 && HEhigh) {
    HEhigh = false;
  }

Yes, I meant to send that, I copied this from a previous version of the code as the current one is messed up even more. The code you sent appears to be like something I have tried before, and writing out the logic makes sense but actually using it gives wildly inaccurate numbers, I think I am going to try using interrupts for this. Thank you for trying to help!

No, you must have done something wrong. Do you have a 'scope?