FA info icon.svg Angle down icon.svg Project data
Authors Team X
matt small
Solomon Clark
Peter Duin
Javier Hinojosa
Location Arcata, California
Status Designed
Completed 2013
OKH Manifest Download

This article is designed for use for the Team X Water Meter used on the WetLand Barge. This page is for the main Team X Appropedia page located at https://www.appropedia.org/Wetlands_Water_Meter

The Arduino Program[edit | edit source]

The Arduino runs off of an open source downloadable program which can be downloaded from this site. The user designs programs that are then uploaded to the Arduino. These sections of code can be inputted straight into the Arduino program and compiled (compiling means to run the code to make sure the code has no programming errors in it) right away, for this project Team X has pre-uploaded the program to the Arduino for the client. All of the outputs from the code are printed to a liquid crystal display (LCD) and saved on an SD card to track trends. The program is separated into multiple tabs with each tab running a separate sensor. To help with the flow and to help the reader decipher the program a /* is used to start a long section of comment and a */ is used to end it and two slash marks (//) are used to denote a short amount of comments in the program, neither type of comments are not read nor do they actually change the program, but rather assist the programmer understand and organize the code. The symbols “{“and “}” denote a beginning and end to sections for example in the program you will see directly under the statement “void setup ()” there is an “{“and then after the setup to end that section there is an “}”. It is important to strictly follow the sections of the program given as the code will not operate if even one symbol or word is misspelled.

About Tabs[edit | edit source]

The Arduino compiler has the ability to separate the program into multiple tabs. Much like when using the internet these tabs are displayed at the top of the page and are read from left to right like a book. Simply put the tab furthest to the left will be read first and the tab furthest to right will read last. On the first tab all of the information that is required to set up the program is written, and any of this information can be accessed throughout the program.

The Code[edit | edit source]

The next six sections are each individual tab with the names: Water Meter Code, pH and Flow, Saline, Temperature, Volume, and Data Shield.

Water Meter Code[edit | edit source]

In the first tab the setup is run as well as the flow into the storage tank. Code for the flow meter can be found here: http://themakersworkbench.com/content/tutorial/reading-liquid-flow-rate-arduino

//This code is for the water meter designed by Team X.
//the first page is for an inlet flow meter
#include <LiquidCrystal.h>
LiquidCrystal lcd(12, 11, 10, 5, 4, 3, 2);
#include <SoftwareSerial.h>	 //we have to include the SoftwareSerial library, or else we can't use it.
#define rx 2					 //define what pin rx is going to be.
#define tx 3					 //define what pin Tx is going to be.
SoftwareSerial myserial(rx, tx); //define how the soft serial port is going to work.
volatile int NbTopsFan; //measuring the rising edges of the signal
int Calc;							
int hallsensor = 2;	//The pin location of the sensor
int tempPin = 0; //the analog pin the TMP36's Vout (sense) pin is connected to
int const max = 20;
float conductivityValue = A0;
float salineValue;
int sensorPin = A1;
float temperatureF;
#define echoPin 7 // Echo Pin (digital)
#define trigPin 8 // Trigger Pin (digital)
#define LEDPin 13 // Onboard LED
float realvolume;
float height;
int maximumRange = 200; // Maximum range needed
int minimumRange = 0; // Minimum range needed
long duration, distance; // Duration used to calculate distance
char ph_data[20];				//we make a 20 byte character array to hold incoming data from the pH.
char computerdata[20];			//we make a 20 byte character array to hold incoming data from a pc/mac/other.
byte pc_debug=1;				 //if you would like to debug the pH Circuit through the serial monitor(pc/mac/other). if not set this to 0.
byte received_from_computer=0;	 //we need to know how many characters have been received.								
byte received_from_sensor=0;	 //we need to know how many characters have been received.
byte arduino_only=0;			 //if you would like to operate the pH Circuit with the arduino only and not use the serial monitor to send it commands set this to 1. The data will still come out on the serial monitor, so you can see it working.
byte startup=0;				 //used to make sure the arduino takes over control of the pH Circuit properly.
float ph=0;					 //used to hold a floating point number that is the pH.
byte string_received=0;			//used to identify when we have received a string from the pH circuit.
volatile int Fanspeed; //measuring the rising edges of the signal
int Flow;							
int FlowsensorIN = A5;	//The pin location of the sensor
#include <SD.h>
//SPI settings
//MOSI,MISO,SCLK Set by default
int CS_pin = 10;
int pow_pin = 8;
void rpm ()	 //This is the function that the interupt calls
{
Fanspeed++; //This function measures the rising and falling edge of the hall effect sensors signal
NbTopsFan++; //This function measures the rising and falling edge of the hall effect sensors signal
}
//void rpm ()	 //This is the function that the interupt calls
//{
// NbTopsFan++; //This function measures the rising and falling edge of the hall effect sensors signal
//}
// The setup() method runs once, when the sketch starts
void setup() //
{
pinMode(FlowsensorIN, INPUT); //initializes digital pin 2 as an input
Serial.begin(38400); //This is the setup function where the serial port is initialised,
attachInterrupt(0, rpm, RISING); //and the interrupt is attached
			Serial.begin(38400);	 //enable the hardware serial port
		myserial.begin(38400);	 //enable the software serial port
		 pinMode(hallsensor, INPUT); //initializes digital pin 2 as an input
Serial.begin(38400); //This is the setup function where the serial port is initialised,
attachInterrupt(0, rpm, RISING); //and the interrupt is attached
	pinMode(trigPin, OUTPUT);
pinMode(echoPin, INPUT);
pinMode(LEDPin, OUTPUT); // Use LED indicator (if required)
Serial.begin(38400);
Serial.begin(38400);
	Serial.println("Initializing Card");
//CS pin is an output
pinMode(CS_pin, OUTPUT);
//Card will draw power from pin 8 so set high
pinMode(pow_pin, HIGH);
//Check if card is ready
if(!SD.begin(CS_pin))
{
	 Serial.println("Card Failed");
	 return;
}
Serial.println("Card Ready");
}
// the loop() method runs over and over again,
// as long as the Arduino has power
void serialEvent(){		 //this interrupt will trigger when the data coming from the serial monitor(pc/mac/other) is received.	
			 if(pc_debug==1){	 //if pc debug is set to 0 this function will be bypassed.
				 received_from_computer=Serial.readBytesUntil(13,computerdata,20); //we read the data sent from the serial monitor(pc/mac/other) until we see a <CR>. We also count how many characters have been received.	
				 computerdata[received_from_computer]=0; //we add a 0 to the spot in the array just after the last character we recived. This will stop us from transmiting incorrect data that may have been left in the buffer.
				 myserial.print(computerdata);		 //we transmit the data received from the serial monitor(pc/mac/other) through the soft serial port to the pH Circuit.
				 myserial.print('\r');				 //all data sent to the pH Circuit must end with a <CR>.
				 }	
			 }
void loop ()	
{
Fanspeed = 0;	//Set NbTops to 0 ready for calculations
sei();		//Enables interrupts
delay (1000);	//Wait 1 second
cli();		//Disable interrupts
Flow= (Fanspeed * 60 / 7.5); //(Pulse frequency x 60) / 7.5Q, = flow rate in L/hour
//lcd.print (Flow, DEC); //Prints the number calculated above
//lcd.print (" L/hour\r\n"); //Prints "L/hour" and returns a new line

pH and Flow[edit | edit source]

In the second tab the code for the second flow meter and the pH meter. The flow meter code has the same format but the variables have different name. The pH code can be found here: http://web.archive.org/web/20150816150846/http://atlas-scientific.com:80/product_pages/embedded/ph.html

	 NbTopsFan = 0;	//Set NbTops to 0 ready for calculations
sei();		//Enables interrupts
delay (1000);	//Wait 1 second
cli();		//Disable interrupts
Calc = (NbTopsFan * 60 / 7.5); //(Pulse frequency x 60) / 7.5Q, = flow rate in L/hour
if (Calc > 0)
{
Serial.print (Calc, DEC); //Prints the number calculated above
Serial.print (" L/hour\r\n"); //Prints "L/hour" and returns a new line
if(myserial.available() > 0){	//if we see that the pH Circuit has sent a character.
		received_from_sensor=myserial.readBytesUntil(13,ph_data,20); //we read the data sent from ph Circuit untill we see a <CR>. We also count how many character have been recived.
		ph_data[received_from_sensor]=0; //we add a 0 to the spot in the array just after the last character we recived. This will stop us from transmiting incorrect data that may have been left in the buffer.
		string_received=1;				//a flag used when the arduino is controlling the pH Circuit to let us know that a complete string has been received.
		//Serial.println(ph_data);		 //lets transmit that data received to the serial monitor.
		}	
if(arduino_only==1){			 //if you set arduino_only to = 1.
		if (startup==0){				//if the arduino just booted up, we need to set some things up first.
				pc_debug=0;				 //make sure pc_debug is set to 0. You will no longer be able to write commands to the pH circuit in the serial monitor.
				 myserial.print("e\r");	 //take the pH Circuit out of continues mode.
				 delay(50);				 //on start up sometimes the first command is missed.
				 myserial.print("e\r");	 //so, let’s send it twice.
				 delay(50);				 //a short delay after the ph Circuit was taken out of continues mode is used to make sure we don’t over load it with commands.
				 startup=1;				 //startup is completed, let's not do this again during normal operation.
		 }
delay(800);						 //we will take a reading ever 800ms. You can make this much longer or shorter if you like.
	myserial.print("R\r");			 //send it the command to take a single reading.
	if(string_received==1){			//did we get data back from the ph Circuit?
		ph=atof(ph_data);			 //many people ask us "how do I convert a sting into a float?" this is how...(pretty tough)
		//if(ph>=7.5){Serial.println("high\r");} //This is the proof that it has been converted into a string.
		//if(ph<7.5){Serial.println("low\r");} //This is the proof that it has been converted into a string.
		string_received=0;}			 //reset the string received flag.
}
/*
here are some functions you might find useful
// calibrate to a pH of 7
void s_cal()
{
// send the "s" command to calibrate to a pH of 7.00
mySerial.print("s\r");
}
// calibrate to a pH of 4
void f_cal()
{
// send the "f" command to calibrate to a pH of 4.00
mySerial.print("f\r");
}
// calibrate to a pH of 10.00
void t_cal()
{
// send the "t" command to calibrate to a pH of 10.00
mySerial.print("t\r");
}
// factory defaults the pH circuit
void phFactoryDefault()
{
// send the "X" command to factory reset the device
mySerial.print("X\r");
}
// send the "I" command to query the information
	 mySerial.print("I\r");
// turn the LEDs on or off
void phSetLEDs(byte enabled)
{
if(enabled)
	 mySerial.print("L1\r");
else
	 mySerial.print("L0\r");
}
{
*/

Saline[edit | edit source]

The saline code converts the conductivity to salinity in parts per million and displays whether the saline value is with in the acceptable limits or not.

//convert conductivityvalue to salineValue
conductivityValue = 10 * conductivityValue;
conductivityValue = pow(conductivityValue, 1.0878);
salineValue= 0.4655 * conductivityValue;
//use an if else structure to check if the value of the saline
//is acceptable or not. if its not the program shows bad and if
//its acceptable then the program prints good.
//if(salineValue > max)
//{
// lcd.print("BAD");
// }
// else
// {
// lcd.print("GOOD");
// }

Temperature[edit | edit source]

The temperature code converts from volts to Celsius and further converts to Fahrenheit and displays in Fahrenheit. The page that supplied the code is: http://learn.adafruit.com/tmp36-temperature-sensor/using-a-temp-sensor

//getting the voltage reading from the temperature sensor
int reading = analogRead(tempPin);
// converting that reading to voltage, for 3.3v arduino use 3.3
float voltage = reading * 5.0;
voltage /= 1024.0;
// print out the voltage
//Serial.print(voltage); Serial.println(" volts");
// now print out the temperature
float temperatureC = (voltage - 0.5) * 100 ; //converting from 10 mv per degree wit 500 mV offset
													 //to degrees ((voltage - 500mV) times 100)
// now convert to Fahrenheit
float temperatureF = (temperatureC * 9.0 / 5.0) + 32.0;
//Serial.print(temperatureF); Serial.println(" degrees F");

Volume[edit | edit source]

The volume sensor code is a modification off of http://arduinobasics.blogspot.com/2012/11/arduinobasics-hc-sr04-ultrasonic-sensor.html webpage. The code measures the time from when the sonar sensor, bounce off the water, and return to the sensor. Then it converts that to centimeters, then to meters, and then to meters cubed using the dimensions of the IBC tote, and finally converts meters cubed into gallons.

/*
HC-SR04 Ping distance sensor:
VCC to arduino 5v
GND to arduino GND
Echo to Arduino pin 7
Trig to Arduino pin 8
This sketch originates from Virtualmix: http://goo.gl/kJ8Gl
Has been modified by Winkle ink here: http://winkleink.blogspot.com.au/2012/05/arduino-hc-sr04-ultrasonic-distance.html
And modified further by ScottC here: http://arduinobasics.blogspot.com/
on 10 Nov 2012.
*/
//#define echoPin 7 // Echo Pin
//#define trigPin 8 // Trigger Pin
//#define LEDPin 13 // Onboard LED
//int maximumRange = 200; // Maximum range needed
//int minimumRange = 0; // Minimum range needed
//long duration, distance; // Duration used to calculate distance
//void setup() {
// Serial.begin (9600);
// pinMode(trigPin, OUTPUT);
// pinMode(echoPin, INPUT);
// pinMode(LEDPin, OUTPUT); // Use LED indicator (if required)
//}
//void loop() {
/* The following trigPin/echoPin cycle is used to determine the
distance of the nearest object by bouncing soundwaves off of it. */
digitalWrite(trigPin, LOW);
delayMicroseconds(2);
digitalWrite(trigPin, HIGH);
delayMicroseconds(10);
digitalWrite(trigPin, LOW);
duration = pulseIn(echoPin, HIGH);
//Calculate the distance (in cm) based on the speed of sound.
distance = duration/58.2;
height = 101.96 - distance;
realvolume = height * 101.9 * 100.2; //give cubic centimeters
realvolume = realvolume/1000000; //put it in cubic meters
realvolume = realvolume/264.171; //make it into gallons
}
else
{
delay(50); //wait a bit and see if there is a flow at the outlet
}
//have the lcd print here!!!
lcd.print (Flow, DEC); //Prints the number calculated above
lcd.print (" L/hour\r\n"); //Prints "L/hour" and returns a new line
lcd.print(ph_data);
	if(salineValue > max)
{
	 lcd.print("BAD");
}
else
{
	 lcd.print("GOOD");
}
lcd.print(temperatureF );
lcd.print(realvolume); lcd.print("gal");

Data Shield[edit | edit source]

The data shield prints the data from taken from the sensors and saves it on a SD card.

String dataString = "Please work";
//Open a file to write to
//Only one file can be open at a time
File dataFile = SD.open("log.txt", FILE_WRITE);
if(dataFile)
{
	 dataFile.println(dataString);
	 dataFile.close();
	 Serial.println(dataString);
}
else
{
	 Serial.println("Couldn't access file");
}
}
}
FA info icon.svg Angle down icon.svg Page data
Part of Engr205 Introduction to Design, WetLand ENGR215 projects
Keywords water, wetland, monitoring and evaluation
SDG SDG06 Clean water and sanitation
Authors matt small
License CC-BY-SA-3.0
Organizations Engr205 Introduction to Design, Cal Poly Humboldt, WetLand
Derivative of Wetlands Water Meter
Other derivatives WetLand water meter instructions
Language English (en)
Related 0 subpages, 7 pages link here
Impact 1,174 page views
Created December 9, 2013 by matt small
Modified February 28, 2024 by Felipe Schenone
Cookies help us deliver our services. By using our services, you agree to our use of cookies.