Picked up one of these from aliexpress. In my infinite wisdom, i selected the pulse model (its digital, should be more accurate, how hard can it be to just count pulses?).
well, all the tutorials online are for the analog one where wind speed corresponds to a voltage. guess i should of checked for tutorials before i ordered it....
Anyway, it seems like i have it partially working, 5v goes in, ground goes in,, and a signal wire gives me 5v back and drops to 0v every time it turns. did a quick sample code job with pulseIn and it sometimes reads right, sometimes reads garbage, so presumable I need a pullup or pulldown resistor. grabbed a 4.7k resistor tried it both as a pullup and a pulldown on the signal wire, no luck though. either way, the resistor just zero's the readings out.
label on the sensor seems to match the manual for the pulse version.
pulled out my ladder and opened it up, looks like its just a hall sensor and already has a pull up resistor in it. issue must be in my code for the bad readings.
Here is how I measure the rotational speed of a pulse type anemometer (1 pulse per revolution), using simple input polling:
unsigned long start, revtime;
while (digitalRead(anem_input) == LOW); //wait for input to go high
start=millis(); //reset timer
while (digitalRead(anem_input) == HIGH); //wait for it to go low again
while (digitalRead(anem_input) == LOW); //wait for next high
revtime = millis()-start; //time for one revolution
Of course, the processor can't do anything else while it is polling the input, but that is all my particular setup needs to do, except to send data out the serial port once every minute.
While waits for the next pinchange, and could lock up your loop on a windless day.
Maybe better to record millis() when the pin changes, or has changed several times.
This page might help.
Yes, that does happen, but then you know that the wind velocity is zero (fine for my application).
It is easy enough to build a timeout into the while loop, for example:
unsigned long timeout=millis(); //start timeout timer
while (digitalRead(anem_input) == HIGH && (millis() - timeout < 3000UL) ); //wait for it to go low again, but not wait longer than 3 seconds
thanks to jremington's code I managed to get my sensor up and running. i then had an issue with the readings jumping around given it was only one pulse and needed some smoothing/averaging, so i then started counting the number of pulses in a given time, but the code was doing this on demand when it was served to a webpage query and was too slow. I also ran into what Wawa mentioned with windless days. I then moved over to figuring out interrupts, found out after much time that not all digital pins are equal, had some serious issues with loosing decimals, some issues with compiling errors (constants than needed to be unsigned longs) and finally have it working reasonable well now.
for future reference for anybody hopefully this helps. it is a cut and paste out of my weather station code and i haven't tested it on its own (it works great in my weather station)
thanks again for the help!
#define windspeed_PIN 3 //must be an interrupt pin
//predefine variables as global to accomidate interupt
float windspeedPulses = 0;
unsigned long windspeedLastTime = millis();
float windspeedInterval = 120000; //average reading over 120 seconds
float windspeedKPH = 0;
void windspeedInterrupt() {
windspeedPulses++;
if (millis() > (windspeedLastTime + windspeedInterval)) {
windspeedKPH = (windspeedPulses / ((millis() - windspeedLastTime) / 1000)) * 0.88 * 3.6;
windspeedPulses = 0;
windspeedLastTime = millis();
}
//Serial.println(F("Windspeed interrupt."));
}
void setup() {
Serial.begin(9600);
//setup windspeed/anemometer pin
pinMode(windspeed_PIN, INPUT);
attachInterrupt(digitalPinToInterrupt(windspeed_PIN), windspeedInterrupt, RISING);
}
void loop() {
//periocially check if windspeed interrupt hasnt been called incase wind speed is 0
//don't call too often or this will skew low wind speeds
if (millis() > (windspeedLastTime + (180UL * 1000))) {
//if not signifiant number of pulses, zero out, else, force an interrupt
if (windspeedPulses < 12) {
windspeedPulses = 0;
windspeedLastTime = millis();
windspeedKPH = 0;
}
else {
windspeedInterrupt();
}
}
Serial.print(F("Windspeed: ")); Serial.print(windspeedKPH); Serial.println(F(" kph"));
delay(1000);
}
(1) variables used in both interrupt routines and elsewhere must be declared "volatile". Otherwise the compiler may optimize your code and it will mysteriously stop working
(2) never print within an interrupt (now commented out), as printing depends on interrupts and they are turned off in an interrupt routine.
(3) It is not a good idea to call windspeedInterrupt from the main loop. This can lock up your program if a genuine interrupt occurs. The interrupt should simply set a flag variable that it has been called (again declared volatile) which the main loop can check and reset.
#define windspeed_PIN 3 //must be an interrupt pin
//predefine variables as global to accomidate interupt
//variable used outside windspeedInterrupt function must be volatile
//https://www.arduino.cc/en/reference/volatile
volatile float windspeedPulses = 0;
volatile unsigned long windspeedLastTime = millis();
volatile float windspeedKPH = 0;
volatile float windspeedInterval = 120000; //average reading over 120 seconds
void windspeedInterrupt() {
windspeedPulses++;
if (millis() > (windspeedLastTime + windspeedInterval)) {
windspeedKPH = (windspeedPulses / ((millis() - windspeedLastTime) / 1000)) * 0.88 * 3.6;
windspeedPulses = 0;
windspeedLastTime = millis();
}
}
void setup() {
Serial.begin(9600);
//setup windspeed/anemometer pin
pinMode(windspeed_PIN, INPUT);
//https://www.arduino.cc/en/Reference/AttachInterrupt
attachInterrupt(digitalPinToInterrupt(windspeed_PIN), windspeedInterrupt, RISING);
}
void loop() {
//periocially check if windspeed interrupt hasnt been called incase wind speed is 0
//don't call too often or this will skew low wind speeds, using 150% of interval
if (millis() > (windspeedLastTime + (windspeedInterval * 1.5 * 1000))) {
//if there hasn't been a signifiant number of pulses, zero out windspeed variable and reset
if (windspeedPulses < 12) {
windspeedKPH = 0;
windspeedPulses = 0;
windspeedLastTime = millis();
}
//else there has been enough pulses to be significant, therefore calculate a new speed and reset
else {
windspeedKPH = (windspeedPulses / ((millis() - windspeedLastTime) / 1000)) * 0.88 * 3.6;
windspeedPulses = 0;
windspeedLastTime = millis();
}
}
//For debugging, windspeedPulses should increase if wired correctly and interrupt is being called
//do not call serial.print from within interrupt loop
//Serial.print(F("windspeedPulses: ")); Serial.println(windspeedPulses);
//display windpseed
Serial.print(F("Windspeed: ")); Serial.print(windspeedKPH); Serial.println(F(" kph"));
delay(1000);
}