⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 specana.asm

📁 快速傅里叶变换在单片机中的实现,可用来显示生音波形
💻 ASM
📖 第 1 页 / 共 2 页
字号:
;-----------------------------------------------------------------------------;
;                              
; (                                       ;
;-----------------------------------------------------------------------------;
; Edited by Fabian "ape" Thiele                             Jan 26, 2005      ;
; me@apetech.de                                                               ;
; http://www.apetech.de                                                       ;
;                                                                             ;
; MPU:   ATmega32                                                             ;
; Clock: 18.432MHz                                                            ;
;-----------------------------------------------------------------------------;
;
.include "m32def.inc"
.include "avr.inc"
.include "akiglcd.inc"

.equ	FFT_N		= 128	;Number of samples

.equ	FFT_SCALE	= 256/2	;FFT scaling
.equ	FFT_BDEC	= 4	;Bar decay rate
.equ	FFT_PS		= 6	;Peak Speed

.equ	TWI_ADR		= 0x10	;TWI Slave Address
.equ	TWI_RECV_ACK	= (1<<TWIE) | (1<<TWEN) | (1<<TWINT) | (1<<TWEA)
.equ	TWI_RECV_NACK	= (1<<TWIE) | (1<<TWEN) | (1<<TWINT)
.equ	TWI_TRANS_ACK	= (1<<TWIE) | (1<<TWEN) | (1<<TWINT) | (1<<TWEA)
.equ	TWI_TRANS_NACK	= (1<<TWIE) | (1<<TWEN) | (1<<TWINT)
.equ	TWI_NOT_ADDR	= (1<<TWIE) | (1<<TWEN) | (1<<TWINT) | (1<<TWEA)

.def	_0		= r15	;Zero
.def	_Flags		= r25	;b0: capture loRes, b1: capture hiRes, b7: ADC hiRes-Mode: 1st/2nd Sample

;----------------------------------------------------------;
; Data memory area

.dseg
	.org	RAMTOP
CaptBuf:	.byte	FFT_N*2		;Sampling buffer
BflyBuf:	.byte	FFT_N*4		;Butterfly operation table, Wave form buffer
AdPtr:		.byte	2		;Sampling pointer for hiRes FFT
hiResPS:	.byte	1		;Software ADC prescaler for high resolution prescaling
TwiPtr:		.byte	2		;TWI read pointer

TmpLvlBuf1:	.byte	FFT_N/2		;Temp level buffer for hiRes FFT
PeakSpeedBuf1:	.byte	FFT_N/2		;Peak speed buffer for hiRes FFT

TmpLvlBuf2:	.byte	FFT_N/2		;Temp level buffer for loRes FFT
PeakSpeedBuf2:	.byte	FFT_N/2		;Peak speed buffer for loRes FFT

TmpLvlBuf3:	.byte	78		;Temp level buffer for interpolated FFT
PeakSpeedBuf3:	.byte	78		;Peak speed buffer for interpolated FFT


LvlBuf1:	.byte	FFT_N/2		;Spectrum bar length for hiRes FFT
PeakBuf1:	.byte	FFT_N/2		;Peak buffer for hiRes FFT

LvlBuf2:	.byte	FFT_N/2		;Spectrum bar length for loRes FFT
PeakBuf2:	.byte	FFT_N/2		;Peak buffer for loRes FFT

LvlBuf3:	.byte	78		;Spectrum bar length for interpolated FFT
PeakBuf3:	.byte	78		;Peak buffer for interpolated FFT


;----------------------------------------------------------;
; Program code area

.cseg
	jmp	reset		; RESET
	jmp	0		; INT0
	jmp	0		; INT1
	jmp	0		; INT2
	jmp	0		; TC2 COMP
	jmp	0		; TC2 OVF
	jmp	0		; TC1 CAPT
	jmp	0		; TC1 COMPA
	jmp	0		; TC1 COMPB
	jmp	0		; TC1 OVF
	jmp	0		; TC0 COMP
	jmp	0		; TC0 OVF
	jmp	0		; SPI
	jmp	0		; USART RXC
	jmp	0		; USART UDRE
	jmp	0		; USART TXC
	jmp	isr_adc		; ADC
	jmp	0		; EE_RDY
	jmp	0		; ANA_COMP
	jmp	isr_twi		; TWI
	jmp	0		; SPM_RDY


;----------------------------------------------------------;
; ADC interrupt (22.2ksps)


isr_adc:
	push	AL
	in	AL, SREG
	pushw	A
	pushw	B
	pushw	Y
	push	CL


	; Sample for high resolution FFT
	sbrs	_Flags, 0	;Skip if in Idle
	rjmp	adc_loRes	;/
	ldsw	Y, AdPtr	;load pointer
	addiw	Y, CaptBuf	;/
	inw	A, ADC		;load A/D value
	sbrs	_Flags, 7	;1st or 2nd sample?
	rjmp	isr_adc_l1
	ldw	B, Y+		;load value
	subiw	Y, 2		;/
	addw	B, A		;add sample
	lsrw	B		;value = value / 2
	stw	Y+, B		;store down-sampled value
	subiw	Y, CaptBuf	;store incremented pointer
	stsw	AdPtr, Y	;/
	cbr	_Flags, bit7	;clear flag for 2nd sample
	cpiw	Y, FFT_N*2	;Terminate if FFT_N/2 samples captured.
	brne	adc_skip
	clrw	A
	stsw	AdPtr, A
	cbr	_Flags, bit0	;/
	rjmp	adc_skip
isr_adc_l1:
	stw	Y+, A		;store sample
	sbr	_Flags, bit7	;set flag for 2nd sample

adc_loRes:
	; Sample for low resolution FFT
	sbrs	_Flags, 1	;Skip if in Idle
	rjmp	adc_skip	;/
	ldsw	Y, AdPtr	;load pointer
	addiw	Y, CaptBuf	;/
	inw	A, ADC		;load A/D value
	stw	Y+, A		;store sample
	subiw	Y, CaptBuf	;
	stsw	AdPtr, Y	;/
	cpiw	Y, FFT_N*2	;Terminate if FFT_N/2 samples captured.
	brne	adc_skip
	clrw	A
	stsw	AdPtr, A
	cbr	_Flags, bit1	;/

adc_skip:
	pop	CL
	popw	Y
	popw	B
	popw	A
	out	SREG, AL
	pop	AL
	reti


;----------------------------------------------------------;
; TWI interrupt
isr_twi:
	push	AL
	in	AL, SREG
	pushw	A
	pushw	Y

	in	AL, TWSR
	andi	AL, 0xF8

	;Slave Receiver Status Codes
	cpi	AL, 0x60		; SLA+W received, ACK returned
	breq	twi_sla_w
	cpi	AL, 0x80		; Data received, ACK returned
	breq	twi_data_recv_ack
	cpi	AL, 0x88		; Data received, NACK returned
	breq	twi_data_recv_nack
	;Slave Transmitter Status Codes
	cpi	AL, 0xA8		; SLA+R received, ACK returned
	breq	twi_sla_r
	cpi	AL, 0xB8		; Data byte in TWDR transmitted, ACK received
	breq	twi_data_trans_ack
	cpi	AL, 0xC0		; Data byte in TWDR transmitted, NACK received
	breq	twi_data_trans_nack
	cpi	AL, 0xC8		; Last byte transmitted, ACK received
	breq	twi_last_data_trans_ack

	outi	TWCR, TWI_NOT_ADDR	; Default: Switch to not addressed slave mode
	rjmp	isr_twi_end

twi_sla_w:
	outi	TWCR, TWI_RECV_ACK	; receive data, return ACK
	rjmp	isr_twi_end

twi_data_recv_ack:
	in	AL, TWDR		; get 1st (high) address byte
	sts	TwiPtr+1, AL		; /
	outi	TWCR, TWI_RECV_NACK	; receive next byte, return NACK
	rjmp	isr_twi_end

twi_data_recv_nack:
	in	AL, TWDR		; get 2nd (low) address byte
	sts	TwiPtr, AL		; /
	outi	TWCR, TWI_NOT_ADDR	; Switch to not addressed slave mode
	rjmp	isr_twi_end

twi_sla_r:
	ldsw	Y, TwiPtr		; get requested address
	addiw	Y, LvlBuf1		; /
	ld	AL, Y+			; Load first level into TWDR
	out	TWDR, AL		; /
	stsw	TwiPtr, Y		; Store next pointer
 	outi	TWCR,TWI_TRANS_ACK	; Start TWI transmission
	rjmp	isr_twi_end

twi_data_trans_ack:
	ldsw	Y, TwiPtr		; Load next address
	ld	AL, Y+			; Load next level into TWDR
	out	TWDR, AL		; /
	stsw	TwiPtr, Y		; Store next pointer
	cpiw	Y, PeakBuf3+78		; Stop transmission if end of spectrum memory reached
	breq	twi_stop_trans		; /
	outi	TWCR, TWI_TRANS_ACK	; Start TWI transmission
	rjmp	isr_twi_end
twi_stop_trans:
	outi	TWCR, TWI_TRANS_NACK	; Start (last) TWI transmission
	rjmp	isr_twi_end

twi_data_trans_nack:
	outi	TWCR, TWI_NOT_ADDR	; Switch to not addressed slave mode
	rjmp	isr_twi_end

twi_last_data_trans_ack:
	outi	TWCR, TWI_NOT_ADDR	; Switch to not addressed slave mode

isr_twi_end:
	popw	Y
	popw	A
	out	SREG, AL
	pop	AL
	reti

;----------------------------------------------------------;
; Initialize peripherals (ATmega32)

reset:
	clr	_0			;Zero reg.
	ldiw	Z, RAMTOP		;Clear all variables
	ldiw	X, RAMEND-RAMTOP+1	;
	st	Z+, _0			;
	sbiw	XL, 1			;
	brne	PC-2			;/
	sbiw	ZL, 1			;SP 弶婜壔
	outw	SP, Z			;/

	; Two Wire Interface (Slave Mode)
	outi	TWAR, TWI_ADR
	outi	TWCR, (1<<TWEA) | (1<<TWEN) | (1<<TWIE)

	; Start A/D with ch0, free running, 11.1ksps
	outi	ADMUX, 0b00000000	;MUX[3:0]=0000
	outi	ADCSR, 0b11101111	;ADEN=1,ADSC=1,ADFR=1,ADIE=1,ADPS[2:0]=110

	; MAX297 clock;
	outi	DDRD, (1<<5)		;clock pin -> output
	ldiw	A, 135-1		;136.5kHz -> 2.73kHz cut off
	outw	ICR1, A			;
	ldiw	A, 135/2-1		;
	outw	OCR1A, A		;/
	outi	TCCR1A, 0b10000010	;COM1A[1:0]=10, WGM1[1:0]=10
	outi	TCCR1B, 0b00011001	;WGM1[3:2]=11, CS1[2:0]=001

	clr	_Flags
	sei
	sbr	_Flags, bit0		;Start wave form hiRes captureing


;----------------------------------------------------------;
; Main


main:	
	outi	PORTB, 0b00000100
	rcall	calc_peaks1
	rcall	calc_peaks2
	rcall	calc_mixed_spec		;calculate interpolated spectrum
	rcall	calc_peaks3
	
	;------------------------------------------
	; High Resolution FFT
	;------------------------------------------

	sbrc	_Flags, 0		;Wait for end of 5.5kHz wave captureing
	rjmp	PC-1			;Here is a lot of CPU time wasted...

	;Change MAX297 clock
	ldiw	A, 36-1			;512kHz -> 10.2kHz cut off
	outw	ICR1, A			;
	ldiw	A, 36/2-1		;
	outw	OCR1A, A		;
	outi	TCNT1L, 0		;
	outi	TCNT1H, 0		;/

	rcall	do_window		;Fill butterfly table			[300us]

	;Start captureing for loRes FFT
	outi	ADCSR, 0b11101110	;22.2kHz Sampling Rate
	sbr	_Flags, bit1		;set flag to start captureing

	rcall	do_fft			;Butterfly operations			[3.8ms]
	ldiw	Y, TmpLvlBuf1		;Temp bar length buffer
	rcall	make_bars		;Get scalar values, update spectrum	[2.9ms]

	;------------------------------------------
	; Low Resolution FFT
	;------------------------------------------
	sbrc	_Flags, 1		;Wait for end of 22.2kHz wave captureing
	rjmp	PC-1			;/

	;Change MAX297 clock
	ldiw	A, 135-1		;136.5kHz -> 2.73kHz cut off
	outw	ICR1, A			;
	ldiw	A, 135/2-1		;
	outw	OCR1A, A		;
	outi	TCNT1L, 0		;
	outi	TCNT1H, 0		;/

	rcall	do_window		;Fill butterfly table			[300us]
	
	;Start captureing for hiRes FFT
	outi	ADCSR, 0b11101111	;11.1kHz Sampling Rate
	sbr	_Flags, bit0		;set flag to start captureing

	rcall	do_fft			;Butterfly operations			[3.8ms]
	ldiw	Y, TmpLvlBuf2		;Temp bar length buffer
	rcall	make_bars		;Get scalar values, update spectrum	[2.9ms]

	rjmp	main



⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -