I have a modified script to gather readings from an anenometer (reed switch), pluvometer (reed switch), and wind vane (resistor array).
As-is it seems to work fine.
I'm trying to break it out into a separate .cpp and .h file in order to clean up the main loop. Here I've run into problems, and can't figure out how to declare the variables and functions such that the ISR's have access at runtime. However I arrange things I get errors indicating no variables are available, or all variables are defined multiple times.
Any help arranging the headers would be much appreciated, I'm afraid I've tried every possible combination already ![]()
//Main
#include "header.h"
void setup(){
pinMode(ANEMOMETER_PIN, INPUT_PULLUP);
pinMode(VANE_POWERPIN, INPUT);
pinMode(VANE_PIN, OUTPUT);
analogWrite(VANE_POWERPIN, HIGH);
pinMode(RAIN_PIN, INPUT_PULLUP);
attachInterrupt(ANEMOMETER_PIN, anemometerISR, RISING);
attachInterrupt(RAIN_PIN, pluvometerISR, RISING);
Header.h
#ifndef HEADER_H
#define HEADER_H
#pragma once
#define ANEMOMETER_PIN 9
#define VANE_PIN A1
#define VANE_POWERPIN A5
#define RAIN_PIN 8
#define ANEMOMETER_CONV 2.4*0.277778 // m/s
#define PLUVOMETER_CONV 0.2794*60*60 //mm/h
extern void anemometerISR();
extern void pluvometerISR();
#endif
WX.cpp
#include <Arduino.h>
#include "WX.h"
#include "header.h"
//All functions reside here
WX.h
const byte anemometerPin = ANEMOMETER_PIN;
const byte pluvometerPin = RAIN_PIN;
const byte windVanePin = VANE_PIN;
const byte windVaneRefPin = VANE_POWERPIN;
volatile unsigned long sTime;
volatile float pulseTime;
volatile float culPulseTime;
volatile bool startRev; //tracks when measurement start
volatile unsigned int avgWindCount;
volatile unsigned int pluvCount; //stores pluvometer counts
volatile int vaneSample[51];
int vaneSampleSize;
unsigned int vaneSampleIdx;
unsigned int windDirBin[16];
unsigned long WX_Timer; //used to track how often to communicate data
float windDir;
Below is the full (working) script in a single file:
/* Modified from :
** @file ADSWeather.cpp
** @author John Cape
*/
const byte anemometerPin = 9;
const byte pluvometerPin = 8;
const byte windVanePin = A1;
int vaneSampleSize = 51;
#define ANEMOMETER_CONV 2.4*0.277778 // m/s
#define PLUVOMETER_CONV 0.2794*60*60 //mm/h
volatile unsigned long sTime = 0; //stores startRev time
volatile float pulseTime = 0; //stores time between one anemomter relay closing and the next
volatile float culPulseTime = 0; //stores cumulative pulsetimes
volatile bool startRev = true; //tracks when a new anemometer measurement startRevs
volatile unsigned int avgWindCount = 0; //stores anemometer relay counts
volatile unsigned int pluvCount = 0; //stores anemometer relay counts
volatile int vaneSample[51];
unsigned int vaneSampleIdx = 0;
unsigned int windDirBin[16];
unsigned long WX_Timer = 0; //used to track how often to communicate data
float windDir;
void setup() {
pinMode(anemometerPin, INPUT_PULLUP);
// pinMode(windVaneRefPin, OUTPUT);
// analogWrite(windVaneRefPin, HIGH);
pinMode(pluvometerPin, INPUT_PULLUP);
pinMode(windVanePin, INPUT);
attachInterrupt(anemometerPin, anemometerISR, RISING);
attachInterrupt(pluvometerPin, pluvometerISR, RISING);
WX_Timer = millis(); //reset loop timer
}
void loop() {
if ((millis() - WX_Timer) > 5000) { //See if it is time to transmit
float aWSpeed = getAvgWindSpeed(culPulseTime, avgWindCount); //calculate average wind speed
culPulseTime = 0; //reset cumulative pulse counter
avgWindCount = 0; //reset average wind count
float aPrecip = getAvgPrecip(millis() - WX_Timer, pluvCount);
pluvCount = 0;
float aFreq = 0; //set to zero initially
if (pulseTime > 0.0) aFreq = getFreq(pulseTime);
float wSpeed = getWind(aFreq);
windDir = readWindDir();
//windDir = analogRead(windVanePin);
Serial.begin(9600); //serial uses interrupts
Serial.print(wSpeed);
Serial.print(" Current_average_wind_speed ");
Serial.print(aWSpeed);
Serial.print(" Average_precipitation ");
Serial.print(aPrecip);
Serial.print(" Average_direction ");
Serial.println(windDir);
Serial.end(); //serial uses interrupts
startRev = true;
}
}
//using time between anemometer pulses calculate frequency of anemometer
float getFreq(float pTime) {
return (1 / pTime);
}
//Use anemometer frequency to calculate wind speed in MPH, note 2.5 comes from anemometer data sheet
float getWind(float freq) {
return (freq * ANEMOMETER_CONV);
}
float getPrecip(float freq) {
return (freq * PLUVOMETER_CONV);
}
//Calculates average wind speed over given time period
float getAvgWindSpeed(float cPulse, int per) {
if (per) return getWind(getFreq((float)(cPulse / per)));
else return 0;
}
//Calculates average wind speed over given time period
float getAvgPrecip(float cPulse, int per) {
if (per) return getPrecip(getFreq((float)(cPulse / per)));
else return 0;
}
//This is the interrupt service routine (ISR) for the anemometer input pin
void anemometerISR() {
unsigned long cTime = millis(); //get current time
if ((cTime - sTime) > 2500) startRev = true; //if the wind speed has dropped below 1MPH than set it to zero
if (!startRev) { //This is not the first pulse and we are not at 0 MPH so calculate time between pulses
// test = cTime - sTime;
pulseTime = (float)(cTime - sTime) / 1000;
culPulseTime += pulseTime; //add up pulse time measurements for averaging
avgWindCount++; //anemomter went around so record for calculating average wind speed
}
sTime = cTime; //store current time for next pulse time calculation
//sample the wind direction
vaneSample[vaneSampleIdx] = analogRead(windVanePin);
vaneSampleIdx++;
if (vaneSampleIdx >= vaneSampleSize)
{
vaneSampleIdx = 0;
}
startRev = false;
}
//This is the interrupt service routine (ISR) for the anemometer input pin
void pluvometerISR() {
pluvCount++;
}
//Updates the wind direction internal state.
** @file ADSWeather.cpp
** @author John Cape
** @copyright Argent Data Systems, Inc. - All rights reserved
*/
float readWindDir()
{
unsigned int maximum, sum;
unsigned char i, j, max_i;
//Clear wind vane averaging bins
for (i = 0; i < 16; i++)
{
windDirBin[i] = 0;
}
//Read all samples into bins
for (i = 0; i < vaneSampleSize; i++)
{
setBin(vaneSample[i]);
}
//Calculate the weighted average
//Find the blokc of 5 bins with the highest sum
maximum = 0;
for (i = 0; i < 16; i++)
{
//get the sum of the next 5 bins
sum = 0;
for (j = 0; j < 5; j++)
{
sum += windDirBin[(i + j) & 0x0F];
}
if (sum > maximum)
{
maximum = sum;
max_i = i;
}
}
sum = 0;
for (i = 1; i < 5; i++)
{
sum += (windDirBin[(max_i + i) & 0x0F] * i);
}
sum = ((max_i * 45) + ((sum * 45) / maximum) >> 1) % 360; //Convert into degrees
return sum;
}
//fwind direction using consensus averaging.
void setBin(unsigned int windVane)
{
//Read wind directions into bins
unsigned char bin;
if ( windVane > 940) bin = 12; //W
else if (windVane > 890) bin = 14; //NW
else if (windVane > 820) bin = 13; //WNW
else if (windVane > 785) bin = 0; //N
else if (windVane > 690) bin = 15; //NNW
else if (windVane > 630) bin = 10; //SW
else if (windVane > 590) bin = 11; //WSW
else if (windVane > 455) bin = 2; //NE
else if (windVane > 400) bin = 1; //NNE
else if (windVane > 285) bin = 8; //S
else if (windVane > 240) bin = 9; //SSW
else if (windVane > 180) bin = 6; //SE
else if (windVane > 125) bin = 7; //SSE
else if (windVane > 90) bin = 4; //E
else if (windVane > 80) bin = 3; //ESE
else bin = 5;
windDirBin[bin]++;
}