diff options
-rw-r--r-- | pcrFinal.ino | 323 |
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 +} |