Problemas al usar Mplab Sim

#1
Hola a todos. Soy nuevo con los PIC y estoy intentando realizar un intermitente de 1 segundo en ON y 1 segundo OFF.
El tema es que al usar mplab sim se queda en un bucle infinito entre las instrucciones que comprueban si se ha desbordado el timer 0 (usado como temporizador por medio del flag T0IF) instrucción btfss INTCON, T0IF y goto revose
No sé si es debido a que no cuenta el TMR0, pero tengo entendido que está continuamente contando o que no se activa la bandera de desbordamiento, o que hay que configurar algo en mplab para usar los timers.

A continuación os dejo el programa en ensamblador, también debo decir que he probado otro programa que estaba por Internet y me ocurre el mismo fallo.

Muchísimas gracias, por adelantado.

PHP:
;Este programa hace parpadear 1 led 1sg y 1sg
        list    P=16F648A
        #include <P16F648A.inc>
        __config _CP_OFF & _WDT_OFF & _PWRTE_OFF & _HS_OSC
;Definición de constantes
#define _XTAL_FREQ 20000000  ;cristal utilizado de 20Mhz

;            
TMR0    equ     h'0'
PORTA     equ     h'05'
PORTB    equ     h'06'
CONTA     equ     h'20'
W        equ     0
F        equ     1

        org 0
        clrwdt        
        bcf     STATUS,RP0;Seleccionamos el banco 0
        bcf        STATUS,RP1;
        bcf     INTCON,T0IE
        clrf    PORTB;Se pone a cero el puerto b
        bsf     STATUS,RP0;Nos posicionamos en el banco 1
        bcf     STATUS,RP1;
        movlw    h'00'
        movwf   TRISB;Configuramos PORTB como salida
        movlw   b'00000111';Configuramos reg OPTION con prescaler a 256
        movwf   OPTION_REG
        bcf     STATUS,RP0;Nos situamos en el banco de memoria 0
        bcf     STATUS,RP1;
        clrf    TMR0;
        bcf      INTCON,T0IF
        bsf        INTCON,T0IE
        bsf     INTCON,GIE     
Inicio  bsf     PORTB,0;Encendemos el led colocado en el bit 0 del PORTB
        call    Retardo;llamamos a la subrutita que cuenta 1 sg
        bcf     PORTB,0;apagamos el led situado en el bit0 del PORTB
        call    Retardo;Volvemos a llamar a la subrutina para que cuente 1 sg
        goto    Inicio;Volvemos a Inicio para hacer un bucle
Retardo movlw   .60; precargo el timer0
        movwf    TMR0
Revose  btfss   INTCON,T0IF;compruebo si se a activado el flaf de desbordamiento del TMR0
        goto    Revose;comprueba hasta que se active el flag
        bcf     INTCON,T0IF; resetea el flag
        incf    CONTA,1;contamos 100 veces 10ms
        movlw   b'01100100'
        xorwf   CONTA,0;comprobamos que hemos llegado a 100
        btfsc   STATUS,2
        goto    Revose
        return
        end
 
Última edición por un moderador:
#2
Vamos a aclarar algunas cosas sobre tu programa y la lógica que se debe tomar.
En primera. Al usar un PIC16F648A, debes tener en cuenta los fuses.
_CP_OFF es un fuse por defecto, así que queda de sobra establecerlo.
Este PIC es igual al 16F628A pero con más RAM, así que puede programarse de la misma forma.
Cuenta con un sistema de programación por bajo voltaje, y por ello tiene un fuse llamado LVP (Low Voltaje Programming)
Si no se va a usar ese modo de programación, ese fuse debe ser deshabilitado porque inhibirá el funcionamiento normal del pin RB4.

En segunda. Cuando declaras la librería del PIC a usar, en este caso: P16F648A.INC
Ya no tiene sentido redefinir los registros, porque su locación ya está definida en la librería.
Y tú estás redefiniendo los registros: TMR0, PORTA, PORTB, W y F
Al hacer eso, el compilador puede mostrar un error por redefinición de registros.
(No sé qué versión tengas de MPASM, que no te lo advirtió.)

Ahora, pasando a tu problema...
Estás activando interrupciones que no usas y eso provocará un desborde, ya que al no estar controladas, no se tendrá un punto de retorno.
En este PIC el Timer 0 (8 bits) siempre está contando desde 0 hasta 255 y ahí desbordará regresando obviamente a 0.
Eso siempre lo hará, y podrá configurarse para un desborde cada x tiempo conforme a la frecuencia de reloj.
Pero si configuras su interrupción y no la controlas, tendrás un problema por desbordamiento conocido como (Stack Overflow) debido a que el programa no tendrá un punto de retorno definido.
O sea que, en pocas palabras, se pierde el control del programa.

Por lo que veo, estás tratando de definir una frecuencia de reloj con:
#define _XTAL_FREQ 20000000 ;cristal utilizado de 20Mhz
Pero esa definición no será tomada en cuenta por el compilador como referencia del cristal a usar.
Podrá ser válida en otros compiladores como XC, pero no en este compilador. (MPASM)

Y ten en cuenta algo fundamental.
Si quieres usar el desborde del Timer 0 para realizar 1 segundo en ON y otro en OFF, entonces debes realizar dos conteos, porque cuando se llegue al primer conteo de 100 ciclos a 10 mS, para determinar 1 segundo en ON, también debes realizar otro conteo para el tiempo en OFF.
Y eso lo debe saber el programa por medio de banderas.
Algo básico, porque ningún programa es adivino y el programador es quien establece las condiciones.

Así que por lo que comentas, el problema radica en un bucle por Stack Overflow, al activar interrupciones y no estar controladas.

La inicialización de un programa básico con interrupciones, es la siguiente, por ejemplo:
Código:
    [COLOR=Blue]org 0x00[/COLOR]    [COLOR=DarkGreen]; Vector de reset.[/COLOR]
    [COLOR=blue]goto[/COLOR]    [COLOR=Purple]inicio[/COLOR]
    [COLOR=blue]org    0x04[/COLOR]    [COLOR=darkgreen]; Vector de interrupciones.[/COLOR]
    [COLOR=blue]goto[/COLOR]    [COLOR=purple]servicio_interrupciones[/COLOR]

[COLOR=purple]inicio[/COLOR]
    [COLOR=darkgreen]; Configuraciones iniciales.[/COLOR]
[COLOR=purple]programa[/COLOR]
    [COLOR=DarkGreen]; Ejecución y llamadas a rutinas.[/COLOR]
    [COLOR=blue]goto[/COLOR] [COLOR=purple]programa[/COLOR]

[COLOR=purple]servicio_interrupciones[/COLOR]
   [COLOR=darkgreen] ; Comprobación de interrupciones y control.[/COLOR]
    [COLOR=blue]retfie[/COLOR]

Y bueno... tomando en cuenta lo expuesto y si tratas de hacerlo de la forma en que lo estás haciendo, cada 10 mS. ocurrirá una interrupción dentro de la cual no podrás hacer un conteo válido, porque al tratarse de un proceso que se repetirá por interrupción, habrá una realimentación que provocará un bucle.
Para eso debes usar banderas y un doble conteo como te comenté.

Hacer eso en ensamblador resulta tedioso, y es por eso que los lenguajes de alto nivel lo han reemplazado, ya que con pocas instrucciones y menor razonamiento de lógica, se llega al mismo fin en muy poco tiempo.

Ejemplo en C (PCWHD Compiler de CCS)
PHP:
#include    <16f648a.h>
#use        delay(crystal = 20 MHz)

// Declaración de variables globales.
int8 contador1 = 0,contador2 = 0;
int1 flag_1seg = 0;

// Servicio de interrupción por desborde del Timer 0
#INT_TIMER0
void sdi_desborde_timer0 (void)
{
    contador1 ++;
    
    if(contador1 > 99)                        // Si la variable "contador1" llega a 100...
    {
        flag_1seg = 1;                        // Indicar que se han realizado 100 ciclos de 10 mS.)
        contador1 = 0;                        // Regresar la variable "contador1" a 0
        contador2 ++;                        // Incrementar un segundo contador para ejecutar dos tiempos.
        
        if(contador2 > 1)                    // Como el primer tiempo fue de 1 segundo, (100 ciclos) ahora esperamos 2 segundos. (200 ciclos)
        {
            contador2 = 0;                    // Contados los 200 ciclos de 10 ms, se resetea la variable "contador2"
            flag_1seg = 0;                    // Se indica que han pasado 2 segundos (200 ciclos) y se pone en 0 la bandera "flag_1seg"
        }
    }
        
    set_timer0(60);                            // Recargar el Timer 0
}

void main (void)
{
    setup_timer_0(T0_INTERNAL|T0_DIV_256);    // Configurar el Timer 0
    set_timer0(60);                            // Cargar el Timer 0 para que desborde cada 10 ms @ 20 MHz.
    
    enable_interrupts(INT_TIMER0);            // Habilitar la interrupción por desborde del Timer 0.
    enable_interrupts(GLOBAL);                // Habilitar interrupciones globales.
    
    while (true)                            // Bucle infinito del programa principal.
    {
        if(flag_1seg)                        // Si "flag_1seg" está en 1, poner en 1 RB4
            output_high(PIN_B4);
        else
            output_low(PIN_B4);                // Si "flag_1seg" está en 0, poner en 0 RB4
    }
}
Nota la diferencia. Pero tú sabrás el motivo de usar ensamblador. ;)
Y no digo que sea malo, al contrario, es lo mejor y hasta la fecha no conozco un compilador directo de C a Hex.
Aunque en sus tiempos no había de otra, ahora los nuevos PIC ya están diseñados para ser óptimos en compiladores C. (Algo que aún no le encuentro la razón) Pero eso dice Microchip. :D
 
Última edición:
#3
Muchísimas gracias d@rkbytes, quite la habilitación de las interrupciones y quite la parte de código redundante , el caso es que en mplab sim sigue ocurriendo lo mismo pero al simularlo en proteus funciona perfecto, ahora estoy aprendiendo a usar el ensamblador con los pics cuando lo tenga dominado empezare con el C que parece que es mas fácil al ser un lenguaje de alto nivel.
Lo dicho muchas gracias por la respuesta tan completa y rápida, me has sido de gran ayuda.
 

Temas similares

Arriba