diff --git a/icon_arrow.c b/icon_arrow.c new file mode 100644 index 0000000..dfb6ecf --- /dev/null +++ b/icon_arrow.c @@ -0,0 +1,4 @@ +#define icon_arrow_width 5 +#define icon_arrow_height 8 +static unsigned char icon_arrow_bits[] = { + 0x04, 0x0e, 0x1f, 0x04, 0x04, 0x04, 0x04, 0x04 }; diff --git a/icon_arrow.xcf b/icon_arrow.xcf new file mode 100644 index 0000000..394fa92 Binary files /dev/null and b/icon_arrow.xcf differ diff --git a/icon_incident.c b/icon_incident.c new file mode 100644 index 0000000..5f0db4e --- /dev/null +++ b/icon_incident.c @@ -0,0 +1,6 @@ +#define icon_incident_width 16 +#define icon_incident_height 16 +static unsigned char icon_incident_bits[] = { + 0x41, 0x00, 0x21, 0x18, 0x07, 0x06, 0x9d, 0x01, 0x31, 0x60, 0x21, 0x1c, + 0x61, 0x03, 0x41, 0x00, 0x41, 0x00, 0x61, 0x03, 0x21, 0x1c, 0x31, 0x60, + 0x9d, 0x01, 0x07, 0x06, 0x21, 0x18, 0x41, 0x00 }; diff --git a/icon_incident.xcf b/icon_incident.xcf index fe9a89a..444fc4b 100644 Binary files a/icon_incident.xcf and b/icon_incident.xcf differ diff --git a/icon_one_half.c b/icon_one_half.c new file mode 100644 index 0000000..16291b3 --- /dev/null +++ b/icon_one_half.c @@ -0,0 +1,4 @@ +#define icon_one_half_width 5 +#define icon_one_half_height 12 +static unsigned char icon_one_half_bits[] = { + 0x04, 0x06, 0x04, 0x04, 0x04, 0x1f, 0x00, 0x06, 0x08, 0x0c, 0x02, 0x0e }; diff --git a/icon_one_third.c b/icon_one_third.c new file mode 100644 index 0000000..7191f9e --- /dev/null +++ b/icon_one_third.c @@ -0,0 +1,4 @@ +#define icon_one_third_width 5 +#define icon_one_third_height 12 +static unsigned char icon_one_third_bits[] = { + 0x04, 0x06, 0x04, 0x04, 0x04, 0x1f, 0x00, 0x06, 0x08, 0x06, 0x08, 0x06 }; diff --git a/icon_spot.c b/icon_spot.c new file mode 100644 index 0000000..4b419ff --- /dev/null +++ b/icon_spot.c @@ -0,0 +1,6 @@ +#define icon_spot_width 16 +#define icon_spot_height 16 +static unsigned char icon_spot_bits[] = { + 0x80, 0x01, 0x80, 0x01, 0xe0, 0x07, 0xb8, 0x1d, 0x88, 0x11, 0x8c, 0x31, + 0x04, 0x20, 0x3f, 0xfc, 0x3f, 0xfc, 0x04, 0x20, 0x8c, 0x31, 0x88, 0x11, + 0xb8, 0x1d, 0xe0, 0x07, 0x80, 0x01, 0x80, 0x01 }; diff --git a/icon_spot.xcf b/icon_spot.xcf index 0dfac7a..eb36329 100644 Binary files a/icon_spot.xcf and b/icon_spot.xcf differ diff --git a/icon_thirds.xcf b/icon_thirds.xcf new file mode 100644 index 0000000..a227bb4 Binary files /dev/null and b/icon_thirds.xcf differ diff --git a/icon_two_third.c b/icon_two_third.c new file mode 100644 index 0000000..15a6c19 --- /dev/null +++ b/icon_two_third.c @@ -0,0 +1,4 @@ +#define icon_two_third_width 5 +#define icon_two_third_height 12 +static unsigned char icon_two_third_bits[] = { + 0x06, 0x08, 0x0c, 0x02, 0x0e, 0x1f, 0x00, 0x06, 0x08, 0x06, 0x08, 0x06 }; diff --git a/lightmeter.ino b/lightmeter.ino index 9399f82..fa61272 100644 --- a/lightmeter.ino +++ b/lightmeter.ino @@ -12,6 +12,8 @@ #include #include // http://www.instructables.com/id/Monochrome-096-i2c-OLED-display-with-arduino-SSD13/ //128 x 64 px +#define WIDTH 128 +#define HEIGHT 64 #include //from: https://github.com/mysensors/MySensorsArduinoExamples/tree/master/libraries/BH1750 BH1750 lightMeter; @@ -27,6 +29,7 @@ BH1750 lightMeter; #define PIN_ON PB9 #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 INCIDENTDELAY 100 //minimum delay between incident sensor (BH1750) readings #define DEBOUNCETIME 50 //time to not check for inputs after key press @@ -60,6 +63,7 @@ long last_incidentReading=0; long millis_lastchange=0; long millis_lastinput=0; + long timebuttonpressed_trigger; long timebuttonpressed_left; long timebuttonpressed_center; @@ -111,7 +115,8 @@ uint16_t setISO=100; //set to ISO enum displaymode { lightmeter, - settings + settings, + meteringmodeselection }; displaymode displaymode=lightmeter; uint8_t settings_selectedItem=0; //in settings display @@ -124,56 +129,25 @@ boolean settings_itemActive=false; //item in settings selected to change value uint8_t meteringmode=METERINGMODE_REFLECTIVE; + + char tempstring[16]; //for dtostrf //dtostrf(modefactor,1,3,tempstring); #if (SSD1306_LCDHEIGHT != 64) #error("Height incorrect, please fix Adafruit_SSD1306.h!"); #endif -//Icon Spot -#define ICON_METERINGMODE_HEIGHT 16 -#define ICON_METERINGMODE_WIDTH 16 -static const unsigned char PROGMEM icon_spot[] = -{ B00000001, B10000000, - B00000001, B10000000, - B00000111, B11100000, - B00011101, B10111000, - B00010001, B10001000, - B00110001, B10001100, - B00100000, B00000100, - B11111100, B00111111, - B11111100, B00111111, - B00100000, B00000100, - B00110001, B10001100, - B00010001, B10001000, - B00011101, B10111000, - B00000111, B11100000, - B00000001, B10000000, - B00000001, B10000000 -}; +//Icons. Exported as .xbm from gimp and renamed to .c +#include "icon_incident.c" +#include "icon_spot.c" -static const unsigned char PROGMEM icon_incident[] = -{ B10000010, B00000000, - B10000100, B00011000, - B11100000, B01100000, - B10111001, B10000000, - B10001100, B00000110, - B10000100, B00111000, - B10000110, B11000000, - B10000010, B00000000, - B10000010, B00000000, - B10000110, B11000000, - B10000100, B00111000, - B10001100, B00000110, - B10111001, B10000000, - B11100000, B01100000, - B10000100, B00011000, - B10000010, B00000000 -}; +#include "icon_arrow.c" +#include "icon_one_third.c" +#include "icon_one_half.c" +#include "icon_two_third.c" - -void setup() { +void setup() { Serial.begin(9600); Serial.println("Started"); @@ -215,8 +189,9 @@ void loop() { handleInputs(); + - calculateEV(); + calculateFromEV(); updateDisplay(); @@ -381,6 +356,9 @@ void handleInputs() case settings: handleInputs_Settings(); break; + case meteringmodeselection: + handleInputs_Meteringmodeselection(); + break; } @@ -390,7 +368,7 @@ void handleInputs() } if ( button_trigger || button_left || button_center || button_right ) { - millis_lastchange=millis(); //for auto poweroff + millis_lastchange=millis(); //for auto poweroff and auto closes millis_lastinput=millis(); //for debouncing } @@ -398,16 +376,14 @@ void handleInputs() void handleInputs_Lightmeter() { + if ( button_center ) { //open meteringmode selection + displaymode=meteringmodeselection; + } + if ( button_hold_center ) { //Go to Settings displaymode=settings; } - if ( button_center ) { //Change Refelctive - Incident - if (meteringmode == METERINGMODE_REFLECTIVE){ - meteringmode = METERINGMODE_INCIDENT; - }else if (meteringmode == METERINGMODE_INCIDENT) { - meteringmode = METERINGMODE_REFLECTIVE; - } - } + if (setShutter==0 && setAperature==0){ //Auto //Value Change @@ -462,6 +438,10 @@ void handleInputs_Lightmeter() } } + if (button_trigger) { //Trigger + ev=getEV(); //set ev to current measurement by selected mode + } + } @@ -539,6 +519,26 @@ void handleInputs_Settings() } +void handleInputs_Meteringmodeselection() +{ + if ( button_center ) { //next or back to main screen + displaymode=lightmeter; + } + + if ( button_left ){ + meteringmode = METERINGMODE_REFLECTIVE; + displaymode=lightmeter; // and close + } + if ( button_right ) { + meteringmode = METERINGMODE_INCIDENT; + displaymode=lightmeter; // and close + } + + if (millis()-millis_lastchange>TIME_METERINGMODESELECTION_CLOSE){ //Automatic close + displaymode=lightmeter; + } +} + float reciprocFloat(float p){ if (p<1){ return (1.0f/( (int)(p*1000000) ) )*1000000 ; @@ -547,25 +547,32 @@ float reciprocFloat(float p){ } } -void calculateEV() -{ - if (meteringmode == METERINGMODE_REFLECTIVE){ +float getEV(){ + float _ev=0; + if (meteringmode == METERINGMODE_REFLECTIVE){ //### SPOT //ev=map(analog_low,500, 3500 ,500, 1400)/100.0; //for testing 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; + _ev=highev; }else if(lowev<12.5){ - ev=lowev; + _ev=lowev; }else{ //mix of both float mix=min(1.0, max(0.0,(lowev-12.5)/(14-12.5))); //0 to 1, 0-> use only lowev, 1-> use only highev - ev=lowev*(1-mix)+highev*mix; + _ev=lowev*(1-mix)+highev*mix; } - }else if (meteringmode == METERINGMODE_INCIDENT){ - ev = luxToEv(incident); + }else if (meteringmode == METERINGMODE_INCIDENT){ //### INCIDENT + _ev = luxToEv(incident); } + return _ev; +} + +void calculateFromEV() +{ + + if (setAperature>0){ //Aperature Priority showAperature=setAperature; //use user set Aperature showShutter=calculateShutter(ev,setISO, setAperature); @@ -834,6 +841,9 @@ void updateDisplay() case settings: updateDisplay_Settings(); break; + case meteringmodeselection: + updateDisplay_Meteringmodeselection(); + break; } @@ -844,7 +854,7 @@ void updateDisplay_Lightmeter() //Lightmeter display { #define xpos_aperature 2 #define ypos_aperature 29 - #define xpos_shutter 60 + #define xpos_shutter 50 #define ypos_shutter 29 #define xpos_icon 112 //128-16 #define ypos_icon 29 @@ -904,17 +914,70 @@ void updateDisplay_Lightmeter() //Lightmeter display } //Shutter border if (setShutter>0){ //Shutter Priority Mode - display.drawRect(xpos_shutter-2, ypos_shutter-2, 40, 18, WHITE); + display.drawRect(xpos_shutter-2, ypos_shutter-2, 60, 18, WHITE); } if (meteringmode == METERINGMODE_REFLECTIVE){ - display.drawBitmap(xpos_icon, ypos_icon, icon_spot, ICON_METERINGMODE_HEIGHT, ICON_METERINGMODE_WIDTH, 1); + display.drawXBitmap(xpos_icon, ypos_icon, icon_spot_bits, icon_spot_width, icon_spot_height, WHITE); }else if (meteringmode == METERINGMODE_INCIDENT) { - display.drawBitmap(xpos_icon, ypos_icon, icon_incident, ICON_METERINGMODE_HEIGHT, ICON_METERINGMODE_WIDTH, 1); + display.drawXBitmap(xpos_icon, ypos_icon, icon_incident_bits, icon_incident_width,icon_incident_height, WHITE); } //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 + + #define FULLEVLINEDISTANCE 9 + #define THIRDEVLINEDISTANCE 3 + #define ypos_evtext 7 + #define ypos_icon_arrow 6 + + uint8_t xpos_arrow=(ev-_startev*1.0) *FULLEVLINEDISTANCE; + + display.setTextSize(1); + display.drawLine(THIRDEVLINEDISTANCE,0,THIRDEVLINEDISTANCE,0,WHITE); //first third line + display.drawLine(THIRDEVLINEDISTANCE+THIRDEVLINEDISTANCE,0,THIRDEVLINEDISTANCE+THIRDEVLINEDISTANCE,0,WHITE); //second third line + for (uint8_t _fullevline=1;_fullevline<=13;_fullevline++){ + uint8_t _current_evvalue = _fullevline+_startev; + uint8_t _xpos_center_evtext = _fullevline*FULLEVLINEDISTANCE; //center of current ev line x pos + display.drawLine(_xpos_center_evtext,0,_xpos_center_evtext,2,WHITE); + display.drawLine(_xpos_center_evtext+THIRDEVLINEDISTANCE,0,_xpos_center_evtext+THIRDEVLINEDISTANCE,0,WHITE); + display.drawLine(_xpos_center_evtext+THIRDEVLINEDISTANCE+THIRDEVLINEDISTANCE,0,_xpos_center_evtext+THIRDEVLINEDISTANCE+THIRDEVLINEDISTANCE,0,WHITE); + if (_fullevline%2==1){ //only every second + + uint8_t _evtextmove=2; //movement of left point of text to the left. Compensation for center position + if (_current_evvalue>9){ //text has two digits + _evtextmove=5; + } + if ( (xpos_arrow-7 > _xpos_center_evtext) || (xpos_arrow+7 < _xpos_center_evtext) ) { //drawn arrow not too close to ev text + display.setCursor(_xpos_center_evtext-_evtextmove,ypos_evtext); display.print(_current_evvalue); //EV Text + } + } + } + //Arrow at current ev + float _ev_decimals=ev-((int)ev); + display.drawXBitmap(xpos_arrow - icon_arrow_width/2.0, ypos_icon_arrow, icon_arrow_bits, icon_arrow_width, icon_arrow_height, WHITE); //arrow icon + uint8_t _xpos_current_evtext_move=5; //for text centering + if (_ev_decimals <= 0.1666 || _ev_decimals > 0.8333) { //without fraction displayed + _xpos_current_evtext_move=2; + } + display.setCursor(xpos_arrow-_xpos_current_evtext_move,ypos_icon_arrow+icon_arrow_height+2); //current ev text position + if (_ev_decimals > 0.8333 ){ + display.print((int)ev+1); //EV Value under arrow. Ceil + }else{ + display.print((int)ev); //EV Value under arrow + } + + if ( _ev_decimals > 0.1666 && _ev_decimals <= 0.4166) { + display.drawXBitmap(xpos_arrow , ypos_icon_arrow+icon_arrow_height-(icon_one_third_height-8)/2 +2, icon_one_third_bits, icon_one_third_width, icon_one_third_height, WHITE); //one third + }else if ( _ev_decimals > 0.4166 && _ev_decimals <= 0.5833) { + display.drawXBitmap(xpos_arrow , ypos_icon_arrow+icon_arrow_height-(icon_one_half_height-8)/2 +2, icon_one_half_bits, icon_one_half_width, icon_one_half_height, WHITE); //one half + }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); @@ -963,17 +1026,26 @@ void updateDisplay_Settings() display.setCursor(SETTINGS_XPOS_OFFSET,display.getCursorY()+SETTINGS_YPOS_INCREMENT); //move cursor to next entry } - - - /* - if (settings_selectedItem==1){ - if (settings_itemActive){ - display.drawRect(display.getCursorX()-2, display.getCursorY()-2, 126 , 11, WHITE); - }else{ - display.drawCircle(0, display.getCursorY()+4,2, display.getCursorY()+6); - } - } - display.print("TestTest");*/ - +} + +void updateDisplay_Meteringmodeselection() +{ + display.clearDisplay(); + display.setTextColor(WHITE); + #define xpos_center_icon_spot 30 + #define ypos_icon_spot 20 + #define xpos_center_icon_incident 97 + #define ypos_icon_incident 20 + + display.drawXBitmap(xpos_center_icon_spot-icon_spot_width/2, ypos_icon_spot, icon_spot_bits, icon_spot_width, icon_spot_height, WHITE); //Spot icon + display.drawRect(xpos_center_icon_spot-icon_spot_width/2-2, ypos_icon_spot-2, icon_spot_width+4,icon_spot_height+4,WHITE); + display.drawXBitmap(xpos_center_icon_incident-icon_incident_width/2, ypos_icon_incident, icon_incident_bits, icon_incident_width, icon_incident_height, WHITE); //incident icon + display.drawRect(xpos_center_icon_incident-icon_incident_width/2-2, ypos_icon_incident-2, icon_incident_width+4,icon_incident_height+4,WHITE); + + display.setTextSize(1); + display.setCursor(xpos_center_icon_spot-10,ypos_icon_spot+icon_spot_height +6); //text position upper left + 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"); }