Arduino Pro and Anemometer (Reading Pulse Times)

I am using a Wind Vaned Anemometer to find the wind speed and direction. The system uses two sets of reed switches (one used for speed and one used for direction).

I am trying to print out the data to the serial monitor to confirm the data I am reading in, but am receiving nothing.

Can someone offer my some advice? I checked my syntax and I'm not sure if it is the way that it is being written or if it has to do with my timing.

When I hook up my system to the oscilloscope this is the reading that I get.

What I'm trying to do is calculate the time difference between the yellow pulses to figure out my RPM. And use the Time difference between the yellow and blue pulses to calculate phase shift to give me direction.

I referenced this other thread to give me what I have now: http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1265052228

//////////////////////////////////////////////////////////
// Declaration of Variables //
//////////////////////////////////////////////////////////

int analogSpeed = 0; //Speed bus connected to analog pin 0
int analogDirection = 1; //Direction bus connected to analog pin 1
unsigned long Speedvalue = 0;
unsigned long Directionvalue = 0;

// Variables for time
unsigned long SpeedDuration;
unsigned long DirectionDuration;
unsigned long SpeedTimePrevious;
unsigned long DirectionTimePrevious;
unsigned long DirectionTimePrevious1;
unsigned long DirectionTimePeriod;
unsigned long TimeDifference;
unsigned long Frequency;

// Variables for counting
volatile byte count;

void setup()
{
pinMode (analogSpeed, INPUT);
pinMode (analogDirection, INPUT);
Serial.begin(9600); // Setup serial with baud rate
attachInterrupt(0, arduino_anemometer, RISING);
count = 0;
SpeedDuration = 0;
DirectionDuration = 0;
SpeedTimePrevious = 0;
DirectionTimePrevious = 0;
DirectionTimePrevious1 = 0;

TimeDifference = 0;
}

void loop()
{
///////////////////////////////////////////////////////////////////////////////////////////
// It takes about 100 microseconds to read an analog input //
// Max reading rate is 10,000 times a second //
/////////////////////////////////////////////////////////////////////////////////////////

//Do I want digital or analog read??

Speedvalue = analogRead(analogSpeed); // Read the input pin at 0
Directionvalue = analogRead(analogDirection); // Read the input pin at 1

if (count >= 1)
{
//Calculating Speed Duration
SpeedDuration = (millis() - SpeedTimePrevious);
SpeedTimePrevious = millis();

if (SpeedTimePrevious > DirectionTimePrevious)
{
DirectionDuration = (millis() - DirectionTimePrevious);
DirectionTimePrevious = millis();
DirectionTimePeriod = (DirectionTimePrevious - DirectionTimePrevious1);
}

// Calculates Frequency between DIRECTION signals
DirectionTimePrevious1 = DirectionTimePrevious;
Frequency = 1/DirectionTimePeriod;

// Calculates time difference between SPEED and DIRECTION signals
if (DirectionTimePrevious != 0 ) // Ensures that Direction must occur second
{
TimeDifference = (SpeedTimePrevious - DirectionTimePrevious);
}

count = 0;

//////////////////////////////////
// VALUES //
/////////////////////////////////
Speedvalue = (1492/SpeedDuration); // Finds speed of cup rotation in
Directionvalue = 360FrequencyTimeDifference; //Finds Angle of Wind Vein

/////////////////////////////////////////////////////////////////////////////
// Printing SPEED, DIRECTION, TIME //
/////////////////////////////////////////////////////////////////////////////
Serial.print("Speed: ");
Serial.println(Speedvalue, DEC);
//delay(1000);
Serial.print("Direction: ");
Serial.println(Directionvalue, DEC);
//delay(1000);
Serial.print("Time: ");
Serial.println(millis());
//delay(1000);

}

}

void arduino_anemometer()
{
count++;
}

I am trying to print out the data to the serial monitor to confirm the data I am reading in, but am receiving nothing.

You are only printing a value when count is greater than 0. The count variable only gets incremented in the interrupt function. That you get nothing in the serial monitor implies that the interrupt handler is not being called, which implies that the Arduino is not receiving any signal on digital pin 2. What is connected to that pin?

from your code:

//Do I want digital or analog read??

As I see the pulses in the scope I would go for a digital read as it seems a nice square wave.

What is the voltage measured? You might need to boost it to get a decent level.

You are only printing a value when count is greater than 0.

I took my printing out of the IF statement for now, but I may want to put it back there once I get the reading for the interrupt correct.

which implies that the Arduino is not receiving any signal on digital pin 2. What is connected to that pin?

You are right, I didn't connect anything to Digital Pin 2. I misread the how the interrupt function worked. I put my two inputs into Analog 0 and Analog 1.

I wanted to be able to tell when my analog signal rises so I can find the difference in time from when the signals rise relative to one another, and use that time to calculate speed and direction using RPM's and Phase Shift.

Since my signals are close to squares, could I send them through the digital pins (2,3). How would I handle the interrupt if now I have two different signals that I will need to compare?

As I see the pulses in the scope I would go for a digital read as it seems a nice square wave.

What is the voltage measured? You might need to boost it to get a decent level.

Input voltage is being regulated to 5 V, from a DC power Supply that is simulating a solar panel voltage for now.

I think you might want to look at some of the tachometer examples on this board, like Counting PulseIn.

I know a bit about anemometry and wind resource assessment. Are you sure your wind vane uses a reed switch? Don't think I've ever seen one of those, unless it uses several switches to indicate wind sectors.

Typical wind vanes are either:

  • linear potentiometer — linear output from 2° to 358°. Really nice ones are linear from -90° to 450° to help with direction trending.
  • Gray code — has several ttl outputs which generate a bitmap from which the wind sector can be deduced.

Reed switch anemometers are probably the easiest to read, but are quite low resolution. They work well with long cables. Other types are linear (voltage or current loop), low voltage AC (with frequency proportional to wind speed) and square wave (usually generated by a photochopper).

Since most wind data loggers (even the really expensive ones used for utility-grade work) are many times less powerful than an Arduino, I've been meaning to develop a decent logger sketch.

Since my signals are close to squares, could I send them through the digital pins (2,3). How would I handle the interrupt if now I have two different signals that I will need to compare?

The answer to the first question is yes. But, I wouldn't. I'd use 4 and 5. Or use 2 and 3, but attach interrupt handlers to the two pins (they are the external interrupt pins). Each ISR would fire on the RISING edge or the FALLING edge. In each ISR, record when the interrupt occured. In loop, look at the relative times.

Are you sure your wind vane uses a reed switch? Don't think I've ever seen one of those, unless it uses several switches to indicate wind sectors.

Yes, it does implement reed switches. Two in fact (one associated with the three cup system and one for the wind vein). You can find speed relative to one switch and seeing how fast the switch turns on and off. To find direction you have to measure the shift between the two pulses.

The answer to the first question is yes. But, I wouldn't. I'd use 4 and 5. Or use 2 and 3, but attach interrupt handlers to the two pins (they are the external interrupt pins). Each ISR would fire on the RISING edge or the FALLING edge. In each ISR, record when the interrupt occured. In loop, look at the relative times.

I guess I am just confused on how the data will be stored. If I attach my pins to 2 and 3 using and use 2 attathinterrupts instead of two

attachInterrupt(0, arduino_anemometer, RISING);
attachInterrupt(1, arduino_anemometer, RISING);

in my loop function if digital pin 2 triggers on the rising and digital pin 3 rises while pin 2 is high, will the data I have for stored while using Pin 2 be erased?

for example...

//Calculating Speed Duration
SpeedDuration = (millis() - SpeedTimePrevious);
SpeedTimePrevious = millis();

if (SpeedTimePrevious > DirectionTimePrevious)
{
DirectionDuration = (millis() - DirectionTimePrevious);
DirectionTimePrevious = millis();
DirectionTimePeriod = (DirectionTimePrevious - DirectionTimePrevious1);
}

// Calculates Frequency between DIRECTION signals
DirectionTimePrevious1 = DirectionTimePrevious;
Frequency = 1/DirectionTimePeriod;

// Calculates time difference between SPEED and DIRECTION signals
if (DirectionTimePrevious != 0 ) // Ensures that Direction must occur second
{
TimeDifference = (SpeedTimePrevious - DirectionTimePrevious);
}

I would only want my SpeedDuration to trigger only when pin 2 rises. Does that mean I have to create a new subroutine outside of loop to account for this? Will this data be erased when pin 3 triggers with an interrupt? Can I compare the Time Difference in the loop if they are being handled in the interrupt subroutine?

So I tried doing a simple loop.

My signal is low and for some reason count is incrementing, because the values being printed out for SpeedDuration and SpeedTimePrevious are nonzero.

setup()
{
attachInterrupt(0, arduino_anemometer, RISING);
attachInterrupt(1, arduino_direction, RISING);
}

void loop()
{

if (count = 1)
{
//Calculating Speed Duration
SpeedDuration = (millis() - SpeedTimePrevious);
SpeedTimePrevious = millis();
Serial.print("Speed: ");
Serial.println(SpeedDuration, DEC);
Serial.println(SpeedTimePrevious, DEC);
delay(1000);

}

Serial.print("Speed2: ");
Serial.println(DirectionTimePrevious, DEC);
delay(1000);

count=0;
directioncount=0;
}

void arduino_anemometer()
{
count++
}

void arduino_direction()
{
directioncount++
}

if (count = 1)

This is an assignment statement, not an equality test.

You would not want to test for equality, anyway. You want to do something when count > 0, not any specific value greater than 0.

Are count and directionCount volatile?

In order to get good timing data, the time the interrupt occured needs to be recorded in the ISRs. Finally, while didling with the time and count values, you really should disable interrupts, so you are not interrupted during the computations. Re-enable them when done.

And last, but not necessarily least, GET RID OF THE delay()s. You probably want to only calculate and output speed and direction once every few seconds, but don't use delay to make that happen.

So this is the data that I am getting now. (code is posted below)

Count: 0
Speed: 0
DirectionCount: 0
Speed Time: 0
Direction Time: 0
Time Difference: 0
DirectionTimePeriod: 0
Speed: 4294967295
Direction: 4294967295
Time: 2861

Count: 3
Speed: 820
DirectionCount: 3
Speed2: 11790
Speed Time: 11632
Direction Time: 11790
Time Difference: 158
DirectionTimePeriod: 820
Speed: 1312478
Direction: 69
Time: 12382

Count: 2
Speed: 821
DirectionCount: 3
Speed2: 14252
Speed Time: 14094
Direction Time: 14252
Time Difference: 158
DirectionTimePeriod: 821
Speed: 1310880
Direction: 69
Time: 14843

For some reason my direction is always 69 +/- 1 no matter the direction the wind vein points.

I'm calculating speed and direction value using

Speedvalue = (14923600000/SpeedDuration);
---where 1492 is some arbitrary distance and 3600000 is to convert to hours from miliseconds
Directionvalue = 360
TimeDifference/DirectionTimePeriod;
---I decided to divide by the period of my direction signal rather than multiply by the frequency, because I would end up getting zero because of the scaling.

I'm checking the math using the tables and they match up to be 69-ish. I guess this leads to the idea that I'm not reading the rising pulses correctly. Any thoughts?

Here is my code for now:

//////////////////////////////////////////////////////////
// Declaration of Variables //
//////////////////////////////////////////////////////////

int analogSpeed = 0; //Speed bus connected to analog pin 0
int analogDirection = 1; //Direction bus connected to analog pin 1
unsigned long Speedvalue = 0;
unsigned long Directionvalue = 0;

// Variables for time
unsigned long SpeedDuration;
unsigned long DirectionDuration;
unsigned long SpeedTimePrevious;
unsigned long DirectionTimePrevious;
unsigned long DirectionTimePrevious1;
unsigned long DirectionTimePeriod;
unsigned long TimeDifference;
unsigned long Frequency;

// Variables for counting
volatile byte count;
volatile byte directioncount;

void setup()
{
//pinMode (analogSpeed, INPUT);
//pinMode (analogDirection, INPUT);
Serial.begin(2400); // Setup serial with baud rate
attachInterrupt(0, arduino_anemometer, RISING);
attachInterrupt(1, arduino_direction, RISING);

count = 0;
directioncount=0;
SpeedDuration = 0;
DirectionDuration = 0;
SpeedTimePrevious = 0;
DirectionTimePrevious = 0;
DirectionTimePrevious1 = 0;

TimeDifference = 0;
}

void loop()
{
///////////////////////////////////////////////////////////////////////////////////////////
// It takes about 100 microseconds to read an analog input //
// Max reading rate is 10,000 times a second //
/////////////////////////////////////////////e////////////////////////////////////////////

//DO I WANT DIGITAL OR ANALOG READ?!

Speedvalue = digitalRead(analogSpeed); // Read the input pin at 0
Directionvalue = digitalRead(analogDirection); // Read the input pin at 1

Serial.print("Count: ");
Serial.println(count, DEC);

if (count >= 1)
{
//Calculating Speed Duration
SpeedDuration = (millis() - SpeedTimePrevious);
SpeedTimePrevious = millis();
count = 0;

}

Serial.print("Speed: ");
Serial.println(SpeedDuration, DEC);
Serial.println(SpeedTimePrevious, DEC);

Serial.print("DirectionCount: ");
Serial.println(directioncount, DEC);

if ((SpeedTimePrevious > DirectionTimePrevious) && (directioncount >= 1))
{
DirectionDuration = (millis() - DirectionTimePrevious);
DirectionTimePrevious = millis();
DirectionTimePeriod = (DirectionTimePrevious - DirectionTimePrevious1);
directioncount = 0;

Serial.print("Speed2: ");
Serial.println(DirectionTimePrevious, DEC);

// Calculates Frequency between DIRECTION signals
DirectionTimePrevious1 = DirectionTimePrevious;
Frequency = 1/DirectionTimePeriod;
}

// Calculates time difference between SPEED and DIRECTION signals
if (DirectionTimePrevious != 0 ) // Ensures that Direction must occur second
{
TimeDifference = (DirectionTimePrevious - SpeedTimePrevious);
}
Serial.print("Speed Time: ");
Serial.println(SpeedTimePrevious, DEC);
Serial.print("Direction Time: ");
Serial.println(DirectionTimePrevious, DEC);
Serial.print("Time Difference: ");
Serial.println(TimeDifference, DEC);
Serial.print("DirectionTimePeriod: ");
Serial.println(DirectionTimePeriod, DEC);

//////////////////////////////////
// VALUES //
/////////////////////////////////
Speedvalue = (14923600000/SpeedDuration); // Finds speed of cup rotation in
Directionvalue = 360
TimeDifference/DirectionTimePeriod; //Finds Angle of Wind Vein

/////////////////////////////////////////////////////////////////////////////
// Printing SPEED, DIRECTION, TIME //
/////////////////////////////////////////////////////////////////////////////
Serial.print("Speed: ");
Serial.println(Speedvalue, DEC);
Serial.print("Direction: ");
Serial.println(Directionvalue, DEC);
Serial.print("Time: ");
Serial.println(millis());

}

void arduino_anemometer()
{
count++;
}

void arduino_direction()
{
directioncount++;
}

Speedvalue = (1492*3600000/SpeedDuration);

1492 and 3600000 are treated as ints. 1492 is an int, but 3600000 is not. You should have a L or UL at the end, to tell the compiler to treat the value as a long or unsigned long.

int analogSpeed = 0;             //Speed bus connected to analog pin 0
int analogDirection = 1;          //Direction bus connected to analog pin 1

Speedvalue = digitalRead(analogSpeed);       // Read the input pin at 0
Directionvalue = digitalRead(analogDirection);    // Read the input pin at 1

Are you using the digital pins, so digitalRead is appropriate, or the analog pins?
If you are using digital pins, 0 and 1 are not good choices while doing serial I/O.
If you are using analog pins, you should be using the analogRead function.

1492 and 3600000 are treated as ints. 1492 is an int, but 3600000 is not. You should have a L or UL at the end, to tell the compiler to treat the value as a long or unsigned long.

Are you implying that I store the 1492*3600000 as 5371200000 in another UL variable and hash out my math in explicit UL variables?

Are you using the digital pins, so digitalRead is appropriate, or the analog pins?
If you are using digital pins, 0 and 1 are not good choices while doing serial I/O.
If you are using analog pins, you should be using the analogRead function.

Sorry those were poor name choices for variables. Since the input were square waves, I decided to have them be digital inputs. Originally they were supposed to be analog inputs at pins 0 and 1, but I changed it to digital pin 2 and 3 and forgot to change my comments/names.

On another note, I am trying out a debounce circuit on my input to help clean out my input. That could be a source of error when reading in my data.

I added a debouncing circuit (RC) to my reed switch. My voltage dropped but the results did not change at all. Anyways I thought I'd share what I was seeing on the oscilloscope and the computer.

Time between Directional signal rising

I'm getting a time that's within 700ms. (I checked over a course of 10 impulses that were printed)

Some delay was expected...but not like this...

Here are the relations that I received using the picture above

Computer Data Oscilloscope Data

Speed Period: 763 ms
Time Difference: 162 ms
Direction Period: 766 ms
Direction: 76 degrees

Speed Period: 580 ms
Time Difference: 260 ms
Direction Period: 560 ms
Direction: 167 degrees

Again I am calculating my direction value with

Directionvalue = 360*TimeDifference/DirectionPeriod;

It makes sense that the period of the speed and the direction are the same since the rotation of the axis hits the 2 reeds at the same time.

I cleaned up the code a little bit to get rid of some redundancies in the old code.

I am noticing the following:

  1. My Time Difference is always the same no matter what angle I move my anemometer.

It makes me wonder if I am even making it to that part of the code to update my software or if the program is reading my square waves correctly.

  1. I have my sensor set up to a fan that gives my cups 154 rotations per minute, which give my code 308 interrupts per minute.

I read that the millis() function acts as an interrupt as well. I referr to millis() at lease 4 x in my loop function.

That mixed in with the number of interrupts I am getting, will I be able to make it though my loop function to update my data correctly?

Another question: How much voltage does it take to trigger a rising interrupt? I have very minimal noise on my signal when it is on/off. I'm not sure if this is a problem as my timing to measure my distance between rising edges on 1 signal is off from the oscilloscope readings.

void loop()
{
Speedvalue = digitalRead(digitalSpeed); // Read the input pin at 2
Directionvalue = digitalRead(digitalDirection); // Read the input pin at 3

if (count >= 1)
{
//Calculating Speed Duration
SpeedPeriod = (millis() - SpeedTimePrevious);
SpeedTimePrevious = millis();
count = 0;

}

Serial.print("Speed Period: ");
Serial.println(SpeedPeriod, DEC);

//Value of the Speed
SpeedDistance = 6000045; // 4.5 ft * 60,000 ms/min * 10 scaling factor
Speedvalue = (SpeedDistance/(10
SpeedPeriod)); // Finds speed of cup rotation in ft/min
// ft * (ms/min) / ms = ft/min
//divide 10 scaling factor back out

if ((SpeedTimePrevious > DirectionTimeRising) && (directioncount >= 1))
{
DirectionTimeRising = millis();
directioncount = 0;
}

// Calculates time difference between SPEED and DIRECTION signals
if (DirectionTimeRising > SpeedTimePrevious ) // Ensures that Direction must occur second
{
TimeDifference = (DirectionTimeRising - SpeedTimePrevious);
}
Serial.print("Time Difference: ");
Serial.println(TimeDifference, DEC);

//Value of Direction
Directionvalue = (360*TimeDifference)/SpeedPeriod; //Finds Angle of Wind Vein

I am wondering whether your use of Serial.print is impacting your times. I assume that the UART will buffer the text to some extent, but since you're sending around 30 characters each iteration of the loop, you may be getting delayed by that.

Also, you might get a bit more accuracy on the speed if you collect a few more interrupts (10?) before calculating the time difference

Okay so I restructured my code. I thought with the high rate of interrupts going in my program there would be inconsistencies with interpreting the data.

I restructured it to go through 10 cycles and averaging the data being outputted.

I am noticing that my output in binary is inconsistent with the number of bits being outputted. Sometimes I would get 9 bits/11 bits outputted to the serial monitor. Since I am using long unsigned integers, does the arduino ignore the rest of the 32 bits if the bits are 0? or is it more likely that my bits are being cut short with an interrupt each time I'm printing out.

I'll give you an idea with what I am seeing.

Right now I am printing only my period and my difference in time on the same line.

I Want to get around
440 270
for my two printed values

In Decimal I'm Getting
6405 312
545 273
5212 276
657 328
650 325
449 313

In Binary I'm getting
111010010 100000001
110110010 11110000
110111011 100000101
110011010 11110110
110110100 100011100
110101011 100110001
111111111 101110100
110110101 110010100
110110000 101010100


Right now I am printing two variables on one line. In the end I want to be able to print three variables on one line.

Does my loop function look too long? Am I trying to output too many bits at once? Are my interrupts affecting the data outputted?

What I am trying to look for is consistency (+/- x) within the outputted data and need some advice on whats going on.

Here is my loop function.

void loop()
{
Speedvalue = digitalRead(digitalSpeed); // Read the input pin at 2
Directionvalue = digitalRead(digitalDirection); // Read the input pin at 3

// Anemometer has to go through N rotations before calculating
if (count >= N)
{
//Calculating Speed Duration
SpeedPeriod = (millis() - SpeedTimePrevious);
SpeedTimePrevious = millis();

loopcounter++; //Count itterations

if(loopcounter==1) //First itteration
{
SpeedTimeRising = SpeedTimePrevious;
}
if(loopcounter==2) //Second itteration
{
SpeedPeriod= SpeedPeriod/N;
//Value of the Speed
SpeedDistance = 6000045; // 4.5 ft * 60,000 ms/min * 10 scaling factor
Speedvalue = (SpeedDistance/(10
SpeedPeriod)); // Finds speed of cup rotation in ft/min
// ft * (ms/min) / ms = ft/min
//divide 10 scaling factor back out
loopcounter=0;

}

count = 0;

}

if ((SpeedTimeRising > DirectionTimeRising) && (directioncount >= ((2N))))
{
DirectionTimeRising = millis();
directioncount = 0;
// Calculates time difference between SPEED and DIRECTION signals
TimeDifference = (DirectionTimeRising - SpeedTimeRising)/((2
N));

//Value of Direction
Directionvalue = (360TimeDifference)/SpeedPeriod; //Finds Angle of Wind Vein
/
*****************************************
// Printing SPEED, DIRECTION, TIME //
*****************************************/
Serial.print(SpeedPeriod, DEC);
Serial.print(" ");
Serial.print(TimeDifference, DEC);
Serial.println();

}

}

Did you ever get this working?

I'm just starting down this exact path now.
I do have a datasheet from Ultimeter showing their calibrations for revs per seconds to speed.

I've got the speed happening quite easily, but now to work on the direction component.