/**************************************************************************** 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 ); }