PCR thermocycler

Hi I am trying to make a PCR thermocycler based on this project link:

I am currently basing the project off of this circuit:

The goal of the device is essentially have resistors heat up based on the cycle code, heating using a relay controlled by an Arduino Uno and cooling with a 5V fan.
The project code is based on the MAX6675 library, compiles, and so far I would think its functional.
The issue is that the project will only ever give "C= 0" on the serial monitor, and both the heater or fan won't run. I have tried different approaches to solve this, including changing the thermocouple, however it always reads the same. I feel like i am wiring something incorrectly to stop any data and maybe messing up the ground loop, but I'm currently at a loss. I have double checked that nothing is fried.

I also checked my fan wiring on the transistor referencing this forum:

If someone could give some guidance on the transistor wiring and ground connections I would be grateful.


Sorry for the long post.

Low hanging fruit, but there is no base resistor on the transistor. In the diagram, that is...

Well, it's hard to guess what changes you made... it's hard to advise, not knowing the circuit. :slight_smile:

missing.

The optocoupler/AC relay LED requires a current limiting resistor (if not built in), as well as the transistor. You will burn out port pins with that circuit.

That is a terrible tutorial, which is pretty typical of Instructables. The people running that crap show don't allow "critical comments", so individual authors are free to advise people how to destroy their equipment.

Sorry! Here we are.

#include <MAX6675.h>
#include <SPI.h>
#include <Adafruit_MAX31855.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 in degrees Celcius.
*/


/* PCR VARIABLES*/
double DENATURE_TEMP = 94;
double ANNEALING_TEMP = 54.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 long int INITIAL_DENATURE_TIME = 300000;
unsigned long int FINAL_EXTENSION_TIME = 600000;

// how many cycles we should do. (most protocols recommend 32-35)
int NUM_CYCLES = 34;  
 
/* Hardware variables */
int heatPin = 7;  // pin that controls the relay w resistors

// Thermocouple pins
int thermoDO = 3;
int thermoCS = 4;
int thermoCLK = 5;

Adafruit_MAX31855 thermocouple(thermoCLK, thermoCS, thermoDO);


int fanPin = 9; // pin for controling the fan

/* LED Pins */
int denaturePin = 10;
int annealingPin = 11;
int extensionPin = 12;
int statusPin = 13;
 
//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 setup() {
  Serial.begin(9600);
 
  
  while (!Serial) delay(1); // wait for Serial on Leonardo/Zero, etc

  Serial.println("MAX31855 test");
  // wait for MAX chip to stabilize
  delay(500);
  Serial.print("Initializing sensor...");
  if (!thermocouple.begin()) {
    Serial.println("ERROR.");
    while (1) delay(10);
  }
  Serial.println("DONE.");


 
}

void loop() {
  // basic readout test, just print the current temp
   Serial.print("Internal Temp = ");
   Serial.println(thermocouple.readInternal());

   double c = thermocouple.readCelsius();
   if (isnan(c)) {
     Serial.println("Something wrong with thermocouple!");
   } else {
     Serial.print("C = ");
     Serial.println(c);
   }
   Serial.print("F = ");
   Serial.println(thermocouple.readFahrenheit());

   delay(1000);
}


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 (int cycles = 0; 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");
  digitalWrite(denaturePin, HIGH); // turn denature LED on
    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();
  digitalWrite(denaturePin, LOW); // turn denature LED off
  
    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");
  digitalWrite(annealingPin, HIGH); // turn denature LED on
    time = millis();
    CURRENT_PHASE='A';
    holdConstantTemp(ANNEALING_TIME, ANNEALING_TEMP);
    dif = millis()-time;
    Serial.print("***TOTAL ANNEALING TIME ");
    Serial.println(dif);
    Serial.println();
  digitalWrite(annealingPin, LOW); // turn denature LED off
    
    
    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");
  digitalWrite(extensionPin, HIGH); // turn denature LED on
    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();
  digitalWrite(extensionPin, LOW); // turn denature LED off
    
    Serial.print("///TOTAL CYCLE TIME: ");
    Serial.println(millis()-cycleStartTime);
    Serial.println();
  } 
    
  Serial.println("DONE");
  digitalWrite(statusPin, LOW); // turn status LED off
}


/* Set up all pins */



int cycles = 0;

Thank you so much for this clarification. I figured it was something with the Digital pin wiring since there was an issue with the fan/thermocouple/relay communication. It looks like the pins aren't burnt out just yet, so I will give this another shot! I'm learning the best I can too so I suppose I overlooked any skepticism of the tutorial.
I will be ordering more resistors and am thinking 1k for the thermocycle pin, and 560 ohm for the relay, feel free to let me know if that should be changed.

Post a link to the SSR/AC relay you have, and we can tell you if it needs a current limiting resistor.

The transistor MUST have one: 1K or 470 Ohms would be fine for a fan. If the fan doesn't run, it seems likely that you did not connect all the grounds, like the 12V negative to Arduino and emitter GND (not shown on that miserable schematic).

The unenclosed heater resistors connect directly to the AC line, which presents a deadly electrical hazard on equipment being used near water or with aqueous samples. That would never meet public safety standards, anywhere.

Link please.
He/she must be stopped from spreading misinformation.

Normally you add a diode across an inductive load (solenoid/fan/etc.), but in this case (comuter fan) I don't think it's needed, because of the electronics inside the fan. No harm done if you still add one.

The missing base current limiting resistor is a problem. That will burn out the Arduino pin.
1k should be ok for a TIP120 and a ~300mA fan.

The SSR I see already has a resistor built-in, so don't add another one.
Leo..

Here is the current relay I have:

The unenclosed heater resistors connect directly to the AC line, which presents a deadly electrical hazard on equipment being used near water or with aqueous samples. That would never meet public safety standards, anywhere.

My initial thought was to use an inductor coil relay, instead of heating up resistors which does provide some anxiety. I figured this would be best for the circuit, especially considering I would only be heating a microcentrifuge tube.

Thanks so much for your input!

Thanks so much! I have more 1k resistors on the way and I figured it would work considering its going to provide 5v to the fan. I have worked with solenoids a lot before so I suppose I am more used to using a diode as a precaution, and I appreciate the information.

Will do. I got the same SSR relay and was working with that. Thanks so much!

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.