Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
main.cpp
00001 // MBED SCRIPT FOR CONTROLLING THE TEMPERATURE CONTROLLED TEST FIXTURE (TCTF) 00002 // DATE: SEPTEMBER 2017 00003 //CHANGE THE PYTHON CODE TO REFLECT ERROR STATE ENTERED 00004 00005 #include "mbed.h" 00006 #include "MODSERIAL.h" 00007 #include "MCP23008.h" 00008 #include "LTC2487.h" 00009 #include <string> 00010 00011 00012 //DEFINITIVE VARIABLES 00013 #define DEBUG_LOOP_TIME 0x00000001 00014 #define RXDATA_PRINT 0x00000002 00015 #define UID_PRINT 0x00000004 00016 #define ERROR_PRINT 0x00000008 00017 #define ADC_VAL_PRINT 0x00000010 00018 #define HEATER_CHILLER_PRINT 0x00000020 00019 #define HEATER_ON_TIME_PRINT 0x00000040 00020 #define LED_PRINT 0x00000080 00021 #define TEMP_PRINT 0x00000100 00022 #define I2C_PRINT 0x00000200 00023 00024 #define IO_I2C_LINE 1 00025 #define ADC_I2C_LINE 2 00026 00027 #define CHAN_COUNT 8 00028 #define ERROR_COUNT 6 00029 #define MIN_TEMP 10 00030 #define MAX_TEMP 65 00031 #define TEMP_MARGIN 10 00032 #define HYST_LOW 0.3 00033 #define HYST_HIGH 1 00034 #define VALVE_ON 1 00035 #define HEATER_ON 2 00036 #define GREEN_STATUS_ON 3 00037 #define RED_STATUS_ON 4 00038 #define ERROR_STATUS_ON 5 00039 #define ALL_OFF 6 00040 #define sizeLUT 34 00041 #define BACK_THERM 0 00042 #define FRONT_THERM 1 00043 #define HEAT_FET_AMP 2 00044 #define VALVE_FET_AMP 3 00045 #define NUM_EMAIL_SEND 2 00046 #define STATUS_COOLING 1 00047 #define STATUS_HEATING 2 00048 #define STATUS_INACTIVE 3 00049 #define STATUS_STANDBY 4 00050 #define MIN_AD_COUNT 10428 //65C 00051 #define MAX_AD_COUNT 49169 //10C 00052 #define MAX_TIME_TO_SP 60 //allow 60 minutes for channel to reach set point 00053 00054 #define READ_TEMP_TASK_TIME .300f //300ms to read one A/D value 00055 #define I2C_READ_WAIT_TIME 0.08f 00056 00057 // Defines for use with Serial communication 00058 #pragma pack (1) 00059 #define RX_SOF 0x7B 00060 #define RX_EOF 0x7D 00061 #define TX_SOF 0x7B 00062 #define TX_EOF 0x7D 00063 #define DELIMETER 0x2E 00064 #define SET_TEMPERATURE 0xB0 00065 #define SELECT_CHANNEL 0xB1 00066 #define READ_UID 0xB2 00067 #define READ_FW_VERSION 0xB3 00068 #define DEBUG_CONTROL 0xB4 00069 #define RESPONSE_DATA 0xD0 00070 #define TEMP_DATA 0xD1 00071 #define UID_DATA 0xD2 00072 #define FW_VERSION_DATA 0xD3 00073 #define ERROR_DATA 0xDF 00074 00075 // Defines for errors 00076 #define ERR_OVER_TEMP 0 00077 #define ERR_UNDER_TEMP 1 00078 #define ERR_TEMP_DIFF 2 00079 #define ERR_ACK_LTC 3 00080 #define ERR_ACK_MCP 4 00081 #define ERR_SP_TIME 5 00082 #define MAX_ERROR_CNT 8 00083 00084 #define PRINT_ERROR_CHECK_VALS 0 00085 #define PRINT_ERRORS 0 00086 00087 00088 00089 00090 const char FW_Version[8] = "V0.01D"; 00091 unsigned int chanSel_SendTemp = 0; 00092 unsigned int chanSel_SetTemp = 0; 00093 // Default to chan 0 00094 int currChan = 0; 00095 bool newTempSet = false; 00096 bool readFrontThermistor = true; 00097 bool newTempData = false; 00098 bool newTempDataAvailable = false; 00099 unsigned int UID_print_count = 0; 00100 unsigned int debug_control = 0x80; 00101 00102 //*********************************************** 00103 // Timers 00104 //*********************************************** 00105 Ticker frontTempDoneTicker; 00106 Ticker backTempDoneTicker; 00107 Ticker readThermistorTicker; 00108 Ticker frontTempInProgTicker; 00109 Ticker backTempInProgTicker; 00110 Ticker setPointTimeTicker; 00111 00112 //*********************************************** 00113 // LEDs 00114 //*********************************************** 00115 DigitalOut rLed(LED1); 00116 DigitalOut gLed(LED2); 00117 00118 //*********************************************** 00119 // Functions Declarations 00120 //*********************************************** 00121 void sendUID (); 00122 void sendFWVersion(); 00123 void read_front_temp(); 00124 void read_back_temp(); 00125 void update_front_temp_data(); 00126 void update_back_temp_data(); 00127 void temperatureDataReady(); 00128 00129 //*********************************************** 00130 // Serial Rx Packet Format 00131 //*********************************************** 00132 typedef struct { 00133 unsigned char SOF_flag; 00134 unsigned char cmd_type; 00135 unsigned char len; 00136 unsigned char Delim; 00137 } HOST_CMD_HEADER; 00138 00139 typedef struct { 00140 HOST_CMD_HEADER cmd_header; 00141 unsigned char chanID; 00142 unsigned char tempDelim; 00143 float setTemp; 00144 unsigned char chanStatDelim; 00145 unsigned char chanStat; 00146 } SET_TEMPERATURE_CMD; 00147 00148 typedef struct { 00149 HOST_CMD_HEADER cmd_header; 00150 unsigned char chanIDSel; 00151 unsigned char chanDelim; 00152 unsigned char chanStat; 00153 } SELECT_CHANNEL_CMD; 00154 00155 typedef struct { 00156 unsigned char SOF_flag; 00157 unsigned char cmd_type; 00158 unsigned char len; 00159 unsigned char Delim; 00160 uint32_t channel; 00161 float data; 00162 unsigned char EOF_flag; 00163 } RESPONSE_CMD; 00164 00165 typedef struct { 00166 unsigned char SOF_flag; 00167 unsigned char cmd_type; 00168 unsigned char len; 00169 unsigned char Delim; 00170 float chTemp[CHAN_COUNT]; 00171 unsigned char EOF_flag; 00172 } RESPONSE_TEMP_CMD; 00173 00174 typedef struct { 00175 HOST_CMD_HEADER cmd_header; 00176 unsigned char chanIDSel; 00177 unsigned char chanDelim; 00178 unsigned char chanStat; 00179 } READ_UID_CMD; 00180 00181 typedef struct { 00182 HOST_CMD_HEADER cmd_header; 00183 unsigned char chanIDSel; 00184 unsigned char chanDelim; 00185 uint32_t commandData; 00186 } GUI_STANDARD_CMD; 00187 00188 typedef struct { 00189 unsigned char SOF_flag; 00190 unsigned char cmd_type; 00191 unsigned char len; 00192 unsigned char Delim; 00193 unsigned char FW_Version[8]; 00194 unsigned char EOF_flag; 00195 } FW_VERSION_RESPONSE; 00196 00197 typedef struct { 00198 unsigned char SOF_flag; 00199 unsigned char cmd_type; 00200 unsigned char len; 00201 unsigned char Delim; 00202 uint32_t UIDMH; 00203 uint32_t UIDML; 00204 uint32_t UIDL; 00205 unsigned char EOF_flag; 00206 } UID_RESPONSE; 00207 00208 //TCTF CHANNEL DATA 00209 struct CHNL_DATA{ 00210 bool status; 00211 float setTemp; 00212 bool error; 00213 int state; 00214 int LTCi2cAckRxed; 00215 int MCPi2cAckRxed; 00216 bool SPReached; 00217 int SPTime; 00218 }; 00219 00220 CHNL_DATA chnlStatus[] = { 00221 {0, NULL, false, 0, 0, 0, false, 0}, 00222 {0, NULL, false, 0, 0, 0, false, 0}, 00223 {0, NULL, false, 0, 0, 0, false, 0}, 00224 {0, NULL, false, 0, 0, 0, false, 0}, 00225 {0, NULL, false, 0, 0, 0, false, 0}, 00226 {0, NULL, false, 0, 0, 0, false, 0}, 00227 {0, NULL, false, 0, 0, 0, false, 0}, 00228 {0, NULL, false, 0, 0, 0, false, 0} 00229 }; 00230 00231 00232 //I2C AADRESS LOOK UP TABLE, CREATED IN EXCEL SHEET (COUNT, TEMP) 00233 struct I2C_ADDR_LUT{ 00234 int adc; 00235 int io; 00236 }; 00237 00238 I2C_ADDR_LUT addrLUT[] = { 00239 {0x23, 0x10}, 00240 {0x53, 0x60}, 00241 {0x43, 0x70}, 00242 {0x73, 0x40}, 00243 {0x63, 0x50}, 00244 {0x22, 0x11}, 00245 {0x52, 0x61}, 00246 {0x42, 0x71} 00247 }; 00248 00249 //THERMISTOR LOOK UP TABLE, CREATED IN EXCEL SHEET (COUNT, TEMP) 00250 struct THERM_LUT{ 00251 int adc; 00252 int temp; 00253 }; 00254 00255 THERM_LUT thermLUT[] = { 00256 {113779,-40}, 00257 {109152,-35}, 00258 {103830,-30}, 00259 {97855,-25}, 00260 {91319,-20}, 00261 {84352,-15}, 00262 {77124,-10}, 00263 {69820,-5}, 00264 {62621,0}, 00265 {55693,5}, 00266 {49169,10}, 00267 {43144,15}, 00268 {37669,20}, 00269 {32768,25}, 00270 {28429,30}, 00271 {24622,35}, 00272 {21309,40}, 00273 {18439,45}, 00274 {15962,50}, 00275 {13831,55}, 00276 {12002,60}, 00277 {10428,65}, 00278 {9080,70}, 00279 {7919,75}, 00280 {6923,80}, 00281 {6063,85}, 00282 {5323,90}, 00283 {4685,95}, 00284 {4130,100}, 00285 {3653,105}, 00286 {3234,110}, 00287 {2876,115}, 00288 {2563,120}, 00289 {2284,125} 00290 }; 00291 00292 00293 00294 //TCTF CHANNEL TEMPERATURE 00295 typedef struct{ 00296 float currADCFront; 00297 float currADCBack; 00298 float currTempFront; 00299 float currTempBack; 00300 }CHNL_TEMP; 00301 00302 CHNL_TEMP channelTempData[CHAN_COUNT]; 00303 00304 //SERIAL COMMUNICATION SETUP 00305 MODSERIAL pc(USBTX, USBRX); 00306 00307 //DEFINE PINS 00308 DigitalOut myled(LED2); 00309 00310 //I2C FOR MCP23008 (I/O Control) 00311 MCP23008 io_control(PTC9, PTC8, 0x10, 100000); //sda, scl 00312 00313 //I2C FOR LTC2487 (ADC Control) 00314 LTC2487 ltc2487(PTC11, PTC10, 0x23, 100000); //sda, scl 00315 00316 //GLOBAL VARIABLES 00317 volatile bool dataReceived = false; //used to check if data has been received 00318 volatile bool dataTxReady = false; 00319 char rxBuf[50]; 00320 int chnlSel; 00321 bool standbyLED[CHAN_COUNT] = {false,false,false,false,false,false,false,false}; 00322 00323 int errorCount[CHAN_COUNT][ERROR_COUNT] = 00324 { 00325 {0,0,0,0,0,0}, 00326 {0,0,0,0,0,0}, 00327 {0,0,0,0,0,0}, 00328 {0,0,0,0,0,0}, 00329 {0,0,0,0,0,0}, 00330 {0,0,0,0,0,0}, 00331 {0,0,0,0,0,0}, 00332 {0,0,0,0,0,0} 00333 }; 00334 00335 int errorEmailSent[CHAN_COUNT][ERROR_COUNT] = 00336 { 00337 {0,0,0,0,0,0}, 00338 {0,0,0,0,0,0}, 00339 {0,0,0,0,0,0}, 00340 {0,0,0,0,0,0}, 00341 {0,0,0,0,0,0}, 00342 {0,0,0,0,0,0}, 00343 {0,0,0,0,0,0}, 00344 {0,0,0,0,0,0} 00345 }; 00346 00347 void resetErrorCount(){ 00348 for(int i = 0; i < CHAN_COUNT; i++){ 00349 for(int i = 0; i < ERROR_COUNT; i++){ 00350 errorCount[CHAN_COUNT][ERROR_COUNT] = 0; 00351 errorEmailSent[CHAN_COUNT][ERROR_COUNT] = 0; 00352 } 00353 } 00354 } 00355 00356 /* Function: turnOffChannel 00357 ************************************************************** 00358 Description: Turns off a channel 00359 Recieves: chnl: channel to turn off 00360 Returns: N/A 00361 */ 00362 00363 void turnOffChannel(int chnl){ 00364 io_control.setAddress(addrLUT[chnl].io); 00365 io_control.init(); 00366 io_control.writeOutput(0,0,0,0); 00367 } 00368 00369 00370 /* Function: rxInterrupt 00371 ************************************************************** 00372 Description: serial rx interupt handler 00373 Receives: N/A 00374 Returns: N/A 00375 */ 00376 00377 //*********************************************** 00378 // Rx Interrupt from serial Host interface 00379 //*********************************************** 00380 void rxInterrupt(MODSERIAL_IRQ_INFO *info) 00381 { 00382 gLed = 0; 00383 dataReceived = true; 00384 //wait(.5); 00385 gLed = 1; 00386 } 00387 00388 00389 //*************************************************************** 00390 // Tx Interrupt from serial Host interface 00391 //*************************************************************** 00392 void txInterrupt(MODSERIAL_IRQ_INFO *info) 00393 { 00394 gLed = 1; 00395 dataTxReady = true; 00396 gLed = 1; 00397 } 00398 00399 00400 /* Function: parseRXData 00401 ************************************************************** 00402 Description: The parse received data into 00403 Receives: chn: The channel we want to put into the channel 00404 Returns: N/A 00405 */ 00406 void processRxUARTData() 00407 { 00408 HOST_CMD_HEADER *pRxPktHdr; 00409 string data = ""; 00410 00411 pRxPktHdr = (HOST_CMD_HEADER *)rxBuf; 00412 00413 if (debug_control & RXDATA_PRINT) { 00414 pc.printf("DBG: SOF=%02x, Len=%02x, CMD=%02x\r\n", pRxPktHdr->SOF_flag, pRxPktHdr->len, pRxPktHdr->cmd_type); 00415 pc.printf("DBG: "); 00416 for (int i=0; i <5; i++) 00417 pc.printf("%02x ", rxBuf[i]); 00418 pc.printf("\n"); 00419 } 00420 00421 // Exit if the packet does not contain correct header 00422 // Maybe send NAK? 00423 if ((pRxPktHdr->SOF_flag != RX_SOF) || (pRxPktHdr->Delim != DELIMETER)) 00424 return; 00425 00426 switch (pRxPktHdr->cmd_type) 00427 { 00428 case SET_TEMPERATURE: 00429 // Process set temp for specified channel 00430 { 00431 SET_TEMPERATURE_CMD *pRxPkt = (SET_TEMPERATURE_CMD *)(rxBuf); 00432 00433 if (debug_control & RXDATA_PRINT) 00434 pc.printf("DBG: SETTEMP: ch = %02x, tempSet = %f, chanStat = %02x\r\n", 00435 pRxPkt->chanID, pRxPkt->setTemp, pRxPkt->chanStat); 00436 00437 if ((pRxPkt->tempDelim != DELIMETER) || (pRxPkt->chanStatDelim != DELIMETER)) { 00438 // Send NAK back 00439 pc.printf("DBG: Error\n"); 00440 } 00441 else { 00442 if((pRxPkt->setTemp < MAX_TEMP) && (pRxPkt->setTemp > MIN_TEMP)){ 00443 chanSel_SetTemp = pRxPkt->chanID; 00444 chnlStatus[pRxPkt->chanID].status = pRxPkt->chanStat; 00445 chnlStatus[pRxPkt->chanID].state = STATUS_INACTIVE; 00446 chnlStatus[pRxPkt->chanID].setTemp = pRxPkt->setTemp; 00447 chnlStatus[pRxPkt->chanID].error = false; 00448 chnlStatus[pRxPkt->chanID].LTCi2cAckRxed = 0; 00449 chnlStatus[pRxPkt->chanID].MCPi2cAckRxed = 0; 00450 chnlStatus[pRxPkt->chanID].SPReached = false; 00451 chnlStatus[pRxPkt->chanID].SPTime = 0; 00452 memset(errorCount[pRxPkt->chanID], 0, sizeof(int)*ERROR_COUNT); 00453 memset(errorEmailSent[pRxPkt->chanID], 0, sizeof(int)*ERROR_COUNT); 00454 newTempSet = true; 00455 } 00456 } 00457 } 00458 break; 00459 00460 case SELECT_CHANNEL: 00461 // Select channel to send temp data to 00462 { 00463 SELECT_CHANNEL_CMD *pRxPkt = (SELECT_CHANNEL_CMD *)(rxBuf); 00464 00465 chanSel_SendTemp = pRxPkt->chanIDSel; 00466 00467 // Send back FW version for each select channel 00468 sendFWVersion(); 00469 if (debug_control & RXDATA_PRINT) 00470 pc.printf("DBG: CHAN_SEL: chan=%02x, chanStat = %02x\r\n", pRxPkt->chanIDSel, pRxPkt->chanStat); 00471 00472 } 00473 break; 00474 00475 case READ_UID: 00476 { 00477 READ_UID_CMD *pRxPkt = (READ_UID_CMD *)(rxBuf); 00478 if (debug_control & RXDATA_PRINT) 00479 pc.printf("DBG: Read UID: chan%02x\n", pRxPkt->chanIDSel); 00480 00481 sendUID(); 00482 } 00483 break; 00484 00485 case READ_FW_VERSION: 00486 { 00487 sendFWVersion(); 00488 if (debug_control & RXDATA_PRINT) 00489 pc.printf("DBG: Read SW Version\r\n"); 00490 00491 } 00492 break; 00493 00494 case DEBUG_CONTROL: 00495 { 00496 GUI_STANDARD_CMD *pRxPkt = (GUI_STANDARD_CMD *)rxBuf; 00497 debug_control = pRxPkt->commandData; 00498 if (debug_control & RXDATA_PRINT) 00499 pc.printf ("DBG: Rx'd DEBUG CMD: %04x\r\n", pRxPkt->commandData); 00500 } 00501 break; 00502 00503 00504 default: 00505 // Error 00506 break; 00507 } 00508 } 00509 00510 /* Function: get_temp 00511 ************************************************************** 00512 Description: Convert A/D count to temperature value 00513 Receives: ADC_val: the count from the A/D reading 00514 Returns: the temp. of the A/D reading 00515 */ 00516 00517 float get_temp(float ADC_val){ 00518 myled = 1; 00519 //ltc2487.setAddress(addrLUT[chn].adc); 00520 00521 //float ADC_val = ltc2487.readOutput(port); //(65536*1.334)/2.5 00522 00523 int i = 0; 00524 00525 while((i < sizeLUT) && (thermLUT[i].adc > ADC_val)){ 00526 i++; 00527 } //find the temp. above therm temp 00528 00529 //Point slope formula extrapolation: 00530 // m = (y1-y0)/(x1-x0)+ y0 , y = temp. value, x = adc value 00531 // y1 = thermLUT[i-1].temp y0 = thermLUT[i].temp 00532 // x1 = thermLUT[i-1].adc x0 =thermLUT[i].adc 00533 float a = float(thermLUT[i-1].temp - thermLUT[i].temp); //slope of temp between points where therm temp is between (Tmax - Tmin) 00534 float b = float(thermLUT[i-1].adc - thermLUT[i].adc); //slope of adc between points where therm adc is between (Amax - Amin) 00535 00536 float m = a/b; 00537 float y = (m*(ADC_val-thermLUT[i].adc))+thermLUT[i].temp; 00538 00539 if (debug_control & ADC_VAL_PRINT) 00540 pc.printf("DBG: ADC VAL: %f TEMP: %f \r\n", ADC_val, y); 00541 00542 return y; 00543 } 00544 00545 /* Function: get_front_temp_DATA 00546 ************************************************************** 00547 Description: Read A/D data from LTC2487 and set array with front temp. 00548 Save values in CHNL_TEMP data struct 00549 Receives: N/A 00550 Returns: int If the write recieved an ACK 00551 */ 00552 void read_front_temp_data() 00553 { 00554 readThermistorTicker.detach(); 00555 //Write to all 8 channels selecting the front port to read 00556 for(int chnl = 0; chnl < CHAN_COUNT; chnl++){ 00557 chnlStatus[chnl].LTCi2cAckRxed = 0; 00558 ltc2487.setAddress(addrLUT[chnl].adc); 00559 //Check if write was ack'ed (0 = ACK, (non)0 = NACK) 00560 chnlStatus[chnl].LTCi2cAckRxed = !ltc2487.writePort(FRONT_THERM); 00561 } 00562 //wait until next clock cycle on LTC 00563 //wait(I2C_READ_WAIT_TIME); 00564 frontTempInProgTicker.attach(&update_front_temp_data, I2C_READ_WAIT_TIME); 00565 } 00566 00567 void update_front_temp_data(){ 00568 float countVal; 00569 frontTempInProgTicker.detach(); 00570 for(int chnl = 0; chnl < CHAN_COUNT; chnl++){ 00571 ltc2487.setAddress(addrLUT[chnl].adc); 00572 countVal = ltc2487.read(); 00573 channelTempData[chnl].currADCFront = countVal; 00574 channelTempData[chnl].currTempFront = get_temp(countVal); 00575 } 00576 //wait until next clock cycle on LTC 00577 //wait(0.08); 00578 frontTempDoneTicker.attach(&read_back_temp, I2C_READ_WAIT_TIME); 00579 } 00580 00581 /* Function: get_back_temp_DATA 00582 ************************************************************** 00583 Description: Read A/D data from LTC2487 and set array with back temp. 00584 Save values in CHNL_TEMP data struct 00585 Receives: N/A 00586 Returns: N/A 00587 */ 00588 00589 void read_back_temp() 00590 { 00591 frontTempDoneTicker.detach(); 00592 //Write to all 8 channels selecting the front port to read 00593 for(int chnl = 0; chnl < CHAN_COUNT; chnl++){ 00594 chnlStatus[chnl].LTCi2cAckRxed = 0; 00595 ltc2487.setAddress(addrLUT[chnl].adc); 00596 //Check if write was ack'ed (0 = ACK, (non)0 = NACK) 00597 chnlStatus[chnl].LTCi2cAckRxed = !ltc2487.writePort(BACK_THERM); 00598 } 00599 00600 //wait until next clock cycle on LTC 00601 //wait(I2C_READ_WAIT_TIME); 00602 backTempInProgTicker.attach(&update_back_temp_data, I2C_READ_WAIT_TIME); 00603 } 00604 00605 void update_back_temp_data(){ 00606 float countVal; 00607 backTempInProgTicker.detach(); 00608 for(int chnl = 0; chnl < CHAN_COUNT; chnl++){ 00609 ltc2487.setAddress(addrLUT[chnl].adc); 00610 countVal = ltc2487.read(); 00611 channelTempData[chnl].currADCBack = countVal; 00612 channelTempData[chnl].currTempBack = get_temp(countVal); 00613 } 00614 //wait until next clock cycle on LTC 00615 //wait(0.08); 00616 backTempDoneTicker.attach(&temperatureDataReady, I2C_READ_WAIT_TIME); 00617 00618 } 00619 00620 /* Function: temperatureDataReady 00621 ************************************************************** 00622 Description: Flag that temperature data is ready to be 00623 processed 00624 Restart task timer 00625 Receives: N/A 00626 Returns: N/A 00627 */ 00628 void temperatureDataReady() 00629 { 00630 backTempDoneTicker.detach(); 00631 newTempDataAvailable = true; 00632 readThermistorTicker.attach(&read_front_temp_data, READ_TEMP_TASK_TIME); 00633 } 00634 00635 /* Function: get_heater_current 00636 ************************************************************** 00637 Description: Retrieve current into heater control MOSFET 00638 Receives: chn: the channel of the fixture to read current from 00639 Returns: the current into the heater control MOSFET 00640 */ 00641 void get_heater_current(int chn, int port){ 00642 ltc2487.setAddress(addrLUT[chn].adc); 00643 ltc2487.writePort(HEAT_FET_AMP); 00644 wait(0.08); 00645 ltc2487.read(); 00646 wait(0.08); 00647 } 00648 00649 /* Function: get_valve_current 00650 ************************************************************** 00651 Description: Retrieve current into valve control MOSFET 00652 Receives: chn: the channel of the fixture to read current from 00653 Returns: the current into the valve control MOSFET 00654 */ 00655 00656 void get_valve_current(int chn, int port){ 00657 ltc2487.setAddress(addrLUT[chn].adc); 00658 ltc2487.writePort(VALVE_FET_AMP); 00659 wait(0.08); 00660 ltc2487.read(); 00661 wait(0.08); 00662 } 00663 00664 /* Function: MCP_Control 00665 ************************************************************** 00666 Description: Controls valves/status LEDs 00667 Receives: chn: the channel of the fixture 00668 status: the status of channel (good (1) or bad (0)) 00669 Returns: N/A 00670 */ 00671 00672 void Chn_Control(int chn, int status){ 00673 //writeOutput(VALVE, HEATER, GREEN STATUS LED, RED STATUS LED) 00674 pc.printf("[%i] CHANNEL CONTROL \r\n", chn); 00675 if(status == VALVE_ON){ 00676 //valve ON, heater OFF, green status LED ON, red status led OFF 00677 if(debug_control & LED_PRINT) pc.printf("VALVE ON %d \r\n", chn); 00678 io_control.setAddress(addrLUT[chn].io); 00679 io_control.init(); 00680 chnlStatus[chn].MCPi2cAckRxed = 0; 00681 //Check if write was ack'ed (0 = ACK, (non)0 = NACK) 00682 chnlStatus[chn].MCPi2cAckRxed = !io_control.writeOutput(1,0,1,0); 00683 } 00684 if(status == HEATER_ON){ 00685 //valve ON, heater ON, green status LED ON, red status led OFF 00686 if(debug_control & LED_PRINT) pc.printf("HEATER ON %d \r\n", chn); 00687 io_control.setAddress(addrLUT[chn].io); 00688 io_control.init(); 00689 chnlStatus[chn].MCPi2cAckRxed = 0; 00690 //Check if write was ack'ed (0 = ACK, (non)0 = NACK) 00691 chnlStatus[chn].MCPi2cAckRxed = !io_control.writeOutput(0,1,1,0); 00692 } 00693 if(status == GREEN_STATUS_ON){ 00694 //valve OFF, heater OFF, green status LED ON, red status led OFF 00695 if(debug_control & LED_PRINT) pc.printf("GREEN LED %d \r\n", chn); 00696 io_control.setAddress(addrLUT[chn].io); 00697 io_control.init(); 00698 chnlStatus[chn].MCPi2cAckRxed = 0; 00699 //Check if write was ack'ed (0 = ACK, (non)0 = NACK) 00700 chnlStatus[chn].MCPi2cAckRxed = !io_control.writeOutput(0,0,1,0); 00701 } 00702 if(status == RED_STATUS_ON){ 00703 //valve OFF, heater OFF, green status LED OFF, red status led ON 00704 if(debug_control & LED_PRINT) pc.printf("RED LED %d \r\n", chn); 00705 io_control.setAddress(addrLUT[chn].io); 00706 io_control.init(); 00707 chnlStatus[chn].MCPi2cAckRxed = 0; 00708 //Check if write was ack'ed (0 = ACK, (non)0 = NACK) 00709 chnlStatus[chn].MCPi2cAckRxed = !io_control.writeOutput(0,0,0,1); 00710 } 00711 if(status == ERROR_STATUS_ON){ 00712 //valve ON, heater OFF, green status LED OFF, red status led ON 00713 if(debug_control & LED_PRINT) pc.printf("RED AND BLUE LED %d \r\n", chn); 00714 io_control.setAddress(addrLUT[chn].io); 00715 io_control.init(); 00716 chnlStatus[chn].MCPi2cAckRxed = 0; 00717 //Check if write was ack'ed (0 = ACK, (non)0 = NACK) 00718 chnlStatus[chn].MCPi2cAckRxed = !io_control.writeOutput(1,0,0,1); 00719 } 00720 if(status == ALL_OFF){ 00721 //valve OFF, heater OFF, green status LED OFF, red status led OFF 00722 if(debug_control & LED_PRINT) pc.printf("ALL OFF %d \r\n", chn); 00723 io_control.setAddress(addrLUT[chn].io); 00724 io_control.init(); 00725 chnlStatus[chn].MCPi2cAckRxed = 0; 00726 //Check if write was ack'ed (0 = ACK, (non)0 = NACK) 00727 chnlStatus[chn].MCPi2cAckRxed = !io_control.writeOutput(0,0,0,0); 00728 } 00729 } 00730 00731 00732 //*************************************************************** 00733 // Build packet with temperature readings to send to GUI 00734 //*************************************************************** 00735 void processTxUARTData() 00736 { 00737 RESPONSE_TEMP_CMD response; 00738 unsigned char *ptr = (unsigned char *)&response; 00739 int i; 00740 00741 response.SOF_flag = TX_SOF; 00742 response.cmd_type = TEMP_DATA; 00743 response.len = 5+(sizeof(response.chTemp)); 00744 response.Delim = DELIMETER; 00745 response.chTemp[0] = channelTempData[0].currTempBack; 00746 response.chTemp[1] = channelTempData[1].currTempBack; 00747 response.chTemp[2] = channelTempData[2].currTempBack; 00748 response.chTemp[3] = channelTempData[3].currTempBack; 00749 response.chTemp[4] = channelTempData[4].currTempBack; 00750 response.chTemp[5] = channelTempData[5].currTempBack; 00751 response.chTemp[6] = channelTempData[6].currTempBack; 00752 response.chTemp[7] = channelTempData[7].currTempBack; 00753 00754 // Send Errors Count/Info 00755 00756 /*float *dst = (float *)&response.chTemp[0]; 00757 float *src = (float *)&channelTempData[0]; 00758 memcpy(dst, src, sizeof(channelTempData));*/ 00759 response.EOF_flag = TX_EOF; 00760 00761 // Send response to GUI 00762 for (i=0; i < response.len; i++, ptr++) 00763 pc.printf("%02x", *ptr); 00764 pc.printf("\n"); 00765 } 00766 00767 //*************************************************************** 00768 // Build packet with Board UID (Unique Identification) 00769 //*************************************************************** 00770 void sendUID () 00771 { 00772 UID_RESPONSE response; 00773 unsigned char *ptr = (unsigned char *)&response; 00774 int i; 00775 00776 response.SOF_flag = TX_SOF; 00777 response.cmd_type = UID_DATA; 00778 response.len = 17; 00779 response.Delim = DELIMETER; 00780 response.UIDMH = (uint32_t)SIM->UIDMH; 00781 response.UIDML = (uint32_t)SIM->UIDML; 00782 response.UIDL = (uint32_t)SIM->UIDL; 00783 response.EOF_flag = TX_EOF; 00784 00785 // Send response to GUI 00786 for (i=0; i < response.len; i++, ptr++) 00787 pc.printf("%02x", *ptr); 00788 pc.printf("\n"); 00789 } 00790 00791 //*************************************************************** 00792 // Build packet with SW Version 00793 //*************************************************************** 00794 void sendFWVersion() 00795 { 00796 FW_VERSION_RESPONSE response; 00797 unsigned char *ptr = (unsigned char *)&response; 00798 int i; 00799 rLed = 1; 00800 00801 for (i=0; i < 20; i++) 00802 rLed = 0; 00803 00804 rLed = 1; 00805 00806 response.SOF_flag = TX_SOF; 00807 response.cmd_type = FW_VERSION_DATA; 00808 response.len = 13; 00809 response.Delim = DELIMETER; 00810 memcpy(response.FW_Version, FW_Version, 8); 00811 response.FW_Version[7] = '\0'; 00812 response.EOF_flag = TX_EOF; 00813 00814 // Send response to GUI 00815 for (i=0; i < response.len; i++, ptr++) 00816 pc.printf("%02x", *ptr); 00817 pc.printf("\n"); 00818 } 00819 00820 //*************************************************************** 00821 // Build packet with errors to send to GUI 00822 //*************************************************************** 00823 void sendError (int chan, float error) 00824 { 00825 RESPONSE_CMD response; 00826 unsigned char *ptr = (unsigned char *)&response; 00827 int i; 00828 00829 response.SOF_flag = TX_SOF; 00830 response.cmd_type = ERROR_DATA; 00831 response.len = 13; 00832 response.Delim = DELIMETER; 00833 response.channel = chan; 00834 response.data = (float)error; 00835 00836 response.EOF_flag = TX_EOF; 00837 00838 // Send response to GUI 00839 for (i=0; i < response.len; i++, ptr++) 00840 pc.printf("%02x", *ptr); 00841 pc.printf("\n"); 00842 00843 } 00844 00845 /* Function: toggleI2C 00846 ************************************************************** 00847 Description: Toggle the I2C line in an attempt to unfreeze it 00848 Receives: N/A 00849 Returns: N/A 00850 */ 00851 00852 void toggleI2C(){ 00853 DigitalOut ioSDAIn(PTC9); 00854 DigitalOut adcSDAIn(PTC11); 00855 DigitalOut ioSCLIn(PTC8); 00856 DigitalOut adcSCLIn(PTC10); 00857 00858 ioSDAIn = 1; 00859 adcSDAIn = 1; 00860 ioSCLIn = 1; 00861 adcSCLIn = 1; 00862 wait(0.5); 00863 ioSDAIn = 0; 00864 adcSDAIn = 0; 00865 ioSCLIn = 0; 00866 adcSCLIn = 0; 00867 wait(0.5); 00868 ioSDAIn = 1; 00869 adcSDAIn = 1; 00870 ioSCLIn = 1; 00871 adcSCLIn = 1; 00872 wait(0.5); 00873 ioSDAIn = 0; 00874 adcSDAIn = 0; 00875 ioSCLIn = 0; 00876 adcSCLIn = 0; 00877 wait(0.5); 00878 00879 MCP23008 io_control(PTC9, PTC8, 0x10, 100000); //sda, scl 00880 LTC2487 ltc2487(PTC11, PTC10, 0x23, 100000); //sda, scl 00881 00882 } 00883 00884 /* Function: sendErrorEmail 00885 ************************************************************** 00886 Description: sends error email 00887 Receives: chn: channel to check error on 00888 Returns: N/A 00889 */ 00890 00891 void sendErrorEmail(int chn){ 00892 int error; 00893 00894 for (error=0; error < ERROR_COUNT; error++){ 00895 if((errorCount[chn][error] == MAX_ERROR_CNT) && (!errorEmailSent[chn][error])){ 00896 sendError(chn, error); 00897 errorEmailSent[chn][error] = 1; 00898 } 00899 } 00900 } 00901 00902 /* Function: errorCheck 00903 ************************************************************** 00904 Description: Updates error count for the channel 00905 Receives: chn: channel to update 00906 errorFlag: if the error was encountered 00907 errorNum: number of error encountered 00908 Returns: N/A 00909 */ 00910 00911 void errorCheck(int chn, bool errorFlag, int errorNum){ 00912 if(errorFlag){ 00913 if(errorCount[chn][errorNum] < MAX_ERROR_CNT){ 00914 //increase error count 00915 errorCount[chn][errorNum]++; 00916 pc.printf("[%i] ERROR ENCOUNTERED: %i %i \r\n", chn, errorNum, errorCount[chn][errorNum]); 00917 } 00918 else{ 00919 //this is an error, set error flag 00920 chnlStatus[chn].error = true; 00921 //pc.printf("[%i] ERROR FLAGGED: %i %i\r\n", chn, errorNum, errorCount[chn][errorNum]); 00922 } 00923 } 00924 else{ 00925 if(errorCount[chn][errorNum] > 0){ 00926 //decrease error count 00927 errorCount[chn][errorNum]--; 00928 } 00929 //pc.printf("[%i] NO ERROR FLAGGED: %i \r\n\n", chn, errorNum); 00930 } 00931 } 00932 00933 /* Function: softwareReset 00934 ************************************************************** 00935 Description: soft reset 00936 Recieves: N/A 00937 Returns: N/A 00938 */ 00939 00940 void softwareReset(void){ 00941 SCB->AIRCR = (0x5FA<<SCB_AIRCR_VECTKEY_Pos)|SCB_AIRCR_SYSRESETREQ_Msk; 00942 for(;;){} 00943 } 00944 00945 /* Function: SP_Time_Check 00946 ************************************************************** 00947 Description: Reset the SP time for each channel every minute 00948 (minutes since SP has been set and SP hasn't been reach) 00949 Recieves: N/A 00950 Returns: N/A 00951 */ 00952 00953 void SP_Time_Check(){ 00954 int chan; 00955 00956 for (chan=0; chan < CHAN_COUNT; chan++){ 00957 if(chnlStatus[chan].status == 1){ 00958 if(!chnlStatus[chan].SPReached){ 00959 if(chnlStatus[chan].SPTime != MAX_TIME_TO_SP){ 00960 chnlStatus[chan].SPTime++; 00961 } 00962 } 00963 } 00964 } 00965 } 00966 00967 /* Function: read I2C Line 00968 ************************************************************** 00969 Description: Read the I2C line to check if pulled high 00970 Receives: N/A 00971 Returns: N/A 00972 */ 00973 00974 int readI2CLine(int line) 00975 { 00976 if(line == IO_I2C_LINE){ 00977 DigitalIn ioSDAIn(PTC9); 00978 int ioSDA = ioSDAIn.read(); 00979 if(I2C_PRINT) pc.printf("DBG: TEMPERATURE SDA LINE: %d \r\n", ioSDA); 00980 MCP23008 io_control(PTC9, PTC8, 0x10, 100000); //sda, scl 00981 return ioSDA; 00982 } 00983 if(line == ADC_I2C_LINE){ 00984 DigitalIn adcSDAIn(PTC11); 00985 int adcSDA = adcSDAIn.read(); 00986 if(I2C_PRINT) pc.printf("DBG: IO SDA LINE: %d \r\n", adcSDA); 00987 LTC2487 ltc2487(PTC11, PTC10, 0x23, 100000); //sda, scl 00988 return adcSDA; 00989 } 00990 return 0; 00991 } 00992 00993 00994 /* Function: systemLogic 00995 ************************************************************** 00996 Description: Sets setting for fixture needed to maintain temperature at SP 00997 Receives: N/A 00998 Returns: N/A 00999 */ 01000 01001 void systemLogic(){ 01002 int chan; 01003 float currTemp; 01004 01005 for (chan=0; chan < CHAN_COUNT; chan++) 01006 { 01007 if(chnlStatus[chan].status == 1){ 01008 //Current Temperature 01009 currTemp = channelTempData[chan].currTempBack; 01010 01011 if(currTemp > ((chnlStatus[chan].setTemp)+HYST_HIGH)){ 01012 //TURN COOLING ON 01013 chnlStatus[chan].state = STATUS_COOLING; 01014 } 01015 else if(currTemp < ((chnlStatus[chan].setTemp)-HYST_LOW)){ 01016 //TURN HEATER ON 01017 chnlStatus[chan].state = STATUS_HEATING; 01018 } 01019 else{ 01020 //FIXTURE INACTIVE 01021 chnlStatus[chan].state = STATUS_INACTIVE; 01022 } 01023 } 01024 else{ 01025 //FIXTURE STANDBY 01026 pc.printf("FIXTURE IN STANDBY \r\n"); 01027 chnlStatus[chan].state = STATUS_STANDBY; 01028 } 01029 } 01030 01031 } 01032 01033 /* Function: systemControl 01034 ************************************************************** 01035 Description: Changes fixture setting in accordance to logic set in systemLOGIC function 01036 Receives: N/A 01037 Returns: N/A 01038 */ 01039 01040 void systemControl() 01041 { 01042 int chan; 01043 01044 for (chan=0; chan < CHAN_COUNT; chan++){ 01045 pc.printf("[%i] CHANNEL ERRORS: %d \r\n", chan, chnlStatus[chan].error); 01046 if(!chnlStatus[chan].error){ 01047 //pc.printf("[%i] CHANNEL NO ERRORS \r\n", chan); 01048 if(errorCount[chan][ERR_ACK_LTC] == 0){ 01049 if(chnlStatus[chan].state == STATUS_INACTIVE){ 01050 //FIXTURE INACTIVE 01051 Chn_Control(chan, GREEN_STATUS_ON); 01052 //SP reached 01053 chnlStatus[chan].SPReached = true; 01054 } 01055 else if(chnlStatus[chan].state == STATUS_COOLING){ 01056 //TURN COOLING ON 01057 Chn_Control(chan, VALVE_ON); 01058 } 01059 else if(chnlStatus[chan].state == STATUS_HEATING){ 01060 //TURN HEATER ON (have to toggle bc of charge pump in circuit) 01061 Chn_Control(chan, GREEN_STATUS_ON); //turn heater off 01062 Chn_Control(chan, HEATER_ON); 01063 } 01064 else if(chnlStatus[chan].state == STATUS_STANDBY){ 01065 //FIXTURE IN STANDBY (i.e. off) 01066 if(standbyLED[chan]){ 01067 Chn_Control(chan, GREEN_STATUS_ON); 01068 standbyLED[chan] = !standbyLED[chan]; 01069 } 01070 else{ 01071 Chn_Control(chan, ALL_OFF); 01072 standbyLED[chan] = !standbyLED[chan]; 01073 } 01074 } 01075 } 01076 } 01077 else{ 01078 sendErrorEmail(chan); 01079 } 01080 } 01081 } 01082 01083 /* Function: systemDiagnostic 01084 ************************************************************** 01085 Description: Checks for any system errors 01086 Receives: chn: Channel to modify 01087 Returns: N/A 01088 */ 01089 01090 void systemDiagnostic(){ 01091 int chan; 01092 float backCount; 01093 float frontCount; 01094 float backTemp; 01095 float frontTemp; 01096 bool errorFlag; 01097 float tempDiff; 01098 int LTC_Ack; 01099 int MCP_Ack; 01100 int timeToSP; 01101 bool reachedSP; 01102 01103 for (chan=0; chan < CHAN_COUNT; chan++){ 01104 backCount = channelTempData[chan].currADCBack; 01105 frontCount = channelTempData[chan].currADCFront; 01106 frontTemp = channelTempData[chan].currTempFront; 01107 backTemp = channelTempData[chan].currTempBack; 01108 LTC_Ack = chnlStatus[chan].LTCi2cAckRxed; 01109 MCP_Ack = chnlStatus[chan].MCPi2cAckRxed; 01110 timeToSP = chnlStatus[chan].SPTime; 01111 reachedSP = chnlStatus[chan].SPReached; 01112 01113 if(PRINT_ERROR_CHECK_VALS){ 01114 pc.printf("BAKC COUNT: %f \r\n", backCount); 01115 pc.printf("FRONT COUNT: %f \r\n", frontCount); 01116 pc.printf("TEMP DIFF: %f \r\n", abs(frontTemp-backTemp)); 01117 pc.printf("LTC ACK: %f \r\n", LTC_Ack); 01118 pc.printf("MCP ACK: %f \r\n", MCP_Ack); 01119 } 01120 01121 //Check if the ADC temperature is too high (low ADC count) 01122 errorFlag = false; 01123 if((backCount < MIN_AD_COUNT) || (frontCount < MIN_AD_COUNT)) errorFlag = true; 01124 errorCheck(chan, errorFlag, ERR_OVER_TEMP); 01125 01126 //Check if the ADC temperature is too low (high ADC count), valve stuck on 01127 errorFlag = false; 01128 if((backCount > MAX_AD_COUNT) || (frontCount > MAX_AD_COUNT)) errorFlag = true; 01129 errorCheck(chan, errorFlag, ERR_UNDER_TEMP); 01130 01131 //Check for a substantial temp. diff. |b| the front & back of the fixture 01132 errorFlag = false; 01133 tempDiff = abs(frontTemp-backTemp); 01134 if(tempDiff > TEMP_MARGIN) errorFlag = true; 01135 errorCheck(chan, errorFlag, ERR_TEMP_DIFF); 01136 01137 //Check for ACK from the LTC2487 chip (temperature reading) 01138 errorFlag = false; 01139 if(!LTC_Ack) errorFlag = true; 01140 errorCheck(chan, errorFlag, ERR_ACK_LTC); 01141 01142 //Check for ACK from the MCP23008 chip (valve/heater controller) 01143 /*errorFlag = false; 01144 if(!MCP_Ack) errorFlag = true; 01145 errorCheck(chan, errorFlag, ERR_ACK_MCP);*/ 01146 01147 //Check if the fixture has not reached SP in X amount of time 01148 errorFlag = false; 01149 if(!reachedSP && (timeToSP == MAX_TIME_TO_SP)) errorFlag = true; 01150 errorCheck(chan, errorFlag, ERR_SP_TIME); 01151 01152 } 01153 } 01154 01155 /*************************************************************/ 01156 /* NEW MAIN FUNCTION */ 01157 /*************************************************************/ 01158 01159 int main(){ 01160 /* INITIALIZATION CODE */ 01161 // Setup serial port 01162 // Look for RX_EOF 01163 uint32_t UIDMH, UIDML, UIDL; 01164 int UID_print_count = 0; 01165 //resetErrorCount(); 01166 01167 01168 //********************************* 01169 // Initial thermistors readings 01170 // Kick of SP time updates 01171 // Kick off temperature reading 01172 // state machine 01173 //********************************* 01174 readThermistorTicker.attach(&read_front_temp_data, .0001); 01175 //setPointTimeTicker.attach(&SP_Time_Check, 60); 01176 01177 pc.baud(9600); 01178 pc.autoDetectChar(RX_EOF); 01179 pc.attach(&rxInterrupt, MODSERIAL::RxAutoDetect); 01180 01181 UIDMH = (uint32_t)SIM->UIDMH; 01182 UIDML = (uint32_t)SIM->UIDML; 01183 UIDL = (uint32_t)SIM->UIDL; 01184 01185 //print UID three times on start-up to ID Mbed board 01186 if(UID_print_count++ < 3) 01187 pc.printf("DBG: [UID: %04X%08X%08X]\n", UIDMH, UIDML, UIDL); 01188 01189 01190 while(1) { 01191 //********************************* 01192 // Process Rx UART data from GUI 01193 //********************************* 01194 //pc.printf("LOOP \r\n"); 01195 if (dataReceived) 01196 { 01197 dataReceived = false; 01198 if (debug_control & RXDATA_PRINT) 01199 pc.printf("DBG: %d bytes Rx'd\n", pc.rxBufferGetCount()); 01200 01201 pc.move(rxBuf, 50); 01202 processRxUARTData(); 01203 pc.rxBufferFlush(); 01204 } 01205 01206 //********************************* 01207 // Logic Loop 01208 //********************************* 01209 // System Logic/Control 01210 if (newTempDataAvailable) 01211 systemLogic(); 01212 01213 //********************************* 01214 // System Diagnostic & Error Check 01215 //********************************* 01216 systemDiagnostic(); 01217 01218 //********************************* 01219 // Process Tx UART data 01220 // Send Temperature Data/Error to GUI 01221 //********************************* 01222 if (newTempDataAvailable) 01223 { 01224 processTxUARTData(); 01225 01226 //********************************* 01227 //Actuate Loop 01228 //********************************* 01229 systemControl(); 01230 newTempDataAvailable = false; 01231 } 01232 } 01233 }
Generated on Sun Jul 24 2022 23:58:38 by
1.7.2