Last active
June 1, 2020 22:27
-
-
Save nytpu/753158379559c04b7728f9998a10473d to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* Photo Printing Dev Timer * | |
* by nytpu */ | |
/* | |
* Warning: this was written in a very short time, all in one day, | |
* so it's not necessarily quality code. I see *at least* three | |
* places that I could significantly refactor it, but I'm lazy and | |
* it still works without any significant bugs. | |
* | |
* For more info, check out my write-up at: | |
* https://www.nytpu.com/projects/dev-timer | |
* | |
* You also need SendOnlySoftwareSerial | |
* https://github.com/nickgammon/SendOnlySoftwareSerial | |
*/ | |
#include <SendOnlySoftwareSerial.h> // Gotta save those precious I/O pins | |
#include <EEPROM.h> | |
#define DEFAULT_EXPOSURE 5 // Seconds | |
#define DEFAULT_DEVELOPMENT 60 | |
#define DEFAULT_STOP 10 | |
#define DEFAULT_FIX 4 * 60 | |
#define LENGTH_BAR 10 | |
#define LENGTH_DIP 7 // Cut one switch because there aren't enough I/O pins otherwise | |
#define BACKLIGHT 255 // Min: 0; Max: 255 | |
#define EEPROM_OFFSET 155 // Move to a strange point in EEPROM in an an attempt to not overwrite existing data | |
#define LCD_CLEAR 0x01 | |
#define LCD_ON 0x0C // Also turns off both types of cursor, but must be called twice to make sure display is on and cursor is off | |
#define LCD_OFF 0x08 // Turns off LCD, not backlight | |
#define LCD_SET_CURSOR 0x80 // Requires extra byte to set cursor position, 0 for top left to 31 for bottom right | |
/* Only 7 switches are connected to pins due to lack of IO * | |
* Max 255 can be set */ | |
const int bar[LENGTH_BAR] = {10, 11, 12, 13, A0, A1, A2, A3, A4, A5}; // LED bar graph counts down left→right | |
const int dip[LENGTH_DIP] = {1, 3, 4, 5, 6, 7, 8}; | |
const int select = 9; | |
const int power_relay = 0; | |
SendOnlySoftwareSerial lcd(2); | |
byte status = 0; | |
int bar_status; | |
int mode = 0; | |
byte times[4]; | |
void setup (void) | |
{ | |
for (int i = 0; i < LENGTH_BAR; i++) { | |
pinMode(bar[i], OUTPUT); | |
} | |
for (int i = 0; i < LENGTH_DIP; i++) { | |
pinMode(dip[i], INPUT_PULLUP); | |
} | |
pinMode(select, INPUT_PULLUP); | |
pinMode(power_relay, OUTPUT); | |
lcd.begin(9600); | |
lcdSpecialCommand(LCD_CLEAR); | |
} | |
void loop (void) | |
{ | |
readStatus(); | |
switch (mode) { | |
case 0: | |
bar_status = 7; // 7 steps before timing actually starts | |
setBar(bar_status); | |
lcdSetBacklight(BACKLIGHT); | |
digitalWrite(power_relay, HIGH); // Allow negative vieing, focusing, etc. | |
dispAll(); | |
bar_status--; | |
break; | |
case 1: | |
lcdSetBacklight(0); // Turn off backlight to make it easier to see. | |
dispAll(); | |
bar_status--; | |
lcdSetBacklight(BACKLIGHT); | |
case 2: | |
set_time(0); // 0 = set exposure | |
bar_status--; | |
break; | |
case 3: | |
set_time(1); // 1 = set Development | |
bar_status--; | |
break; | |
case 4: | |
set_time(2); // 2 = set Stop | |
bar_status--; | |
break; | |
case 5: | |
set_time(3); // 3 = set Fixer | |
bar_status--; | |
break; | |
case 6: | |
dispAll(); | |
bar_status--; | |
lcdSetBacklight(0); // Turn off LCD backlight for the rest of the time | |
digitalWrite(power_relay, LOW); // Turn off to allow getting paper ready, etc. | |
break; | |
case 7: | |
lcdSpecialCommand(LCD_CLEAR); | |
lcd.write("Press SEL again to start exposure"); // LCD is still displaying, just hard to see without backlight | |
while (!bitRead(status, 7)) { | |
readStatus(); | |
delay(100); | |
} | |
mode++; | |
break; | |
case 8: | |
timer_run(0); | |
break; | |
case 9: | |
timer_run(1); | |
break; | |
case 10: | |
timer_run(2); | |
break; | |
case 11: | |
timer_run(3); | |
mode = 0; | |
break; | |
} | |
lcdSpecialCommand(LCD_CLEAR); | |
while (bitRead(status, 7)){ | |
readStatus(); | |
delay(100); | |
} | |
setBar(bar_status); | |
} | |
void lcdSpecialCommand (int command) | |
{ | |
lcd.write(0xFE); // Magic Bytes | |
lcd.write(command); | |
} | |
void lcdSetBacklight (int level) | |
{ | |
lcd.write(0x80); // Backlight set code | |
lcd.write(level); | |
} | |
void readStatus (void) | |
{ | |
byte status_byte = 0; | |
for (int i = 0; i < LENGTH_DIP; i++) { | |
bitWrite(status_byte, i, digitalRead(dip[i])); | |
} | |
bitWrite(status_byte, 7, digitalRead(select)); | |
status = (byte)~status_byte; | |
} | |
void setBar (int value) | |
{ | |
for (int i = 0; i < value; i++) { | |
digitalWrite(bar[i], HIGH); | |
} | |
for (int i = value; i < LENGTH_BAR; i++) { | |
digitalWrite(bar[i], LOW); | |
} | |
} | |
void dispAll (void) | |
{ | |
for (int i = 0; i < 4; i++){ | |
times[i] = EEPROM.read(i + EEPROM_OFFSET); | |
} | |
lcdSpecialCommand(LCD_CLEAR); | |
lcd.write("Exp:"); | |
lcd.print(times[0], DEC); | |
lcd.write(" Dev:"); | |
lcd.print(times[1], DEC); | |
lcdSpecialCommand(LCD_SET_CURSOR); | |
lcd.write(16); | |
lcd.write("Stp:"); | |
lcd.print(times[2], DEC); | |
lcd.write(" Fix:"); | |
lcd.print(times[3], DEC); | |
while (!bitRead(status, 7)) { | |
readStatus(); | |
delay(100); | |
} | |
delay(100); | |
mode++; | |
} | |
void set_time (int sel) | |
{ | |
while (!bitRead(status, 7)) { | |
lcdSpecialCommand(LCD_CLEAR); | |
readStatus(); | |
current_value = status & 0b01111111; // Mask out select button | |
switch (sel) { | |
case 0: | |
lcd.write("Exp time in Sec"); | |
break; | |
case 1: | |
lcd.write("Dev time in Sec"); | |
break; | |
case 2: | |
lcd.write("Stp time in Sec"); | |
break; | |
case 3: | |
lcd.write("Fix in Min Max 4"); // technically 4.25 min (255 sec) but couldn't fit it in the LCD | |
break; | |
} | |
lcdSpecialCommand(LCD_SET_CURSOR); | |
lcd.write(16); // Start of second line | |
lcd.write("Current: "); | |
lcdSpecialCommand(LCD_SET_CURSOR); | |
lcd.write(25); // After "Current: " | |
lcd.print(current_value, DEC); | |
delay(100); | |
} | |
if (current_value != 0) { | |
if (sel != 3) { | |
EEPROM.update(sel + EEPROM_OFFSET, current_value); | |
} else { | |
EEPROM.update(sel + EEPROM_OFFSET, current_value * 60); | |
} | |
} | |
mode++; | |
} | |
void timer_run (int sel) | |
{ | |
unsigned int count = times[sel]; | |
lcdSpecialCommand(LCD_CLEAR); | |
lcd.print(count, DEC); | |
if (sel == 0) { | |
digitalWrite(power_relay, HIGH); | |
} | |
if (count > 60) { | |
bar_status = count / 60; | |
setBar(bar_status); | |
} | |
while (count > 60) { | |
delay(1000); | |
count--; | |
lcdSpecialCommand(LCD_CLEAR); | |
lcd.print(count, DEC); | |
if (count % 60 == 0) { | |
setBar(--bar_status); | |
} | |
} | |
if (count > 10) { | |
bar_status = count / 10; | |
setBar(bar_status); | |
} | |
while (count > 10) { | |
delay(1000); | |
count--; | |
lcdSpecialCommand(LCD_CLEAR); | |
lcd.print(count, DEC); | |
if (count % 10 == 0) { | |
setBar(--bar_status); | |
} | |
} | |
bar_status = count; | |
setBar(bar_status); | |
while (count > 0) { | |
delay(1000); | |
count--; | |
lcdSpecialCommand(LCD_CLEAR); | |
lcd.print(count, DEC); | |
setBar(--bar_status); | |
} | |
if (sel == 0) { | |
digitalWrite(power_relay, LOW); | |
} | |
lcdSpecialCommand(LCD_CLEAR); | |
lcd.write("DONE! Press SEL to continue."); | |
delay(100); | |
for (int i = 0; i < 2; i++){ | |
setBar(10); | |
delay(200); | |
setBar(0); | |
delay(200); | |
} | |
while (!bitRead(status, 7)) { | |
readStatus(); | |
delay(100); | |
} | |
mode++; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment