Initial commit
Dependencies: FastPWM Lamp_Intensity_Lock_withTempCo mbed
Fork of Lamp_Intensity_Lock_withTempCo by
Revision 4:eb26ac5c3bd5, committed 2017-03-13
- Comitter:
- laserdad
- Date:
- Mon Mar 13 22:36:47 2017 +0000
- Parent:
- 3:a8ec3c6aeb08
- Commit message:
- Added board heater. Switched 2 pins v.s orig AlsTempR3 schematic to deal w/mbed pin assigment fail. Got rid of fan enable (automatic on board). Added slot heater. Added light ramp on/off. Refactored for legibility.
Changed in this revision
main.cpp | Show annotated file Show diff for this revision Revisions of this file |
diff -r a8ec3c6aeb08 -r eb26ac5c3bd5 main.cpp --- a/main.cpp Fri Jan 13 22:30:02 2017 +0000 +++ b/main.cpp Mon Mar 13 22:36:47 2017 +0000 @@ -2,23 +2,55 @@ #include "FastPWM.h" #define TMD2772_Addr 0x72 //this is the 8-bit address -#define MAX31725_Addr 0x92 //this is the 8-bit address +#define MAX31725_Addr 0x96 //this is the 8-bit address +#define iGainNormal 0.005 +#define pGainNormal 0.15 +#define lampVsense_pin PA_0 //do not switch this with boardPWM or it will not compile +#define PWM_pin PA_6 +#define v12Sense_pin PA_7 +#define vDiv 4.01 +#define cal 0.987 +#define boardPWM_pin PA_3 +#define debugPrint 1 +#define alsFilterLength 8 +#define slotHeaterPWM_pin PA_1 +//compiles with PA_6 as PWM and lampVsense as PA_0 and PWM_pin as PA_3 +//does not compile with PA_5 as lampvsense, boardPWM as PA_0 and PWM_pin as PA_3, +//DNC for lampVsense PA_3, PWM PA_6 boardPWM PA_0 const uint8_t ALSDataRegister = 0x14; -const uint8_t waitIntervals = 100; //number of 2.73 ms waits +const uint8_t waitIntervals = 0; //number of 2.73 ms waits const int measPeriod_ms = 699; -const float tempRef = 29.5; //C temperature at which all optical powers are calculated to +const float tempRef = 40; //C temperature at which all optical powers are calculated to const float Ch0tempCo = 0.00228; // % per degree C const float Ch1tempCo = 0.001765; //% per degree C const float warmUp = 15; //number of measurements with a higher than usual pGain (to get to target faster); +const float targetV = 10.9; +const float VfilterLength = 8; +const float tempFilterLength = 8; +const uint8_t numLampMeas = 64; +float ch0Data=0; +float ch1Data=0; +float vLamp; +float v12; +float lampVolts=0; +float temperature=0; +float instantTemperature=0; +float dutyCycle =0.93; //initial duty cycle to try +const float boardSetpointTemp = 40; +float boardDutyCycle = 0.055; +const float tempTol = 0.01; //tolerance within which to ignore temperature changes +const float boardPropGain = 0.04; +const float boardDerGain = 1.5; I2C i2c(I2C_SDA,I2C_SCL); -Serial pc(USBTX,USBRX); //open serial port (optionally add baud rate after specifying TX and RX pins) +Serial pc(USBTX,USBRX,115200); //open serial port (optionally add baud rate after specifying TX and RX pins) Timer t; -FastPWM mypwm(PA_1); - - - +FastPWM mypwm(PWM_pin); +AnalogIn lampVsense(lampVsense_pin); +AnalogIn v12Sense(v12Sense_pin); +FastPWM boardPWM(boardPWM_pin); +FastPWM slotHeaterPWM(slotHeaterPWM_pin); //********************************** //declare subroutines void writeRegister(uint8_t addr, uint8_t reg, uint8_t val) @@ -88,20 +120,19 @@ float getTemp( int address) { char tempData[2]; uint16_t tempBits; - const float LSB =0.00390625; + const float tempLSB =0.00390625; // read temperature readRegisters(MAX31725_Addr,0x00,tempData,2); tempBits = MSB_LSB_2uint16(tempData); if(bitRead(tempBits,15) == 1 ) { - return( (32768-tempBits)*LSB ); //negative temp + return( (32768-tempBits)*tempLSB ); //negative temp } else { - return ( tempBits*LSB ); //positive temp + return ( tempBits*tempLSB ); //positive temp } } - void initTMD2772(void) { writeRegister(TMD2772_Addr,(0x00 | 0x80),0x0B);// Set power on, ALS enabled, Wait enabled, Interrupts enabled (register 0) writeRegister(TMD2772_Addr,(0x01 | 0x80),0x00);//ALS time register - 0x00 is max integration time of 699ms (register 1) @@ -128,91 +159,304 @@ } +float getAvgLampV(uint8_t numMeas) +{ + float lampCounts=0; + numMeas = (numMeas > 256) ? 256 : numMeas; + for(int16_t n=0; n<numMeas; n++) { + lampCounts += lampVsense.read(); + + } + return lampCounts/numMeas; +} + +float getAvg12V(uint8_t numMeas) +{ + float lampCounts=0; + numMeas = (numMeas > 256) ? 256 : numMeas; + for(int16_t n=0; n<numMeas; n++) { + lampCounts += v12Sense.read(); + + } + return lampCounts/numMeas; +} + +void updateLampVolts(uint8_t numMeas) +{ + if(lampVolts == 0) + { + lampVolts = ( vDiv * cal * 3.3 * ( getAvg12V(numMeas) - getAvgLampV(numMeas) ) - lampVolts); //initialize lamp volts + } + else + { + lampVolts += ( vDiv * cal * 3.3 * ( getAvg12V(numMeas) - getAvgLampV(numMeas) ) - lampVolts)/VfilterLength; //update with IIR filter + } +} + +void updateTemperature(void) +{ + if (temperature == 0) + { + instantTemperature=getTemp(MAX31725_Addr); + temperature = instantTemperature; + } + else + { + instantTemperature=getTemp(MAX31725_Addr); + temperature += (instantTemperature-temperature)/tempFilterLength ; + } +} + +void updateAlsData(void) +{ + float ch0RawData; + float ch1RawData; + char data[4]; + + readRegisters(TMD2772_Addr, (ALSDataRegister | 0x80), data ,4); + ch0RawData = (float) LSB_MSB_2uint16(data); + ch1RawData = LSB_MSB_2uint16(data+2); + + if(temperature==0) {//no temp measurement + if(ch0Data==0) {//no prior ch0Data--initialize filter + ch0Data = ch0RawData; + ch1Data = ch1RawData; + } + else {//prior data exists, update w/IIR filter + ch0Data += (ch0RawData-ch0Data)/alsFilterLength; + ch1Data += (ch1RawData-ch0Data)/alsFilterLength; + } + } + else { //temp meas exists + if(ch0Data == 0) { + ch0Data = (tempCorrectTMDCh0(ch0RawData,temperature)-ch0Data)/alsFilterLength; //initialize with temperature corrected the data + ch1Data = (tempCorrectTMDCh1(ch1RawData,temperature)-ch1Data)/alsFilterLength; //initialize with temperature corrected the data + } + else { + ch0Data += (tempCorrectTMDCh0(ch0RawData,temperature)-ch0Data)/alsFilterLength; //update IIR filter with temperature corrected data + ch1Data += (tempCorrectTMDCh1(ch1RawData,temperature)-ch1Data)/alsFilterLength; //update IIR filter with temperature corrected data + } + } +} //end updateCh0Data + +void updateLampPWM(float err, float sumErr, float pGain, float iGain) +{ + const float dutyCycleMin =0; + const float dutyCycleMax =0.98; + const float stepMax=0.005; + const float stepMin=-0.005; + float step; //duty cycle change per sample + + step = err * pGain + sumErr*iGain; + step = (step > stepMax) ? stepMax : step; + step = (step < stepMin) ? stepMin : step; + dutyCycle -= step; + dutyCycle = (dutyCycle < dutyCycleMin) ? dutyCycleMin : dutyCycle; + dutyCycle = (dutyCycle > dutyCycleMax) ? dutyCycleMax : dutyCycle; + mypwm.write(dutyCycle); //update with new settings +} + + +void updateBoardPWM(float err, float pGain, float dGain) +{ + static float prevTemp=temperature; + const float dutyCycleMin =0; + const float dutyCycleMax =0.1; + const float stepMax=0.05; + const float stepMin=-0.05; + float step; //duty cycle change per sample + float pGain1 = pGain; +// if(err>0) +// { +// pGain1=0; +// } +// else +// { +// pGain1 = pGain; +// } + step = err * pGain1 + (temperature-prevTemp)/boardSetpointTemp*dGain; + step = (step > stepMax) ? stepMax : step; + step = (step < stepMin) ? stepMin : step; + boardDutyCycle -= step; + boardDutyCycle = (boardDutyCycle < dutyCycleMin) ? dutyCycleMin : boardDutyCycle; + boardDutyCycle = (boardDutyCycle > dutyCycleMax) ? dutyCycleMax : boardDutyCycle; + boardPWM.write(boardDutyCycle); //update with new settings + + prevTemp = temperature; + +} + + +void rampLamp(float finalDutyCycle) +{ + float currentDutyCycle; + float step = 0.01; //increment or decrement duty cycle by 1% increments + bool ramping = 1; + currentDutyCycle = mypwm.read(); + while (ramping) { + wait_ms(40); + if(finalDutyCycle - currentDutyCycle > step) + { + currentDutyCycle += step; + mypwm.write(currentDutyCycle); + } + else if (finalDutyCycle - currentDutyCycle < -step) + { + currentDutyCycle -= step; + mypwm.write(currentDutyCycle); + } + else + { + ramping = 0; + mypwm.write(finalDutyCycle); + } + } +} + + +float getNewSetpoint(float targetVoltage, float warmUpTime, float calTime) +{ + warmUpTime = ( warmUpTime < 0 ) ? 0 : warmUpTime; + calTime = (calTime <= warmUpTime) ? calTime= warmUpTime*2+1: calTime; + const float calTime_ms = 1000*calTime; //convert seconds to ms + const float warmUpTime_ms = 1000*warmUpTime; + + const float tol =0.02;// volts tolerance on target voltage + const uint8_t persist=8; //number of consecutive samples in range in order to output new setpoint + uint8_t consecutiveInRange=0; + const float propGain = 2e-3; //proportional gain + float errVoltage; + float tempErr; + t.start(); + + //turn on heater and stabilize board at target temp + rampLamp(dutyCycle); + rampLamp(0.05); //low level power keeps fan on + boardPWM.write(boardDutyCycle); + while(t.read_ms() < 120*1000) + { + wait_ms(699); + updateTemperature(); + tempErr = (instantTemperature - boardSetpointTemp)/boardSetpointTemp; + if (abs(tempErr*boardSetpointTemp)>tempTol) { + updateBoardPWM(tempErr,boardPropGain,boardDerGain); + } + + pc.printf( "%.4f, %.2f, %f, %f, %f, %U\r\n",lampVolts, ch0Data, mypwm.read(),boardPWM.read(),temperature,consecutiveInRange); + } + + rampLamp(dutyCycle); + //begin adjust output to target voltage at desired sensor board temperature. + while(t.read_ms() < calTime_ms) { + wait_ms(699); + updateTemperature(); + updateLampVolts(numLampMeas); + updateAlsData(); + //#ifdef printDebug + pc.printf( "%.4f, %.2f, %f, %f, %f, %U\r\n",lampVolts, ch0Data, mypwm.read(),boardPWM.read(),temperature,consecutiveInRange); + //#endif + errVoltage = lampVolts-targetVoltage; + if (abs(errVoltage) < tol ) + { + consecutiveInRange++; + if ( consecutiveInRange >= persist) + { + if(t.read_ms() > warmUpTime_ms) + { + return floor(ch0Data)+0.5; + } + } + } + else + { + consecutiveInRange=0; + } + updateLampPWM(errVoltage,0,propGain,0); + tempErr = (instantTemperature - boardSetpointTemp)/boardSetpointTemp; + if (abs(tempErr*boardSetpointTemp)>tempTol) { + updateBoardPWM(tempErr,boardPropGain,boardDerGain); + } + + } //end while + return ch0Data; +} + int main() { float ratio; - char data[4]; - uint16_t ch0Data; - uint16_t ch1Data; - float setpoint = 37250; //ch0/ch1 color setpoint ~0.88 duty cycle - static float step; //duty cycle change per sample - float dutyCycle=0.9275; - float dutyCycleMin =0.8; - float dutyCycleMax =0.98; - float stepMax=0.0025; - float stepMin=-0.0025; + static bool inRange=false; + float setpoint = 37250.5; //ch0/ch1 color setpoint ~0.88 duty cycle // float iGain = 0.05; //integral gain --adding this because when I blew on it, it couldn't recover float err; - float tol=1; //tolerance within which to ignore changes in signal intensity - float pGain = 0.25; //proportional gain -// float quadGain = 0;*/ - static float temperature = 0; - //float ch0Avg; //integral error -// float filterLength = 15; - float tempFilterLength = 8; + float tempErr; + const float tol=0.5; //tolerance within which to ignore changes in signal intensity + float pGain; //proportional gain + float iGain; // 250 : 0.2 ratio relative to pGain + float sumErr=0; + const float sumErrMax = .01; + //setup everything mypwm.period_us(400); - mypwm.write(dutyCycle); + boardPWM.period_us(400); + slotHeaterPWM.period_us(400); + slotHeaterPWM.write(0); + //mypwm.write(dutyCycle); + boardPWM.write(0); i2c.frequency(400000); //set I2C frequency to 400kHz wait_ms(1000); initTMD2772(); - regDump(TMD2772_Addr,(0x00 | 0x80),0x0F); + #ifdef printDebug + regDump(TMD2772_Addr,(0x00 | 0x80),0x0F); + #endif + pc.printf("fan on\r\n"); pc.printf("Done initializing\r\n"); wait_ms(700); static int loopCount =0; - //get initial filter value -// reg2write=ALSDataRegister | 0x80; - readRegisters(TMD2772_Addr, (ALSDataRegister | 0x80), data ,4); -// -// i2c.write(TMD2772_Addr,®2write,1,true); //1 byte of data, repeated start for read -// i2c.read(TMD2772_Addr,data,4); - ch0Data = LSB_MSB_2uint16(data); - ch1Data = LSB_MSB_2uint16(data+2); - ratio = (float)ch0Data/(float)ch1Data; - wait_ms(699); + wait_ms(measPeriod_ms); + + //warmup and choose setpoint + pc.printf("finding %f V setpoint\r\n",targetV); + setpoint = getNewSetpoint(targetV, 300, 400); + pc.printf( "new setpoint is %f counts\r\n",setpoint ); - + while(1) { - loopCount++; - if (loopCount<warmUp) + t.start(); + updateTemperature(); + updateAlsData(); + ratio = ch0Data/ch1Data; + err = (ch0Data - setpoint)/setpoint; + tempErr = (instantTemperature - boardSetpointTemp)/boardSetpointTemp; + if(loopCount<warmUp) { - pGain =0.25; + sumErr=0; //no integral gain during initial warmup--takes too long to integate error out + pGain=0.25; } else { - pGain =0.2; + sumErr += err; //use integral gain while the sensor is heating up to get to setpoint faster and avoid lag. + pGain=pGainNormal; } - t.start(); - readRegisters(TMD2772_Addr, (ALSDataRegister | 0x80), data ,4); - //reg2write=ALSDataRegister | 0x80; -//// pc.printf("%X\r\n",reg2write); -// i2c.write(TMD2772_Addr,®2write,1,true); //1 byte of data, repeated start for read -// i2c.read(TMD2772_Addr,data,4); - ch0Data = LSB_MSB_2uint16(data); - if (temperature ==0) + inRange = (abs(sumErr)<sumErrMax) ? true : false; + if(inRange) { - temperature = getTemp(MAX31725_Addr); - } - else + iGain=0; //no need for iGain--inRange + } + else { - temperature += (getTemp(MAX31725_Addr)-temperature)/tempFilterLength ; + iGain = iGainNormal; } - ch0Data = tempCorrectTMDCh0(ch0Data,temperature); - ch1Data = LSB_MSB_2uint16(data+2); - ch1Data = tempCorrectTMDCh1(ch0Data,temperature); - ratio = (float)ch0Data/(float)ch1Data; - err = ch0Data - setpoint; - pc.printf( "%U,%U, %f, %f, %f, %f\r\n",ch0Data,ch1Data,ratio,mypwm.read(),temperature, step); - if (abs(err)>tol) { - step = err/setpoint * pGain ; - step = (step > stepMax) ? stepMax : step; - step = (step < stepMin) ? stepMin : step; - dutyCycle -= step; - dutyCycle = (dutyCycle < dutyCycleMin) ? dutyCycleMin : dutyCycle; - dutyCycle = (dutyCycle > dutyCycleMax) ? dutyCycleMax : dutyCycle; - //update with new settings - mypwm.write(dutyCycle); + updateLampVolts(numLampMeas); + //#ifdef printDebug + 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 ); + //#endif + if (abs(err*setpoint)>tol) { + updateLampPWM(err,sumErr,pGain,iGain); } + if (abs(tempErr*boardSetpointTemp)>tempTol) { + updateBoardPWM(tempErr,boardPropGain,boardDerGain); + } + loopCount++; while(t.read_ms() < measPeriod_ms) { //pc.printf("%U \r\n",t.read_ms()); }