如何解决如何使用宏使 PIC16F1829 的代码更高效
我正在尝试通过使用宏设置参数来播放可听声音来改进 PIC16F1829 的汇编代码(见下文)。
我之前的尝试使用了宏 BEEP,现在已将其解构为等效的行。
然而,这种尝试没有奏效;这是我上一个问题的目的,程序在第一次调用 BEEP 宏时卡住了。
但是,(1) 我的代码效率不高,(2) 我需要更好地掌握如何使用需要参数的宏,它不会在第一次被调用时卡住。>
LIST p=16f1829 ; list directive to define processor
#INCLUDE <p16f1829.inc> ; processor specific variable deFinitions
__CONfig _CONfig1,(_FOSC_INTOSC & _WDTE_OFF & _PWRTE_OFF & _MCLRE_OFF & _CP_OFF & _CPD_OFF & _BOREN_ON & _CLKOUTEN_OFF & _IESO_OFF & _FcmeN_OFF);
__CONfig _CONfig2,(_WRT_OFF & _PLLEN_OFF & _STVREN_OFF & _LVP_OFF);
;----------------------------------------------------------------------------
; UDATA declares a section of uninitialised data
VARIABLES UDATA ; VARIABLES is the name of the section of memory
Delay1 RES 1 ; uninitialised data,placed by linker in GPR's.
Direction RES 1 ; uninitialised data,placed by linker in GPR's.
Beep_TEMP1 RES 1 ;
Beep_TEMP2 RES 1 ;
Beep_TEMP3 RES 1 ;
;-------------------------------------------------------------------------
; Hardware Declarations
#define SWITCH PORTA,0 ; Pin where SW1 is connected.
#define PULL_UPS
#define BEEPlat LATA,2 ; Speaker pin located
#define BEEPtris TRISA,2
#define PLAY_ONE 0xFF ; Keep track of Tone played
#define PLAY_TWO 0x00
;-------------------------------------------------------------------------
; Constant DeFinitions
CONSTANT PRESCbeep = b'00000111' ; 65.3ms per cycle
;-------------------------------------------------------------------------
; RESET VECTOR
;-------------------------------------------------------------------------
RESET_VECTOR CODE 0x0000
GOTO START
;-------------------------------------------------------------------------
; INTERRUPT SERVICE ROUTINE
;-------------------------------------------------------------------------
INT_VECTOR CODE 0x0004 ; Interrupt vector location
ISR ; Relocatable Interrupt Service Routine
; Context saving for ISR
MOVWF w_temp ; save off current W register contents
MOVF STATUS,w ; move status register into W register
MOVWF status_temp ; save off contents of STATUS register
MOVF PCLATH,w ; Saves value in register PCLATH
MOVWF pclath_temp
;-------------------------------------------------------------------------
; SAMPLE INTERRUPT SERVICE ROUTINE
;-------------------------------------------------------------------------
; If the interrupt came from the timer,execute the TMR0 interrupt
; service routine.
BANKSEL IOCAF ; Selects memory bank containing IOCAF register
BTFSC IOCAF,2 ; Check the interrupt-on-change flag
BRA Service_SW1 ; Switch was pressed
BRA Service_TMR0 ; Timer0 overflowed
;-------------------------------------------------------------------------
; END OF SAMPLE INTERRUPT SERVICE ROUTINE
;-------------------------------------------------------------------------
ISR_END
; Restore contents before returning from interrupt
MOVF pclath_temp,w ; PCLATH is given its original content
MOVWF PCLATH
MOVF status_temp,w ; STATUS is given its original content
MOVWF STATUS
SWAPF w_temp,f ; W is given its original content
SWAPF w_temp,w
BSF INTCON,GIE ; Global interrupt enabled
RETFIE ; Return from interrupt routine
;-------------------------------------------------------------------------
; MAIN PROGRAM
;-------------------------------------------------------------------------
MAIN_PROG CODE
START
;-------------------------------------------------------------------------
; SET OSCILLATOR TO FACTORY FREQUENCY AND CLEAR GPR's
;-------------------------------------------------------------------------
ERRORLEVEL -302 ; disable warning accessing register not in bank 0
BANKSEL OSCTUNE ; Configure OPTION_REG and TMR0
MOVLW 0x00 ; Set oscillator to factory calibrated frequency
MOVWF OSCTUNE ;
BANKSEL STATUS
ERRORLEVEL +302 ; Enable warning accessing register not in bank 0
CLEAR_RAM ; code sequence initialises all GPR's to 0x00
MOVLW 0x70 ; initialise pointer to RAM
MOVWF FSR0
NEXT
CLRF INDF ; clear INDF register
INCF FSR0,F ; inc pointer
BTFSS FSR0,7 ; all done?
GOTO NEXT ; no clear NEXT
CONTINUE ; yes CONTINUE
nop
;-------------------------------------------------------------------------
; REMAINDER OF PROGRAM GOES HERE
;-------------------------------------------------------------------------
; Setup main init
BANKSEL OSCCON ; Selects memory bank containing OSCCON register
MOVLW b'00111000' ; Set cpu clock speed of 500KHz -> correlates to (1/(500K/4)) for each instruction
MOVWF OSCCON ; OSCCON <- 0x38
; Configure the input & output pins
BSF TRISA,RA0 ; Switch as input
BCF TRISA,RA2 ; Port as output
BANKSEL ANSELA ; Selects bank containing ANSEL
CLRF ANSELA ; All pins are digital
; Setup Timer0 as the delay
BANKSEL OPTION_REG ; Selects memory bank containing OPTION_REG register
MOVLW b'00000111' ; 1:256 prescaler for a delay of: (insruction-cycle * 256-counts)*prescaler = ((8uS * 256)*256) =~ 524mS
MOVWF OPTION_REG
BSF INTCON,TMR0IE ; Enable the rollover interrupt to occur
; Setup interrupt-on-change for the switch
BSF INTCON,IOCIE ; Must set this global enable flag to allow any interrupt-on-change flags to cause an interrupt
BANKSEL IOCAN ; Selects memory bank containing IOCAN register
BSF IOCAN,IOCAN0 ; when SW1 is pressed,enter the ISR (Note,this is set when a FALLING EDGE is detected)
BSF INTCON,GIE ; must set this global to allow any interrupt to bring the program into the ISR
; If this is not set,the interrupt flags will still get set,but the ISR will never be entered
#IFDEF PULL_UPS ; Enter here if this is defined (not commented out)
BANKSEL WPUA ; Selects memory bank containing WPUA register
BSF WPUA,0 ; Enable the weak pull-up for the switch
BANKSEL OPTION_REG ; Selects memory bank containing OPTION_REG register
BANKSEL OPTION_REG,NOT_WPUEN ; enable the global weak pull-up bit
; This bit is active HIGH,meaning it must be cleared for it to be enabled
#ENDIF
MOVLW PLAY_ONE ; Start with playing tune 1
MOVWF Direction
; Clear the RAM
CLRF Delay1
MAINLOOP:
BRA MAINLOOP ; Spend rest of time here
DEBOUNCE:
;delay for approximatly 5ms
MOVLW d'209' ; (1/(500KHz/4))*209*3 = 5.016mS
MOVWF Delay1
DEBOUNCELOOP:
DECFSZ Delay1,f ; 1 instruction to decrement,unless if branching (ie Delay1 = 0)
BRA DEBOUNCELOOP ; 2 instructions to branch
RETURN
PLAY1:
;BEEP macro freq,duration
; BEEP 0XFF,0X02
BANKSEL PORTA ; Selects memory bank containing PORTA register
MOVLW 0XFF
MOVWF Beep_TEMP1
MOVLW 0X02
CALL BEEPsub ; Call
; BEEP 0X90,0X05
BANKSEL PORTA ; Selects memory bank containing PORTA register
MOVLW 0X90
MOVWF Beep_TEMP1
MOVLW 0X05
CALL BEEPsub ; Call
; BEEP 0XC0,0X03
BANKSEL PORTA ; Selects memory bank containing PORTA register
MOVLW 0XC0
MOVWF Beep_TEMP1
MOVLW 0X03
CALL BEEPsub
; BEEP 0XFF,0X03 ; First tune
BANKSEL PORTA ; Selects memory bank containing PORTA register
MOVLW 0XFF
MOVWF Beep_TEMP1
MOVLW 0X03
CALL BEEPsub
BRA ISR_END ; RETFIE ; Return to main code
PLAY2:
; BEEP 0XBB,0X02
BANKSEL PORTA ; Selects memory bank containing PORTA register
MOVLW 0XBB
MOVWF Beep_TEMP1
MOVLW 0X02
CALL BEEPsub
; BEEP 0X87,0X05
BANKSEL PORTA ; Selects memory bank containing PORTA register
MOVLW 0X87
MOVWF Beep_TEMP1
MOVLW 0X05
CALL BEEPsub
; BEEP 0XA2,0X03
BANKSEL PORTA ; Selects memory bank containing PORTA register
MOVLW 0XA2
MOVWF Beep_TEMP1
MOVLW 0X03
CALL BEEPsub
; BEEP 0X98,0X03 ; Second tune
BANKSEL PORTA ; Selects memory bank containing PORTA register
MOVLW 0X98
MOVWF Beep_TEMP1
MOVLW 0X03
CALL BEEPsub
BRA ISR_END ; RETFIE ; Return to main code
; SWITCH Interrupt routine
Service_SW1:
; In order to ensure that no detected edge is lost while clearing flags,; the following 3 lines mask out only the kNown changed bits and don't
; interfere with the others. A simple clrf would work,but this current
; method is good practice
MOVLW 0xFF
XORWF IOCAF,w
ANDLW IOCAF,f ; MUST ALWAYS clear this in software or else stuck in the ISR forever
; Clearing this will clear the INTCON,IOCIF bit as well
CALL DEBOUNCE ; Delay for 5ms and then check the switch again
BANKSEL PORTA ; Select bank containing PORTA register
BTFSC SWITCH ; Is it still held down?
BRA ISR_END ; RETFIE ; nope,exit the ISR back to the main code
MOVLW 0xFF
XORWF Direction,f ; Toggle the direction state and save it back
BRA ISR_END ; RETFIE ; Return to main code
; TIMER 0 Interrupt routine clears the TMR0 interrupt flag.
Service_TMR0:
BANKSEL INTCON
BCF INTCON,TMR0IF ; MUST ALWAYS clear this in software or else stuck in the ISR forever
BANKSEL LATA ; Change to bank2
MOVLW PLAY_ONE ; Check what tune is currently playing
SUBWF Direction,w ; Be sure to save in wreg so as to not corrupt 'Direction'
BTFSC STATUS,Z
BRA PLAY1
BRA PLAY2
;------------------------------------------------------------------------
; BEEP SUbroUTINE
;------------------------------------------------------------------------
BEEPsub
MOVWF Beep_TEMP2 ; Set the sound duration
CLRF TMR0 ; Initialize the counter
BCF INTCON,TMR0IF ; Clear TMR0 overflow flag
BCF BEEPlat
BEEPa
BCF INTCON,TMR0IF ; Clear TMR0 overflow flag
BEEPb
BANKSEL LATA
BSF BEEPlat
CALL B_Wait ; Duration of logical "1"
BCF BEEPlat
CALL B_Wait ; Duration of logical "0"
BTFSS INTCON,T0IF ; Check TMR0 overflow flag
BRA BEEPb ; Skip if set
DECFSZ Beep_TEMP2,1 ; Is Beep_TEMP2 = 0?
BRA BEEPa ; If not,jump back to BEEP
RETURN
B_Wait
MOVF Beep_TEMP1
MOVWF Beep_TEMP3
B_Waita
DECFSZ Beep_TEMP3,1
BRA B_Waita
RETURN
;-------------------------------------------------------------------------
; END OF PROGRAM
;-------------------------------------------------------------------------
END ; End of program
非常感谢任何人可以提供的任何见解。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。