;************************************************************************** ; FILE: chorus.asm * ; CONTENTS: Dawn Chorus * ; COPYRIGHT: MadLab Ltd. 2002 * ; AUTHOR: James Hutchby * ; UPDATED: 17/10/03 * ;************************************************************************** list p=12C508A include "p12c508a.inc" __config _IntRC_OSC & _WDT_ON & _MCLRE_OFF & _CP_ON __idlocs h'CF10' errorlevel -302,-305 ;************************************************************************** ; * ; Specification * ; * ;************************************************************************** ; power-up self-test - beeps continuously if ldr failure else beeps twice ; pushbutton pressed on power-up -> ldr resistance indicated by variable tone ; wakes from sleep every ~2.5 secs and samples light level ; averages samples over last ~1.25 mins ; if last 8 averages show increasing light level then triggers dawn chorus ; 8 birds, wake up one by one ; songs gets progressively louder ; reaches a peak then slows down ; resets if pushbutton pressed or after ~8 mins ; if pushbutton held down for 2 secs then triggers dawn chorus demo ; ldr charges in ~20us at 10k, ~20ms at 10M ;************************************************************************** ; * ; Port assignments * ; * ;************************************************************************** GPIO_IO equ b'111000' ; port I/O status #define CAP GPIO,4 ; capacitor #define LDR GPIO,5 ; ldr #define BUTTON GPIO,3 ; pushbutton #define SPK1 GPIO,2 ; speaker #define SPK2 GPIO,1 #define SPK3 GPIO,0 charge macro ; charge capacitor clrf GPIO movlw GPIO_IO&~(1<<5) tris GPIO endm discharge macro ; discharge capacitor clrf GPIO movlw GPIO_IO&~(1<<4) tris GPIO endm ;************************************************************************** ; * ; Constants and timings * ; * ;************************************************************************** CLOCK equ d'4000000' ; processor clock frequency in Hz DISCHARGE equ d'1' ; capacitor discharge period in ms DAWN_RATE equ d'1' ; threshold for rate of light level increase BUFFER equ d'8' ; sample history/bird songs buffer size MAX_BIRDS equ BUFFER ; maximum number of birds SAMPLES equ d'32' ; number of samples averaged BIRD_RATE equ d'16' ; development rate (~8 mins in total) ;************************************************************************** ; * ; File register usage * ; * ;************************************************************************** RAM equ h'07' cblock RAM flags ; various flags volume ; volume (1 - 3, 5 - 7) cycles ; cycles pnt:0, pitch ; history pointer/pitch sum:0, offset, spread ; samples sum/pitch offset and spread samples:0, birds ; number of samples/birds song ; song history:0, songs:BUFFER ; sample history/bird songs repeat ; repeat counter timer:2 ; timers clock ; clock rand_l, rand_h ; random number count ; scratch counter work1, work2 ; work registers RAM_ endc if RAM_ > h'20' error "File register usage overflow" endif ; flags RELEASE equ 0 ; set if waiting for pushbutton release POLL equ 1 ; set if pushbutton polled during wait DIREC equ 2 ; envelope direction AWAKE equ 3 ; set if all birds awake DEMO equ 4 ; set if demo mode DAWN equ 5 ; set if dawn ;************************************************************************** ; * ; Macros * ; * ;************************************************************************** routine macro label ; routine label endm label macro label ; label label endm table macro label ; define lookup table label addwf PCL endm entry macro value ; define table entry retlw value endm index macro label ; index lookup table call label endm jump macro label ; jump through table goto label endm tstw macro ; test w register iorlw 0 endm movff macro f1,f2 ; move file to file movfw f1 movwf f2 endm movlf macro n,f ; move literal to file movlw n movwf f endm tris_A macro ; tristate port A bsf STATUS,RP0 movwf TRISA&h'7f' bcf STATUS,RP0 endm tris_B macro ; tristate port B bsf STATUS,RP0 movwf TRISB&h'7f' bcf STATUS,RP0 endm option_ macro ; set options bsf STATUS,RP0 movwf OPTION_REG&h'7f' bcf STATUS,RP0 endm ;-------------------------------------------------------------------------- ; reset vector ;-------------------------------------------------------------------------- org 0 movwf OSCCAL goto main_entry ;************************************************************************** ; * ; Lookup tables * ; * ;************************************************************************** table volume_table entry 1 ; 0 entry 1 ; 1 entry 1 ; 2 entry 1 ; 3 entry 2 ; 4 entry 2 ; 5 entry 2 ; 6 entry 3 ; 7 entry 3 ; 8 entry 5 ; 9 entry 5 ; 10 entry 6 ; 11 entry 6 ; 12 entry 7 ; 13 entry 7 ; 14 ;************************************************************************** ; * ; Procedures * ; * ;************************************************************************** ;-------------------------------------------------------------------------- ; polls the pushbutton, returns NZ flag set if pushbutton pressed ;-------------------------------------------------------------------------- routine poll bsf BUTTON setz btfss BUTTON clrz btfss flags,RELEASE ; waiting for release ? goto poll1 ; branch if not skpnz ; wait for pushbutton to be bcf flags,RELEASE ; released setz poll1 retlw 0 ;-------------------------------------------------------------------------- ; generates a pseudo random number ;-------------------------------------------------------------------------- routine get_random movfw rand_l iorwf rand_h,w bnz getr1 movfw TMR0 ; seed generator movwf rand_l xorlw h'ff' movwf rand_h getr1 rlf rand_h,w ; calculate next in sequence xorwf rand_h,w movwf work1 ; msb <= Q15 ^ Q14 swapf rand_l,w btfsc rand_h,4 xorlw h'80' ; msb <= Q12 ^ Q3 xorwf work1 rlf work1 rlf rand_l rlf rand_h ; << 1 + (Q15 ^ Q14 ^ Q12 ^ Q3) retlw 0 ;-------------------------------------------------------------------------- ; waits for a number of milliseconds, fed with the wait in the wreg ;-------------------------------------------------------------------------- routine wait_ms movwf work1 wait1 movlf CLOCK/(d'1000'*d'20'),work2 wait2 clrwdt ; [4] nop ; [4] decfsz work2 ; [4] goto wait2 ; [8] decfsz work1 goto wait1 retlw 0 ;-------------------------------------------------------------------------- ; waits, fed with the wait in 1/100s in the w reg ;-------------------------------------------------------------------------- routine wait movwf count wait3 movlf CLOCK/(d'100'*d'16'*d'256'),work1 wait4 clrf work2 wait5 clrwdt ; [4] decfsz work2 ; [4] goto wait5 ; [8] decfsz work1 goto wait4 btfss flags,POLL goto wait7 bsf BUTTON ; poll pushbutton setz btfss BUTTON clrz btfss flags,RELEASE ; waiting for release ? goto wait6 ; branch if not skpnz ; wait for pushbutton to be bcf flags,RELEASE ; released setz wait6 bnz stop_chorus ; branch if pushbutton pressed wait7 decfsz count goto wait3 retlw 0 ;-------------------------------------------------------------------------- ; tests the ldr, returns NZ flag set if present ;-------------------------------------------------------------------------- routine test_ldr movlw b'01001111' ; prescale WDT 1:128, option ; weak pull-ups disabled discharge ; discharge the capacitor movlw DISCHARGE call wait_ms clrf timer+0 ; charge the capacitor through clrf timer+1 ; the ldr charge bsf LDR test1 clrwdt nop nop nop nop nop nop nop nop nop nop bsf CAP incf timer+1 skpnz incf timer+0 movfw timer+0 iorwf timer+1,w bz test2 ; branch if timeout btfss CAP goto test1 clrz ; signal ok goto test3 test2 setz ; signal error test3 retlw 0 ;-------------------------------------------------------------------------- ; samples the current light level ;-------------------------------------------------------------------------- routine sample_ldr movlw b'01001111' ; prescale WDT 1:128, option ; weak pull-ups disabled discharge ; discharge the capacitor movlw DISCHARGE call wait_ms clrf timer ; charge the capacitor through clrwdt ; the ldr charge bsf LDR bsf CAP samp1 incf timer ; [4] skpnz ; [8] goto samp2 btfss CAP ; [4] goto samp1 ; [8] goto samp3 samp2 decf timer ; overflow samp3 retlw 0 ;-------------------------------------------------------------------------- ; single beep ;-------------------------------------------------------------------------- BEEP_PITCH equ d'40' BEEP_PERIOD equ d'200' routine beep movlf BEEP_PERIOD,cycles movlw BEEP_PITCH ; goto do_sound ;-------------------------------------------------------------------------- ; sound ;-------------------------------------------------------------------------- routine do_sound btfss volume,0 ; speaker on bcf SPK1 btfsc volume,0 bsf SPK1 btfss volume,1 bcf SPK2 btfsc volume,1 bsf SPK2 bcf SPK3 movwf work1 ; half-cycle delay dos1 clrwdt ; [4] decfsz work1 ; [4] goto dos1 ; [8] bcf SPK1 ; speaker on bcf SPK2 btfss volume,2 bcf SPK3 btfsc volume,2 bsf SPK3 movwf work1 ; half-cycle delay dos2 clrwdt ; [4] decfsz work1 ; [4] goto dos2 ; [8] decfsz cycles goto do_sound bcf SPK1 ; speaker off bcf SPK2 bcf SPK3 retlw 0 ;-------------------------------------------------------------------------- ; chirping ;-------------------------------------------------------------------------- CHIRP_PITCH equ d'40' CHIRP_PERIOD equ d'45' CHIRP_ENV equ d'20' routine chirp movfw song andlw b'111' movwf spread movlw d'5' addwf spread movlw CHIRP_PERIOD-d'5' btfsc song,7 movlw CHIRP_PERIOD+d'5' movwf repeat movlw CHIRP_PITCH-d'2' btfsc song,6 movlw CHIRP_PITCH+d'2' movwf pitch clrf offset bcf flags,DIREC btfsc song,5 bsf flags,DIREC chirp1 movlw CHIRP_ENV-d'2' btfsc song,4 movlw CHIRP_ENV+d'2' movwf cycles movfw pitch addwf offset,w call do_sound call poll bnz stop_chorus btfsc flags,DIREC incf offset btfss flags,DIREC decf offset movfw spread subwf offset,w bz chirp2 movfw spread addwf offset,w bnz chirp4 chirp2 btfsc song,3 goto chirp3 comf offset incf offset goto chirp4 chirp3 movlw 1<