Program to control UPAS with MicroChip BLE chip + iPhone App
Dependencies: ADS1115 BME280 Calibration CronoDot EEPROM LSM303 MCP40D17 MicroBLE NCP5623BMUTBG SDFileSystem SI1145 STC3100 mbed
Diff: main.cpp
- Revision:
- 0:2cb2b2ea316f
- Child:
- 1:9fbb5b665068
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/main.cpp Mon Jan 18 22:09:51 2016 +0000 @@ -0,0 +1,410 @@ +#include "mbed.h" +#include "SDFileSystem.h" +#include "Adafruit_ADS1015.h" +#include "MCP40D17.h" +#include "STC3100.h" +#include "LSM303.h" +#include "BME280.h" +#include "SI1145.h" +#include "NCP5623BMUTBG.h" +#include "CronoDot.h" +#include "EEPROM.h" +#include "Calibration.h" + +#define SCL 20 +#define SDA 22 + + +uint8_t startAndEndTime[12] = {0,}; +uint8_t logIntervalReadOut[1] = {0,}; + +I2C i2c(p22, p20); +Adafruit_ADS1115 ads(&i2c); +MCP40D17 DigPot(&i2c); +BME280 bmesensor(p22, p20); +STC3100 gasG(p22, p20); + +Serial microChannel(P0_9,P0_11); + +DigitalOut blower(p29, 0); +DigitalOut pbKill(p18, 1); +LSM303 movementsensor(p22, p20); +SI1145 lightsensor(p22, p20); +NCP5623BMUTBG RGB_LED(p22, p20); +CronoDot RTC(p22, p20); +EEPROM E2PROM(p22, p20); +DigitalOut GPS_EN(p4,0); //pin 4 is used to enable and disable the GPS, in order to recive serial communications +Calibration calibrations(1); //Default serial/calibration if there are no values for the selected option + +Timeout stop; //This is the stop call back object +Timeout logg; //This is the logging call back object + +uint16_t serial_num = 1; // Default serial/calibration number +int RunReady =0; + + +float press; +float temp; +float rh; + +int uv; +int vis; +int ir; + +float compass; +float accel_x; +float accel_y; +float accel_z; +float accel_comp; +float mag_x; +float mag_y; +float mag_z; + +int vInReading; +int vBlowerReading; +int omronDiff; +float omronVolt; //V +int omronReading; +float atmoRho; //g/L + +float massflow; //g/min +float volflow; //L/min +float volflowSet = 1.0; //L/min +int logInerval = 10; //seconds +double secondsD = 0; +float massflowSet; +float deltaVflow = 0.0; +float deltaMflow = 0.0; +float gainFlow; +float sampledVol; //L, total sampled volume + +int digital_pot_setpoint; //min = 0x7F, max = 0x00 +int digital_pot_set; +int digital_pot_change; +int digitalpotMax = 127; +int digitalpotMin = 2; + +int dutyUp; +int dutyDown; + +// variables are only place holders for the US_Menu // +int refreshtime; +float home_lat, home_lon, work_lat, work_lon; +//*************************************************// + +//int refresh_Time = 10; // refresh time in s, note calling read_GPS()(or similar) will still take how ever long it needs(hopefully < 1s) + +char filename[] = "/sd/XXXX0000LOG000000000000---------------.txt"; +SDFileSystem sd(SPIS_PSELMOSI, SPIS_PSELMISO, SPIS_PSELSCK, SPIS_PSELSS, "sd"); // I believe this matches Todd's pinout, let me know if this doesn't work. (p12, p13, p15, p14) + + + +void check_stop() // this checks if it's time to stop and shutdown +{ + + if(RTC.compare(startAndEndTime[6], startAndEndTime[7], startAndEndTime[8], startAndEndTime[9], startAndEndTime[10], startAndEndTime[11])) { + pbKill = 0; // this is were we shut everything down + } + stop.detach(); + stop.attach(&check_stop, 9); + +} + + +void log_data() +{ + logg.detach(); + + logg.attach(&log_data, logInerval); // reading and logging data must take significintly less than 0.5s. This can be increased. + + RTC.get_time(); + + omronReading = ads.readADC_SingleEnded(0, 0xC583); // read channel 0 PGA = 2 : Full Scale Range = 2.048V + omronVolt = (omronReading*4.096)/(32768*2); + + if(omronVolt<=calibrations.omronVMin) { + massflow = calibrations.omronMFMin; + } else if(omronVolt>=calibrations.omronVMax) { + massflow = calibrations.omronMFMax; + } else { + massflow = calibrations.MF4*pow(omronVolt,(float)4)+calibrations.MF3*pow(omronVolt,(float)3)+calibrations.MF2*pow(omronVolt,(float)2)+calibrations.MF1*omronVolt+calibrations.MF0; + } + + atmoRho = ((press-((6.1078*pow((float)10,(float)((7.5*temp)/(237.3+temp))))*(rh/100)))*100)/(287.0531*(temp+273.15))+((6.1078*pow((float)10,(float)((7.5*temp)/(237.3+temp))))*(rh/100)*100)/(461.4964*(temp+273.15)); + volflow = massflow/atmoRho; + sampledVol = sampledVol + ((((float)logInerval)/60.0)*volflow); + deltaVflow = volflow-volflowSet; + massflowSet = volflowSet*atmoRho; + deltaMflow = massflow-massflowSet; + if(abs(deltaMflow)>.025) { + digital_pot_change = (int)(gainFlow*deltaMflow); + + + if(abs(digital_pot_change)>=50) { + digital_pot_set = (int)(digital_pot_set+(int)((10.0*deltaMflow))); + RGB_LED.set_led(1,0,0); + + } else if(digital_pot_change+digital_pot_set>=digitalpotMax&abs(digital_pot_change)<50) { + digital_pot_set = digitalpotMax; + RGB_LED.set_led(1,0,0); + } else if(digital_pot_change+digital_pot_set<=digitalpotMin&abs(digital_pot_change)<50) { + digital_pot_set = digitalpotMin; + RGB_LED.set_led(1,0,0); + } else { + digital_pot_set = (digital_pot_set+ digital_pot_change); + RGB_LED.set_led(1,1,0); + } + + DigPot.writeRegister(digital_pot_set); + + } else { + RGB_LED.set_led(0,1,0); + } + movementsensor.getACCEL(); + movementsensor.getCOMPASS(); + compass = movementsensor.getCOMPASS_HEADING(); + accel_x = movementsensor.AccelData.x; + accel_y = movementsensor.AccelData.y; + accel_z = movementsensor.AccelData.z; + accel_comp = pow(accel_x,(float)2)+pow(accel_y,(float)2)+pow(accel_z,(float)2)-1.0; + mag_x = movementsensor.MagData.x; + mag_y = movementsensor.MagData.y; + mag_z = movementsensor.MagData.z; + vInReading = ads.readADC_SingleEnded(1, 0xD583); // read channel 0 + vBlowerReading = ads.readADC_SingleEnded(2, 0xE783); // read channel 0 + omronDiff = ads.readADC_Differential(0x8583); // differential channel 2-3 + press = bmesensor.getPressure(); + temp = bmesensor.getTemperature()-5.0; + rh = bmesensor.getHumidity(); + uv = lightsensor.getUV(); + vis = lightsensor.getVIS(); + ir = lightsensor.getIR(); + FILE *fp = fopen(filename, "a"); + fprintf(fp, "%02d,%02d,%02d,%02d,%02d,%02d,%1.3f,%1.3f,%2.2f,%4.2f,%2.1f,%1.3f,%1.3f,%5.1f,%1.1f,%1.1f,%1.1f,%1.1f,%d,%d,%d,%d,%d,%d,%d,%d,%d,%1.3f,%1.3f,%f\r\n",RTC.year, RTC.month,RTC.date,RTC.hour,RTC.minutes,RTC.seconds,omronVolt,massflow,temp,press,rh,atmoRho,volflow,sampledVol,accel_x,accel_y,accel_z,accel_comp,uv,omronReading, vInReading, vBlowerReading, omronDiff,gasG.getAmps(), gasG.getVolts(), gasG.getCharge(),digital_pot_set, deltaMflow, deltaVflow, compass); + fclose(fp); + +} + +static uint8_t rx_buf[20]; +static uint8_t rx_len=0; + +void uartMicro(void){ + int j = 0; + while(microChannel.readable()){ + rx_buf[rx_len++] = microChannel.getc(); + if(rx_len>=20 ||rx_buf[rx_len-1]=='\0' || rx_buf[rx_len-1]=='\n')break; + j++; + } + for(int i=0; i<rx_len; i++){ + microChannel.putc(rx_buf[i]); + } + rx_len = 0; + +} +/*EEPROM ADDRESSING: + 0:Status bit-Unused + 1-15:Device Name + 16-19:Flow Rate + 20: Data Log Interval + 21-26: Start Time: ssmmHHddMMyy + 27-32: Stop Time: ssmmHHddMMyy + 33: Duty Up + 34: Duty Down + 35-38: Home Latitude + 39-42: Home Longitude + 43-46: Work Latitude + 47-50: Work Longitude + 51: Runready: Currently useless, should be 0 + 52-53: Device Calibration + 54: Consider RunReady + 55-56: Menu Options + 57+ Nothing*/ +int main() +{ + RGB_LED.set_led(1,1,1); + microChannel.baud(115200); + microChannel.attach(uartMicro,microChannel.RxIrq); +// Setup and Initialization +//---------------------------------------------------------------------------------------------// + RTC.get_time(); + uint8_t rtcPassValues[7] = {0x00,RTC.seconds, RTC.minutes,RTC.hour,RTC.date,RTC.month,RTC.year}; + uint8_t sampleTimePassValues[13] = {0x01,}; + uint8_t subjectLabelOriginal[9] = {0x02,}; + uint8_t dataLogOriginal[2] = {0x03,}; + uint8_t flowRateOriginal[5] = {0x04,}; + //uint8_t presetRunModeCheck[1] = {0,}; Commented and currently unused to prevent mem issues + E2PROM.read(0x00015, sampleTimePassValues+1, 12); + E2PROM.read(0x00001, subjectLabelOriginal+1,8); + E2PROM.read(0x00014,dataLogOriginal+1,1); + E2PROM.read(0x00010,flowRateOriginal+1,4); + //E2PROM.read(0x00033,presetRunModeCheck,1); //commented out mem issue + + while (1) { + + for(int i=0; i<7; i++){ + microChannel.putc(rtcPassValues[i]); + } + wait(2); + + for(int i=0; i<13; i++){ + microChannel.putc(sampleTimePassValues[i]); + } + wait(2); + + for(int i=0; i<9; i++){ + microChannel.putc(subjectLabelOriginal[i]); + } + wait(2); + + for(int i=0; i<2; i++){ + microChannel.putc(dataLogOriginal[i]); + } + wait(2); + + for(int i=0; i<5; i++){ + microChannel.putc(flowRateOriginal[i]); + } + wait(2); + + if(RunReady==10){ //Check to see if app is done with configurations + break; + } + + if(RunReady==12){ //If 24 hour mode has been set, then shut down the UPAS for automatic start later. + pbKill = 0; + } + } + + E2PROM.read(0x00015, startAndEndTime, 12); //Grab start and end times from EEPROM + while(!RTC.compare(startAndEndTime[0], startAndEndTime[1], startAndEndTime[2], startAndEndTime[3], startAndEndTime[4], startAndEndTime[5])) { // this while waits for the start time by looping until the start time + wait(0.5); + + RTC.get_time(); + + } + + + RGB_LED.set_led(0,1,0); + + //Get the proper serial number + E2PROM.read(0x00034, flowRateOriginal,2); + serial_num = ((uint16_t)flowRateOriginal[1] << 8) | flowRateOriginal[0]; + calibrations.initialize(serial_num); + blower=1; + E2PROM.read(0x00014,logIntervalReadOut,1); + logInerval = logIntervalReadOut[0]; + + RunReady = 0; + + + stop.attach(&check_stop, 30); // check if we should shut down every 9 seconds, starting 60s after the start. + + //Use the flow rate value stored in eeprom + E2PROM.read(0x00010,flowRateOriginal,4); + E2PROM.byteToFloat(flowRateOriginal, &volflowSet); + + if(volflowSet<=1.0) { + gainFlow = 100; + } else if(volflowSet>=2.0) { + gainFlow = 25; + } else { + gainFlow = 25; + } + + RGB_LED.set_led(1,0,0); + press = bmesensor.getPressure(); + temp = bmesensor.getTemperature(); + rh = bmesensor.getHumidity(); + + atmoRho = ((press-((6.1078*pow((float)10,(float)((7.5*temp)/(237.3+temp))))*(rh/100)))*100)/(287.0531*(temp+273.15))+((6.1078*pow((float)10,(float)((7.5*temp)/(237.3+temp))))*(rh/100)*100)/(461.4964*(temp+273.15)); + massflowSet = volflowSet*atmoRho; + //Digtal pot tf from file: UPAS v2 OSU-PrimaryFlowData FullSet 2015-05-29 CQ mods.xlsx + + + digital_pot_setpoint = (int)floor(calibrations.DP4*pow(massflowSet,4)+calibrations.DP3*pow(massflowSet,3)+calibrations.DP2*pow(massflowSet,2)+calibrations.DP1*massflowSet+calibrations.DP0); //min = 0x7F, max = 0x00 + + if(digital_pot_setpoint>=digitalpotMax) { + digital_pot_setpoint = digitalpotMax; + } else if(digital_pot_setpoint<=digitalpotMin) { + digital_pot_setpoint = digitalpotMin; + } + + DigPot.writeRegister(digital_pot_setpoint); + wait(1); + blower = 1; + + + E2PROM.read(0x00001, subjectLabelOriginal,8); + //sprintf(filename, "/sd/%c%c%c%c%c%c%c%cLOG_%02d-%02d-%02d_%02d=%02d=%02d.txt",subjectLabelOriginal[0],subjectLabelOriginal[1],subjectLabelOriginal[2],subjectLabelOriginal[3],subjectLabelOriginal[4],subjectLabelOriginal[5],subjectLabelOriginal[6],subjectLabelOriginal[7],RTC.year,RTC.month,RTC.date,RTC.hour,RTC.minutes,RTC.seconds); + sprintf(filename, "/sd/UPAS%04dLOG_%02d-%02d-%02d_%02d=%02d=%02d_%c%c%c%c%c%c%c%c.txt",serial_num,RTC.year,RTC.month,RTC.date,RTC.hour,RTC.minutes,RTC.seconds,subjectLabelOriginal[0],subjectLabelOriginal[1],subjectLabelOriginal[2],subjectLabelOriginal[3],subjectLabelOriginal[4],subjectLabelOriginal[5],subjectLabelOriginal[6],subjectLabelOriginal[7]); + FILE *fp = fopen(filename, "w"); + fclose(fp); + + //---------------------------------------------------------------------------------------------// + //Following lines are needed to enter into the initiallization flow control loop + + wait(10); + + omronReading = ads.readADC_SingleEnded(0, 0xC583); // read channel 0 PGA = 2 : Full Scale Range = 2.048V + omronVolt = (omronReading*4.096)/(32768*2); + if(omronVolt<=calibrations.omronVMin) { + massflow = calibrations.omronMFMin; + } else if(omronVolt>=calibrations.omronVMax) { + massflow = calibrations.omronMFMax; + } else { + massflow = calibrations.MF4*pow(omronVolt,(float)4)+calibrations.MF3*pow(omronVolt,(float)3)+calibrations.MF2*pow(omronVolt,(float)2)+calibrations.MF1*omronVolt+calibrations.MF0; + } + deltaMflow = massflow-massflowSet; + digital_pot_set = digital_pot_setpoint; + wait(5); + + //---------------------------------------------------------------------------------------------// + //Sets the flow withen +-1.5% of the desired flow rate based on mass flow + + while(abs(deltaMflow)>.015) { + + omronReading = ads.readADC_SingleEnded(0, 0xC583); // read channel 0 PGA = 2 : Full Scale Range = 2.048V + omronVolt = (omronReading*4.096)/(32768*2); + //Mass Flow tf from file: UPAS v2 OSU-PrimaryFlowData FullSet 2015-05-29 CQ mods.xlsx + if(omronVolt<=calibrations.omronVMin) { + massflow = calibrations.omronMFMin; + } else if(omronVolt>=calibrations.omronVMax) { + massflow = calibrations.omronMFMax; + } else { + massflow = calibrations.MF4*pow(omronVolt,(float)4)+calibrations.MF3*pow(omronVolt,(float)3)+calibrations.MF2*pow(omronVolt,(float)2)+calibrations.MF1*omronVolt+calibrations.MF0; + } + + atmoRho = ((press-((6.1078*pow((float)10,(float)((7.5*temp)/(237.3+temp))))*(rh/100)))*100)/(287.0531*(temp+273.15))+((6.1078*pow((float)10,(float)((7.5*temp)/(237.3+temp))))*(rh/100)*100)/(461.4964*(temp+273.15)); + volflow = massflow/atmoRho; + massflowSet = volflowSet*atmoRho; + deltaMflow = massflow-massflowSet; + + digital_pot_set = (int)(digital_pot_set+(int)((gainFlow*deltaMflow))); + if(digital_pot_set>=digitalpotMax) { + digital_pot_set = digitalpotMax; + } else if(digital_pot_set<=digitalpotMin) { + digital_pot_set = digitalpotMin; + } + + wait(2); + DigPot.writeRegister(digital_pot_set); + wait(1); + + + } + + sampledVol = 0.0; + RGB_LED.set_led(0,1,0); + + + + //** end of initalization **// + //---------------------------------------------------------------------------------------------// + //---------------------------------------------------------------------------------------------// + // Main Control Loop + + + logg.attach(&log_data, logInerval); // uses callbacks or block Interrupts for anything that uses i2c + +} +