 title  "Delay"
;
;
;
  LIST P=16F84, R=DEC          ;  16C84 Runs at 2 MHz or 4 MHz
  errorlevel 0,-305
  INCLUDE "p16f84.inc"

;
; Schematic diagram using a LED array as the display device:
;
;                                -------   -------
;                               -¦ra2         ra1¦-
;                                ¦               ¦
;     +5VDC____/\/\____          ¦               ¦
;                     ¦         -¦ra3         ra0¦_______ out to relay driver
;                     ¦          ¦               ¦
;       100    _\/_   ¦          ¦               ¦
;    ____/\/\__o  o___¦____in____¦ra4        OSC2¦_______________¦ ¦_        cap 33pF
;    ¦                           ¦     PIC       ¦   __¦__       ¦ ¦ ¦
;   ___                 1k       ¦    16F84      ¦  ¦_____¦          ¦    Xtal 4Mhz
;    _      +5VDC ______/\/\_____¦/Mclr      OSC1¦_____¦_________¦ ¦_¦       cap 33pF
;                                ¦               ¦               ¦ ¦ ¦
;                                ¦               ¦                   ¦
;             ___________________¦Vss         Vdd¦____ + 5VDC        ¦
;             ¦                  ¦               ¦                   ¦
;             ¦                  ¦               ¦                   ¦
;             ¦_______¦/¦__/\/\__¦rb0         rb7¦_____/\/\____¦\¦___¦     8 LEDS and 8 resistors (330 ohms)
;             ¦       ¦\¦        ¦               ¦             ¦/¦   ¦
;             ¦                  ¦               ¦                   ¦
;             ¦_______¦/¦__/\/\__¦rb1         rb6¦_____/\/\____¦\¦___¦ 
;             ¦       ¦\¦        ¦               ¦             ¦/¦   ¦
;             ¦                  ¦               ¦                   ¦
;             ¦_______¦/¦__/\/\__¦rb2         rb5¦_____/\/\____¦\¦___¦
;             ¦       ¦\¦        ¦               ¦             ¦/¦   ¦
;             ¦                  ¦               ¦                   ¦
;             ¦_______¦/¦__/\/\__¦rb3         rb4¦_____/\/\____¦\¦___¦
;             ¦       ¦\¦        -----------------             ¦/¦   ¦
;            ___                                                    ___
;             _                                                      _
;
;
;
;
;
;
; Schematic diagram using a 7 segment LED display as the display device (in this case, add a line
; #define SEVENSEGMENT
; to the source code)
;
;                                -------   -------
;                               -¦ra2         ra1¦-
;                                ¦               ¦
;     +5VDC____/\/\____          ¦               ¦
;                     ¦         -¦ra3         ra0¦_______ out to relay driver
;                     ¦          ¦               ¦
;       100    _\/_   ¦          ¦               ¦
;    ____/\/\__o  o___¦____in____¦ra4        OSC2¦_______________¦ ¦_        cap 33pF
;    ¦                           ¦     PIC       ¦   __¦__       ¦ ¦ ¦
;   ___                 1k       ¦    16F84      ¦  ¦_____¦          ¦    Xtal 4Mhz
;    _      +5VDC ______/\/\_____¦/Mclr      OSC1¦_____¦_________¦ ¦_¦       cap 33pF
;                                ¦               ¦               ¦ ¦ ¦
;                                ¦               ¦                   ¦
;             ___________________¦Vss         Vdd¦____ + 5VDC        ¦
;             ¦                  ¦               ¦                   ¦
;             ¦      1           ¦               ¦                   ¦
;             ¦_______¦/¦__/\/\__¦rb0         rb7¦                   ¦     7 segment display with 7 resistors
;             ¦       ¦\¦        ¦               ¦                   ¦        (330 ohms)
;             ¦      2           ¦               ¦                7  ¦
;             ¦_______¦/¦__/\/\__¦rb1         rb6¦_____/\/\____¦\¦___¦ 
;             ¦       ¦\¦        ¦               ¦             ¦/¦   ¦
;             ¦      3           ¦               ¦                6  ¦
;             ¦_______¦/¦__/\/\__¦rb2         rb5¦_____/\/\____¦\¦___¦
;             ¦       ¦\¦        ¦               ¦             ¦/¦   ¦
;             ¦      4           ¦               ¦                5  ¦
;             ¦_______¦/¦__/\/\__¦rb3         rb4¦_____/\/\____¦\¦___¦
;             ¦       ¦\¦        -----------------             ¦/¦   ¦
;            ___                                                    ___
;             _                                                      _
;
;
;  Seven segment display layout:
;       
;               _______
;              ¦___1___¦
;             _         _
;            ¦ ¦       ¦ ¦
;            ¦ ¦       ¦ ¦
;            ¦4¦       ¦6¦
;            ¦_¦       ¦_¦
;               _______
;              ¦___2___¦
;             _         _
;            ¦ ¦       ¦ ¦
;            ¦ ¦       ¦ ¦
;            ¦5¦       ¦7¦
;            ¦_¦       ¦_¦
;               _______
;              ¦___3___¦
;
;
;  You can also use an alternative seven segment display layout if you
;  like (define SEVENSEGMENT_ALTERNATIVELAYOUT in that case).
;  Alternative seven segment display layout:
;       
;               _______
;              ¦___5___¦
;             _         _
;            ¦ ¦       ¦ ¦
;            ¦ ¦       ¦ ¦
;            ¦7¦       ¦3¦
;            ¦_¦       ¦_¦
;               _______
;              ¦___2___¦
;             _         _
;            ¦ ¦       ¦ ¦
;            ¦ ¦       ¦ ¦
;            ¦1¦       ¦4¦
;            ¦_¦       ¦_¦
;               _______
;              ¦___6___¦
;
;
;


; define DEBUG or NODEBUG
#define NODEBUG

; define SEVENSEGMENT for 7-segment display or NO_SEVENSEGMENT for
; bar-graph display.
#define SEVENSEGMENT_ALTERNATIVELAYOUT

; define TWO_MHZ if a 2 Mhz crystal is used, or FOUR_MHZ if 4 Mhz xtal.
#define FOUR_MHZ

; define COMMON_CATHODE if all LEDS cathodes are connected together to,
; ground, or COMMON_ANODE if all anodes are connected together to plus.
#define COMMON_CATHODE

; define PULSE_MODE if you want the relay to just perform a short
; on at the end of the countdown, or define NO_PULSE_MODE for the relay
; to stay on all the time during countdown and go off at the end of the
; countdown.
#define PULSE_MODE



;**********************************************************************
;*                                                                    *
;*     Variables                                                      *
;*                                                                    *
;**********************************************************************
;  Register Usage
 CBLOCK 0x00C                   ;  Start Registers at End of the Values
Dlay                            ;  8 Bit Delay Variable
DlayTemp                        ;
GlobalCounter                   ;
LoopCounter                     ;
keypad                          ;
pulsed                          ; To indicate, in pulse-mode, wether the
                                ; start pulse has been given or not.

; variables local to timer service
TimerL                          ;
TimerH                          ;
Seconds                         ;
Minutes                         ;
Hours                           ;

; variables for context saving during interrupt service
w_safe                          ;
status_safe                     ;

; variables local to ScanKeys  
key                             ;


 ENDC


;**********************************************************************
;*                                                                    *
;*     Definitions                                                    *
;*                                                                    *
;**********************************************************************
OptionReg equ   1h              ;
z       equ     2               ;
RBPU    equ     7               ;


;**********************************************************************
;*                                                                    *
;*     Macros                                                         *
;*                                                                    *
;**********************************************************************


 PAGE
 __CONFIG _CP_OFF & _XT_OSC & _PWRTE_ON  & _WDT_OFF
                                ;  Note that the WatchDog Timer is OFF

;
  org    0                      ;
  goto   init                   ;
;
  org    4                      ;
  goto   ServiceInterrupt       ;


;**********************************************************************
;*                                                                    *
;*     01  Interrupts                  parent = xx  none              *
;*                                                                    *
;**********************************************************************
;
ServiceInterrupt
  btfsc  INTCON, RBIF           ; Change on RB int?
  goto   RBWakeUpService        ; Yes, then service.
  btfsc  INTCON, T0IF           ; Timer int?
  goto   TimerService           ; Yes, then service.

; we are now on INT interrupt
  bcf    INTCON, INTE           ; Clear int mask.
  bcf    INTCON, INTF           ; Clear flag.
  retfie                        ; Return from int interrupt.

TimerService
; We are now on timer interrupt: indicate that we did service!
  bcf    INTCON, T0IE           ; Clear TMR0 int mask.
  bcf    INTCON, T0IF           ; Clear flag.

  movwf  w_safe                 ; Save context.
  swapf  STATUS, w              ;
  movwf  status_safe            ;

  incf   TimerL, f              ; Increment 16-bit low level counter.
  btfsc  STATUS, Z              ;
  incf   TimerH, f              ;

;
; PortA.1 is used for test purposes: you can test on this pin
; with a frequency counter, it should measure about 1.953 kiloHerts (2Mhz xtal)
; or 3.906 kiloHertz (4 Mhz xtal).
  bsf    PORTA, 1               ;
  nop                           ;
  nop                           ;
  nop                           ;
  nop                           ;
  nop                           ;
  nop                           ;
  nop                           ;
  nop                           ;
  nop                           ;
  nop                           ;
  bcf    PORTA, 1               ;
;
; Frequency = 2 Mhz, 4 cycles for 1 instruction = 500000 counts for
; 1 second. Divide this by 256 (timer interrupt), and we have 1953.125
; counts before we reach 1 second.
;
; So this means that if TimerH:TimerL reaches 1953.125, 1 second has elapsed.
; Since we can't handle the .125 part, we will test on 1954 and then increment
; the seconds. Than we give the TimerL every 8 seconds a boost of 7
; counts, which results in a second corresponding to 1954 - (7/8) = 1953.125 counts.

; If a 4 Mhz crystal is used, we use different values for the reference.
#ifdef FOUR_MHZ
#define  TIMEREF_L 0x44
#define  TIMEREF_H 0x0f
#else
#define  TIMEREF_L 0xa2
#define  TIMEREF_H 0x07
#endif

  movlw  TIMEREF_L              ;
  subwf  TimerL, w              ;
  btfss  STATUS, Z              ;
  goto   SecTest_af             ;
  movlw  TIMEREF_H              ;
  subwf  TimerH, w              ;
  btfss  STATUS, Z              ;
  goto   SecTest_af             ;
  clrf   TimerL                 ;
  clrf   TimerH                 ;
  incf   Seconds, f             ;

  btfsc  Seconds, 0             ; Are bit 0, 1 and 2 of seconds cleared?
  goto   Correctie_af           ;
  btfsc  Seconds, 1             ;
  goto   Correctie_af           ;
  btfsc  Seconds, 2             ;
  goto   Correctie_af           ;
  movlw  7                      ; Yes: boots low counter with 7.
  addwf  TimerL, f              ;

Correctie_af
  movlw  D'60'                  ; Now increment the Minutes and Hours if
  subwf  Seconds, w             ; necessary.
  btfss  STATUS, Z              ;
  goto   SecTest_af             ;
  clrf   Seconds                ;
  incf   Minutes                ;
  incf   TimerL, f              ;
  movlw  D'60'                  ;
  subwf  Minutes, w             ;
  btfss  STATUS, Z              ;
  goto   SecTest_af             ;
  clrf   Minutes                ;
  decf   Hours                  ; Verminder het aantal uren.
  btfsc  Hours, 7               ;
  clrf   Hours                  ; Uren negatief: terug op nul.
SecTest_af


  swapf  status_safe, w         ; Restore context.
  movwf  STATUS                 ;
  swapf  w_safe, f              ;
  swapf  w_safe, w              ;

  bsf    INTCON, T0IE           ; Set TMR0 int mask.

  retfie                        ; Return from timer interrupt.



;
; This routine checks which input is changed and stores it
; into the corresponding variables.
; This service is the only one that can wake up the processor
; from sleep mode.
RBWakeUpService
  bcf    INTCON, RBIE           ; Clear mask.
  bcf    INTCON, RBIF           ; Clear flag.


  movwf  w_safe                 ; Save context.
  swapf  STATUS, w              ;
  movwf  status_safe            ;


  call   Dlay160                ;
  call   Dlay160                ;
  call   Dlay160                ;
  call   Dlay160                ;


  swapf  status_safe, w         ; Restore context.
  movwf  STATUS                 ;
  swapf  w_safe, f              ;
  swapf  w_safe, w              ;

  bsf    INTCON, RBIE           ; Set mask.


  retfie                        ; Return from interrupt.
;
;
;

;**********************************************************************
;*                                                                    *
;*     01  Program                     parent = xx  none              *
;*                                                                    *
;*     Function: main program.                                        *
;*                                                                    *
;*     params: none                                                   *
;*     return: none                                                   *
;*                                                                    *
;**********************************************************************
init



  clrf   PORTA                  ; Do some initializations.
  clrf   PORTB                  ;

  clrf   TimerL                 ;
  clrf   TimerH                 ;
  clrf   Seconds                ;
  clrf   Minutes                ;
  clrf   Hours                  ;
  clrf   keypad                 ;

  movlw  1                      ;
  movwf  pulsed                 ;

  movlw  B'00000000'            ; Enable RB0..RB7 for output.
  bsf    STATUS, RP0            ;
  movwf  TRISB ^ 0x080          ;
  bcf    STATUS, RP0            ;


  movlw  B'00010000'            ; Enable RA4 input, rest output.
  bsf    STATUS, RP0            ;
  movwf  TRISA ^ 0x080          ;
  bcf    STATUS, RP0            ;


; Set the timer.
  bsf    STATUS, RP0            ; Select page 1.
  movlw  B'00001000'            ; No prescaler.
#ifdef DEBUG
  movlw  B'00000000'            ;
#endif
  movwf  OptionReg              ;
  bcf    OptionReg, RBPU        ; Enable pull up on RB port.
  bcf    STATUS, RP0            ; Select page 0.


  clrf   TMR0                   ;
  bsf    INTCON, GIE            ; Globally allow interrupts.
  bsf    INTCON, T0IE           ; Enable timer interrupt.
  bsf    INTCON, RBIE           ; Enable interrupt on change.


; Initialize the keypad.
  movlw  0x10                   ; Indicate no key pressed.
  movwf  key                    ;


; Power-on self test.
  movlw  B'00000000'            ; Laat LEDs knipperen.
  movwf  PORTB                  ;
  call   Dlay250                ;
  movlw  B'11111111'            ;
  movwf  PORTB                  ;
  call   Dlay250                ;
  movlw  B'00000000'            ;
  movwf  PORTB                  ;
  call   Dlay250                ;
  movlw  B'11111111'            ;
  movwf  PORTB                  ;
  call   Dlay250                ;
  movlw  B'00000000'            ;
  movwf  PORTB                  ;





; Now the main loop is coming...
;
  clrf   GlobalCounter          ;



Loop				; Loop Forever.



  movlw  D'10'                  ;
  movwf  LoopCounter            ; Inner loop for higher responsitivity to the keypad.
LLoop
  call   Dlay5                  ;


; Handle the keyboard.
  call   ReadButton             ;
  btfsc  key, 4                 ;
  goto   keypadtest_af          ;


b_checkrelease
  btfss  key, 0                 ; Wait for button to be released.
  goto   b_released             ;
  call   ReadButton             ;
  goto   b_checkrelease         ;
b_released

  incf   Hours, f               ; Button pressed: increment hours.
  movlw  9                      ; Test for overflow.
#ifdef SEVENSEGMENT
  movlw  10                     ;
#endif
#ifdef SEVENSEGMENT_ALTERNATIVELAYOUT
  movlw  10                     ;
#endif
  subwf  Hours, w               ;
  btfsc  STATUS, Z              ;
  clrf   Hours                  ;

  clrf   Seconds                ; When button pressed, clear
  clrf   Minutes                ; seconds and minutes.

  call   ShowHours              ;


keypadtest_af
  movlw  0x10                   ; Ready for next time.
  movwf  key                    ;


; Show things on the screen.
  call   ShowHours              ;


  decfsz LoopCounter            ;
  goto   LLoop                  ;

  goto   Loop                   ;




; Subroutines


;**********************************************************************
;*                                                                    *
;*     ShowHours                                                      *
;*                                                                    *
;*     Function: translates value in Hours to LEDs and relay          *
;*                                                                    *
;*     return: none                                                   *
;*                                                                    *
;**********************************************************************
ShowHours
  movlw  0                      ;
  subwf  Hours, w               ;
  btfsc  STATUS, Z              ;
  goto   sd0                    ;
  movlw  1                      ;
  subwf  Hours, w               ;
  btfsc  STATUS, Z              ;
  goto   sd1                    ;
  movlw  2                      ;
  subwf  Hours, w               ;
  btfsc  STATUS, Z              ;
  goto   sd2                    ;
  movlw  3                      ;
  subwf  Hours, w               ;
  btfsc  STATUS, Z              ;
  goto   sd3                    ;
  movlw  4                      ;
  subwf  Hours, w               ;
  btfsc  STATUS, Z              ;
  goto   sd4                    ;
  movlw  5                      ;
  subwf  Hours, w               ;
  btfsc  STATUS, Z              ;
  goto   sd5                    ;
  movlw  6                      ;
  subwf  Hours, w               ;
  btfsc  STATUS, Z              ;
  goto   sd6                    ;
  movlw  7                      ;
  subwf  Hours, w               ;
  btfsc  STATUS, Z              ;
  goto   sd7                    ;
  movlw  8                      ;
  subwf  Hours, w               ;
  btfsc  STATUS, Z              ;
  goto   sd8                    ;
  movlw  9                      ;
  subwf  Hours, w               ;
  btfsc  STATUS, Z              ;
  goto   sd9                    ;
  return                        ;





#ifdef SEVENSEGMENT

sd0
  movlw  B'01111101'            ;
  goto   sd_sam                 ;
sd1
  movlw  B'01100000'            ;
  goto   sd_sam                 ;
sd2
  movlw  B'00110111'            ;
  goto   sd_sam                 ;
sd3
  movlw  B'01100111'            ;
  goto   sd_sam                 ;
sd4
  movlw  B'01101010'            ;
  goto   sd_sam                 ;
sd5
  movlw  B'01001111'            ;
  goto   sd_sam                 ;
sd6
  movlw  B'01011111'            ;
  goto   sd_sam                 ;
sd7
  movlw  B'01100001'            ;
  goto   sd_sam                 ;
sd8
  movlw  B'01111111'            ;
  goto   sd_sam                 ;
sd9
  movlw  B'01101111'            ;
  goto   sd_sam                 ;

#else

#ifdef SEVENSEGMENT_ALTERNATIVELAYOUT

;rb0 <> rb4
;rb3 <> rb6
;rb2 <> rb5

sd0
  movlw  B'01111101'            ;
  goto   sd_sam                 ;
sd1
  movlw  B'00001100'            ;
  goto   sd_sam                 ;
sd2
  movlw  B'00110111'            ;
  goto   sd_sam                 ;
sd3
  movlw  B'00111110'            ;
  goto   sd_sam                 ;
sd4
  movlw  B'01001110'            ;
  goto   sd_sam                 ;
sd5
  movlw  B'01111010'            ;
  goto   sd_sam                 ;
sd6
  movlw  B'01111011'            ;
  goto   sd_sam                 ;
sd7
  movlw  B'00011100'            ;
  goto   sd_sam                 ;
sd8
  movlw  B'01111111'            ;
  goto   sd_sam                 ;
sd9
  movlw  B'01111110'            ;
  goto   sd_sam                 ;




#else

sd0
  movlw  B'00000000'            ;
  goto   sd_sam                 ;
sd1
  movlw  B'00000001'            ;
  goto   sd_sam                 ;
sd2
  movlw  B'00000011'            ;
  goto   sd_sam                 ;
sd3
  movlw  B'00000111'            ;
  goto   sd_sam                 ;
sd4
  movlw  B'00001111'            ;
  goto   sd_sam                 ;
sd5
  movlw  B'00011111'            ;
  goto   sd_sam                 ;
sd6
  movlw  B'00111111'            ;
  goto   sd_sam                 ;
sd7
  movlw  B'01111111'            ;
  goto   sd_sam                 ;
sd8
  movlw  B'11111111'            ;
  goto   sd_sam                 ;
sd9
  movlw  B'11111111'            ;
  goto   sd_sam                 ;

#endif
#endif





sd_sam
#ifdef COMMON_ANODE
  xorlw  H'FF'                  ;
#endif
  movwf  PORTB                  ;


  movf   Hours, f               ;
  btfss  STATUS, Z              ;
  goto   counting_down          ;
counting_done
#ifdef PULSE_MODE
  movf   pulsed, f              ;
  btfss  STATUS, Z              ;
  return                        ;
  bsf    PORTA, 0               ; Give a pulse
  call   Dlay250                ; of 250 ms
  bcf    PORTA, 0               ; to the relay.
  bsf    pulsed, 0              ; Indicate we did give a pulse.
#else
  bcf    PORTA, 0               ;
#endif
  return                        ;

counting_down
#ifdef PULSE_MODE
  bcf    pulsed, 0              ; Indicate pulse still has to be given.
#else
  bsf    PORTA, 0               ;
#endif

  return                        ;

;**********************************************************************
;*                                                                    *
;*     ReadButton                                                     *
;*                                                                    *
;*     Function: reads button on PORTA.4                              *
;*                                                                    *
;*     return: none                                                   *
;*                                                                    *
;**********************************************************************
;
; This routine checks which input is changed and stores it
; into variable 'key'.
; Bit 0 = button pressed (RA4)
; Bit 4 = no key pressed
;

ReadButton

  movf   PORTA, w               ; Read buttons connected to PORTA.
  call   Dlay5                  ; Debounce.
  call   Dlay5                  ;
  movf   PORTA, w               ; Read buttons again.
  andlw  0xf0                   ; Only interested in high nibble.
  movwf  keypad                 ;

  btfss  keypad, 4              ; Translate to key.
  bsf    key, 0                 ;
  btfsc  keypad, 4              ;
  bcf    key, 0                 ;

  movf   key, w                 ;
  movwf  keypad                 ;
  movlw  B'00001111'            ;
  andwf  keypad, f              ;

  movf   keypad, f              ;
  btfsc  STATUS, Z              ;
  bsf    key, 4                 ;

  btfss  STATUS, Z              ;
  bcf    key, 4                 ;

  return                        ;

;**********************************************************************
;*                                                                    *
;*     Dlay160                                                        *
;*                                                                    *
;*     Function: delays 160 usecs.                                    *
;*                                                                    *
;*     return: none                                                   *
;*                                                                    *
;**********************************************************************
Dlay160                         ;  Delay 160 usecs
#ifdef DEBUG
        return                  ;
#endif

  movlw  256 - ( 160 / 2 )      ;  Loop Until Carry Set
  addlw  1                      ;
  btfss  STATUS, C              ;
   goto  $-2

  return



;**********************************************************************
;*                                                                    *
;*     Dlay5                                                          *
;*                                                                    *
;*     Function: delays 5 msecs.                                      *
;*                                                                    *
;*     return: none                                                   *
;*                                                                    *
;**********************************************************************

Dlay5                           ; Delay 5 msecs.

#ifdef DEBUG
  return                        ;
#endif
  movlw  2                      ; Set up the Delay.
  movwf  Dlay                   ;
  movlw  256 - 0x0E8            ;
  addlw  1                      ;
  btfsc  STATUS, Z              ;
  decfsz Dlay                   ;
  goto   $-3                    ;

  return                        ;


;**********************************************************************
;*                                                                    *
;*     Dlay250                                                        *
;*                                                                    *
;*     Function: delays 250 msecs.                                    *
;*                                                                    *
;*     return: none                                                   *
;*                                                                    *
;**********************************************************************
Dlay250
#ifdef DEBUG
        return                  ;
#endif
  movlw  D'50'                  ;  Set up the Delay
  movwf  DlayTemp               ;
Dlay250Lus
  call   Dlay5                  ;
  decfsz DlayTemp               ;
  goto   Dlay250Lus             ;
  return                        ;
  






  end


