From 3bece79a5f931da517f64fd89ec4953c309dc736 Mon Sep 17 00:00:00 2001 From: Fisch Date: Sat, 14 Apr 2018 13:56:49 +0200 Subject: [PATCH] implement eeprom save and load --- lightmeter.ino | 285 ++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 256 insertions(+), 29 deletions(-) diff --git a/lightmeter.ino b/lightmeter.ino index e3df436..ca90d0f 100644 --- a/lightmeter.ino +++ b/lightmeter.ino @@ -14,28 +14,42 @@ //128 x 64 px #define WIDTH 128 #define HEIGHT 64 +#include #include //from: https://github.com/mysensors/MySensorsArduinoExamples/tree/master/libraries/BH1750 BH1750 lightMeter; +#define INCIDENT_CORRECTION_FACTOR 1.17 +//with 1125 25 225 2465 120 +//wihtout 1335 32 265 2865 145 +/*1,186666667 +1,28 +1,177777778 +1,162271805 +1,208333333*/ + + #define PIN_LDR 0 //A0 #define PIN_BRIGHTMODE 1 //A1 #define PIN_VBAT 2 //A2 +#define PIN_LED 8 //White status led A8 #define PIN_TRIGGER PB8 #define PIN_BTNLEFT PA15 #define PIN_BTNCENTER PB4 #define PIN_BTNRIGHT PB5 -#define PIN_ON PB9 +#define PIN_ON PB9 //pin for hardware latch #define TIME_AUTOPOWEROFF 120000 -#define TIME_METERINGMODESELECTION_CLOSE 4000 -#define LDRDELAY 50 //minimum delay between ldr readings. Transistor for lower value pulldown resistor switches in between +#define TIME_METERINGMODESELECTION_CLOSE 60000 +#define LDRDELAY 100 //delay between ldr switches. New analog_high or low reading after that time. Transistor for lower value pulldown resistor switches in between +#define LDRFILTERDELAY 1 //delay in ms between readings sequent readings for smoothing . LDRFILTERDELAY*64 > LDRDELAY +#define LDRSWITCHDELAY 30 //time to wait after transistor switched #define INCIDENTDELAY 100 //minimum delay between incident sensor (BH1750) readings #define DEBOUNCETIME 20 //time to not check for inputs after key press #define BUTTONTIMEHOLD 750 //time for button hold -#define voltage_warn 3.4 //voltage per cell //TODO implement warning +#define VOLTAGE_WARN 3.4 //voltage per cell //TODO implement warning //float shuttertimes1[]={1,1.0/2, 1.0/4, 1.0/8, 1.0/15, 1.0/30, 1.0/60, 1.0/125, 1.0/250, 1.0/500, 1.0/1000, 1.0/2000, 1.0/4000, 1.0/8000}; float shuttertimes1[]={64,32,16,8,4,2,1,1.0/2, 1.0/4, 1.0/8, 1.0/15, 1.0/30, 1.0/60, 1.0/125, 1.0/250, 1.0/500, 1.0/1000, 1.0/2000, 1.0/4000, 1.0/8000}; @@ -59,9 +73,13 @@ float isoThird[]={12,16,20,25,32,40,50,64,80,100,125,160,200,250,320,400,500,640 long loopmillis=0; //only use one millis reading each loop long last_ldrReading=0; +long last_ldrReadingFilter=0; long last_incidentReading=0; long millis_lastchange=0; long millis_lastinput=0; +long millis_ledoff=0; //for led blink +long millis_opened_meteringmodeselection=0; //time when meteringmodeselecten was opened (for led flashlight timing) +#define DELAY_METERINGMODESELECTION_FLASHLIGHT 2000 long timebuttonpressed_trigger; @@ -90,7 +108,15 @@ struct Settings { uint8_t ISOSelectionMode; //1=Full, 2=Thirds }; +bool settingsStructEqual(Settings a, Settings b){ + if (a.minimumAperatureIndex!=b.minimumAperatureIndex || a.aperatureSelectionMode!=b.aperatureSelectionMode || a.shutterSelectionMode!=b.shutterSelectionMode || a.ISOSelectionMode!=b.ISOSelectionMode){ + return false; + } + return true; +} + Settings userSettings= {1,1, 1,2}; +Settings eeprom_userSettings; //to store current eeprom status @@ -98,9 +124,12 @@ Settings userSettings= {1,1, 1,2}; #define OLED_RESET 4 Adafruit_SSD1306 display(OLED_RESET); + uint16_t incident=0; //incident reading from bh1750 uint16_t analog_low=0; //better for low light uint16_t analog_high=0; //better for bright light (higher pulldown resistor for ldr) +uint16_t analog_reading_filtering=0; +uint8_t analog_reading_count=0; float ev=0; //calculated EV from LDR readings (reflected) or from Luxmeter (incident) float ev_min=6,ev_max=12,ev_last=8; @@ -113,6 +142,16 @@ float setAperature=8; //set to use aperature. 0 for auto float setShutter=0; //set to use shutter time, 0 for auto uint16_t setISO=100; //set to ISO +float eeprom_setAperature=0; //set to use aperature. 0 for auto +float eeprom_setShutter=0; //set to use shutter time, 0 for auto +uint16_t eeprom_setISO=0; //set to ISO + +#define EEPROMADDRESS_APERATURE 0x801F000 //float = 32bit = 4byte +#define EEPROMADDRESS_SHUTTER 0x801F004 //float = 32bit = 4byte +#define EEPROMADDRESS_ISO 0x801F008 //uint16_T 16bit = 2byte +#define EEPROMADDRESS_METERINGMODE 0x801F00A //uint8_t 1byte +#define EEPROMADDRESS_USERSETTINGS 0x801F00B //Settings struct + enum displaymode { lightmeter, settings, @@ -123,12 +162,20 @@ uint8_t settings_selectedItem=0; //in settings display String settingStrings[]={"ISO:","F-Stops:","Timetable:","Turn Off"}; #define SETTINGS_SELECTEDITEM_MAX 3 //inclusive. 2 means 3 items available boolean settings_itemActive=false; //item in settings selected to change value +#define DISPLAY_UPDATEDELAY 200 +long last_displayupdate=0; #define METERINGMODE_REFLECTIVE 0 #define METERINGMODE_INCIDENT 1 uint8_t meteringmode=METERINGMODE_REFLECTIVE; +uint8_t eeprom_meteringmode=0; + +bool eeprom_red=false; //false, if eeprom need to be red +bool debug_printreadings=false; +uint16_t debug_analog_high=0; +uint16_t debug_analog_low=0; char tempstring[16]; //for dtostrf //dtostrf(modefactor,1,3,tempstring); @@ -148,7 +195,7 @@ char tempstring[16]; //for dtostrf //dtostrf(modefactor,1,3,tempstring); void setup() { - Serial.begin(9600); + Serial.begin(115200); Serial.println("Started"); Serial.println("Init Display"); @@ -172,33 +219,128 @@ void setup() { digitalWrite(PIN_BRIGHTMODE, LOW); pinMode(PIN_ON, OUTPUT); digitalWrite(PIN_ON, HIGH); + pinMode(PIN_LED, OUTPUT); + digitalWrite(PIN_LED, HIGH);//blink led on + delay(50); + digitalWrite(PIN_LED,LOW); //blink led off millis_lastchange=millis(); Serial.println("Initialized"); + if (!digitalRead(PIN_TRIGGER)){ //hold trigger button during power on activates serial debug printing + debug_printreadings=true; + } + //display.drawPixel(10, 10, WHITE); } + +bool saveSettingsToEEPROM(bool force){ + bool _eepromwritten=false; + //checks and writes changes to eeprom + if (eeprom_setAperature!=setAperature || force){ //value change or write forced + EEPROM_writeAnything(EEPROMADDRESS_APERATURE, setAperature); + _eepromwritten=true; + } + if (eeprom_setShutter!=setShutter || force){ //value change or write forced + EEPROM_writeAnything(EEPROMADDRESS_SHUTTER, setShutter); + _eepromwritten=true; + } + if (eeprom_setISO!=setISO || force){ //value change or write forced + EEPROM_writeAnything(EEPROMADDRESS_ISO, setISO); + _eepromwritten=true; + } + if (eeprom_meteringmode!=meteringmode || force){ //one of the values change or write forced + EEPROM_writeAnything(EEPROMADDRESS_METERINGMODE, meteringmode); + _eepromwritten=true; + } + if (!settingsStructEqual(eeprom_userSettings,userSettings) || force){ //one of the values change or write forced + EEPROM_writeAnything(EEPROMADDRESS_USERSETTINGS, userSettings); + _eepromwritten=true; + } + + + return _eepromwritten; +} + + void loop() { loopmillis=millis(); //read millis for this cycle - + if (!eeprom_red){ //only executed one time + eeprom_red=true; + readEEPROM(); + } handleInputs(); - calculateFromEV(); updateDisplay(); - + checkLED(); } +void readEEPROM(){ + + if (!digitalRead(PIN_BTNLEFT) && !digitalRead(PIN_BTNCENTER) && !digitalRead(PIN_BTNRIGHT) ){ //push all front buttons (left, center, right) to restore default settings + digitalWrite(PIN_LED,HIGH); + delay(1000); //1s led on confirmation + digitalWrite(PIN_LED,LOW); + saveSettingsToEEPROM(true); //force writing. userSettings contains the default values at this point + delay(200); + digitalWrite(PIN_LED,HIGH); + delay(200); //1s led on confirmation + digitalWrite(PIN_LED,LOW); + delay(200); + digitalWrite(PIN_LED,HIGH); + delay(200); //1s led on confirmation + digitalWrite(PIN_LED,LOW); + delay(1000); + } + + //read current eeprom + EEPROM_readAnything(EEPROMADDRESS_APERATURE, eeprom_setAperature); + EEPROM_readAnything(EEPROMADDRESS_SHUTTER, eeprom_setShutter); + EEPROM_readAnything(EEPROMADDRESS_ISO, eeprom_setISO); + EEPROM_readAnything(EEPROMADDRESS_METERINGMODE, eeprom_meteringmode); + EEPROM_readAnything(EEPROMADDRESS_USERSETTINGS, eeprom_userSettings); + Serial.println(""); + Serial.println("EEPROM eeprom settings"); + Serial.println(eeprom_setAperature); + Serial.println(eeprom_setShutter); + Serial.println(eeprom_setISO); + Serial.println("EEPROM eeprom_userSettings"); + Serial.println(eeprom_userSettings.minimumAperatureIndex); + Serial.println(eeprom_userSettings.aperatureSelectionMode); + Serial.println(eeprom_userSettings.shutterSelectionMode); + Serial.println(eeprom_userSettings.ISOSelectionMode); + Serial.println(""); + + if (eeprom_userSettings.minimumAperatureIndex==255){ //after flashing eeprom contains FF.., check one value + for (int i=0;i<10;i++){ //blink a few times to show that eeprom was clean + delay(50); + digitalWrite(PIN_LED,HIGH); + delay(50); //1s led on confirmation + digitalWrite(PIN_LED,LOW); + } + }else{ // + //apply + setAperature=eeprom_setAperature; + setShutter=eeprom_setShutter; + setISO=eeprom_setISO; + meteringmode=eeprom_meteringmode; + userSettings=eeprom_userSettings; + } + +} + + void handleInputs() { @@ -290,13 +432,31 @@ void handleInputs() vbat=map(analogRead(PIN_VBAT), 0,3560,0,8200)/1000.0; //180k and 300k voltage divider. 8,4V -> 3,15V=3910 //LDR - if ( loopmillis-last_ldrReading>LDRDELAY ) + + if ( loopmillis-last_ldrReadingFilter>LDRFILTERDELAY && loopmillis-last_ldrReading>LDRSWITCHDELAY) //multiple successive reading for filtering. each LDRFILTERDELAY ms and wait LDRSWITCHDELAY for first reading + { + analog_reading_filtering+=analogRead(PIN_LDR); + analog_reading_count++; + last_ldrReadingFilter=loopmillis; + } + + if ( loopmillis-last_ldrReading>LDRDELAY ) //time over for one reading (low or high) { if (!digitalRead(PIN_BRIGHTMODE)){ - analog_low=analogRead(PIN_LDR); + analog_low=analog_reading_filtering/analog_reading_count; }else{ - analog_high=analogRead(PIN_LDR); + analog_high=analog_reading_filtering/analog_reading_count; + if (debug_printreadings){ + Serial.print(analog_low);//for calibration output + Serial.print(";"); + Serial.println(analog_high); + } } + /*Serial.print(analog_reading_count); + Serial.print(" value="); + Serial.println(analog_reading_filtering);*/ + analog_reading_count=0; //reset + analog_reading_filtering=0; //reset digitalWrite(PIN_BRIGHTMODE, !digitalRead(PIN_BRIGHTMODE)); //switch modes last_ldrReading=loopmillis; } @@ -364,7 +524,7 @@ void handleInputs() if (millis()-millis_lastchange>TIME_AUTOPOWEROFF){ - digitalWrite(PIN_ON, LOW); + poweroff(); } if ( button_trigger || button_left || button_center || button_right ) { @@ -374,10 +534,25 @@ void handleInputs() } +void poweroff(){ + bool _eepromwritten=saveSettingsToEEPROM(false); //save only changes to eeprom + digitalWrite(PIN_LED,HIGH); //Blink led + delay(100); + digitalWrite(PIN_LED,LOW); + if (_eepromwritten){ + delay(100); + digitalWrite(PIN_LED,HIGH); + delay(100); + digitalWrite(PIN_LED,LOW); + } + digitalWrite(PIN_ON, LOW); //Turn off hardware latch +} + void handleInputs_Lightmeter() { if ( button_center ) { //open meteringmode selection displaymode=meteringmodeselection; + millis_opened_meteringmodeselection=loopmillis; } if ( button_hold_center ) { //Go to Settings @@ -440,12 +615,15 @@ void handleInputs_Lightmeter() if (button_trigger || button_hold_trigger) { //Trigger ev=getEV(); //set ev to current measurement by selected mode + debug_analog_high=analog_high; + debug_analog_low=analog_low; + blinkLED(20); } - } + void handleInputs_Settings() { if ( button_hold_center ) { //Go to Lightmeter @@ -509,7 +687,7 @@ void handleInputs_Settings() break; case 3: //Turn Off - digitalWrite(PIN_ON, LOW); //set power latch low + poweroff(); break; } if ( button_center ){ @@ -551,8 +729,12 @@ float getEV(){ float _ev=0; if (meteringmode == METERINGMODE_REFLECTIVE){ //### SPOT //ev=map(analog_low,500, 3500 ,500, 1400)/100.0; //for testing + + //first prototype double highev=11.7400532 + 0.000216655133*analog_high + 0.00000111372253*pow(analog_high,2) + -0.000000000163800818 *pow(analog_high,3); double lowev=-0.763427709 + 0.0138031137*analog_low + -0.00000576990095*pow(analog_low,2) + 0.000000000871611285*pow(analog_low,3); + + if (lowev>14){ _ev=highev; @@ -563,7 +745,7 @@ float getEV(){ _ev=lowev*(1-mix)+highev*mix; } }else if (meteringmode == METERINGMODE_INCIDENT){ //### INCIDENT - _ev = luxToEv(incident); + _ev = luxToEv(incident*INCIDENT_CORRECTION_FACTOR); } return _ev; @@ -834,20 +1016,24 @@ uint8_t findISOIndex(float pISO,uint8_t pMethod) //find index of closest iso fro void updateDisplay() { - switch(displaymode){ - case lightmeter: - updateDisplay_Lightmeter(); - break; - case settings: - updateDisplay_Settings(); - break; - case meteringmodeselection: - updateDisplay_Meteringmodeselection(); - break; + if (loopmillis-last_displayupdate>=DISPLAY_UPDATEDELAY){ + switch(displaymode){ + case lightmeter: + updateDisplay_Lightmeter(); + break; + case settings: + updateDisplay_Settings(); + break; + case meteringmodeselection: + updateDisplay_Meteringmodeselection(); + break; + } + last_displayupdate=loopmillis; + display.display(); } - display.display(); + } void updateDisplay_Lightmeter() //Lightmeter display @@ -867,6 +1053,8 @@ void updateDisplay_Lightmeter() //Lightmeter display display.clearDisplay(); display.setTextColor(WHITE); + + //Aperature float _showAperature=roundAperature(showAperature,userSettings.aperatureSelectionMode); @@ -925,6 +1113,7 @@ void updateDisplay_Lightmeter() //Lightmeter display //ISO display.setCursor(xpos_iso,ypos_iso); display.setTextSize(1); display.print("ISO "); display.print(setISO); + //EV Scale uint8_t _startev=2; //first ev to display, 13 ev values can fit on screen @@ -972,7 +1161,7 @@ void updateDisplay_Lightmeter() //Lightmeter display _displayev=(int)(ev+1);//EV Value under arrow. Ceil } if (_displayev>=10){ - _xpos_current_evtext_move+=5; //move digits to left + _xpos_current_evtext_move+=6; //move digits to left. positive means left } display.setCursor(xpos_arrow-_xpos_current_evtext_move,ypos_icon_arrow+icon_arrow_height+2); //current ev text position display.print(_displayev); //EV Value under arrow @@ -985,17 +1174,22 @@ void updateDisplay_Lightmeter() //Lightmeter display }else if ( _ev_decimals > 0.5833 && _ev_decimals <= 0.8333) { display.drawXBitmap(xpos_arrow , ypos_icon_arrow+icon_arrow_height-(icon_two_third_height-8)/2 +2, icon_two_third_bits, icon_two_third_width, icon_two_third_height, WHITE); //two third } + //DEBUG Message display.setTextSize(1); display.setCursor(xpos_debug,ypos_debug); - display.print(vbat); + /*display.print(vbat); display.print("V "); display.print("Ev="); display.print(ev); display.print(" |"); - display.print(incident); + display.print(incident);*/ + + display.print(debug_analog_low); + display.print(" : "); + display.print(debug_analog_high); } @@ -1055,5 +1249,38 @@ void updateDisplay_Meteringmodeselection() display.print("SPOT"); //7x5 characters, xpos_center_icon_spot-(5*#chars /2) display.setCursor(xpos_center_icon_incident-20,ypos_icon_incident+icon_incident_height+6); //text position upper left display.print("INCIDENT"); + + if (loopmillis-millis_opened_meteringmodeselection>=DELAY_METERINGMODESELECTION_FLASHLIGHT){ + blinkLED(500); //turn led on continously + } } +void blinkLED(long duration){ + digitalWrite(PIN_LED,HIGH); + millis_ledoff=loopmillis+duration; +} +void checkLED(){ + if (loopmillis>=millis_ledoff && digitalRead(PIN_LED)){ + digitalWrite(PIN_LED,LOW); + } +} + + +template int EEPROM_writeAnything(int ee, const T& value) +{ //from http://www.stm32duino.com/viewtopic.php?t=1576 + const byte* p = (const byte*)(const void*)&value; + unsigned int i; + for (i = 0; i < sizeof(value); i++) + EEPROM.write(ee++, *p++); + + return i; +} + +template int EEPROM_readAnything(int ee, T& value) +{ + byte* p = (byte*)(void*)&value; + unsigned int i; + for (i = 0; i < sizeof(value); i++) + *p++ = EEPROM.read(ee++); + return i; +}