Why the Led stay at on position, instead of blink?

76 Views Asked by At

This is the MPASM code for blinking led using the TIMER0 interrupt in pic16f676. The pin 0 (RA0) of portA is not toggling to off position. please help...

I'm newbie to pic assembly, I would like to master pic. is there any pic prodigies please help me to learn...

I need to blink at an interval of 1 sec. CODE is:

    #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

It seems to bet the delay problem. But shuffling the pre-scalar and counter keeps led in on position. I need to On and Off Led.

1

There are 1 best solutions below

1
Kozmotronik On

Here are some problems I detected in your code...

1. Wrong port initialization

As I have mentioned in this answer your init code lacks code for CMCON, the register that controls the analog comparators modue. Here is how you should set it up correctly:

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. Your timer setup will not give you a 1 second delay

You set the prescaler to 1:128, means that the timer will be incremented on every 128us.
Your timer reload value is 10, means that it will count 245 until it overflows. Then your overflow rate is 128us * 245 = 31360us.
In order to produce 1 sec delay from this value you should use a helper variable and set it to 1000000 / 31360 = 31.8877 let's round it up to 32 in decimal. So you should load the MyCount variable with 32 in order to generate a 1 sec delay in total.
But your actual value is 18 in decimal, that would make a 18 * 31360 = 564.480ms which is approximately half a second.

3. Incorrect interrupt handling

Let's see your timer0 interrupt handler code first.

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

You should have cleared the timer0 flag everytime the timer0 hits the interrupt. But you clear it only when your counter reaches to zero. But here is the problem: the program will get stuck in the timer interrupt until its flag gets cleared. So the DECFSZ MyCount, 1 instruction will be executed very rapidly due to the successive calls to the timer interrupt, resulting in a very fast flashing of the output pin. Hence no eyes will catch it is flashing.
Another problem is that you don't reload the MyCount's value after it reaches the zero. This will cause that the variable underflow to 255 and after the first time it always will keep counting down from 255.

So what you should do is to clear the flag and reload the timer0 value everytime the interrupt gets hit, regardles the value of the counter. You should also reload the MyCount value so that it keeps counting down from the calculated value. Finally the correct flow in the timer interrupt would be as following:

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  

Apply the above fixes into your code and try it again. Let me know the result.