ARDUINO readout of DAVIS Wind Sensor

This sketch will readout a DAVIS Wind sensor (Vantage Pro & Vantage Pro 2) and display the wind direction & speed on a 2x 16 character LCD display. The same low cost wind sensor is available from other sources (see specs here)

In addition, the temperature is measured with a 10k NTC resistor, which can be mounted outside, close to the wind sensor.

The wind vane direction can be permanently calibrated with following procedure : upon startup of the ARDUINO board, depress the CAL button while the vane is oriented towards the true North.  From that moment on, the correction is stored in EEPROM and readouts will be correct.

 

See http://www.lexingtonwx.com/anemometer/ for detailed about the sensor.

Schematic of the DAVIS Wind Sensor

 

This is the sketch  or download it here.   It was compiled with IDE version 0022.- IMPORTANT : please use the same or you might get errors when compiling !  You still can download previous versions from ARDUINO website . The interrupt is triggered by FALLING level, because RISING proved to be less accurate at high wind speed.  The code called by the interrupt provides a timer (15 ms) to avoid REED contact bounce, it will allow to measure wind speeds in excess of 150 km/h.


/* Sketch to read David Wind Vane  
   de ON7EQ Dec 2011

    To disable interrupts:
    cli();                // disable global interrupts 
    and to enable them:  
    sei();                // enable interrupts

NTC readout routine

http://arduino.cc/playground/ComponentLib/Thermistor2

=================================================================== 
Thermistor Schematic
=================================================================== 

 (+5v ) ---- (10k-Resister) -------|------- (Thermistor) ---- (GND)
                                   |
                                Analog Pin 'NTCpin'

=================================================================== 
DAVIS Vantage Pro & Vantage Pro 2    Wind Sensor (speed & direction
===================================================================

On RJ-45 plug terminals:

Black =  pulse from anemometer. Connect to Digital 2 pin, and use a 4k7 resistor as pull up to + 5v.
         use a 10 to 22nF capacitor from pin D2 to ground to debounce the reed switch of anemometer
       
Red =    Ground

Green =  Wiper  of Wind direction vane - connect to A0.  Use a 1 ... 10 µF / 16v capacitor between A0 and ground (observe C polarity) to avoid jitter

Yellow = + 5v (reference of potentiometer)

*/

// include EEPROM write - required to memorize antenna / band config.
#include <EEPROM.h>

#include <math.h>

#include <LiquidCrystal.h>
// initialize the library with the numbers of the interface pins
LiquidCrystal lcd(7, 8, 9, 10, 11, 12);

int Direction ; // Wind direction

#define PotPin (A0)    // define the input pin for the wind vane potentiometer
int PotValue = 0;      // variable to store the value coming from the potentiometer
int DirCorr = 0;       // Correction on direction ( - 360  to + 360)

#define CalPin (A1)    // define the input pin to initiate direction calibration @ startup. Ground pin to calibrate
byte DirCorrB1 = 0;    // 2 bytes of DirCorr
byte DirCorrB2 = 0;

volatile unsigned long RPMTops;  // RPM tops counter in interrupt routine                             
volatile unsigned long ContactTime;  // Timer to avoid conatct bounce in interrupt routine                              

float RPM;       // RPM count
float TEMP;      // Temp
                                    
#define RPMsensor (2)      //The pin location of the anemometer sensor

#define  NTCpin    (A4)    // Pin for NTC 10k

float temp = (0);

// build LCD specific characters 'degrees'
byte degree [8] = {
  B00100,
  B01010,
  B00100,
  B00000,
  B00000,
  B00000,
  B00000,
};

// This function will calculate temperature from 10k NTC readout
double Thermister(int RawADC) {
 double Temp;
 Temp = log(((10240000/RawADC) - 10000));
 Temp = 1 / (0.001129148 + (0.000234125 + (0.0000000876741 * Temp * Temp ))* Temp );
 Temp = Temp - 273.15;            // Convert Kelvin to Celcius
// Temp = (Temp * 9.0)/ 5.0 + 32.0; // Convert Celcius to Fahrenheit
 return Temp;
}


////////////////////////////////////////////////////////////////////
void setup() { 

//  Clean EEPROM
//  EEPROM.write (1, 0);
//  EEPROM.write (2, 0);
   
   // set up the LCD's number of columns and rows: 
  lcd.begin(16, 2);
  lcd.clear(); 
  
  // Print a message to the LCD.
  lcd.print(" DAVIS Readout");
  lcd.setCursor(0, 1);  
  lcd.print(" v2.0 de ON7EQ"); 
  
  
  delay (2000);
  
// CALIBRATE if button depressed at startup !

  if ((analogRead(CalPin)<512)) calibrate ();


// else retrieve CAL vales from EEPROM

  DirCorrB1 = EEPROM.read(1);
  DirCorrB2 = EEPROM.read(2);  
  
  DirCorr = (DirCorrB1) + (DirCorrB2);

  
// print screen template
  lcd.clear(); 
  
 // Print variables
  lcd.setCursor(0, 0);  
  lcd.print("Dir  "); 

  lcd.setCursor(12, 0);
  lcd.print("Temp"); 
  

pinMode(RPMsensor, INPUT); 
attachInterrupt(0, rpm, FALLING); 

lcd.createChar(0, degree);
lcd.setCursor(7, 0);  
lcd.write(0);

// speed
lcd.setCursor(0, 1);
lcd.print("Spd   0km/h");
    
 } 

/////////////////////////////////////////////////////////////////////////////////

void loop() { 



// Wind Direction
  
  PotValue = analogRead(PotPin);     // read the value from the potmeter
  Direction = map(PotValue, 0, 1023, 0, 359); 
  Direction = Direction + DirCorr + 3;   // Correct for offset & 5° precision

 convert:       // Convert to 360°  
  
  if (Direction < 0) {
    Direction = Direction + 360;
    goto convert;
  }
  
  if (Direction > 360) {
    Direction = Direction - 360;
    goto convert;
  }
    
  if (Direction == 360) Direction = 0;
  
  lcd.setCursor(4, 0);                // print the value from the potmeter
  

      if (Direction < 100)   lcd.print("0");
      if (Direction < 10)    lcd.print("0");            
      lcd.print(((Direction/5)*5), DEC);    // 5° precision is enough to print te direction value

 
   lcd.setCursor(9, 0);                
 
   if ((Direction)<23) {
    lcd.print(" N");
    } 
   if ((Direction>22) && (Direction<68)) {
    lcd.print("NE");
    } 
   if ((Direction>67) && (Direction<113)) {
    lcd.print(" E");
    } 
   if ((Direction>112) && (Direction<158)) {
    lcd.print("SE");
    } 
   if ((Direction>157) && (Direction<203)) {
    lcd.print(" S");
    } 
    if ((Direction>202) && (Direction<247)) {
    lcd.print("SW");
    } 
    if ((Direction>246) && (Direction<292)) {
    lcd.print(" W");
    } 
    if ((Direction>291) && (Direction<337)) {
    lcd.print("NW");
    } 
    if ((Direction>336) && (Direction<=360)) {
    lcd.print(" N");
    } 
      
  // measure & print the temp

  lcd.setCursor(11, 1);

  TEMP = ((Thermister(1023 - analogRead(NTCpin))) + 0.0);

  if (TEMP >= 0) lcd.print(" ");       // If temp positive, print space, else a '-' will show up
  if (abs(TEMP)<10) lcd.print(" "); 

  lcd.print(TEMP, DEC); 
  
         
  // measure RPM
  
   RPMTops = 0;   //Set NbTops to 0 ready for calculations
   sei();         //Enables interrupts
   delay (3000);  //Wait 3 seconds to average
   cli();         //Disable interrupts

 
 // convert to km/h
 

 if ((RPMTops >= 0) and (RPMTops <= 21)) RPM = RPMTops * 1.2;
 if ((RPMTops > 21) and (RPMTops <= 45)) RPM = RPMTops * 1.15;
 if ((RPMTops > 45) and (RPMTops <= 90)) RPM = RPMTops * 1.1;
 if ((RPMTops > 90) and (RPMTops <= 156)) RPM = RPMTops * 1.0;
 if ((RPMTops > 156) and (RPMTops <= 999)) RPM = RPMTops * 1.0;

     
 // print the speed 

  lcd.setCursor(4, 1); 
  
  if (RPM < 100)   lcd.print(" ");
  if (RPM < 10)    lcd.print(" ");            
  lcd.print(int(RPM), DEC); 

}


//// This is the function that interrupt calls to measure  RPM  

 void rpm ()   { 

    if ((millis() - ContactTime) > 15 ) {  // debounce of REED contact. With 15ms speed more than 150 km/h can be measured
      RPMTops++; 
      ContactTime = millis();
    }
    
} 
//// end of RPM measure  
 
  
//// This is the function that calibrates the vane

 void calibrate () {
   
  lcd.setCursor(0, 1);  
  lcd.print("Hold to calibr !"); 
  delay (2000);  //Wait 2 second
  if ((analogRead(CalPin)>512)) setup();  // CAL not really required ... abort !

  lcd.setCursor(0, 1);  
  lcd.print("Now calibrating ...    "); 
  delay (1000);  //Wait 1 second
  
  PotValue = analogRead(PotPin);     // read the value from the potmeter
  DirCorr = map(PotValue, 0, 1023, 359, 0);

  lcd.setCursor(0, 1);  
  lcd.print("CAL value = "); 
  lcd.print(DirCorr, DEC); 
  lcd.print("            ");  
  delay (2000);  //Wait 2 seconds  
  
//  
  DirCorrB1 = DirCorr / 255;
  if (DirCorrB1 == 1){ 
  DirCorrB1 = 255;  
  DirCorrB2 = DirCorr - 255 ;
    }
  else {
  DirCorrB1 = DirCorr;  
  DirCorrB2 = 0;
    }   
//
//  DirCorrB1 = DirCorr;  
//  DirCorrB2 = 0;
  EEPROM.write (1, DirCorrB1);
  EEPROM.write (2, DirCorrB2);

 wait:
  lcd.setCursor(0, 1);  
  lcd.print("CAL OK - Release !   ");  
  if ((analogRead(CalPin)<512)) goto wait;
 
  lcd.setCursor(0, 1);  
  lcd.print("Now rebooting...    ");   
  delay (1000);     

  setup (); 
}