微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

如何使用宏使 PIC16F1829 的代码更高效

如何解决如何使用宏使 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 举报,一经查实,本站将立刻删除。