;------------------------------------------------------------------------------------- ; ; Template for a real time application that polls the Peripherals and PORTB for inputs ; Copyright 2003, Douglas Rice ; ; Ver 1.1 7th June 2003 ; ; Bell Code Delay. ; ; Button presses on PORT B I/P 7 are replayed with a delay ; To set the hold off delay, press button connected to Port B6 for required duration ; ; These output go high. ; Port B bit 0 is output Bellcode ; Port B bit 1 is output On when replaying bell codes ; Port B bit 2 is output On when Hold off timer is running ; ; Buttons connected to PB6 (or PB7) to GND ; Port B bit 7 is input pulse in bell code ; Port B bit 6 is input hold low for required duration of hold off. ; ; Max delay is 255 / ticks per second. ; At 40 ticks per second, max delay is 6.375 seconds. ; ; list p=16F628,r=dec ;16F628, decimal system #include ;link pre-defines, standard EQU's etc. __idlocs 0x2048 ;give the chip an ID word number __config 0x3FFF & _INTRC_OSC_NOCLKOUT & _PWRTE_OFF & _MCLRE_OFF & _LVP_OFF & _WDT_OFF & _BODEN_OFF ;--------------------------------------------------------------- ; SEC 0.0 - Defines ;--------------------------------------------------------------- RUN_RTN1 EQU 0 RUN_RTN2 EQU 1 RUN_DELAYTMR EQU 2 RUN_HOLDOFFTMR EQU 3 RUN_RINGBELLTICKTMR EQU 4 BUTTON_7 EQU 7 ; press bell code BUTTON_6 EQU 6 ; sets hold off time. press for duration of holdoff delay ;--------------------------------------------------------------- ; SEC 1.0 - Variables ;--------------------------------------------------------------- CBLOCK 0x20 ; 7 word queue QU_start ENDC CBLOCK 0x30 dotimeslice RTN1_COUNT JumpTableTemp ; polled input stuff IPnewF IPlastF IPbuttonPressEvents IPbuttonReleaseEvents ; queue variables. QUinPtr QUoutPtr QUtemp ; Timers TMnextDelayCounter ; Hold Off delay TMholdOffDelayCounter ; Hold off count TMholdOffDelayCounterInit ; Hold off count TMringBellDelay ; Hold RingBell Output on for thid delay TMtsCount ; incremented every tick, reset on button press. ENDC ORG 0x000 ;we are at 0x000h GOTO Start ;goto start of program ;--------------------------------------------------------------- ; SEC 2.0 - Jump Tables for state machines ;--------------------------------------------------------------- StateMachine JumpTable ; MOVWF JumpTableTemp MOVLW high($) MOVWF PCLATH MOVFW JumpTableTemp MOVWF PCL JumpTableEnd MOVWF JumpTableTemp RETURN RETLW 3 ; return a value in W PROC1_1: NOP MOVLW low( PROC1_2 ) GOTO JumpTableEnd PROC1_2: NOP MOVLW low( PROC1_3 ) GOTO JumpTableEnd PROC1_3: NOP MOVLW low( PROC1_4 ) GOTO JumpTableEnd PROC1_4: NOP MOVLW low( PROC1_1 ) GOTO JumpTableEnd JumpTableCodeEnd ;test if the Jumptable straddles a Page boundary ; They must not as PCLATH will not be set for all cases IF 0 != ( high ( JumpTableCodeEnd ) - high ( JumpTable ) ) Error "Table straddles Page Boundary " ENDIF ;--------------------------------------------------------------- ; SEC 3.0 - Initilization code ;--------------------------------------------------------------- Start: CALL INIT_CHIP ;--------------------------------------------------------------- ; SEC 4.0 - Main Loop - polls around looking for events to service ;--------------------------------------------------------------- Main_loop_begins: ; Poll for a condition ; It would be better if this was ; CALL pollForCondition Main_loop_Polled_Conditions: MOVFW IPbuttonPressEvents BZ Main_loop_Polled_Conditions2 BTFSC IPbuttonPressEvents, BUTTON_7 CALL TMbuttonPressed BTFSC IPbuttonPressEvents, BUTTON_6 CALL TMbuttonDurationPressed Main_loop_Polled_Conditions2: MOVFW IPbuttonReleaseEvents BZ Main_loop_Peripherals BTFSC IPbuttonReleaseEvents, BUTTON_7 CALL TMbuttonReleased BTFSC IPbuttonReleaseEvents, BUTTON_6 CALL TMbuttonDurationReleased Main_loop_Peripherals: ; Poll around the chips Peripherals for any needing servicing BTFSC INTCON, RBIF CALL INT_SERVICE_RBI BTFSC INTCON, INTF CALL INT_SERVICE_INTI BTFSC INTCON, T0IF CALL INT_SERVICE_TMR0 MOVFW PIR1 ; ANDLW 0xFF ; Mask BITs Interested in BZ Main_loop_Processes ; There are other peripherals in PIR1 ; EEIF CMIF RCIF TXIF CCP1IF TMR2IF TMR1IF BTFSC PIR1, TMR1IF CALL INT_SERVICE_TMR1 BTFSC PIR1, TMR2IF CALL INT_SERVICE_TMR2 Main_loop_Processes: ; Any Routines to run? Check if dotimeslice is zero? ; you could do a similar thing on INTCON and PIR1 MOVF dotimeslice,f BZ Main_loop_begins BTFSC dotimeslice, RUN_RTN1 CALL RTN1 BTFSC dotimeslice, RUN_RTN2 CALL RTN2 ; Add extra routines here GOTO Main_loop_begins ;--------------------------------------------------------------- ; SEC 5.0 - Event Service routines - Peripherals ;--------------------------------------------------------------- ; ; The events are cleared and serviced in these routines. ; The routines must not block waiting for an event ; INT_SERVICE_RBI ; This is called 1000 times per second BCF INTCON, RBIF ;clear the interrupt ; your code here RETURN INT_SERVICE_INTI ; This is called 1000 times per second BCF INTCON, INTF ;clear the interrupt ; your code here RETURN INT_SERVICE_TMR0 ; This is called 1000 times per second ; Poll for a condition ; It would be better if this was CALL pollForCondition BCF INTCON, T0IF ;clear the interrupt MOVLW 256+1-125 ADDWF TMR0, F ;include any increases since rollover NOP ; You could put some code here DECFSZ RTN1_COUNT RETURN BSF dotimeslice,RUN_RTN1 MOVLW .25 MOVWF RTN1_COUNT RETURN INT_SERVICE_TMR1 ; This is called 1000 times per second BCF PIR1, TMR1IF ;clear the interrupt ; your code here RETURN INT_SERVICE_TMR2 ; This is called 1000 times per second BCF PIR1, TMR2IF ;clear the interrupt ; your code here RETURN ;--------------------------------------------------------------- ; SEC 6.0 - Event Service routines - Processes ;--------------------------------------------------------------- RTN1 ; This is called once every 7 ms BCF dotimeslice,RUN_RTN1 NOP ;Your code goes here CALL StateMachine ; MOVWF JumpTableTemp ; always increment tsCount, used to time interval between button presses INCF TMtsCount,f ; only run every 100 ms BTFSC dotimeslice, RUN_RINGBELLTICKTMR CALL TMringBellTick BTFSC dotimeslice, RUN_DELAYTMR CALL TMdelayTmrTick BTFSC dotimeslice, RUN_HOLDOFFTMR CALL TMholdOffTmrTick RETURN RTN2 ; This is called once every 7 ms BCF dotimeslice,RUN_RTN2 NOP ;Your code goes here RETURN RTN3 ; This is called once every 7 ms BCF dotimeslice,RUN_RTN2 NOP ;Your code goes here RETURN ;--------------------------------------------------------------- ; SEC 7.0 - Poll Condition Service routines ;--------------------------------------------------------------- pollForCondition ; Poll for a condition and generate and event if found ; really this should be called say every 10ms to filter out contact bounce. ; NOTE: setting up TRIB B is done else where. IPtimesliceFast ; Buttons could be push to make switches that pull down an PORTB input ; ----___ ; --_____ ; ; This reads all Port B inputs and looks for Presses which are falling edges MOVFW IPnewF MOVWF IPlastF MOVFW PORTB MOVWF IPnewF ; IP last contains new setting, IPlast contains previous ; --_____ Bit in IPnewF ; __----- Bit in /IPnewF ; ----___ Bit in IPlastF ; __--____ /IPnewF & IPlastF , the edge is found. COMF IPnewF,W ANDWF IPlastF,W ; now force IPbuttonEvent bits to high for new pressed button ; the service routine should reset the bit to clear the event. IORWF IPbuttonPressEvents, COMF IPlastF,W ANDWF IPnewF,W ; now force IPbuttonEvent bits to high for new released button ; the service routine should reset the bit to clear the event. IORWF IPbuttonReleaseEvents, RETURN ;--------------------------------------------------------------- ; SEC 8.0 - INIT routines ;--------------------------------------------------------------- INIT_CHIP: ; Set up TMR0 to tick 1000 times a second ; use a prescale of 8 and a TMR0 count of 125 ; To make TMRO count reliably at 125 ticks, ADD (255-125) to TMR0 on each timeout ; Adding means that as long as the addition does not cause a carry, ; the count will be reduced. CALL QUinit BSF STATUS, RP0 ;must enter bank 1 for OPTION reg ; set up tris B MOVLW 0xF2 MOVWF TRISB BCF STATUS, RP0 ;return to bank 0 CLRF PORTB CLRF dotimeslice BSF STATUS, RP0 ;must enter bank 1 for OPTION reg MOVLW 0<< T0CS | 0 << PSA | 2 MOVWF OPTION_REG BCF STATUS, RP0 ;return to bank 0 MOVLW 256+1-125 MOVWF TMR0 ;CALL INIT_CLEAR_TMR0_INTERRUPT BCF INTCON, T0IF ;clear the TMR0 interrupt flag ; Initilize Jump Table MOVLW PROC1_3 MOVWF JumpTableTemp ; set up RTN1_COUNT so that the RTN_1 is held off for 7ms MOVLW 7 MOVWF RTN1_COUNT CALL TMringBell MOVLW .100 MOVWF TMholdOffDelayCounterInit RETURN ;--------------------------------------------------------------- ; SEC 9.0 - buffer ;--------------------------------------------------------------- QUinit MOVLW 0 MOVWF QU_start MOVWF QU_start+1 MOVWF QU_start+2 MOVWF QU_start+3 MOVWF QU_start+4 MOVWF QU_start+5 MOVWF QU_start+6 MOVWF QU_start+7 CLRF QUinPtr CLRF QUoutPtr RETURN QUput ;Add W to queue. MOVWF QUtemp MOVFW QUinPtr ADDLW QU_start MOVWF FSR ; Inc PTR INCF QUinPtr,w ANDLW 0x0F MOVWF QUinPtr ; put MOVFW QUtemp MOVWF INDF ; use ptr and save into buffer RETURN QUget ; W = top of queue ; pointer incremented ; do not call if QUinPtr == QUoutPtr MOVFW QUoutPtr ADDLW QU_start MOVWF FSR ; Inc Pointer INCF QUoutPtr,w ANDLW 0x0F MOVWF QUoutPtr ; get value MOVFW INDF RETURN QUtest ; If queue is empty return zero ; If pointers are equal, Queue is empty MOVFW QUoutPtr XORWF QUinPtr,w RETURN TMmainTmr ; check queue. If byte available start back off timer TMdelayTmrTick ; only ticked every 100 ms BSF PORTB,2 DECFSZ TMnextDelayCounter,F RETURN TMdelayTmrTick2 ; only ticked every 100 ms ; NextDelay timed out so ring bell CALL TMringBell CALL QUtest ; if zero then no queued messages SKPZ GOTO TMdelayTmr1 ; zero, so stop delayTmr BCF dotimeslice, RUN_DELAYTMR BCF PORTB,2 RETURN TMdelayTmr1 ; restart CALL QUget ; ADDLW 1 ; ANDLW 0x0F MOVWF TMnextDelayCounter RETURN TMholdOffTmrTick ; only ticked every 100 ms BSF PORTB,3 DECFSZ TMholdOffDelayCounter,F RETURN ; HoldoffTmr timed out, so stop it running BCF dotimeslice, RUN_HOLDOFFTMR BCF PORTB,3 ; now start delayTmr to time out after 2 ticks after holdoff timer. ; ring bell once if any queued items schedule atime out. BSF dotimeslice, RUN_DELAYTMR MOVLW 2 MOVWF TMnextDelayCounter RETURN TMringBellTick ; only ticked every 100 ms BSF PORTB,0 DECFSZ TMringBellDelay,F RETURN ; HoldoffTmr timed out BCF dotimeslice, RUN_RINGBELLTICKTMR ; ring bell once and start Timer. BCF PORTB,0 RETURN TMbuttonPressed BCF IPbuttonPressEvents, BUTTON_7 BTFSS dotimeslice, RUN_HOLDOFFTMR CLRF TMtsCount INCF TMtsCount,W CALL QUput CLRF TMtsCount ; Start Hold off Timer ; Restart HoldOfTmr with 50 ticks MOVFW TMholdOffDelayCounterInit MOVWF TMholdOffDelayCounter BSf dotimeslice, RUN_HOLDOFFTMR CALL TMringBell RETURN TMbuttonReleased BCF IPbuttonReleaseEvents, BUTTON_7 RETURN ; Start Hold off Timer ; Restart HoldOfTmr with 50 ticks ; restart timer from button release each time button is released MOVFW TMholdOffDelayCounterInit MOVWF TMholdOffDelayCounter BSf dotimeslice, RUN_HOLDOFFTMR ; CALL TMringBell RETURN TMringBell BSF dotimeslice, RUN_RINGBELLTICKTMR MOVLW 2 MOVWF TMringBellDelay BCF PORTB,0 RETURN ; TMbuttonDurationPressed BCF IPbuttonPressEvents, BUTTON_6 ; use the currently tickingTMtsCount CLRF TMtsCount BSF PORTB,2 BSF PORTB,3 RETURN TMbuttonDurationReleased BCF IPbuttonReleaseEvents, BUTTON_6 BCF PORTB,2 BCF PORTB,3 MOVFW TMtsCount MOVWF TMholdOffDelayCounterInit RETURN ; save in EEPROM BSF STATUS,RP0 MOVWF EEDATA MOVLW 01 MOVWF EEADR CALL EEwrt RETURN ;-------------------------------------------------------------------------- ; Sec 10.0 EEprom Routines for 16F628 ;-------------------------------------------------------------------------- EEread ; w contains address BSF STATUS,RP0 MOVWF EEADR BSF EECON1,RD MOVFW EEDATA BCF STATUS,RP0 RETURN EEsetAddr BSF STATUS,RP0 MOVWF EEADR BSF STATUS,RP0 RETURN EEwrt ; blocking, EEADR and EEDATA set up. BSF STATUS,RP0 MOVWF EEDATA BCF INTCON,GIE BCF EECON1,EEIF BSF EECON1,WREN MOVLW 0x55 MOVWF EECON2 MOVLW 0xAA MOVWF EECON2 BSF EECON1,WR ; Now wait for EEwrt to finish write EEwaitForWrt ; block until EEPROM write has finished. BCF EECON1,WREN ; disable EROM BTFSC EECON1,WR GOTO EEwaitForWrt BCF EECON1,EEIF ; EEPROM finished BCF STATUS,RP0 RETURN ;--------------------------------------------------------------- ; SEC 11.0 - END ;--------------------------------------------------------------- END ;-------------------------------------------------------------------------- ; EEPROM data ;-------------------------------------------------------------------------- ORG 0x2100 ; first 2 on and off are general ones DE 0 DE .100 ; initial Hold off delay