You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1678 lines
58 KiB
1678 lines
58 KiB
//STM32F103C, 64k flash |
|
//upload method: serial (A9 to RX, A10 to TX) |
|
//To upload set Boot0 jumper to 1 (the one further away from reset btn) and press reset (stm will boot from flash wich contains uart to flash uploader) |
|
//upload via arduino IDE |
|
//To boot program after restart set Boot0 jumper to 0 |
|
|
|
//Letters 5x7 at Size 1 |
|
|
|
#include <math.h> |
|
//#include <SPI.h> |
|
#include <Wire.h> |
|
#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 <EEPROM.h> |
|
|
|
#include <BH1750.h> //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 //pin for hardware latch |
|
#define TIME_AUTOPOWEROFF 120000 |
|
#define TIME_METERINGMODESELECTION_CLOSE 60000 |
|
#define TIME_METERINGMODESELECTION_SHUTDOWN_SHORTCUT 500 |
|
#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 BUTTONTIMEHOLDLONG 3000 //time for button long hold |
|
|
|
#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}; |
|
#define SHUTTERTIMES1_MAXINDEX 19 |
|
float shuttertimes2[]={30,25,20,15,13,10,8,6,5,4,3.2,2.5,2,1.6,1.3,1,0.8,0.6,0.5,0.4,0.3,1.0/4,1.0/5,1.0/6,1.0/8,1.0/10,1.0/13,1.0/15,1.0/20,1.0/25,1.0/30,1.0/40,1.0/50,1.0/60,1.0/80,1.0/100,1.0/125,1.0/160,1.0/200,1.0/250,1.0/320,1.0/400,1.0/500,1.0/640,1.0/800,1.0/1000,1.0/1250,1.0/1600,1.0/2000,1.0/2500,1.0/3200,1.0/4000}; |
|
#define SHUTTERTIMES2_MAXINDEX 51 |
|
float shuttertimes3[]={3600,2400,1800,1200,900,600,420,300,210,150,100,60,45,30,20,16,10,8,6,4,3,2,1.5,1,0.5,0.25,0.125,1.0/16}; |
|
#define SHUTTERTIMES3_MAXINDEX 27 |
|
String settingsnameShutterSelectionMode[]={"Analog","Digital","Pinhole"}; //names for tables |
|
#define MAXIMUM_SHUTTERSELECTIONMODES 3 |
|
|
|
//Aperature numbers https://en.wikipedia.org/wiki/F-number |
|
float aperaturesFull[]={1,1.4, 2, 2.8, 4, 5.6, 8, 11, 16, 22, 32,45}; |
|
#define APERATURESFULL_MAXINDEX 11 |
|
float aperaturesHalf[]={1, 1.2, 1.4, 1.7, 2, 2.4, 2.8, 3.4, 4, 4.8, 5.6, 6.7, 8, 9.5, 11, 13, 16, 19, 22, 27 ,32, 38, 45}; |
|
#define APERATURESHALF_MAXINDEX 22 |
|
float aperaturesThird[]={1, 1.1, 1.2, 1.4, 1.6, 1.8, 2, 2.2, 2.5, 2.8, 3.2, 3.5, 4, 4.5, 5.0, 5.6, 6.3, 7.1, 8, 9, 10, 11, 13, 14, 16, 18, 20, 22, 25, 29, 32, 36, 40, 45}; |
|
#define APERATURESTHIRD_MAXINDEX 33 |
|
String settingsnameAperatureSelectionMode[]={"Full","Half","Third"}; //names for tables |
|
#define MAXIMUM_APERATURESELECTIONMODES 3 |
|
|
|
float isoFull[]={0.78,1.56,3.13,6.25,12.5,25,50,100,200,400,800,1600,3200,6400,12500,25600}; |
|
uint8_t isoFullDIN[]={0,3, 6, 9, 12, 15,18,21 ,24 ,27 ,30 ,33 ,36 ,39 ,42 ,45}; |
|
float isoThird[]={0.78,0.98,1.24,1.56,1.97,2.48,3.13,3.93,4.96,6.25,7.87,9.92,12.5,16,20,25,32,40,50,64,80,100,125,160,200,250,320,400,500,640,800,1000,1250,1600,2000,2500,3200,4000,5000,6400,8000,10000,12500,16000,20000,25600}; |
|
uint8_t isoThirdDIN[]={0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20, 21, 22 ,23 ,24 ,25 ,26 ,27 ,28 ,29 ,30 ,31 ,32 ,33 ,34 ,35 ,36 ,37 ,38 ,39 ,40 ,41 ,42 ,43 ,44 ,56}; |
|
|
|
|
|
|
|
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; |
|
long timebuttonpressed_left; |
|
long timebuttonpressed_center; |
|
long timebuttonpressed_right; |
|
|
|
//Short press (true when button short pressed, on release) |
|
boolean button_trigger=false; |
|
boolean button_left=false; |
|
boolean button_center=false; |
|
boolean button_right=false; |
|
|
|
//long press (true when button is held down for BUTTONTIMEHOLD, on time elapsed) |
|
boolean button_hold_trigger=false; |
|
boolean button_hold_left=false; |
|
boolean button_hold_center=false; |
|
boolean button_hold_right=false; |
|
|
|
//even longer press |
|
boolean button_hold_long_trigger=false; |
|
long timebuttonpressed_trigger_long=0; |
|
|
|
float vbat=100; |
|
|
|
struct Settings { |
|
uint8_t minimumAperatureIndex; //see corresponding aperatures table |
|
uint8_t aperatureSelectionMode; //1=Full, 2=Half, 3=Third |
|
uint8_t shutterSelectionMode; //index for which shuttertimes table to use |
|
uint8_t ISOSelectionMode; //1=Full, 2=Thirds |
|
uint8_t manualev_moveamount_frac; // 1=1ev, 2=1/2ev, 3=1/3 ev |
|
}; |
|
#define MAXIMUM_MANUAL_EV_MOVEAMOUNT_FRAC 3 |
|
|
|
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,1}; |
|
Settings eeprom_userSettings; //to store current eeprom status |
|
|
|
|
|
|
|
|
|
#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=-255,ev_max=-255,ev_last=-255; |
|
|
|
float showAperature=0; |
|
float showShutter=0; |
|
bool manualev_mode=false; //manual ev change by left/right |
|
|
|
//Usersettings |
|
float setAperature=8; //set to use aperature. 0 for auto |
|
float setShutter=0; //set to use shutter time, 0 for auto |
|
float 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 |
|
float eeprom_setISO=0; //set to ISO |
|
|
|
#define EEPROMADDRESS_APERATURE 0x801F000 //float = 32bit = 4byte |
|
#define EEPROMADDRESS_SHUTTER 0x801F004 //float = 32bit = 4byte |
|
#define EEPROMADDRESS_ISO 0x801F008 //float 32bit = 4byte |
|
#define EEPROMADDRESS_METERINGMODE 0x801F00C //uint8_t 1byte |
|
#define EEPROMADDRESS_USERSETTINGS 0x801F00D //Settings struct |
|
|
|
enum displaymode { |
|
lightmeter, |
|
settings, |
|
meteringmodeselection |
|
}; |
|
displaymode displaymode=lightmeter; |
|
uint8_t settings_selectedItem=0; //in settings display |
|
String settingStrings[]={"ISO:","F-Stops:","Timetable:","EV Step:","Turn Off"}; |
|
#define SETTINGS_SELECTEDITEM_MAX 4 //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); |
|
|
|
#if (SSD1306_LCDHEIGHT != 64) |
|
#error("Height incorrect, please fix Adafruit_SSD1306.h!"); |
|
#endif |
|
|
|
//Icons. Exported as .xbm from gimp and renamed to .c |
|
#include "icon_incident.c" |
|
#include "icon_spot.c" |
|
|
|
#include "icon_arrow.c" |
|
#include "icon_one_third.c" |
|
#include "icon_one_half.c" |
|
#include "icon_two_third.c" |
|
|
|
|
|
void setup() { |
|
Serial.begin(115200); |
|
Serial.println("Started"); |
|
|
|
Serial.println("Init Display"); |
|
display.begin(SSD1306_SWITCHCAPVCC, 0x3C); |
|
display.clearDisplay(); |
|
display.display(); |
|
|
|
Serial.println("Init BH1750"); |
|
lightMeter.begin(BH1750_CONTINUOUS_HIGH_RES_MODE_2); //max reading=54612 |
|
//set measurement time (for higher resolution) http://www.raspberry-pi-geek.de/Magazin/2015/04/Digital-Light-Sensor-BH1750-am-Raspberry-Pi |
|
//lightMeter.write8(71); //01000111 //high bit: 01000xxx bits 7,6,5 |
|
//lightMeter.write8(126); //01111110 //log bit: 011xxxxx bits 4,3,2,1,0 |
|
|
|
pinMode(PIN_LDR, INPUT_ANALOG); |
|
pinMode(PIN_VBAT, INPUT_ANALOG); |
|
pinMode(PIN_TRIGGER, INPUT_PULLUP); |
|
pinMode(PIN_BTNLEFT, INPUT_PULLUP); |
|
pinMode(PIN_BTNCENTER, INPUT_PULLUP); |
|
pinMode(PIN_BTNRIGHT, INPUT_PULLUP); |
|
pinMode(PIN_BRIGHTMODE, OUTPUT); |
|
digitalWrite(PIN_BRIGHTMODE, LOW); |
|
pinMode(PIN_ON, OUTPUT); |
|
digitalWrite(PIN_ON, HIGH); |
|
pinMode(PIN_LED, OUTPUT); |
|
analogWrite(PIN_LED,255); //blink led on |
|
delay(50); |
|
analogWrite(PIN_LED,0); //LED OFF //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; |
|
} |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
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 |
|
analogWrite(PIN_LED,255); |
|
delay(1000); //1s led on confirmation |
|
analogWrite(PIN_LED,0); //LED OFF |
|
saveSettingsToEEPROM(true); //force writing. userSettings contains the default values at this point |
|
delay(200); |
|
analogWrite(PIN_LED,255); |
|
delay(200); //1s led on confirmation |
|
analogWrite(PIN_LED,0); //LED OFF |
|
delay(200); |
|
analogWrite(PIN_LED,255); |
|
delay(200); //1s led on confirmation |
|
analogWrite(PIN_LED,0); //LED OFF |
|
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); |
|
analogWrite(PIN_LED,255); |
|
delay(50); //1s led on confirmation |
|
analogWrite(PIN_LED,0); |
|
} |
|
}else{ // |
|
//apply |
|
setAperature=eeprom_setAperature; |
|
setShutter=eeprom_setShutter; |
|
setISO=eeprom_setISO; |
|
meteringmode=eeprom_meteringmode; |
|
userSettings=eeprom_userSettings; |
|
} |
|
|
|
} |
|
|
|
|
|
|
|
void handleInputs() |
|
{ |
|
//Short press (true when button short pressed, on release) |
|
button_trigger=false; |
|
button_left=false; |
|
button_center=false; |
|
button_right=false; |
|
|
|
//long press (true when button is held down for BUTTONTIMEHOLD, on time elapsed) |
|
button_hold_trigger=false; |
|
button_hold_left=false; |
|
button_hold_center=false; |
|
button_hold_right=false; |
|
|
|
//even longer press |
|
button_hold_long_trigger=false; |
|
|
|
|
|
if (millis()-millis_lastinput>DEBOUNCETIME) //Button debouncing |
|
{ |
|
//Trigger |
|
if (timebuttonpressed_trigger == 0 && !digitalRead(PIN_TRIGGER)){ //first time pressed down. (low when pressed) |
|
timebuttonpressed_trigger=loopmillis; //set time of button press |
|
timebuttonpressed_trigger_long=loopmillis; //set time of button press, for long hold timing |
|
millis_lastinput=millis(); //for debouncing |
|
}else if(timebuttonpressed_trigger != 0 && digitalRead(PIN_TRIGGER)){ //button released (was pressed) |
|
if (loopmillis-timebuttonpressed_trigger < BUTTONTIMEHOLD){ //short press |
|
button_trigger=true; |
|
} |
|
timebuttonpressed_trigger=0; //re-enable after short press and release from hold |
|
millis_lastinput=millis(); //for debouncing |
|
}else if(loopmillis-timebuttonpressed_trigger >= BUTTONTIMEHOLD && timebuttonpressed_trigger>0){ //held down long enough and not already hold triggered |
|
button_hold_trigger=true; |
|
timebuttonpressed_trigger=-1; //-1 as flag for hold triggered |
|
} |
|
|
|
if (timebuttonpressed_trigger_long>0 && loopmillis-timebuttonpressed_trigger_long >= BUTTONTIMEHOLDLONG && !digitalRead(PIN_TRIGGER)) { //button held down even longer, set hold long flag for as long as button is down |
|
button_hold_long_trigger=true; |
|
}else if(timebuttonpressed_trigger_long>0 && digitalRead(PIN_TRIGGER)){ //released |
|
timebuttonpressed_trigger_long=0; //reset long hold timing |
|
} |
|
|
|
//Left |
|
if (timebuttonpressed_left == 0 && !digitalRead(PIN_BTNLEFT)){ //first time pressed down. (low when pressed) |
|
timebuttonpressed_left=loopmillis; //set time of button press |
|
millis_lastinput=millis(); //for debouncing |
|
}else if(timebuttonpressed_left != 0 && digitalRead(PIN_BTNLEFT)){ //button released (was pressed) |
|
if (loopmillis-timebuttonpressed_left < BUTTONTIMEHOLD){ //short press |
|
button_left=true; |
|
} |
|
timebuttonpressed_left=0; //re-enable after short press and release from hold |
|
millis_lastinput=millis(); //for debouncing |
|
}else if(loopmillis-timebuttonpressed_left >= BUTTONTIMEHOLD && timebuttonpressed_left>0){ //held down long enough and not already hold triggered |
|
button_hold_left=true; |
|
timebuttonpressed_left=-1; //-1 as flag for hold triggered |
|
} |
|
|
|
//Center |
|
if (timebuttonpressed_center == 0 && !digitalRead(PIN_BTNCENTER)){ //first time pressed down. (low when pressed) |
|
timebuttonpressed_center=loopmillis; //set time of button press |
|
millis_lastinput=millis(); //for debouncing |
|
}else if(timebuttonpressed_center != 0 && digitalRead(PIN_BTNCENTER)){ //button released (was pressed) |
|
if (loopmillis-timebuttonpressed_center < BUTTONTIMEHOLD){ //short press |
|
button_center=true; |
|
} |
|
timebuttonpressed_center=0; //re-enable after short press and release from hold |
|
millis_lastinput=millis(); //for debouncing |
|
}else if(loopmillis-timebuttonpressed_center >= BUTTONTIMEHOLD && timebuttonpressed_center>0){ //held down long enough and not already hold triggered |
|
button_hold_center=true; |
|
timebuttonpressed_center=-1; //-1 as flag for hold triggered |
|
} |
|
|
|
//Right |
|
if (timebuttonpressed_right == 0 && !digitalRead(PIN_BTNRIGHT)){ //first time pressed down. (low when pressed) |
|
timebuttonpressed_right=loopmillis; //set time of button press |
|
millis_lastinput=millis(); //for debouncing |
|
}else if(timebuttonpressed_right != 0 && digitalRead(PIN_BTNRIGHT)){ //button released (was pressed) |
|
if (loopmillis-timebuttonpressed_right < BUTTONTIMEHOLD){ //short press |
|
button_right=true; |
|
} |
|
timebuttonpressed_right=0; //re-enable after short press and release from hold |
|
millis_lastinput=millis(); //for debouncing |
|
}else if(loopmillis-timebuttonpressed_right >= BUTTONTIMEHOLD && timebuttonpressed_right>0){ //held down long enough and not already hold triggered |
|
button_hold_right=true; |
|
timebuttonpressed_right=-1; //-1 as flag for hold triggered |
|
} |
|
} |
|
|
|
/* |
|
if (button_trigger || button_left || button_center || button_right){ |
|
Serial.println("Buttons short:"); |
|
Serial.print(button_trigger); |
|
Serial.print(button_left); |
|
Serial.print(button_center); |
|
Serial.println(button_right); |
|
} |
|
if (button_hold_trigger || button_hold_left || button_hold_center || button_hold_right){ |
|
Serial.println("Buttons long:"); |
|
Serial.print(button_hold_trigger); |
|
Serial.print(button_hold_left); |
|
Serial.print(button_hold_center); |
|
Serial.println(button_hold_right); |
|
} |
|
*/ |
|
|
|
//Voltage |
|
float _vbat=map(analogRead(PIN_VBAT), 0,3560,0,8200)/1000.0; //180k and 300k voltage divider. 8,4V -> 3,15V=3910 |
|
if (_vbat<vbat){ |
|
vbat=_vbat; //voltage can only decrease |
|
} |
|
|
|
//LDR |
|
|
|
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=analog_reading_filtering/analog_reading_count; |
|
}else{ |
|
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; |
|
} |
|
|
|
|
|
|
|
//Lightsensor BH1750 |
|
if ( loopmillis-last_incidentReading>INCIDENTDELAY ) |
|
{ |
|
incident = lightMeter.readLightLevel(); //value in lux from sensor |
|
last_incidentReading=loopmillis; |
|
} |
|
|
|
|
|
|
|
//Test asdf |
|
/* |
|
if ( !digitalRead(PIN_TRIGGER) ) { |
|
Serial.println("roundAperature"); |
|
for (float i=0.1;i<30;i+=0.5){ |
|
Serial.print(i); |
|
Serial.print(" -> "); |
|
Serial.println(roundAperature(i,1)); |
|
} |
|
Serial.println("roundShutter"); |
|
for (float i=1.0/8000;i<32;i*=2){ |
|
Serial.print(i,6); |
|
Serial.print(" -> "); |
|
Serial.print(roundShutter(i,2),6); |
|
Serial.print(" -- "); |
|
Serial.println(reciprocFloat(roundShutter(i,2))); |
|
} |
|
} |
|
|
|
|
|
|
|
Serial.println("calculateShutter at iso 100 f2.8"); |
|
for (float i=-2;i<18;i+=0.25){ |
|
Serial.print(i); |
|
Serial.print(" -> "); |
|
float test_calcshutter=calculateShutter(i, (uint16_t)100, 2.8); |
|
//Serial.println(test_calcshutter,6); |
|
|
|
float test_showShutter=roundShutter(test_calcshutter,2); |
|
Serial.print("rounded Shutter from "); Serial.print(test_calcshutter,6); Serial.print(" to "); Serial.println(test_showShutter,6); //asdf |
|
if (test_showShutter>0.25) //check shuttertime |
|
{ //show full seconds |
|
Serial.print("int="); |
|
Serial.print(int(test_showShutter)); |
|
if (test_showShutter-int(test_showShutter)>0){ //has decimals |
|
Serial.print(" ,"); |
|
Serial.print((int)round( (test_showShutter-int(test_showShutter))*10)); //show one decimal |
|
} |
|
Serial.println(""); |
|
}else{ //show fraction of a second |
|
Serial.print("frac= 1/"); |
|
int _frac_showShutter = (int) ( (1.0f/( (int)(test_showShutter*1000000) ) )*1000000 ); |
|
Serial.print( _frac_showShutter ); |
|
Serial.println(""); |
|
} |
|
} |
|
|
|
Serial.println("calculateAperature at iso 100 1/250s"); |
|
for (float i=-2;i<18;i+=0.25){ |
|
Serial.print(i); |
|
Serial.print(" -> "); |
|
Serial.println(calculateAperature(i, (uint16_t)100, 1.0/250),6); |
|
} |
|
|
|
}*/ |
|
|
|
|
|
|
|
switch(displaymode){ |
|
case lightmeter: |
|
handleInputs_Lightmeter(); |
|
break; |
|
case settings: |
|
handleInputs_Settings(); |
|
break; |
|
case meteringmodeselection: |
|
handleInputs_Meteringmodeselection(); |
|
break; |
|
} |
|
|
|
|
|
|
|
if (millis()-millis_lastchange>TIME_AUTOPOWEROFF){ |
|
poweroff(); |
|
} |
|
|
|
if ( button_trigger || button_left || button_center || button_right ) { |
|
millis_lastchange=millis(); //for auto poweroff and auto closes |
|
millis_lastinput=millis(); //for debouncing |
|
} |
|
|
|
} |
|
|
|
void poweroff(){ |
|
bool _eepromwritten=saveSettingsToEEPROM(false); //save only changes to eeprom |
|
analogWrite(PIN_LED,255); //Blink led |
|
delay(100); |
|
analogWrite(PIN_LED,0); |
|
if (_eepromwritten){ |
|
delay(100); |
|
analogWrite(PIN_LED,255); |
|
delay(100); |
|
analogWrite(PIN_LED,0); |
|
} |
|
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 |
|
displaymode=settings; |
|
} |
|
|
|
|
|
if (manualev_mode){ //Manual Ev |
|
//Value Change |
|
if ( button_left ) { |
|
ev-=1.0/userSettings.manualev_moveamount_frac; |
|
} |
|
if ( button_right ) { |
|
ev+=1.0/userSettings.manualev_moveamount_frac; |
|
} |
|
//Change Mode |
|
if ( button_hold_left ){ // Manual Ev -> Av |
|
setAperature=showAperature; |
|
setShutter=0; |
|
manualev_mode=false; |
|
} |
|
if ( button_hold_right ){ // Manual Ev -> T |
|
setShutter=showShutter; |
|
setAperature=0; |
|
manualev_mode=false; |
|
} |
|
}else if(setShutter==0){ //Aperature Priority |
|
manualev_mode=false; |
|
//Value Change |
|
if ( button_left ) { |
|
changeAperature(1); //Decrement Aperature |
|
} |
|
if ( button_right ) { |
|
changeAperature(-1); //Increment Aperature |
|
} |
|
//Change Mode |
|
if ( button_hold_left ){ //Av -> Manual Ev |
|
manualev_mode=true; |
|
} |
|
if ( button_hold_right ){ //Av -> T |
|
setShutter=showShutter; |
|
setAperature=0; |
|
} |
|
}else if (setAperature==0){ //Shutter Priority |
|
manualev_mode=false; |
|
//Value Change |
|
if ( button_left ) { |
|
changeShutter(1); //Decrement Aperature |
|
} |
|
if ( button_right ) { |
|
changeShutter(-1); //Increment Aperature |
|
} |
|
//Change Mode |
|
if ( button_hold_left ){ //T -> Av |
|
setAperature=showAperature; |
|
setShutter=0; |
|
} |
|
if ( button_hold_right ){ //T -> Manual Ev |
|
manualev_mode=true; |
|
} |
|
} |
|
|
|
if (button_trigger || button_hold_long_trigger) { //Trigger or very long hold |
|
ev_last=ev; |
|
ev=getEV(); //set ev to current measurement by selected mode |
|
if (ev<ev_min || ev_min<-254){ //new ev is smaller than last or ev_min wasn set |
|
ev_min=ev; |
|
} |
|
if(ev>ev_max){ //new ev is greater |
|
ev_max=ev; |
|
} |
|
debug_analog_high=analog_high; |
|
debug_analog_low=analog_low; |
|
//LED Brightness on trigger |
|
uint8_t triggerblinkbrightness=255; |
|
if (ev<4){ //dim led when dark |
|
triggerblinkbrightness=map(ev,2,4,5,255); |
|
} |
|
if (ev<2){ |
|
triggerblinkbrightness=5; |
|
} |
|
if (button_hold_long_trigger){ //low brightness on long hold |
|
triggerblinkbrightness=5; |
|
} |
|
blinkLED(20,triggerblinkbrightness); |
|
} |
|
|
|
if (button_hold_trigger) { //Trigger hold, resets ev_min,max and last |
|
ev_min=-255; //placeholder for "not set" |
|
ev_max=-255; |
|
ev_last=-255; |
|
//LED Brightness on trigger |
|
uint8_t triggerblinkbrightness=255; |
|
if (ev<4){ //dim led when dark |
|
triggerblinkbrightness=map(ev,4,0,255,50); |
|
} |
|
blinkLED(400,triggerblinkbrightness); |
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
void handleInputs_Settings() |
|
{ |
|
if ( button_hold_center ) { //Go to Lightmeter |
|
settings_itemActive=false; //deselect item |
|
displaymode=lightmeter; |
|
} |
|
|
|
|
|
|
|
if (!settings_itemActive){ //select items |
|
if ( button_left ) { |
|
if (settings_selectedItem>0){ //not first item |
|
settings_selectedItem-=1; |
|
} |
|
} |
|
if ( button_right ) { |
|
if (settings_selectedItem<SETTINGS_SELECTEDITEM_MAX){ //not last item |
|
settings_selectedItem+=1; |
|
} |
|
} |
|
if ( button_center ){ |
|
settings_itemActive=true; //select item to change value |
|
} |
|
|
|
}else{ //item selected to change value |
|
|
|
switch (settings_selectedItem) |
|
{ |
|
case 0: //ISO |
|
if ( button_left ) { |
|
changeISO(-1); |
|
} |
|
if ( button_right ) { |
|
changeISO(1); |
|
} |
|
break; |
|
|
|
case 1: //Aperature Selection Mode |
|
if ( button_left ) { |
|
if(userSettings.aperatureSelectionMode>1){ |
|
userSettings.aperatureSelectionMode-=1; |
|
} |
|
} |
|
if ( button_right ) { |
|
if (userSettings.aperatureSelectionMode<MAXIMUM_APERATURESELECTIONMODES){ |
|
userSettings.aperatureSelectionMode+=1; |
|
} |
|
} |
|
break; |
|
|
|
case 2: //Shutter Selection Mode |
|
if ( button_left ) { |
|
if(userSettings.shutterSelectionMode>1){ |
|
userSettings.shutterSelectionMode-=1; |
|
} |
|
} |
|
if ( button_right ) { |
|
if (userSettings.shutterSelectionMode<MAXIMUM_SHUTTERSELECTIONMODES){ |
|
userSettings.shutterSelectionMode+=1; |
|
} |
|
} |
|
break; |
|
|
|
case 3: //manual ev moveamount |
|
if ( button_left ) { |
|
if(userSettings.manualev_moveamount_frac>1){ |
|
userSettings.manualev_moveamount_frac-=1; |
|
} |
|
} |
|
if ( button_right ) { |
|
if (userSettings.manualev_moveamount_frac<MAXIMUM_MANUAL_EV_MOVEAMOUNT_FRAC){ |
|
userSettings.manualev_moveamount_frac+=1; |
|
} |
|
} |
|
break; |
|
|
|
case 4: //Turn Off |
|
poweroff(); |
|
break; |
|
} |
|
if ( button_center ){ |
|
settings_itemActive=false; //return to item selection |
|
} |
|
} |
|
|
|
} |
|
|
|
void handleInputs_Meteringmodeselection() |
|
{ |
|
if ( button_center ) { //next or back to main screen |
|
if (millis()-millis_lastchange<TIME_METERINGMODESELECTION_SHUTDOWN_SHORTCUT) { //double press select (center) to poweroff |
|
poweroff(); //Turn off |
|
} |
|
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 ; |
|
}else{ |
|
return (1/p); |
|
} |
|
} |
|
|
|
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); |
|
|
|
//calibration 20180413 |
|
//polynomial only |
|
//double highev=4.76455098 + 0.00961533698*analog_high - 0.00000399325586*pow(analog_high,2) + 0.000000000654378697 *pow(analog_high,3); |
|
//double lowev=-38.9534785 + 0.310426970*analog_low - 0.000769939297*pow(analog_low,2) + 0.000000639458491*pow(analog_low,3); |
|
|
|
|
|
double log_low=log(analog_low); |
|
//[-2.47999992e+02 5.59942657e+03 -4.74076773e+04 1.78389539e+05 -2.51728845e+05] |
|
double lowev=-251728.845 + 178389.539*log_low - 47407.6773*pow(log_low,2) + 5599.42657*pow(log_low,3) - 247.999992*pow(log_low,4); |
|
|
|
double log_high=log(analog_high); |
|
//[7.27310051e-02 -2.02919373e+00 2.23823220e+01 -1.22121768e+02 3.32574527e+02 -3.60445720e+02] |
|
double highev=-360.445720 + 332.574527*log_high - 122.121768*pow(log_high,2) + 22.3823220*pow(log_high,3) - 2.02919373*pow(log_high,4) + 0.0727310051*pow(log_high,5); |
|
|
|
/*Serial.print("analog_low="); //asdf |
|
Serial.print(analog_low); |
|
Serial.print(" log_low="); |
|
Serial.print(log_low); |
|
Serial.print(" lowev="); |
|
Serial.println(lowev); |
|
|
|
Serial.print("analog_high="); |
|
Serial.print(analog_high); |
|
Serial.print(" log_high="); |
|
Serial.print(log_high); |
|
Serial.print(" highev="); |
|
Serial.println(highev);*/ |
|
|
|
|
|
|
|
if (highev>2){ |
|
_ev=highev; |
|
Serial.println("using high ev"); |
|
}else if(lowev<1){ |
|
_ev=lowev; |
|
Serial.println("using low ev"); |
|
}else{ //mix of both |
|
float mix=min(1.0, max(0.0,(lowev-1)/(2-1))); //0 to 1, 0-> use only lowev, 1-> use only highev |
|
_ev=lowev*(1-mix)+highev*mix; |
|
Serial.print("mixing mix="); |
|
Serial.println(mix); |
|
} |
|
Serial.print("EV="); |
|
Serial.println(_ev); |
|
}else if (meteringmode == METERINGMODE_INCIDENT){ //### INCIDENT |
|
_ev = luxToEv(incident*INCIDENT_CORRECTION_FACTOR); |
|
} |
|
|
|
return _ev; |
|
} |
|
|
|
void calculateFromEV() |
|
{ |
|
if (setAperature>0){ //Aperature Priority |
|
showAperature=setAperature; //use user set Aperature |
|
showShutter=calculateShutter(ev,setISO, setAperature); |
|
}else if(setShutter>0){ //Shutter Priority |
|
showShutter=setShutter; //use user set Shutter |
|
showAperature=calculateAperature(ev, setISO, setShutter); |
|
} |
|
} |
|
|
|
double evToLux(double ev) { |
|
return pow(2, ev) * 2.5; |
|
} |
|
double luxToEv(uint16_t lux){ |
|
if (lux <= 2){ |
|
return 0; |
|
} |
|
return log (lux/2.5) / log (2); |
|
} |
|
|
|
float calculateShutter(float pEv, uint16_t pIso, float pAperature) //returns calculated Shutter speed given Ev, ISO and Aperature |
|
{ |
|
//EV = log2 ( 100* Aperature^2 / (ISO * Time )) |
|
//100* Aperature^2 / (2^EV * ISO) = Time |
|
return (100.0 * pow( pAperature,2) ) / (pow(2,pEv)*pIso); |
|
} |
|
float calculateAperature(float pEv, uint16_t pIso, float pShutter) //returns mathematical aperature in x1 |
|
{ |
|
//EV = log2 ( 100* Aperature^2 / (ISO * Time )) |
|
// sqrt( 2^EV *(ISO * Time ) /100 ) = Aperature |
|
return sqrt( pow(2,pEv) * pIso * pShutter / 100.0 ) ; |
|
} |
|
float roundShutter(float pShutter, uint8_t pMethod) //round shutter to typical values |
|
{ |
|
uint8_t _index=findShutterIndex(pShutter,pMethod); |
|
|
|
//use closest shutter value |
|
switch(pMethod){ |
|
case 1: // |
|
return shuttertimes1[_index]; |
|
break; |
|
case 2: // |
|
return shuttertimes2[_index]; |
|
break; |
|
case 3: // |
|
return shuttertimes3[_index]; |
|
break; |
|
} |
|
} |
|
|
|
float roundAperature(float pAperature, uint8_t pMethod) //round Aperature (x1) to typical values. method=0 -> leave, 1=full stops, 2=half stops, 3=third stops |
|
{ |
|
if (pMethod==0){ |
|
return pAperature; |
|
} |
|
|
|
uint8_t closest_index=findAperatureIndex(pAperature,pMethod); |
|
|
|
//use closest aperature value |
|
switch(pMethod){ |
|
case 1: //full stops |
|
return aperaturesFull[closest_index]; |
|
break; |
|
case 2: //half stops |
|
//return float ( pow(sqrt(sqrt(2)), _index-2) ); |
|
return aperaturesHalf[closest_index]; |
|
break; |
|
case 3: //third stops |
|
return aperaturesThird[closest_index]; |
|
//return float ( pow(cbrt(sqrt(2)), _index-2) ); |
|
break; |
|
} |
|
} |
|
|
|
void changeAperature(int8_t pchange){ //pchange>0 means more light exposure (brighter image) |
|
uint8_t _newAperatureIndex=findAperatureIndex(setAperature,userSettings.aperatureSelectionMode); |
|
|
|
uint8_t _maximumAperatureIndex=0; |
|
switch(userSettings.aperatureSelectionMode){ //check max |
|
case 1: //full stops |
|
_maximumAperatureIndex=sizeof(aperaturesFull)/sizeof(float); |
|
break; |
|
case 2: //half stops |
|
_maximumAperatureIndex=sizeof(aperaturesHalf)/sizeof(float); |
|
break; |
|
case 3: //third stops |
|
_maximumAperatureIndex=sizeof(aperaturesThird)/sizeof(float); |
|
break; |
|
} |
|
_newAperatureIndex-=pchange; //change aperature |
|
_newAperatureIndex=min(_newAperatureIndex,_maximumAperatureIndex-1); //maximum limit |
|
_newAperatureIndex=max(_newAperatureIndex,userSettings.minimumAperatureIndex); //minimum limit |
|
|
|
switch(userSettings.aperatureSelectionMode){ |
|
case 1: //full stops |
|
setAperature=aperaturesFull[_newAperatureIndex]; |
|
break; |
|
case 2: //half stops |
|
setAperature=aperaturesHalf[_newAperatureIndex]; |
|
break; |
|
case 3: //third stops |
|
setAperature=aperaturesThird[_newAperatureIndex]; |
|
break; |
|
} |
|
} |
|
uint8_t findAperatureIndex(float pAperature,uint8_t pMethod) //find index of closest aperature from given aperature tables (pMethod |
|
{ |
|
float _minDistance=90000; |
|
float _lastminDistance=100000; |
|
uint8_t _index=userSettings.minimumAperatureIndex; |
|
uint8_t _maxindexpossible=0; |
|
|
|
switch(pMethod){ |
|
case 1: |
|
_maxindexpossible=APERATURESFULL_MAXINDEX; |
|
break; |
|
case 2: |
|
_maxindexpossible=APERATURESHALF_MAXINDEX; |
|
break; |
|
case 3: |
|
_maxindexpossible=APERATURESTHIRD_MAXINDEX; |
|
break; |
|
} |
|
|
|
while (_lastminDistance>_minDistance) //until distance increases |
|
{ |
|
if (_index>_maxindexpossible){ //this index will be out of bounds |
|
return _maxindexpossible; |
|
} |
|
|
|
_lastminDistance=_minDistance; |
|
|
|
switch(pMethod){ |
|
case 1: //full stops |
|
_minDistance=abs( pAperature - aperaturesFull[_index] ); |
|
break; |
|
case 2: //half stops |
|
_minDistance=abs( pAperature - aperaturesHalf[_index] ); |
|
break; |
|
case 3: //third stops |
|
_minDistance=abs( pAperature - aperaturesThird[_index] ); |
|
break; |
|
} |
|
_index++; //next |
|
} |
|
|
|
return _index-2; //use index with closest value |
|
} |
|
|
|
|
|
void changeShutter(int8_t pchange){ //pchange>0 means more light exposure (brighter image) |
|
|
|
|
|
uint8_t _newShutterIndex=findShutterIndex(setShutter,userSettings.shutterSelectionMode); |
|
|
|
uint8_t _maximumShutterIndex=0; |
|
switch(userSettings.shutterSelectionMode){ //get max index from array |
|
case 1: |
|
_maximumShutterIndex=sizeof(shuttertimes1)/sizeof(float); |
|
break; |
|
case 2: |
|
_maximumShutterIndex=sizeof(shuttertimes2)/sizeof(float); |
|
break; |
|
case 3: |
|
_maximumShutterIndex=sizeof(shuttertimes3)/sizeof(float); |
|
break; |
|
} |
|
|
|
if (!( -pchange<0 && _newShutterIndex==0)){ //changed value would not yield negative index |
|
_newShutterIndex-=pchange; //change aperature |
|
_newShutterIndex=min(_newShutterIndex,_maximumShutterIndex-1); //maximum limit from array |
|
//_newShutterIndex=min(_newShutterIndex,maximumShutterIndex); //maximum limit from user settings |
|
} |
|
|
|
switch(userSettings.shutterSelectionMode){ |
|
case 1: // |
|
setShutter=shuttertimes1[_newShutterIndex]; |
|
break; |
|
case 2: // |
|
setShutter=shuttertimes2[_newShutterIndex]; |
|
break; |
|
case 3: // |
|
setShutter=shuttertimes3[_newShutterIndex]; |
|
break; |
|
} |
|
} |
|
uint8_t findShutterIndex(float pShutter,uint8_t pMethod) //find index of closest aperature from given aperature tables (pMethod |
|
{ |
|
float _minDistance=0; |
|
switch(userSettings.shutterSelectionMode){ |
|
case 1: // |
|
_minDistance=abs(pShutter-shuttertimes1[0]); |
|
break; |
|
case 2: // |
|
_minDistance=abs(pShutter-shuttertimes2[0]); |
|
break; |
|
case 3: // |
|
_minDistance=abs(pShutter-shuttertimes3[0]); |
|
break; |
|
} |
|
float _lastminDistance=_minDistance; |
|
uint8_t _index=0; |
|
uint8_t _maxindexpossible=0; |
|
|
|
switch(pMethod){ |
|
case 1: |
|
_maxindexpossible=SHUTTERTIMES1_MAXINDEX; |
|
break; |
|
case 2: |
|
_maxindexpossible=SHUTTERTIMES2_MAXINDEX; |
|
break; |
|
case 3: |
|
_maxindexpossible=SHUTTERTIMES3_MAXINDEX; |
|
break; |
|
} |
|
|
|
|
|
while (_lastminDistance>=_minDistance) //until distance increases |
|
{ |
|
if (_index>_maxindexpossible){ //this index will be out of bounds |
|
return _maxindexpossible; |
|
} |
|
|
|
_lastminDistance=_minDistance; |
|
|
|
switch(pMethod){ |
|
case 1: |
|
_minDistance=abs(pShutter - shuttertimes1[_index]); |
|
break; |
|
case 2: |
|
_minDistance=abs(pShutter - shuttertimes2[_index]); |
|
break; |
|
case 3: |
|
_minDistance=abs(pShutter - shuttertimes3[_index]); |
|
break; |
|
} |
|
_index++; //next |
|
} |
|
|
|
return _index-2; //use index with closest value |
|
} |
|
|
|
void changeISO(int8_t pchange){ //pchange>0 means more light exposure (brighter image), higher iso |
|
|
|
|
|
uint8_t _newISOIndex=findISOIndex(setISO,userSettings.ISOSelectionMode); |
|
|
|
uint8_t _maximumISOIndex=0; |
|
switch(userSettings.ISOSelectionMode){ //get max index from array |
|
case 1: |
|
_maximumISOIndex=sizeof(isoFull)/sizeof(float); |
|
break; |
|
case 2: |
|
_maximumISOIndex=sizeof(isoThird)/sizeof(float); |
|
break; |
|
} |
|
if (!( pchange<0 && _newISOIndex==0)){ //changed value would not yield negative index |
|
_newISOIndex+=pchange; //change iso |
|
_newISOIndex=min(_newISOIndex,_maximumISOIndex-1); //maximum limit from array |
|
//_newISOIndex=min(_newISOIndex,maximumISOIndex); //maximum limit from user settings |
|
} |
|
|
|
switch(userSettings.ISOSelectionMode){ |
|
case 1: // |
|
setISO=isoFull[_newISOIndex]; |
|
break; |
|
case 2: // |
|
setISO=isoThird[_newISOIndex]; |
|
break; |
|
} |
|
} |
|
|
|
uint8_t findISOIndex(float pISO,uint8_t pMethod) //find index of closest iso from given iso table (pMethod) |
|
{ |
|
float _minDistance=abs(pISO-isoFull[0]); |
|
float _lastminDistance=_minDistance; |
|
uint8_t _index=0; |
|
|
|
|
|
while (_lastminDistance>=_minDistance) //until distance increases |
|
{ |
|
_lastminDistance=_minDistance; |
|
|
|
switch(pMethod){ |
|
case 1: |
|
_minDistance=abs(pISO - isoFull[_index]); |
|
break; |
|
case 2: |
|
_minDistance=abs(pISO - isoThird[_index]); |
|
break; |
|
} |
|
_index++; //next |
|
} |
|
return _index-2; |
|
} |
|
|
|
int isoToDIN(float pISO,uint8_t pMethod){ |
|
uint8_t _isoIndex=findISOIndex(pISO,pMethod); |
|
switch(pMethod){ |
|
case 1: |
|
return isoFullDIN[_isoIndex]; |
|
break; |
|
case 2: |
|
return isoThirdDIN[_isoIndex]; |
|
break; |
|
} |
|
} |
|
|
|
void displayPrintISO(float pISO,bool pDisplayBoth){ //for lower iso values use din notation |
|
|
|
if (pISO>=25 || pDisplayBoth){ |
|
if (pDisplayBoth){ |
|
display.print(pISO,2); |
|
}else{ |
|
display.print(pISO,0); |
|
} |
|
} |
|
if (pDisplayBoth){ |
|
display.print("/"); |
|
} |
|
if (pISO<25 || pDisplayBoth){ |
|
display.print(isoToDIN(pISO,userSettings.ISOSelectionMode)); |
|
display.write(0xF7); //degree char |
|
} |
|
} |
|
|
|
float calculateEV(float pISO, float pShutter, float pAperature) |
|
{ //EV = log2 ( 100* Aperature^2 / (ISO * Time )) |
|
return log (100*pow(pAperature,2) / (pISO*pShutter)) / log (2); |
|
} |
|
|
|
void updateDisplay() |
|
{ |
|
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(); |
|
} |
|
|
|
|
|
|
|
} |
|
|
|
void updateDisplay_Lightmeter() //Lightmeter display |
|
{ |
|
#define xpos_aperature 2 |
|
#define ypos_aperature 29 |
|
#define xpos_shutter 50 |
|
#define ypos_shutter 29 |
|
#define xpos_icon 112 //128-16 |
|
#define ypos_icon 29 |
|
|
|
#define xpos_debug 0 |
|
#define ypos_debug 63-7 |
|
|
|
#define xpos_iso 2 |
|
#define ypos_iso 63-7-9 |
|
|
|
display.clearDisplay(); |
|
display.setTextColor(WHITE); |
|
|
|
|
|
|
|
//Aperature |
|
float _showAperature=roundAperature(showAperature,userSettings.aperatureSelectionMode); |
|
display.setTextSize(1); |
|
display.setCursor(xpos_aperature,ypos_aperature); display.print("F"); |
|
display.setTextSize(2); |
|
display.setCursor(display.getCursorX(),display.getCursorY()); display.print(int(_showAperature)); |
|
if ( int( (_showAperature-int(_showAperature) )*10 ) !=0){ //has a decimal |
|
display.setTextSize(1); |
|
display.setCursor(display.getCursorX()-2,display.getCursorY()+7); display.print("."); display.setCursor(display.getCursorX()+1,display.getCursorY()-7); |
|
display.setTextSize(2); |
|
display.setCursor(display.getCursorX()-2,display.getCursorY()); |
|
display.print( (int)round( (_showAperature-int(_showAperature) )*10)); |
|
} |
|
//Aperature border |
|
if (setAperature>0){ //Aperature Priority Mode |
|
if (!manualev_mode){ //selection |
|
display.drawRect(xpos_aperature-2, ypos_aperature-2, 40, 18, WHITE); //normal border |
|
}else{ //manual ev selection |
|
drawRectCorners(xpos_aperature-2, ypos_aperature-2, 40, 18, 5,WHITE); //alternative border |
|
} |
|
} |
|
|
|
|
|
//Shutter |
|
display.setCursor(xpos_shutter,ypos_shutter); |
|
float _showShutter=roundShutter(showShutter,userSettings.shutterSelectionMode); |
|
//Serial.print("rounded Shutter from "); Serial.print(showShutter); Serial.print(" to "); Serial.println(_showShutter); //asdf |
|
if (_showShutter>0.25) //check shuttertime |
|
{ //show full seconds |
|
display.print(int(_showShutter)); |
|
if (_showShutter-int(_showShutter)>0){ //has decimals |
|
display.setTextSize(1); |
|
display.setCursor(display.getCursorX()-2,display.getCursorY()+7); display.print("."); display.setCursor(display.getCursorX()+1,display.getCursorY()-7); |
|
display.setTextSize(2); |
|
display.setCursor(display.getCursorX()-2,display.getCursorY()); |
|
display.print( (int)round( (_showShutter-int(_showShutter))*10)); //show one decimal |
|
} |
|
display.setTextSize(1); display.setCursor(display.getCursorX(),display.getCursorY()+7); |
|
display.print("s"); |
|
}else{ //show fraction of a second |
|
display.setTextSize(1); display.print("1"); |
|
display.drawLine(display.getCursorX()+1,display.getCursorY(), display.getCursorX()-1, display.getCursorY()+9, WHITE); |
|
display.setTextSize(2); display.setCursor(display.getCursorX()+2,display.getCursorY()); |
|
int _frac_showShutter = (int) ( (1.0f/( (int)(_showShutter*1000000) ) )*1000000 ); |
|
display.print( _frac_showShutter ); |
|
display.setTextSize(1); display.setCursor(display.getCursorX(),display.getCursorY()+7); |
|
display.print("s"); |
|
} |
|
//Shutter border |
|
if (setShutter>0){ //Shutter Priority Mode |
|
if (!manualev_mode){ //selection |
|
display.drawRect(xpos_shutter-2, ypos_shutter-2, 60, 18, WHITE); //normal border |
|
}else{ //manual ev selection |
|
drawRectCorners(xpos_shutter-2, ypos_shutter-2, 60, 18, 5, WHITE); //alternative border |
|
} |
|
} |
|
|
|
//Draw line for ev error |
|
float _actualEV = calculateEV(setISO,_showShutter,_showAperature); |
|
float _evError=_actualEV-ev; //Line on the right means suggested values will overexpose the image |
|
uint8_t evErrorX=0; |
|
uint8_t evErrorY=ypos_aperature+16; |
|
if (setAperature>0){ //Aperature Priority Mode |
|
evErrorX=xpos_shutter+20; |
|
evErrorY=ypos_shutter+16; |
|
}else if(setShutter>0) { //Shutter Priority Mode |
|
evErrorX=xpos_aperature+20; |
|
evErrorY=ypos_aperature+16; |
|
} |
|
uint8_t everrorpixels_per_ev=20; |
|
if (_evError>1 || _evError<1){ //scale smaller if error greater 1 EV |
|
everrorpixels_per_ev=10; |
|
} |
|
display.drawLine(evErrorX,evErrorY,evErrorX,evErrorY+1,WHITE); //center line |
|
display.drawLine(evErrorX-everrorpixels_per_ev,evErrorY,evErrorX-everrorpixels_per_ev,evErrorY+1,WHITE); //-1 ev |
|
display.drawLine(evErrorX+everrorpixels_per_ev,evErrorY,evErrorX+everrorpixels_per_ev,evErrorY+1,WHITE); //+1ev |
|
if (_evError>1 || _evError<1){ //scale smaller if error greater 1 EV |
|
display.drawLine(evErrorX-2*everrorpixels_per_ev,evErrorY,evErrorX-2*everrorpixels_per_ev,evErrorY+1,WHITE); //-1 ev |
|
display.drawLine(evErrorX+2*everrorpixels_per_ev,evErrorY,evErrorX+2*everrorpixels_per_ev,evErrorY+1,WHITE); //+1ev |
|
} |
|
display.drawLine(evErrorX,evErrorY,evErrorX+(everrorpixels_per_ev*_evError+0.5),evErrorY,WHITE); //Draw ev error line |
|
|
|
//Meteringmode Icon |
|
if (meteringmode == METERINGMODE_REFLECTIVE){ |
|
display.drawXBitmap(xpos_icon, ypos_icon, icon_spot_bits, icon_spot_width, icon_spot_height, WHITE); |
|
}else if (meteringmode == METERINGMODE_INCIDENT) { |
|
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); |
|
if (setISO<25){ |
|
display.print("DIN "); //below iso 25 only din value is shown here |
|
}else{ |
|
display.print("ISO "); |
|
} |
|
displayPrintISO(setISO,false);//display.print(formatISO(setISO,false)); |
|
|
|
|
|
//EV Scale |
|
uint8_t _evrangedisplay=10;//which range to display. Default value |
|
if (ev_min>-254 && ev_max>-254){ //values set |
|
_evrangedisplay=ev_max-ev_min; |
|
} |
|
if (_evrangedisplay<6){ //minimum range |
|
_evrangedisplay=6; |
|
} |
|
|
|
//#define FULLEVLINEDISTANCE 9 |
|
//#define THIRDEVLINEDISTANCE 3 |
|
|
|
uint8_t FULLEVLINEDISTANCE=((int)(WIDTH/(_evrangedisplay+2))/3)*3; //scale distance to fit evrange_display with safety margin, floor to multiples of 3 |
|
uint8_t THIRDEVLINEDISTANCE=FULLEVLINEDISTANCE/3; |
|
uint8_t _max_evvalues_displayed=(WIDTH/(FULLEVLINEDISTANCE)); |
|
#define ypos_evtext 7 |
|
#define ypos_icon_arrow 6 |
|
|
|
int8_t _startev=-5; //first ev to display, 13 ev values can fit on screen |
|
/*if (ev>2 && (ev_min<-254 || ev_min>2)){ //TODO make ev scale start better |
|
_startev=0; |
|
} |
|
if (ev>_max_ev_displayed-2 || ev_max>_max_ev_displayed-2){ |
|
_startev=5+ev-(_max_ev_displayed-2); |
|
}*/ |
|
|
|
float _evrangemargin=(_max_evvalues_displayed-_evrangedisplay)/2.0; //space left on both sides between evnrange (min to max) and display width |
|
if (_evrangemargin<0){ //bound |
|
_evrangemargin=0; |
|
} |
|
if (ev_min>-254 && ev_max>-254 ){ //minmax values set |
|
if (ev>=ev_min && ev<=ev_max){ //arrow between min and max |
|
_startev=(ev_max-ev_min)/2+ev_min - _max_evvalues_displayed/2; //center of evmin and max at display center |
|
}else{ //arrow outside of ev min max range |
|
if (ev<ev_min) { //on the left |
|
_startev=ev-_evrangemargin-2; |
|
}else if (ev>ev_max) { //on the right |
|
_startev=ev+_evrangemargin-_evrangedisplay; |
|
} |
|
} |
|
}else{ //ev min max values not set yet |
|
_startev=ev-_max_evvalues_displayed/2; //center |
|
_startev=(int(_startev/(_max_evvalues_displayed/2)))*(_max_evvalues_displayed/2); //floor to multiples of (_evrangedisplay/2) |
|
} |
|
|
|
|
|
uint8_t xpos_arrow=(ev-_startev*1.0) *FULLEVLINEDISTANCE+1; //calculate display position for ev |
|
|
|
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<=_max_evvalues_displayed;_fullevline++){ //with fullevlindistance=9 and WIDTH=128 -> <=13 |
|
int8_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 ((FULLEVLINEDISTANCE>9 && _current_evvalue<10 && _current_evvalue>=0) || (FULLEVLINEDISTANCE>12) || _fullevline%2==1){ //display every single digit ev if distance greater 9 OR if dist. gr. 12 OTHERWISE only every second digit |
|
|
|
uint8_t _evtextmove=2; //movement of left point of text to the left. Compensation for center position |
|
if (_current_evvalue>9 || _current_evvalue<0){ //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 at scale line |
|
} |
|
} |
|
} |
|
//Arrow at current ev |
|
float _ev_decimals=abs(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 |
|
if (manualev_mode){ //in manual ev mode |
|
display.drawXBitmap(xpos_arrow - icon_arrow_width/2.0 -1, ypos_icon_arrow, icon_arrow_bits, icon_arrow_width, icon_arrow_height, WHITE); //arrow icon //draw bold |
|
display.drawXBitmap(xpos_arrow - icon_arrow_width/2.0 +1, ypos_icon_arrow, icon_arrow_bits, icon_arrow_width, icon_arrow_height, WHITE); //arrow icon //draw bold |
|
display.drawXBitmap(xpos_arrow - icon_arrow_width/2.0 , ypos_icon_arrow-1, icon_arrow_bits, icon_arrow_width, icon_arrow_height, WHITE); //arrow icon //draw bold |
|
} |
|
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; |
|
} |
|
|
|
int _displayev=(int)ev; |
|
if (_ev_decimals > 0.8333 ){ |
|
if (ev>=0){ //ev is positive |
|
_displayev=(int)(ev+1);//EV Value under arrow. Ceil |
|
}else if (ev<0){ //ev is negative |
|
_displayev=(int)(ev-1);//EV Value under arrow. Ceil (negative) |
|
} |
|
|
|
} |
|
//int _xpos_current_fraction_move=0; //move fraction icon |
|
if (_displayev>=10 || ev<-0.1666){ //displayev is two digits long (>=10 or negative sign) |
|
_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 |
|
if (ev<0 && _displayev==0){ //ev is negative but displayev is zero |
|
display.print("-"); // add minus in front |
|
} |
|
display.print(_displayev); //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 |
|
} |
|
|
|
//ev min & max |
|
int16_t xpos_ev_min=(ev_min-_startev*1.0) *FULLEVLINEDISTANCE; //calculate display position for ev |
|
int16_t xpos_ev_max=(ev_max-_startev*1.0) *FULLEVLINEDISTANCE; //calculate display position for ev |
|
|
|
bool arrow_is_between_minmax=true; |
|
if (xpos_arrow<=xpos_ev_min || xpos_arrow>=xpos_ev_max){ |
|
arrow_is_between_minmax=false; //selected ev is not between min and max ev |
|
} |
|
if (ev_min>-254 && xpos_ev_min>=0 && xpos_ev_min<WIDTH){ //ev_min is set (-255 is placeholder for "not set") |
|
display.drawLine(xpos_ev_min,2,xpos_ev_min,5,WHITE); |
|
if ((xpos_arrow-xpos_ev_min)>3 && arrow_is_between_minmax){ //arrow is not overlaying line and is in between min and max |
|
//display.drawLine(xpos_ev_min,4,xpos_arrow ,4,WHITE); //line from left horizontally to arrow |
|
display.drawLine(xpos_ev_min,5,xpos_arrow - 4,5,WHITE); //line from left horizontally to arrow |
|
} |
|
} |
|
if (ev_max>-254 && xpos_ev_max>=0 && xpos_ev_max<WIDTH){ //ev_min is set (-255 is placeholder for "not set") |
|
display.drawLine(xpos_ev_max,2,xpos_ev_max,5,WHITE); |
|
if ((xpos_ev_max-xpos_arrow)>3 && arrow_is_between_minmax){ //arrow is not overlaying line and is in between min and max |
|
//display.drawLine(xpos_ev_max,4,xpos_arrow ,4,WHITE); //line from right horizontally to arrow |
|
display.drawLine(xpos_ev_max,5,xpos_arrow + 2,5,WHITE); //line from right horizontally to arrow |
|
} |
|
} |
|
if (ev_min>-254 && ev_max>-254){ //evmin and max are set |
|
uint8_t _xpos_ev_min_line=xpos_ev_min; |
|
uint8_t _xpos_ev_max_line=xpos_ev_max; |
|
if (xpos_ev_min<0){ |
|
_xpos_ev_min_line=0; |
|
}else if (xpos_ev_min>=WIDTH-1){ |
|
_xpos_ev_min_line=WIDTH-1; |
|
} |
|
if (xpos_ev_max<0){ |
|
_xpos_ev_max_line=0; |
|
}else if (xpos_ev_max>=WIDTH-1){ |
|
_xpos_ev_max_line=WIDTH-1; |
|
} |
|
display.drawLine(_xpos_ev_min_line,4,_xpos_ev_max_line ,4,WHITE); //draw single line between them |
|
} |
|
|
|
for (int8_t i=-(xpos_arrow-xpos_ev_min)/FULLEVLINEDISTANCE;i<(xpos_ev_max-xpos_arrow)/FULLEVLINEDISTANCE;i++){ //draw black lines for every zone border |
|
display.drawLine(xpos_arrow+i*FULLEVLINEDISTANCE+FULLEVLINEDISTANCE/2,4,xpos_arrow+i*FULLEVLINEDISTANCE+FULLEVLINEDISTANCE/2 ,5,BLACK); //erase part of horizontal line |
|
} |
|
|
|
|
|
|
|
|
|
//DEBUG Message |
|
display.setTextSize(1); |
|
display.setCursor(xpos_debug,ypos_debug); |
|
display.print(vbat,2); |
|
display.print("V "); |
|
/*display.print("Ev="); |
|
display.print(ev); |
|
display.print(" |"); |
|
display.print(incident);*/ |
|
|
|
/*display.print(debug_analog_low); |
|
display.print(" : "); |
|
display.print(debug_analog_high);*/ |
|
|
|
/*display.print(ev_min,1); |
|
display.print("<"); |
|
display.print(ev,1); |
|
display.print("<"); |
|
display.print(ev_max,1);*/ |
|
|
|
|
|
display.setCursor(xpos_debug+50,ypos_debug-5); |
|
if (ev_min>-254 && ev>=ev_min) { //ev min set |
|
display.print("-"); |
|
display.print(ev-ev_min,1); |
|
}else{ |
|
display.print("/"); |
|
} |
|
display.print(" <> "); |
|
if (ev_max>-254 && ev<=ev_max){ |
|
display.print("+"); |
|
display.print(ev_max-ev,1); |
|
}else{ |
|
display.print("/"); |
|
} |
|
|
|
|
|
} |
|
|
|
void updateDisplay_Settings() |
|
{ |
|
display.clearDisplay(); |
|
display.setTextColor(WHITE); |
|
display.setTextSize(1); |
|
#define SETTINGS_YPOS_INCREMENT 9 |
|
#define SETTINGS_XPOS_OFFSET 1 |
|
|
|
|
|
|
|
display.setCursor(SETTINGS_XPOS_OFFSET,0); //absolute position for first item |
|
|
|
for (uint8_t _currentItemIndex=0;_currentItemIndex<=SETTINGS_SELECTEDITEM_MAX;_currentItemIndex++) |
|
{ |
|
if (settings_selectedItem==_currentItemIndex){ |
|
if (settings_itemActive){ |
|
display.drawRect(0, display.getCursorY()-2, 126 , 11, WHITE); |
|
}else{ |
|
display.fillCircle(2, display.getCursorY()+3,2, WHITE); //x,y,r,color |
|
} |
|
display.setCursor(display.getCursorX()+5,display.getCursorY()); //move text to the right |
|
} |
|
display.print(settingStrings[_currentItemIndex]); |
|
switch(_currentItemIndex){ //if values need to be shown |
|
case 0: displayPrintISO(setISO,true);//display.print(formatISO(setISO,true)); |
|
break; |
|
case 1: display.print(settingsnameAperatureSelectionMode[userSettings.aperatureSelectionMode-1]); |
|
break; |
|
case 2: display.print(settingsnameShutterSelectionMode[userSettings.shutterSelectionMode-1]); |
|
break; |
|
case 3: display.print("1/"); display.print(userSettings.manualev_moveamount_frac);display.print(" EV"); |
|
break; |
|
//case 4 is power off, no value to display here |
|
} |
|
|
|
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 |
|
|
|
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"); |
|
|
|
if (loopmillis-millis_opened_meteringmodeselection>=DELAY_METERINGMODESELECTION_FLASHLIGHT){ |
|
blinkLED(500); //turn led on continously |
|
} |
|
} |
|
|
|
void drawRectCorners(uint8_t px,uint8_t py, uint8_t pw, uint8_t ph, uint8_t pcornerlength, uint8_t pc){ |
|
//px py are top left |
|
display.drawLine(px,py,px+pcornerlength,py, pc); |
|
display.drawLine(px,py,px,py+pcornerlength, pc); |
|
|
|
display.drawLine(px+pw,py, px+pw-pcornerlength,py, pc); |
|
display.drawLine(px+pw,py, px+pw,py+pcornerlength, pc); |
|
|
|
display.drawLine(px+pw,py+ph, px+pw-pcornerlength,py+ph, pc); |
|
display.drawLine(px+pw,py+ph, px+pw,py+ph-pcornerlength, pc); |
|
|
|
display.drawLine(px,py+ph, px+pcornerlength,py+ph, pc); |
|
display.drawLine(px,py+ph, px,py+ph-pcornerlength, pc); |
|
|
|
} |
|
|
|
void blinkLED(long duration){ |
|
blinkLED(duration,255); |
|
} |
|
void blinkLED(long duration,uint8_t brightness){ |
|
//digitalWrite(PIN_LED,HIGH); |
|
analogWrite(PIN_LED,brightness); |
|
millis_ledoff=loopmillis+duration; |
|
} |
|
void checkLED(){ |
|
if (loopmillis>=millis_ledoff && digitalRead(PIN_LED)){ |
|
//digitalWrite(PIN_LED,LOW); |
|
analogWrite(PIN_LED,0); //LED OFF |
|
} |
|
} |
|
|
|
|
|
template <class T> 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 <class T> 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; |
|
}
|
|
|