/* Code to automatically dim the instrument panel LED's, and to control the navigational lights. */ #include // #include "LowPower.h" // Uncomment this statement if you want to use the LowPower library. This reduces the power consumption from 16mA to 3mA. You have to install the LowPower library first! // Settings #define CURRENT_TRESHOLD 10 // Any value above this indicates that the power to a lamp has been switched on. Theoretically 0, but allow for noise. #define MARGIN 10 // Percentage the measured current is allowed to be below the stored current. #define SENSOR_SAMPLES 10 // Amount of photo sensor samples to derive the average from. // Analog inputs #define POTMETER 0 #define PHOTO_SENSOR 1 #define REF_VOLTAGE 2 // This input is used as reference voltage, this pin is tied via a zener to the 12V rail. Voltage will vary depending on the charge state, and so will the voltage over the lamp resistors. #define LAMP1_CURRENT 3 // These inputs are connected to a small resistor in line with the 12V feed to the lamp. Voltage drop will be dependent on lamp current. #define LAMP2_CURRENT 4 #define LAMP3_CURRENT 5 #define LAMP4_CURRENT 6 #define LAMP5_CURRENT 7 // Digital inputs #define BUTTON 2 #define PWM2_ENABLE 4 // Digital outputs #define ALARM 5 // This output will become HIGH when one of the lamps fails. #define PWM1_OUT 3 // PWM Output for instrument panel lighting #define PWM2_OUT 11 // PWM Output for auxilliary panel lighting #define IT_IS_DARK 13 // Becomes HIGH when the ambient light is below the configured treshold value. #define LAMP1_IND 7 // Indicators for the associated lamps. Becomes HIGH when the LED indicator should be lit. #define LAMP2_IND 8 #define LAMP3_IND 9 #define LAMP4_IND 10 #define LAMP5_IND 12 struct settings_t { byte pwm_lo_limit; // The lowest PWM ratio selected byte pwm_hi_limit; // The highest PWM ratio selected int pwm_lo_photo; // The photo sensor value where the lowest PWM ratio will be selected int pwm_hi_photo; // The photo sensor value where the highest PWM ratio will be selected int vdiff1; // These are the recorded voltage drops over the resistors, minus a margin of MARGIN percent. int vdiff2; int vdiff3; int vdiff4; int vdiff5; int treshold; // This is the photo sensor value where the system switches over from day to night mode. } settings; struct led { byte current_pin; byte led_pin; int *vdiff; // Pointer to the corresponding vdiff entry in the settings structure. }; // This is an array of led structures. struct led lamps[]={ {LAMP1_CURRENT,LAMP1_IND,&settings.vdiff1}, {LAMP2_CURRENT,LAMP2_IND,&settings.vdiff2}, {LAMP3_CURRENT,LAMP3_IND,&settings.vdiff3}, {LAMP4_CURRENT,LAMP4_IND,&settings.vdiff4}, {LAMP5_CURRENT,LAMP5_IND,&settings.vdiff5} }; struct average_t { unsigned long sum; unsigned int average; byte samples; const byte samples_required; }; average_t average_photo_sensor ={SENSOR_SAMPLES/2,0,0,SENSOR_SAMPLES}; unsigned int average(unsigned int value, struct average_t* average) { // We will just collect "samples_required" of samples, and once we got this amount, we calculate the average and start all over again. // Note that this will cause a delay of maximal "samples_required"/LOOPS_PER_SECOND before a sudden change in measured value will show up in the average. average->sum+=value; average->samples++; if(average->samples==average->samples_required) { average->average=average->sum/average->samples; average->samples=0; average->sum=average->samples_required/2; // Seed sum with half the division value so we obtain a rounded result later when we perform the division. } return average->average; } void setup() { // Initialize digital inputs pinMode(BUTTON,INPUT_PULLUP); pinMode(PWM2_ENABLE,INPUT_PULLUP); // Initialize PWM outputs analogWrite(PWM1_OUT,0); analogWrite(PWM2_OUT,0); // Initialize digital outputs pinMode(IT_IS_DARK,OUTPUT); digitalWrite(IT_IS_DARK,LOW); pinMode(ALARM,OUTPUT); digitalWrite(ALARM,LOW); for(int i=0; i<(int)( sizeof(lamps) / sizeof(lamps[0]));i++) { pinMode(lamps[i].led_pin,OUTPUT); digitalWrite(lamps[i].led_pin,LOW); } eeprom_read_block((void*)&settings, (void*)0, sizeof(settings)); // Read the configuration settings. // Initialize analog averages average_photo_sensor.average=analogRead(PHOTO_SENSOR); if(digitalRead(BUTTON)==LOW) { while(digitalRead(BUTTON)==LOW) { analogWrite(PWM1_OUT,100); delay(50); analogWrite(PWM1_OUT,0); delay(50); } settings.treshold=average_photo_sensor.average; eeprom_write_block((void*)&settings, (void*)0, sizeof(settings)); // Record the new settings in the EEPROM } } void loop() { #ifdef LowPower_h // Sleep for 500ms, but keep timer2 on, switch off the rest. Timer2 is used for generating the PWM signal, we don't want to loose that while sleeping! LowPower.idle(SLEEP_500MS, ADC_OFF, TIMER2_ON, TIMER1_OFF, TIMER0_OFF, SPI_OFF, USART0_OFF, TWI_OFF); #else delay(500); #endif unsigned int photo_sensor=average(analogRead(PHOTO_SENSOR),&average_photo_sensor); // Setting the IT_IS_DARK output if(photo_sensor>settings.treshold) { digitalWrite(IT_IS_DARK,LOW); } else { digitalWrite(IT_IS_DARK,HIGH); } // If the button is pressed... if(digitalRead(BUTTON)==LOW) { // Check to see if some lamp is switched on. if(analogRead(LAMP1_CURRENT)>CURRENT_TRESHOLD || analogRead(LAMP2_CURRENT)>CURRENT_TRESHOLD || analogRead(LAMP3_CURRENT)>CURRENT_TRESHOLD || analogRead(LAMP4_CURRENT)>CURRENT_TRESHOLD || analogRead(LAMP5_CURRENT)>CURRENT_TRESHOLD) { while(digitalRead(BUTTON)==LOW) { // Flash the indication led of the lamps which are switched on, until the button is released for(int i=0; i<(int)( sizeof(lamps) / sizeof(lamps[0]));i++) { if(analogRead(lamps[i].current_pin)>CURRENT_TRESHOLD) digitalWrite(lamps[i].led_pin,!digitalRead(lamps[i].led_pin)); // This lamp is on. Toggle the indicator. } delay(50); } // Setting of lamp normal currents for(int i=0; i<(int)( sizeof(lamps) / sizeof(lamps[0]));i++) { if(analogRead(lamps[i].current_pin)>CURRENT_TRESHOLD) { *lamps[i].vdiff=(analogRead(REF_VOLTAGE)-analogRead(lamps[i].current_pin))*100/(100+MARGIN); } } } else { // Setting of the PWM level and sensor values while(digitalRead(BUTTON)==LOW) { analogWrite(PWM1_OUT,analogRead(POTMETER)/4); // Set PWM level according to potentiometer } if(photo_sensor>settings.treshold) { // Treshold potentiometer determines whether we are recording the low or high light value settings.pwm_hi_limit=analogRead(POTMETER)/4; settings.pwm_hi_photo=photo_sensor; } else { settings.pwm_lo_limit=analogRead(POTMETER)/4; settings.pwm_lo_photo=photo_sensor; } } eeprom_write_block((void*)&settings, (void*)0, sizeof(settings)); // Record the new settings in the EEPROM } // Determining and setting the PWM output byte pwm_out; if(photo_sensor>=settings.pwm_hi_photo) { // Photo sensor indicates more light than our high setting, so give the highest output pwm_out=settings.pwm_hi_limit; } else if(photo_sensor<=settings.pwm_lo_photo) { // Photo sensor indicates less light than our low setting, so give the lowest output pwm_out=settings.pwm_lo_limit; } else { // Sensor value between high and low, so use both output setpoints to calculate a value according to ratio pwm_out=settings.pwm_lo_limit+((settings.pwm_hi_limit-settings.pwm_lo_limit)*50/((settings.pwm_hi_photo-settings.pwm_lo_photo)*50/(photo_sensor-settings.pwm_lo_photo))); } analogWrite(PWM1_OUT,pwm_out); if(digitalRead(PWM2_ENABLE)==LOW) analogWrite(PWM2_OUT,pwm_out); // Use the lamp current to set the indication LED's digitalWrite(ALARM,LOW); for(int i=0; i<(int)( sizeof(lamps) / sizeof(lamps[0]));i++) { // If the power to the lamp is switched on... if(analogRead(lamps[i].current_pin)>CURRENT_TRESHOLD) { if(analogRead(REF_VOLTAGE)-analogRead(lamps[i].current_pin) >= *lamps[i].vdiff) { digitalWrite(lamps[i].led_pin,HIGH); // Current is at least equal to the current we have set, so everything is ok. } else { digitalWrite(lamps[i].led_pin,!digitalRead(lamps[i].led_pin)); // Current is too low. Toggle the associated indication LED... digitalWrite(ALARM,HIGH); //... and set the Alarm } } else { digitalWrite(lamps[i].led_pin,LOW); // Lamp is switched off. So switch off the associated indication LED. } } }