?? audio.asm
字號:
; audio.asm
; Program to demonstrate the use of PWM using the CCP modules on the PIC
; by driving the audio output on the Raven board.
;
; PWM output is a square wave with the following characteristics
;
; Period
; |<----------------->|
;
; |-------| |-------|
; | | | |
; -------| |-----------| |-------
;
; :<----->: :
; : Duty : :
; : Cycle : TMR2 = PR2
; : :
; TMR2=PR2 TMR2 = Duty Cycle
;
; You begin with PR2 set to some value. Timer2 is started and when the
; Timer2 count register is equal to PR2, the PWM output goes high. It
; then resets Timer2 and counts until the Timer2 count equals the duty
; cycle counter (CCPRxL:CCP1CON) and then the signal goes low again.
; Then the process starts again. So the period consists of a high part
; and a low part, defined by the period and the duty cycle. Note that
; the duty cycle need not be one-half of the period. Normally the duty
; cycle is reported as a percentage, such as 65%, meaning that 65% of the
; period the signal is high.
;
; In this instance, we want to generate signals that can be used to drive
; a speaker, so we will have a duty cycle of 50% and we will want to vary
; the frequency (by varying the period) to get different tones.
LIST P=16F877, R=DEC
INCLUDE "P16F877.inc"
; Definitions
; __CONFIG _CP_OFF & _DEBUG_OFF & _WRT_ENABLE_OFF & _CPD_OFF & _LVP_OFF & _BODEN_OFF & _PWRTE_ON & _WDT_OFF & _HS_OSC20
; Define start of vars
RAM EQU 0x20
; Variables
Temp EQU RAM+0
DTemp1 EQU RAM+1
DTemp2 EQU RAM+2
Counter EQU RAM+3
; Start of the Program
ORG 3
goto Start
ORG 4
Timer1ISR
; Since PWM won't give us the low end frequencies we want, we will generate our own.
; Timer1 will be set up to interrupt every 1/4000 seconds to give us the desired
; resolution. Then, we will set our own version of T2CON to determine the period.
; In this case, the duty cycle is always 50%, so its not a problem.
;
;
ORG 0x20
; The frequencies are numbered 0 through 15 and represent an uniformly spaced
; group from 1225 Hz to 9470 Hz in steps of about 550Hz.
GetFreq
addwf PCL,F
retlw 33
retlw 48
retlw 63
retlw 77
retlw 92
retlw 107
retlw 122
retlw 137
retlw 151
retlw 166
retlw 181
retlw 196
retlw 211
retlw 225
retlw 240
retlw 255
SongNote
addwf PCL,F
retlw 0x0F
retlw 0x0E
retlw 0x1B
retlw 0x0C
retlw 0x0B
retlw 0x09
retlw 0x0A
retlw 0x0B
retlw 0x0C
retlw 0x0D
retlw 0x1A
retlw 0x1C
Start
bsf STATUS, RP0
bcf TRISC,2 ; PWM output port
bcf STATUS, RP0
call PWMConfig
; Go through a cycle of creating some special sounds. We aren't far from music
; here. Everybody sing along!!
movlw 11
movwf Counter
main_loop
movf Counter,W
call SongNote
call PlayNote
decfsz Counter,F
goto main_loop
movlw 11
movwf Counter
goto main_loop
; Sound support
PlayNote
movwf Temp
andlw 0x0F
call GetFreq
call PWMSetPeriod
movlw 250
btfss Temp,7
movlw 100
call Delay_ms
return
; -------------------------------------------------------------------
; PWM routines
; We want to have frequencies in the range of 100 Hz to about 10,000 Hz, so
; we need periods of 0.01 to 0.0001. Given the formula:
; PWM period = [PR2 + 1] * 4 / Fosc * Timer2 Prescale Value
;
; and an oscillator frequency of 20Mhz (Fosc),
; For a 20 MHz clock, the frequency table is:
;
; Prescaler Pr2=1 Pr2=255
; 1 5 MHz 1.9608 kHz
; 4 1.25 MHz 4.902 kHz
; 16 0.3125 MHz 1.225 kHz
;
; So we will have to use two different prescalers. One for use a prescaler of 4 for Timer2 and let Pr2 vary from 208 down
; to about 0.
PWMConfig
; Initialize CCP1
movlw 255
call PWMSetPeriod
movlw b'00100000' ; duty cycle is 50% = 128
movwf CCPR1L
movlw b'00000110' ; Timer 2 is on and prescaler is 16
movwf T2CON
movlw b'00001100' ; PWM mode with two LSB's = 00
movwf CCP1CON
return
PWMSetPeriod
bsf STATUS,RP0
movwf PR2 ; set period
bcf STATUS,C
rrl PR2,W ; and duty cycle = period/2
movwf CCPR1L
bcf STATUS,RP0
return
; -----------------------------------------------
; Output a value to the LED bar
DispLedBar
; Enable the led bar and put the value in W there.
movwf Temp ; save W
movlw 0x12
movwf PORTA
comf Temp,W
movwf PORTD
return
; -------------------------
; Delay milliseconds
Delay_ms
bsf STATUS,RP0
bsf STATUS,RP1
movwf DTemp1
dloop_0 ; number of ms to delay
movlw 250
movwf DTemp2
dloop_1 ; 1 ms delay (approximately)
fill (nop), 17
decfsz DTemp2,F
goto dloop_1
decfsz DTemp1,F
goto dloop_0
bcf STATUS,RP1
bcf STATUS,RP0
return
END
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -