summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--pcrFinal.ino323
1 files changed, 323 insertions, 0 deletions
diff --git a/pcrFinal.ino b/pcrFinal.ino
new file mode 100644
index 0000000..760b0f2
--- /dev/null
+++ b/pcrFinal.ino
@@ -0,0 +1,323 @@
+#include <max6675.h>
+
+/* PCR code to cycle temperatures for denaturing, annealing and extending DNA.
+Stacey Kuznetsov (stace@cmu.edu) and Matt Mancuso (mcmancuso@gmail.com)
+July 2012
+
+
+*** All temperatures at in degrees Celcius.
+*/
+
+
+/* PCR VARIABLES*/
+double DENATURE_TEMP = 94;
+double ANNEALING_TEMP = 60.00;
+double EXTENSION_TEMP = 72;
+
+// Phase durations in ms. I suggest adding 3-5 seconds to
+// the recommended times because it takes a second or two
+// for the temps to stabilize
+unsigned int DENATURE_TIME = 33000;
+unsigned int ANNEALING_TIME= 33000;
+unsigned int EXTENSION_TIME = 35000;
+
+// Most protocols suggest having a longer denature time during the first cycle
+// and a longer extension time for the final cycle.
+unsigned int INITIAL_DENATURE_TIME = 300000;
+unsigned int FINAL_EXTENSION_TIME = 600000;
+
+// how many cycles we should do. (most protocols recommend 32-35)
+int NUM_CYCLES = 32;
+
+/* Hardware variables */
+int heatPin = 7; // pin that controls the relay w resistors
+
+// Thermocouple pins
+int thermoDO = 4;
+int thermoCS = 5;
+int thermoCLK = 6;
+MAX6675 thermocouple(thermoCLK, thermoCS, thermoDO);
+
+
+int fanPin = 9; // pin for controling the fan
+
+
+//safety vars
+short ROOM_TEMP = 18; // if initial temp is below this, we assume thermocouple is diconnected or not working
+short MAX_ALLOWED_TEMP = 100; // we never go above 100C
+double MAX_HEAT_INCREASE = 2.5; // we never increase the temp by more than 2.5 degrees per 650ms
+
+
+/* stuff that the program keeps track of */
+short CURRENT_CYCLE = 0; // current cycle (kept track by the program)
+
+// current phase. H-> heating up
+char CURRENT_PHASE='H';
+
+unsigned long time; // used to track how long program is running
+double curTemp; // current temperature
+
+
+/* Print out current phase, temperature, how long it's been running, etc
+startTime -> when specific phase started running in ms
+*/
+void printTempStats(unsigned long startTime) {
+
+ unsigned long timeElapsed = millis() - startTime;
+ Serial.print("CCL:");
+ Serial.print(CURRENT_CYCLE);
+ Serial.print(" PHS:");
+ Serial.print(CURRENT_PHASE);
+ Serial.print(" ET:");
+ Serial.print(timeElapsed);
+ Serial.print(" TT:");
+ Serial.print(millis());
+ Serial.print(" TMP:");
+ Serial.println(curTemp);
+}
+
+/* Heat up to the desired temperature.
+maxTemp-> Temperature we should heat up to
+printTemps -> whether or not we should print debug stats
+*/
+boolean heatUp(double maxTemp, boolean printTemps = true){
+ unsigned long startTime = millis();
+ double prevTemp = thermocouple.readCelsius();
+ curTemp = thermocouple.readCelsius();
+ if (curTemp < ROOM_TEMP) {
+ Serial.println("STARTING TMP TOO LOW");
+ Serial.println(prevTemp);
+ return false;
+ }
+ int curIteration = 0;
+
+ while (curTemp < maxTemp) {
+ curIteration++;
+ int pulseDuration = min(650, ((600*(maxTemp-curTemp))+80)); // as we approach desired temp, heat up slower
+ digitalWrite(heatPin, HIGH);
+ delay(pulseDuration);
+ digitalWrite(heatPin, LOW);
+
+ curTemp=thermocouple.readCelsius();
+ if(curTemp >= maxTemp)
+ break;
+ if(printTemps) {
+ printTempStats(startTime);
+ }
+
+ if((maxTemp-curTemp) < 1 || curIteration % 30 == 0) {
+ // as we approach desired temperature, wait a little bit longer between heat
+ // cycles to make sure we don't overheat. It takes a while for heat to transfer
+ // between resistors and heating block. As a sanity check, also do this every 20
+ // iterations to make sure we're not overheating
+ do {
+ prevTemp = curTemp;
+ delay(250);
+ curTemp = thermocouple.readCelsius();
+ } while(curTemp > prevTemp);
+ }
+
+ if(curTemp >= maxTemp)
+ break;
+
+ if ((curIteration%2) == 0) {
+ if(curTemp < (prevTemp-1.25)) {
+ Serial.print("Temperature is not increasing... ");
+ Serial.print(curTemp);
+ Serial.print(" ");
+ Serial.println(prevTemp);
+ return false;
+ }
+ } else {
+ prevTemp = curTemp;
+ }
+
+ while ((curTemp-prevTemp) >= MAX_HEAT_INCREASE) {
+ prevTemp = curTemp;
+ Serial.print("HEATING UP TOO FAST! ");
+ delay(1000);
+ curTemp = thermocouple.readCelsius();
+ Serial.println(curTemp);
+ }
+
+ while(curTemp >= MAX_ALLOWED_TEMP) {
+ delay(1000);
+ Serial.print("OVERHEATING");
+ Serial.println(curTemp);
+ }
+
+ }
+ return true;
+}
+
+
+/* Cool down to the desired temperature by turning on the fan.
+minTemp-> Temperature we want to cool off to
+maxTimeout -> how often we poll the thermocouple (300ms is good)
+printTemps -> whether or not to print out stats
+*/
+void coolDown(double minTemp, int maxTimeout = 300, boolean printTemps = true) {
+ unsigned long startTime = millis();
+ while ((curTemp = thermocouple.readCelsius()) > (minTemp+0.75)) {
+ // I've found that turning off the fan a bit before the minTemp is reached
+ // is best (because fan blades continue to rotate even after fan is turned off.
+ digitalWrite(fanPin, HIGH);
+ if(printTemps) {
+ printTempStats(startTime);
+ }
+ delay(maxTimeout);
+ }
+ digitalWrite(fanPin, LOW);
+}
+
+
+/*
+Try to stay close to the desired temperature by making micro adjustments to the
+resistors and fan. Assumes that the current temperature is already very close
+to the idealTemp.
+idealTemp -> desired temperature
+duration -> how long we should keep the temperature (in ms)
+*/
+boolean holdConstantTemp(long duration, double idealTemp) {
+ unsigned long startTime = millis();
+ long timeElapsed = millis() - startTime;
+ // keep track of how much time passed
+ while (timeElapsed < duration) {
+ curTemp = thermocouple.readCelsius();
+ printTempStats(startTime);
+ if(curTemp < idealTemp) {
+ // turn up the heat for 90ms if the temperature is cooler
+ digitalWrite(heatPin, HIGH);
+ delay(90);
+ digitalWrite(heatPin, LOW);
+ } else if (curTemp > (idealTemp+0.5)) {
+ // turn up the fan if the temp is too high
+ // generally if temp is within 0.5degrees, don't use the fan
+ // waiting for the temp to cool naturally seems to be more stable
+ digitalWrite(fanPin, HIGH);
+ delay(90);
+ digitalWrite(fanPin, LOW);
+ }
+ delay(210);
+ timeElapsed = millis() - startTime;
+ }
+ return true;
+}
+
+/* Execute the desired number of PCR cycles.
+*/
+void runPCR() {
+ for (; cycles < NUM_CYCLES; cycles++) {
+ CURRENT_CYCLE = cycles;
+ unsigned long cycleStartTime = millis();
+ Serial.print("///CYCLE ");
+ Serial.print(cycles);
+
+ time = millis();
+ Serial.println("HEATING UP");
+ CURRENT_PHASE='H';
+ if(!heatUp(DENATURE_TEMP)){
+ // if unable to heat up, stop
+ Serial.println("Unable to heat up... something is wrong :(");
+ cycles = NUM_CYCLES;
+ break;
+ }
+
+ long dif = millis() - time;
+ Serial.print("***TOTAL HEAT TIME ");
+ Serial.println(dif);
+ Serial.println();
+
+ time = millis();
+ Serial.println("DENATURATION");
+ CURRENT_PHASE='D';
+ if(cycles > 0) {
+ holdConstantTemp(DENATURE_TIME, DENATURE_TEMP);
+ } else {
+ // if this is the first cycles, hold denature temp for longer
+ holdConstantTemp(INITIAL_DENATURE_TIME, DENATURE_TEMP);
+ }
+ Serial.println();
+
+ Serial.println("COOLING");
+ time = millis();
+ CURRENT_PHASE='C';
+ coolDown((ANNEALING_TEMP));
+ dif = millis()-time;
+ Serial.print("***TOTAL COOLING TIME ");
+ Serial.println(dif);
+ Serial.println();
+
+ Serial.println("ANNEALING");
+ time = millis();
+ CURRENT_PHASE='A';
+ holdConstantTemp(ANNEALING_TIME, ANNEALING_TEMP);
+ dif = millis()-time;
+ Serial.print("***TOTAL ANNEALING TIME ");
+ Serial.println(dif);
+ Serial.println();
+
+
+ Serial.println("HEATING UP");
+ time =millis();
+ CURRENT_PHASE='D';
+ heatUp((EXTENSION_TEMP));
+ dif = millis()-time;
+ Serial.print("***TOTAL HEAT UP TIME IS ");
+ Serial.println(dif);
+ Serial.println();
+
+
+ Serial.println("EXTENSION");
+ time = millis();
+ CURRENT_PHASE='E';
+ if (cycles<(NUM_CYCLES-1)) {
+ holdConstantTemp(EXTENSION_TIME, EXTENSION_TEMP);
+ } else {
+ // if this is the last cycle, hold extension temp for longer
+ holdConstantTemp(FINAL_EXTENSION_TIME, EXTENSION_TEMP);
+ }
+ dif = millis()-time;
+ Serial.print("***TOTAL EXTENSION TIME IS ");
+ Serial.println(dif);
+ Serial.println();
+ Serial.println();
+
+ Serial.print("///TOTAL CYCLE TIME: ");
+ Serial.println(millis()-cycleStartTime);
+ Serial.println();
+}
+
+ Serial.println("DONE");
+}
+
+
+/* Set up all pins */
+void setup() {
+
+ Serial.begin(9600);
+
+ pinMode(heatPin, OUTPUT);
+ digitalWrite(heatPin, LOW);
+ pinMode(fanPin, OUTPUT);
+ digitalWrite(fanPin, LOW);
+
+ // time out for 5 seconds.
+ Serial.println("Starting in");
+ for (int i = 5; i > 0; i--) {
+ Serial.print(i);
+ Serial.print("... ");
+ delay(1000);
+ }
+ Serial.println();
+ runPCR();
+}
+
+
+int cycles = 0;
+
+
+void loop() {
+
+ //nothing
+}