Convert a PWM signal from an anemometer to a DC value

I have been reading about using PWM signals with arduino (MEGA in this case) but nothing seems to address my particular usage.
on my oscope i can see a nice square wave signal from the anemometer that is PWM depending on the wind speed. i input it to analog 13, and i get some average voltage value that is nowhere near the actual speed (i have a weather station that works that shows the true wind speed, i just tapped into the signal wire).
so to me that means i need to convert my PWM to a DC voltage value in order to do an analog read. so i bought a DAC from adafruit. but the more i read, the less i think that this is the solution.

i read threads where setting up a filter was proposed, but i hope i don't have to go that route.

can anyone suggest a simple way to utilize the PWM as an input signal ?

Why not read the PWM as a digital stream?

because i left my digital stream reader in texas.
seriously, could you expand on that a little ?

PWM is a digital signal, so, read it as a digital signal

ok. i'll give it a try. D37 here i come.

Are you sure the anemometer is generating a PWM signal, and not a series of pulses, with the number of pulses over a given time being proportional to the wind speed? (an example of that would be the anemometer generating one pulse per revolution, and you calculate wind speed as the number of revolutions per second).

pratto:
can anyone suggest a simple way to utilize the PWM as an input signal ?

not exactly a simple way of reading in a PWM signal but this is my take on it using interrupts.

the buffer i put in the code is optional really...

//PWM read using External Interrupts. Following code measures the time a PWM pulse is HIGH
#define INTR_2 2
#define MAX_SIZE 16 //"power of 2" buffer size is recommended to dramatically optimize all the modulo operations for ring buffers.

volatile uint32_t prev_time;
volatile uint8_t tail = 0;
uint32_t pwm_buf[MAX_SIZE];
uint8_t head = 0;

void rising() {
  attachInterrupt(digitalPinToInterrupt(INTR_2), falling, FALLING);
  prev_time = micros();
}

void falling() {
  attachInterrupt(digitalPinToInterrupt(INTR_2), rising, RISING);
  pwm_buf[tail] = micros() - prev_time;
  tail = (tail + 1) % MAX_SIZE;
}

void setup() {
  Serial.begin(115200);
  // when pin D2 goes LOW->HIGH, call the rising function
  attachInterrupt(digitalPinToInterrupt(INTR_2), rising, RISING);
}

void loop() {
  if (head != tail) {
    noInterrupts();
    uint32_t pwm_value = pwm_buf[head];
    interrupts();
    
    head = (head + 1) % MAX_SIZE;

    Serial.print("pulse width: ");
    Serial.print(pwm_value);
    Serial.println("us");
  }
}

hope that helps....

Do you have a data sheet for the sensor so that we can get a better idea what we are dealing with? My anemometer outputs an asynchronous serial data stream with the wind speed and direction infortion encoded

You said a square wave. Do you mean that or do you mean a PWM signal? They're not the same thing (except perhaps at 50% duty cycle).

It's just that the few anemometers I've seen output a variable frequency pulse wave not a fixed frequency variable duty cycle PWM signal (and often a linear voltage output too).

Steve

it is aggravating. i typed a detailed reply, then it got lost in trying to post it.

d37 did not work. same output as analog read.

i think you are right that what i thought was a PWM signal on my scope (as i changed the wind from my fan) was actually the number of pulses. as the speed goes down, so does the frequency shown on the oscope. but the trigger was the same and the pulses looked longer.

but even so, how do i tell the arduino to count pulses accurately ? i tried that before and it seems like it is checking so much faster that the signal frequency (4.3 Hz at 10 mph) that it samples the voids and screws up what is high.

Do a forum search on "anemometer", you will get the answers you need.

aarg - i did the search and came up with something that i almost understand and that almost works.

#include <math.h>

#define WindSensorPin (2) // The pin location of the anemometer sensor

volatile unsigned long Rotations; // cup rotation counter used in interrupt routine
volatile unsigned long ContactBounceTime; // Timer to avoid contact bounce in interrupt routine

float WindSpeed; // speed miles per hour

void setup() {
Serial.begin(9600);

pinMode(WindSensorPin, INPUT);
attachInterrupt(digitalPinToInterrupt(WindSensorPin), rotation, FALLING);
Serial.println("Davis Wind Speed Test");
Serial.println("Rotations\tMPH");
}

void loop() {

Rotations = 0; // Set Rotations count to 0 ready for calculations

sei(); // Enables interrupts
delay (3000); // Wait 3 seconds to average
cli(); // Disable interrupts


// convert to mp/h using the formula V=P(2.25/T)
// V = P(2.25/3) = P * 0.75

WindSpeed = Rotations * 0.75;

Serial.print(Rotations); Serial.print("\t\t");
Serial.println(WindSpeed);

}

// This is the function that the interrupt calls to increment the rotation count
void rotation () {

if ((millis() - ContactBounceTime) > 15 ) { // debounce the switch contact.
Rotations++;
ContactBounceTime = millis();
}

}

attached is an image of the serial print. it shows rotations of about 120. yet the oscope shows a frequency of 4.8 Hz. the true wind speed is 10 mph.

i think what it is telling me is if i have a freq of 4.5 Hz, and it pauses for 3 seconds to collect data. that should be 14.4 revolutions. and at .75*revolutions = 10.8 mph. i don't get where the 120 revs is coming from.

i think i found the problem. the yellow wire in the Davis Anemometer is called the 5v line, but i only measure 2.5v. when i jump 5v from the nano to the yellow wire, and put a 4.7k pullup resistor between the black wire (signal from anemometer) and 5v, i get the correct speed value (at least at 10 mph).

if I use INPUT_PULLUP I can dispense with the resistor, and both the wind & temp operate at 2.5v just fine.