Team X Water Meter Arduino Code

From Appropedia
Jump to: navigation, search
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 http://www.appropedia.org/Wetlands_Water_Meter

The Arduino Program[edit]

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]

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]

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]

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]

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: https://www.atlas-scientific.com/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]

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]

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]

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]

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");
 } 
 }
 }