@ -12,6 +12,8 @@
# include <Adafruit_GFX.h>
# include <Adafruit_SSD1306.h> // http://www.instructables.com/id/Monochrome-096-i2c-OLED-display-with-arduino-SSD13/
//128 x 64 px
# define WIDTH 128
# define HEIGHT 64
# include <BH1750.h> //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 ( ) ;
calculate EV( ) ;
calculate From EV( ) ;
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 6 0
# define xpos_shutter 5 0
# 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 , 4 0, 18 , WHITE ) ;
display . drawRect ( xpos_shutter - 2 , ypos_shutter - 2 , 6 0, 18 , WHITE ) ;
}
if ( meteringmode = = METERINGMODE_REFLECTIVE ) {
display . draw Bitmap( xpos_icon , ypos_icon , icon_spot , ICON_METERINGMODE_HEIGHT , ICON_METERINGMODE_WIDTH , 1 ) ;
display . draw X Bitmap( xpos_icon , ypos_icon , icon_spot _bits, icon_spot_width , icon_spot_height , WHITE ) ;
} else if ( meteringmode = = METERINGMODE_INCIDENT ) {
display . draw Bitmap( xpos_icon , ypos_icon , icon_incident , ICON_METERINGMODE_HEIGHT , ICON_METERINGMODE_WIDTH , 1 ) ;
display . draw X Bitmap( 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
}
}
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
/*
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 " ) ; */
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 " ) ;
}