Initial commit

Dependencies:   FastPWM Lamp_Intensity_Lock_withTempCo mbed

Fork of Lamp_Intensity_Lock_withTempCo by Medic

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers main.cpp Source File

main.cpp

00001 #include "mbed.h"
00002 #include "FastPWM.h"
00003 
00004 #define TMD2772_Addr 0x72 //this is the 8-bit address
00005 #define MAX31725_Addr 0x96 //this is the 8-bit address
00006 #define iGainNormal 0.005
00007 #define pGainNormal 0.15
00008 #define lampVsense_pin PA_0 //do not switch this with boardPWM or it will not compile
00009 #define PWM_pin PA_6
00010 #define v12Sense_pin PA_7
00011 #define vDiv 4.01
00012 #define cal 0.987
00013 #define boardPWM_pin PA_3 
00014 #define debugPrint 1
00015 #define alsFilterLength 8
00016 #define slotHeaterPWM_pin PA_1
00017 
00018 //compiles with PA_6 as PWM and lampVsense as PA_0 and PWM_pin as PA_3
00019 //does not compile with PA_5 as lampvsense, boardPWM as PA_0 and PWM_pin as PA_3, 
00020 //DNC for lampVsense PA_3, PWM PA_6 boardPWM PA_0
00021 const uint8_t ALSDataRegister = 0x14;
00022 const uint8_t waitIntervals = 0; //number of 2.73 ms waits
00023 const int measPeriod_ms = 699;
00024 const float tempRef = 40;  //C temperature at which all optical powers are calculated to
00025 const float Ch0tempCo = 0.00228; // % per degree C
00026 const float Ch1tempCo = 0.001765; //% per degree C
00027 const float warmUp = 15; //number of measurements with a higher than usual pGain (to get to target faster);
00028 const float targetV = 10.9;
00029 const float VfilterLength = 8;
00030 const float tempFilterLength = 8;
00031 const uint8_t numLampMeas = 64; 
00032 float ch0Data=0;
00033 float ch1Data=0;   
00034 float vLamp;
00035 float v12;
00036 float lampVolts=0;
00037 float temperature=0;
00038 float instantTemperature=0;
00039 float dutyCycle =0.93; //initial duty cycle to try
00040 const float boardSetpointTemp = 40;
00041 float boardDutyCycle = 0.055;
00042 const float tempTol = 0.01; //tolerance within which to ignore temperature changes
00043 const float boardPropGain = 0.04;
00044 const float boardDerGain = 1.5;
00045 
00046 I2C i2c(I2C_SDA,I2C_SCL);
00047 Serial pc(USBTX,USBRX,115200); //open serial port (optionally add baud rate after specifying TX and RX pins)
00048 Timer t;
00049 FastPWM mypwm(PWM_pin);
00050 AnalogIn   lampVsense(lampVsense_pin);
00051 AnalogIn   v12Sense(v12Sense_pin);
00052 FastPWM boardPWM(boardPWM_pin);
00053 FastPWM slotHeaterPWM(slotHeaterPWM_pin);
00054 //**********************************
00055 //declare subroutines
00056 void writeRegister(uint8_t addr, uint8_t reg, uint8_t val)
00057 {
00058     /*writes 1 byte to a single register*/
00059     char writeData[2];
00060     writeData[0] = reg ;
00061     writeData[1] = val;
00062     i2c.write(addr,writeData, 2);
00063 }
00064 
00065 void writeBlock(uint8_t addr, uint8_t startReg, uint8_t *data, uint8_t numBytes)
00066 {
00067     /*writes data from an array beginning at the startReg*/
00068     char writeData[numBytes+1];
00069     writeData[0]=startReg;
00070     for(int n=1; n<numBytes; n++) {
00071         writeData[n]=data[n-1];
00072     }
00073     i2c.write(addr,writeData,numBytes+1);
00074 }
00075 
00076 void readRegisters(uint8_t addr, uint8_t startReg, char *regData, int numBytes)
00077 {
00078     char writeData = startReg;
00079     i2c.write(addr,&writeData,1,true); //true is for repeated start
00080     i2c.read(addr,regData,numBytes);
00081 }
00082 
00083 uint16_t LSB_MSB_2uint16(char *data) {
00084 /*returns an unsinged 16 bit integer from a 2 data bytes, where the second byte is the MSB*/
00085     return ((uint16_t)data[1] << 8) + (uint16_t)data[0];
00086 }
00087 
00088 uint16_t MSB_LSB_2uint16(char *data) {
00089 /*returns an unsinged 16 bit integer from a 2 data bytes, where the second byte is the MSB*/
00090     return ((uint16_t)data[0] << 8) + (uint16_t)data[1];
00091 }
00092 
00093 void regDump(uint8_t Addr, uint8_t startByte, uint8_t endByte)
00094 {
00095     /*print the values of up to 20 registers*/
00096     char regData[20];
00097     int numBytes;
00098     if (endByte>=startByte) {
00099         numBytes =  (endByte-startByte+1) < 20 ? (endByte-startByte+1) : 20;
00100     } else {
00101         numBytes=1;
00102     }
00103 
00104     regData[0] = startByte;
00105     i2c.write(Addr,regData,1,true);
00106     i2c.read(Addr, regData, numBytes);
00107     for(int n=0; n<numBytes; n++) {
00108         pc.printf("%X, %X \r\n", startByte+n, regData[n]);
00109     }
00110 }
00111 
00112 
00113 bool bitRead(uint16_t data, uint8_t bitNum)
00114 {
00115     uint16_t mask = 1<<bitNum;
00116     uint16_t masked_bit = data & mask;
00117     return masked_bit >> bitNum;
00118 }
00119 
00120 float getTemp( int address) {
00121     char tempData[2];
00122     uint16_t tempBits; 
00123     const float tempLSB =0.00390625;
00124   // read temperature
00125     readRegisters(MAX31725_Addr,0x00,tempData,2);
00126     tempBits = MSB_LSB_2uint16(tempData);
00127     if(bitRead(tempBits,15) == 1 )
00128     {
00129         return( (32768-tempBits)*tempLSB ); //negative temp
00130     }
00131     else {
00132         return ( tempBits*tempLSB ); //positive temp
00133     }
00134 } 
00135 
00136 void initTMD2772(void) {
00137     writeRegister(TMD2772_Addr,(0x00 | 0x80),0x0B);// Set power on, ALS enabled, Wait enabled, Interrupts enabled (register 0)
00138     writeRegister(TMD2772_Addr,(0x01 | 0x80),0x00);//ALS time register - 0x00 is max integration time of 699ms (register 1) 
00139     writeRegister(TMD2772_Addr,(0x03 | 0x80),0xFF-waitIntervals); // Wtime = 2.73 ms * delay peroids (subtract from 0xFF to enter into register)
00140 //    writeRegister(TMD2772_Addr,(0x0D | 0x80),0x04); //optionally scale ALS gain by 0.16 by seleting 0x04;
00141     writeRegister(TMD2772_Addr,(0x0D | 0x80),0x00); //optionally scale ALS gain by 0.16 by seleting 0x04;
00142 
00143     writeRegister(TMD2772_Addr,(0x0F | 0x80),0x00); //ALS gain is 1x
00144 }
00145 
00146 float tempCorrectTMDCh0(float counts, float tempC) 
00147 {
00148     float tDiff = tempC-tempRef;
00149     float delta = Ch0tempCo*tDiff; //the % difference observed vs. reference temperature
00150    return counts *(1-delta); //the count value equivalent if measured at reference temperature (less counts if temp is higher)
00151     
00152 }
00153 
00154 float tempCorrectTMDCh1(float counts, float tempC) 
00155 {
00156     float tDiff = tempC-tempRef;
00157     float delta = Ch1tempCo*tDiff; //the % difference observed vs. reference temperature
00158    return counts *(1-delta); //the count value equivalent if measured at reference temperature (less counts if temp is higher)
00159     
00160 }
00161 
00162 float getAvgLampV(uint8_t numMeas) 
00163 {
00164     float lampCounts=0;
00165     numMeas = (numMeas > 256) ? 256 : numMeas;
00166     for(int16_t n=0; n<numMeas; n++) {
00167         lampCounts += lampVsense.read();
00168     
00169     }    
00170     return lampCounts/numMeas;
00171 }
00172 
00173 float getAvg12V(uint8_t numMeas) 
00174 {
00175     float lampCounts=0;
00176     numMeas = (numMeas > 256) ? 256 : numMeas;
00177     for(int16_t n=0; n<numMeas; n++) {
00178         lampCounts += v12Sense.read();
00179     
00180     }    
00181     return lampCounts/numMeas;
00182 }
00183 
00184 void updateLampVolts(uint8_t numMeas) 
00185 {
00186     if(lampVolts == 0)
00187     {
00188         lampVolts =  ( vDiv * cal * 3.3 * ( getAvg12V(numMeas) - getAvgLampV(numMeas) ) - lampVolts); //initialize lamp volts  
00189     }
00190     else
00191     {
00192         lampVolts += ( vDiv * cal * 3.3 * ( getAvg12V(numMeas) - getAvgLampV(numMeas) ) - lampVolts)/VfilterLength; //update with IIR filter
00193     }
00194 }
00195 
00196 void updateTemperature(void) 
00197 {
00198     if (temperature == 0) 
00199     {
00200         instantTemperature=getTemp(MAX31725_Addr);
00201         temperature = instantTemperature;
00202     }
00203     else 
00204     {
00205         instantTemperature=getTemp(MAX31725_Addr);
00206         temperature += (instantTemperature-temperature)/tempFilterLength  ;  
00207     }
00208 }
00209 
00210 void updateAlsData(void)
00211 {
00212     float ch0RawData;
00213     float ch1RawData;
00214     char data[4];
00215         
00216     readRegisters(TMD2772_Addr, (ALSDataRegister | 0x80), data ,4);
00217     ch0RawData = (float) LSB_MSB_2uint16(data);
00218     ch1RawData = LSB_MSB_2uint16(data+2);
00219     
00220     if(temperature==0) {//no temp measurement
00221         if(ch0Data==0) {//no prior ch0Data--initialize filter        
00222             ch0Data = ch0RawData;
00223             ch1Data = ch1RawData;
00224         }
00225         else {//prior data exists, update w/IIR filter
00226             ch0Data += (ch0RawData-ch0Data)/alsFilterLength;
00227             ch1Data += (ch1RawData-ch0Data)/alsFilterLength;
00228         }
00229     }
00230     else { //temp meas exists
00231         if(ch0Data == 0) {
00232             ch0Data = (tempCorrectTMDCh0(ch0RawData,temperature)-ch0Data)/alsFilterLength; //initialize with temperature corrected the data 
00233             ch1Data = (tempCorrectTMDCh1(ch1RawData,temperature)-ch1Data)/alsFilterLength; //initialize with temperature corrected the data 
00234         }
00235         else {
00236             ch0Data += (tempCorrectTMDCh0(ch0RawData,temperature)-ch0Data)/alsFilterLength; //update IIR filter with temperature corrected data
00237             ch1Data += (tempCorrectTMDCh1(ch1RawData,temperature)-ch1Data)/alsFilterLength; //update IIR filter with temperature corrected data
00238         }
00239     }      
00240 } //end updateCh0Data
00241 
00242 void updateLampPWM(float err, float sumErr, float pGain, float iGain)
00243 {
00244     const float dutyCycleMin =0;
00245     const float dutyCycleMax =0.98;
00246     const float stepMax=0.005;
00247     const float stepMin=-0.005;          
00248     float step; //duty cycle change per sample 
00249        
00250     step = err * pGain + sumErr*iGain;
00251     step = (step > stepMax) ? stepMax : step;
00252     step = (step < stepMin) ? stepMin : step;
00253     dutyCycle -= step;
00254     dutyCycle = (dutyCycle < dutyCycleMin) ? dutyCycleMin : dutyCycle;
00255     dutyCycle = (dutyCycle > dutyCycleMax) ? dutyCycleMax : dutyCycle;
00256     mypwm.write(dutyCycle);   //update with new settings
00257 }
00258 
00259 
00260 void updateBoardPWM(float err, float pGain, float dGain)
00261 {
00262     static float prevTemp=temperature;
00263     const float dutyCycleMin =0;
00264     const float dutyCycleMax =0.1;
00265     const float stepMax=0.05;
00266     const float stepMin=-0.05;          
00267     float step; //duty cycle change per sample 
00268     float pGain1 = pGain;   
00269 //    if(err>0)
00270 //    {
00271 //        pGain1=0;
00272 //    }
00273 //    else 
00274 //    {
00275 //        pGain1 = pGain;  
00276 //    }    
00277     step = err * pGain1 + (temperature-prevTemp)/boardSetpointTemp*dGain;
00278     step = (step > stepMax) ? stepMax : step;
00279     step = (step < stepMin) ? stepMin : step;
00280     boardDutyCycle -= step;
00281     boardDutyCycle = (boardDutyCycle < dutyCycleMin) ? dutyCycleMin : boardDutyCycle;
00282     boardDutyCycle = (boardDutyCycle > dutyCycleMax) ? dutyCycleMax : boardDutyCycle;
00283     boardPWM.write(boardDutyCycle);   //update with new settings
00284 
00285     prevTemp = temperature;
00286     
00287 }
00288 
00289 
00290 void rampLamp(float finalDutyCycle) 
00291 {
00292     float currentDutyCycle;
00293     float step = 0.01; //increment or decrement duty cycle by 1% increments
00294     bool ramping = 1;
00295     currentDutyCycle = mypwm.read();
00296     while (ramping) {
00297         wait_ms(40);
00298         if(finalDutyCycle - currentDutyCycle > step) 
00299         {
00300             currentDutyCycle += step;
00301             mypwm.write(currentDutyCycle);
00302         }
00303         else if (finalDutyCycle - currentDutyCycle < -step)
00304         {
00305             currentDutyCycle -= step;
00306             mypwm.write(currentDutyCycle);
00307         }
00308         else
00309         {
00310             ramping = 0;
00311             mypwm.write(finalDutyCycle);
00312         }
00313     }
00314 }
00315 
00316 
00317 float getNewSetpoint(float targetVoltage, float warmUpTime, float calTime)
00318 {
00319     warmUpTime = ( warmUpTime < 0 ) ? 0 : warmUpTime;
00320     calTime = (calTime <= warmUpTime) ? calTime= warmUpTime*2+1: calTime;
00321     const float calTime_ms = 1000*calTime; //convert seconds to ms
00322     const float warmUpTime_ms = 1000*warmUpTime;
00323     
00324     const float tol =0.02;// volts tolerance on target voltage
00325     const uint8_t persist=8; //number of consecutive samples in range in order to output new setpoint
00326     uint8_t consecutiveInRange=0;
00327     const float propGain = 2e-3; //proportional gain
00328     float errVoltage;
00329     float tempErr;
00330     t.start();
00331     
00332     //turn on heater and stabilize board at target temp
00333     rampLamp(dutyCycle);
00334     rampLamp(0.05); //low level power keeps fan on
00335     boardPWM.write(boardDutyCycle);
00336     while(t.read_ms() < 120*1000) 
00337     {
00338         wait_ms(699);
00339         updateTemperature();
00340         tempErr = (instantTemperature - boardSetpointTemp)/boardSetpointTemp;
00341         if (abs(tempErr*boardSetpointTemp)>tempTol) {
00342             updateBoardPWM(tempErr,boardPropGain,boardDerGain);
00343         }
00344         
00345         pc.printf( "%.4f, %.2f, %f, %f, %f, %U\r\n",lampVolts, ch0Data, mypwm.read(),boardPWM.read(),temperature,consecutiveInRange);
00346     }
00347     
00348     rampLamp(dutyCycle);   
00349     //begin adjust output to target voltage at desired sensor board temperature.
00350     while(t.read_ms() < calTime_ms) { 
00351         wait_ms(699);
00352         updateTemperature();
00353         updateLampVolts(numLampMeas); 
00354         updateAlsData();
00355         //#ifdef printDebug 
00356             pc.printf( "%.4f, %.2f, %f, %f, %f, %U\r\n",lampVolts, ch0Data, mypwm.read(),boardPWM.read(),temperature,consecutiveInRange);
00357         //#endif
00358         errVoltage = lampVolts-targetVoltage;
00359         if (abs(errVoltage) < tol )
00360         {    
00361             consecutiveInRange++;
00362             if ( consecutiveInRange >= persist)
00363             {    
00364                 if(t.read_ms() > warmUpTime_ms) 
00365                 {
00366                     return floor(ch0Data)+0.5;
00367                 }
00368             }
00369         }
00370         else
00371         {
00372             consecutiveInRange=0;
00373         }
00374         updateLampPWM(errVoltage,0,propGain,0);
00375         tempErr = (instantTemperature - boardSetpointTemp)/boardSetpointTemp;
00376         if (abs(tempErr*boardSetpointTemp)>tempTol) {
00377             updateBoardPWM(tempErr,boardPropGain,boardDerGain);
00378         }
00379         
00380     } //end while
00381     return ch0Data;
00382 }
00383 
00384 int main() {
00385     float ratio;
00386     static bool inRange=false;
00387     float setpoint = 37250.5; //ch0/ch1 color setpoint ~0.88 duty cycle
00388 //    float iGain = 0.05; //integral gain --adding this because when I blew on it, it couldn't recover
00389     float err;
00390     float tempErr;
00391     const float tol=0.5; //tolerance within which to ignore changes in signal intensity
00392     float pGain; //proportional gain
00393     float iGain; // 250 : 0.2 ratio relative to pGain
00394     float sumErr=0;
00395     const float sumErrMax = .01;
00396     
00397     //setup everything
00398     mypwm.period_us(400);
00399     boardPWM.period_us(400);
00400     slotHeaterPWM.period_us(400);
00401     slotHeaterPWM.write(0);
00402     //mypwm.write(dutyCycle);
00403     boardPWM.write(0);
00404     i2c.frequency(400000); //set I2C frequency to 400kHz
00405     wait_ms(1000);
00406     initTMD2772();
00407     #ifdef printDebug
00408         regDump(TMD2772_Addr,(0x00 | 0x80),0x0F);
00409     #endif
00410     pc.printf("fan on\r\n");
00411     pc.printf("Done initializing\r\n");
00412     wait_ms(700);
00413     static int loopCount =0;
00414     
00415     wait_ms(measPeriod_ms);
00416     
00417     //warmup and choose setpoint
00418     pc.printf("finding %f V setpoint\r\n",targetV);
00419     setpoint = getNewSetpoint(targetV, 300, 400);
00420     pc.printf( "new setpoint is %f counts\r\n",setpoint );
00421     
00422 
00423     while(1) {
00424         t.start();
00425         updateTemperature();
00426         updateAlsData();
00427         ratio = ch0Data/ch1Data;
00428         err = (ch0Data - setpoint)/setpoint;
00429         tempErr = (instantTemperature - boardSetpointTemp)/boardSetpointTemp;
00430         if(loopCount<warmUp) 
00431         {
00432             sumErr=0;   //no integral gain during initial warmup--takes too long to integate error out
00433             pGain=0.25;
00434         }
00435         else 
00436         {
00437             sumErr += err; //use integral gain while the sensor is heating up to get to setpoint faster and avoid lag.
00438             pGain=pGainNormal;
00439         }
00440         inRange = (abs(sumErr)<sumErrMax) ? true : false;
00441         if(inRange) 
00442         {
00443             iGain=0; //no need for iGain--inRange
00444         } 
00445         else
00446         {
00447             iGain = iGainNormal;
00448         }
00449         updateLampVolts(numLampMeas); 
00450         //#ifdef printDebug
00451             pc.printf( "%.2f,%.2f, %f, %f, %f, %f, %f, %U, %f, %f\r\n",ch0Data,ch1Data,ratio,mypwm.read(),boardPWM.read(),temperature,sumErr,inRange, iGain*sumErr, lampVolts );
00452         //#endif
00453         if (abs(err*setpoint)>tol) {
00454             updateLampPWM(err,sumErr,pGain,iGain);
00455         }
00456         if (abs(tempErr*boardSetpointTemp)>tempTol) {
00457             updateBoardPWM(tempErr,boardPropGain,boardDerGain);
00458         }
00459         loopCount++;
00460         while(t.read_ms() < measPeriod_ms) {
00461          //pc.printf("%U \r\n",t.read_ms());   
00462         }
00463         t.reset();
00464     }
00465     
00466     
00467 }
00468