;; ;; main.asm, a PIC 16F84 doorbell timer. ;; Copyright (C) 2006 James Cameron (quozl@us.netrek.org) ;; ;; This program is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation; either version 2 of the License, or ;; (at your option) any later version. ;; ;; This program is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with this program; if not, write to the Free Software ;; Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ;; processor 16f84 list f=inhx8m include "p16f84.inc" __config _cp_off & _wdt_off & _hs_osc movlf macro lit,to movlw lit movwf to endm mov8 macro from,to movf from,w movwf to endm mov16 macro from,to ; move 16 bit value mov8 from+0,to+0 mov8 from+1,to+1 endm mov24 macro from,to ; move 24 bit value mov16 from+0,to+0 mov8 from+2,to+2 endm clr24 macro count ; clear 24 bit value clrf count+0 clrf count+1 clrf count+2 endm align macro org (($>>2)<<2)+4 ; align to four byte boundary endm ;; symbol naming conventions ;; p_ port address of ;; t_ tris address of ;; m_ mask bits of ;; b_ bit number ;; file register allocations base equ 0x0c ; first free file register address p_sw equ PORTB ; switch address t_sw equ TRISB m_sw equ b'00000011' p_out equ PORTB t_out equ TRISB m_out equ b'00000011' cblock base flag r_t0 r_t1 r_t2 r_t3 endc ; flag and port b values b_sw_a equ 0 ; RB0, doorbell input (C/D) b_sw_b equ 1 ; RB1, reset button b_wake equ 0 b_ignoring equ 1 b_alive equ 2 ; RB2, alive indicator b_delayed_long equ 3 ; RB3, lighting output b_instant_latched equ 4 ; RB4, triggered indicator b_delayed_short equ 5 ; RB5, fire alarm bell output (G/H) b_instant_short equ 6 ; RB6, deranged canary output (E/F) org 0 goto main org 4 isr cblock saved_w ; saved w register saved_status ; saved status register (swapped) endc bcf status,rp0 ; contributed by ryan@ryancocks.net bcf status,rp1 movwf saved_w ; save w register swapf status,w ; save status register movwf saved_status btfss intcon,t0if ; test timer zero interrupt flag goto isr_skip_clock isr_clock bcf intcon,t0if ; clear the interrupt cblock u0 u1 u2 endc ;; add 65536us to the microsecond counter incf u2,f cblock r_alive_counter endc bcf flag,b_alive decf r_alive_counter,f btfss status,z goto isr_skip_alive bsf flag,b_alive movlf 10,r_alive_counter isr_skip_alive call update cblock t0 ; temporary copy of u0-u2 t1 t2 endc ;; save a copy of the counter mov24 u0,t0 ;; subtract 1s from copy of counter movlw d'1000000'&0xff subwf t0,f btfss status,c decf t1,f movlw d'1000000'>>d'8'&0xff subwf t1,f btfss status,c decf t2,f movlw d'1000000'>>d'16'&0xff subwf t2,f btfss status,c goto isr_clock_end ; underflow, ignore the subtraction ;; did not underflow, save the result, occurs once per second mov24 t0,u0 ;; wake mainline bsf flag,b_wake isr_clock_end ;;; start of insert for doorbell isr_swa btfsc flag,b_ignoring ; if ignoring, don't look goto isr_swa_end btfsc p_sw,b_sw_a ; if button not down, ignore goto isr_swa_end bsf flag,b_ignoring ; begin ignoring movlf d'5',r_t0 ; schedule ignoring period end bsf flag,b_instant_latched ; and show it bsf flag,b_instant_short ; and show it movlf d'1',r_t1 ; schedule trigger period end bcf flag,b_wake ; avoid waking mainline call update clr24 u0 ; reset one second clock isr_swa_end isr_swb btfsc p_sw,b_sw_b goto isr_swb_end bcf flag,b_instant_latched call update isr_swb_end ;;; end of insert for doorbell isr_skip_clock swapf saved_status,w ; restore registers saved movwf status swapf saved_w,f swapf saved_w,w retfie align update ; move flags to port mov8 flag,p_out return align initialise ;; clear output port clrf porta clrf portb call retris ;; clear counters clr24 u0 clrf flag clrf r_t0 clrf r_t1 clrf r_t2 clrf r_t3 movlf 10,r_alive_counter ;; initialise option register bsf status,rp0 bcf option_reg,t0cs ; set timer to use oscillator/4 bcf option_reg,psa ; set prescaler to TMR0 bsf option_reg,ps2 ; set prescaler to 1:128 bsf option_reg,ps1 bcf option_reg,ps0 bcf status,rp0 ;; lastly, enable interrupts bsf intcon,t0ie ; enable timer interrupt bsf intcon,gie ; enable all interrupts return align wait bcf flag,b_wake call update wait_loop btfss flag,b_wake goto wait_loop return align retris bsf status,rp0 movlw m_sw movwf t_sw movlw m_out movwf t_out bcf status,rp0 return align cdtf macro a movf a,w ; check timer state btfsc status,z return ; return if not running (zero) decf a,f ; decrement timer btfss status,z return ; return if still running (not zero) endm cdt0 cdtf r_t0 bcf flag,b_ignoring call update return align cdt1 cdtf r_t1 bcf flag,b_instant_short bsf flag,b_delayed_short bsf flag,b_delayed_long call update movlf d'2',r_t2 return align cdt2 cdtf r_t2 bcf flag,b_delayed_short call update movlf d'255',r_t3 return align cdt3 cdtf r_t3 bcf flag,b_delayed_long call update return align main call initialise goto resume loop call wait ; return once per second or on trigger resume call retris call cdt0 call cdt1 call cdt2 call cdt3 goto loop end