Skip to content
Permalink
0a6fb064fc
Switch branches/tags

Name already in use

A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
Go to file
 
 
Cannot retrieve contributors at this time
543 lines (479 sloc) 18.7 KB
//(c) Copyright 2018 Radu Corcodel
// Developers: Radu Corcodel
//
// Scope of code: Arduino sketch for a darkroom timer with a Touch Sensitive LCD as user
// interface.
//
// License: Code is licensed under Creative Commons Attribution-NonCommercial (CC BY-NC) https://creativecommons.org/licenses/by-nc/4.0/
#include <UTFT.h>
#include <URTouch.h>
UTFT myGLCD(ILI9325D_16,38,39,40,41); // Initialize display
URTouch myTouch(45,47,49,51,53); // Initialize touchscreen 6,5,4,3,2
#define REL_ENLARGER 42
#define BUZZER 52
#define BACKLIGHT 44
#define MainScreen 0
#define DevScreen 1
#define StopScreen 2
#define FixScreen 3
#define EnlargeScreen 4
#define AdjustScreen 99 // Here you adjust the timer (m:s.ms)
#define TuneScreen 98 //You adjust the internal delay here
extern uint8_t DotMatrix_M[];
extern uint8_t Ubuntu[];
int timerDelay;
bool enlState; //State of the enlarger relay
int brightness;
int minutes, seconds, milliseconds; //Current Timer milliseconds, seconds, minutes
int devMS, devS, devM, stopMS, stopS, stopM, fixMS, fixS, fixM, elMS, elS, elM;
int bx, by, spacingx, spacingy, offsetx, offsety; // Time Adjustment buttons
int MSbx, MSby, MSoffsety, xSpace; // Main screen buttons
int Tbx, Tby, Toffsetx, Toffsety; // Timer screen buttons
int TNbx, TNby, TNoffset; //Tune screen buttons
int scResX, scResY; //Screen resolution
int screen; //Indicates in what menu we are currently in
int senderScreen; //Stores which screen sent the command to adjust the timer
bool ShouldRedraw; //Indicates if the current screen must be redrawn
////// Drawing functions ///////////
void DrawMainScreen(void)
{
int spacingx = (scResX-3*MSbx)/4;
int spacingy = (scResY-2*MSoffsety-3*MSby)/2;
myGLCD.setColor(VGA_RED);
myGLCD.drawRoundRect(spacingx, MSoffsety, spacingx+MSbx, MSoffsety+MSby); //Dev button
myGLCD.setColor(VGA_RED);//VGA_YELLOW
myGLCD.drawRoundRect(2*spacingx+MSbx, MSoffsety, 2*(spacingx+MSbx), MSoffsety+MSby); //Stop button
myGLCD.setColor(VGA_RED);//VGA_WHITE
myGLCD.drawRoundRect(3*spacingx+2*MSbx, MSoffsety, 3*(spacingx+MSbx), MSoffsety+MSby); // Fix button
myGLCD.setColor(VGA_RED);//VGA_SILVER
myGLCD.drawRoundRect(2*spacingx+MSbx-xSpace, MSoffsety+spacingy+MSby, 2*(spacingx+MSbx)+xSpace, MSoffsety+spacingy+2*MSby); //Enlarge button
myGLCD.setColor(VGA_RED);
myGLCD.drawRoundRect(spacingx, scResY-MSoffsety-MSby, spacingx+MSbx+xSpace, scResY-MSoffsety); //Tunning button
myGLCD.drawRoundRect(scResX-spacingx-MSbx-xSpace, scResY-MSoffsety-MSby, scResX-spacingx, scResY-MSoffsety); //Enlarger on/off switch
myGLCD.setFont(DotMatrix_M);
myGLCD.setColor(VGA_RED);
int fx = myGLCD.getFontXsize();
int fy = myGLCD.getFontYsize();
myGLCD.print(String("DEV"), spacingx+(MSbx-3*fx)/2, MSoffsety+(MSby-fy)/2);
myGLCD.print(String("STOP"), 2*spacingx+MSbx+(MSbx-4*fx)/2, MSoffsety+(MSby-fy)/2);
myGLCD.print(String("FIX"), 3*spacingx+2*MSbx+(MSbx-3*fx)/2, MSoffsety+(MSby-fy)/2);
myGLCD.print(String("ENLARGE"), 2*spacingx+MSbx+(MSbx-7*fx)/2, MSoffsety+spacingy+MSby+(MSby-fy)/2);
myGLCD.print(String("DIMMER"), spacingx+(MSbx+xSpace-6*fx)/2, scResY-MSoffsety-(MSby+fy)/2);
if (enlState)
myGLCD.print(String("Enl. ON"), scResX-spacingx-(MSbx+xSpace+7*fx)/2, scResY-MSoffsety-(MSby+fy)/2);
else
myGLCD.print(String("Enl.OFF"), scResX-spacingx-(MSbx+xSpace+7*fx)/2, scResY-MSoffsety-(MSby+fy)/2);
}
void DrawTimerScreen(String txt)
{
myGLCD.setFont(DotMatrix_M);
myGLCD.setColor(VGA_RED);
int fx = myGLCD.getFontXsize();
int fy = myGLCD.getFontYsize();
myGLCD.print(txt, CENTER, Toffsety+(Tby-fy)/2); //Title text
myGLCD.print(String("Back"), Toffsetx+(Tbx-4*fx)/2, Toffsety+(Tby-fy)/2);
myGLCD.print(String("Adjust"), scResX-Tbx-Toffsetx+(Tbx-6*fx)/2, Toffsety+(Tby-fy)/2);
myGLCD.print(String("START / STOP"), CENTER, scResY-Toffsety-Tby+(Tby-fy)/2);
myGLCD.setColor(VGA_RED);
myGLCD.drawRoundRect(Toffsetx, Toffsety, Toffsetx+Tbx, Toffsety+Tby); //Back button
myGLCD.drawRoundRect(scResX-Toffsetx-Tbx, Toffsety, scResX-Toffsetx, Toffsety+Tby); //Adjust button
myGLCD.drawRoundRect(Toffsetx, scResY-Toffsety-Tby, scResX-Toffsetx, scResY-Toffsety); // Start/stop button
int chx = (scResX-7*24)/2; //Position of first character
int chy = (scResY-32)/2;
DrawTimerNumbers(chx, chy);
}
void DrawTimerNumbers(int posx, int posy)
{
myGLCD.setFont(Ubuntu);
myGLCD.setColor(VGA_RED);
// Assuming the type font is 24x32 pixels
myGLCD.printNumI(minutes, posx, posy, 2, '0');
myGLCD.print(String(':'), posx + 2*24, posy);
myGLCD.printNumI(seconds, posx + 3*24, posy, 2, '0');
myGLCD.print(String('.'), posx + 5*24, posy);
myGLCD.printNumI(milliseconds, posx + 6*24, posy);
}
// Main timing function
void DrawCountdownScreen(void)
{
int ms, mt, se; //Save the storred values
int chx = (scResX-7*24)/2; //Position of first character (assuming 24x32 font)
int chy = (scResY-32)/2;
digitalWrite(REL_ENLARGER, HIGH); //Make sure englarger is OFF
switch (screen){
case DevScreen:
mt = devM; se = devS; ms = devMS;
break;
case StopScreen:
mt = stopM; se = stopS; ms = stopMS;
break;
case FixScreen:
mt = fixM; se = fixS; ms = fixMS;
break;
case EnlargeScreen:
mt = elM; se = elS; ms = elMS;
digitalWrite(REL_ENLARGER, LOW); //Turn on the enlarger
break;
}
tone(BUZZER,1000,100);
while (minutes > 0 || seconds > 0 || milliseconds > 0)
{
DrawTimerNumbers(chx,chy);
delay(timerDelay); //38 for Ubuntu font
if (milliseconds == 0){
milliseconds = 9;
if (seconds == 0){
seconds = 59;
(minutes == 0) ? minutes = 0 : minutes--;
}
else
seconds--;
}
else
milliseconds--;
//Check if the timer should be stopped and stop right away. Then wait until you stop touching the screen
int tx, ty;
if (myTouch.dataAvailable()) {
myTouch.read();
tx = scResX-myTouch.getX();
ty = myTouch.getY();
if ((tx>=Toffsetx) && (tx<=scResX-Toffsetx) && (ty>=scResY-Toffsety-Tby) && (ty<=scResY-Toffsety)) //Button is at Toffsetx, scResY-Toffsety-Tby, scResX-Toffsetx, scResY-Toffsety
break;
}
}
// Make sure the enlarger is off and safelights are on
tone(BUZZER,1000,1000);
digitalWrite(REL_ENLARGER, HIGH);
WaitForButton(Toffsetx, scResY-Toffsety-Tby, scResX-Toffsetx, scResY-Toffsety); //Prevents double-tapping the start/stop where you stop the timer and the timer restarts right up
milliseconds = ms; seconds = se; minutes = mt; //Restore the timer
DrawTimerNumbers(chx,chy);
}
void DrawTimerAdjustScreen(void)
{
myGLCD.setColor(VGA_RED);
for (int ix=0; ix<3; ix++)
for (int iy=0; iy<2; iy++)
myGLCD.drawRoundRect(offsetx+ix*(bx+spacingx), offsety+iy*(by+spacingy), offsetx+((ix+1)*bx)+spacingx*ix, offsety+((iy+1)*by)+spacingy*iy);
myGLCD.setColor(VGA_RED);
myGLCD.setFont(DotMatrix_M);
int fx = myGLCD.getFontXsize();
int fy = myGLCD.getFontYsize();
myGLCD.print(String("+1m"),offsetx+(bx-3*fx)/2,offsety+(by-fy)/2); //{(bx-3*fx)/2} 3* because there are three characters to display
myGLCD.print(String("-1m"),offsetx+(bx-3*fx)/2,offsety+spacingy+by+(by-fy)/2);
myGLCD.print(String("+1s"),offsetx+bx+spacingx+(bx-3*fx)/2,offsety+(by-fy)/2); //{(bx-3*fx)/2} 3* because there are three characters to display
myGLCD.print(String("-1s"),offsetx+bx+spacingx+(bx-3*fx)/2,offsety+spacingy+by+(by-fy)/2);
myGLCD.print(String("+.1s"),offsetx+2*(bx+spacingx)+(bx-4*fx)/2,offsety+(by-fy)/2); //{(bx-3*fx)/2} 4* because there are four characters to display
myGLCD.print(String("-.1s"),offsetx+2*(bx+spacingx)+(bx-4*fx)/2,offsety+spacingy+by+(by-fy)/2);
myGLCD.setColor(VGA_PURPLE);
myGLCD.drawRoundRect(50,180,270,230);
myGLCD.setColor(VGA_RED);
myGLCD.print(String("SET TIME"), 50+(220-8*fx)/2, 180+(50-fy)/2);
int chx = (scResX-7*24)/2; //Position of first character
int chy = offsety+(spacingy-32)/2+by;
DrawTimerNumbers(chx, chy);
}
void DrawTuneScreen(void)
{
myGLCD.setColor(VGA_RED);//VGA_OLIVE
myGLCD.drawRoundRect(TNoffset, (scResY-TNby)/2, TNoffset+TNbx, (scResY+TNby)/2);
myGLCD.drawRoundRect(scResX-TNoffset-TNbx, (scResY-TNby)/2, scResX-TNoffset, (scResY+TNby)/2);
myGLCD.drawRoundRect(TNoffset, scResY-TNoffset-TNby, scResX-TNoffset, scResY-TNoffset);
myGLCD.setFont(DotMatrix_M);
int fx = myGLCD.getFontXsize();
int fy = myGLCD.getFontYsize();
myGLCD.print(String("BRIGHTNESS"),CENTER,TNoffset);
myGLCD.print(String("-"), TNoffset+(TNbx-fx)/2, (scResY-fy)/2);
myGLCD.print(String("+"), scResX-TNoffset-(TNbx+fx)/2, (scResY-fy)/2);
myGLCD.print(String("SET BRIGHTNESS"), CENTER, scResY-TNoffset-(TNby+fy)/2);
DrawInternalDelayValue();
}
void DrawInternalDelayValue(void)
{
myGLCD.setFont(Ubuntu);
int fx = myGLCD.getFontXsize();
int fy = myGLCD.getFontYsize();
myGLCD.setColor(VGA_RED);
myGLCD.printNumI(brightness, (scResX-3*fx)/2, (scResY-fy)/2, 3, '0');//timerDelay
}
// Draw a frame while a button is touched (to look like you select that button)
void WaitForButton(int x1, int y1, int x2, int y2)
{
//word curCol = myGLCD.getColor(); //Store the color active before the call
myGLCD.setColor(VGA_TEAL);
myGLCD.drawRoundRect (x1, y1, x2, y2);
while (myTouch.dataAvailable())
myTouch.read();
myGLCD.setColor(VGA_RED);
myGLCD.drawRoundRect (x1, y1, x2, y2);
}
///////// Touch parsing functions ////
void TouchMainScreen(int tx, int ty)
{
// Touched the DEV STOP FIX buttons
int spacingx = (scResX-3*MSbx)/4; // Spacing of buttons on the upper row
if ((ty >= MSoffsety) && (ty <= MSoffsety+MSby)){ //Upper row of buttons (DEV, STOP, FIX)
for (int ix=0; ix<3; ix++){
if ((tx >= (ix+1)*spacingx + ix*MSbx) && (tx <= (ix+1)*(spacingx+MSbx))){
WaitForButton((ix+1)*spacingx + ix*MSbx, MSoffsety, (ix+1)*(spacingx+MSbx), MSoffsety+MSby);
screen = ix+1;
ShouldRedraw = true;
}
}
}
// Touched the ENLARGE button
int spacingy = (scResY-2*MSoffsety-3*MSby)/2;
if ((tx >= 2*spacingx+MSbx-xSpace) && (tx <= 2*(spacingx+MSbx)+xSpace) && (ty >= MSoffsety+spacingy+MSby) && (ty <= MSoffsety+spacingy+2*MSby)){
WaitForButton(2*spacingx+MSbx-xSpace, MSoffsety+spacingy+MSby, 2*(spacingx+MSbx)+xSpace, MSoffsety+spacingy+2*MSby);
screen = EnlargeScreen;
ShouldRedraw = true;
}
// Touched the tunning/focus button
if ((ty >= scResY-MSoffsety-MSby) && (ty <= scResY-MSoffsety)){
if ((tx >= scResX-spacingx-MSbx-xSpace) && (tx <= scResX-spacingx)){ //Focus button
WaitForButton(scResX-spacingx-MSbx-xSpace, scResY-MSoffsety-MSby, scResX-spacingx, scResY-MSoffsety);
enlState = !enlState;
digitalWrite(REL_ENLARGER, enlState);
int fx = myGLCD.getFontXsize();
int fy = myGLCD.getFontYsize();
int spacingx = (scResX-3*MSbx)/4;
myGLCD.setColor(VGA_RED);
enlState ? myGLCD.print(String("Enl. ON"), scResX-spacingx-(MSbx+xSpace+7*fx)/2, scResY-MSoffsety-(MSby+fy)/2)
: myGLCD.print(String("Enl.OFF"), scResX-spacingx-(MSbx+xSpace+7*fx)/2, scResY-MSoffsety-(MSby+fy)/2);
//ShouldRedraw = true;
}
if ((tx >= spacingx) && (tx <= spacingx+MSbx+xSpace)){ //Tune button
WaitForButton(spacingx, scResY-MSoffsety-MSby, spacingx+MSbx+xSpace, scResY-MSoffsety);
screen = TuneScreen;
ShouldRedraw = true;
}
}
}
void TouchTimerScreen(int tx, int ty)
{
if ((tx >= Toffsetx) && (tx <= scResX-Toffsetx) && (ty >= scResY-Toffsety-Tby) && (ty <= scResY-Toffsety)){ // Start/stop button
WaitForButton(Toffsetx, scResY-Toffsety-Tby, scResX-Toffsetx, scResY-Toffsety);
DrawCountdownScreen();
}
if ((ty >= Toffsety) && (ty <= Toffsety+Tby)){ //Upper row
if ((tx >= Toffsetx) && (tx <= Toffsetx+Tbx)){ //Back button was pressed
WaitForButton(Toffsetx, Toffsety, Toffsetx+Tbx, Toffsety+Tby);
screen = MainScreen;
ShouldRedraw = true;
}
if ((tx >= scResX-Toffsetx-Tbx) && (tx <= scResX-Toffsetx)){ //Adjust button was pressed
WaitForButton(scResX-Toffsetx-Tbx, Toffsety, scResX-Toffsetx, Toffsety+Tby);
senderScreen = screen;
screen = AdjustScreen;
ShouldRedraw = true;
}
}
}
void TouchTimerAdjustScreen(int tx, int ty)
{
//// Determine which adjustment button was pressed
int row,col;
for (col=0; col<3; col++)
if ((tx >= offsetx+col*(bx+spacingx)) && (tx <= offsetx+((col+1)*bx)+spacingx*col))
for (row=0; row<2; row++)
if ((ty >= offsety+row*(by+spacingy)) && (ty <= offsety+((row+1)*by)+spacingy*row))
{
WaitForButton(offsetx+col*(bx+spacingx), offsety+row*(by+spacingy), offsetx+((col+1)*bx)+spacingx*col, offsety+((row+1)*by)+spacingy*row);
AdjustTimer(row,col);
int chx = (scResX-7*24)/2; //Position of first character
int chy = offsety+(spacingy-32)/2+by;
DrawTimerNumbers(chx, chy);
}
//Determine if the SET TIME button was pressed (50,180,270,230), and store the new values
if ((tx >= 50) && (tx <= 270) && (ty >= 180) && (ty <= 230)){
WaitForButton(50,180,270,230);
screen = senderScreen;
ShouldRedraw = true;
switch (senderScreen){
case DevScreen:
devM = minutes; devS = seconds; devMS = milliseconds;
break;
case StopScreen:
stopM = minutes; stopS = seconds; stopMS = milliseconds;
break;
case FixScreen:
fixM = minutes; fixS = seconds; fixMS = milliseconds;
break;
case EnlargeScreen:
elM = minutes; elS = seconds; elMS = milliseconds;
break;
}
}
}
// Fine tunes the internal timer. Remember that this timer doesn't actually measure seconds. The time between two ticks (resolution 0.1s)
// is the time to refresh the screen plus some delay. The refresh time should be constant (and you can't adjust it anyway) and the delay is this delay you tune here.
void TouchTuneScreen(int tx, int ty)
{
// Decrement
if ((ty >= (scResY-TNby)/2) && (ty <= (scResY+TNby)/2)){ //Adjust delay
if ((tx >= TNoffset) && (tx <= TNoffset+TNbx)){ // Decrement delay
WaitForButton(TNoffset, (scResY-TNby)/2, TNoffset+TNbx, (scResY+TNby)/2);
(brightness == 255) ? brightness = 255 : brightness++; //Backlight is driven in inverse logic
analogWrite(BACKLIGHT, brightness);
//(timerDelay == 2) ? timerDelay = 2 : timerDelay--;
DrawInternalDelayValue();
}
//Increment
if ((tx >= scResX-TNoffset-TNbx) && (tx <= scResX-TNoffset)){
WaitForButton(scResX-TNoffset-TNbx, (scResY-TNby)/2, scResX-TNoffset, (scResY+TNby)/2);
(brightness == 2) ? brightness = 2 : brightness--; //Backlight is driven in inverse logic
analogWrite(BACKLIGHT, brightness);
//(timerDelay == 999) ? timerDelay = 999 : timerDelay++;
DrawInternalDelayValue();
}
}
if ((tx >= TNoffset) && (tx <= scResX-TNoffset) && (ty >= scResY-TNoffset-TNby) && (ty <= scResY-TNoffset)){
WaitForButton(TNoffset, scResY-TNoffset-TNby, scResX-TNoffset, scResY-TNoffset);
screen = MainScreen;
ShouldRedraw = true;
}
}
// Increments/decrements timer values:
void AdjustTimer(int r, int c)
{
switch (r){
case 0: //r=0 increment
switch (c){
case 0: //Minutes
(minutes == 99) ? minutes = 0 : minutes++; //Capping at 99 minutes
break;
case 1: //Seconds
(seconds == 59) ? seconds = 0 : seconds++; //Use standard 60sec in a minute
break;
case 2: //Milliseconds
(milliseconds == 9) ? milliseconds = 0 : milliseconds++; //Timer will have 0.1sec resolution
break;
}
break;
case 1://r=1 increment
switch (c){
case 0: //msec, sec, mts;
(minutes == 0) ? minutes = 99 : minutes--;
break;
case 1:
(seconds == 0) ? seconds = 59 : seconds--;
break;
case 2:
(milliseconds == 0) ? milliseconds = 9 : milliseconds--;
break;
}
break;
}
}
////////// Standard functions //////////////
void setup()
{
// Initial setup
myGLCD.InitLCD();
myGLCD.clrScr();
myGLCD.setBrightness(0);
myGLCD.setBackColor(VGA_BLACK);
scResX = myGLCD.getDisplayXSize();
scResY = myGLCD.getDisplayYSize();
myTouch.InitTouch();
myTouch.setPrecision(PREC_MEDIUM);
pinMode(REL_ENLARGER, OUTPUT);
enlState = true; //Our relay works in inverse logic (true means not engaged)
digitalWrite(REL_ENLARGER, enlState);
pinMode(BACKLIGHT, OUTPUT);
brightness = 150;
analogWrite(BACKLIGHT, brightness);
timerDelay = 38; //good for the ubuntu font
// Adjustment buttons dimensions dimensions
bx = 80; //Lenght of button
by = 40; //Width of button
spacingx = 15;
spacingy = 80;
offsetx = 25;
offsety = 10;
// Main screen buttons dimensions
MSbx = 90;
MSby = 50;
xSpace = 40; //"Enlarge" text is too long so ENLARGE button has extra space on both sides
MSoffsety = 20;
// Timer buttons dimensions
Tbx = 100;
Tby = 40;
Toffsetx = 18;
Toffsety = 20;
// Tune buttons dimensions
TNbx = 60;
TNby = 40;
TNoffset = 30;
// Initialize timer values
devMS = 0; devS = 30; devM = 1; //Default paper developing time
stopMS = 0; stopS = 15; stopM = 0; //Default stop time
fixMS = 0; fixS = 30; fixM = 1; //Default fixing time
elMS = 0; elS = 3; elM = 0; //Default enlarging time
screen = MainScreen; //At startup we begin with the main menu
ShouldRedraw = true;
}
void loop()
{
int x, y; //Possition where you touch the screen
if (ShouldRedraw){
myGLCD.clrScr();
switch (screen){
case MainScreen:
DrawMainScreen();
break;
case DevScreen:
minutes = devM; seconds = devS; milliseconds = devMS;
DrawTimerScreen(String("DEV"));
break;
case StopScreen:
minutes = stopM; seconds = stopS; milliseconds = stopMS;
DrawTimerScreen(String("STOP"));
break;
case FixScreen:
minutes = fixM; seconds = fixS; milliseconds = fixMS;
DrawTimerScreen(String("FIX"));
break;
case AdjustScreen:
DrawTimerAdjustScreen();
break;
case EnlargeScreen:
minutes = elM; seconds = elS; milliseconds = elMS;
DrawTimerScreen(String("ENLR"));
break;
case TuneScreen:
DrawTuneScreen();
break;
default:
myGLCD.setFont(DotMatrix_M);
myGLCD.setColor(VGA_RED);
myGLCD.print(String("ERR: No such screen"), CENTER, 100);
delay(2000);
myGLCD.clrScr();
screen = MainScreen;
DrawMainScreen();
}
ShouldRedraw = false;
}
if (myTouch.dataAvailable()){
myTouch.read();
x=scResX-myTouch.getX();
y=myTouch.getY();
switch (screen){
case MainScreen:
TouchMainScreen(x,y);
break;
case DevScreen:
case StopScreen:
case FixScreen:
case EnlargeScreen:
TouchTimerScreen(x,y);
break;
case AdjustScreen:
TouchTimerAdjustScreen(x,y);
break;
case TuneScreen:
TouchTuneScreen(x,y);
break;
}
}
}