ADC logging with demo drive board for calibration ADC read synchronised with heater on time
Dependencies: mbed MODSERIAL FastPWM ADS8568_ADC
main.cpp@4:694f0e328a52, 2018-07-31 (annotated)
- Committer:
- justinbuckland
- Date:
- Tue Jul 31 17:25:41 2018 +0000
- Revision:
- 4:694f0e328a52
- Parent:
- 3:447b0de4295a
- Child:
- 5:67e4ee9a00dc
Thermocycling V2 electronics
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
AlexStokoe | 0:362148ad8f6f | 1 | #include "mbed.h" |
AlexStokoe | 0:362148ad8f6f | 2 | |
justinbuckland | 4:694f0e328a52 | 3 | // thermal cycling settings |
justinbuckland | 4:694f0e328a52 | 4 | #define N_CYCLES 10 // number of thermal cycles (ramp-hold-ramp-hold) |
justinbuckland | 4:694f0e328a52 | 5 | #define R_SETPOINT_LOW 0.840 // heater resistance at low temp R60 |
justinbuckland | 4:694f0e328a52 | 6 | #define T_LOW_RAMP 0000 // low temperature ramp time (ms) |
justinbuckland | 4:694f0e328a52 | 7 | #define T_LOW_HOLD 2000 // low temperature hold time (ms) |
justinbuckland | 4:694f0e328a52 | 8 | #define R_SETPOINT_HIGH 0.860 // heater resistance at high temp R95 |
justinbuckland | 4:694f0e328a52 | 9 | #define T_HIGH_RAMP 0000 // high temperaure ramp time (ms) |
justinbuckland | 4:694f0e328a52 | 10 | #define T_HIGH_HOLD 2000 // high temperature time (ms) |
justinbuckland | 4:694f0e328a52 | 11 | #define T_HIGH_START 2000 // hotstart time(ms) |
justinbuckland | 4:694f0e328a52 | 12 | |
justinbuckland | 4:694f0e328a52 | 13 | // temperature measurement settings |
justinbuckland | 4:694f0e328a52 | 14 | #define N_SAMPLES 1 // number of samples to acquire for I and V measurements |
justinbuckland | 4:694f0e328a52 | 15 | #define N_ROLL_AVG 10 // rolling average for R values |
justinbuckland | 4:694f0e328a52 | 16 | #define PULSE_WIDTH 2000 // heat or cool pulse width (us) |
justinbuckland | 4:694f0e328a52 | 17 | #define MEAS_DELAY 1000 // measurement delay after turning on FET (us) |
justinbuckland | 4:694f0e328a52 | 18 | #define CAM_TRIG 20 // camera trigger pulse width (us) |
justinbuckland | 4:694f0e328a52 | 19 | #define LOG_INTERVAL 100 // log file interval (ms) |
justinbuckland | 4:694f0e328a52 | 20 | |
justinbuckland | 4:694f0e328a52 | 21 | // ADC channels to read |
justinbuckland | 4:694f0e328a52 | 22 | #define CH_A 1 // value of convst bus to read channel A only |
justinbuckland | 4:694f0e328a52 | 23 | #define CH_AC 5 // value of convst bus to read channels A and C |
justinbuckland | 4:694f0e328a52 | 24 | #define CH_ABCD 15 // value of convst bus to read all chanels simultaneously |
AlexStokoe | 0:362148ad8f6f | 25 | |
AlexStokoe | 0:362148ad8f6f | 26 | Serial pc(USBTX, USBRX); // tx, rx |
AlexStokoe | 0:362148ad8f6f | 27 | |
justinbuckland | 4:694f0e328a52 | 28 | DigitalOut drive(p21); // drive FET |
justinbuckland | 4:694f0e328a52 | 29 | DigitalOut yLED(p27); // yellow LED (drive on) |
justinbuckland | 4:694f0e328a52 | 30 | DigitalOut gLED(p28); // green LED (power on) |
justinbuckland | 4:694f0e328a52 | 31 | DigitalOut rLED(p26); // red LED (thermocycling in progress) |
justinbuckland | 4:694f0e328a52 | 32 | DigitalOut camTrig(p25); // trigger camera |
AlexStokoe | 0:362148ad8f6f | 33 | |
AlexStokoe | 0:362148ad8f6f | 34 | AnalogIn battVolt(p19); |
AlexStokoe | 0:362148ad8f6f | 35 | AnalogIn auxVolt(p20); |
AlexStokoe | 0:362148ad8f6f | 36 | |
AlexStokoe | 0:362148ad8f6f | 37 | BusOut convt(p11, p12, p13, p14); |
justinbuckland | 4:694f0e328a52 | 38 | SPI spi(p5, p6, p7); // mosi, miso, sclk |
justinbuckland | 4:694f0e328a52 | 39 | DigitalOut cs(p8); // chip select |
AlexStokoe | 0:362148ad8f6f | 40 | DigitalIn busy(p9); |
AlexStokoe | 0:362148ad8f6f | 41 | DigitalOut reset(p10); |
AlexStokoe | 0:362148ad8f6f | 42 | |
justinbuckland | 4:694f0e328a52 | 43 | Timer timer; |
justinbuckland | 4:694f0e328a52 | 44 | LocalFileSystem local("local"); |
justinbuckland | 4:694f0e328a52 | 45 | |
justinbuckland | 4:694f0e328a52 | 46 | FILE *fp = fopen("/local/TEST_LOG.csv", "w"); // Open "test_log" on the local file system for writing |
justinbuckland | 4:694f0e328a52 | 47 | |
justinbuckland | 4:694f0e328a52 | 48 | float r = 0; |
justinbuckland | 4:694f0e328a52 | 49 | float rAvg = 0; |
justinbuckland | 4:694f0e328a52 | 50 | float rAcc = 0; |
justinbuckland | 4:694f0e328a52 | 51 | float rSet; |
justinbuckland | 4:694f0e328a52 | 52 | |
justinbuckland | 4:694f0e328a52 | 53 | int nAcc = 0; |
justinbuckland | 4:694f0e328a52 | 54 | int eTime; |
justinbuckland | 4:694f0e328a52 | 55 | int logTime = 0; |
justinbuckland | 4:694f0e328a52 | 56 | int iCycle = 0; |
justinbuckland | 4:694f0e328a52 | 57 | |
justinbuckland | 4:694f0e328a52 | 58 | char outString[100]; |
justinbuckland | 4:694f0e328a52 | 59 | |
AlexStokoe | 0:362148ad8f6f | 60 | char buffer16[16]; |
AlexStokoe | 0:362148ad8f6f | 61 | int val_array[8]; |
AlexStokoe | 0:362148ad8f6f | 62 | const char dummy = 0; |
justinbuckland | 4:694f0e328a52 | 63 | |
justinbuckland | 4:694f0e328a52 | 64 | void logFile(void) { |
justinbuckland | 4:694f0e328a52 | 65 | rAcc = rAcc + r; |
justinbuckland | 4:694f0e328a52 | 66 | nAcc++; |
justinbuckland | 4:694f0e328a52 | 67 | if (eTime > logTime) { |
justinbuckland | 4:694f0e328a52 | 68 | // trigger camera |
justinbuckland | 4:694f0e328a52 | 69 | camTrig = 1; |
justinbuckland | 4:694f0e328a52 | 70 | wait_us(CAM_TRIG); |
justinbuckland | 4:694f0e328a52 | 71 | camTrig = 0; |
AlexStokoe | 0:362148ad8f6f | 72 | |
justinbuckland | 4:694f0e328a52 | 73 | // write data |
justinbuckland | 4:694f0e328a52 | 74 | sprintf(outString, "%10d,%10d,%10.6f,%10.6f\n", iCycle, eTime, rAcc/nAcc, rSet); // log data |
justinbuckland | 4:694f0e328a52 | 75 | pc.printf("%s",outString); |
justinbuckland | 4:694f0e328a52 | 76 | fprintf(fp, outString); |
justinbuckland | 4:694f0e328a52 | 77 | logTime = logTime + LOG_INTERVAL; |
justinbuckland | 4:694f0e328a52 | 78 | rAcc = 0; |
justinbuckland | 4:694f0e328a52 | 79 | nAcc = 0; |
justinbuckland | 4:694f0e328a52 | 80 | } |
justinbuckland | 4:694f0e328a52 | 81 | } |
AlexStokoe | 0:362148ad8f6f | 82 | |
justinbuckland | 4:694f0e328a52 | 83 | void readChannels (char buffer[16], int values[8]){ |
justinbuckland | 2:23f848b21b09 | 84 | //simultaneously samples and reads into buffer |
AlexStokoe | 0:362148ad8f6f | 85 | short int val_array[8]; |
justinbuckland | 2:23f848b21b09 | 86 | |
justinbuckland | 2:23f848b21b09 | 87 | //send convert signal to channels |
justinbuckland | 2:23f848b21b09 | 88 | convt = CH_AC; |
justinbuckland | 2:23f848b21b09 | 89 | wait_us(1); |
justinbuckland | 2:23f848b21b09 | 90 | convt = 0; |
justinbuckland | 2:23f848b21b09 | 91 | |
justinbuckland | 2:23f848b21b09 | 92 | //SPI(like) data transfer |
justinbuckland | 2:23f848b21b09 | 93 | cs = 0; |
justinbuckland | 2:23f848b21b09 | 94 | spi.write(&dummy, 1, buffer, 16); |
justinbuckland | 2:23f848b21b09 | 95 | cs=1; |
justinbuckland | 2:23f848b21b09 | 96 | |
justinbuckland | 2:23f848b21b09 | 97 | //loop over bytes to add channel voltage values |
justinbuckland | 2:23f848b21b09 | 98 | for (int i=0; i<8; i++){ |
justinbuckland | 2:23f848b21b09 | 99 | val_array[i] = buffer[2*i]<<8 | buffer16[(2*i) + 1]; |
justinbuckland | 2:23f848b21b09 | 100 | values [i] = val_array[i]; |
justinbuckland | 4:694f0e328a52 | 101 | } |
justinbuckland | 4:694f0e328a52 | 102 | r = (double)(val_array[5]-val_array[4])/(double)(val_array[1]-val_array[0]); |
justinbuckland | 4:694f0e328a52 | 103 | } |
justinbuckland | 4:694f0e328a52 | 104 | |
justinbuckland | 4:694f0e328a52 | 105 | void tempControl(int endTime){ |
justinbuckland | 4:694f0e328a52 | 106 | eTime = timer.read_ms(); |
justinbuckland | 4:694f0e328a52 | 107 | while (eTime < endTime) { |
justinbuckland | 4:694f0e328a52 | 108 | yLED = 1; |
justinbuckland | 4:694f0e328a52 | 109 | drive = 1; |
justinbuckland | 4:694f0e328a52 | 110 | wait_us(MEAS_DELAY); // wait for heater current to stabilise |
justinbuckland | 4:694f0e328a52 | 111 | readChannels (buffer16, val_array); // read ADC channels and update r |
justinbuckland | 4:694f0e328a52 | 112 | rAvg = ((N_ROLL_AVG-1)*rAvg + r)/N_ROLL_AVG; // calculate rolling average r |
justinbuckland | 4:694f0e328a52 | 113 | // printf("hold r: %8.4f\r\n",r); |
justinbuckland | 4:694f0e328a52 | 114 | if (rAvg > rSet) { |
justinbuckland | 4:694f0e328a52 | 115 | drive = 0; // turn off heater if setpoint resistance is exceeded |
justinbuckland | 4:694f0e328a52 | 116 | yLED = 0; |
AlexStokoe | 0:362148ad8f6f | 117 | } |
justinbuckland | 4:694f0e328a52 | 118 | // printf("set r: %8.4f\r\n",r); |
justinbuckland | 4:694f0e328a52 | 119 | |
justinbuckland | 4:694f0e328a52 | 120 | logFile(); |
justinbuckland | 4:694f0e328a52 | 121 | wait_us(PULSE_WIDTH); //wait until pulse_width (us) has elapsed |
justinbuckland | 4:694f0e328a52 | 122 | eTime = timer.read_ms(); |
justinbuckland | 4:694f0e328a52 | 123 | } |
justinbuckland | 4:694f0e328a52 | 124 | } |
justinbuckland | 4:694f0e328a52 | 125 | |
justinbuckland | 4:694f0e328a52 | 126 | void tempControlRamp(float setStartR, float setEndR, int endTime){ |
justinbuckland | 4:694f0e328a52 | 127 | float setRate; |
justinbuckland | 4:694f0e328a52 | 128 | int startTime; |
AlexStokoe | 0:362148ad8f6f | 129 | |
justinbuckland | 4:694f0e328a52 | 130 | startTime = timer.read_ms(); |
justinbuckland | 4:694f0e328a52 | 131 | setRate = (setEndR - setStartR)/(endTime - startTime); |
justinbuckland | 4:694f0e328a52 | 132 | eTime = startTime; |
justinbuckland | 4:694f0e328a52 | 133 | while (eTime < endTime) { |
justinbuckland | 4:694f0e328a52 | 134 | rSet = setStartR + setRate*(eTime - startTime); |
justinbuckland | 4:694f0e328a52 | 135 | yLED = 1; |
justinbuckland | 4:694f0e328a52 | 136 | drive = 1; |
justinbuckland | 4:694f0e328a52 | 137 | wait_us(MEAS_DELAY); // wait for heater current to stabilise |
justinbuckland | 4:694f0e328a52 | 138 | readChannels (buffer16, val_array); // read ADC channels and update r |
justinbuckland | 4:694f0e328a52 | 139 | rAvg = ((N_ROLL_AVG-1)*rAvg + r)/N_ROLL_AVG; // measure r |
justinbuckland | 4:694f0e328a52 | 140 | if (rAvg > rSet) { |
justinbuckland | 4:694f0e328a52 | 141 | drive = 0; // turn off heater if setpoint resistance is exceeded |
justinbuckland | 4:694f0e328a52 | 142 | yLED = 0; |
justinbuckland | 4:694f0e328a52 | 143 | } |
justinbuckland | 4:694f0e328a52 | 144 | // printf("ramp r: %8.4f\r\n",r); |
justinbuckland | 4:694f0e328a52 | 145 | |
justinbuckland | 4:694f0e328a52 | 146 | logFile(); |
justinbuckland | 4:694f0e328a52 | 147 | wait_us(PULSE_WIDTH); //wait until pulse_width (us) has elapsed |
justinbuckland | 4:694f0e328a52 | 148 | eTime = timer.read_ms(); |
justinbuckland | 4:694f0e328a52 | 149 | } |
justinbuckland | 4:694f0e328a52 | 150 | } |
justinbuckland | 4:694f0e328a52 | 151 | |
AlexStokoe | 0:362148ad8f6f | 152 | |
AlexStokoe | 0:362148ad8f6f | 153 | int main() { |
justinbuckland | 4:694f0e328a52 | 154 | int endTime = 0; |
justinbuckland | 2:23f848b21b09 | 155 | |
AlexStokoe | 0:362148ad8f6f | 156 | rLED = 0; |
AlexStokoe | 0:362148ad8f6f | 157 | yLED = 0; |
AlexStokoe | 0:362148ad8f6f | 158 | gLED = 0; |
AlexStokoe | 0:362148ad8f6f | 159 | |
AlexStokoe | 0:362148ad8f6f | 160 | drive = 0; |
justinbuckland | 2:23f848b21b09 | 161 | |
AlexStokoe | 0:362148ad8f6f | 162 | pc.baud(115200); |
AlexStokoe | 0:362148ad8f6f | 163 | //Reset ADC sequence |
justinbuckland | 4:694f0e328a52 | 164 | |
AlexStokoe | 0:362148ad8f6f | 165 | reset = 1; |
AlexStokoe | 0:362148ad8f6f | 166 | wait_ms(1); |
AlexStokoe | 0:362148ad8f6f | 167 | reset = 0; |
AlexStokoe | 0:362148ad8f6f | 168 | |
AlexStokoe | 0:362148ad8f6f | 169 | //set SPI serial to 2MHz, 16 bit data transfer, mode 2 (clock normally high, data preceeding clock cycle) |
AlexStokoe | 0:362148ad8f6f | 170 | spi.format(8,2); |
AlexStokoe | 0:362148ad8f6f | 171 | spi.frequency(2000000); |
AlexStokoe | 0:362148ad8f6f | 172 | spi.set_default_write_value(0x00); |
AlexStokoe | 0:362148ad8f6f | 173 | cs = 1; |
AlexStokoe | 0:362148ad8f6f | 174 | |
justinbuckland | 4:694f0e328a52 | 175 | rLED = 1; // thermal cycling in progress |
justinbuckland | 4:694f0e328a52 | 176 | yLED = 0; // heater on |
justinbuckland | 4:694f0e328a52 | 177 | gLED = 1; // microprocessor power on |
AlexStokoe | 0:362148ad8f6f | 178 | |
justinbuckland | 4:694f0e328a52 | 179 | sprintf(outString," iCycle, Time(ms), r, rSet\n"); |
justinbuckland | 4:694f0e328a52 | 180 | pc.printf("%s", outString); |
justinbuckland | 4:694f0e328a52 | 181 | fprintf(fp, outString); |
justinbuckland | 4:694f0e328a52 | 182 | |
justinbuckland | 4:694f0e328a52 | 183 | timer.start(); |
justinbuckland | 4:694f0e328a52 | 184 | |
justinbuckland | 4:694f0e328a52 | 185 | // optional hot start: additional HIGH temperature time at start |
justinbuckland | 4:694f0e328a52 | 186 | if (T_HIGH_START > 0) { |
justinbuckland | 4:694f0e328a52 | 187 | endTime = T_HIGH_START; |
justinbuckland | 4:694f0e328a52 | 188 | rSet = R_SETPOINT_HIGH; |
justinbuckland | 4:694f0e328a52 | 189 | tempControl(endTime); |
justinbuckland | 4:694f0e328a52 | 190 | } |
AlexStokoe | 0:362148ad8f6f | 191 | |
justinbuckland | 4:694f0e328a52 | 192 | // thermocycle loop |
justinbuckland | 4:694f0e328a52 | 193 | for (iCycle = 0; iCycle < N_CYCLES; iCycle++ ) { |
justinbuckland | 4:694f0e328a52 | 194 | |
justinbuckland | 4:694f0e328a52 | 195 | // ramp up to HIGH temperature |
justinbuckland | 4:694f0e328a52 | 196 | endTime = endTime + T_HIGH_RAMP; |
justinbuckland | 4:694f0e328a52 | 197 | tempControlRamp(R_SETPOINT_LOW, R_SETPOINT_HIGH, endTime); |
justinbuckland | 4:694f0e328a52 | 198 | |
justinbuckland | 4:694f0e328a52 | 199 | // hold at HIGH temperature |
justinbuckland | 4:694f0e328a52 | 200 | endTime = endTime + T_HIGH_HOLD; |
justinbuckland | 4:694f0e328a52 | 201 | rSet = R_SETPOINT_HIGH; |
justinbuckland | 4:694f0e328a52 | 202 | tempControl(endTime); |
AlexStokoe | 0:362148ad8f6f | 203 | |
justinbuckland | 4:694f0e328a52 | 204 | // ramp down to LOW temperature |
justinbuckland | 4:694f0e328a52 | 205 | endTime = endTime + T_LOW_RAMP; |
justinbuckland | 4:694f0e328a52 | 206 | tempControlRamp(R_SETPOINT_HIGH, R_SETPOINT_LOW, endTime); |
justinbuckland | 4:694f0e328a52 | 207 | |
justinbuckland | 4:694f0e328a52 | 208 | // hold at LOW temperature |
justinbuckland | 4:694f0e328a52 | 209 | endTime = endTime + T_LOW_HOLD; |
justinbuckland | 4:694f0e328a52 | 210 | rSet = R_SETPOINT_LOW; |
justinbuckland | 4:694f0e328a52 | 211 | tempControl(endTime); |
justinbuckland | 4:694f0e328a52 | 212 | |
justinbuckland | 4:694f0e328a52 | 213 | } |
justinbuckland | 4:694f0e328a52 | 214 | |
justinbuckland | 4:694f0e328a52 | 215 | // extinguish rLED (thermocycling complete), ensure heater is off and close log file for access |
justinbuckland | 4:694f0e328a52 | 216 | drive = 0; |
justinbuckland | 4:694f0e328a52 | 217 | rLED = 0; |
justinbuckland | 4:694f0e328a52 | 218 | logTime = 0; |
justinbuckland | 4:694f0e328a52 | 219 | logFile(); |
justinbuckland | 4:694f0e328a52 | 220 | fclose(fp); |
justinbuckland | 4:694f0e328a52 | 221 | } |