And here is the code
#include <LiquidCrystal.h> // library for AC1602 type 16x2 lcd display
#include <FlexiTimer2.h> // timer library
#include <PID_v1.h> // proportional integral/derivative library for heater
#include <EEPROM.h> // used to store last column temperature
/* Arduino halogenated hydrocarbon Gas Chromatograph
*/
const char version[]="0.2";
/* by Leon Harris
GC performs the following simple functions:
1) Displays welcome message
2) reads default set temperature
3) prompts user to enter set temperature
4) warms column to required temperature then
5) waits for "inject button" to be pushed, then
6) Start timing, and report ldr value, temperature and time
7) Write out value to serial port
8) Reports conditions to lcd
parts
ldr: infinity to 30k
lm35 sensor for column temperature
push button to detect start
red led for running indicator
green led for ready indicator
lcd 2 line Hitachi HD44780 type
Pin Assignments
Analog
A0 column temperature sensor lm35
A1 LDR detector
A2 up/down push buttons; up to 27k, down to 10k pulldown 10k
this gives ADC down = 512 counts, up = 276 counts,
both simultaneously = 592 counts. Use +/-5% in logic
Digital
D2 Run/Stop button
D3 Ready LED (Red)
D4 Busy LED (Green)
D5 lcd DB7, pin 14 of lcd
D6 lcd DB6, pin 13 of lcd
D7 LCD DB5, pin 12 of lcd
D8 LCD DB4, pin 11 of lcd
D10 PWM drive for mosfet heater controller
D11 Enable, pin 6 of lcd
D12 Register Select, pin 4 of lcd
*/
//Globals -> I have the programming equivalent of poor hygiene with my globals:TODO clean up
const int buttonPin = 2; //use an interupt on pin 2 for start button
const int readyLED = 3; // digital pin the heartbeat led is on
const int busyLED = 4; // digital pin the BUSY LED is on
const int columnTempSensor = A0; // front LM35 column sensor
const int detectorLDR = A1; // ldr for detecting green flame
const int setButtons = A2; // ldr for detecting green flame
const int mosfetDrive = 10; // drive pin for heater
volatile int flashpin =1;
volatile int serviceInterrupt = 0;
double temperature;
double epromTemperature; // holds the temperature read from the eprom
int epromaddy=0; // just writes to address 0. Uses var in case I upgrade to a better save record like a struct (ie for multi-temp runs)
double settemperature;
double input,output; // needed for pid for column heater
int photoDetector;
int runFlag = 1;
unsigned long time;
unsigned long startTime;
int serInLen = 25; // used for Gobetwino
char serInString[25]; // used for Gobetwino
LiquidCrystal lcd(12, 11, 8, 7, 6, 5);
PID myPID(&temperature, &output, &settemperature,2.5,0.2,0, DIRECT); // Kp,Ki,Kd values generated from autotune sketch run previously
/*
10 Mosfet pwm drive pin for heater
*/
enum stat {
INITIALISING,
WAITING,
RUNNING,
BUSY
};
stat Status;
float getTemp ()
{
float tempTemp;
int aRead=0;
int span=5;
// Temperature is so noisy, this damps it down
for (int i=1; i< span; i++) {
aRead = aRead + analogRead(columnTempSensor);
}
//tempTemp=(5.0 * aRead *100) /1024;
tempTemp=(aRead* 0.4882812) /5;
return (tempTemp); //convert voltage to temperature
}
void controlTemp() {
// runs PID controller to keep temperature constant
}
int readLDR () {
int numReadings=10;
int rawLight=0;
for (int i=0; i<numReadings; i++) {
rawLight=rawLight + analogRead(detectorLDR);
}
rawLight=rawLight/numReadings;
return (rawLight);
}
void changeStatus()
{
Status=RUNNING;
runFlag=1;
}
// Prints data to console, incsv, where it can be picked up by mouse and fed into excel
void logData( long unsigned value1, int value2, float value3 )
{
Serial.print(value1);
Serial.print(",");
Serial.print(value2);
Serial.print(",");
Serial.println(value3);
// readSerialString(serInString,1000);
// There ought to be a check here for a non 0 return value indicating an error and some error handeling
}
//read a string from the serial and store it in an array
//you must supply the array variable - return if timeOut ms passes before the sting is read
void readSerialString (char *strArray,long timeOut)
{
long startTime=millis();
int i;
while (!Serial.available()) {
if (millis()-startTime >= timeOut) {
return;
}
}
while (Serial.available() && i < serInLen) {
strArray[i] = Serial.read();
i++;
}
}
void flashWaitStatus ()
{
digitalWrite(readyLED, flashpin);
digitalWrite(busyLED,0);
flashpin = !flashpin;
}
void flashBusyStatus ()
{
digitalWrite(readyLED, flashpin);
digitalWrite(busyLED, flashpin);
flashpin = !flashpin;
}
void flashRunStatus ()
{
digitalWrite(busyLED, flashpin);
digitalWrite(readyLED, 0);
flashpin = !flashpin;
serviceInterrupt=1;
}
void servicePID() {
temperature=double(getTemp());
myPID.Compute();
analogWrite(mosfetDrive, output);
}
void setup()
{
// Set initial welcome message
lcd.begin(16, 2);
// Print Banner
lcd.print("G Chromatograph");
lcd.setCursor(0, 1);
lcd.print("by L Harris V");
lcd.print(version);
delay(2000);
lcd.clear();
Status = INITIALISING;
pinMode(readyLED, OUTPUT);
pinMode(busyLED, OUTPUT);
pinMode(mosfetDrive,OUTPUT); // setup pin 9 for pwm
attachInterrupt(0, changeStatus, CHANGE); // interupt 0 sits on pin D2
Serial.begin(9600);
Serial.print("Gas Chromatograph version " );
Serial.println(version);
// set up column temperature
epromTemperature = double(EEPROM.read(epromaddy)); // get the last stored temp
settemperature = epromTemperature;
while (Status==INITIALISING){
int button=0; // initial value for inc and dec buttons
lcd.setCursor(0, 0);
lcd.print("temp? press both");
lcd.setCursor(0, 1);
lcd.print ("to save)");
lcd.setCursor(12, 1);
lcd.print(settemperature);
button=analogRead(setButtons);
if (button != 0) {
if (button > 500 && button < 530) { // down pressed
settemperature -=1;
delay(200); // for debounce
}
else if (button > 250 && button < 300) { // up pressed
settemperature +=1;
delay(200);
}
else if ( button > 580 && button < 600) { //both pressed - save
Status=BUSY;
if (settemperature != epromTemperature) {
EEPROM.write(epromaddy,settemperature);
}
}
}
}
lcd.clear();
lcd.print("set temp =");
lcd.print(settemperature);
lcd.print(" oC");
lcd.setCursor(0, 1);
lcd.print("warming column");
//create a pid object to control the column temperature
myPID.SetMode(AUTOMATIC);
Status = BUSY;
FlexiTimer2::set(500, flashBusyStatus); // 500ms period
FlexiTimer2::start();
// just lock us out until the column heats up
while (Status == BUSY) {
servicePID();
if (temperature > settemperature ){
Status = WAITING;
FlexiTimer2::stop();
FlexiTimer2::set(500, flashWaitStatus); // 500ms period
FlexiTimer2::start();
lcd.clear();
lcd.print("column= ");
lcd.print(temperature);
lcd.print(" oC");
lcd.setCursor(0, 1);
lcd.print("Press run");
lcd.blink(); // wants input from us, so blink
}
Serial.println(temperature);
}
Serial.println("we have reached column temp");
}
void loop()
{
while (Status==WAITING) {
servicePID();
if ( runFlag == 1) {
Serial.print("column temperature is ");
Serial.println(temperature);
Serial.print("photodetector reading is ");
Serial.println(readLDR());
runFlag=0;
}
/*digitalWrite(readyLED,HIGH);
delay(500);
digitalWrite(readyLED, LOW);
delay(500);
*/
}
if (runFlag==1) {
runFlag=0;
startTime=millis();
FlexiTimer2::stop();
flashpin=0;
flashWaitStatus();
FlexiTimer2::set(1000, flashRunStatus); // 500ms period
FlexiTimer2::start();
lcd.noBlink(); // doesn't want anything, so stop blinking
while (Status == RUNNING)
{
//main running loop goes here
//wait 1 sec
//read ldr
//read temp
if (serviceInterrupt ==1 ){
time=(millis()-startTime)/1000;
temperature=double(getTemp());
photoDetector=readLDR();
logData(time, photoDetector, temperature);
lcd.clear();
lcd.print("temp=");
lcd.print(temperature);
lcd.print(" oC");
lcd.setCursor(0, 1);
lcd.print("detector=");
lcd.print(photoDetector);
lcd.print(" units");
serviceInterrupt=0;
}
servicePID();
//log time since start, ldr, and temp to csv file via Gobetweeno
// later write time and ldr to lcd
//do it all again until status is stopped
}
}
}