; Dublin Pedestrian Crossing Lights Emulator
; Filename: crossing.asm
; This is a state machine that emulates the sound of Dublin's pedestrian crossings.
; When button is pressed it waits a random time then goes green.
; V0.0 151115 New project
; V0.1 151116 TMR0 interrupt, CONFIG bits
; V0.2 151117 pew sound (second version)
; V0.3 151117 pew sound (third version)
; V0.4 151118 pew sound (final version)
; V0.5 151119 pop
; V1.0 151122 Release, MCLR enabled, BTN -> GPIO2
LIST P=12F629, F=INHX8M
#include <P12F629.INC>
__CONFIG _INTRC_OSC_NOCLKOUT & _WDT_OFF & _CP_OFF & _CPD_OFF & _BODEN_OFF & _MCLRE_ON & _PWRTE_OFF
; Equates
RESET_V EQU 0x00 ; Address of RESET Vector
OSC_FREQ EQU D'4000000' ; Oscillator Frequency is 4.0 MHz
; Registers
PERIOD EQU 0x20 ; Determines sound frequency
RND EQU 0x21 ; Used as cheap source of randomness (PIPCOUNT)
STATE EQU 0x22 ; Only one bit should be active at any time but the test takes the first set one
PIPON EQU 0x23 ; pip/pop active
PIPOFF EQU 0x24 ; pip/pop silent
PIPCOUNT EQU 0x25 ; # of pips/pops to generate
; Ports
#define RED GPIO,0 ; Red LED
#define GRN GPIO,1 ; Green LED
#define BTN GPIO,2 ; Call Button, WPU bit set on POR
#define SPKN GPIO,4 ; Negative terminal of speaker
#define SPKP GPIO,5 ; Positive terminal of speaker
#define IDLE STATE,0 ; Wait for button press, no sound
#define WAIT STATE,1 ; Button pressed, wait for green, don't generate pip
#define WAITP STATE,2 ; Button pressed, wait for green, generate pip
#define PREPEW STATE,3 ; Wait before sliding tone, red light
#define PEW STATE,4 ; Generate sliding tone, green light
#define PREPOP STATE,5 ; Short silence before pop, green light
#define POP STATE,6 ; Generate pop, green light
#define NOPOP STATE,7 ; Don't generate pop, green light
ORG 0x00
GOTO START
ORG 0x04
; Interrupt handlers
BCF INTCON,T0IF ; Clear source of interrupt (TMR0)
MOVLW 0xF0
MOVWF TMR0
TESTIDLE
BTFSC IDLE
GOTO BTNCHK
TESTPIP
BTFSC WAITP
GOTO GENPIP
TESTNOPIP
BTFSC WAIT
GOTO NOGENPIP
TESTPREPEW
BTFSC PREPEW
GOTO GENPREPEW
TESTPEW
BTFSC PEW
GOTO GENPEW
TESTPREPOP
BTFSC PREPOP
GOTO GENPREPOP
TESTPOP
BTFSC POP
GOTO GENPOP
TESTNOPOP
BTFSC NOPOP
GOTO NOGENPOP
GOTO ENDINT
BTNCHK
; IDLE set
BTFSC BTN
GOTO ENDINT
BCF IDLE
BSF WAITP ; Change state to generate pip
MOVLW 0x0C ; 1 kHz
MOVWF PERIOD
MOVFW RND
ANDLW 0x0F
MOVWF PIPCOUNT
BTFSC PIPCOUNT,3
GOTO COUNTOK
BTFSC PIPCOUNT,2
GOTO COUNTOK ; Test for PIPCOUNT <4
MOVLW 0x03
IORWF PIPCOUNT,1 ; PIPCOUNT is minimum 3 and max 15
COUNTOK
BSF SPKP ; Start pip
GOTO ENDINT
NOGENPIP
; Don't generate pip, duh... Wait 1.9 s, WAIT set
DECFSZ PERIOD,1
GOTO ENDINT
MOVLW 0x0C ; 1 kHz
MOVWF PERIOD
DECFSZ PIPON,1 ; Inner loop?
GOTO ENDINT
MOVLW 0x32
MOVWF PIPON
DECFSZ PIPOFF,1 ; Outer loop?
GOTO ENDINT
MOVLW 0x4C
MOVWF PIPOFF
BSF WAITP
BCF WAIT
BSF SPKP ; Start pip
GOTO ENDINT
GENPIP
; Generate 1 kHz, WAITP set
DECFSZ PERIOD,1
GOTO ENDINT
MOVLW 0x0C ; 1 kHz
MOVWF PERIOD
MOVLW B'00110000'
XORWF GPIO,1 ; Toggle SPKP and SPKN
DECFSZ PIPON,1
GOTO ENDINT
BCF SPKP
BCF SPKN
BCF WAITP
BSF WAIT
MOVLW 0x32
MOVWF PIPON
DECFSZ PIPCOUNT,1 ; # of pips
GOTO ENDINT
BCF WAIT
BSF PREPEW
BCF SPKP
BCF SPKN
MOVLW 0x02
MOVWF PIPCOUNT
MOVLW 0x3F
MOVWF PIPOFF
MOVLW 0xFF
MOVWF PERIOD
GOTO ENDINT
GENPREPEW
; Wait 652 ms, PREPEW set
DECFSZ PERIOD,1 ; Inner loop? (resumes @ 0xFF)
GOTO ENDINT
DECFSZ PIPOFF,1 ; Outer loop? (total 0x3FFF)
GOTO ENDINT
MOVLW 0x2B ; 0x2B=0.279 ms, 0xD2=1.61 ms
MOVWF PERIOD
MOVWF PIPOFF ; Copy of PERIOD
MOVLW 0x04 ; Slide extender
MOVWF PIPON
BCF PREPEW
BSF PEW
BCF RED
BSF GRN
BSF SPKP ; Start pew
GOTO ENDINT
GENPEW
; Doesn't use TMR0 to create the gliding tone but PERIOD, PIPON and PIPOFF
DECFSZ PERIOD,1
GOTO GENPEW
CALL PEWTOGGLE
DECFSZ PIPON,1
GOTO GENPEW
MOVFW PIPOFF ; Restore PERIOD
MOVWF PERIOD
MOVLW 0x08 ; Slide extender (note: one cycle is two periods)
MOVWF PIPON
INCF PIPOFF,1
MOVLW 0x40
SUBWF PIPOFF,0
BTFSS STATUS,Z ; Test for short slide extender
GOTO GENPEW ; Not yet
MOVFW PIPOFF ; Restore PERIOD
MOVWF PERIOD
GENPEW1
DECFSZ PERIOD,1
GOTO GENPEW1
CALL PEWTOGGLE
DECFSZ PIPON,1
GOTO GENPEW1
MOVFW PIPOFF ; Restore PERIOD
MOVWF PERIOD
MOVLW 0x04 ; Slide extender
MOVWF PIPON
INCF PIPOFF,1
MOVLW 0x4D
SUBWF PIPOFF,0
BTFSS STATUS,Z ; Test for shorter slide extender
GOTO GENPEW1 ; Not yet
MOVFW PIPOFF ; Restore PERIOD
MOVWF PERIOD
GENPEW2
DECFSZ PERIOD,1
GOTO GENPEW2
CALL PEWTOGGLE
DECFSZ PIPON,1
GOTO GENPEW2
MOVFW PIPOFF ; Restore PERIOD
MOVWF PERIOD
MOVLW 0x02 ; Slide extender
MOVWF PIPON
INCF PIPOFF,1
MOVLW 0x7C
SUBWF PIPOFF,0
BTFSS STATUS,Z ; Test for end slide extender
GOTO GENPEW2 ; Not yet
MOVFW PIPOFF ; Restore PERIOD
MOVWF PERIOD
GENPEW3
DECFSZ PERIOD,1
GOTO GENPEW3
CALL PEWTOGGLE
INCF PIPOFF,1
MOVLW 0xC8
SUBWF PIPOFF,0
BTFSC STATUS,Z ; Test for end pew
GOTO ENDPEW ; Yes
GOTO GENPEW3
PEWTOGGLE
; Subroutine, used four times in GENPEW
MOVFW PIPOFF ; Restore PERIOD
MOVWF PERIOD
MOVLW B'00110000'
XORWF GPIO,1 ; Toggle SPKP and SPKN
RETURN
ENDPEW
BCF SPKP
BCF SPKN
BCF PEW
BSF PREPOP
MOVLW 0xFF
MOVWF PERIOD
GOTO ENDINT
GENPREPOP
; Wait 12 ms, PREPOP set
DECFSZ PERIOD,1
GOTO ENDINT
BSF POP
BCF PREPOP
MOVLW 0x69 ; 105 pops
MOVWF PIPCOUNT
MOVLW 0x19 ; 480 Hz
MOVWF PERIOD
MOVLW 0x0C ; pop of 12 ms is only 6 cycles
MOVWF PIPON
BSF SPKP ; Start pop
NOGENPOP
; Registers for pip are reused, NOPOP set, wait 122 ms
DECFSZ PERIOD,1
GOTO ENDINT
MOVLW 0x19 ; 480 Hz
MOVWF PERIOD
DECFSZ PIPOFF,1 ; Loop?
GOTO ENDINT
MOVLW 0x78
MOVWF PIPOFF
MOVLW 0x0C
MOVWF PIPON
BSF POP
BCF NOPOP
BSF SPKP ; Start pop
GOTO ENDINT
GENPOP
; Generate 480 Hz, POP set
DECFSZ PERIOD,1
GOTO ENDINT
MOVLW 0x19 ; 480 Hz
MOVWF PERIOD
MOVLW B'00110000'
XORWF GPIO,1 ; Toggle SPKP and SPKN
DECFSZ PIPON,1
GOTO ENDINT
BCF SPKP
BCF SPKN
BCF POP
BSF NOPOP
MOVLW 0x78
MOVWF PIPOFF
DECFSZ PIPCOUNT,1 ; # of pips
GOTO ENDINT
BCF POP
BSF IDLE
BCF SPKP
BCF SPKN
BCF GRN
BSF RED
MOVLW 0x0C ; 1 kHz
MOVWF PERIOD
MOVLW 0x32
MOVWF PIPON
MOVLW 0x4C
MOVWF PIPOFF
ENDINT
BSF INTCON,GIE ; Enable global interrupts
RETFIE
START
CLRF STATUS ; Do initialization, Select bank 0
CLRF INTCON ; Clear int-flags, Disable interrupts
CLRF PCLATH ; Keep in lower 2KByte
BANKSEL TRISIO
MOVLW B'00001100' ; All outputs except GPIO3 (MCLR) and GPIO2 (BTN)
MOVWF TRISIO
MOVLW B'00000000' ; TMR0 Prescaler 1:2
MOVWF OPTION_REG
BANKSEL T1CON
CLRF T1CON
MOVLW B'00000111' ; Comparators off
MOVWF CMCON
MOVLW B'10100000' ; Enable GIE, TMR0 interrupt
MOVWF INTCON
CLRF GPIO
BSF RED
MOVLW 0x0C ; 1 kHz
MOVWF PERIOD
CLRF STATE
BSF IDLE ; Wait for button
MOVLW 0x32 ; Prep pip
MOVWF PIPON
MOVLW 0x4C
MOVWF PIPOFF
MAIN
INCF RND,1
GOTO MAIN
END