![](/media/cache/img/default_profile.jpg.50x50_q85.jpg)
Temperature calibration control program
main.cpp@0:147db0900012, 2019-06-24 (annotated)
- Committer:
- justinbuckland
- Date:
- Mon Jun 24 08:48:22 2019 +0000
- Revision:
- 0:147db0900012
- Child:
- 1:68515313ce3e
Initial version; 3-point calibration
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
justinbuckland | 0:147db0900012 | 1 | #include "mbed.h" |
justinbuckland | 0:147db0900012 | 2 | |
justinbuckland | 0:147db0900012 | 3 | // thermal cycling settings |
justinbuckland | 0:147db0900012 | 4 | #define N_CYCLES 40 // number of thermal cycles (ramp-hold-ramp-hold) |
justinbuckland | 0:147db0900012 | 5 | #define R_SETPOINT_LOW 2.129 // heater resistance at low temp |
justinbuckland | 0:147db0900012 | 6 | #define T_LOW_RAMP 0 // low temperature ramp time (ms) |
justinbuckland | 0:147db0900012 | 7 | #define T_LOW_HOLD 30000 // low temperature hold time (ms) |
justinbuckland | 0:147db0900012 | 8 | #define R_SETPOINT_MID 2.211 // heater resistance at mid temp |
justinbuckland | 0:147db0900012 | 9 | #define T_MID_RAMP 0 // mid temperature ramp time (ms) |
justinbuckland | 0:147db0900012 | 10 | #define T_MID_HOLD 0 // mid temperature hold time (ms) |
justinbuckland | 0:147db0900012 | 11 | #define R_SETPOINT_HIGH 2.35 // heater resistance at high temp |
justinbuckland | 0:147db0900012 | 12 | #define T_HIGH_RAMP 0 // high temperaure ramp time (ms) |
justinbuckland | 0:147db0900012 | 13 | #define T_HIGH_HOLD 10000 // high temperature time (ms) |
justinbuckland | 0:147db0900012 | 14 | #define T_HIGH_START 60000 // hotstart time(ms) |
justinbuckland | 0:147db0900012 | 15 | #define R_LYSE 1.99 // lyse temperature setpoint |
justinbuckland | 0:147db0900012 | 16 | #define T_LYSE 0 // lyse time (ms) |
justinbuckland | 0:147db0900012 | 17 | #define R_RT 2.3 // RT temperature setpoint |
justinbuckland | 0:147db0900012 | 18 | #define T_RT 300000 // RT time (ms) |
justinbuckland | 0:147db0900012 | 19 | #define T_FLUIDICS 0 // nominal time for fluidics post lyse |
justinbuckland | 0:147db0900012 | 20 | #define T_HOLD 60000 |
justinbuckland | 0:147db0900012 | 21 | #define T_RAMP 15000 |
justinbuckland | 0:147db0900012 | 22 | |
justinbuckland | 0:147db0900012 | 23 | #define T_FORM_DSNA 0 // form dsna post thermocycling |
justinbuckland | 0:147db0900012 | 24 | #define R_FORM_DSNA 2.8 // temperature to form dsna post thermocycling |
justinbuckland | 0:147db0900012 | 25 | |
justinbuckland | 0:147db0900012 | 26 | #define T_MELT_CURVE 50000 // melt curve ramp time |
justinbuckland | 0:147db0900012 | 27 | #define R_MELT_LOW 1.82 // low end melt curve temperature |
justinbuckland | 0:147db0900012 | 28 | #define R_MELT_HIGH 2.08 // high end melt curve temperature |
justinbuckland | 0:147db0900012 | 29 | |
justinbuckland | 0:147db0900012 | 30 | // temperature measurement settings |
justinbuckland | 0:147db0900012 | 31 | #define N_SAMPLES 1 // number of samples to acquire for I and V measurements |
justinbuckland | 0:147db0900012 | 32 | #define N_ROLL_AVG 10 // rolling average for R values |
justinbuckland | 0:147db0900012 | 33 | #define PULSE_WIDTH 5000 // heat or cool pulse width (us) |
justinbuckland | 0:147db0900012 | 34 | #define MEAS_DELAY 50 // measurement delay after turning on FET (us) |
justinbuckland | 0:147db0900012 | 35 | #define CAM_TRIG 20 // camera trigger pulse width (us) |
justinbuckland | 0:147db0900012 | 36 | #define LOG_INTERVAL 500 // log file interval (ms) |
justinbuckland | 0:147db0900012 | 37 | |
justinbuckland | 0:147db0900012 | 38 | // ADC channels to read |
justinbuckland | 0:147db0900012 | 39 | #define CH_A 1 // value of convst bus to read channel A only |
justinbuckland | 0:147db0900012 | 40 | #define CH_AC 5 // value of convst bus to read channels A and C |
justinbuckland | 0:147db0900012 | 41 | #define CH_ABCD 15 // value of convst bus to read all chanels simultaneously |
justinbuckland | 0:147db0900012 | 42 | |
justinbuckland | 0:147db0900012 | 43 | Serial pc(USBTX, USBRX); // tx, rx |
justinbuckland | 0:147db0900012 | 44 | |
justinbuckland | 0:147db0900012 | 45 | DigitalOut drive(p21); // drive FET |
justinbuckland | 0:147db0900012 | 46 | DigitalOut yLED(p27); // yellow LED (drive on) |
justinbuckland | 0:147db0900012 | 47 | DigitalOut gLED(p28); // green LED (power on) |
justinbuckland | 0:147db0900012 | 48 | DigitalOut rLED(p26); // red LED (thermocycling in progress) |
justinbuckland | 0:147db0900012 | 49 | DigitalOut mbedIO(p25); // MBED IO |
justinbuckland | 0:147db0900012 | 50 | DigitalOut camTrig(p24); // trigger camera |
justinbuckland | 0:147db0900012 | 51 | |
justinbuckland | 0:147db0900012 | 52 | AnalogIn battVolt(p19); |
justinbuckland | 0:147db0900012 | 53 | AnalogIn auxVolt(p20); |
justinbuckland | 0:147db0900012 | 54 | |
justinbuckland | 0:147db0900012 | 55 | BusOut convt(p11, p12, p13, p14); |
justinbuckland | 0:147db0900012 | 56 | SPI spi(p5, p6, p7); // mosi, miso, sclk |
justinbuckland | 0:147db0900012 | 57 | DigitalOut cs(p8); // chip select |
justinbuckland | 0:147db0900012 | 58 | DigitalIn busy(p9); |
justinbuckland | 0:147db0900012 | 59 | DigitalOut reset(p10); |
justinbuckland | 0:147db0900012 | 60 | DigitalIn userButton(p16); |
justinbuckland | 0:147db0900012 | 61 | Timer timer; |
justinbuckland | 0:147db0900012 | 62 | LocalFileSystem local("local"); |
justinbuckland | 0:147db0900012 | 63 | |
justinbuckland | 0:147db0900012 | 64 | FILE *fp = fopen("/local/TEST_LOG.csv", "w"); // Open "test_log" on the local file system for writing |
justinbuckland | 0:147db0900012 | 65 | |
justinbuckland | 0:147db0900012 | 66 | float r = 0; |
justinbuckland | 0:147db0900012 | 67 | float r1 = 0; |
justinbuckland | 0:147db0900012 | 68 | float r2 = 0; |
justinbuckland | 0:147db0900012 | 69 | float rAvg = 0; |
justinbuckland | 0:147db0900012 | 70 | float rAcc = 0; |
justinbuckland | 0:147db0900012 | 71 | float rSet; |
justinbuckland | 0:147db0900012 | 72 | |
justinbuckland | 0:147db0900012 | 73 | int nAcc = 0; |
justinbuckland | 0:147db0900012 | 74 | int eTime; |
justinbuckland | 0:147db0900012 | 75 | int logTime = 0; |
justinbuckland | 0:147db0900012 | 76 | int iCycle = 0; |
justinbuckland | 0:147db0900012 | 77 | |
justinbuckland | 0:147db0900012 | 78 | char outString[100]; |
justinbuckland | 0:147db0900012 | 79 | |
justinbuckland | 0:147db0900012 | 80 | char buffer16[16]; |
justinbuckland | 0:147db0900012 | 81 | int val_array[8]; |
justinbuckland | 0:147db0900012 | 82 | const char dummy = 0; |
justinbuckland | 0:147db0900012 | 83 | |
justinbuckland | 0:147db0900012 | 84 | void logFile(void) { |
justinbuckland | 0:147db0900012 | 85 | rAcc = rAcc + r; |
justinbuckland | 0:147db0900012 | 86 | nAcc++; |
justinbuckland | 0:147db0900012 | 87 | if (eTime > logTime) { |
justinbuckland | 0:147db0900012 | 88 | // trigger camera |
justinbuckland | 0:147db0900012 | 89 | camTrig = 1; |
justinbuckland | 0:147db0900012 | 90 | mbedIO = 1; |
justinbuckland | 0:147db0900012 | 91 | wait_us(CAM_TRIG); |
justinbuckland | 0:147db0900012 | 92 | camTrig = 0; |
justinbuckland | 0:147db0900012 | 93 | mbedIO = 0; |
justinbuckland | 0:147db0900012 | 94 | |
justinbuckland | 0:147db0900012 | 95 | // write data |
justinbuckland | 0:147db0900012 | 96 | sprintf(outString, "%10d,%10d,%10.6f,%10.6f\n", iCycle, eTime, rAcc/nAcc, rSet); // log data |
justinbuckland | 0:147db0900012 | 97 | pc.printf("%s",outString); |
justinbuckland | 0:147db0900012 | 98 | fprintf(fp, outString); |
justinbuckland | 0:147db0900012 | 99 | logTime = logTime + LOG_INTERVAL; |
justinbuckland | 0:147db0900012 | 100 | rAcc = 0; |
justinbuckland | 0:147db0900012 | 101 | nAcc = 0; |
justinbuckland | 0:147db0900012 | 102 | } |
justinbuckland | 0:147db0900012 | 103 | } |
justinbuckland | 0:147db0900012 | 104 | |
justinbuckland | 0:147db0900012 | 105 | void readChannels (char buffer[16], int values[8]){ |
justinbuckland | 0:147db0900012 | 106 | //simultaneously samples and reads into buffer |
justinbuckland | 0:147db0900012 | 107 | short int val_array[8]; |
justinbuckland | 0:147db0900012 | 108 | double i1, v1, i2, v2; |
justinbuckland | 0:147db0900012 | 109 | |
justinbuckland | 0:147db0900012 | 110 | //send convert signal to channels |
justinbuckland | 0:147db0900012 | 111 | convt = CH_ABCD; |
justinbuckland | 0:147db0900012 | 112 | wait_us(1); |
justinbuckland | 0:147db0900012 | 113 | convt = 0; |
justinbuckland | 0:147db0900012 | 114 | |
justinbuckland | 0:147db0900012 | 115 | //SPI(like) data transfer |
justinbuckland | 0:147db0900012 | 116 | cs = 0; |
justinbuckland | 0:147db0900012 | 117 | spi.write(&dummy, 1, buffer, 16); |
justinbuckland | 0:147db0900012 | 118 | cs=1; |
justinbuckland | 0:147db0900012 | 119 | |
justinbuckland | 0:147db0900012 | 120 | //loop over bytes to add channel voltage values |
justinbuckland | 0:147db0900012 | 121 | for (int i=0; i<8; i++){ |
justinbuckland | 0:147db0900012 | 122 | val_array[i] = buffer[2*i]<<8 | buffer16[(2*i) + 1]; |
justinbuckland | 0:147db0900012 | 123 | values [i] = val_array[i]; |
justinbuckland | 0:147db0900012 | 124 | } |
justinbuckland | 0:147db0900012 | 125 | i1 = (double) (val_array[0]-val_array[1]); |
justinbuckland | 0:147db0900012 | 126 | i2 = (double) (val_array[2]-val_array[1]); |
justinbuckland | 0:147db0900012 | 127 | v1 = (double) (val_array[4]-val_array[5]); |
justinbuckland | 0:147db0900012 | 128 | v2 = (double) (val_array[6]-val_array[7]); |
justinbuckland | 0:147db0900012 | 129 | |
justinbuckland | 0:147db0900012 | 130 | // update values if no division by zero (to avoid NaN if PSU is off) |
justinbuckland | 0:147db0900012 | 131 | if (i1 > 0) r1 = v1/i1; |
justinbuckland | 0:147db0900012 | 132 | if (i2 > 0) r2 = v2/i2; |
justinbuckland | 0:147db0900012 | 133 | |
justinbuckland | 0:147db0900012 | 134 | // select heater (inner or outer) |
justinbuckland | 0:147db0900012 | 135 | r = r1; // r1 is inner, r21 is outer |
justinbuckland | 0:147db0900012 | 136 | } |
justinbuckland | 0:147db0900012 | 137 | |
justinbuckland | 0:147db0900012 | 138 | void tempControl(int endTime){ |
justinbuckland | 0:147db0900012 | 139 | eTime = timer.read_ms(); |
justinbuckland | 0:147db0900012 | 140 | while (eTime < endTime) { |
justinbuckland | 0:147db0900012 | 141 | yLED = 1; |
justinbuckland | 0:147db0900012 | 142 | drive = 1; |
justinbuckland | 0:147db0900012 | 143 | wait_us(MEAS_DELAY); // wait for heater current to stabilise |
justinbuckland | 0:147db0900012 | 144 | readChannels (buffer16, val_array); // read ADC channels and update r |
justinbuckland | 0:147db0900012 | 145 | rAvg = ((N_ROLL_AVG-1)*rAvg + r)/N_ROLL_AVG; // calculate rolling average r |
justinbuckland | 0:147db0900012 | 146 | // printf("hold r: %8.4f\r\n",r); |
justinbuckland | 0:147db0900012 | 147 | if (rAvg > rSet) { |
justinbuckland | 0:147db0900012 | 148 | drive = 0; // turn off heater if setpoint resistance is exceeded |
justinbuckland | 0:147db0900012 | 149 | yLED = 0; |
justinbuckland | 0:147db0900012 | 150 | } |
justinbuckland | 0:147db0900012 | 151 | // printf("set r: %8.4f\r\n",r); |
justinbuckland | 0:147db0900012 | 152 | |
justinbuckland | 0:147db0900012 | 153 | logFile(); |
justinbuckland | 0:147db0900012 | 154 | wait_us(PULSE_WIDTH); //wait until pulse_width (us) has elapsed |
justinbuckland | 0:147db0900012 | 155 | eTime = timer.read_ms(); |
justinbuckland | 0:147db0900012 | 156 | } |
justinbuckland | 0:147db0900012 | 157 | } |
justinbuckland | 0:147db0900012 | 158 | |
justinbuckland | 0:147db0900012 | 159 | void tempControlRamp(float setStartR, float setEndR, int endTime){ |
justinbuckland | 0:147db0900012 | 160 | float setRate; |
justinbuckland | 0:147db0900012 | 161 | int startTime; |
justinbuckland | 0:147db0900012 | 162 | |
justinbuckland | 0:147db0900012 | 163 | |
justinbuckland | 0:147db0900012 | 164 | startTime = timer.read_ms(); |
justinbuckland | 0:147db0900012 | 165 | setRate = (setEndR - setStartR)/(endTime - startTime); |
justinbuckland | 0:147db0900012 | 166 | eTime = startTime; |
justinbuckland | 0:147db0900012 | 167 | while (eTime < endTime) { |
justinbuckland | 0:147db0900012 | 168 | rSet = setStartR + setRate*(eTime - startTime); |
justinbuckland | 0:147db0900012 | 169 | yLED = 1; |
justinbuckland | 0:147db0900012 | 170 | drive = 1; |
justinbuckland | 0:147db0900012 | 171 | wait_us(MEAS_DELAY); // wait for heater current to stabilise |
justinbuckland | 0:147db0900012 | 172 | readChannels (buffer16, val_array); // read ADC channels and update r |
justinbuckland | 0:147db0900012 | 173 | rAvg = ((N_ROLL_AVG-1)*rAvg + r)/N_ROLL_AVG; // measure r |
justinbuckland | 0:147db0900012 | 174 | if (rAvg > rSet) { |
justinbuckland | 0:147db0900012 | 175 | drive = 0; // turn off heater if setpoint resistance is exceeded |
justinbuckland | 0:147db0900012 | 176 | yLED = 0; |
justinbuckland | 0:147db0900012 | 177 | } |
justinbuckland | 0:147db0900012 | 178 | // printf("ramp r: %8.4f\r\n",r); |
justinbuckland | 0:147db0900012 | 179 | |
justinbuckland | 0:147db0900012 | 180 | logFile(); |
justinbuckland | 0:147db0900012 | 181 | wait_us(PULSE_WIDTH); //wait until pulse_width (us) has elapsed |
justinbuckland | 0:147db0900012 | 182 | eTime = timer.read_ms(); |
justinbuckland | 0:147db0900012 | 183 | } |
justinbuckland | 0:147db0900012 | 184 | } |
justinbuckland | 0:147db0900012 | 185 | |
justinbuckland | 0:147db0900012 | 186 | |
justinbuckland | 0:147db0900012 | 187 | int main() { |
justinbuckland | 0:147db0900012 | 188 | int endTime = 0; |
justinbuckland | 0:147db0900012 | 189 | |
justinbuckland | 0:147db0900012 | 190 | rLED = 0; |
justinbuckland | 0:147db0900012 | 191 | yLED = 0; |
justinbuckland | 0:147db0900012 | 192 | gLED = 0; |
justinbuckland | 0:147db0900012 | 193 | |
justinbuckland | 0:147db0900012 | 194 | drive = 0; |
justinbuckland | 0:147db0900012 | 195 | |
justinbuckland | 0:147db0900012 | 196 | pc.baud(115200); |
justinbuckland | 0:147db0900012 | 197 | //Reset ADC sequence |
justinbuckland | 0:147db0900012 | 198 | |
justinbuckland | 0:147db0900012 | 199 | sprintf(outString," iCycle, Time(ms), r, rSet\n"); |
justinbuckland | 0:147db0900012 | 200 | pc.printf("%s", outString); |
justinbuckland | 0:147db0900012 | 201 | fprintf(fp, outString); |
justinbuckland | 0:147db0900012 | 202 | |
justinbuckland | 0:147db0900012 | 203 | // while(userButton == 0) |
justinbuckland | 0:147db0900012 | 204 | // { |
justinbuckland | 0:147db0900012 | 205 | // wait_ms(1); |
justinbuckland | 0:147db0900012 | 206 | // }; |
justinbuckland | 0:147db0900012 | 207 | |
justinbuckland | 0:147db0900012 | 208 | |
justinbuckland | 0:147db0900012 | 209 | reset = 1; |
justinbuckland | 0:147db0900012 | 210 | wait_ms(1); |
justinbuckland | 0:147db0900012 | 211 | reset = 0; |
justinbuckland | 0:147db0900012 | 212 | |
justinbuckland | 0:147db0900012 | 213 | //set SPI serial to 2MHz, 16 bit data transfer, mode 2 (clock normally high, data preceeding clock cycle) |
justinbuckland | 0:147db0900012 | 214 | spi.format(8,2); |
justinbuckland | 0:147db0900012 | 215 | spi.frequency(2000000); |
justinbuckland | 0:147db0900012 | 216 | spi.set_default_write_value(0x00); |
justinbuckland | 0:147db0900012 | 217 | cs = 1; |
justinbuckland | 0:147db0900012 | 218 | |
justinbuckland | 0:147db0900012 | 219 | rLED = 1; // thermal cycling in progress |
justinbuckland | 0:147db0900012 | 220 | yLED = 0; // heater off |
justinbuckland | 0:147db0900012 | 221 | gLED = 1; // microprocessor power on |
justinbuckland | 0:147db0900012 | 222 | |
justinbuckland | 0:147db0900012 | 223 | |
justinbuckland | 0:147db0900012 | 224 | timer.start(); |
justinbuckland | 0:147db0900012 | 225 | |
justinbuckland | 0:147db0900012 | 226 | if (T_HOLD > 0) { |
justinbuckland | 0:147db0900012 | 227 | endTime = endTime + T_HOLD; |
justinbuckland | 0:147db0900012 | 228 | rSet = R_SETPOINT_LOW; |
justinbuckland | 0:147db0900012 | 229 | tempControl(endTime); |
justinbuckland | 0:147db0900012 | 230 | } |
justinbuckland | 0:147db0900012 | 231 | if (T_RAMP > 0) { |
justinbuckland | 0:147db0900012 | 232 | endTime = endTime + T_RAMP; |
justinbuckland | 0:147db0900012 | 233 | tempControlRamp(R_SETPOINT_LOW, R_SETPOINT_MID, endTime); |
justinbuckland | 0:147db0900012 | 234 | |
justinbuckland | 0:147db0900012 | 235 | } |
justinbuckland | 0:147db0900012 | 236 | if (T_HOLD > 0) { |
justinbuckland | 0:147db0900012 | 237 | endTime = endTime + T_HOLD; |
justinbuckland | 0:147db0900012 | 238 | rSet = R_SETPOINT_MID; |
justinbuckland | 0:147db0900012 | 239 | tempControl(endTime); |
justinbuckland | 0:147db0900012 | 240 | } |
justinbuckland | 0:147db0900012 | 241 | if (T_RAMP > 0) { |
justinbuckland | 0:147db0900012 | 242 | endTime = endTime + T_RAMP; |
justinbuckland | 0:147db0900012 | 243 | tempControlRamp(R_SETPOINT_MID, R_SETPOINT_HIGH, endTime); |
justinbuckland | 0:147db0900012 | 244 | |
justinbuckland | 0:147db0900012 | 245 | } |
justinbuckland | 0:147db0900012 | 246 | if (T_HOLD > 0) { |
justinbuckland | 0:147db0900012 | 247 | endTime = endTime + T_HOLD; |
justinbuckland | 0:147db0900012 | 248 | rSet = R_SETPOINT_HIGH; |
justinbuckland | 0:147db0900012 | 249 | tempControl(endTime); |
justinbuckland | 0:147db0900012 | 250 | } |
justinbuckland | 0:147db0900012 | 251 | |
justinbuckland | 0:147db0900012 | 252 | // extinguish rLED (thermocycling complete), ensure heater is off and close log file for access |
justinbuckland | 0:147db0900012 | 253 | drive = 0; |
justinbuckland | 0:147db0900012 | 254 | rLED = 0; |
justinbuckland | 0:147db0900012 | 255 | logTime = 0; |
justinbuckland | 0:147db0900012 | 256 | logFile(); |
justinbuckland | 0:147db0900012 | 257 | fclose(fp); |
justinbuckland | 0:147db0900012 | 258 | } |