/****************************************************************************
DARK01.C
This is a darkroom lamp control system.
---------
+5--20-|Vdd |
+5---1-|Mclr |
Gnd---8-|Vss |
Gnd--19-|Vss |
4MHz--10-|Xtal |
---9-|Xtal |
| |
| 16F873 |-26-->--- Relay K2 safe lamp
In from | |-27-->--- Relay K3 enlarger lamp
photocell | |-28-->--- audible alarm
amplifier --->--2-|A0 |
| |
| |
Switch A ---->-21-|B0 |
Switch B ---->-22-|B1 |
Switch B ---->-23-|B2 | ---------
Switch B ---->-24-|B3 C4|-15-->----11-|D4 |
| C5|-16-->----12-|D5 |
| C6|-17-->----13-|D6 |
| C7|-18-->----14-|D7 |
| | | |-3--20K pot (contrast)
| C3|-14-->-----6-|EN |
| C2|-13-->-----4-|RS |
| | | |
| | +5-2-| |
| | Gnd-1-| |
| | Gnd-5-| |
| | | DISPLAY |
--------- ---------
*/
#case
#include < 16F873.H >
#include < jonsinc.h >
#device *=16 ADC=10
#fuses XT, NOPROTECT, PUT, NOWDT, BROWNOUT, NOLVP, NOCPD, NOWRT
/* INTERNAL EEPROM ADDRESS ASSIGNMENTS */
#define ENLARGE_TIME 0
#define TIMER_MINUTES 1
#define TIMER_SECONDS 2
#define PAPER_SPEED_HI 3
#define PAPER_SPEED_LO 4
/* LCD STUFF */
#define LCD_D0 PIN_C4
#define LCD_D1 PIN_C5
#define LCD_D2 PIN_C6
#define LCD_D3 PIN_C7
#define LCD_EN PIN_C3
#define LCD_RS PIN_C2
#define FIRST_LINE 0x00
#define SECOND_LINE 0x40
#define CLEAR_DISP 0x01
#define SWITCH_A PIN_B0
#define SWITCH_B PIN_B1
#define SWITCH_C PIN_B2
#define SWITCH_D PIN_B3
#define RELAY_SAFELAMP PIN_B4
#define RELAY_ENLARGER PIN_B5
#define ALERT PIN_B7
#define CAL_PAPER_SPEED 500
#define AUTOREPEAT_DELAY 150
#define DEBOUNCE_DELAY 20
#use delay ( clock=4000000 )
#use standard_io ( A )
#use standard_io ( B )
#use standard_io ( C )
void DisplayMenuFocus ( void );
void DisplayMenuExpose ( void );
void DisplayMenuTimer ( void );
void LCD_Init ( void );
void LCD_SetPosition ( unsigned int cX );
void LCD_PutChar ( unsigned int cX );
void LCD_PutCmd ( unsigned int cX );
void LCD_PulseEnable ( void );
void LCD_SetData ( unsigned int cX );
void DebounceSwitchA ( void );
void DebounceSwitchB ( void );
void DebounceSwitchC ( void );
void DebounceSwitchD ( void );
static char cEnlargeTime, cMenu;
static char cSafeLamp, cEnlargerLamp;
static char cAlarmMinutes, cAlarmSeconds;
static long iPaperSpeed;
/******************************************************************************/
void main ( void )
{
char cX;
// preset all output bits
output_high ( RELAY_SAFELAMP );
output_low ( RELAY_ENLARGER );
output_low ( ALERT );
// initilize screen
LCD_Init();
LCD_PutCmd ( CLEAR_DISP );
LCD_SetPosition ( FIRST_LINE );
printf ( LCD_PutChar, "DARKROOM SYSTEM " );
LCD_SetPosition ( SECOND_LINE );
printf ( LCD_PutChar, " v1.1 " );
delay_ms ( 1000 );
LCD_SetPosition ( FIRST_LINE );
printf ( LCD_PutChar, " Jon Fick " );
LCD_SetPosition ( SECOND_LINE );
printf ( LCD_PutChar, " 01/20/03 " );
delay_ms ( 500 );
LCD_PutCmd ( CLEAR_DISP );
/* RESTORE PREVIOUS STATE */
cEnlargeTime = read_eeprom ( ENLARGE_TIME );
if ( cEnlargeTime > 99 )
{
cEnlargeTime = 10; // default if EEPROM not written before
}
cAlarmMinutes = read_eeprom ( TIMER_MINUTES );
if ( cAlarmMinutes > 59 )
{
cAlarmMinutes = 0; // default if EEPROM not written before
}
cAlarmSeconds = read_eeprom ( TIMER_SECONDS );
if ( ( cAlarmSeconds > 59 ) || ( ( cAlarmSeconds % 10 ) != 0 ) )
{
cAlarmSeconds = 0; // default if EEPROM not written before or not an increment of 10
}
iPaperSpeed = ( 256 * read_eeprom ( PAPER_SPEED_HI ) ) + read_eeprom ( PAPER_SPEED_LO );
if ( ( iPaperSpeed > 1000 ) || ( ( iPaperSpeed % 50 ) != 0 ) )
{
iPaperSpeed = 500; // default if EEPROM not written before or not an increment of 50
}
cSafeLamp = ON; // safelamp state
port_b_pullups ( TRUE ); // turn on port B pullups
setup_adc_ports ( RA0_ANALOG ); /* these three statements set up the ADC */
setup_adc ( ADC_CLOCK_INTERNAL ); /* clock source */
set_adc_channel ( 0 ); /* select channel */
// check if setup mode if SWITCH_A held down during reset
if ( input ( SWITCH_A ) == LOW )
{
LCD_PutCmd ( CLEAR_DISP );
LCD_SetPosition ( FIRST_LINE );
printf ( LCD_PutChar, "Paper speed " );
LCD_SetPosition ( SECOND_LINE );
printf ( LCD_PutChar, "NXT DEC INC " );
DebounceSwitchA();
while ( TRUE )
{
if ( input ( SWITCH_A ) == LOW )
{
write_eeprom ( PAPER_SPEED_HI, iPaperSpeed / 256 ); // save speed to EEPROM
write_eeprom ( PAPER_SPEED_LO, iPaperSpeed % 256 );
break; // drop out to main menu sequence
}
if ( input ( SWITCH_B ) == LOW )
{
if ( iPaperSpeed > 50 )
{
iPaperSpeed -= 50; // decrement by 50
delay_ms ( AUTOREPEAT_DELAY ); // autorepeat delay
}
}
if ( input ( SWITCH_C ) == LOW )
{
if ( iPaperSpeed <= 949 )
{
iPaperSpeed += 50; // increment by 50
delay_ms ( AUTOREPEAT_DELAY ); // autorepeat delay
}
}
// display adjusted paper speed
LCD_SetPosition ( FIRST_LINE + 12 );
printf ( LCD_PutChar, "%03lu", iPaperSpeed );
}
}
while ( TRUE )
{
LCD_PutCmd ( CLEAR_DISP );
LCD_SetPosition ( FIRST_LINE );
printf ( LCD_PutChar, "Select... " );
LCD_SetPosition ( SECOND_LINE );
printf ( LCD_PutChar, "SAF FOC EXP TIMR" );
while ( TRUE )
{
if ( input ( SWITCH_A ) == LOW )
{
DebounceSwitchA();
if ( cSafeLamp == ON ) // toggle safelight
{
cSafeLamp = OFF;
output_low ( RELAY_SAFELAMP );
}
else
{
cSafeLamp = ON;
output_high ( RELAY_SAFELAMP );
}
break;
}
if ( input ( SWITCH_B ) == LOW )
{
DebounceSwitchB();
DisplayMenuFocus();
break;
}
if ( input ( SWITCH_C ) == LOW )
{
DebounceSwitchC();
DisplayMenuExpose();
break;
}
if ( input ( SWITCH_D ) == LOW )
{
DebounceSwitchD();
DisplayMenuTimer();
break;
}
delay_ms ( 100 );
}
}
}
void DisplayMenuFocus ( void )
{
char cCnt, cAdcCnt;
long iAdc, iAdcAvg;
float fAdc;
cAdcCnt = 0; // reset to zero readings count
iAdcAvg = 0; // reset average to zero
LCD_PutCmd ( CLEAR_DISP );
LCD_SetPosition ( FIRST_LINE );
printf ( LCD_PutChar, "Expo Meter " );
LCD_SetPosition ( SECOND_LINE );
printf ( LCD_PutChar, "RET " );
output_high ( RELAY_ENLARGER );
while ( TRUE )
{
if ( input ( SWITCH_A ) == LOW )
{
DebounceSwitchA();
break; // drop out
}
iAdc = read_adc(); // read ADC
if ( cAdcCnt++ < 20 ) // if less than ten counts
{
iAdcAvg += iAdc; // add ADC reading into average
}
else
{
iAdcAvg /= 20; // calculate average
// scale reading
fAdc = ( float ) iAdcAvg / 1024 * 200 * iPaperSpeed / CAL_PAPER_SPEED;
// display reading
LCD_SetPosition ( FIRST_LINE + 11 );
printf ( LCD_PutChar, "%3.0f%% ", fAdc );
cAdcCnt = 0; // reset
iAdcAvg = 0; // reset
}
delay_ms ( 10 );
if ( cCnt > 200 ) // turn safelight off if here more than 2 seconds
{
output_low ( RELAY_SAFELAMP );
}
}
output_low ( RELAY_ENLARGER );
output_high ( RELAY_SAFELAMP );
cSafeLamp = ON;
}
void DisplayMenuExpose ( void )
{
char cEnlargeLampState, cCnt;
LCD_PutCmd ( CLEAR_DISP );
LCD_SetPosition ( FIRST_LINE );
printf ( LCD_PutChar, "Exposure sec" );
LCD_SetPosition ( SECOND_LINE );
printf ( LCD_PutChar, "RET DEC BEG INC " );
DebounceSwitchD(); // prevent repetitive cycling
while ( TRUE )
{
if ( input ( SWITCH_A ) == LOW )
{
DebounceSwitchA();
break; // drop out
}
if ( input ( SWITCH_B ) == LOW )
{
if ( cEnlargeTime != 1 )
{
cEnlargeTime--; // decrement
delay_ms ( AUTOREPEAT_DELAY ); // autorepeat delay
}
}
if ( input ( SWITCH_D ) == LOW )
{
if ( cEnlargeTime != 99 )
{
cEnlargeTime++; // increment
delay_ms ( AUTOREPEAT_DELAY ); // autorepeat delay
}
}
if ( input ( SWITCH_C ) == LOW ) // start exposure
{
DebounceSwitchD(); // prevent repetitive cycling
write_eeprom ( ENLARGE_TIME, cEnlargeTime ); // save time to EEPROM
cCnt = cEnlargeTime; // get time
LCD_PutCmd ( CLEAR_DISP );
LCD_SetPosition ( FIRST_LINE );
printf ( LCD_PutChar, "Exposing %02u sec", cCnt ); // display initial time
LCD_SetPosition ( SECOND_LINE );
printf ( LCD_PutChar, " RET " );
cEnlargeLampState = ON;
output_high ( RELAY_ENLARGER ); // turn enlarge lamp on
while ( cEnlargeLampState == ON )
{
// delay
delay_ms ( 984 ); // delay one second, adjusted
// decrement time
cCnt--; // decrement count
// display new time
LCD_SetPosition ( FIRST_LINE + 10 );
printf ( LCD_PutChar, "%02u", cCnt ); // display new value
// check if time done
if ( cCnt == 0 ) // if counted down to zero
{
cEnlargeLampState = OFF; // falls out of while()
}
// check if stop switch pressed
if ( input ( SWITCH_D ) == LOW ) // if button pressed
{
cEnlargeLampState = OFF;
}
}
output_low ( RELAY_ENLARGER ); // turn enlarger lamp off
for ( cCnt = 0; cCnt < 255; cCnt++ )
{
output_high ( ALERT ); // beep
delay_us ( 120 );
output_low ( ALERT );
delay_us ( 120 );
}
break;
}
// display adjusted time
LCD_SetPosition ( FIRST_LINE + 10 );
printf ( LCD_PutChar, "%02u", cEnlargeTime );
}
}
void DisplayMenuTimer ( void )
{
char cM, cS, cTimerState, cAlarmState, cCnt;
//cM = cAlarmMinutes; // get presets
//cS = cAlarmSeconds;
LCD_PutCmd ( CLEAR_DISP );
LCD_SetPosition ( FIRST_LINE );
printf ( LCD_PutChar, "Timer : " );
LCD_SetPosition ( SECOND_LINE );
printf ( LCD_PutChar, "RET DEC INC BEG " );
DebounceSwitchD(); // prevent repetitive cycling
while ( TRUE )
{
if ( input ( SWITCH_A ) == LOW )
{
DebounceSwitchA();
break; // drop out
}
if ( input ( SWITCH_B ) == LOW )
{
if ( cAlarmSeconds != 0 ) // seconds isn't zero
{
cAlarmSeconds -= 10; // decrement seconds by 10
}
else // seconds is zero
{
if ( cAlarmMinutes != 0 )
{
cAlarmSeconds = 50; // wrap seconds to 50
cAlarmMinutes--; // decrement minutes
}
else
{
// do nothing, don't decrement any lower
}
}
delay_ms ( AUTOREPEAT_DELAY ); // autorepeat delay
}
if ( input ( SWITCH_C ) == LOW )
{
if ( cAlarmSeconds != 50 ) // seconds isn't 50
{
cAlarmSeconds += 10; // increment seconds by 10
}
else // seconds is 50
{
if ( cAlarmMinutes != 59 )
{
cAlarmSeconds = 0; // wrap seconds to 00
cAlarmMinutes++; // increment minutes
}
else
{
// do nothing, don't increment any higher
}
}
delay_ms ( AUTOREPEAT_DELAY ); // autorepeat delay
}
if ( input ( SWITCH_D ) == LOW ) // start timer
{
DebounceSwitchD();
write_eeprom ( TIMER_MINUTES, cAlarmMinutes ); // save time to EEPROM
write_eeprom ( TIMER_SECONDS, cAlarmSeconds ); // save time to EEPROM
cM = 0; // start at zero
cS = 0;
LCD_PutCmd ( CLEAR_DISP );
LCD_SetPosition ( FIRST_LINE );
printf ( LCD_PutChar, "Timing %02u:%02u ", cM, cS ); // display preset time
LCD_SetPosition ( SECOND_LINE );
printf ( LCD_PutChar, " RET " );
cTimerState = ON;
cAlarmState = OFF; // default to alarm off
while ( cTimerState == ON )
{
if ( ( cM == cAlarmMinutes ) && ( cS == cAlarmSeconds ) &&
( ( cAlarmMinutes != 0 ) || ( cAlarmSeconds != 0 ) ) )
{
cAlarmState = ON; // turn alarm on
LCD_SetPosition ( SECOND_LINE + 8 );
printf ( LCD_PutChar, "SIL" );
}
if ( cAlarmState == OFF )
{
// delay
delay_ms ( 943 ); // delay one second, adjusted
}
else
{
// beep
for ( cCnt = 0; cCnt < 255; cCnt++ )
{
output_high ( ALERT ); // beep
delay_us ( 120 );
output_low ( ALERT );
delay_us ( 120 );
}
// delay
delay_ms ( 878 ); // delay remainder of one second, adjusted
if ( input ( SWITCH_C ) == LOW )
{
cAlarmState = OFF; // silence
LCD_SetPosition ( SECOND_LINE + 8 );
printf ( LCD_PutChar, " " );
}
}
// increment time
if ( cS != 59 ) // if seconds isn't 59
{
cS++; // increment seconds
}
else // if seconds is zero
{
if ( cM != 59 ) // if minutes isn't 59
{
cS = 00; // wrap seconds to 00
cM++; // increment minutes
}
else
{
cTimerState = OFF;
}
}
// display new time
LCD_SetPosition ( FIRST_LINE + 10 );
printf ( LCD_PutChar, "%02u", cM );
LCD_SetPosition ( FIRST_LINE + 13 );
printf ( LCD_PutChar, "%02u", cS );
// check if stop switch pressed
if ( input ( SWITCH_D ) == LOW ) // if button pressed
{
cTimerState = OFF;
}
}
break;
}
// display adjusted time
LCD_SetPosition ( FIRST_LINE + 10 );
printf ( LCD_PutChar, "%02u", cAlarmMinutes );
LCD_SetPosition ( FIRST_LINE + 13 );
printf ( LCD_PutChar, "%02u", cAlarmSeconds );
}
}
void DebounceSwitchA ( void )
{
char cX;
for ( cX = 0; cX < DEBOUNCE_DELAY; cX++ )
{
if ( input ( SWITCH_A ) == LOW )
{
cX = 0;
}
delay_ms ( 1 );
}
}
void DebounceSwitchB ( void )
{
char cX;
for ( cX = 0; cX < DEBOUNCE_DELAY; cX++ )
{
if ( input ( SWITCH_B ) == LOW )
{
cX = 0;
}
delay_ms ( 1 );
}
}
void DebounceSwitchC ( void )
{
char cX;
for ( cX = 0; cX < DEBOUNCE_DELAY; cX++ )
{
if ( input ( SWITCH_C ) == LOW )
{
cX = 0;
}
delay_ms ( 1 );
}
}
void DebounceSwitchD ( void )
{
char cX;
for ( cX = 0; cX < DEBOUNCE_DELAY; cX++ )
{
if ( input ( SWITCH_D ) == LOW )
{
cX = 0;
}
delay_ms ( 1 );
}
}
/******************************************************************************/
void LCD_Init ( void )
{
LCD_SetData ( 0x00 );
delay_ms ( 200 ); /* wait enough time after Vdd rise */
output_low ( LCD_RS );
LCD_SetData ( 0x03 ); /* init with specific nibbles to start 4-bit mode */
LCD_PulseEnable();
LCD_PulseEnable();
LCD_PulseEnable();
LCD_SetData ( 0x02 ); /* set 4-bit interface */
LCD_PulseEnable(); /* send dual nibbles hereafter, MSN first */
LCD_PutCmd ( 0x2C ); /* function set (all lines, 5x7 characters) */
LCD_PutCmd ( 0x0C ); /* display ON, cursor off, no blink */
LCD_PutCmd ( 0x01 ); /* clear display */
LCD_PutCmd ( 0x06 ); /* entry mode set, increment */
}
void LCD_SetPosition ( unsigned int cX )
{
/* this subroutine works specifically for 4-bit Port A */
LCD_SetData ( swap ( cX ) | 0x08 );
LCD_PulseEnable();
LCD_SetData ( swap ( cX ) );
LCD_PulseEnable();
}
void LCD_PutChar ( unsigned int cX )
{
/* this subroutine works specifically for 4-bit Port A */
output_high ( LCD_RS );
LCD_SetData ( swap ( cX ) ); /* send high nibble */
LCD_PulseEnable();
LCD_SetData ( swap ( cX ) ); /* send low nibble */
LCD_PulseEnable();
output_low ( LCD_RS );
}
void LCD_PutCmd ( unsigned int cX )
{
/* this subroutine works specifically for 4-bit Port A */
LCD_SetData ( swap ( cX ) ); /* send high nibble */
LCD_PulseEnable();
LCD_SetData ( swap ( cX ) ); /* send low nibble */
LCD_PulseEnable();
}
void LCD_PulseEnable ( void )
{
output_high ( LCD_EN );
delay_us ( 10 );
output_low ( LCD_EN );
delay_ms ( 5 );
}
void LCD_SetData ( unsigned int cX )
{
output_bit ( LCD_D0, cX & 0x01 );
output_bit ( LCD_D1, cX & 0x02 );
output_bit ( LCD_D2, cX & 0x04 );
output_bit ( LCD_D3, cX & 0x08 );
}