Team:Queens Canada/Software

Introduction

Two programs were created over the course of this project: an Arduino program and a Processing program. Arduino is a microcontroller programming interface, which means it can program general purpose input-output pins that are wired to different electrical components such as pushbuttons, LEDs, sensors and displays. Processing is an open-source graphical library and integrated development environment that makes visualizations simple to execute. Comments on both programs are denoted by the double slashes (//) and explain what specific lines in the code do.

Arduino

The code below was developed for the fluorometer. The general steps that the program takes is shown in the flowchart below. The pushbutton indicates the start of a sequence which turns on the excitation LED to excite the fluorophore on the device’s membrane, then measures the amount of illuminance coming from the membrane using the lux sensor. The data from the lux sensor is then transmitted wirelessly through Bluetooth communication to a receiving device (for example on a police officer’s cruiser computer), while general results are displayed on the OLED display.

Arduino Code:

//libraries for OLED display
#include <Adafruit_SSD1306.h>
#include <splash.h>
#include <Adafruit_GFX.h>
#include <gfxfont.h>

#define SCREEN_WIDTH 128 //display width, in pixels
#define SCREEN_HEIGHT 32 //display height, in pixels 

#define OLED_RESET -1 //same reset as arduino 
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
int SSD1306Address = 0x3C;

//for i2c, used for both OLED and sensor
#include <Wire.h>

//for TSL2591 sensor
#include <Adafruit_Sensor.h>
#include "Adafruit_TSL2591.h"

Adafruit_TSL2591 tsl = Adafruit_TSL2591(2591); //this is the sensor ID
int TSL2591Address = 0x29;

#define LED 9 //light emitting diode digital pin
#define start 12 //button digital pin

void configureSensor(void){
  //both can vary
  tsl.setGain(TSL2591_GAIN_MED); 
  tsl.setTiming(TSL2591_INTEGRATIONTIME_300MS);
}

int val = 0;//data received from serial port
int dataNum = 0;//counter for number of datapoints

void setup() {
  //setup code runs once
  Serial.begin(9600); //initializes serial monitor

  //configure pins as input or output
  pinMode (LED, OUTPUT); 
  pinMode (start, INPUT);
  
  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
  display.display();
  delay(2000);

  display.clearDisplay();
  
  //display calculated concentration result to OLED 
  displaySomething();
  
  configureSensor(); 
  establishContact();//send a byte to establish contact with receiver
}

void loop() {
  //main code will run repeatedly
  //light up the LED that will excite the fluorophore (with push button)
  
  digitalWrite(LED, LOW);
  if(digitalRead(start) == LOW){ //if start button is pressed
    for (int i=0; i<100; i++){ //enter for loop
      while (dataNum <= i){ //the number of datapoints is less than i counter in for loop
        digitalWrite(LED, HIGH); //turn on LED 
          
        if (Serial.available() > 0){ //if we get a valid byte
          val = Serial.read(); //read data and store into val
          sensorRead(); //carry out sensorRead function
        }
      }
    }
  }
  else{
    digitalWrite(LED, LOW);//keep LED off otherwise
  }
}

void establishContact(){ //this function sends a byte to establish contact until receiver responds
  while(Serial.available() <= 0){
    Serial.println("A");
    delay(300);
  }
}

void sensorRead(void){ //this function reads sensor values and prints them to the serial monitor
  uint32_t lum = tsl.getFullLuminosity();
  uint16_t ir, full;
  ir = lum >> 16;
  full = lum & 0xFFFF;
  Serial.println(tsl.calculateLux(full, ir),6);
  dataNum++;
}

Processing


The purpose of the Processing program is to receive the Bluetooth-transmitted data from the Arduino and visualize it on the receiving device. The current program functions only on computers, however adjustments can be made to the program to work on mobile devices as well. This program creates a new window showing a plot of live data from the illuminance sensor on the Arduino over time.

Processing Code:

import processing.serial.*; //imports the serial library
import org.gicentre.utils.stat.*; //imports the stats library

Serial myPort; //intializes serial port

String val;
float counter[] = new float[100]; //array for x values on plot
float sensorData[] = new float[100]; //array for y values on plot
boolean firstContact = false; //boolean variable storing whether or not contact has been established
int serialCount = 0; //counts serial instance 
boolean isSerialEventCalled = false; //boolean variable storing whether or not function serialEvent is called

XYChart plot; //initializes plot area 

void setup(){
  size(1000, 800); //size of popup window 
  textFont(createFont("Arial",15),15); //font
  background(0); //black background colour
  
  println(Serial.list()[0]); //prints COM port to console
  
  myPort = new Serial(this, Serial.list()[0], 115200); //sets up the serial port
  myPort.bufferUntil('\n'); //delimited by the \n symbol 
  
  for(int j=0;j<counter.length; j++){ //populates counter array with numbers
    counter[j] = j;
  }
  
  //setting up various parameters for the plot
  plot = new XYChart(this);
  plot.setData(counter, sensorData);
  plot.setMinY(0);
  plot.setMaxY(2000);
  plot.showXAxis(true);
  plot.showYAxis(true);
  plot.setYFormat("###.###");
  plot.setXAxisLabel("\nCounter");
  plot.setYAxisLabel("Luminosity in lux");
  
  plot.setPointColour(color(96,245,66,100));
  plot.setPointSize(5);
  
}

void draw(){
  plot.draw(20,20,width-40,height-40); //draws the plot on the popup window
}

void serialEvent(Serial myPort){ //serialEvent function is called when data is available
  isSerialEventCalled = true;
  //put incoming data into string val
  val = myPort.readStringUntil('\n'); 
  
  //make sure data isn't empty
  if(val != null){
    val = trim(val); //trim whitespace and formatting 
    println(val);
    
    //look for 'A' string, if found, clear buffer and request data
    if(firstContact == false){
      if(val.equals("A")){
        myPort.clear();
        firstContact = true;
        myPort.write("A");
        println("Contact");
      }
    }
    
    //if we already have contact keep getting data
    else{ 
      println(val);
      }
    }
    float fal = float(val);
    sensorData[serialCount] = fal;
    serialCount++;
    delay(100);
    myPort.write("A");
  }