Davis anemometer and Electron

Hi,

I’m using this code in my arduino board and is working perfet. Now I want to use it in my Electron and I have some problems.

Could you help to me what I have to modify to work with my Electron?

The Library TimerOne did not exist in Electron

Many many thank’s

#include "TimerOne.h"          // Timer Interrupt set to 2 second for read sensors
#include <math.h>

#define WindSensorPin (2)      // The pin location of the anemometer sensor
#define WindVanePin (A4)       // The pin the wind vane sensor is connected to
#define VaneOffset 0;        // define the anemometer offset from magnetic north
double x = 0;
double y = 0;
int VaneValue;       // raw analog value from wind vane
int Direction;       // translated 0 - 360 direction
int CalDirection;    // converted value with offset applied
int LastValue;

volatile bool IsSampleRequired;       // this is set true every 2.5s. Get wind speed
volatile unsigned int  TimerCount;    // used to determine 2.5sec timer count
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() {

  LastValue = 0;
  
  IsSampleRequired = false;
  
  TimerCount = 0;
  Rotations = 0;   // Set Rotations to 0 ready for calculations
  
  Serial.begin(9600);

  pinMode(WindSensorPin, INPUT);
  attachInterrupt(digitalPinToInterrupt(WindSensorPin), isr_rotation, FALLING);

  Serial.println("Davis Anemometer Test");
  Serial.println("Speed (MPH)\tKnots\tDirection\tStrength");

  // Setup the timer intterupt
  Timer1.initialize(500000);
  Timer1.attachInterrupt(isr_timer);
}

void loop() {
  
  getWindDirection();

  // Only update the display if change greater than 5 degrees. 
  if(abs(CalDirection - LastValue) > 5)
  { 
     LastValue = CalDirection;
  }

  if(IsSampleRequired)
  {

    
     // convert to mp/h using the formula V=P(2.25/T)
     // V = P(2.25/2.5) = P * 0.9
     WindSpeed = (Rotations * 0.9)*1.61;
     Rotations = 0;   // Reset count for next sample
     
     IsSampleRequired = false; 
     
     Serial.print(WindSpeed);    Serial.print("\t\t");
     Serial.print(getKnots(WindSpeed));    Serial.print("\t"); 
     Serial.print(CalDirection); 
     getHeading(CalDirection);   Serial.print("\t\t"); 
     getWindStrength(WindSpeed);
     x = WindSpeed;
     if (x >= y) {
     y = x;
     } else {
     y = y;
     }
  }

}

// isr routine fr timer interrupt
void isr_timer() {
  
  TimerCount++;
  
  if(TimerCount == 5)
  {
    IsSampleRequired = true;
    TimerCount = 0;
  }
}

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

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

}

// Convert MPH to Knots
float getKnots(float speed) {
   return speed * 0.539957;
}

// Get Wind Direction
void getWindDirection() {
 
   VaneValue = analogRead(WindVanePin);
   Direction = map(VaneValue, 0, 1023, 0, 360);
   CalDirection = Direction + VaneOffset;
   
   if(CalDirection > 360)
     CalDirection = CalDirection - 360;
     
   if(CalDirection < 0)
     CalDirection = CalDirection + 360;
  
}

// Converts compass direction to heading
void getHeading(int direction) {
    
    if(direction < 22)
      Serial.print(" N");
    else if (direction < 67)
      Serial.print(" NE");
    else if (direction < 112)
      Serial.print(" E");
    else if (direction < 157)
      Serial.print(" SE");
    else if (direction < 212)
      Serial.print(" S");
    else if (direction < 247)
      Serial.print(" SW");
    else if (direction < 292)
      Serial.print(" W");
    else if (direction < 337)
      Serial.print(" NW");
    else
      Serial.print(" N");  
}

// converts wind speed to wind strength
void getWindStrength(float speed)
{
   
  if(speed < 2)
    Serial.println("Calm");
  else if(speed >= 2 && speed < 4)
    Serial.println("Light Air");
  else if(speed >= 4 && speed < 8)
    Serial.println("Light Breeze");
  else if(speed >= 8 && speed < 13)
    Serial.println("Gentle Breeze");
  else if(speed >= 13 && speed < 18)
    Serial.println("Moderate Breeze");
  else if(speed >= 18 && speed < 25)
    Serial.println("Fresh Breeze");
  else if(speed >= 25 && speed < 31)
    Serial.println("Strong Breeze");
  else if(speed >= 31 && speed < 39)
    Serial.println("Near Gale");
  else
    Serial.println("RUN");
}

Can you be more specific?

@ecabanas, TimerOne is being used as a simple 500ms (500,000us) timer. You can replace the TimerOne library and code with a Software Timer set to a 500ms interval with the callback being isr_timer(). Very straight forward. :wink:

3 Likes

Hi @ScruffR

sorry, but If I try to compile the arduino code I receive an answer like this.

I’m triying to find TimerOne in Particle’s Library but i did not find it

Thank’s for your help

Eduard

As @peekay123 said, Particle provides a replacement for that without the need to import any library.

1 Like

Hi @peekay123

Thank’s for your help, I solved the Arduino Timer

Timer.initialize(500000);
Timer1.attachInterrupt(isr_timer);

with this Electron one, I hope I did it well

Timer timer(500000, isr_timer);

I also change this Arduino code, but I’m not really sure if it’s correct

attachInterrupt(digitalPinToInterrupt(WindSensorPin), isr_rotation, FALLING);

To this one:
attachInterrupt(WindSensorPin, isr_rotation, FALLING);

Thank’s to every one

Eduard

@ecabanas, the Arduino Timer is in microseconds whereas the Particle timer is in milliseconds so you should use:

Timer timer(500, isr_timer);

:wink:

Upssss thank’s
and
the arduino function

attachInterrupt(digitalPinToInterrupt(WindSensorPin), isr_rotation, FALLING);

Is correct in Electron mode?To this one: is not neccessary to use digitalPintoInterrupt???
attachInterrupt(WindSensorPin, isr_rotation, FALLING);

thank’s again!!!

Correct, you only need to state the pin, but you need to check whether your used pin as interrupt source.
On the Particle devices it’s also prefered to use the pin names as printed on the device D2 instead of just 2.
https://docs.particle.io/reference/firmware/electron/#attachinterrupt-

Unfortunately there is no explicit list of “available” pins for the Electron, so D2 might pose a problem.
It shares its EXTI line with A0, A3 and maybe MODE (I couldn’t find any info in the docs - have to look in the sources) and since MODE already uses an interrupt you can’t reuse the same line.
So if you experience problems with the interrupt try a different pin for the interrupt.

Hi @ScruffR

Yes, the pin has been defined as you comment in D2

Have you seen my edit above?

Also I’d use INPUT_PULLUP as pinMode() when triggering for FALLING edge.

Hi @ScruffR

I just edit my script and modified the pinmode:

  pinMode(WindSensorPin, INPUT_PULLUP);
  attachInterrupt(WindSensorPin, isr_rotation, FALLING);

  Serial.println("Davis Anemometer Test");
  Serial.println("Speed (MPH)\tKnots\tDirection\tStrength");

is it correct, no?

Looks fine to me. Does anything not work that way?

Just about your map() function.

   Direction = map(VaneValue, 0, 1023, 0, 360);

The Particle devices sport a 12bit ADC so you’d map the raw readings of 0…4095 to your actual value.
And the allowed voltage range is 0…3.3V not 5V - take care.

1 Like

mmm upsss right, I’m gonna check the voltage in raw mode and see what are the readings and later map them

Thank’s @ScruffR

Hi :slight_smile:

I use the following code to handle the interrupts:

interrupts();
delay (3000); // Wait 3 seconds to average
noInterrupts();

The original arduino code is:

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

sei() and cli() doesn’t seem to exist in the particle IDE.

So will the result be the same?

When using #include "Arduino.h" sei() and cli() should be available but both ways should work alike.

Just one thing to be careful about. While an Arduino doesn’t do a lot else than running your code, Particle devices do other stuff while not occupied with your code (e.g. cloud house keeping) which might get affected by disabling interrupts for prolonged periods.
If you are not using SYSTEM_THREAD(ENABLED) delay() does (try to) attend to the cloud every second (unless you prevent it by disabling interrupts) and with multi threading disabling interrupts might have even more impact.

So should I use

attachInterrupt(digitalPinToInterrupt(WindSensorPin), isr_rotation, FALLING);

or

attachInterrupt(WindSensorPin, isr_rotation, FALLING);

with Arduino.h?

So should I add SYSTEM_THREAD(ENABLED)?

@ScruffR

When writing code purely for Particle devices, I’d stick with the “native” syntax.
But if you want to write portable code you can use the Arduino way of writing it. On Particle devices (with more recent system versions) digitalPinToInterrupt is defined like this (or similar)

#define digitalPinToInterrupt(_pin)  _pin

So it just uses the _pin parameter as is, while on Arduinos the pins need to be mapped to some other number, due to a more limited numer of available interrupts.

As for SYSTEM_THREAD(ENABLED) this only exitst for Particle devices, so that won’t port to Arduinos, but for the Electron I’d use it.

Hi :slight_smile:

If I use sei(); and cli(); instead of interrupts(); and noInterrupts(); my Electron behaves strangely… It connects to to the cloud (breathing blue) but since I upload the code I’m unable to flash a new code (over OTA). So I can only flash the code over USB. Also the code isn’t running. Any ideas?

as mentioned before

1 Like