mirror of
https://github.com/RobTillaart/Arduino.git
synced 2024-10-03 18:09:02 -04:00
0.3.0 PCR
This commit is contained in:
parent
62230e22d8
commit
4794e6adaf
@ -6,6 +6,19 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/)
|
|||||||
and this project adheres to [Semantic Versioning](http://semver.org/).
|
and this project adheres to [Semantic Versioning](http://semver.org/).
|
||||||
|
|
||||||
|
|
||||||
|
## [0.3.0] - 2024-06-01
|
||||||
|
- breaking change
|
||||||
|
- duration in configuration function to **float seconds** as this is more convenient.
|
||||||
|
- update examples to use seconds.
|
||||||
|
- fix **getHoldTemp()** bug.
|
||||||
|
- fix signature of functions in 0.2.1
|
||||||
|
- clean up code (remove commented sections).
|
||||||
|
- add **PCR_demo_aquarium.ino** example (for fun).
|
||||||
|
- update readme.md
|
||||||
|
- update unit tests
|
||||||
|
|
||||||
|
----
|
||||||
|
|
||||||
## [0.2.1] - 2024-05-31
|
## [0.2.1] - 2024-05-31
|
||||||
- add **setHeatPulseLength(uint16_t len)** to modify the pulse length of the heater / cooler.
|
- add **setHeatPulseLength(uint16_t len)** to modify the pulse length of the heater / cooler.
|
||||||
- add example **PCR_demo_DS18B20.ino** DS18B20 for PCR.
|
- add example **PCR_demo_DS18B20.ino** DS18B20 for PCR.
|
||||||
@ -16,11 +29,11 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
|
|||||||
- update readme.md
|
- update readme.md
|
||||||
- minor edits
|
- minor edits
|
||||||
|
|
||||||
|
|
||||||
## [0.2.0] - 2024-05-30
|
## [0.2.0] - 2024-05-30
|
||||||
- initial class version (published)
|
- initial class version (published)
|
||||||
|
|
||||||
----
|
----
|
||||||
|
|
||||||
## [0.1.3] - 2024-05-30
|
## [0.1.3] - 2024-05-30
|
||||||
- initial class version (not published)
|
- initial class version (not published)
|
||||||
|
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
// FILE: PCR.h
|
// FILE: PCR.h
|
||||||
// AUTHOR: Rob Tillaart
|
// AUTHOR: Rob Tillaart
|
||||||
// DATE: 2015-06-10
|
// DATE: 2015-06-10
|
||||||
// VERSION: 0.2.1
|
// VERSION: 0.3.0
|
||||||
// PURPOSE: Arduino library for PCR process control.
|
// PURPOSE: Arduino library for PCR process control.
|
||||||
// URL: https://github.com/RobTillaart/PCR
|
// URL: https://github.com/RobTillaart/PCR
|
||||||
// https://forum.arduino.cc/t/problem-with-arduino-pcr-amplifies-of-dna/314808
|
// https://forum.arduino.cc/t/problem-with-arduino-pcr-amplifies-of-dna/314808
|
||||||
@ -12,7 +12,7 @@
|
|||||||
|
|
||||||
#include "Arduino.h"
|
#include "Arduino.h"
|
||||||
|
|
||||||
#define PCR_LIB_VERSION (F("0.2.1"))
|
#define PCR_LIB_VERSION (F("0.3.0"))
|
||||||
|
|
||||||
enum PCRSTATE {
|
enum PCRSTATE {
|
||||||
PCR_STATE_IDLE = 0,
|
PCR_STATE_IDLE = 0,
|
||||||
@ -40,52 +40,52 @@ public:
|
|||||||
|
|
||||||
|
|
||||||
// PARAMETERS
|
// PARAMETERS
|
||||||
void setInitial(float Celsius, uint32_t ms)
|
void setInitial(float Celsius, float seconds)
|
||||||
{
|
{
|
||||||
_initialTemp = Celsius;
|
_initialTemp = Celsius;
|
||||||
_initialTime = ms;
|
_initialTime = seconds * 1000;
|
||||||
}
|
}
|
||||||
float getInitialTemp() { return _initialTemp; }
|
float getInitialTemp() { return _initialTemp; }
|
||||||
uint32_t getInitialTime() { return _initialTime; }
|
float getInitialTime() { return _initialTime * 0.001; }
|
||||||
|
|
||||||
void setDenature(float Celsius, uint32_t ms)
|
void setDenature(float Celsius, float seconds)
|
||||||
{
|
{
|
||||||
_denatureTemp = Celsius;
|
_denatureTemp = Celsius;
|
||||||
_denatureTime = ms;
|
_denatureTime = seconds * 1000;
|
||||||
}
|
}
|
||||||
float getDenatureTemp() { return _denatureTemp; }
|
float getDenatureTemp() { return _denatureTemp; }
|
||||||
uint32_t getDenatureTime() { return _denatureTime; }
|
float getDenatureTime() { return _denatureTime * 0.001; }
|
||||||
|
|
||||||
void setAnnealing(float Celsius, uint32_t ms)
|
void setAnnealing(float Celsius, float seconds)
|
||||||
{
|
{
|
||||||
_annealingTemp = Celsius;
|
_annealingTemp = Celsius;
|
||||||
_annealingTime = ms;
|
_annealingTime = seconds * 1000;
|
||||||
}
|
}
|
||||||
float getAnnealingTemp() { return _annealingTemp; }
|
float getAnnealingTemp() { return _annealingTemp; }
|
||||||
uint32_t getAnnealingTime() { return _annealingTime; }
|
float getAnnealingTime() { return _annealingTime * 0.001; }
|
||||||
|
|
||||||
void setExtension(float Celsius, uint32_t ms)
|
void setExtension(float Celsius, float seconds)
|
||||||
{
|
{
|
||||||
_extensionTemp = Celsius;
|
_extensionTemp = Celsius;
|
||||||
_extensionTime = ms;
|
_extensionTime = seconds * 1000;
|
||||||
}
|
}
|
||||||
float getExtensionTemp() { return _extensionTemp; }
|
float getExtensionTemp() { return _extensionTemp; }
|
||||||
float getExtensionTime() { return _extensionTime; }
|
float getExtensionTime() { return _extensionTime * 0.001; }
|
||||||
|
|
||||||
void setElongation(float Celsius, uint32_t ms)
|
void setElongation(float Celsius, float seconds)
|
||||||
{
|
{
|
||||||
_elongationTemp = Celsius;
|
_elongationTemp = Celsius;
|
||||||
_elongationTime = ms;
|
_elongationTime = seconds * 1000;
|
||||||
}
|
}
|
||||||
float getElongationTemp() { return _elongationTemp; }
|
float getElongationTemp() { return _elongationTemp; }
|
||||||
float getElongationTime() { return _elongationTime; }
|
float getElongationTime() { return _elongationTime * 0.001; }
|
||||||
|
|
||||||
void setHold(float Celsius) { _holdTemp = Celsius; }
|
void setHold(float Celsius) { _holdTemp = Celsius; }
|
||||||
float getHoldTemp() { return _extensionTemp; }
|
float getHoldTemp() { return _holdTemp; }
|
||||||
|
|
||||||
|
|
||||||
// PROCESS CONTROL
|
// PROCESS CONTROL
|
||||||
void reset(int iterations)
|
void reset(uint16_t iterations)
|
||||||
{
|
{
|
||||||
_startTime = millis();
|
_startTime = millis();
|
||||||
_cycles = iterations;
|
_cycles = iterations;
|
||||||
@ -94,7 +94,7 @@ public:
|
|||||||
debug();
|
debug();
|
||||||
}
|
}
|
||||||
|
|
||||||
int iterationsLeft()
|
uint16_t iterationsLeft()
|
||||||
{
|
{
|
||||||
return _cycles;
|
return _cycles;
|
||||||
}
|
}
|
||||||
@ -104,11 +104,6 @@ public:
|
|||||||
uint8_t process(float temperature)
|
uint8_t process(float temperature)
|
||||||
{
|
{
|
||||||
_temperature = temperature;
|
_temperature = temperature;
|
||||||
/* 0.3.0
|
|
||||||
if (_temperature < temp[_state]) heat();
|
|
||||||
else if (_temperature > temp[_state]) cool();
|
|
||||||
else off();
|
|
||||||
*/
|
|
||||||
switch(_state)
|
switch(_state)
|
||||||
{
|
{
|
||||||
case PCR_STATE_IDLE:
|
case PCR_STATE_IDLE:
|
||||||
@ -190,18 +185,19 @@ public:
|
|||||||
|
|
||||||
|
|
||||||
// HEATER / COOLER CONTROL
|
// HEATER / COOLER CONTROL
|
||||||
|
// ms = timing in milliseconds
|
||||||
void setHeatPulseLength(uint16_t ms = 10)
|
void setHeatPulseLength(uint16_t ms = 10)
|
||||||
{
|
{
|
||||||
if (ms > 1000) ms = 1000;
|
if (ms > 1000) ms = 1000;
|
||||||
_heatPulseLength = ms;
|
_heatPulseLength = ms;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// returns milliseconds.
|
||||||
uint16_t getHeatPulseLength()
|
uint16_t getHeatPulseLength()
|
||||||
{
|
{
|
||||||
return _heatPulseLength;
|
return _heatPulseLength;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void heat()
|
void heat()
|
||||||
{
|
{
|
||||||
digitalWrite(_heatPin, HIGH);
|
digitalWrite(_heatPin, HIGH);
|
||||||
@ -222,26 +218,9 @@ public:
|
|||||||
digitalWrite(_coolPin, LOW);
|
digitalWrite(_coolPin, LOW);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// blocking version of single step.
|
|
||||||
// to be tested what to do with it
|
|
||||||
// could be a separate class / stand alone version.
|
|
||||||
/*
|
|
||||||
void keepTempTime(float temperature, uint32_t ms, float (*getTemp)())
|
|
||||||
{
|
|
||||||
_startTime = millis();
|
|
||||||
_temperature = temperature;
|
|
||||||
while (millis() - _startTime < ms)
|
|
||||||
{
|
|
||||||
if (getTemp() < _temperature ) heat();
|
|
||||||
else if (getTemp() > _temperature) cool();
|
|
||||||
else off();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
// estimator timeLeft, assumes process is not stopped.
|
// estimator timeLeft, assumes process is not stopped.
|
||||||
uint32_t timeLeft()
|
// returns value in seconds
|
||||||
|
float timeLeft()
|
||||||
{
|
{
|
||||||
uint32_t sum = 0;
|
uint32_t sum = 0;
|
||||||
if (_state < PCR_STATE_DENATURE) sum += _initialTime;
|
if (_state < PCR_STATE_DENATURE) sum += _initialTime;
|
||||||
@ -249,7 +228,7 @@ public:
|
|||||||
sum += _annealingTime * _cycles;
|
sum += _annealingTime * _cycles;
|
||||||
sum += _extensionTime * _cycles;
|
sum += _extensionTime * _cycles;
|
||||||
if (_state <= PCR_STATE_ELONGATION) sum += _elongationTime;
|
if (_state <= PCR_STATE_ELONGATION) sum += _elongationTime;
|
||||||
return sum;
|
return sum * 0.001;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -257,12 +236,6 @@ protected:
|
|||||||
// development.
|
// development.
|
||||||
void debug()
|
void debug()
|
||||||
{
|
{
|
||||||
// log for plotting temperature
|
|
||||||
//
|
|
||||||
// Serial.print(_cycles);
|
|
||||||
// Serial.print("\t");
|
|
||||||
// Serial.println(_temperature);
|
|
||||||
|
|
||||||
// log for seeing state transitions.
|
// log for seeing state transitions.
|
||||||
Serial.print(_startTime);
|
Serial.print(_startTime);
|
||||||
Serial.print("\t");
|
Serial.print("\t");
|
||||||
@ -278,16 +251,8 @@ protected:
|
|||||||
else if (_state == PCR_STATE_HOLD) Serial.println("\tHold");
|
else if (_state == PCR_STATE_HOLD) Serial.println("\tHold");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float _initialTemp = 94; // °Celsius
|
||||||
/*
|
uint32_t _initialTime = 0; // milliseconds
|
||||||
// simplify the code. 0.3.0
|
|
||||||
// maybe temperature only?
|
|
||||||
float _temp[6] = { 94, 94, 54, 76, 76, 14 };
|
|
||||||
float _time[6] = { 0, 1, 1, 1, 1, -1 };
|
|
||||||
*/
|
|
||||||
|
|
||||||
float _initialTemp = 94;
|
|
||||||
uint32_t _initialTime = 0;
|
|
||||||
float _denatureTemp = 94;
|
float _denatureTemp = 94;
|
||||||
uint32_t _denatureTime = 1000;
|
uint32_t _denatureTime = 1000;
|
||||||
float _annealingTemp = 54;
|
float _annealingTemp = 54;
|
||||||
@ -303,7 +268,7 @@ protected:
|
|||||||
int _heatPin = 0;
|
int _heatPin = 0;
|
||||||
int _coolPin = 0;
|
int _coolPin = 0;
|
||||||
PCRSTATE _state = PCR_STATE_IDLE;
|
PCRSTATE _state = PCR_STATE_IDLE;
|
||||||
int _cycles = 0;
|
uint16_t _cycles = 0;
|
||||||
uint32_t _startTime = 0;
|
uint32_t _startTime = 0;
|
||||||
uint16_t _heatPulseLength = 10; // milliseconds.
|
uint16_t _heatPulseLength = 10; // milliseconds.
|
||||||
};
|
};
|
||||||
|
@ -19,7 +19,7 @@ Arduino library for PCR process control.
|
|||||||
|
|
||||||
**Experimental**
|
**Experimental**
|
||||||
|
|
||||||
From wikipedia:
|
From Wikipedia:
|
||||||
|
|
||||||
_The polymerase chain reaction (PCR) is a method widely used to make millions to
|
_The polymerase chain reaction (PCR) is a method widely used to make millions to
|
||||||
billions of copies of a specific DNA sample rapidly, allowing scientists to amplify
|
billions of copies of a specific DNA sample rapidly, allowing scientists to amplify
|
||||||
@ -103,10 +103,21 @@ Some examples:
|
|||||||
- control an ice making machine.
|
- control an ice making machine.
|
||||||
|
|
||||||
|
|
||||||
|
#### Breaking change 0.3.0
|
||||||
|
|
||||||
|
Since 0.3.0 the timing of the 6 steps is done in seconds instead of milliseconds.
|
||||||
|
As the steps take up to 15 minutes of more, defining the time in seconds is a more
|
||||||
|
natural order of magnitude than milliseconds.
|
||||||
|
Note however that the internal math still is done in milliseconds so one can define
|
||||||
|
a step as taking 15.75 seconds = 15750 milliseconds.
|
||||||
|
|
||||||
|
Pre 0.3.0 versions are now obsolete.
|
||||||
|
|
||||||
#### Related
|
#### Related
|
||||||
|
|
||||||
- https://en.wikipedia.org/wiki/Polymerase_chain_reaction
|
- https://en.wikipedia.org/wiki/Polymerase_chain_reaction
|
||||||
- https://github.com/RobTillaart/PCR
|
- https://github.com/RobTillaart/PCR
|
||||||
|
- https://github.com/RobTillaart/Temperature scale conversions.
|
||||||
- https://forum.arduino.cc/t/problem-with-arduino-pcr-amplifies-of-dna/314808
|
- https://forum.arduino.cc/t/problem-with-arduino-pcr-amplifies-of-dna/314808
|
||||||
- https://www.scientificamerican.com/article/the-unusual-origin-of-the-polymeras/ (paid site)
|
- https://www.scientificamerican.com/article/the-unusual-origin-of-the-polymeras/ (paid site)
|
||||||
|
|
||||||
@ -121,15 +132,17 @@ Some examples:
|
|||||||
|
|
||||||
- **PCR(uint8_t heatPin, uint8_t coolPin)** constructor defines the hardware pins to which
|
- **PCR(uint8_t heatPin, uint8_t coolPin)** constructor defines the hardware pins to which
|
||||||
the heater and cooler are connected.
|
the heater and cooler are connected.
|
||||||
- **void reset(int iterations)** full stop of the process, also stops heating and cooling,
|
- **void reset(uint16_t iterations)** full stop of the process, also stops heating and cooling,
|
||||||
resets the state to IDLE and defines the number of iterations for the next run.
|
resets the state to IDLE and defines the number of iterations for the next run.
|
||||||
|
The parameter iterations must be >= 0 so it changed to unsigned int in 0.3.0.
|
||||||
- **uint8_t process(float temperature)** The worker core. This function runs the main process
|
- **uint8_t process(float temperature)** The worker core. This function runs the main process
|
||||||
and iterates over the DENATURE, ANNEALING and EXTENSION phase. Returns the current state.
|
and iterates over the DENATURE, ANNEALING and EXTENSION phase. Returns the current state.
|
||||||
The user **MUST** provide the actual temperature of the sample so process can heat and cool
|
The user **MUST** provide the actual temperature of the sample so process can heat and cool
|
||||||
the sample on a need to basis.
|
the sample on a need to basis.
|
||||||
The user **MUST** call this function as often as possible in a tight loop.
|
The user **MUST** call this function as often as possible in a tight loop.
|
||||||
- **int iterationsLeft()** returns the number of iterations left.
|
- **int iterationsLeft()** returns the number of iterations left.
|
||||||
- **uint32_t timeLeft()** estimator of the time left to reach the HOLD state.
|
- **float timeLeft()** estimator of the time left to reach the HOLD state.
|
||||||
|
Since 0.3.0 returns its value in seconds.
|
||||||
This function assumes that the duration per phase does not change runtime,
|
This function assumes that the duration per phase does not change runtime,
|
||||||
however it will adapt its estimate.
|
however it will adapt its estimate.
|
||||||
Returns the value in milliseconds.
|
Returns the value in milliseconds.
|
||||||
@ -137,29 +150,36 @@ Returns the value in milliseconds.
|
|||||||
|
|
||||||
#### About phases
|
#### About phases
|
||||||
|
|
||||||
Temperatures are in °Celsius, timing is in milliseconds (for 0.2.x version).
|
Temperatures are in **°Celsius**, timing is in **seconds** (since 0.3.0 version).
|
||||||
|
|
||||||
The timing is the time that the process will be in this state, so it includes
|
The timing is the time that the process will be in this state, so it includes
|
||||||
the time to heat / cool to reach the temperature defined.
|
the time to heat / cool to reach the temperature defined.
|
||||||
|
The timing parameter is a float so you can use e.g. 10.5 seconds, or even use
|
||||||
|
scientific notation like 1.2e2.
|
||||||
|
In theory the maximum time is 4294967 seconds which is 49.7 days,
|
||||||
|
In practice the phases are much shorter.
|
||||||
|
- 1 hour = 3600 seconds, 1 day = 86400 seconds
|
||||||
|
|
||||||
Note that the parameters of the phases can change while the process is running,
|
Note that the parameters of the phases can change while the process is running,
|
||||||
e.g. one can increase the duration of the extension phase per cycle to give
|
e.g. one can increase the duration of the extension phase per cycle to give
|
||||||
that part of the PCR process more time.
|
that part of the PCR process more time (adjust to concentration?).
|
||||||
|
|
||||||
|
|
||||||
#### 1 Initial phase
|
#### 1 Initial phase
|
||||||
|
|
||||||
This step used in **hot-start PCR** (Wikipedia) to bring the system to starting temperature.
|
This step used in **hot-start PCR** (Wikipedia) to bring the system to starting temperature.
|
||||||
|
|
||||||
- **void setInitial(float Celsius, uint32_t ms)** Sets temperature and duration.
|
- **void setInitial(float Celsius, float seconds)** Sets temperature and duration.
|
||||||
- **float getInitialTemp()** returns set value.
|
- **float getInitialTemp()** returns set value.
|
||||||
- **uint32_t getInitialTime()** returns set value.
|
- **float getInitialTime()** returns set value.
|
||||||
|
|
||||||
#### 2 Denature phase
|
#### 2 Denature phase
|
||||||
|
|
||||||
This step breaks the double DNA helix into two single strands.
|
This step breaks the double DNA helix into two single strands.
|
||||||
|
|
||||||
- **void setDenature(float Celsius, uint32_t ms)** Sets temperature and duration.
|
- **void setDenature(float Celsius, float seconds)** Sets temperature and duration.
|
||||||
- **float getDenatureTemp()** returns set value.
|
- **float getDenatureTemp()** returns set value.
|
||||||
- **uint32_t getDenatureTime()** returns set value.
|
- **float getDenatureTime()** returns set value.
|
||||||
|
|
||||||
#### 3 Annealing phase
|
#### 3 Annealing phase
|
||||||
|
|
||||||
@ -167,16 +187,16 @@ This step let **primers** (Wikipedia) connect to the single strands.
|
|||||||
The primers create a starting point for the replication.
|
The primers create a starting point for the replication.
|
||||||
The temperature and duration depends on many factors, so very specific for the reaction.
|
The temperature and duration depends on many factors, so very specific for the reaction.
|
||||||
|
|
||||||
- **void setAnnealing(float Celsius, uint32_t ms)** Sets temperature and duration.
|
- **void setAnnealing(float Celsius, float seconds)** Sets temperature and duration.
|
||||||
- **float getAnnealingTemp()** returns set value.
|
- **float getAnnealingTemp()** returns set value.
|
||||||
- **uint32_t getAnnealingTime()** returns set value.
|
- **float getAnnealingTime()** returns set value.
|
||||||
|
|
||||||
#### 4 Extension phase
|
#### 4 Extension phase
|
||||||
|
|
||||||
This step extends the primers with **dNTP's** nucleotides (Wikipedia) to complete
|
This step extends the primers with **dNTP's** nucleotides (Wikipedia) to complete
|
||||||
the duplication process.
|
the duplication process.
|
||||||
|
|
||||||
- **void setExtension(float Celsius, uint32_t ms)** Sets temperature and duration.
|
- **void setExtension(float Celsius, float seconds)** Sets temperature and duration.
|
||||||
- **float getExtensionTemp()** returns set value.
|
- **float getExtensionTemp()** returns set value.
|
||||||
- **float getExtensionTime()** returns set value.
|
- **float getExtensionTime()** returns set value.
|
||||||
|
|
||||||
@ -185,7 +205,7 @@ the duplication process.
|
|||||||
This step is used to finalize the remaining DNA strands that are not fully extended
|
This step is used to finalize the remaining DNA strands that are not fully extended
|
||||||
in step 4 Extension phase.
|
in step 4 Extension phase.
|
||||||
|
|
||||||
- **void setElongation(float Celsius, uint32_t ms)** Sets temperature and duration.
|
- **void setElongation(float Celsius, float seconds)** Sets temperature and duration.
|
||||||
- **float getElongationTemp()** returns set value.
|
- **float getElongationTemp()** returns set value.
|
||||||
- **float getElongationTime()** returns set value.
|
- **float getElongationTime()** returns set value.
|
||||||
|
|
||||||
@ -204,8 +224,9 @@ from their own code.
|
|||||||
|
|
||||||
In 0.2.x version the heater / cooler are switched on/off for a short period.
|
In 0.2.x version the heater / cooler are switched on/off for a short period.
|
||||||
This prevent excessive heating or cooling due to not switching of the heater / cooler in time.
|
This prevent excessive heating or cooling due to not switching of the heater / cooler in time.
|
||||||
This pulsed heating cooling makes the process safer and a bit slower to heat up / cool down.
|
This pulsed heating / cooling makes the process safer as after the call it is switched off.
|
||||||
The length of the period can be adjusted between 0 and 1000 milliseconds to increase
|
Drawback is that the pulsed behaviour makes the process a bit slower to heat up / cool down.
|
||||||
|
Therefore the length of the period can be adjusted between 0 and 1000 milliseconds to increase
|
||||||
the efficiency of the process. Be aware that the heat() and cool() will block longer.
|
the efficiency of the process. Be aware that the heat() and cool() will block longer.
|
||||||
|
|
||||||
- **void heat()** Switches off cooler first, and then switches the heater for (default)
|
- **void heat()** Switches off cooler first, and then switches the heater for (default)
|
||||||
@ -213,9 +234,10 @@ the efficiency of the process. Be aware that the heat() and cool() will block lo
|
|||||||
- **void cool()** switch on the cooler for (default) 10 milliseconds. Switches off heater first.
|
- **void cool()** switch on the cooler for (default) 10 milliseconds. Switches off heater first.
|
||||||
- **void off()** switch off both heater and cooler.
|
- **void off()** switch off both heater and cooler.
|
||||||
- **void setHeatPulseLength(uint16_t ms = 10)** adjust the timing for heat() and cool().
|
- **void setHeatPulseLength(uint16_t ms = 10)** adjust the timing for heat() and cool().
|
||||||
- The maximum value is 1000 milliseconds == 1 second.
|
- The maximum value is 1000 milliseconds == 1 second (this limit is to prevent overheating).
|
||||||
- The minimum value is 0 milliseconds but it would slow down the heating / cooling.
|
- The minimum value is 0 milliseconds but it would slow down the heating / cooling.
|
||||||
- warning the heat() and cool() will block for the set period.
|
- Assumption: optimal time == time to increase 0.1°C. This depends on the specific heat.
|
||||||
|
- Warning: the heat() and cool() will block for the set period.
|
||||||
- **uint16_t getHeatPulseLength()** returns set value.
|
- **uint16_t getHeatPulseLength()** returns set value.
|
||||||
|
|
||||||
|
|
||||||
@ -235,8 +257,6 @@ Users can patch this function when needed, or make it empty.
|
|||||||
|
|
||||||
#### Should
|
#### Should
|
||||||
|
|
||||||
- time of phases should be in seconds ==> breaking change
|
|
||||||
- **void setAnnealing(float Celsius, float seconds)** Sets temperature and duration.
|
|
||||||
- investigate the blocking version
|
- investigate the blocking version
|
||||||
- void keepTempTime(temp, time, getTemperature());
|
- void keepTempTime(temp, time, getTemperature());
|
||||||
|
|
||||||
@ -244,17 +264,17 @@ Users can patch this function when needed, or make it empty.
|
|||||||
|
|
||||||
- PCR scripting language, simple example?
|
- PCR scripting language, simple example?
|
||||||
- add examples
|
- add examples
|
||||||
- optimize code
|
|
||||||
- have an array of times and temperatures to go through.
|
|
||||||
- add continuous heating (unsafe mode) versus the current pulsed heating(safe mode).
|
|
||||||
- add stir pin, to control the stirring of the PCR device.
|
- add stir pin, to control the stirring of the PCR device.
|
||||||
- add signalling pin to indicate ready by a buzzer.
|
- add signalling pin to indicate ready by a buzzer.
|
||||||
- add unit tests
|
|
||||||
|
|
||||||
#### Wont
|
#### Wont
|
||||||
|
|
||||||
- add callback function when ready (user can check state)
|
- add callback function when ready (user can check state)
|
||||||
|
- Fahrenheit interface (C = (F-32) x 5/9.0; F = C x 9/5.0 + 32;
|
||||||
|
- Kelvin or other temperature scale.
|
||||||
|
- optimize code
|
||||||
|
- have an array of times and temperatures to go through.
|
||||||
|
- add continuous heating (unsafe mode) versus the current pulsed heating(safe mode).
|
||||||
|
|
||||||
## Support
|
## Support
|
||||||
|
|
||||||
|
@ -51,17 +51,17 @@ void setup()
|
|||||||
sensor.begin();
|
sensor.begin();
|
||||||
sensor.setResolution(10); // 10 bit ==> 0.25 degrees precision
|
sensor.setResolution(10); // 10 bit ==> 0.25 degrees precision
|
||||||
sensor.requestTemperatures();
|
sensor.requestTemperatures();
|
||||||
delay(1000); // wait a second to get a first reading.
|
delay(1000); // wait a second to get a first measurement.
|
||||||
|
|
||||||
|
|
||||||
// configure PCR process
|
// configure PCR process
|
||||||
// adjust timing and temperature to your needs.
|
// adjust timing and temperature to your needs.
|
||||||
pcr.setInitial(98, 10000); // temp, ms
|
pcr.setInitial(98, 10); // temp, seconds
|
||||||
pcr.setDenature(94.5, 5000); // temp, ms
|
pcr.setDenature(94.5, 5); // temp, seconds
|
||||||
pcr.setAnnealing(54.2, 2000); // temp, ms
|
pcr.setAnnealing(54.2, 2); // temp, seconds
|
||||||
pcr.setExtension(75.0, 3000); // temp, ms
|
pcr.setExtension(75.0, 3); // temp, seconds
|
||||||
pcr.setElongation(75.0, 3000); // temp, ms
|
pcr.setElongation(75.0, 5); // temp, seconds
|
||||||
pcr.setHold(8.0); // temp only
|
pcr.setHold(8.0); // temp only
|
||||||
|
|
||||||
pcr.reset(15); // iterations.
|
pcr.reset(15); // iterations.
|
||||||
Serial.print("Estimated time (ms): ");
|
Serial.print("Estimated time (ms): ");
|
||||||
|
@ -46,12 +46,12 @@ void setup()
|
|||||||
|
|
||||||
// configure PCR process
|
// configure PCR process
|
||||||
// adjust timing and temperature to your needs.
|
// adjust timing and temperature to your needs.
|
||||||
pcr.setInitial(98, 10000); // temp, ms
|
pcr.setInitial(98, 10); // temp, seconds
|
||||||
pcr.setDenature(94.5, 5000); // temp, ms
|
pcr.setDenature(94.5, 5); // temp, seconds
|
||||||
pcr.setAnnealing(54.2, 2000); // temp, ms
|
pcr.setAnnealing(54.2, 2); // temp, seconds
|
||||||
pcr.setExtension(75.0, 3000); // temp, ms
|
pcr.setExtension(75.0, 3); // temp, seconds
|
||||||
pcr.setElongation(75.0, 3000); // temp, ms
|
pcr.setElongation(75.0, 3); // temp, seconds
|
||||||
pcr.setHold(8.0); // temp only
|
pcr.setHold(8.0); // temp only
|
||||||
|
|
||||||
pcr.reset(15); // iterations.
|
pcr.reset(15); // iterations.
|
||||||
Serial.print("Estimated time (ms): ");
|
Serial.print("Estimated time (ms): ");
|
||||||
|
@ -0,0 +1,54 @@
|
|||||||
|
//
|
||||||
|
// FILE: PCR_demo_aquarium.ino
|
||||||
|
// AUTHOR: Rob Tillaart
|
||||||
|
// PURPOSE: using PCR class to control temperature in a tropic aquarium
|
||||||
|
// URL: https://github.com/RobTillaart/PCR
|
||||||
|
//
|
||||||
|
// Warning: example takes a day to do one cycle. Adjust timing to see effect.
|
||||||
|
|
||||||
|
|
||||||
|
#include "PCR.h"
|
||||||
|
|
||||||
|
|
||||||
|
PCR pcr(8, 9); // heatPin, coolPin
|
||||||
|
|
||||||
|
|
||||||
|
float getTemperature()
|
||||||
|
{
|
||||||
|
return 30; // dummy, to be elaborated.
|
||||||
|
}
|
||||||
|
|
||||||
|
void setup()
|
||||||
|
{
|
||||||
|
Serial.begin(115200);
|
||||||
|
Serial.println();
|
||||||
|
Serial.println(__FILE__);
|
||||||
|
Serial.print("PCR_LIB_VERSION: ");
|
||||||
|
Serial.println(PCR_LIB_VERSION);
|
||||||
|
Serial.println();
|
||||||
|
|
||||||
|
// split 86400 seconds over three temperature levels
|
||||||
|
pcr.setDenature(32, 23200); // temp, seconds
|
||||||
|
pcr.setAnnealing(29, 43200); // temp, seconds
|
||||||
|
pcr.setExtension(27, 20000); // temp, seconds
|
||||||
|
|
||||||
|
// just one cycle a day.
|
||||||
|
pcr.reset(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void loop()
|
||||||
|
{
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
float temp = getTemperature();
|
||||||
|
pcr.process(temp);
|
||||||
|
// break after a full cycle / day.
|
||||||
|
if (pcr.iterationsLeft() == 0) break;
|
||||||
|
}
|
||||||
|
// do next cycle / day.
|
||||||
|
pcr.reset(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// -- END OF FILE --
|
@ -28,25 +28,25 @@ void setup()
|
|||||||
Serial.println();
|
Serial.println();
|
||||||
|
|
||||||
// configure all phases
|
// configure all phases
|
||||||
pcr[0].setInitial(98, 10000); // temp, ms
|
pcr[0].setInitial(98, 10); // temp, seconds
|
||||||
pcr[0].setDenature(94.5, 5000); // temp, ms
|
pcr[0].setDenature(94.5, 5); // temp, seconds
|
||||||
pcr[0].setAnnealing(54.2, 2000); // temp, ms
|
pcr[0].setAnnealing(54.2, 2); // temp, seconds
|
||||||
pcr[0].setExtension(75.0, 3000); // temp, ms
|
pcr[0].setExtension(75.0, 3); // temp, seconds
|
||||||
pcr[0].setElongation(75.0, 3000); // temp, ms
|
pcr[0].setElongation(75.0, 3); // temp, seconds
|
||||||
pcr[0].setHold(8.0); // temp only
|
pcr[0].setHold(8.0); // temp only
|
||||||
|
|
||||||
pcr[1].setInitial(97, 8000);
|
pcr[1].setInitial(97, 8);
|
||||||
pcr[1].setDenature(94, 4000);
|
pcr[1].setDenature(94, 4);
|
||||||
pcr[1].setAnnealing(54, 2000);
|
pcr[1].setAnnealing(54, 2);
|
||||||
pcr[1].setExtension(70.0, 2000);
|
pcr[1].setExtension(70.0, 2);
|
||||||
pcr[1].setElongation(70.0, 2000);
|
pcr[1].setElongation(70.0, 2);
|
||||||
pcr[1].setHold(8.0);
|
pcr[1].setHold(8.0);
|
||||||
|
|
||||||
pcr[2].setInitial(96, 15000);
|
pcr[2].setInitial(96, 15);
|
||||||
pcr[2].setDenature(93, 8000);
|
pcr[2].setDenature(93, 8);
|
||||||
pcr[2].setAnnealing(53, 4000);
|
pcr[2].setAnnealing(53, 4);
|
||||||
pcr[2].setExtension(75.0, 4000);
|
pcr[2].setExtension(75.0, 4);
|
||||||
pcr[2].setElongation(75.0, 4000);
|
pcr[2].setElongation(75.0, 4);
|
||||||
pcr[2].setHold(8.0);
|
pcr[2].setHold(8.0);
|
||||||
|
|
||||||
pcr[0].reset(15); // iterations.
|
pcr[0].reset(15); // iterations.
|
||||||
|
@ -25,9 +25,9 @@ void setup()
|
|||||||
Serial.println(PCR_LIB_VERSION);
|
Serial.println(PCR_LIB_VERSION);
|
||||||
Serial.println();
|
Serial.println();
|
||||||
|
|
||||||
pcr.setDenature(94.5, 1000); // temp, ms
|
pcr.setDenature(94.5, 1); // temp, seconds
|
||||||
pcr.setAnnealing(54.2, 1000); // temp, ms
|
pcr.setAnnealing(54.2, 2); // temp, seconds
|
||||||
pcr.setExtension(75.0, 1000); // temp, ms
|
pcr.setExtension(75.0, 3); // temp, seconds
|
||||||
|
|
||||||
pcr.reset(5); // iterations.
|
pcr.reset(5); // iterations.
|
||||||
|
|
||||||
|
@ -27,12 +27,12 @@ void setup()
|
|||||||
Serial.println();
|
Serial.println();
|
||||||
|
|
||||||
// configure all phases
|
// configure all phases
|
||||||
pcr.setInitial(98, 10000); // temp, ms
|
pcr.setInitial(98, 10); // temp, seconds
|
||||||
pcr.setDenature(94.5, 5000); // temp, ms
|
pcr.setDenature(94.5, 5); // temp, seconds
|
||||||
pcr.setAnnealing(54.2, 2000); // temp, ms
|
pcr.setAnnealing(54.2, 2); // temp, seconds
|
||||||
pcr.setExtension(75.0, 3000); // temp, ms
|
pcr.setExtension(75.0, 3); // temp, seconds
|
||||||
pcr.setElongation(75.0, 3000); // temp, ms
|
pcr.setElongation(75.0, 5); // temp, seconds
|
||||||
pcr.setHold(8.0); // temp only
|
pcr.setHold(8.0); // temp only
|
||||||
|
|
||||||
pcr.reset(15); // iterations.
|
pcr.reset(15); // iterations.
|
||||||
Serial.print("Estimated time (ms): ");
|
Serial.print("Estimated time (ms): ");
|
||||||
|
@ -27,15 +27,15 @@ void setup()
|
|||||||
Serial.println();
|
Serial.println();
|
||||||
|
|
||||||
// configure all phases
|
// configure all phases
|
||||||
pcr.setInitial(98, 10000); // temp, ms
|
pcr.setInitial(98, 10); // temp, seconds
|
||||||
pcr.setDenature(94.5, 5000); // temp, ms
|
pcr.setDenature(94.5, 5); // temp, seconds
|
||||||
pcr.setAnnealing(54.2, 2000); // temp, ms
|
pcr.setAnnealing(54.2, 2); // temp, seconds
|
||||||
pcr.setExtension(75.0, 3000); // temp, ms
|
pcr.setExtension(75.0, 3); // temp, seconds
|
||||||
pcr.setElongation(75.0, 3000); // temp, ms
|
pcr.setElongation(75.0, 3); // temp, seconds
|
||||||
pcr.setHold(8.0); // temp only
|
pcr.setHold(8.0); // temp only
|
||||||
|
|
||||||
pcr.reset(10); // iterations.
|
pcr.reset(10); // iterations.
|
||||||
Serial.print("Estimated time (ms): ");
|
Serial.print("Estimated time (seconds): ");
|
||||||
Serial.println(pcr.timeLeft());
|
Serial.println(pcr.timeLeft());
|
||||||
|
|
||||||
bool flagFive = false;
|
bool flagFive = false;
|
||||||
@ -48,10 +48,10 @@ void setup()
|
|||||||
if ((pcr.iterationsLeft() == 5) && (flagFive == false))
|
if ((pcr.iterationsLeft() == 5) && (flagFive == false))
|
||||||
{
|
{
|
||||||
flagFive = true;
|
flagFive = true;
|
||||||
pcr.setDenature(94.5, 7500); // temp, ms
|
pcr.setDenature(94.5, 7.5); // temp, seconds
|
||||||
pcr.setAnnealing(54.2, 4000); // temp, ms
|
pcr.setAnnealing(54.2, 4.25); // temp, seconds
|
||||||
pcr.setExtension(75.0, 5000); // temp, ms
|
pcr.setExtension(75.0, 5.75); // temp, seconds
|
||||||
Serial.print("Estimated time (ms): ");
|
Serial.print("Estimated time (seconds): ");
|
||||||
Serial.println(pcr.timeLeft());
|
Serial.println(pcr.timeLeft());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/RobTillaart/PCR.git"
|
"url": "https://github.com/RobTillaart/PCR.git"
|
||||||
},
|
},
|
||||||
"version": "0.2.1",
|
"version": "0.3.0",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"frameworks": "*",
|
"frameworks": "*",
|
||||||
"platforms": "*",
|
"platforms": "*",
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
name=PCR
|
name=PCR
|
||||||
version=0.2.1
|
version=0.3.0
|
||||||
author=Rob Tillaart <rob.tillaart@gmail.com>
|
author=Rob Tillaart <rob.tillaart@gmail.com>
|
||||||
maintainer=Rob Tillaart <rob.tillaart@gmail.com>
|
maintainer=Rob Tillaart <rob.tillaart@gmail.com>
|
||||||
sentence=Arduino library for PCR process control.
|
sentence=Arduino library for PCR process control.
|
||||||
|
@ -54,8 +54,82 @@ unittest(test_constructor_parameters)
|
|||||||
{
|
{
|
||||||
PCR pcr(8,9);
|
PCR pcr(8,9);
|
||||||
|
|
||||||
assertEqual(1, 1);
|
pcr.setInitial(94, 50);
|
||||||
// to elaborate configuration.
|
assertEqualFloat(94, pcr.getInitialTemp(), 0.01);
|
||||||
|
assertEqualFloat(50, pcr.getInitialTime(), 0.01);
|
||||||
|
|
||||||
|
pcr.setDenature(93, 30);
|
||||||
|
assertEqualFloat(93, pcr.getDenatureTemp(), 0.01);
|
||||||
|
assertEqualFloat(30, pcr.getDenatureTime(), 0.01);
|
||||||
|
|
||||||
|
pcr.setAnnealing(54, 40);
|
||||||
|
assertEqualFloat(54, pcr.getAnnealingTemp(), 0.01);
|
||||||
|
assertEqualFloat(40, pcr.getAnnealingTime(), 0.01);
|
||||||
|
|
||||||
|
pcr.setExtension(75, 60);
|
||||||
|
assertEqualFloat(75, pcr.getExtensionTemp(), 0.01);
|
||||||
|
assertEqualFloat(60, pcr.getExtensionTime(), 0.01);
|
||||||
|
|
||||||
|
pcr.setElongation(74, 90);
|
||||||
|
assertEqualFloat(74, pcr.getElongationTemp(), 0.01);
|
||||||
|
assertEqualFloat(90, pcr.getElongationTime(), 0.01);
|
||||||
|
|
||||||
|
pcr.setHold(17);
|
||||||
|
assertEqualFloat(17, pcr.getHoldTemp(), 0.01);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
unittest(test_constructor_iterations)
|
||||||
|
{
|
||||||
|
PCR pcr(8,9);
|
||||||
|
|
||||||
|
assertEqual(0, pcr.iterationsLeft());
|
||||||
|
for (int i = 1; i < 10; i++)
|
||||||
|
{
|
||||||
|
pcr.reset(i);
|
||||||
|
assertEqual(i, pcr.iterationsLeft());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
unittest(test_constructor_heat_pulse_length)
|
||||||
|
{
|
||||||
|
PCR pcr(8,9);
|
||||||
|
|
||||||
|
assertEqual(10, pcr.getHeatPulseLength());
|
||||||
|
for (int i = 10; i <= 100; i+= 10)
|
||||||
|
{
|
||||||
|
pcr.setHeatPulseLength(i);
|
||||||
|
assertEqual(i, pcr.getHeatPulseLength());
|
||||||
|
}
|
||||||
|
// test constrain
|
||||||
|
pcr.setHeatPulseLength(5000);
|
||||||
|
assertEqual(1000, pcr.getHeatPulseLength());
|
||||||
|
|
||||||
|
pcr.setHeatPulseLength();
|
||||||
|
assertEqual(10, pcr.getHeatPulseLength());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
unittest(test_constructor_timeLeft)
|
||||||
|
{
|
||||||
|
PCR pcr(8,9);
|
||||||
|
|
||||||
|
assertEqualFloat(1, pcr.timeLeft(), 0.01);
|
||||||
|
|
||||||
|
pcr.setInitial(94, 50);
|
||||||
|
pcr.setDenature(93, 30);
|
||||||
|
pcr.setAnnealing(54, 40);
|
||||||
|
pcr.setExtension(75, 60);
|
||||||
|
pcr.setElongation(74, 90);
|
||||||
|
pcr.setHold(17);
|
||||||
|
|
||||||
|
// note: zero cycles
|
||||||
|
assertEqualFloat(140, pcr.timeLeft(), 0.1);
|
||||||
|
|
||||||
|
pcr.reset(10);
|
||||||
|
assertEqualFloat(1440, pcr.timeLeft(), 0.1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user