2018-03-22 07:57:53 +00:00
//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 <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
# include <BH1750.h> //from: https://github.com/mysensors/MySensorsArduinoExamples/tree/master/libraries/BH1750
BH1750 lightMeter ;
# define PIN_LDR 0 //A0
# define PIN_BRIGHTMODE 1 //A1
# define PIN_VBAT 2 //A2
# define PIN_TRIGGER PB8
# define PIN_BTNLEFT PA15
# define PIN_BTNCENTER PB4
# define PIN_BTNRIGHT PB5
# define PIN_ON PB9
# define TIME_AUTOPOWEROFF 120000
# define LDRDELAY 50 //minimum delay between ldr readings. Transistor for lower value pulldown resistor switches in between
2018-03-23 19:21:27 +00:00
# define INCIDENTDELAY 100 //minimum delay between incident sensor (BH1750) readings
2018-03-22 07:57:53 +00:00
# define DEBOUNCETIME 50 //time to not check for inputs after key press
2018-03-23 19:21:27 +00:00
# define BUTTONTIMEHOLD 750 //time for button hold
2018-03-22 07:57:53 +00:00
# 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 } ;
2018-03-23 19:21:27 +00:00
# define SHUTTERTIMES1_MAXINDEX 19
2018-03-22 07:57:53 +00:00
String settingsnameShutterSelectionMode [ ] = { " Analog " } ; //names for tables
# define MAXIMUM_SHUTTERSELECTIONMODES 1
float aperaturesFull [ ] = { 1 , 1.4 , 2 , 2.8 , 4 , 5.6 , 8 , 11 , 16 , 22 , 32 } ;
2018-03-23 19:21:27 +00:00
# define APERATURESFULL_MAXINDEX 10
2018-03-22 07:57:53 +00:00
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 } ;
2018-03-23 19:21:27 +00:00
# define APERATURESHALF_MAXINDEX 18
2018-03-22 07:57:53 +00:00
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 } ;
2018-03-23 19:21:27 +00:00
# define APERATURESTHIRD_MAXINDEX 33
2018-03-22 07:57:53 +00:00
String settingsnameAperatureSelectionMode [ ] = { " Full " , " Half " , " Third " } ; //names for tables
# define MAXIMUM_APERATURESELECTIONMODES 3
float isoFull [ ] = { 12 , 25 , 50 , 100 , 200 , 400 , 800 , 1600 , 3200 , 6400 , 12500 , 25600 } ;
float isoThird [ ] = { 12 , 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 } ;
long loopmillis = 0 ; //only use one millis reading each loop
long last_ldrReading = 0 ;
2018-03-23 19:21:27 +00:00
long last_incidentReading = 0 ;
2018-03-22 07:57:53 +00:00
long millis_lastchange = 0 ;
long millis_lastinput = 0 ;
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 ;
float vbat = 0 ;
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
} ;
Settings userSettings = { 1 , 1 , 1 , 2 } ;
# define OLED_RESET 4
Adafruit_SSD1306 display ( OLED_RESET ) ;
2018-03-23 19:21:27 +00:00
uint16_t incident = 0 ; //incident reading from bh1750
2018-03-22 07:57:53 +00:00
uint16_t analog_low = 0 ; //better for low light
uint16_t analog_high = 0 ; //better for bright light (higher pulldown resistor for ldr)
float ev = 0 ; //calculated EV from LDR readings (reflected) or from Luxmeter (incident)
float ev_min = 6 , ev_max = 12 , ev_last = 8 ;
float showAperature = 0 ;
float showShutter = 0 ;
//Usersettings
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
enum displaymode {
lightmeter ,
settings
} ;
displaymode displaymode = lightmeter ;
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
2018-03-23 19:21:27 +00:00
# define METERINGMODE_REFLECTIVE 0
# define METERINGMODE_INCIDENT 1
uint8_t meteringmode = METERINGMODE_REFLECTIVE ;
2018-03-22 07:57:53 +00:00
char tempstring [ 16 ] ; //for dtostrf //dtostrf(modefactor,1,3,tempstring);
# if (SSD1306_LCDHEIGHT != 64)
# error("Height incorrect, please fix Adafruit_SSD1306.h!");
# endif
2018-03-25 19:20:39 +00:00
//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
} ;
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
} ;
2018-03-22 07:57:53 +00:00
void setup ( ) {
Serial . begin ( 9600 ) ;
Serial . println ( " Started " ) ;
2018-03-23 19:21:27 +00:00
Serial . println ( " Init Display " ) ;
2018-03-22 07:57:53 +00:00
display . begin ( SSD1306_SWITCHCAPVCC , 0x3C ) ;
display . clearDisplay ( ) ;
display . display ( ) ;
2018-03-23 19:21:27 +00:00
Serial . println ( " Init BH1750 " ) ;
lightMeter . begin ( BH1750_CONTINUOUS_HIGH_RES_MODE_2 ) ; //max reading=54612
2018-03-22 07:57:53 +00:00
//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 ) ;
millis_lastchange = millis ( ) ;
Serial . println ( " Initialized " ) ;
//display.drawPixel(10, 10, WHITE);
}
void loop ( ) {
loopmillis = millis ( ) ; //read millis for this cycle
handleInputs ( ) ;
calculateEV ( ) ;
updateDisplay ( ) ;
}
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 ;
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
} 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
} 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
}
//Left
if ( timebuttonpressed_left = = 0 & & ! digitalRead ( PIN_BTNLEFT ) ) { //first time pressed down. (low when pressed)
timebuttonpressed_left = loopmillis ; //set time of button press
} 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
} 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
} 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
} 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
} 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
} 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
vbat = map ( analogRead ( PIN_VBAT ) , 0 , 3910 , 0 , 8400 ) / 1000.0 ; //180k and 300k voltage divider. 8,4V -> 3,15V=3910
2018-03-23 19:21:27 +00:00
//LDR
2018-03-22 07:57:53 +00:00
if ( loopmillis - last_ldrReading > LDRDELAY )
{
if ( ! digitalRead ( PIN_BRIGHTMODE ) ) {
analog_low = analogRead ( PIN_LDR ) ;
} else {
analog_high = analogRead ( PIN_LDR ) ;
}
digitalWrite ( PIN_BRIGHTMODE , ! digitalRead ( PIN_BRIGHTMODE ) ) ; //switch modes
last_ldrReading = loopmillis ;
}
2018-03-23 19:21:27 +00:00
//Lightsensor BH1750
if ( loopmillis - last_incidentReading > INCIDENTDELAY )
{
incident = lightMeter . readLightLevel ( ) ; //value in lux from sensor
last_incidentReading = loopmillis ;
}
2018-03-22 07:57:53 +00:00
//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 , 1 ) , 6 ) ;
Serial . print ( " -- " ) ;
Serial . println ( reciprocFloat ( roundShutter ( i , 1 ) ) ) ;
}
Serial . println ( " calculateShutter at iso 100 f8 " ) ;
for ( int8_t i = - 2 ; i < 18 ; i + + ) {
Serial . print ( i ) ;
Serial . print ( " -> " ) ;
Serial . println ( calculateShutter ( i , ( uint16_t ) 100 , 8.0 ) , 6 ) ;
}
Serial . println ( " calculateAperature at iso 100 1/125s " ) ;
for ( int8_t i = - 2 ; i < 18 ; i + + ) {
Serial . print ( i ) ;
Serial . print ( " -> " ) ;
Serial . println ( calculateAperature ( i , ( uint16_t ) 100 , 1.0 / 125 ) , 6 ) ;
}
}
*/
switch ( displaymode ) {
case lightmeter :
handleInputs_Lightmeter ( ) ;
break ;
case settings :
handleInputs_Settings ( ) ;
break ;
}
if ( millis ( ) - millis_lastchange > TIME_AUTOPOWEROFF ) {
digitalWrite ( PIN_ON , LOW ) ;
}
if ( button_trigger | | button_left | | button_center | | button_right ) {
millis_lastchange = millis ( ) ; //for auto poweroff
millis_lastinput = millis ( ) ; //for debouncing
}
}
void handleInputs_Lightmeter ( )
{
if ( button_hold_center ) { //Go to Settings
displaymode = settings ;
}
2018-03-23 19:21:27 +00:00
if ( button_center ) { //Change Refelctive - Incident
if ( meteringmode = = METERINGMODE_REFLECTIVE ) {
meteringmode = METERINGMODE_INCIDENT ;
} else if ( meteringmode = = METERINGMODE_INCIDENT ) {
meteringmode = METERINGMODE_REFLECTIVE ;
}
}
2018-03-22 07:57:53 +00:00
if ( setShutter = = 0 & & setAperature = = 0 ) { //Auto
//Value Change
if ( button_left ) {
}
if ( button_right ) {
}
//Change Mode
if ( button_hold_left ) { //Auto -> T
setShutter = showShutter ;
setAperature = 0 ;
}
if ( button_hold_right ) { //Auto -> Av
setAperature = showAperature ;
setShutter = 0 ;
}
} else if ( setShutter = = 0 ) { //Aperature Priority
//Value Change
if ( button_left ) {
changeAperature ( 1 ) ; //Decrement Aperature
}
if ( button_right ) {
changeAperature ( - 1 ) ; //Increment Aperature
}
//Change Mode
if ( button_hold_left ) { //change from Aperature Priority to Auto, Av -> Auto
setAperature = 0 ;
setShutter = 0 ;
}
if ( button_hold_right ) { //Av -> T
setShutter = showShutter ;
setAperature = 0 ;
}
} else if ( setAperature = = 0 ) { //Shutter Priority
//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 -> Auto
setAperature = 0 ;
setShutter = 0 ;
}
}
}
void handleInputs_Settings ( )
{
if ( button_hold_center ) { //Go to Lightmeter
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 : //Turn Off
digitalWrite ( PIN_ON , LOW ) ; //set power latch low
break ;
}
if ( button_center ) {
settings_itemActive = false ; //return to item selection
}
}
}
float reciprocFloat ( float p ) {
if ( p < 1 ) {
return ( 1.0f / ( ( int ) ( p * 1000000 ) ) ) * 1000000 ;
} else {
return ( 1 / p ) ;
}
}
void calculateEV ( )
{
2018-03-23 19:21:27 +00:00
if ( meteringmode = = METERINGMODE_REFLECTIVE ) {
//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 ;
} else if ( lowev < 12.5 ) {
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 ;
}
} else if ( meteringmode = = METERINGMODE_INCIDENT ) {
ev = luxToEv ( incident ) ;
2018-03-22 07:57:53 +00:00
}
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 ) ;
} else { //Auto
//TODO
showAperature = 42 ;
showShutter = 42 ;
}
}
2018-03-23 19:21:27 +00:00
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 ) ;
}
2018-03-22 07:57:53 +00:00
float calculateShutter ( float pEv , uint16_t pIso , uint16_t 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 ;
}
}
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 ;
2018-03-23 19:21:27 +00:00
uint8_t _maxindexpossible = 0 ;
switch ( pMethod ) {
case 1 :
_maxindexpossible = APERATURESFULL_MAXINDEX ;
break ;
case 2 :
_maxindexpossible = APERATURESHALF_MAXINDEX ;
break ;
case 3 :
_maxindexpossible = APERATURESTHIRD_MAXINDEX ;
break ;
}
2018-03-22 07:57:53 +00:00
while ( _lastminDistance > _minDistance ) //until distance increases
{
2018-03-23 19:21:27 +00:00
if ( _index > _maxindexpossible ) { //this index will be out of bounds
return _maxindexpossible ;
}
2018-03-22 07:57:53 +00:00
_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
}
2018-03-23 19:21:27 +00:00
return _index - 2 ; //use index with closest value
2018-03-22 07:57:53 +00:00
}
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 ;
}
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 ;
}
}
uint8_t findShutterIndex ( float pShutter , uint8_t pMethod ) //find index of closest aperature from given aperature tables (pMethod
{
float _minDistance = abs ( pShutter - shuttertimes1 [ 0 ] ) ;
float _lastminDistance = _minDistance ;
uint8_t _index = 0 ;
2018-03-23 19:21:27 +00:00
uint8_t _maxindexpossible = 0 ;
switch ( pMethod ) {
case 1 :
_maxindexpossible = SHUTTERTIMES1_MAXINDEX ;
break ;
}
2018-03-22 07:57:53 +00:00
while ( _lastminDistance > = _minDistance ) //until distance increases
{
2018-03-23 19:21:27 +00:00
if ( _index > _maxindexpossible ) { //this index will be out of bounds
return _maxindexpossible ;
}
2018-03-22 07:57:53 +00:00
_lastminDistance = _minDistance ;
switch ( pMethod ) {
case 1 :
_minDistance = abs ( pShutter - shuttertimes1 [ _index ] ) ;
break ;
}
_index + + ; //next
}
2018-03-23 19:21:27 +00:00
return _index - 2 ; //use index with closest value
2018-03-22 07:57:53 +00:00
}
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 ;
}
void updateDisplay ( )
{
switch ( displaymode ) {
case lightmeter :
updateDisplay_Lightmeter ( ) ;
break ;
case settings :
updateDisplay_Settings ( ) ;
break ;
}
display . display ( ) ;
}
void updateDisplay_Lightmeter ( ) //Lightmeter display
{
# define xpos_aperature 2
# define ypos_aperature 29
# define xpos_shutter 60
# define ypos_shutter 29
2018-03-25 19:20:39 +00:00
# define xpos_icon 112 //128-16
# define ypos_icon 29
2018-03-22 07:57:53 +00:00
# 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
display . drawRect ( xpos_aperature - 2 , ypos_aperature - 2 , 40 , 18 , WHITE ) ;
}
//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 > = 1 ) //check time
{ //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
display . drawRect ( xpos_shutter - 2 , ypos_shutter - 2 , 40 , 18 , WHITE ) ;
}
2018-03-25 19:20:39 +00:00
if ( meteringmode = = METERINGMODE_REFLECTIVE ) {
display . drawBitmap ( xpos_icon , ypos_icon , icon_spot , ICON_METERINGMODE_HEIGHT , ICON_METERINGMODE_WIDTH , 1 ) ;
} else if ( meteringmode = = METERINGMODE_INCIDENT ) {
display . drawBitmap ( xpos_icon , ypos_icon , icon_incident , ICON_METERINGMODE_HEIGHT , ICON_METERINGMODE_WIDTH , 1 ) ;
}
2018-03-22 07:57:53 +00:00
//ISO
display . setCursor ( xpos_iso , ypos_iso ) ; display . setTextSize ( 1 ) ; display . print ( " ISO " ) ; display . print ( setISO ) ;
//DEBUG Message
display . setTextSize ( 1 ) ;
display . setCursor ( xpos_debug , ypos_debug ) ;
display . print ( vbat ) ;
display . print ( " V " ) ;
display . print ( " Ev= " ) ;
display . print ( ev ) ;
2018-03-23 19:21:27 +00:00
display . print ( " | " ) ;
display . print ( incident ) ;
2018-03-22 07:57:53 +00:00
}
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 : display . print ( setISO ) ;
break ;
case 1 : display . print ( settingsnameAperatureSelectionMode [ userSettings . aperatureSelectionMode - 1 ] ) ;
break ;
case 2 : display . print ( settingsnameShutterSelectionMode [ userSettings . shutterSelectionMode - 1 ] ) ;
break ;
}
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 " ) ; */
}