# Manejar bien interruptores y pulsadores en asm.



## Meta (Ago 6, 2012)

Hola:

Teniendo un pulsador escrito en ASM sea del PIC16Fxxx. Se hace de esta manera.








```
INICIO
     btfss PORTA,0     ;¿Entrada a 1? ¿Interruptor pulsado?
     goto ENCENDER
     goto APAGAR
ENCENDER
     bsf PORTB,0       ; Enciender Led.
     goto INICIO       ; Vuelve a INICIO.
APAGAR
     bcf PORTB,0       ; Apaga el Led.
     goto INICIO       ; Vuelve a INICIO.
END     ; Fin de programa.
```

Mi idea es ahcerlo con un pulsador, es decir, con el mismo botón pueda apagar un Led y encenderlo. Recuerda que es un pulsador, no interruptor. La diferencia es que al pulsar el pulsador, mientras esté pulsado pasa a estado 0, si lo dejas de pulsar, pasa otra vez a 1. 

¿Cómo hago esto en ensamblador?

Un cordial saludo.

PD: Me da la impresión que el código será un poco más largo.


----------



## Chico3001 (Ago 6, 2012)

De echo el codigo es el mismo.. a menos que necesites mantener el led activo, en cuyo caso solo hay que quitar la rutina de apagado y ponerla en otro lugar despues de ejecutar la accion...


----------



## Dano (Ago 6, 2012)

Meta dijo:


> Hola:
> 
> Teniendo un pulsador escrito en ASM sea del PIC16Fxxx. Se hace de esta manera.
> 
> ...



Lo que se hace es un biestable por decirlo de una manera simple.


```
INICIO
     goto APAGADO  

ENCENDIDO
     bsf PORTB,0       ; Enciender Led.
     btfsc PORTA,0     ;¿Entrada a 1? ¿Interruptor pulsado?
     goto ENCENDIDO       ; Vuelve a INICIO.
     goto APAGADO     

APAGADO
     bcf PORTB,0       ; Apaga el Led.
     btfss PORTA,0     ;¿Entrada a 1? ¿Interruptor pulsado?
     goto ENCENDIDO       ; Vuelve a INICIO.
     goto APAGADO

END     ; Fin de programa.
```

es bueno agregarle un detector de flancos al pulsador (electronico o programado), asi como esta diseñado cambia de estado por nivel por lo tanto si mantenes apretado el pulsador va a saltar de un estado a otro.


----------



## Meta (Ago 6, 2012)

Hola:

Lo he comprobado con el MPLAB v8.86. Se comporta como una señal cuadrada. Uso el PIC16F886.

Por si acaso, a lo mejor no me expliqué bien. Cuando pulsa el botón, el Led queda encendido. Si lo vuelves a pulsar, se apaga. Hay que dejar claro una cosa. Como es un pulsador, al pulsar tiene 0 y cuando dejo de pulsar tiene un 1. No es un interruptor y se comporta como si lo fuera. LA función con el ejemplo que me pusieron, funciona bien si dejo el botón pulsado con el dedo. Espero que lo haya explicado bien lo que quiero decir.


Aquí dejo el código.

```
List    p=16F886        ;Tipo de procesador
            include    "P16F886.INC"    ;Definiciones de registros internos

;Ajusta los valores de las palabras de configuración durante el ensamblado. Los bits no empleados
;adquieren el valor por defecto.Estos y otros valores se pueden modificar según las necesidades

        __config    _CONFIG1, _LVP_OFF&_PWRTE_ON&_WDT_OFF&_EC_OSC&_FCMEN_OFF&_BOR_OFF     ;Palabra 1 de configuración
        __config    _CONFIG2, _WRT_OFF                                    ;Palabra 2 de configuración

            org    0x00
            goto    Inicio            ;Vector de reset
            org    0x05    

Inicio    
        clrf     PORTB            ;Borra los latch de salida
        bsf        STATUS,RP0
        bsf        STATUS,RP1        ;Selecciona banco 3
        clrf    ANSEL            ;Puerta A digital
        clrf    ANSELH            ;Puerta B digital
        bcf        STATUS,RP1        ;Selecciona banco 1
        clrf    TRISB            ;RB7:RB0 se configuran como salida
        movlw    b'11111111'        
        movwf    TRISA            ;RA5:RA0 se configuran como entrada
        bcf        STATUS,RP0        ;Selecciona banco 0            

ENCENDIDO
         bsf PORTB,0       ; Enciender Led.
         btfsc PORTA,0     ;¿Entrada a 1? ¿Interruptor pulsado?
         goto ENCENDIDO       ; Vuelve a INICIO.
         goto APAGADO     

APAGADO
         bcf PORTB,0       ; Apaga el Led.
         btfss PORTA,0     ;¿Entrada a 1? ¿Interruptor pulsado?
         goto ENCENDIDO       ; Vuelve a INICIO.
         goto APAGADO


        END                        ;Fin del programa.
```
Un saludo.


----------



## Dano (Ago 6, 2012)

Hago una acotación principalmente para los principiantes, cuando edité el código de Meta no modifique los comentarios, por lo tanto no miren los comentarios porque no tienen lógica.


----------



## road24 (Ago 6, 2012)

INICIO
     btfss PORTA,0     ;¿Entrada a 1? 
     goto COMPROBAR ;No, Salta a comprobar
     goto INICIO            ;Si, vuelve a testear el bit 

COMPROBAR
   btfss PORTB,0    ;El led esta encendido?  
   goto APAGAR     ; Ve a apagar
   goto ENCENDER; No, Ve a encender

ENCENDER
     bsf PORTB,0       ; Enciender Led.
     goto INICIO       ; Vuelve a INICIO.

APAGAR
     bcf PORTB,0       ; Apaga el Led.
     goto INICIO       ; Vuelve a INICIO.
END     ; Fin de programa.

Ese te va a cambiar de apagado a encendido el led cada que presiones el pulsador


----------



## Meta (Ago 6, 2012)

Hola:

Cuando doy algunos pulsos probando. El Led nunca se enciende, jejejej.







```
List    p=16F886        ;Tipo de procesador
            include    "P16F886.INC"    ;Definiciones de registros internos

;Ajusta los valores de las palabras de configuración durante el ensamblado.Los bits no empleados
;adquieren el valor por defecto.Estos y otros valores se pueden modificar según las necesidades

        __config    _CONFIG1, _LVP_OFF&_PWRTE_ON&_WDT_OFF&_EC_OSC&_FCMEN_OFF&_BOR_OFF     ;Palabra 1 de configuración
        __config    _CONFIG2, _WRT_OFF                                    ;Palabra 2 de configuración

            org    0x00
            goto    Comienzo            ;Vector de reset
            org    0x05    

Comienzo    
        clrf     PORTB            ;Borra los latch de salida
        bsf        STATUS,RP0
        bsf        STATUS,RP1        ;Selecciona banco 3
        clrf    ANSEL            ;Puerta A digital
        clrf    ANSELH            ;Puerta B digital
        bcf        STATUS,RP1        ;Selecciona banco 1
        clrf    TRISB            ;RB7:RB0 se configuran como salida
        movlw    b'11111111'        
        movwf    TRISA            ;RA5:RA0 se configuran como entrada
        bcf        STATUS,RP0        ;Selecciona banco 0            

; CODIGO**********************************************************
INICIO
    btfss PORTA,0 ;¿Entrada a 1?
    goto COMPROBAR ;No, Salta a comprobar
    goto INICIO ;Si, vuelve a testear el bit

COMPROBAR
    btfss PORTB,0 ;El led esta encendido?
    goto APAGAR ; Ve a apagar
    goto ENCENDER; No, Ve a encender

ENCENDER
    bsf PORTB,0 ; Enciender Led.
    goto INICIO ; Vuelve a INICIO.

APAGAR
    bcf PORTB,0 ; Apaga el Led.
    goto INICIO ; Vuelve a INICIO.

    END
```

Un saludo.


----------



## D@rkbytes (Ago 6, 2012)

Saludos.
Aquí pongo un ejemplo sencillo de como hacer el efecto Toggle.
Básicamente es algo como esto:

```
Ciclo 
; Esperar a que se presione el botón
Si_Push btfsc   GPIO,0        ; Repetir hasta que GP0 sea 0
    goto    $-1                ; No es 0, regresar 1 instrucción
; Hacer el Toggle
    bsf        GPIO,1            ; Es 0 (Encender LED) 
    xorlw    b'10'            ; Toggle sobre el bit correspondiente (GP1)
    movwf   GPIO            ; Mover W a GPIO
 ; Esperar a que se suelte el botón
No_Push btfss   GPIO,0        ; Repetir hasta que GP0 sea 1
    goto    $-1                ; No es 1, regresar 1 instrucción    
    goto    Ciclo            ; Es 1, repetir el ciclo
```
Adjunto una simulación para el 12F508 que use para hacer la prueba.
Pero el código también funciona para otros PIC.

Nota: También lo probe fisicamente.
Quizás solo haga falta agregar un pequeño retardo, pero así funciona bien. 
Suerte.


----------



## Meta (Ago 6, 2012)

Buenas:

Ahora mismo no dispongo de simulador Proteus. Deja ver si lo consigo instalar.

Lo voy a adaptar al 16F886 que es que dispongo ahora mismo para simularo con un módulo físico. Haber si esta vez funciona.

En tu caso usa memoria RAM. Estaba averiguando si hay manera de no hacerlo así, jeejjee. Entre la memoria RAM y usarlo sin RAM, hay que ver cual usas menos código.

Gracias por tu ejemplo y tiempo, incluyendo a los demás.


----------



## fdesergio (Ago 6, 2012)

El gran problema es que no tienes en cuenta el rebote del pulsador (en la parte real) debes cada vez que vas a la subrutina de cambio de estado hacer un delay y revisar nuevamente el pulsador para ver si continua en el estado correcto, personalmente uso un delay de 150mS pq es el tiempo normal que mantiene uno presionado un pulsador y que sea valido, chauuuuuuuuu


----------



## Meta (Ago 6, 2012)

Si lo tengo en cuenta, lo haré al final de todo.


----------



## fernandob (Ago 6, 2012)

les hago una consulta:
ustedes en la realidad usan eso ???? 

yo cuando programaba en asm como venia de la costumbre de el tema de los rebotes de pulsadores y ruidos siempre para mi la deteccion de un pulsadr NO era verificar la entrada una vez y listo, no .
siempre tenia una rutina de verificacion, en la cual hacia avanzar un contador y solo si el contador llegaba a tal valor ahi se daba por confirmada.
o sea verificaba en la interrupcion que la entrada sea igual digamos 10 tiempos , o lo que sea.

digamos que me aseguraba que el pulsador este pulsado 50 o 100ms .
idem al soltar si lo ameritaba .

ustedes no hacen asi ???


----------



## D@rkbytes (Ago 6, 2012)

fernandob dijo:


> les hago una consulta:
> ustedes en la realidad usan eso ????
> 
> yo cuando programaba en asm como venia de la costumbre de el tema de los rebotes de pulsadores y ruidos siempre para mi la deteccion de un pulsadr NO era verificar la entrada una vez y listo, no .
> ...


Pues, yo lo que generalmente hago, es después de la comparación de botón pulsado llamar a una rutina de retardo.
Por lo regular de 100 a 250 mS, pero dependiendo del tipo de rutina a seguir.
Si quiero avances rápidos, el retardo lo hago más corto.
Por ejemplo para hacer avanzar un contador, ó hacer el cambio de canales de un sintonizador.
En esos casos se requiere de un avance más o menos rápido.
Y si la rutina es por ejemplo, solo hacer cierta tarea y regresar, entonces el retardo lo hago más largo.

Saludos fernandob


----------



## Meta (Ago 7, 2012)

fernandob dijo:


> les hago una consulta:
> ustedes en la realidad usan eso ????
> 
> yo cuando programaba en asm como venia de la costumbre de el tema de los rebotes de pulsadores y ruidos siempre para mi la deteccion de un pulsadr NO era verificar la entrada una vez y listo, no .
> ...



Esa idea es original.

Como un reloj CASIO. Si te fijas bien a cambiar de modo.




Al pulsar el botón "MODE" desde que lo pulse cambia de modo, claro como es un pulsador vuelve al estado original como normalmente abierto "N/A". Así es lo que quiero usar el botón.

En estos momentos estoy adaptando el código del 12F508 al 16F886 para saber si funciona, lo del retardo lo haré despué shaber donde lo meto.

Gracias a todos, luego publico el código.



Hola:

Algo no hice bien, doy el pulso, sube pero no baja.






Su código es:

```
List    p=16F886        ;Tipo de procesador
            include    "P16F886.INC"    ;Definiciones de registros internos

;Ajusta los valores de las palabras de configuración durante el ensamblado.Los bits no empleados
;adquieren el valor por defecto.Estos y otros valores se pueden modificar según las necesidades

        __config    _CONFIG1, _LVP_OFF&_PWRTE_ON&_WDT_OFF&_EC_OSC&_FCMEN_OFF&_BOR_OFF     ;Palabra 1 de configuración
        __config    _CONFIG2, _WRT_OFF                                    ;Palabra 2 de configuración

            org    0x00
            goto    Comienzo            ;Vector de reset
            org    0x05    

Comienzo    
        clrf     PORTB            ;Borra los latch de salida
        bsf        STATUS,RP0
        bsf        STATUS,RP1        ;Selecciona banco 3
        clrf    ANSEL            ;Puerta A digital
        clrf    ANSELH            ;Puerta B digital
        bcf        STATUS,RP1        ;Selecciona banco 1
        clrf    TRISB            ;RB7:RB0 se configuran como salida
        movlw    b'11111111'        
        movwf    TRISA            ;RA5:RA0 se configuran como entrada
        bcf        STATUS,RP0        ;Selecciona banco 0            

; CODIGO**********************************************************


Ciclo 
; Esperar a que se presione el botón
Si_Push 
    btfsc   PORTA,0        ; Repetir hasta que GP0 sea 0
    goto    Si_Push                ; No es 0, regresar 1 instrucción
; Hacer el Toggle
    bsf        PORTB,1            ; Es 0 (Encender LED) 
    xorlw    b'00000010'            ; Toggle sobre el bit correspondiente (GP1)
    movwf   PORTB           ; Mover W a GPIO
 ; Esperar a que se suelte el botón
No_Push 
    btfss   PORTA,0        ; Repetir hasta que GP0 sea 1
    goto    No_Push                ; No es 1, regresar 1 instrucción    
    goto    Ciclo            ; Es 1, repetir el ciclo

    END                        ;Fin del programa.
```

Saludo.


----------



## D@rkbytes (Ago 7, 2012)

Meta dijo:


> Algo no hice bien, doy el pulso, sube pero no baja.


Desafortunadamente no tengo el PIC16F886 para ver que pasa.
Pero tengo el PIC16F88 que es algo similar, y adapte el código a este PIC y funciono bien.
Este es el programa adaptado.

```
list    p=16f88
    #include <p16f88.inc>

     __CONFIG    _CONFIG1, _INTRC_IO & _CP_OFF & _CCPMX_RB0 & _DEBUG_OFF & _WRT_PROTECT_OFF & _CPD_OFF & _LVP_OFF & _BODEN_OFF & _MCLR_ON & _PWRTE_ON & _WDT_OFF
     __CONFIG    _CONFIG2, _IESO_OFF & _FCMEN_OFF
    errorlevel    -302

    org    0x00

Inicio
    bsf        STATUS,RP0        ; Ir al banco 1
    movlw    0xFF            ; Todo el puerto A como entradas
    movwf    TRISA
    movlw    b'11111101'        ; RB1 como salida
    movwf    TRISB
    movlw    b'01110100'        ; Configurar el registro OSCCON a 8MHz estable
    movwf    OSCCON
    clrf    ANSEL            ; Todos los pines como entradas digitales. (Incluyendo RB5 y RB6)
    bcf        STATUS,RP0        ; Ir al banco 0
    clrf    PORTB

Ciclo 
; Esperar a que se presione el botón
Si_Push btfsc   PORTA,0        ; Repetir hasta que RA0 sea 0
    goto    $-1                ; No es 0, regresar 1 instrucción
; Hacer el Toggle
    xorlw    b'10'            ; Toggle sobre el bit correspondiente (RB1)
    movwf    PORTB            ; Mover W al puerto B
 ; Esperar a que se suelte el botón
No_Push btfss   PORTA,0        ; Repetir hasta que RA0 sea 1
    goto    $-1                ; No es 1, regresar 1 instrucción   
    goto    Ciclo            ; Es 1, repetir el ciclo

    end
```
Note que al declarar algunos o todos los pines del puerto B como salidas,
al hacer la función toggle, los pines del puerto B toman valor 1 por mover el resultado al puerto B.
Pero el toggle se sigue realizando sobre el bit establecido en el XORLW B'10' ; (RB1)
Puede ser que por ahí este el problema, habrá que realizar más pruebas. 

Saludos.


----------



## Meta (Ago 7, 2012)

Ahora ocurre lo mismo pero al revés.






```
List    p=16F886        ;Tipo de procesador
            include    "P16F886.INC"    ;Definiciones de registros internos

;Ajusta los valores de las palabras de configuración durante el ensamblado.Los bits no empleados
;adquieren el valor por defecto.Estos y otros valores se pueden modificar según las necesidades

        __config    _CONFIG1, _LVP_OFF&_PWRTE_ON&_WDT_OFF&_EC_OSC&_FCMEN_OFF&_BOR_OFF     ;Palabra 1 de configuración
        __config    _CONFIG2, _WRT_OFF                                    ;Palabra 2 de configuración

            org    0x00
            goto    Comienzo            ;Vector de reset
            org    0x05    

Comienzo    
    clrf     PORTB            ;Borra los latch de salida
    bsf        STATUS,RP0
    bsf        STATUS,RP1        ;Selecciona banco 3
    clrf    ANSEL            ;Puerta A digital
    clrf    ANSELH            ;Puerta B digital
    bcf        STATUS,RP1        ;Selecciona banco 1
    clrf    TRISB            ;RB7:RB0 se configuran como salida
    clrf    TRISC
    movlw    b'11111111'        
    movwf    TRISA            ;RA5:RA0 se configuran como entrada
    bcf        STATUS,RP0        ;Selecciona banco 0            

; CODIGO**********************************************************


    Ciclo 
; Esperar a que se presione el botón
Si_Push btfsc   PORTA,0        ; Repetir hasta que RA0 sea 0
    goto    $-1                ; No es 0, regresar 1 instrucción
; Hacer el Toggle
    xorlw    b'10'            ; Toggle sobre el bit correspondiente (RB1)
    movwf    PORTB            ; Mover W al puerto B
 ; Esperar a que se suelte el botón
No_Push btfss   PORTA,0        ; Repetir hasta que RA0 sea 1
    goto    $-1                ; No es 1, regresar 1 instrucción   
    goto    Ciclo            ; Es 1, repetir el ciclo

    END                        ;Fin del programa.
```

Pensando bien. Hay que hacer pruebas y las sigo haciendo sobre la instrucción *btfss* o *btfsc* solo con la memoria RAM. Me explico.
Una variable llamada Flag,0. Sólo cambia el bit de menor pero que es el 0.
Si el btfss Flag,0 ; es 1.
goto APAGAR
goto ENCENDER ; Salta aquí.

Cosas así. El problema que no estamos con modo interruptor, sino modo pulsador, por eso es más complicado. 

Cuando sea uno irá a goto ENCENDER, si dejas de pulsar, se comporta como interruptor y vuelve a 0 y se apaga. El dilema que el pulsador al pulsarlo se quede encendido y al pulsarlo de nuevo se quede apagado el Led. No el efecto de que al pulsarlo se quede encendido siempre y no puedas apagarlo o que al pulsarlo o dejarlo pulsado se enciende y cuando lo dejas de pulsar se vuelva a apagar. Fuerte lío lo que acabo de decir.

Recuerdo que en el 2009 lo hice, ahora no recuerdo y debo aprenderlo otra vez y anotar estos apuntes. El ASM si no lo practicas lo olvidas muy rápido más que a la hora de aprenderlo.

Seguiré haciendo pruebas.


----------



## Dano (Ago 7, 2012)

```
List    p=16F886        ;Tipo de procesador
            include    "P16F886.INC"    ;Definiciones de registros internos

;Ajusta los valores de las palabras de configuración durante el ensamblado.Los bits no empleados
;adquieren el valor por defecto.Estos y otros valores se pueden modificar según las necesidades

        __config    _CONFIG1, _LVP_OFF&_PWRTE_ON&_WDT_OFF&_EC_OSC&_FCMEN_OFF&_BOR_OFF     ;Palabra 1 de configuración
        __config    _CONFIG2, _WRT_OFF                                    ;Palabra 2 de configuración

            org    0x00
            goto    Comienzo            ;Vector de reset
            org    0x05    


Comienzo    
    clrf     PORTB            ;Borra los latch de salida
    bsf        STATUS,RP0
    bsf        STATUS,RP1        ;Selecciona banco 3
    clrf    ANSEL            ;Puerta A digital
    clrf    ANSELH            ;Puerta B digital
    bcf        STATUS,RP1        ;Selecciona banco 1
    clrf    TRISB            ;RB7:RB0 se configuran como salida
    clrf    TRISC
    movlw    b'11111111'        
    movwf    TRISA            ;RA5:RA0 se configuran como entrada
    bcf        STATUS,RP0        ;Selecciona banco 0            

; CODIGO**********************************************************


Ciclo 
								; Esperar a que se presione el botón
Si_Push btfsc   PORTA,0        ; Repetir hasta que RA0 sea 0
 	    goto    Si_Push               ; No es 0, regresar 1 instrucción
								; Hacer el Toggle
    COMF    PORTB            ; COMPLEMENTA RB
	GOTO	Si_Push

    END                        ;Fin del programa.
```

Probado en MPLAB funciona perfecto, lo reduje mas al codigo, son 4 lineas ahora .

Reitero lo que dije antes, es necesario agregarle un detector de flancos pero mas alla de eso es 100% funcional.


----------



## Meta (Ago 7, 2012)

Hola:

No funciona. Lo probé con "Toggle" y el "Pulse High". Pulse High es el ideal para probarlo.

Si te refieres un detector de flancos, pues si, una direción de RAM basta. Es lo que estoy haciendo, lo haré así y sin RAM. Estoy haciendo a mano un diagrama de flujo, parece ser que se necesita hacer como mínimo  tres instrucciones de salto sea el btfss o el btfsc.

Sigo investigando.



Parece que ahor ame funciona. DEbo usar retardos para antirrebores, lo probaré con hardware.


```
LIST    P=16F886        ;Tipo de procesador
    INCLUDE    <P16F886.INC>    ;Definiciones de registros internos

;Ajusta los valores de las palabras de configuración durante el ensamblado.Los bits no empleados
;adquieren el valor por defecto.Estos y otros valores se pueden modificar según las necesidades

    __CONFIG    _CONFIG1, _LVP_OFF&_PWRTE_ON&_WDT_OFF&_EC_OSC&_FCMEN_OFF&_BOR_OFF     ;Palabra 1 de configuración
    __CONFIG    _CONFIG2, _WRT_OFF                                    ;Palabra 2 de configuración

    ERRORLEVEL -302
    #DEFINE    LED    PORTB,0

    ORG    0x00
    goto    Comienzo            ;Vector de reset
    ORG    0x05    

Comienzo    
    clrf     PORTB            ;Borra los latch de salida
    bsf        STATUS,RP0
    bsf        STATUS,RP1        ;Selecciona banco 3
    clrf    ANSEL            ;Puerta A digital
    clrf    ANSELH            ;Puerta B digital
    bcf        STATUS,RP1        ;Selecciona banco 1
    clrf    TRISB            ;RB7:RB0 se configuran como salida
    clrf    TRISC
    movlw    b'11111111'        
    movwf    TRISA            ;RA5:RA0 se configuran como entrada
    bcf        STATUS,RP0        ;Selecciona banco 0            

; CODIGO**********************************************************

Led_OFF
    bcf        LED         ; Apagar Led.
    btfss    PORTA,0        ; ¿Entrada 0? ¿Botón pulsado?
    goto    Led_OFF        ; Apagar Led.
    goto    Led_ON        ; Encender Led.
Led_ON
    bsf        LED            ; Encender Led.
    btfss    PORTA,0        ; ¿Entrada 0? ¿Botón pulsado?
    goto    Led_ON        
    goto    Led_OFF

    END                        ;Fin del programa.
```

En MPLAB simulando debo pulsar varias veces el pulsador para que me haga caso, cuando lo logro, me funciona. No hace falta RAM.

A probarlo ustedes que a lo mejor sacan mejores resultado que yo.

Sigo probando por si acaso.

Un saludo y gracias a todos.


----------



## D@rkbytes (Ago 8, 2012)

Con estos cambios que realice al programa, funciono mejor.
También le agregue una rutina de retardo antirebotes de 150ms.

Con el programa anterior, no funcionaba con la rutina de retardo y ahora si.

```
Si_Push
    btfsc    PORTA,0            ; Comparar que RA0 sea 0
    goto    Si_Push            ; No es 0, regresar
    call    Demora            ; 150ms de retardo antirebote
    movlw    b'10'            ; Establecer el bit 1 (RB1)
    xorwf    PORTB,F            ; Realizar el cambio de estado (Toggle)
No_Push
    btfss    PORTA,0            ; Comparar que RA0 sea 1
    goto    No_Push            ; No es 1, regresar
    goto    Si_Push            ; Es 1, repetir el ciclo
```
La rutina de retardo la genere con el programa PIC Delayer (PDEL)
Igualmente probé el programa con un 16F88 y funciona excelentemente.

Saludos.


----------



## Meta (Ago 8, 2012)

Buenas:

Con lo mismo hice este y en simulador me funciona.

```
LIST    P=16F886        ;Tipo de procesador
    INCLUDE    <P16F886.INC>    ;Definiciones de registros internos

;Ajusta los valores de las palabras de configuración durante el ensamblado.Los bits no empleados
;adquieren el valor por defecto.Estos y otros valores se pueden modificar según las necesidades

    __CONFIG    _CONFIG1, _LVP_OFF&_PWRTE_ON&_WDT_OFF&_EC_OSC&_FCMEN_OFF&_BOR_OFF     ;Palabra 1 de configuración
    __CONFIG    _CONFIG2, _WRT_OFF                                    ;Palabra 2 de configuración

    CBLOCk    0x20
    ENDC

    ERRORLEVEL -302
    #DEFINE    LED    PORTB,0

    ORG    0x00
    goto    Comienzo            ;Vector de reset
    ORG    0x05    

Comienzo    
    clrf     PORTB            ;Borra los latch de salida
    bsf        STATUS,RP0
    bsf        STATUS,RP1        ;Selecciona banco 3
    clrf    ANSEL            ;Puerta A digital
    clrf    ANSELH            ;Puerta B digital
    bcf        STATUS,RP1        ;Selecciona banco 1
    clrf    TRISB            ;RB7:RB0 se configuran como salida
    clrf    TRISC
    movlw    b'11111111'        
    movwf    TRISA            ;RA5:RA0 se configuran como entrada
    bcf        STATUS,RP0        ;Selecciona banco 0            

; CODIGO**********************************************************

Led_OFF
    bcf        LED         ; Apagar Led.
    btfss    PORTA,0        ; ¿Entrada 0? ¿Botón pulsado?
    call    Retardo_20ms
    goto    Led_OFF        ; Apagar Led.
    goto    Led_ON        ; Encender Led.
Led_ON
    bsf        LED            ; Encender Led.
    btfss    PORTA,0        ; ¿Entrada 0? ¿Botón pulsado?
    call    Retardo_20ms
    goto    Led_ON        
    goto    Led_OFF

    INCLUDE    <RETARDOS.INC>
    END                        ;Fin del programa.
```
En un libro acaba de encontrar el adecuado, más efectivo que le mio.


----------



## Meta (Ago 8, 2012)

Hola de nuevo:

El código que vi en un libro.

```
LIST    P=16F886        ;Tipo de procesador
    INCLUDE    <P16F886.INC>    ;Definiciones de registros internos

;Ajusta los valores de las palabras de configuración durante el ensamblado.Los bits no empleados
;adquieren el valor por defecto.Estos y otros valores se pueden modificar según las necesidades

    __CONFIG    _CONFIG1, _LVP_OFF&_PWRTE_ON&_WDT_OFF&_EC_OSC&_FCMEN_OFF&_BOR_OFF     ;Palabra 1 de configuración
    __CONFIG    _CONFIG2, _WRT_OFF                                    ;Palabra 2 de configuración

    CBLOCk    0x20
    ENDC

    ERRORLEVEL -302
    #DEFINE Pulsador    PORTA,0
    #DEFINE    LED    PORTB,0

    ORG    0x00
    goto    Comienzo            ;Vector de reset
    ORG    0x05    

Comienzo    
    clrf     PORTB            ;Borra los latch de salida
    bsf        STATUS,RP0
    bsf        STATUS,RP1        ;Selecciona banco 3
    clrf    ANSEL            ;Puerta A digital
    clrf    ANSELH            ;Puerta B digital
    bcf        STATUS,RP1        ;Selecciona banco 1
    clrf    TRISB            ;RB7:RB0 se configuran como salida
    clrf    TRISC
    movlw    b'11111111'        
    movwf    TRISA            ;RA5:RA0 se configuran como entrada
    bcf        STATUS,RP0        ;Selecciona banco 0            

; CODIGO**********************************************************

Principal
    btfsc    Pulsador
    goto    Fin
;    call    Retardo_20ms
    btfsc    Pulsador
    goto    Fin
    bsf        LED
EsperaDejePulsar
    btfss    Pulsador
    goto    EsperaDejePulsar
Fin    goto    Principal

    INCLUDE    <RETARDOS.INC>
    END                        ;Fin del programa.
```

Este código hay un problema, te enciende el Led, pero no es capaz de apagarlo, jajaja.



Lo encontré, este es el código adecuado.

```
; ZONA DE CÓDIGOS ********************************************************************

    ORG    0                        ; El programa comienza en la dirección 0.
Inicio
     bsf        STATUS,RP0            ; Acceso al Banco 1.
    bsf        Pulsador            ; La línea RA4 se configura como entrada.
    bcf        LED                    ; Se configura como salida.
    bcf        STATUS,RP0            ; Acceso al Banco 0.
    bcf        LED                    ; En principio diodo LED apagado.
Principal
    btfsc    Pulsador            ; ¿Pulsador presionado?, ¿(Pulsador)=0?
    goto    Fin                    ; No. Vuelve a leerlo.
    call    Retardo_20ms        ; Espera que se estabilicen los niveles de tensión.
    btfsc    Pulsador            ; Comprueba si es un rebote.
    goto    Fin                    ; Era un rebote y sale fuera.
    btfsc    LED                    ; Testea el último estado del LED.
     goto    EstabaEncendido
EstabaApagado
    bsf        LED                    ; Estaba apagado y lo enciende.
    goto    EsperaDejePulsar
EstabaEncendido
    bcf        LED                    ; Estaba encendido y lo apaga.
EsperaDejePulsar
    btfss    Pulsador            ; ¿Dejó de pulsar?. ¿(Pulsador)=1?
    goto    EsperaDejePulsar    ; No. Espera que deje de pulsar.
Fin
    goto    Principal

    INCLUDE <RETARDOS.INC>
    END
```


----------



## jesusitow (May 9, 2013)

Amigos este programa porque no me corre?
estoy tratando de prender un led mediante un pulsador:

```
LIST P=16F877
    #INCLUDE <P16F877.INC>
PORTA EQU 0X05
TRISA EQU 0X85
PORTB EQU 0X06
TRISB EQU 0X86

    ORG 0X00

    banksel TRISB
    movlw b'111111111'
    movwf TRISB
    banksel TRISA
    movlw b'000000'
    movwf TRISA

INICIO

    btfss PORTA,0 ;¿Entrada a 1?
    goto COMPROBAR ;No, Salta a comprobar
    goto INICIO ;Si, vuelve a testear el bit

COMPROBAR
    btfss PORTB,0 ;El led esta encendido?
    goto APAGAR ; Ve a apagar
    goto ENCENDER; No, Ve a encender

ENCENDER
    bsf PORTB,0 ; Enciender Led.
    goto INICIO ; Vuelve a INICIO.

APAGAR
    bcf PORTB,0 ; Apaga el Led.
    goto INICIO ; Vuelve a INICIO.
    END ; Fin de programa
```


----------



## D@rkbytes (May 9, 2013)

jesusitow dijo:


> Amigos este programa porque no me corre?
> estoy tratando de prender un led mediante un pulsador:


Tienes algunas fallas en el programa.
.- Debes tener en cuenta que el 16F877 tiene ADC en el puerto A y en el puerto E.
Si no lo configuras como digital I/O, la comprobación de estados lógicos no funciona.
.- No tienes establecida la palabra de configuración, y es importante declararla.
Si no lo haces, el compilador establece alguna por default, y no siempre es la requerida.
Ésto también se puede hacer con el programa que grabes el PIC.
.- Estás configurando el puerto B como entradas, el A como salidas, y quieres leer RA0. Así no se podrá.
.- También necesitas usar alguna rutina de retardo para evitar rebotes del pulsador.

Una corrección a tu código, sería así...

```
LIST P=16F877
    #INCLUDE <P16F877.INC>
    __config    _XT_OSC & _WDTE_OFF & _PWRTE_ON & _LVP_OFF

    cblock    0x20
    count1,count2
    endc

    ORG 0X00

    bsf        STATUS,RP0
    movlw    0x06
    movwf    ADCON1
    movlw    b'11111110'
    movwf    TRISB
    bcf        STATUS,RP0
    clrf    PORTB

INICIO
    btfss    PORTA,0            ; ¿Entrada a 1?
    goto    INICIO            ; No, vuelve a testear el bit (RA0)
    call    Retardo.25
    goto    COMPROBAR        ; Si, Salta a comprobar

COMPROBAR
    btfsc    PORTB,0            ; El led esta encendido?
    goto    APAGAR            ; Si, Ve a apagar
    goto    ENCENDER        ; No, Ve a encender

ENCENDER
    bsf        PORTB,0            ; Encender Led.
    goto    INICIO            ; Vuelve a INICIO.

APAGAR
    bcf        PORTB,0            ; Apaga el Led.
    goto    INICIO            ; Vuelve a INICIO.

; Subrutina de retardo de 250ms @ 4MHz
Retardo.25
; 249993 ciclos
    movlw    0x4E
    movwf    count1
    movlw    0xC4
    movwf    count2
Retardo.25_0
    decfsz    count1,f
    goto    $+2
    decfsz    count2,f
    goto    Retardo.25_0
; 3 ciclos
    goto    $+1
    nop
; 4 ciclos (incluyendo call)
    return

    END                        ; Fin de programa
```
Pruébalo usando un resistencia de pull-down en RA0
Comprueba tener el pin 1 (MCLR/Vpp) hacia VDD, revisa la alimentación de los pines.
11 y 32 = VDD, 12 y 31 = VSS, y también la correcta conexión del cristal.

Suerte.


----------



## jesusitow (May 9, 2013)

Muchas Gracias amigo


----------



## D@rkbytes (May 10, 2013)

jesusitow dijo:


> Muchas Gracias amigo


De nada, espero que hayas probado el código y que nos comentes si te funciono.

Otro detalle que se me pasó decir, es qué si incluyes la librería para el PIC con el que trabajarás,
no es necesario declarar los registros que usarás, cómo los que escribiste en tu programa...
    PORTA EQU 0X05
    TRISA EQU 0X85
    PORTB EQU 0X06
    TRISB EQU 0X86
Cuando haces uso de #INCLUDE <PXXXXXX.INC> ó INCLUDE PXXXXXX.INC
Ya no es necesario que los declares, ya que en tal librería se incluyen.
Y el compilador busca los registros declarados en las librerías agregadas.

Suerte.


----------



## End3tz (Nov 13, 2015)

Disculpen. Quisiera saber si está bien el código.

```
LIST P = 18F4550
INCLUDE <P18F4550.INC>
;************************************************************
CONFIG FOSC = HS ;INTOSC_XT no disponible para simulación, usar HS
CONFIG PWRT = ON
CONFIG BOR = OFF
CONFIG WDT = OFF
CONFIG MCLRE = ON
CONFIG PBADEN = OFF
CONFIG LVP = OFF
CONFIG DEBUG = OFF
CONFIG XINST = OFF
; CODE ******************************************************
#define Led PORTB, 4
 
ORG 0x00    ;Iniciar el programa en el registro 0x00
 
    clrf    PORTB   ;Limpia los posibles valores actuales de PORTB
    movlw   b'1111'  ;Entradas y Salidas para PORTB
    movwf   TRISB   ;Configura TRISB <- W

INICIO
      btfss PORTB, 0
      goto Apagado
      goto Encendido
Encendido
      bsf Led
      btfss PORTB, 0
      goto Encendido
      goto Apagado
Apagado
      bcf Led
      goto INICIO
      
 
end
```
Cuando lo pruebo físicamente tengo presionar 2 veces o 3 para prender y lo mismo para apagar.
Suerte y se prende a la primera.

PD: Novato presente.


----------



## proteus7 (Nov 13, 2015)

Lo que pasa es que con el botón generas ruido.


----------



## End3tz (Nov 13, 2015)

¿Y cómo elimino el ruido?


----------



## Don Plaquetin (Nov 13, 2015)

Con un circuito  DEBOUNCER







Saludo


----------



## juanma2468 (Nov 13, 2015)

End3tz dijo:
			
		

> LIST P = 18F4550
> INCLUDE <P18F4550.INC>
> ;*************************************************  ***********
> CONFIG FOSC = HS ;INTOSC_XT no disponible para simulación, usar HS
> ...


Deberias cambiar el orden de las primeras 3 instrucciones, ya que primero asignas un valor al puerto sin antes configurarlo como va a trabajar. Quedaría así:


```
movlw   b'1111'  ;Entradas y Salidas para PORTB
movwf   TRISB   ;Configura TRISB <- W
clrf    PORTB   ;Limpia los posibles valores actuales de PORTB
```
Igual asi como esta, el led va a prender y apagar al presionar el botón, tendrias que esperar a soltar el pulsador para volver a leerlo, a parte del anti rebote que te posteo SSTC.


```
INICIO
btfss PORTB, 0
goto Apagado
goto Encendido
Encendido
bsf Led
Espera1        ; Agregado
btfsc PORTB, 0 ; Agregado
goto Espera1   ; Agregado
btfss PORTB, 0
goto Encendido
goto Apagado
Apagado
bcf Led
Espera2        ; Agregado
btfsc PORTB, 0 ; Agregado
goto Espera2   ; Agregado
goto INICIO

end
```


----------

