Lenguaje ensamblador para PIC desde 0

bueno es una pregunta sencilla

se puede utilizar esta instruccion de esta manera?

Código:
btfss        Pulsador,0

Pulsador es una variable, y queria comprobar si es 1 el primer bit de esa variable, o es de otra manera?
 
Hola. ¿Me podrían explicar en cada línea para que sirve cada parte del código?

Código:
list P=16f628A
   include <P16f628A.INC>
   
   __config _CP_OFF& _WDT_OFF& _PWRTE_ON& _MCLRE_ON& _LVP_OFF& _INTOSC_OSC_NOCLKOUT ; desavilito perro guardion pin 5 no se puede usar, habilito puerto B(lvp_of),habiita el oscilador interno y no el de salida (_intosc_osc_noclkouñ
     
   org 0
       goto CONFIG_PUERTOS

   org 5

CONFIG_PUERTOS

            


       clrF PORTA 
       clrf PORTB

       bcf STATUS,RP1
       bsf STATUS,RP0

       movlw 0x07
       movwf CMCON
       
       
       movlw b\'11111111\'
       movwf TRISA
       
       movlw 0x00 ;clrf trisb
       movwf TRISB
  
       bcf STATUS,RP1
       bcf STATUS,RP0
   
PRINSIPAL 
    
       movf PORTA,W 
       movwf PORTB 
    
     goto PRINSIPAL

     end
 
PHP:
    list P=16f628A              ; informa al ensamblador a qué PIC nos dirigimos
    include <P16f628A.IN>       ; incluye las constantes de ese PIC para usarlas más adelante

                                ; ajusta los fusibles de funcionamiento general
    __config _CP_OFF & _WDT_OFF & _PWRTE_ON & _MCLRE_ON & _LVP_OFF & _INTOSC_OSC_NOCLKOUT

    org     0                   ; origen del programa

    goto    CONFIG_PUERTOS      ; saltar a configurar los puertos

    org     5

CONFIG_PUERTOS:                 ; aquí empieza lo interesante

    clrf    PORTA               ; inicialiazamos el valor de los puertos A y B
    clrf    PORTB

    bcf     STATUS,RP1          ; cambiamos al banco 1
    bsf     STATUS,RP0

    movlw   b'0111'             ; le ponemos 7 al CMCON: desactivamos el modo de comparación en puerto A
    movwf   CMCON


    movlw   b'11111111'         ; configuramos el puerto A como entrada
    movwf   TRISA

    movlw   b'00000000'         ; configuramos el puerto B como salida
    movwf   TRISB

    bcf     STATUS,RP1          ; cambiamos al banco 0
    bcf     STATUS,RP0

PRINCIPAL:                      ; inicio del bucle

    movf    PORTA,W             ; leemos el valor presente en el puerto A
    movwf   PORTB               ; lo escribimos en el puerto B

    goto    PRINCIPAL           ; y repetimos

    end
 
Última edición por un moderador:
Hola soy nuevo en lenguaje en ensamblador quiero hacer un retardo de tiempo con NOP pero aun no se bien como se utiliza, lo que he encontrado en internet es que necesito esto MOVLW .100 , MOVWF cnt, este es mi planteamiento de programa.


PRINCIPAL

MOVLW .100
MOVWF cnt
BSF LED ;ENCIENDE
NOP


BCF LED ; apaga
NOP
GOTO PRINCIPAL
END

según lo que tengo entendido es que el led va a estar encendido al mismo tiempo que va a estar apagado, pero lo simulo en proteus y aveces dura mas encendido que apagado y viceversa, quisiera saber cual es el problema del programa ...
 
Hola, lo que sucede es que el tiempo de ejecución de la instrucción GOTO inserta un tiempo más de ejecución provocando que el led permanezca más tiempo apagado que prendido, para compensarlo pon 2 NOP's más después de BSF LED
 
El problema es que la instrucción nop apenas dura un ciclo de reloj, así que apenas estás poniendo una espera.

Depende de la velocidad del reloj con el que estés alimentando el PIC, que tendrás que poner una cantidad mayor o menor al contador.

Y, lo principal: debes realizar el proceso de descuento del contador: un bucle vacío (con uno o varios nop dentro) que se ocupe solo de decrementar el contador.

La instrucción decfsz (decrementar una posición de memoria y saltar una instrucción si es cero) es la adecuada para estos casos:

PHP:
PRINCIPAL:

    BSF LED ; enciende

    MOVLW .100
    MOVWF cnt
BUCLE1:
    NOP
    DECFSZ cnt
    GOTO BUCLE1

    BCF LED ; apaga

    MOVLW .100
    MOVWF cnt
 BUCLE2:
    NOP
    DECFSZ cnt
    GOTO BUCLE2

    GOTO PRINCIPAL
    END
Edito: Se me adelantó Meza :)
 
Bueno, es cierto, faltó aclarar el uso de los registros contadores, yo me fui más por la parte de que el lazo infinito mantuviera al LED prendido y apagado el mismo lapso de tiempo... si lo que se desea es crear retardos variables por software sigue el consejo de Joaquín... ahora creo recordar que aquí en el foro hace tiempo publicaron un link donde se tenía un calculador automático de valores para cargar en los contadores; incluso el mismo calculador generaba la porción de código correspondiente, será cuestión de buscar
 
Retardo básico en un pic

Yo también participé en la discusión, e hice mi propia versión del generador de Golovchenko (ya que no explicaban cómo lo hacían).

A modo de ejemplo, si tenemos un PIC a 4 Mhz y queremos una espera de 500 ms:
PHP:
$ ./delay_pic.pl 4Mhz 500ms -s
; ----------------------------------------------------------------------------------------------------
; Espera = 500ms
; Frecuencia de reloj = 4Mhz
;
; Espera real = 0.5 segundos = 500000 ciclos
; Error = 0.00 %

        cblock 0x70
                Espera_d1
                Espera_d2
                Espera_d3
        endc

Espera:
                                        ;499994 ciclos
                movlw   0x03
                movwf   Espera_d1
                movlw   0x18
                movwf   Espera_d2
                movlw   0x02
                movwf   Espera_d3

Espera_loop:
                decfsz  Espera_d1, f
                goto    $+2
                decfsz  Espera_d2, f
                goto    $+2
                decfsz  Espera_d3, f
                goto    Espera_loop

                                        ;2 ciclos
                goto    $+1

                                        ;4 ciclos (incluyendo la llamada)
                return

; Generado por delay_pic.pl (Joaquín Ferrero. 2014.07.22)
; ./delay_pic.pl 4Mhz 500ms -s
; jue 25 sep 2014 19:55:09 CEST
; http://perlenespanol.com/foro/generador-de-codigos-de-retardo-para-microcontroladores-pic-t8602.html
; ----------------------------------------------------------------------------------------------------
 
Hola a todos.

Estoy realizando un proyecto: un temporizador para una válvula que puede configurarse como N/A o N/C, operación manual o automática, y el control automático puede ser a ciclo continuo o en un número determinado de ciclos, a un máximo y un mínimo de tiempo programable, crea un historial de operación del dispositivo y, en caso de falla de energía, manda a condición segura la válvula y poderse iniciar automáticamente en caso de restablecerse el servicio. Todo esto con el buen PIC16F876A.

Hasta el momento, a estirones y golpes con el Datasheet y el Manual de Referencia de los PIC's de Medio Rango he logrado sacar adelante el proyecto. Pero me topé con un pequeño problemita:

Puedo realizar bien el paginado del programa, manejar PCLATH y la llamada de rutinas de una página a otra sin ningún problema, es más, he puesto 3 tablas para manejar mensajes en caso de que las EEPROM del historial lleguen a fallar (1 tabla por cada una de las páginas en las que he trabajado por el momento, aun no toco la 4a página del programa del pic, son como 4914 lineas de código).

El problema viene aquí: En uno de los menús necesito acceder a otro submenú y en ese sub menú a otro submenú, y en este, a su vez, realizar la selección de dos opciones.

Por lo que logré entender (con mi ingles mordisqueado y con ayuda de San Google traslator) en el Manual de Referencia del PIC (en la página 100) me establece que...

"No puedo realizar más de 8 llamadas anidadas, pues el stack sufre un sobre flujo (es un buffer circular)"

En otras palabras:

No puedo realizar más de 8 llamadas, una dentro de otra, dentro de otra, dentro de otra... etc. porque si no, la novena llamada realizada se ingresara en la primera posición del STACK y eso me provocaría la perdida de la dirección del PC de la primer llamada que yo realice.

Mi consulta es esta: Estoy en lo cierto??? De no ser así, tengo un problema para entender las cosas y mi ingles no me sirve de mucho. De ser cierto, sugiero, humildemente, que lo pongan dentro del tutorial, pues, al menos a mí, que estoy haciendo este proyecto completamente en Assembler, me hubiese sido de mucha ayuda, pues estuve 2 días batallando con ese problemita.


El "overflow" y "underflow" del STACK causan problemas en el ciclo continuo del programa, entonces, al menos en los PIC's de Rango Medio, no se deben de sobrepasar mas de 8 llamadas, incluido el servicio de interrupciones (sin finalizar con su debido RETURN, RETLW o RETFIE ) para asegurar un correcto funcionamiento del STACK.
 
Hola
El problema viene aquí: En uno de los menús necesito acceder a otro submenú y en ese sub menú a otro submenú, y en este, a su vez, realizar la selección de dos opciones.

¿y cada submenú corresponde a un nivel de pila? o ¿cómo es tu estructura del menú?, pudieses usar otra alternativa para acceder a menús sin necesidad de utilizar intensamente la pila.
 
Si, la verdad desconocia esto, en este momento estoy modificando las rutinas y en lugar de CALL estoy usando GOTO, al final de cuentas, no es una rutina que pueda usar en cualquier otra parte del programa, son solo rutinas para mostrar algunos mensajes del menu y guardar las configuraciones propias de ese submenu. Con esto espero poder liberarme de este problema.

No, no todos los niveles de pila corresponden a un submenu, algunos corresponden a rutinas de retardos que usan otras rutinas de manejo de LCD o de escritura en la EEPROM del PIC, maximo 4 son usadas para los submenus, las otras restantes son para las rutinas ya mencionadas.
 
Lo que también te sugiero es que clasifiques tus subrutinas en función de lo que hagan, temporización, memoria, lcd, etc y que procures en lo posible que sean independientes unas de otras, esto evitará el anidamiento de subrutinas
 
Muy buena tu ayuda, me va a servir de mucho, gracias. Estoy intentando hacer un programa que efectue una acción (un efecto de luces) que se repetida una x cantidad de veces y que luego pase a otro efecto. .Alguien sabe como podría hacer esto? he intentado hacerlo con la instrucción DECFSZ pero no me a resultado como quería, ya que hace el primer efecto, no lo repite, y luego salta al siguiente pero queda en un bucle infinito mezclado con otro efecto... les agredecería que me pudieran ayudar ya que me encuentro bastante confundido con esto.. :(
 
Pon el codigo para ver como manejas la rutina. Quizas estan utilizando un solo registro para todo el proceso y no estas cargando adecuadamente el numero de veces que quieres que se repita una secuencia. Pero es solo imaginacion mia, mejor, pon el codigo para poderte ayudar.
 
Pon el codigo para ver como manejas la rutina. Quizas estan utilizando un solo registro para todo el proceso y no estas cargando adecuadamente el numero de veces que quieres que se repita una secuencia. Pero es solo imaginacion mia, mejor, pon el codigo para poderte ayudar.
acá está, sepan disculpar lo mal que programo :/ todavía no lo domino bien...

Código:
		LIST P=16F628A
		INCLUDE <P16F628A.INC>
		__config _BODEN_OFF & _CP_OFF & DATA_CP_OFF & _PWRTE_ON & _WDT_OFF & _LVP_OFF & _MCLRE_ON & _XT_OSC 
			ORG 0
			BSF STATUS, RP0
			MOVLW B'00000000'
			MOVWF TRISB 
			BCF STATUS, RP0
EFECTO1		EQU H'21'
			MOVLW .15
			MOVWF .15	
			MOVLW B'00001111'
			MOVWF PORTB 
			CALL DEMORA
			MOVLW B'11110000'
			MOVWF PORTB
			CALL DEMORA
			DECFSZ .15
			GOTO EFECTO2
EFECTO2  	EQU H'21'
			MOVLW .15
			MOVWF .15
			MOVLW B'10101010'
			MOVWF PORTB
			CALL DEMORA 
			MOVLW B'01010101'
			MOVWF PORTB
			CALL DEMORA
			DECFSZ .15 
			GOTO EFECTO3
EFECTO3		EQU H'21'
			MOVLW .15
			MOVWF .15
			MOVLW B'10000001'
			MOVWF PORTB 
			CALL DEMORA
			MOVLW B'11000011'
			MOVWF PORTB
			CALL DEMORA 
			MOVLW B'11100111'
			MOVWF PORTB
			CALL DEMORA
			MOVLW B'11111111'
			MOVWF PORTB
			CALL DEMORA
			MOVLW B'11100111'
			MOVWF PORTB
			CALL DEMORA
			MOVLW B'11000011'
			MOVWF PORTB
			CALL DEMORA
			MOVLW B'10000001'
			MOVWF PORTB
			CALL DEMORA
			DECFSZ .15
			GOTO EFECTO1
DEMORA		  
			MOVLW   .100          ;RETARDO DE 250 MILISEGUNDOS
        	MOVWF   H'7E'           ;
TOPB    	MOVLW   .250            ; TIMING ADJUSTMENT VARIABLE
        	MOVWF   H'7F'
TOP2B   	NOP                   
        	NOP
        	NOP
        	NOP
        	NOP
        	NOP
        	DECFSZ  H'7F',F        ; INNER LOOPS COMPLETE?
        	GOTO    TOP2B          ; NO, GO AGAIN
            DECFSZ  H'7E',F        ; OUTER LOOPS COMPLETE?
        	GOTO    TOPB           ; NO, GO AGAIN
			RETURN		       ; YES, RETURN FROM SU
			END
 
Hola, ya vi el error, está en que no permites que el micro entre al lazo de efecto, mira intenta con esto:



Código:
                        MOVLW .15
			MOVWF .15
EFECTO1		EQU H'21'
				
			MOVLW B'00001111'
			MOVWF PORTB 
			CALL DEMORA
			MOVLW B'11110000'
			MOVWF PORTB
			CALL DEMORA
			DECFSZ .15,F
			GOTO EFECTO1

Como verás también, la instrucción que carga el registro contador de lazos lo puse fuera del bucle para que el programa no entre en un lazo interminable
 
gracias, ahora entiendo como funciona la cosa :) pero tengo otra duda... porqué cuando compilo un programa me salta siempre el error de "Messagge [302] : Register in operand not in bank 0. Ensure that bank bits are correct.?
cuando hago doble click sobre el error me aparece esta liena
Código:
			MOVWF TRISB
sin embargo abajo me dice que no hay errores y la compilación se hace correctamente. esto afecta al funcionamiento del programa?
 
no es un error como tal, si no un "warning" ya que el compilador no sabe que anteriormente cambiaste de banco con los bits RP0 y RP1. Para quitarlo coloca un ^0x80 después de las instrucciónes que trabajen con registros en otros bancos. Por ejemplo:

Código:
movwf   TRISX^0x80

clrf        INTCON^0x80

movf     EEDATA^0x100
 
Hay otra forma de hacerlo: diciendo al enlazador que omita ese mensaje.

Pon esto al principio:

PHP:
     errorlevel  -302                        ; Turn off banking message

Eso sí... con eso te estás comprometiendo a que vas a llevar un control férreo de en qué banco estás trabajando en cada momento.

Más información en el manual del ensamblador del PIC.
 
Atrás
Arriba