LIST P=PIC16F628A
include "P16F628A.inc"
__config h'3f18' ; sets the configuration settings - internal oscillator, watchdog timer OFF
; Power Up Timer DISABLED, Master Clear DISABLED, Brown Out Detect DISABLED,
; Low Voltage Programming DISABLED, Data EE Read Protect Disabled,
; Code Protect OFF. (this will remain the same for all tutorials)
; Start by setting bits.
; We want RA5 to be an input and we will use a debouce funcion to use the input to do something
; We use prescaler of 16 to have a wider audio range at PWM
PeriodTicks equ 62 ; And a PR2 of 62. Running at internal OSC of 4 Mhz it gives a clock of 1 Mhz
; that programs the PWM to output 1008 Hz using PR2 = 62 and PRESCALER = 16
;DutyCycle equ 31*4 ; Duty cicle almost 50% of PR2
CCPREGv equ b'00001100' ; Value for CCP1 CCP1CON = 2 LSBs of DutyCycle and set PWM operation
CCP1RLv equ b'00011110' ; 8 MSB of the Duty Cycle
TIMER2v equ b'00000110' ; Set prescaler to 16, activate TIMER2
cblock h'20' ; Within this cblock and endc, we can define our variables. More info on this, later.
delay_1 ; These next two lines will set aside 1byte of ram for delay_1 and 1byte for delay_2
delay_2 ; what we will do with these variables is load them with a number each so that we can
delay_3 ; count down from that number to zero. when we reach zero, we continue with the program!
debounce1 ; for using a debouce routine on our button at RA5
button1 ; when >0 button 1 has been pressed.
volume ; Value to output on PORTA ... between 0 and 0x0F
endc
org h'0000' ; This line just tells the microcontroller what address to start running our program from.
; It will always be 0000 hex for all the tutorials.
movlw h'07' ; This will turn the comparators OFF.
movwf CMCON ; (we just want to use the ports as digital ports)
setup ; I always have a title labeled 'setup' this is where we set everything up
; i.e. our variables and flags etc.. so they are ready for the main program
movlw 0x0F
movwf volume ; set maximum volume 00001111b we only use PORTA0 thru PORTA3
;bsf STATUS, RP0 ; select bank 1 (to enable us to change the Input / Output status of our ports)
banksel PR2
movlw d'62' ; Write the period to the PR2 register
movwf PR2
movlw b'00000000' ; set PORTB all outputs (A '0' means output, A '1' means input.
movwf TRISB ; We can set each bit individualy. Each port having 8-bits or 8 pins.
; this sets the CCP1 pin as output.
movlw b'00100000' ; set PORTA all outputs except for bit 5. Bit 5 is an input ONLY pin.
movwf TRISA ; It cannot be set to an output!
;bcf STATUS, RP0 ; select bank 0
banksel CCPR1L
movlw CCP1RLv ;
movwf CCPR1L ; Set values for the PWM period
movlw CCPREGv
movwf CCP1CON ; Set LSB of PWM period and activate PWM operation
movlw TIMER2v
movwf T2CON ; Set TIMER2 Control Operation, prescaler and activate TIMER2
; PWM must start working on RB3/CCP1
; Write PRESCALER VALUE
; Write DUTY CYCLE VALUE
begin ; This is where our main program starts.
movf volume,0 ; volume -> W
movwf PORTA ; W -> PORTA Output volume value
bcf PORTB, 0 ; clear PORTB pin 0 to a logic 0 (turns the LED off)
call chirp1 ; call the delay so that the LED stays on for a while
call CheckButton1 ; See if button was pressed
bsf PORTB, 0 ; set PORTB pin 0 to a logic 1 (turns the LED on)
call chirp2 ; call the delay so that the LED stays off for a while
call CheckButton1 ; See if button was pressed
bcf PORTB, 0 ; clear PORTB pin 0 to a logic 0 (turns the LED off)
call CheckButton1 ; See if button was pressed
call Silence
goto setup ; and now go and do it all again (it will run in a continuos loop)
Delay
clrf debounce1 ; clear debounce counter
movlw d'100' ; copy the maximum number to our working register (decimal 255)
movwf delay_1 ; and now copy it from the w register to delay_1 and delay_2
movwf delay_2 ; Now the rest of the routine will focus on counting down to zero.
delay_loop ; We come back to this label when we have not yet reached zero.
decfsz delay_1, f ; decrement whatever is in delay_1 by 1 and store the answer back in delay_1
goto delay_loop ; if the answer is not zero, then go back to the delay_loop label. but if the
movwf delay_1 ; and now copy it from the w register to delay_1 and delay_2
decfsz delay_2, f ; answer is zero then decrement delay_2 by one and store the answer in delay_2
goto delay_loop ; if the answer is not zero, then go back to delay_loop label. but if the answer
movwf delay_2 ; is zero, then we have completed our delay and now we can return to our main program!
btfsc PORTA,5 ; let's check for some input in RA5. If button is pressed it will read 0, otherwise it reads 1
incf debounce1,1 ; if RA5 is set then add 1 to deboucel
btfss PORTA,5
clrf debounce1 ; if RA5 is not set then we drop the count as it could be a switch bounce
btfsc debounce1,2 ; if bit 2 is set on debocel then the RA5 has been pressed and found RA5=1 for 5 cycles and is validated.
bsf button1,0
decfsz delay_3, f ;
goto delay_loop
return
DelayVolumeDown
clrf debounce1 ; clear debounce counter
movf volume,0 ; volume -> W
movwf PORTA ; W -> PORTA Output volume value
movlw d'125' ; 125 loops yield 250 clock cycles yield 0.0625 secs delay
movwf delay_1 ; and now copy it from the w register to delay_1 and delay_2
movwf delay_2 ; Now the rest of the routine will focus on counting down to zero.
delay_loop_volumedown ; We come back to this label when we have not yet reached zero.
decfsz delay_1, f ; decrement whatever is in delay_1 by 1 and store the answer back in delay_1
goto delay_loop_volumedown ; if the answer is not zero, then go back to the delay_loop label. but if the
movwf delay_1 ; and now copy it from the w register to delay_1 and delay_2
decfsz delay_2, f ; answer is zero then decrement delay_2 by one and store the answer in delay_2
goto delay_loop_volumedown ; if the answer is not zero, then go back to delay_loop label. but if the answer
movwf delay_2 ; is zero, then we have completed our delay and now we can return to our main program!
movf volume,0 ; volume -> W
movwf PORTA ; W -> PORTA Output volume value
decf volume,1 ; This is for having the volume decreased in 1 step
movlw d'125' ;
decfsz delay_3, f ;
goto delay_loop_volumedown
return
chirp1
;bsf STATUS, RP0 ; select bank 1 (to enable us to change the Input / Output status of our ports)
banksel PR2
movlw d'62' ; Write the period to the PR2 register, output 1008 Hz
movwf PR2
banksel 0
movlw d'2'
movwf delay_3
call Delay
return
chirp2
banksel PR2
movlw d'47' ; Write the period to the PR2 register for 1329 Hz
movwf PR2
banksel 0
movlw 0x1F
movwf volume ; restore maximum volume
movlw d'16' ; 16 loops of DelayVolumeDown aproximate 1 sec (original coin sound is 0.8 secs)
movwf delay_3
;buscar forma de ir bajando el volumen de 15 a 0 en 20 pasos
;
;
call DelayVolumeDown
return
chirp3
banksel PR2
movlw d'142' ; Write the period to the PR2 register for 440 Hz
movwf PR2
banksel 0
movlw d'25' ; 25 delays = 1 sec
movwf delay_3
call Delay
return
CCP1Reset
banksel CCP1CON ; select bank 0
clrw
movwf CCP1CON ; reset/stop PWM operation
return
Silence
call CCP1Reset
movlw d'25'
movwf delay_3
call Delay ; Delay about 1 seconds
return
CheckButton1
clrw
movwf volume ; put 0 on volume
decf volume,1
movf button1,1 ; Test if button1 is Z
btfsc STATUS,2 ; button1 is Zero, do nothing, return
return ;
clrf button1 ; set button1 to Zero
keeptone
movf volume,0 ; volume -> W
movwf PORTA ; W -> PORTA Output volume value
decf volume,1 ; This is for having the volume decreased in 1 step
call chirp3
movf button1,0 ; Test if button1 is Z
btfsc STATUS,Z ; Button1 pressed again?
goto keeptone ; button1 is Zero, keep output of chirp3
clrf button1
movlw 0x0F
movwf volume ; restore maximum volume
return ; button1 is non Zero, clear it & return
end ; We always need to have end at the end, even if we don't want the program
; to actually end, it still must be here![/FONT]