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