Weather Shield past topics do not answer the questions

I have done a lot of searching and found several topics started but never answered.

I am using the github code for the sparkfun weather shield. The wind gust is not working right. anything above about 18mph it will send the gust through the roof. 800, 1500. Before somebody says to put the delay from 10 to something higher in the interrupt I already have moved it up to 100. That is not the problem. If the wind is low the gust works right. And no I can not hook up the serial to monitor parts of it due to it be mounted on the roof.

I have proposed this several times when it comes to interrupts and timing.
Instead of counting interrupts over a “fixed” period of time, measuring the microseconds (or system ticks) between triggers (or - for higher speeds - a dedicated number of triggers) would be an alternative route to investigate - I tend to get better results with it and have less impact on the rest of the code.
Which way to go should be an informed decission.

BTW, adding delays of any kind in an ISR has to be done very cautiously and not by just driven by a whim :wink:
Is it absolutely needed for the ISR to work? If not, don’t do it.

2 Likes

I use a custom board but anemometers generally work the same, though your constants may vary.

I use an external pull-up, 4.7K, to 5V. The anemometer signal connects between GND and the GPIO pin. The reason for the external pull-up is to give a stronger pull, and also adds the ability to make it swing 5V instead of 3.3V, which make the signal more noise tolerant.

In setup I attach the interrupt:

attachInterrupt(ANEMOMETER_PIN, anemometerInterrupt, FALLING);

The interrupt is handled like this:

void anemometerInterrupt() {
	if (millis() - lastAnemometerTime >= DEBOUNCE_TIME_MS) {
		lastAnemometerTime = millis();
		anemometerCount++;
	}
}

As ScruffR pointed out, sticking a delay in the ISR is not the correct solution. Instead, you should measure the time of the last pulse use that to debounce the signal. In my case, DEBOUNCE_TIME_MS, is 10.

In loop, I aggregate the wind clicks every second:

	if (millis() - lastAnemometerAggregationTime >= 1000) {
		lastAnemometerAggregationTime = millis();

		// Process anemometer data once per second
		// Anemometer (D5)
		// One contact closure (falling) = 1.492 MPH (2.4 kh/h) of wind speed
		//Log.info("anemometerCount=%d vaneRaw=%.1f", anemometerCount, 22.5 * (float)adcToDirectionIndex(analogRead(VANE_PIN)));

		if (anemometerCount > 0) {
			float speed = 1.492 * (float) anemometerCount;
			anemometerCount = 0;

			if (speed > windGust) {
				windGust = speed;
			}
			windSum += speed;
			windCount++;
		}

	}

Then I send the 1 second aggregated samples up every 6 seconds:

	if (millis() - lastWeatherPublishTime >= PUBLISH_TIME_MS) {
		lastWeatherPublishTime = millis();

		char buf[128];

		if (windCount > 0) {
			snprintf(buf, sizeof(buf), "{\"weatherWind\":%.1f,\"weatherGust\":%.1f}",
					(windSum / (float)windCount), windGust);
			localEventQueue.publish("environment", buf);

			windGust = 0.0;
			windSum = 0.0;
			windCount = 0;
			windWasNonZero = true;
		}
		else
		if (windWasNonZero && windCount == 0) {
			// Was non-zero, but now it's zero
			snprintf(buf, sizeof(buf), "{\"weatherWind\":%.1f,\"weatherGust\":%.1f}",
					0.0, 0.0);
			localEventQueue.publish("environment", buf);
			windWasNonZero = false;
		}
1 Like

My interrupt is just like yours. except I changed it to 100 instead of 10. The process looks similar just done differently.

Now for the past few days its been almost calm here. No wind or wind gust above about 12mph. Guess I just have to keep waiting.

Interrupt.

void wspeedIRQ()
// Activated by the magnet in the anemometer (2 ticks per rotation), attached to input D3
{
  if (millis() - lastWindIRQ > 100) // Ignore switch-bounce glitches less than 10ms (142MPH max reading) after the reed switch closes
  {
    lastWindIRQ = millis(); //Grab the current time
    windClicks++; //There is 1.492MPH for each click per second.
  }
}

Main loop.
void loop()
{
  //Keep track of which minute it is
  if(millis() - lastSecond >= 1000)
  {

    lastSecond += 1000;

    //Take a speed and direction reading every second for 2 minute average
    if(++seconds_2m > 119) seconds_2m = 0;

    //Calc the wind speed and direction every second for 120 second to get 2 minute average
    //float currentSpeed = get_wind_speed();
    currentSpeed = get_wind_speed();
    //float currentSpeed = random(5); //For testing
    int currentDirection = get_wind_direction();
    windspdavg[seconds_2m] = (int)currentSpeed;
    winddiravg[seconds_2m] = currentDirection;
    //if(seconds_2m % 10 == 0) displayArrays(); //For testing

    //Check to see if this is a gust for the minute
    if(currentSpeed > windgust_10m[minutes_10m])
    {
      windgust_10m[minutes_10m] = currentSpeed;
      windgustdirection_10m[minutes_10m] = currentDirection;
    }

    //Check to see if this is a gust for the day
    if(currentSpeed > windgustmph)
    {
      windgustmph = currentSpeed;
      windgustdir = currentDirection;
    }

    if(++seconds > 59)
    {
      seconds = 0;

      if(++minutes > 59) minutes = 0;
      if(++minutes_10m > 9) minutes_10m = 0;

      rainHour[minutes] = 0; //Zero out this minute's rainfall amount
      windgust_10m[minutes_10m] = 0; //Zero out this minute's gust
    }
--- Rest of this just my other code.

//Returns the instataneous wind speed
float get_wind_speed()
{
  float deltaTime = millis() - lastWindCheck; //750ms

  deltaTime /= 1000.0; //Covert to seconds

  float windSpeed = (float)windClicks / deltaTime; //3 / 0.750s = 4

  windClicks = 0; //Reset and start watching for new wind
  lastWindCheck = millis();

  windSpeed *= 1.492; //4 * 1.492 = 5.968MPH

  /* Serial.println();
   Serial.print("Windspeed:");
   Serial.println(windSpeed);*/

  return(windSpeed);
}