/****************************************************************************
SAFE_COMBO_02.C
PIC 16F628 Combination Lock
- resets to first expected digit two seconds after last key is pressed
- uses PWM to reduce current to coil after initial pulse
--------- ----------
+5 --14-|VCC B0|-17-----|C1 |
| B1|-18-----|C2 |
Gnd ---5-| B2|-1------|C3 |
6MHz XTAL --16-| B4|-2------|R1 KBD |
XTAL --15-| B5|-6------|R2 |
| B6|-7------|R3 |
| B7|-8------|R4 |
| 16F628 | ----------
| |
| B3|-6--- LOCK SOLENOID
| A1|-18-- LED
---------
=========
| 1 2 3 | R0
| 4 5 6 | R1
| 7 8 9 | R2
| * 0 # | R3
=========
C0 C1 C2
Keyboard connector is (backside): C2 C1 C0 R3 R2 R1 R0
Oscillator = 6MHz crystal
Jon Fick 03/09/07
***************************************************************************/
#include <16F628A.h>
#include
// Set configuration bits in the PIC processor
#fuses HS, NOPROTECT, NOWDT, PUT, BROWNOUT, NOMCLR, NOLVP
#define COMBO_1 '1'
#define COMBO_2 '2'
#define COMBO_3 '3'
#define COMBO_4 '4'
#define COMBO_5 '5'
#define COMBO_6 '6'
#define KBD_C1 PIN_B0
#define KBD_C2 PIN_B1
#define KBD_C3 PIN_B2
#define KBD_R1 PIN_B4
#define KBD_R2 PIN_B5
#define KBD_R3 PIN_B6
#define KBD_R4 PIN_B7
#define LOCK_OUT PIN_B3
#define LED PIN_A1
#define NOKEY 0xFF
#define RESET_KBD_COUNT 46 // at 23 counts/second
#define LOCK_HIGH 255 // full PWM duty cycle
#define LOCK_HIGH_TIME 30 // mS at full coil current
#define LOCK_MED 20 // partial PWM duty cycle
#define LOCK_MED_TIME 1450 // mS at partial coil current
#define LOCK_OFF 0 // no PWM current
#use delay ( clock = 6000000 ) // sets appropriate compiler constants
#use standard_io ( A )
#use standard_io ( B )
char GetKey ( void ); // prototypes
static char cKbdTimeoutFlag, cLedCount;
#int_rtcc
void TimerInterrupt ( void ) // 43mS tic, 23/second
{
if ( cKbdTimeoutFlag != 0 )
{
cKbdTimeoutFlag--; // count down to zero
}
if ( cLedCount++ > 12 )
{
cLedCount = 0;
}
if ( cLedCount > 6 )
{
output_high ( LED );
}
else
{
output_low ( LED );
}
}
void main ( void )
{
delay_ms ( 100 ); // power up delay
output_low ( LOCK_OUT ); // turn off lock solenoid */
output_low ( LED );
port_b_pullups ( TRUE ); /* enable pullups */
setup_counters ( RTCC_INTERNAL, RTCC_DIV_256 );
cLedCount = 0;
// PWM is for relay current control
setup_ccp1 ( CCP_PWM ); // set for PWM mode
//The cycle time will be ( 1 / clock ) * 4 * t2div * ( period + 1 )
// 1/6000000 * 4 * 1 * 64 = 42uS = 23KHz
setup_timer_2 ( T2_DIV_BY_1, 64, 1 ); // set PWM period
// duty cycle = value * ( 1 / clock ) * t2div
// val * 1/6000000 * 1 = 1.2uS
set_pwm1_duty ( LOCK_OFF ); // set output off
enable_interrupts ( INT_RTCC ); /* turn on timer interrupt */
enable_interrupts ( GLOBAL ); /* enable interrupts */
while ( TRUE )
{
while ( TRUE )
{
if ( GetKey() != COMBO_1 )
{
break;
}
if ( GetKey() != COMBO_2 )
{
break;
}
if ( GetKey() != COMBO_3 )
{
break;
}
if ( GetKey() != COMBO_4 )
{
break;
}
if ( GetKey() != COMBO_5 )
{
break;
}
if ( GetKey() != COMBO_6 )
{
break;
}
set_pwm1_duty ( LOCK_HIGH ); // set output high current
delay_ms ( LOCK_HIGH_TIME );
set_pwm1_duty ( LOCK_MED ); // set output medium current
delay_ms ( LOCK_MED_TIME );
set_pwm1_duty ( LOCK_OFF ); // set output off
}
}
}
char GetKey ( void )
{
char cKey;
cKbdTimeoutFlag = RESET_KBD_COUNT;
cKey = NOKEY; /* default is invalidated key */
output_low ( KBD_R1 ); /* make all four rows low */
output_low ( KBD_R2 );
output_low ( KBD_R3 );
output_low ( KBD_R4 );
delay_ms ( 5 ); /* wait for row lines to settle */
// wait until a button is pressed
while ( ( input ( KBD_C1 ) == HIGH ) && ( input ( KBD_C2 ) == HIGH ) && ( input ( KBD_C3 ) == HIGH ) )
{
if ( cKbdTimeoutFlag == 0 ) // if counted down to zero
{
return ( cKey ); // timed out, return NOKEY
}
}
while ( TRUE )
{
output_low ( KBD_R1 ); // try Row 1
output_high ( KBD_R2 );
output_high ( KBD_R3 );
output_high ( KBD_R4 );
delay_ms ( 1 );
if ( input ( KBD_C1 ) == LOW )
{
cKey = '1';
break;
}
if ( input ( KBD_C2 ) == LOW )
{
cKey = '2';
break;
}
if ( input ( KBD_C3 ) == LOW )
{
cKey = '3';
break;
}
output_high ( KBD_R1 ); // try Row 2
output_low ( KBD_R2 );
output_high ( KBD_R3 );
output_high ( KBD_R4 );
delay_ms ( 1 );
if ( input ( KBD_C1 ) == LOW )
{
cKey = '4';
break;
}
if ( input ( KBD_C2 ) == LOW )
{
cKey = '5';
break;
}
if ( input ( KBD_C3 ) == LOW )
{
cKey = '6';
break;
}
output_high ( KBD_R1 ); // try Row 3
output_high ( KBD_R2 );
output_low ( KBD_R3 );
output_high ( KBD_R4 );
delay_ms ( 1 );
if ( input ( KBD_C1 ) == LOW )
{
cKey = '7';
break;
}
if ( input ( KBD_C2 ) == LOW )
{
cKey = '8';
break;
}
if ( input ( KBD_C3 ) == LOW )
{
cKey = '9';
break;
}
output_high ( KBD_R1 ); // try Row 4
output_high ( KBD_R2 );
output_high ( KBD_R3 );
output_low ( KBD_R4 );
delay_ms ( 1 );
if ( input ( KBD_C1 ) == LOW )
{
cKey = '*';
break;
}
if ( input ( KBD_C2 ) == LOW )
{
cKey = '0';
break;
}
if ( input ( KBD_C3 ) == LOW )
{
cKey = '#';
break;
}
break; // break anyway to ensure no endless loop
}
delay_ms ( 5 );
// wait until all buttons are up
output_low ( KBD_R1 ); /* make all four rows low */
output_low ( KBD_R2 );
output_low ( KBD_R3 );
output_low ( KBD_R4 );
while ( ( input ( KBD_C1 ) == LOW ) || ( input ( KBD_C2 ) == LOW ) || ( input ( KBD_C3 ) == LOW ) );
// make all four rows high
output_high ( KBD_R1 );
output_high ( KBD_R2 );
output_high ( KBD_R3 );
output_high ( KBD_R4 );
return ( cKey );
}