Arduino Weather Station Project - Davis Anemometer

Hooking Up the Davis Anemometer (Part 5)

Once we have confirmed all the other sensors are working okay we now hookup the last sensor which is the Davis anemometer. This device has two sensors. The wind direction is measured using a potentiometer that changes it's resistance depending on the direction. We connect this to an analog input on the Arduino.

The wind speed is detected by the cups opening and closing a reed switch. A small magnet on the wind cups passes this reed switch once per revolution. The output of this reed switch is connected to a digital input on the Arduino. The number of revolutions is counted for a time period which is then converted to wind speed. The time duration we use is 2.5 seconds.

Connect Arduino to Davis Anemometer

For more details on the Davis Anemometer we did a 3 part hookup guide

Part 1) Hookup and wind direction calibration

Part 2) How to measure wind speed

Part 3) Software to determine wind speed and direction

Code

To get the wind speed we need to count the number of revolutions over a certain time period. We then apply a formula to calculate the wind speed in miles per hour. We have used the time period of 2.5 seconds which is the same as the one Davis use in their technical document.

We are going to use a timer interrupt which triggers every 0.5 seconds. We use the timerCount variable to count up to 2.5 seconds. We calculate the wind speed in the interrupt handler routine as it time critical. You need to be careful around timing critical calculations in the main loop and when you are using commands such as Serial.print(). If you have multiple Serial.print() calls it can mess up your timing accuracy.

In the isr_timer() function we also set the isSampleRequired flag to true when 2.5 seconds has elapsed. In the main loop we check if this flag is true and if so we output all the sensor data to the console.

The second isr (isr_rotation) is used to count the number of revolutions of the wind cups. This sensor is connected to pin 2 on the Arduino board. We attached an interrupt handler (line 124) to this digital pin that is triggered when the reed switch pulses the digital input to ground and back to 5V.

The third interrupt handler (isr_rg) is used for when rain is detected by the Hydreon rain sensor. The sensor open and closes when 0.01mm of rain has been detected. We have configured the sensor for tipping bucket mode and bucket size of 0.01mm.

We have removed the 2 second delay that we used previously to display the data to the console. We do not want to use the delay function as it blocks the operation of any code while the delay is being executed. The advantage of using the timer interrupt is that it allows us to schedule events in code without blocking any other code from executing.

All new code has been highlighted.

Library

We have to include the TimerOne.h and math.h libraries.

Software Sketch

Basic Weather Station Rain Sensor Sketch
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
#include "TimerOne.h"
#include <math.h>

#include "cactus_io_DS18B20.h"
#include "cactus_io_BME280_I2C.h"

#define Bucket_Size 0.01 // bucket size to trigger tip count
#define RG11_Pin 3 // digital pin RG11 connected to
#define TX_Pin 8 // used to indicate web data tx
#define DS18B20_Pin 9 // DS18B20 Signal pin on digital 9

#define WindSensor_Pin (2) // digital pin for wind speed sensor
#define WindVane_Pin (A2) // analog pin for wind direction sensor
#define VaneOffset 0 // define the offset for caclulating wind direction

volatile unsigned long tipCount; // rain bucket tip counter used in interrupt routine
volatile unsigned long contactTime; // timer to manage any rain contact bounce in interrupt routine

volatile bool isSampleRequired; // this is set every 2.5sec to generate wind speed
volatile unsigned int timerCount; // used to count ticks for 2.5sec timer count
volatile unsigned long rotations; // cup rotation counter for wind speed calcs
volatile unsigned long contactBounceTime; // timer to avoid contact bounce in wind speed sensor
volatile float windSpeed;
volatile float totalRainfall; // total amount of rainfall detected

bool txState; // current led state for tx rx led
int vaneValue; // raw analog value from wind vane
int vaneDirection; // translated 0 - 360 wind direction
int calDirection; // calibrated direction after offset applied
int lastDirValue; // last recorded direction value

// Create DS18B20, BME280 object
DS18B20 ds(DS18B20_Pin); // on digital pin 9
BME280_I2C bme; // I2C using address 0x77

void setup() {

txState = HIGH;

// setup rain sensor values
tipCount = 0;
totalRainfall = 0;

// setup anemometer values

lastDirValue = 0;
rotations = 0;
isSampleRequired = false;

// setup timer values
timerCount = 0;

ds.readSensor();

Serial.begin(9600);
Serial.println("cactus.io | Weather Station DS18B20, BME280, RG11, Davis Sensor Test");
Serial.println("DS Temp\t\tBME Temp\tHumdity\t\tPressure\tRainfall\tSpeed\tDirection");

if (!bme.begin()) {
Serial.println("Could not find BME280 sensor, check wiring!");
while (1);
}

pinMode(TX_Pin, OUTPUT);
pinMode(RG11_Pin, INPUT);
pinMode(WindSensor_Pin, INPUT);
attachInterrupt(digitalPinToInterrupt(RG11_Pin), isr_rg, FALLING);
attachInterrupt(digitalPinToInterrupt(WindSensor_Pin), isr_rotation, FALLING);

// setup the timer for 0.5 second
Timer1.initialize(500000);
Timer1.attachInterrupt(isr_timer);

sei();// Enable Interrupts
}

void loop() {

ds.readSensor();
bme.readSensor();

if(isSampleRequired) {

getWindDirection();

Serial.print(ds.getTemperature_C()); Serial.print(" *C\t");
Serial.print(bme.getTemperature_C()); Serial.print(" *C\t");
Serial.print(bme.getHumidity()); Serial.print(" %\t\t");
Serial.print(bme.getPressure_MB()); Serial.print(" mb\t");
Serial.print(totalRainfall); Serial.print(" mm\t\t");
Serial.print(windSpeed); Serial.print(" mph\t");
Serial.print(calDirection); Serial.println("*");

isSampleRequired = false;
}
}

// Interrupt handler routine for timer interrupt
void isr_timer() {

timerCount++;

if(timerCount == 5) {
// 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;
rotations = 0;
txState = !txState; // toggle the led state
digitalWrite(TX_Pin,txState);
isSampleRequired = true;
timerCount = 0;
}
}

// Interrupt handler routine to increment the rotation count for wind speed
void isr_rotation() {

if((millis() - contactBounceTime) > 15 ) { // debounce the switch contact

rotations++;
contactBounceTime = millis();
}
}

// Interrupt handler routine that is triggered when the rg-11 detects rain
void isr_rg() {

if((millis() - contactTime) > 15 ) { // debounce of sensor signal
tipCount++;
totalRainfall = tipCount * Bucket_Size;
contactTime = millis();
}
}

// Get Wind Direction
void getWindDirection() {

vaneValue = analogRead(WindVane_Pin);
vaneDirection = map(vaneValue, 0, 1023, 0, 359);
calDirection = vaneDirection + VaneOffset;

if(calDirection > 360)

calDirection = calDirection - 360;

if(calDirection > 360)

calDirection = calDirection - 360;
}

Sketch Console Output

The sketch displays data from all of the sensors we have connected so far.

Connect Arduino to DS18B20, BME280, RG11 Sensor