Skip to content

Instantly share code, notes, and snippets.

@nytpu
Last active June 1, 2020 22:27
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save nytpu/753158379559c04b7728f9998a10473d to your computer and use it in GitHub Desktop.
Save nytpu/753158379559c04b7728f9998a10473d to your computer and use it in GitHub Desktop.
/* 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