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.
Fork of TCTF_Control_Main by
main.cpp
- Committer:
- jrodenburg
- Date:
- 2018-05-07
- Revision:
- 9:1cada1fe4743
- Parent:
- 8:dbf8bd4815f8
- Child:
- 13:604e6933366f
File content as of revision 9:1cada1fe4743:
// MBED SCRIPT FOR CONTROLLING THE TEMPERATURE CONTROLLED TEST FIXTURE (TCTF)
// DATE: SEPTEMBER 2017
#include "mbed.h"
#include "MODSERIAL.h"
#include "MCP23008.h"
#include "LTC2487.h"
#include <string>
//DEFINITIVE VARIABLES
#define DEBUG 0
#define DEBUG1 0
#define DEBUG2 0
#define DEBUG3 1
#define CHN_COUNT 8
#define MIN_TEMP 10
#define MAX_TEMP 65
#define TEMP_MARGIN 20
#define HYST_LOW 0.3
#define HYST_HIGH 1.5
#define SAMPLES 5
#define I2C_Freq 2000
#define VALVE 1
#define HEATER 2
#define STATUS_GOOD 3
#define STATUS_BAD 0
#define sizeLUT 34
#define BACK_THERM 0
#define FRONT_THERM 1
#define HEAT_FET_AMP 2
#define VALVE_FET_AMP 3
#define FET_ON_CURRENT 1.12
#define ROOM_TEMP 22
// Defines for use with Serial communication
#pragma pack (1)
#define RX_SOF 0x7B
#define RX_EOF 0x7D
#define TX_SOF 0x7B
#define TX_EOF 0x7D
#define DELIMETER 0x2E
#define SET_TEMPERATURE 0xB0
#define SELECT_CHANNEL 0xB1
#define CMD_RESPONSE 0xD0
#define CMD_DATA 0xD1
#define ERROR_DATA 0xD2
unsigned int chanSel_SendTemp = 0;
unsigned int chanSel_SetTemp = 0;
// Default to chan 0
int currChan = 0;
bool newTempSet = false;
//***********************************************
// Serial Rx Packet Format
//***********************************************
typedef struct {
unsigned char SOF_flag;
unsigned char cmd_type;
unsigned char len;
unsigned char Delim;
} HOST_CMD_HEADER;
typedef struct {
HOST_CMD_HEADER cmd_header;
unsigned char chanID;
unsigned char tempDelim;
float setTemp;
unsigned char chanStatDelim;
unsigned char chanStat;
} SET_TEMPERATURE_CMD;
typedef struct {
HOST_CMD_HEADER cmd_header;
unsigned char chanIDSel;
unsigned char chanDelim;
unsigned char chanStat;
} SELECT_CHANNEL_CMD;
typedef struct {
unsigned char SOF_flag;
unsigned char cmd_type;
unsigned char len;
unsigned char Delim;
float data;
unsigned char EOF_flag;
} RESPONSE_CMD;
//TCTF CHANNEL DATA
struct CHNL_DATA{
bool status;
float setTemp;
bool error;
};
CHNL_DATA chnlStatus[] = {
{0, NULL, 0},
{0, NULL, 0},
{0, NULL, 0},
{0, NULL, 0},
{0, NULL, 0},
{0, NULL, 0},
{0, NULL, 0},
{0, NULL, 0},
{0, NULL, 0},
{0, NULL, 0},
{0, NULL, 0},
{0, NULL, 0},
{0, NULL, 0},
{0, NULL, 0},
{0, NULL, 0},
{0, NULL, 0},
{0, NULL, 0},
{0, NULL, 0},
{0, NULL, 0},
{0, NULL, 0},
{0, NULL, 0},
{0, NULL, 0},
{0, NULL, 0},
{0, NULL, 0},
{0, NULL, 0},
{0, NULL, 0},
{0, NULL, 0},
{0, NULL, 0},
{0, NULL, 0},
{0, NULL, 0},
{0, NULL, 0},
{0, NULL, 0},
{0, NULL, 0},
{0, NULL, 0},
{0, NULL, 0},
{0, NULL, 0},
{0, NULL, 0},
{0, NULL, 0},
{0, NULL, 0},
{0, NULL, 0},
{0, NULL, 0},
{0, NULL, 0},
{0, NULL, 0},
{0, NULL, 0},
{0, NULL, 0},
{0, NULL, 0},
{0, NULL, 0},
{0, NULL, 0},
};
//I2C AADRESS LOOK UP TABLE, CREATED IN EXCEL SHEET (COUNT, TEMP)
struct I2C_ADDR_LUT{
int adc;
int io;
};
I2C_ADDR_LUT addrLUT[] = {
{0x23, 0x10},
{0x53, 0x60},
{0x43, 0x70},
{0x73, 0x40},
{0x63, 0x50},
{0x22, 0x11},
{0x52, 0x61},
{0x42, 0x71},
{0x72, 0x41},
{0x62, 0x51},
{0x21, 0x12},
{0x51, 0x62},
{0x41, 0x72},
{0x71, 0x42},
{0x61, 0x52},
{0x20, 0x13},
{0x50, 0x63},
{0x40, 0x73},
{0x70, 0x43},
{0x60, 0x53},
{0x26, 0x14},
{0x56, 0x64},
{0x46, 0x74},
{0x76, 0x44},
{0x66, 0x54},
{0x2C, 0x1F},
{0x5C, 0x6F},
{0x4C, 0x7F},
{0x7C, 0x4F},
{0x6C, 0x5F},
{0x2D, 0x1E},
{0x5D, 0x6E},
{0x4D, 0x7E},
{0x7D, 0x4E},
{0x6D, 0x5E},
{0x2E, 0x1D},
{0x5E, 0x6D},
{0x4E, 0x7D},
{0x7E, 0x4D},
{0x6E, 0x5D},
{0x2F, 0x1C},
{0x5F, 0x6C},
{0x4F, 0x7C},
{0x7F, 0x4C},
{0x6F, 0x5C},
{0x20, 0x1B},
{0x50, 0x6B},
{0x40, 0x7B},
};
//THERMISTOR LOOK UP TABLE, CREATED IN EXCEL SHEET (COUNT, TEMP)
struct THERM_LUT{
int adc;
int temp;
};
THERM_LUT thermLUT[] = {
{113779,-40},
{109152,-35},
{103830,-30},
{97855,-25},
{91319,-20},
{84352,-15},
{77124,-10},
{69820,-5},
{62621,0},
{55693,5},
{49169,10},
{43144,15},
{37669,20},
{32768,25},
{28429,30},
{24622,35},
{21309,40},
{18439,45},
{15962,50},
{13831,55},
{12002,60},
{10428,65},
{9080,70},
{7919,75},
{6923,80},
{6063,85},
{5323,90},
{4685,95},
{4130,100},
{3653,105},
{3234,110},
{2876,115},
{2563,120},
{2284,125}
};
//SERIAL COMMUNICATION SETUP
MODSERIAL pc(USBTX, USBRX);
//DEFINE PINS
DigitalOut myled(LED2);
//I2C FOR MCP23008 (I/O Control)
MCP23008 io_control(PTC9, PTC8, 0x10, 100000); //sda, scl
//I2C FOR LTC2487 (ADC Control)
LTC2487 ltc2487(PTC11, PTC10, 0x23, 100000); //sda, scl
//GLOBAL VARIABLES
volatile bool dataReceived = false; //used to check if data has been received
volatile bool dataTxReady = false;
char rxBuf[50];
int chnlSel;
/* Function: turnOffChannel
**************************************************************
Description: Turns off a channel
Recieves: chnl: channel to turn off
Returns: N/A
*/
void turnOffChannel(int chnl){
io_control.setAddress(addrLUT[chnl].io);
io_control.init();
io_control.writeOutput(0,0,0,0);
}
/* Function: rxInterrupt
**************************************************************
Description: serial rx interupt handler
Receives: N/A
Returns: N/A
*/
DigitalOut rLed(LED1);
DigitalOut gLed(LED2);
//***********************************************
// Rx Interrupt from serial Host interface
//***********************************************
void rxInterrupt(MODSERIAL_IRQ_INFO *info)
{
gLed = 0;
dataReceived = true;
gLed = 1;
}
//***************************************************************
// Tx Interrupt from serial Host interface
//***************************************************************
void txInterrupt(MODSERIAL_IRQ_INFO *info)
{
dataTxReady = true;
}
/* Function: parseRXData
**************************************************************
Description: The parse received data into
Receives: chn: The channel we want to put into the channel
Returns: N/A
*/
void parseRXData()
{
HOST_CMD_HEADER *pRxPktHdr;
string data = "";
unsigned char *ptemp;
int i;
pRxPktHdr = (HOST_CMD_HEADER *)rxBuf;
#ifdef DEBUG
pc.printf("DBG: fl = %02x\n", pRxPktHdr->SOF_flag);
pc.printf("DBG: len = %02x\n", pRxPktHdr->len);
#endif
// Exit if the packet does not contain correct header
// Maybe send NAK?
if ((pRxPktHdr->SOF_flag != RX_SOF) || (pRxPktHdr->Delim != DELIMETER))
return;
switch (pRxPktHdr->cmd_type)
{
case SET_TEMPERATURE:
// Process set temp for specified channel
{
SET_TEMPERATURE_CMD *pRxPkt = (SET_TEMPERATURE_CMD *)(rxBuf);
#if 1 //def DEBUG
pc.printf("DBG: ch = %02x\n", pRxPkt->chanID);
pc.printf("DBG: tempSet = %f\n", pRxPkt->setTemp);
pc.printf("DBG: chanStat = %02x\n", pRxPkt->chanStat);
#endif
if ((pRxPkt->tempDelim != DELIMETER) || (pRxPkt->chanStatDelim != DELIMETER)) {
// Send NAK back
pc.printf("DBG: Error\n");
}
else {
chanSel_SetTemp = pRxPkt->chanID;
chnlStatus[pRxPkt->chanID].status = pRxPkt->chanStat;
chnlStatus[pRxPkt->chanID].setTemp = pRxPkt->setTemp;
chnlStatus[pRxPkt->chanID].error = 0;
newTempSet = true;
}
}
break;
case SELECT_CHANNEL:
// Select channel to send temp data to
{
SELECT_CHANNEL_CMD *pRxPkt = (SELECT_CHANNEL_CMD *)(rxBuf);
chanSel_SendTemp = pRxPkt->chanIDSel;
#if 1 //def DEBUG
pc.printf("DBG: chanSel = %02x\n", pRxPkt->chanIDSel);
pc.printf("DBG: chanStat = %02x\n", pRxPkt->chanStat);
#endif
}
break;
default:
// Error
break;
}
}
/* Function: get_temp
**************************************************************
Description: Retrieve data from thermistor
Receives: chn: the channel of the fixture to read temp. from
port: the I/O channel to read
Returns: the temperature of the fixture (front or back)
*/
float get_temp(int chn, int port){
myled = 1;
ltc2487.setAddress(addrLUT[chn].adc);
float ADC_val = ltc2487.readOutput(port); //(65536*1.334)/2.5
int i = 0;
while((i < sizeLUT) && (thermLUT[i].adc > ADC_val)){
i++;
} //find the temp. above therm temp
//Point slope formula extrapolation:
// y1 = m (x1-x0)+ y0 , y = temp. value, x = adc value
// y1 = thermLUT[i-1].temp y0 = thermLUT[i].temp
// x1 = thermLUT[i-1].adc x0 =thermLUT[i].adc
float a = float(thermLUT[i-1].temp - thermLUT[i].temp); //slope of temp between points where therm temp is between (Tmax - Tmin)
float b = float(thermLUT[i-1].adc - thermLUT[i].adc); //slope of adc between points where therm adc is between (Amax - Amin)
float m = a/b;
float y = (m*(ADC_val-thermLUT[i].adc))+thermLUT[i].temp;
if(DEBUG2) pc.printf("DBG: CHAN: %i PORT: %i ADC VAL: %f TEMP: %f \r\n", chn, port, ADC_val, y);
return y;
}
/* Function: get_heater_current
**************************************************************
Description: Retrieve current into heater control MOSFET
Receives: chn: the channel of the fixture to read current from
Returns: the current into the heater control MOSFET
*/
float get_heater_current(int chn, int port){
return ltc2487.readOutput(port);
}
/* Function: get_valve_current
**************************************************************
Description: Retrieve current into valve control MOSFET
Receives: chn: the channel of the fixture to read current from
Returns: the current into the valve control MOSFET
*/
float get_valve_current(int chn, int port){
return ltc2487.readOutput(port);
}
/* Function: turn_valve_on
**************************************************************
Description: Turn valve on and green status LED on
Receives: chn: the channel of the fixture
Returns: N/A
*/
void turn_valve_on(int chn){
io_control.setAddress(addrLUT[chn].io);
io_control.init();
io_control.writeOutput(1,0,1,0);
}
/* Function: turn_valve_off
**************************************************************
Description: Turn valve off and green status LED on
Receives: chn: the channel of the fixture
Returns: N/A
*/
void turn_valve_off(int chn){
io_control.setAddress(addrLUT[chn].io);
io_control.init();
io_control.writeOutput(0,0,1,0);
}
/* Function: turn_heater_on
**************************************************************
Description: Turn heater on and green status LED on
Receives: chn: the channel of the fixture
Returns: N/A
*/
void turn_heater_on(int chn){
io_control.setAddress(addrLUT[chn].io);
io_control.init();
io_control.writeOutput(0,1,1,0);
}
/* Function: turn_heater_off
**************************************************************
Description: Turn heater off and green status LED on
Receives: chn: the channel of the fixture
Returns: N/A
*/
void turn_heater_off(int chn){
io_control.setAddress(addrLUT[chn].io);
io_control.init();
io_control.writeOutput(0,0,1,0);
}
/* Function: status_led
**************************************************************
Description: Turn status LED on (turns on green or red)
Receives: chn: the channel of the fixture
status: the status of channel (good (1) or bad (0))
Returns: N/A
*/
void status_led(int chn, int status){
io_control.setAddress(addrLUT[chn].io);
if(status){
io_control.writeOutput(0,0,1,0);
}
else{
//turn valve on too
io_control.writeOutput(1,0,0,1);
}
}
/* Function: test_mcp23008
**************************************************************
Description: Test each output of the MCP23009
Receives: N/A
Returns: N/A
*/
void test_mcp23008(int chn){
turn_valve_on(chn);
wait(0.5);
turn_valve_off(chn);
wait(0.5);
turn_heater_on(chn);
wait(0.5);
turn_heater_off(chn);
wait(0.5);
status_led(chn, 0);
wait(0.5);
status_led(chn, 1);
}
/* Function: test_ltc2487
**************************************************************
Description: Test the reading from LTC2487
Receives: N/A
Returns: N/A
*/
void test_ltc2487(int chn){
get_temp(chn, FRONT_THERM);
wait(0.1);
get_temp(chn, BACK_THERM);
wait(0.1);
get_temp(chn, VALVE_FET_AMP);
wait(0.1);
//if(DEBUG1) pc.printf("TEMPERATURE READING: %f \r\n", get_temp(chn));
}
/* Function: error_check
**************************************************************
Description: Checks for any system errors
Recieves: frontTemp: temp. of front thermistor
backTemp: temp. of back thermistor
valveFet: current through valve FET
heaterFet: current through heater FET
Returns: N/A
*/
void error_check(int chn, float frontTemp, float backTemp, float valveFet, float heaterFet){
float setTemp = chnlStatus[chn].setTemp;
//CHECK IF THERMISTOR READINGS ARE OFF (> 5 DEGREES)
if(abs(frontTemp-backTemp) > 5){
//ERROR 6: Thermistor reading off
chnlStatus[chn].error = 1;
}
//CHECK IF HEATER'S STUCK ON OR CELL OVERHEATING
if((frontTemp >= (setTemp+TEMP_MARGIN)) || (backTemp >= (setTemp+TEMP_MARGIN))){
//ERROR 0
chnlStatus[chn].error = 1;
status_led(chn, STATUS_BAD);
if(heaterFet >= FET_ON_CURRENT){
//ERROR 1: Heater FET stuck on
}
if(valveFet <= FET_ON_CURRENT){
//ERROR 2: valve FET stuck off
}
}
//CHECK IF VALVE STUCK ON OR CELL OVERHEATING
if((frontTemp <= (setTemp-TEMP_MARGIN)) || (backTemp <= (setTemp-TEMP_MARGIN))){
//ERROR 0
chnlStatus[chn].error = 1;
status_led(chn, STATUS_BAD);
if(heaterFet <= FET_ON_CURRENT){
//ERROR 2: Heater FET stuck off
}
else if(valveFet >= FET_ON_CURRENT){
//ERROR 3: Chiller FET stuck on
}
}
}
//***************************************************************
// Build packet with temperature readings to send to GUI
//***************************************************************
void sendTempReadings (int chan, float currentTemp)
{
RESPONSE_CMD response;
unsigned char *ptr = (unsigned char *)&response;
int i;
response.SOF_flag = TX_SOF;
response.cmd_type = CMD_DATA;
response.len = 9;
response.Delim = DELIMETER;
response.data = (float)currentTemp;
response.EOF_flag = TX_EOF;
// Send response to GUI
for (i=0; i < response.len; i++, ptr++)
pc.printf("%02x", *ptr);
pc.printf("\n");
}
//***************************************************************
// Build packet with errors to send to GUI
//***************************************************************
void sendError (int chan, float error)
{
RESPONSE_CMD response;
unsigned char *ptr = (unsigned char *)&response;
int i;
response.SOF_flag = TX_SOF;
response.cmd_type = ERROR_DATA;
response.len = 9;
response.Delim = DELIMETER;
response.data = (float)error;
response.EOF_flag = TX_EOF;
// Send response to GUI
for (i=0; i < response.len; i++, ptr++)
pc.printf("%02x", *ptr);
pc.printf("\n");
}
/*************************************************************/
/* MAIN FUNCTION */
/*************************************************************/
int main() {
Timer t;
// Setup serial port
// Look for RX_EOF
pc.baud(9600);
pc.autoDetectChar(RX_EOF);
pc.attach(&rxInterrupt, MODSERIAL::RxAutoDetect);
myled = 1;
rLed = 1;
gLed = 0;
t.start();
while(1) {
if(DEBUG3)
pc.printf("DBG: PROGRAM STARTED \r\n");
for(int chnl = 0; chnl < CHN_COUNT; chnl++){
float currentTempFront = get_temp(chnl, FRONT_THERM);
wait(0.08);
float currentTempBack = get_temp(chnl, BACK_THERM);
//float valveCurrent = get_valve_current(chnl, VALVE_FET_AMP);
//float heaterCurrent = get_heater_current(chnl, HEAT_FET_AMP);
float currentTemp = currentTempFront;
//currentTemp = currentTempFront;
currentTemp = currentTempBack;
//check if we received data/need to update TCTF data
if(dataReceived){
dataReceived = false;
pc.printf("DBG: %d bytes Rx'd\n", pc.rxBufferGetCount());
pc.move(rxBuf, 50);
parseRXData();
pc.rxBufferFlush();
}
if (chnl == chanSel_SendTemp){
//Send temp readings for selected chan to GUI
sendTempReadings(currChan, currentTemp);
}
//CONTROL LOOP:
if(chnlStatus[chnl].status == 1){
if(DEBUG3) pc.printf("DBG: [%d] Temp: F: %f B: %f\r\n", chnl, currentTempFront, currentTempBack);
//Error check on fixture
//error_check(chnl, currentTempFront, currentTempBack, valveCurrent, heaterCurrent);
if(((currentTempFront >= MAX_TEMP) && (currentTempBack >= MAX_TEMP)) ||
((currentTempFront == 0) || (currentTempBack == 0))||
(abs(currentTempBack - currentTempFront) >= TEMP_MARGIN)||
((currentTempFront <= MIN_TEMP) && (currentTempBack <= MIN_TEMP))){
status_led(chnl, STATUS_BAD);
sendError(chnl, 1);
chnlStatus[chnl].error = 1;
}
if(chnlStatus[chnl].error == 0){
if(currentTemp > ((chnlStatus[chnl].setTemp)+HYST_HIGH)){
if(DEBUG3) pc.printf("DBG: [%d] Chiller ON \r\n", chnl);
//Turn chiller on
turn_valve_on(chnl);
}
else if (currentTemp < ((chnlStatus[chnl].setTemp)-HYST_LOW)){
if(DEBUG3) pc.printf("DBG: [%d] Heater ON \r\n", chnl);
//Turn heater on
turn_heater_on(chnl);
}
else{
if(DEBUG3) pc.printf("DBG: [%d] All OFF \r\n", chnl);
//turn off chiller
turn_valve_off(chnl);
//turn off heater
turn_heater_off(chnl);
//turn on green LED status light
status_led(chnl, 1);
}
}
}
}
}
}
