为什么 LED 一直在亮着的位置,而不是闪烁?

问题描述 投票:0回答:1

这是使用 pic16f676 中的 TIMER0 中断使 LED 闪烁的 MPASM 代码。端口 A 的引脚 0 (RA0) 未切换至关闭位置。请帮忙...

我是图片组装新手,我想掌握图片。有没有图片神童请帮我学习一下...

我需要以 1 秒的间隔眨眼。 代码是:

    #include "p16F676.inc"
 
    __CONFIG _FOSC_INTRCIO & _WDTE_OFF & _PWRTE_OFF & _MCLRE_OFF & _BOREN_OFF & _CP_OFF & _CPD_OFF
    MyCount   EQU       0x20    
    RES_VECT    CODE 0x0000     
        GOTO    CODE_INIT     
    
    ISR     CODE 0x0004     
        GOTO    ISR_HANDLER     
    
    ;MAIN_PROG   CODE    
    CODE_INIT:          
        CALL    PORT_INIT       
        CALL    TIMER_INIT      
        GOTO    IDLE_LOOP       
    
    ISR_HANDLER:   
        DECFSZ    MyCount, 1        
        RETFIE
        movlw 0x01 
        xorwf PORTA, F    
        BCF     INTCON, TMR0IF  
        MOVLW   d'10'       
        MOVWF   TMR0        
        RETFIE      
    IDLE_LOOP:
        NOP
        NOP             
        NOP
        NOP
        GOTO    IDLE_LOOP   
    PORT_INIT:
        BSF     STATUS, RP0 
        MOVLW   b'00000000'     
        MOVWF   ADCON1      
        MOVWF   ANSEL       
        MOVWF   TRISA       
        RETURN   
    TIMER_INIT:
        CLRWDT          
        MOVLW   b'00000110'     
        MOVWF   OPTION_REG    
        BSF     INTCON, GIE     
        BSF     INTCON, TMR0IE    
        BCF     STATUS, RP0   
        MOVLW   d'18'       
        MOVWF   MyCount     
    
        BCF     INTCON, TMR0IF  
        MOVLW   d'10'       
        MOVWF   TMR0        
        RETURN    
        END

看来是赌延迟问题。但对预标量和计数器进行改组可以保持引导位置不变。我需要打开和关闭 LED。

assembly embedded microcontroller pic led
1个回答
0
投票

以下是我在您的代码中检测到的一些问题...

1.端口初始化错误

正如我在这个答案中提到的,您的初始化代码缺少

CMCON
的代码,即控制模拟比较器模块的寄存器。以下是正确设置的方法:

BCF     STATUS,RP0  ;Bank 0
CLRF    PORTA       ;Init PORTA
MOVLW   05h         ;Set RA<2:0> to
MOVWF   CMCON       ;digital I/O
BSF     STATUS,RP0  ;Bank 1
CLRF    ANSEL       ;digital I/O
CLRF    TRISA       ;set all pins as outputs
BCF     STATUS,RP0  ;Bank 0

2.您的计时器设置不会给您 1 秒的延迟

将预分频器设置为 1:128,意味着定时器将每 128us 递增一次。
您的计时器重载值为 10,这意味着它将计数 245 直到溢出。那么你的溢出率就是

128us * 245 = 31360us

为了从此值产生 1 秒延迟,您应该使用辅助变量并将其设置为
1000000 / 31360 = 31.8877
让我们将其四舍五入为十进制的 32。因此,您应该将
MyCount
变量加载为 32,以便总共生成 1 秒的延迟。
但您的实际值是十进制 18,这将产生大约半秒的
18 * 31360 = 564.480ms

3.不正确的中断处理

让我们先看看你的timer0中断处理程序代码。

ISR_HANDLER:   
    DECFSZ  MyCount, 1        
    RETFIE
    movlw   0x01 
    xorwf   PORTA, F    
    BCF     INTCON, TMR0IF  
    MOVLW   d'10'       
    MOVWF   TMR0        
    RETFIE  

每次timer0 遇到中断时,您都应该清除timer0 标志。但只有当计数器减至零时才将其清除。但问题是:程序将陷入定时器中断,直到其标志被清除。因此,由于连续调用定时器中断,

DECFSZ    MyCount, 1
指令将非常快速地执行,导致输出引脚非常快速地闪烁。因此没有人的眼睛会发现它在闪烁。
另一个问题是,在
MyCount
的值达到零后,您不会重新加载它。这将导致变量下溢到 255,并且在第一次之后它总是会从 255 开始倒计时。

因此,无论计数器的值如何,您应该做的是每次中断发生时清除标志并重新加载timer0值。您还应该重新加载

MyCount
值,以便它不断从计算值开始倒计时。最后,定时器中断的正确流程如下:

ISR_HANDLER
    bcf     INTCON, TMR0IF
    movlw   d'10'
    BANKSEL TMR0    ; Make sure you're in correct data bank
    decfsz  MyCount, 1
    retfie
    movlw   d'32'
    BANKSEL MyCount ; Again make sure you're in correct bank
    movwf   MyCount
    ; PORTA and MyCount are in the same bank since MyCount's address is 0x20
    movlw   1
    xorwf   PORTA, F ; Toggle output due to 1 sec time out
    retfie  

将上述修复应用到您的代码中,然后重试。让我知道结果。

© www.soinside.com 2019 - 2024. All rights reserved.