Lenguaje ensamblador para PIC desde 0

No soy vidente pero le atine, estabas usando un solo registro para el mismo proposito, en este caso el TMR1.

El compañero Daniel Meza ya te dio la respuesta a tu problema y el compañero JoaquinFerrero ya te dijo como eliminar los "warning".

Solo como sugerencia, nunca utilices los registros de uso especial del PIC como registros cualquiera de la RAM, a menos que no los vayas a utilizar para nada y que tu proceso requiera una cantidad de RAM que ya sobrepasaste y que solo tocando esos registros puedas solucionar ese problema.

Los registros de uso especial pueden verse afectados por el uso de otros registros especiales y cuando menos te lo esperas te crean un "problema" que no contemplas. En este caso no tienes habilitado el TMR1 ni estas utilizando interrupciones ni cosa por el estilo, asi que no hay problema. Lo recomendable es usar la RAM a partir de la direccion donde inician los registros de proposito general (para este PIC, la 20h para el Banco 0).

Ademas, en un futuro podrias necesitar ese registro y tendrias que modificar tu programa, mejor declara tu bloque de variables:

Código:
	CBLOCK	0x20
	CONTADOR			;EN LUGAR DE PONER	"MOVWF	.15"	PUEDES PONER	"MOVWF	CONTADOR"
	ENDC
 
Tengo una duda, a ver si los expertos en ensambler me ayudan. Imaginaos, cargo un registro con el número 25 y ese número deseo sacarlo de la siguiente forma por el PORTB, el 5 sacarlo por un nibble que puede ser desde RB0 a RB3, y el 2 por otro nibble desde RB4 a RB7 ¿Como lo haría?. Lo que pretendo es poder sacar cualquier número entre 0 a 99 y poder visualizarlo por dos displays de 7 segmentos.
 
Tengo una duda, a ver si los expertos en ensambler me ayudan. Imaginaos, cargo un registro con el número 25 y ese número deseo sacarlo de la siguiente forma por el PORTB, el 5 sacarlo por un nibble que puede ser desde RB0 a RB3, y el 2 por otro nibble desde RB4 a RB7 ¿Como lo haría?. Lo que pretendo es poder sacar cualquier número entre 0 a 99 y poder visualizarlo por dos displays de 7 segmentos.

Si no hay problema con codigo extenso puedes usar una tabla, cargas el valor en W, llamas la tabla, retornas con el codigo en W y pasas al PORTB, asi de facil, chaooooo
 
Lo primero que debes hacer es transformar el número en binario a BCD. Por estos foros hay algunos hilos que lo explican.

Hay dos formas básicas:

  • Hacemos un bucle por el que necesitamos sacar el número de decenas restando 10 al valor original. Si es menor que 10, entonces lo que quedan son las unidades. Cuando tenemos los dos valores, componemos el nuevo valor en BCD haciendo una rotación del valor de las decenas en el nibble alto, y luego haciendo un OR con el valor de las unidades
  • La otra forma es un poco más de matemáticas, pero más breve que la anterior. Consiste primero en saber cuántas decenas hay. Eso lo podemos sacar haciendo lo mismo que antes, con restas sucesivas. Una vez que lo sabemos, multiplicamos ese valor por 6, y el resultado se lo sumamos al valor original. Eso nos da el valor original ya transformado a BCD. Naturalmente, esta es la solución literal, pero en la práctica se usan trucos, como por ejemplo: cada vez que sumamos una decena más, lo que hacemos en realidad es sumar 6 a un sumador aparte. De esa manera, al mismo tiempo que hacemos la división de las decenas, estamos haciendo la multiplicación por 6 de las decenas. Solo quedaría hacer la suma del valor original con ese multiplicando.
 
Última edición por un moderador:
Leyendo el foro, observé que la mayoría de ustedes no comenta su código, y como es un tema para principiantes, deben de hacerlo para que todo mundo los siga sin dificultad.

También observé que cuando quieren mostrar un dato binario en un display multiplexado, tienen varias dudas de cómo hacerlo.

Si pueden leer inglés, les recomiendo éste sitio:
http://www.islavici.ro/cursuriold/conducere sist cu calculatorul/PICbook/0_Uvod.htm
Tiene la versión on-line del libro gratis "PIC microcontrollers, for beginners too"

Si no, aquí les dejo el macro corregido y programa de prueba como aparece en ese libro. (No lo he simulado)
Si alguien quiere simularlo y comentar su resultado, sería muy bueno.
PHP:
; Ejemplo de uso de macro

        PROCESSOR    P16F84
        #include    "p16f84.inc"
        _CONFIG        _CP_OFF & _WDT_OFF & _PWRTE_ON & _XT_OSC

; Macro para extraer info para mostrar en el Display
; Dig1 = MSD (centenas) Dig2= decenas  Dig3= LSB (unidades)
; par0 = variable a ser mostrada LSB 8-bits (0-255)

digibyte macro par0
    local Loop_C
    local Loop_D
    local Pozitiv
    
    clrf    Dig1        ; Limpiamos contadores que contienen lo
    clrf    Dig2        ; que se va a mostrar en el display
    clrf    Dig3        ; En este caso 3 digitos (0 a 255)

Pozitiv
    movf    par0,w        ; Guarda el número a ser separado
    movwf    Digtemp        ; en forma temporal
;
; Convierte a BCD
; La técnica consiste en dividir el parámetro entre una mascara
;   (100,10,1). para obtener asi el digito en decimal.
; Se implementa la división - subtrayendo al parametro la
;    mascara contando cuantas veces lo hemos hecho, hasta que el
;    resultado de la resta sea menor a la mascara. 
; como empesamos con el contador en 1 debemos substraer 1 antes de
; salir. Para tener en el contador con el resultado correcto
;
; Empesamos con las centenas 
    movlw    .100        ; mascara para las centenas
Loop_C
    incf    Dig1,f      ; Centenas = Centenas + 1
    subwf    Digtemp,f   ; Parametro = Parametro - .100
    btfsc    STATUS,C    ; Si es menor a zero (c=0) salta 1 linea
    goto    Loop_C        ; Si no regresa hasta que ocurra
    decf    Dig1,f        ; Resta 1 alcontador antes de salir
                        ; Digtemp contiene el cosiente de la division
; Seguimos con las decenas
    movlw    .10         ; Ajustamos la mascara para decenas
Loop_D
    incf    Dig2,f        ; Decenas = Decenas + 1
    subwf    Digtemp,f
    btfsc    STATUS,C
    goto    Loop_D
    decf    Dig2,f      ; Dig2 contiene las Decenas y
                        ; Digtemp contiene ahora las unidades
; y finalizamos con las unidades
    movf    Digitemp,w    ; Mueve las unidades a su contador
    movwf    Dig3
    endm
        
        org    0x00
        goto    main        ; Inicio del programa
        
        org    0x04
        goto    ISR            ; Inicio del vextor de interrupción
        
        Cblock 0x0C
        Dig1                ; Centenas del numero binario D
        Dig2                ; Decenas  del numero binario D
        Dig3                ; Unidades del numero binario D
        Digtemp             ; auxiliar en conversion bin-.Dec
        D                    ; numero a desplegar
        One                    ; auxiliar para el multiplexado del Display
        W_temp                ; copia de W en interrupciones
        endc
        
Main
;    banksel    TRISA
        bsf STATUS,5        ;se pone un 1 en el bit 5 del status para
                            ;   elegir el banco 1
         movlw    b'11111100'    ; RA0 & RA1 son salida para multiplexado
        movwf    TRISA
        clrf    TRISB        ; Puerto B son las salidas de los segmentos
        movlw    b'10000100'    ; Prescaler = 32-> TMR0 incrementa cada 32ms
        movwf    OPTION_REG    ;   Asumimos que se usa un cristal de 4 MHz4
;        banksel    PORTA
        bcf STATUS,5  n     ; cambiamos al banco 0 poniendo un 0 en el
                            ;   bit 5 del Status
        movf PORTA,0nn      ; leemos el puerto A y cargamos en W
        movlw    ,96            ; TMR0 inicia en 96
                            ; de manera que una interrupcion ocurre
                            ; cada (255-97)* 32 ms = 5.088 ms
        movwf    TMR0
        movlw    b'10100000'    ; Habilita interrupcion del timer 0
        novwf    INTCON
        
        movlw    .21            ; Despliega el numero 21
        movwf    D
        clrf    One
        clrf    PORTA        ; Apaga ambos digitos al inicio
Loop
        goto Loop        ; Loop principal -> salimos con una interrupcion
        
ISR                            ; Rutina de interrupcion
        movwf    W_temp        ; Salva W
        movlw    .96            ; Inicializa TMR0 para que tenga la siguiente
        movwf    TMR0        ; interrupcion en aprox 5ms
        bcf        INTCON, T0IF ;Limpia bandera de Overflow del TMR0
                            ; para ser capaz de reaccionar a la siguiente
                            ; interupcion
        bcf        PORTA, 0    ; Digito en A0, apagado
        bcf        PORTA, 1    ; Digito en A1, encendido
        movf    One, f        ; Ajusta banderas
        btfsc    STATUS,Z    ; Cual display debe prenderse?
        goto     Msd_on
Lsd_on                        ; Si el MSD estaba anteriormente ON
        bcf        One,0        ; indica que LSD esta ON
        movlw    High Bcdto7seg ; Antes de usar el macro tenemos que ir
                            ; a la tabla de conversion, PCLATH
        movwf    PCLATH        ; W debe sr inizializado con la direccion
                            ; mas alta de la tabla
                            ; para prever errores de direccionamiento
        digibyte    D        ; llama a la macro para separar digitos de D
        movf    Dig3, w        ; W = Unidades
        call    Bcdto7seg    ; llama la tabla de conversion para 7-seg
                            ; para displays que son catodo común
                            ; regresa W con el codigo correspondiente
        movwf    PORTB        ; y prepara los segmentos
        bsf        PORTA, 1    ; Enciende el Digito de las Unidades
                            ; por ~ 5ms, hasta que la siguiente
                            ; interrución ocurra
        movf    W_temp,w    ; Recupera W alvalor que tenia antes de
                            ; entrar a la rutina de interrupción.
        retie
        
Msd_On
        bsf        One, 0        ; Indica que el MSD esta encendido
        movlw    High Bcdto7seg ; Antes de usar el macro tenemos que ir
                            ; a la tabla de conversion, PCLATH
        movwf    PCLATH        ; W debe sr inizializado con la direccion
                            ; mas alta de la tabla
                            ; para prever errores de direccionamiento
        digibyte    D        ; llama a la macro para separar digitos de D
        movf    Dig2, w        ; W = Unidades
        call    Bcdto7seg    ; llama la tabla de conversion para 7-seg
                            ; para displays que son catodo común
                            ; regresa W con el codigo correspondiente
        movwf    PORTB        ; y prepara los segmentos
        bsf        PORTA, 0    ; Enciende el Digito de las Decenas
                            ; por ~ 5ms, hasta que la siguiente
                            ; interrución ocurra
        movf    W_temp,w    ; Recupera W alvalor que tenia antes de
                            ; entrar a la rutina de interrupción.
        retie
    
    org    0x300                ; Inicio de la tabla de conversion
                            ; puesta al inicio de la tercer banco de RAM4
                            ; Otras paginas son posibles pero la tabla
                            ;debe estar en una sola pagina (banco) de RAM

Bcdto7seg                    ; Tabla de conversion para 7-seg
        addwf    PCL,f        ; Ajusta W al valor de tabla + offset
        dt        0x3f, 0x06, 0x5b, 0x4f, 0x66, 0x6d, 0x7d, 0x07, 0x7f, 0x6f
;        retlw    0x3f        ; número 0
;        retlw    0x06        ; número 1
;        retlw    0x5b        ; número 2
;        retlw    0x4f        ; número 3
;        retlw    0x66        ; número 4
;        retlw    0x6d        ; número 5
;        retlw    0x7d        ; número 6
;        retlw    0x07        ; número 7
;        retlw    0x7f        ; número 8
;        retlw    0x6f        ; número 9
 

Adjuntos

  • macro.txt
    5.9 KB · Visitas: 27
Última edición por un moderador:
Les dejo una traducción e interpretación del codigo de conversión de un número de 16-bits a BCD
Este código se puede usar en cualquier PIC, y esta publicado en la nota de aplicación de microchip
AN526 PIC16C5X KPIC16CXXX Math Utility Routines.
Espero que les sea útil.

Código:
LIST P = 16C54, n = 66
;
;********************************************************************
;  Programa para convertir un número Binario de 16-Bit a BCD
; Esta rutina convierte un número binario de 16-Bit a un  número
; BCD  de 5 Digitos. Esta rutina es útil puesto que los PIC16C55 & ;
;  PIC16C57 tienen dos puertos de 8-bit y uno de 4-bit (RA) 
; para mostrar el resultado de los 5 digitos BCD)
;
; El número binario de 16-bit es colocado en variables RAM
;  H_byte & L_byte, con el byte más significativo en H_byte.
; El número BCD de 5-digitos es regresado en R0, R1 & R2 
;  con R0 conteniendo el MSD en su nibble alto (el mas a la derecha) 
; Usa la técnica Shift - Add 3
;
; Performance :
; Program Memory : 35
; Clock Cycles : 885
;
;
; Program: B16TOBCD.ASM
; Revision Date:
; 1-13-97 Compatibility with MPASMWIN 1.40
;
;*******************************************************************;
;
		Cuenta equ 16		; Contador para número de bits
		temp   equ 17
;
		H_byte equ 10
		L_byte equ 11
		R0     equ 12 		; RAM Assignments
		R1     equ 13
		R2     equ 14
;
	include “p16c5x.inc”
	LIST
;P16C5X.INC Standard Header File, Ver. 3.30 Microchip Technology, Inc.
    LIST
;
B2_BCD
		bcf STATUS,0 	        ; carry bit = 0
		movlw .16		; Cuenta=16  bits
		movwf Cuenta
		clrf R0			; Limpia Registros
		clrf R1
		clrf R2
loop16
		rlf L_byte, F      ; Shift a la izquierda un bit del dato en 
		rlf H_byte, F	;   los registros del resultado
		rlf R2, F
		rlf R1, F
		rlf R0, F
;
		decfsz Cuenta, F ; Terminamos todos los16 bits
		goto adjDEC         ;  No: Continua procesando
		RETLW 0               ; Si:  Regresa con W = 0
;
adjDEC				  ; Despues de cada shift left
					  ; Debemos checar cada nibble del Registro
		movlw R2		  ;  no sea mayor a 7 y si es así hay que
                                          ; sumarle 3
		movwf FSR	  ;  empesamos con R2
		call adjBCD			
;
		movlw R1		  ; y seguimos con R1
		movwf FSR			
		call adjBCD
;
		movlw R0		 ; y al último con R0
		movwf FSR
		call adjBCD
;
		goto loop16
;
adjBCD
		; 
		movlw 3			; Suma 3 a LSB
		addwf 0, W		; y sumamos al registro
		movwf temp		;
		btfsc temp, 3		; test if LSB > 7
							;  Si :  LSD = LSD + 3 
		movwf 0				;  No :  no alteramos LSD
		movlw 30			; Suma 30 al MSB
		addwf 0, W		;
		movwf temp
		btfsc temp, 7 		; test if MSB > 7
							;  Si  :  MSD = MSD + 3 
		movwf 0				;  No : no alteramos MSD
		RETLW 0
;
;********************************************************************
; Test Program
;*********************************************************************
main
		movlw 0FF		; número binario a convertir = FFFF
		movwf H_byte	        ; 
		movwf L_byte
		call B2_BCD 	        ; Despues de la conversion del número
						; a BCD obtenemos
; 						;      R0,R1,R2 = 06,55,35
;
self
		goto self
;
		org 1FF			; Reset vector
		goto main
		
		END
 

Adjuntos

  • 16-Bit Binary To BCD Conversion Routine.txt
    2.9 KB · Visitas: 18
Última edición:
Disculpen por el error en la macro para descomponer un numero binario de 8-bits usando division entre 10
aqui esta el codigo correcto

Código:
; Macro para extraer info para mostrar en el Display
; Dig1 = Centenas, Dig2= Decenas  Dig3= LSB (unidades)
; par0 = variable 8-bits a ser convertida a BCD  (0-255)

digibyte macro par0
	local ExitC			; Declaramos las etiquetas internas
	local ExitD
	
	clrf	Dig1		; Limpiamos contadores que contien
	clrf	Dig2		;    en decimal lo que se va a mostrar en
	clrf	Dig3		;     el display

; Convierte a BCD
; La técnica consiste en dividir el parámetro entre una mascara
;   (100,10). para obtener así el digito en decimal.
; Se implementa la división - subtrayendo al parametro la
;    mascara y contando cuantas veces lo hemos hecho, hasta que el
;    resultado de la resta sea menor a la mascara. 
; como empesamos con el contador en 1 debemos substraer 1 antes de
; salir y sumar la mascara al parametro. Para tener en el contador
; con el resultado correcto
;
	movf	par1,w		; Guarda el número a ser
	movwf	Digtemp	;    separado en registro de conversión
;
; Empesamos con las Centenas
;
	movlw	.100        ; mascara para las centenas
ExitC
	incf	Dig1, f		; Centenas = Centenas + 1
	subwf	Digtemp, f	; Parametro = Parametro - .100
	btfsc	STATUS, C	; Si es menor a zero (c=0) salta 1 linea
	goto	ExitC		; Si no regresa hasta que ocurra
	addwf	Digtemp, f	; Agrega 100 ya que restamos de más 
	decf	Dig1, f		;    y Resta 1 al contador antes de salir
	                    ; Digtemp contiene del número a procesar
						;    solo las Decenas y Unidades
; Seguimos con las decenas
;
	movlw	.10			; Ajustamos la mascara para decenas
ExitD
	incf	Dig2, f		; Decenas = Decenas + 1
	subwf	Digtemp, f
	btfsc	STATUS, C
	goto	ExitD
	addwf	Digtemp, f	; Agrega 10 ya que restamos de más 
	decf	Dig2, f		;    y Resta 1 al contador antes de salir
	                    ; Digtemp contiene del número a procesar
						;    solo las Unidades
; y finalizamos con las unidades
	movf	Digitemp,w	; Mueve las unidades a su contador
	movwf	Dig3
	endm
 
Última edición:
Cambiando un poco, Supongan que deseamos colocar 4 datos, en el ejemplo números, en 4 localidades de memoria RAM consecutivas, en el ejemplo empesamos en 10h. Facil verdad...? un ejemplo de clase o tarea. Les dejo aqui 3 formas diferentes de hacerlo. Fuerza bruta si son números, uso de pseudo-instruccion, y el importante direccionamiento indirecto.

Código:
;****************************************************
;                                                                    *
;    Filename:	    Dir_Indexado.asm                 *
;    Date:          Septiembre 29,2015                *
;    File Version:  1.0                                       *
;                                                                    *
;    Author:	    David Sanchez                      *
;    Company:       David Sanchez                     *
;                                                                    * 
;                                                                    *
;****************************************************
;    Descripción :                                              *
; Prueba de movimiento de Datos usando          *
;   diferentes metodos de direccionamiento        *
;   direccionamiento indexado                            *
;       Dirección = Reg4(FSR) + Reg0 (INDF)      *
;       Contenido de Dirección  en W0                 *
;                                                                     *
;   Para ello se coloca los números 1,2,3 & 4     *
;   En localidades continuas de RAM                 *
;   iniciando en 0x010h                                      *
;                                                                     *
;                                                                     *
;*****************************************************

	list      p=16c54             ; directiva para definir el procesador
	#include <p16c5x.inc>         ; definición  de las variables specificas
                                 ; del procesador 

	__CONFIG   _CP_OFF & _WDT_OFF & _RC_OSC

; '__CONFIG'  Esta directiva es useda para implantar una palabra  de configuración en el archivo  *.asm
; Las etiquetas que siguen la directiva estan localizadas en el archivo que describe el procesador *.inc 
;
;***** DEFINICION DE CONSTANTES
Zero	    EQU	0	    ; zero
;
;***** DEFINICION DE VARIABLES RAM
temp	    EQU 0x07        ; 
Prueba	    EQU	0x10        ; Seis localidades seguidas
;    
;***** Macros
; INCW Incrementa W
INCW MACRO
    MOVWF   temp	; Salva W
    INCF    temp, w	; temp = temp + 1
    ENDM
;   
;       Shift PORTA to the left 
;	SLCPA   MACRO
;	MOVLW   1
;	BCF     STATUS, C       ; Clear carry
;	RLF     (PORTA),F       ; Rotate left
;        ENDM        
   
;*****
	ORG     0x000

start	                    ; Inicio del Programa
	CALL CLR_REG	    ; Limpia registros
		
	; Fuerza bruta ... ponemos 1 en 0x10, 2 en 0x11. 3 en 0x12, & 4 en 0x13
	INCF	Prueba         ; 1 en 0x10
	INCF	Prueba +1      ; 1 en 0x11
	INCF	Prueba +2      ; 1 en 0x12
	INCF	Prueba +3      ; 1 en 0x13
	
	INCF	Prueba +1      ; 2 en 0x11
	INCF	Prueba +2      ; 2 en 0x12
	INCF	Prueba +3      ; 2 en 0x13
	
	INCF	Prueba +2      ; 3 en 0x12
	INCF	Prueba +3      ; 3 en 0x13

	INCF	Prueba +3      ; 4 en 0x13
	; aqui terminamos Fuerza bruta
    ;	     ... 10 localidades de Memoria del Programa
	;            ...  0 localidades de RAM
	;            .  10 cyclos de ejecución.
	; Si queremos escribir oto dato a la siguiente localidad
	;    usa 5 más localidades de memoria del program x dato
        ;       o sea "n" localidades de mas por cada dato adicional
	;                  donde "n" es el número de datos
;
	; Exploremos otra forma:
	CALL CLR_REG	    ; Limpia registros
	
	; alternativa 1 de fuerza bruta   usa Pseudo instrucción INCW
	; Una Pseudo instrucción es una instrucción que no es parte de
	;        grupo de instrucciones que vienen en la Hoja de datos.
    ;        Se declaran como macros.	
	MOVLW	1
	MOVWF	Prueba      ;      coloca 1 en 0x10
	INCW		         ; W=2
	MOVWF	Prueba+1    ;      coloca 2 en 0x11
	INCW		         ; W=3
	MOVWF	Prueba+2    ;      coloca 3 en 0x12
	INCW		         ; W=4
	MOVWF	Prueba+3    ;      coloca 4 en 0x13
;
	; INCW no existe asi que tiene que ser implementada
	; por un macro o sustutida por 
	; MOVWF temp
	; INCF  temp ,w
;
	; aqui terminamos  alternativa 1
    ;	... 11 localidades de Memoria del Programa
	;       ...  1 localidades de RAM
	;     ...  11 cyclos de ejecución.
	; Si queremos escribir oto dato a la siguiente localidad
	;    usa solo 2 más localidades de memoria del program x dato
;  Aparentemente Fuerza bruta es más rápida y ocupa menos Memoria,
;    pero solo para pocos movimientos de datos ....si movemos más datos
;    ... alternativa 1 es más eficiente
;
	CALL CLR_REG	    ; Limpia registros
;
	; Alternativa Direccionamiento Indexado
	MOVLW	Prueba	    ; Base = 10h
	MOVWF	FSR         ; FSR = 111 1 0000
	MOVLW	1
	MOVWF	INDF        ; Write W en base         1 en 0x10
	INCF	FSR	    ; Base = base + 1		    ; W = 01h
	INCW		    ;   W = 02h
	MOVWF	INDF	    ;   Write 02 en base+1    2 en 0x11
	INCF	FSR	    ; Base = base + 2
	INCW		    ;   W = 03h
	MOVWF	INDF	    ;   Write 03 en base+2    3 en 0x12
	INCF	FSR	    ; Base = base + 3
	INCW		    ;   W = 04h
	MOVWF	INDF	    ;   Write 04 en base+3    4 en 0x13
;
	;aqui terminamos  Direccionamiento indexado
    ;	... 13 localidades de Memoria del Programa
	;       ...  0 localidades de RAM
	;     ...  13 cyclos de ejecución.
	; Si queremos escribir oto dato a la siguiente localidad
	;    usa solo 3 mas localidades de memoria del programa x dato
	;
;    Aparentemente Alternativa 1 es más rápida pero usa 1 preciosa
;      localidad de Memoria RAM
;  Asi que ha usar el direccionamiento indexado.

; SUBRUTINAS
;
CLR_REG	; Limpia Registros Prueba
	CLRW		   
	MOVWF	temp	    ; temp = 0
	MOVWF	Prueba	    ; Prueba = 0
	MOVWF	Prueba +1   ; Prueba +1 = 0
	MOVWF	Prueba +2   ; Prueba +2 = 0
	MOVWF	Prueba +3   ; Prueba +3 = 0
	RETLW	0	    ;  Regresa con w=0
;
; TABLAS

; ***** Reset
	ORG     0x1FF       ; processor reset vector
	goto    start

	END
 

Adjuntos

  • Dir_Indexado.asm.txt
    5.6 KB · Visitas: 12
Hola a todos,
Necesitaba una rutina para el PIC16x54 que me hiciera la conversión de binario (16-bits) a BCD. Hay muchas en el web pero para PICs más caros y poderosos que usan la instrucción SUBLW ... que el 16x54 carece. Asi que cambie un poco su implementación. Les dejo aqui la rutina en Ensamblador probada en MPLAB X. y espero sus comentarios.

Código:
;****************************************************
;                                                   *
;    Filename:	    ShiftAdd3.asm                   *
;    Date:          Octubre 14,2015                 *
;    File Version:  1.0                             *
;                                                   *
;    Author:	    David Sanchez                   *
;    Company:       David Sanchez                   *
;                                                   * 
;                                                   *
;****************************************************
;    Implementado para el PIC16x54                  *
; Toma un número binario de 16-bit y lo convierte en *
; 5 digitos BCD almacenados en forma consecutiva    *
;  MSB en la localidad más baja                     * 
;****************************************************

	list      p=16c54            ; directiva para definir el procesador
	#include <p16c5x.inc>        ; definición  de las variables specificas
                                 ; del procesador 

	__CONFIG   _CP_OFF & _WDT_OFF & _RC_OSC
;
;***** DEFINICION DE CONSTANTES
;
;***** DEFINICION DE VARIABLES RAM
temp      EQU 0x07   ; variable de trabajo
binH      EQU 0x08   ;número binario a convertir - high byte
binL      EQU 0x09   ;número binario a convertir - low byte
PackBCD_x_4      EQU 0x10   ;resultado en packed BCD - digitos altos
PackBCD_3_2      EQU 0x12   ;resultado en packed BCD - digitos de enmedio
PackBCD_1_0      EQU 0x14   ;resultado en packed BCD - digitos bajos
counter   EQU 0x0A   ;High nible of PackBCD_x_4  - variable de trabajo
BCD_1     EQU 0x13   ;UnPackBCD
BCD_3     EQU 0x11   ;UnPackBCD
;
;***** Macros
;
; Programa principal 
;*****
	ORG     0x000
;
start
; Escribimos valor que deseamos convertir 3AF3=15091  
    movlw   0xF3
    movwf   binL
    movlw   0x3A
    movwf   binH
	    
; Inicia la converción Binario a BCD con el algorithmo shift-Add3     
  ; Limpia los registros BCD     
     clrf   PackBCD_1_0     
     clrf   PackBCD_3_2     
     clrf   PackBCD_x_4
     clrf   BCD_1
     clrf   BCD_3
  
     ; loop por 15 rotaciones con la corrección "add 3"     
     movlw    .15     
     movwf    counter    
     ; convierte binario  (16 bits) a BCD packed     
Bin2Bcd_Loop     
     bcf        STATUS, C     ; preparamos carry flag para RLF   
     ; Rotamos todos a la izquierda     
     rlf        binL, F     
     rlf        binH, F     
     rlf        PackBCD_1_0, F     
     rlf        PackBCD_3_2, F     
     rlf        PackBCD_x_4, F     
     ; Prueba los digitos BCD que tengan un valor binario >= 5     
     ;  - Si son >=5 add3     
Test_Digit_0
     movlw   0x04
     movwf   temp
     movlw   0x0f     
     andwf   PackBCD_1_0, W
;     sublw    0x04
     subwf   temp, w 
      ;
     btfsc   STATUS, C
     goto    Test_Digit_1      ; digito 0 < 5
     ; Add3 a digito 0
     movlw   0x03
     addwf   PackBCD_1_0, F    ;  Nunca hay un acarreo de digitos
Test_Digit_1
     movlw   0x40
     movwf   temp
     movlw   0xf0
     andwf   PackBCD_1_0, W
     ; sublw   0x40
     subwf   temp, w
     btfsc   STATUS, C
     goto    Test_Digit_2      ; digito 1 < 5
     ; Add3 a digito 1
     movlw   0x30
     addwf   PackBCD_1_0, F
Test_Digit_2
     movlw   0x04
     movwf   temp
     movlw   0x0f
     andwf   PackBCD_3_2, W
     ;sublw   0x04
     subwf   temp, w
     btfsc   STATUS, C
     goto    Test_Digit_3      ; digito 2 < 5
     ; Add3 a digito 2
     movlw   0x03
     addwf   PackBCD_3_2, F    ; Nunca hay un acarreo de digitos
Test_Digit_3
     movlw   0x40
     movwf   temp
     movlw   0xf0     
     andwf   PackBCD_3_2, W
     ;sublw   0x40
     subwf   temp, w
     btfsc   STATUS, C
     goto    Test_Digit_4     ; digito 3 < 5
     ; Add3 a digito 3
     movlw   0x30
     addwf   PackBCD_3_2, F
Test_Digit_4
     movlw   0x40
     movwf   temp
     movlw   0x0f
     andwf   PackBCD_x_4, W
     ;sublw   0x40
     subwf   temp, w
     btfsc   STATUS, C
     goto    Test_Digits_End   ; digito 4 < 5
     ; Add3 a digito 4
     movlw   0x03
     addwf   PackBCD_x_4, F    ; Nunca hay un acarreo de digitos
Test_Digits_End
     decfsz  counter, F
     goto    Bin2Bcd_Loop
     ; Ultima rotación (16th) sin adiciones correctivas
     bcf     STATUS, C        ; preparamos carry flag para RLF
     ; Rotamos todos a la izquierda
     rlf     binL, F
     rlf     binH, F
     rlf     PackBCD_1_0, F
     rlf     PackBCD_3_2, F
     rlf     PackBCD_x_4, F
     ; la converción ha terminado
     movlw    0x0f                ; limpiamos los nibble no usados
     andwf    PackBCD_x_4, F
 ;
 ; * Ahora ya tenemos los 5 digitos BCD pero agrupados
 ; *  Si es necesario procedemos a desagruparlos
 ;
 ; Unpack los digitos BCD
     swapf   PackBCD_1_0, W        ; extrae digito 1
     andlw   0x0f
     movwf   BCD_1
     swapf   PackBCD_3_2, W        ; extrae digito 3
     andlw   0x0f
     movwf   BCD_3
     ; limpia los high nibles en BCD_0 y BCD_2
     movlw   0x0f
     andwf   PackBCD_1_0, F
     andwf   PackBCD_3_2, F
 ;
halt_loop     
     nop     
     goto    halt_loop         
 	
; ***** Reset
	ORG     0x1FF       ; processor reset vector
	goto    start

	END
 

Adjuntos

  • ShiftAdd3 para 16-bit.asm.txt
    5.3 KB · Visitas: 11
Leyendo "MANUAL DE MICROCONTROLADORES PIC" que consegui en la web, como no trae otra referencia mas alla del titulo no puedo darle el reconocimiento que se merece el author, me encontre con esta muy eficiente rutina de Shift-Add3 para la conversion de números binarios a BCD. Ya la probe y trabaja muy bien y usa solo 47 localidades de la memoria del programa. Usa direccionamiento indirecto en una forma muy eficiente.

Aqui les dejo la rutina con mis comentarios añadidos
Código:
;****************************************************
;                                                   *
;    Filename:	    ShiftAdd3.asm                   *
;    Date:          Octubre 24,2015                 *
;    File Version:  1.1                             *
;                                                   *
;    Author:	    David Sanchez                   *
;    Company:       David Sanchez                   *
;                                                   * 
;                                                   *
;****************************************************
;                                                   *
;  Convierte número binario 16-bits a 5 digitos BCD *
;     Usando la técnica de Desplaza-Suma3           *
;****************************************************

	list      p=16c54             ; directiva para definir el procesador
	#include <p16c5x.inc>         ; definición  de las variables especificas
                                      ; del procesador 

	__CONFIG   _CP_OFF & _WDT_OFF & _RC_OSC
;
;***** DEFINICION DE CONSTANTES
;
#DEFINE ZERO  STATUS,2   ; Bit de zero
#Define Carry STATUS,0   ; Bit de carry
;
;***** DEFINICION DE VARIABLES RAM
temp      EQU 0x07   ; variable de trabajo
binH      EQU 0x08   ;número binario a convertir - high byte
binL      EQU 0x09   ;número binario a convertir - low byte
counter   EQU 0x0A   ; contador de número de bits (shifts) procesados
BCD_x_5   EQU 0x0B   ;resultado en packed BCD - digitos altos
BCD_4     EQU 0x0C   ;UnPackBCD - digito 4
BCD_4_3   EQU 0x0D   ;resultado en packed BCD - digitos de enmedio
BCD_2     EQU 0x0E   ;UnPackBCD - digito 2
BCD_2_1   EQU 0x0F   ;resultado en packed BCD - digitos bajos

; Programa principal 
; ***** Reset
	ORG     0x1FF       ; processor reset vector
	goto    start

	ORG     0x000
;
Main
  goto start

;
; --- subrutina B2_BCD
; Inicia la converción Binario a BCD con el algorithmo Desplaza-Suma3     
   ; loop por 15 rotaciones con la corrección "Suma 3"     

B2_BCD
    bcf Carry       ;Prepara carry a zero
    movlw .16       ; número de bits = 16
    movwf counter 
    clrf BCD_x_5    ; limpia registros
    clrf BCD_4_3    ; donde almacenamos
    clrf BCD_2_1    ; la conversión
    clrf BCD_2
    clrf BCD_4
    
    ;
Loop16
    rlf binL      ; desplaza todos los registros
    rlf binH      ; una vez a la izquierda
    rlf BCD_2_1   ; aqui el orden es importante
    rlf BCD_4_3   ; por el ajuste del bit Carry
    rlf BCD_x_5
;
    decfsz counter  ; Hemos terminado la conversion?
    goto adjDEC     ;    No:  asi que continua procesando
    retlw 0         ;    Si: ya terminamos asi que salte de la rutina
;
adjDEC
    movlw BCD_2_1   ; apunta a los digitos de menor peso
    movwf FSR      
    call adjBCD     ; y ajustalos
;
    movlw BCD_4_3   ; ahora los siguientes dos digitos 
    movwf FSR
    call adjBCD     ; y ajustalos
;
    movlw BCD_x_5   ; por último los 2 de mayor peso
    movwf FSR
    call adjBCD     ; y ajustalos
;
    goto Loop16
;
adjBCD
    movlw 3         ; Suma 3 al Low-nibble
    addwf 0,W       ;  w = reg_x_y + 3
    movwf temp      ;  y prueba el Low-nibble
    btfsc temp,3    ;   si es mayor a 7
    movwf 0         ;     Si: necesitamos ajustar el high-nibble 
	            ;        vuelve a leer reg_x_y  y
    movlw 30        ;     No: Suma 3 al High-nibble
    addwf 0,W       ;  w = reg_x_y + 30
    movwf temp      ;  y prueba el High-nibble
    btfsc temp,7    ; si es mayor a 7
    movwf 0         ;    Si: Suma 3 a reg_x_y
    retlw 0         ;    No: terminamos los ajustes asi que Regresa con w=0


start
; Escribimos valor que deseamos convertir 3AF3=15091  
    movlw   0xF3
    movwf   binL
    movlw   0x3A
    movwf   binH
    call    B2_BCD
   
     ; la converción ha terminado     
     movlw    0x0f                ; Ajusta a zero el High-nibble     
     andwf    BCD_x_5, F      ;  ya que no lo usamos
 ; * Ahora ya tenemos los 5 digitos BCD pero agrupados     
 ; *  Si es necesario procedemos a desagrurarlos     
 
 ; Unpack los digitos BCD     
     swapf   BCD_2_1, W        ; extrae digito 2     
     andlw   0x0f     
     movwf   BCD_2     
     swapf   BCD_4_3, W        ; extrae digito 4     
     andlw   0x0f     
     movwf   BCD_4     
     ; limpia los high nibles en BCD_2_1 y BCD_4_3     
     movlw   0x0f     
     andwf   BCD_2_1, F     
     andwf   BCD_4_3, F
 
     
	END
 

Adjuntos

  • Improved ShiftAdd3 para 16-bit.asm.txt
    4.4 KB · Visitas: 14
Última edición:
Hola a todos los amigos del foro soy nuevo en el foro y vengo a dejar mi primera aportación
es un material para programar y aprenderse las 35 instrucciones del PIC16F84A con ejemplos prácticos y explicados uno a uno ya se que hay mucha información acerca de esto pero nunca esta demás tener algo extra :LOL:

También les recomiendo el libro ¨ "Microcontrolador PIC16F84 Desarrollo de proyectos"
espero que le sea de ayuda a los que incursionan en este maravilloso mundo de los PIC un saludo al usuario META My respect for you
:cool:
 

Adjuntos

  • Tutorial_Programación_de_PICs_en_Ensamblador.rar
    118.1 KB · Visitas: 67
Hola, hace mucho no ando por aqui y veo que han cambiado algunas cosas :oops:.
Me esta complicando un programa en ASM y necesitaba asistencia de alguien con mas experiencia.
Adjunto el codigo y comento que el problema es que se cuelga la Interrupcion por TIMER1, funciona un par de veces y luego no reacciona mas.
No he podido encontrar la falla.
Algun almita caricativa que le de un vistaso y me oriente donde me equivoque ?
GRACIAS
 

Adjuntos

  • Control arranque.txt
    10.8 KB · Visitas: 5
Hola, hace mucho no ando por aqui y veo que han cambiado algunas cosas :oops:.
Me esta complicando un programa en ASM y necesitaba asistencia de alguien con mas experiencia.
Adjunto el codigo y comento que el problema es que se cuelga la Interrupcion por TIMER1, funciona un par de veces y luego no reacciona mas.
No he podido encontrar la falla.
Algun almita caricativa que le de un vistaso y me oriente donde me equivoque ?
GRACIAS
Hola, te acomodo el código para que sea más facil de acceder.

Código:
;            CONTROL DE ARRANQUE Y FUNCIONAMIENTO DE GENERADOR HOGAR OBRERO           
;08/09/2022  CAMBIO EN LA INT CONTROL DE ACEITE POR CONTROL DE CONTACTO funciono bien el timer1
;pongo la cantidad de horas calculadas
;cambio el config con _XT_OSC
;10/09/2022  Prueba Conta2 = 1=1.4 min ; 10=16.40 min; 36=1 hora
;Dias 10=
;
    List    p=16F877A        ;Tipo de procesador
    include    "P16F877A.INC"    ;Definiciones de registros internos

    __CONFIG    _CP_OFF & _PWRTE_ON & _XT_OSC & _WDT_ON & _LVP_OFF & _BODEN_ON

cblock    0x20
    Delay        ;Variable de temporización
    Conta1        ;Para usar en TIMER1
    Conta2        ;Para usar en TIMER1
    Conta3        ;Para usar en temporizadores largos TIMER0
    Dias        ;Para usar en TIMER1
    Reintentos    ;
    Vigilia        ;
    MarchaMin    ;

endc

        org    0x00        ;Vector de Reset
        goto    Inicio
        
        
        org    0x04
        goto Int_TMR1

Inicio
;Esta configuracion me setea PORTD 0-1-2-3 como entradas digitales
;PORTD 4-5-6-7 mas PORTC 3-4-5-6-7 como salidas.
;Tambien prepara el prescaler para TIMER0
;Prepara los ADCs que se usaran en AN0, AN1 , AN2 , AN4 , AN5 , AN6 , AN7
;COMANDOS DEL LCD por puerto C
        bsf        STATUS,RP0    ;Selecciona banco 1
        bcf        STATUS,RP1    ;
                ;Configuracion de puertos
        movlw    0xFF        ;Puerto A y E se deben tomar como entradas setear en 1
        movwf    TRISA        ;
        movlw    0x07        ;
        movwf    TRISE        ;
        movlw    b'00001111'    ;Puerto D la parte baja va como entrada seteado en 1 y
        movwf    TRISD        ;la parte alta como salida seteada en 0
        movlw    0x00        ;
        movwf    TRISB        ;
        movwf    TRISC        ;
                        ;Configuracion del ADC
        movlw    b'10000001'    ;Justificación dcha 1,Seleccion de Clock 0,No usados 00
        movwf    ADCON1    ;(Todas Analogicas RA3/AN3/Vref+/Pin5) 0001
                    ;Si voy a usar RA o RE como Digital debo configurarlo en
                    ;el momento con "b'00000110' en ADCON1" y dps volver aqui
        bsf        PIE1,ADIE    ;Activa interrupción del convertidor ADC
                        ;Configuracion del TIMER
        movlw    b'10000111'    ;
        movwf    OPTION_REG    ;Preescaler de 256 asociado al TMR0
                        ;Configuracion del TIMER1 con interrupcion
        bsf        PIE1,0        ;Habilita el TIMER1
        
        bcf        STATUS,RP0    ;Selecciona banco 0
        clrf    PORTB        ;Limpia las salidas
        clrf    PORTC        ;
        clrf    PORTD        ;
                        ;Completo configuracion del TIMER1 con interrupcion
        bsf        T1CON,5        ;
        bsf        T1CON,4        ;Elijo Prescaler de 8 (maximo)
        bcf        T1CON,1        ;TIMER1 como temporizador con reloj interno (Fosc/4)
        bsf        T1CON,0        ;Baja la bandera de desborede del TIMER1
        bsf        INTCON,7    ;Habilita interrupciones globales
        bsf        INTCON,6    ;Habilita interrupciones perifericas
        bcf        PIR1,0        ;pone a cero la bandera de desborde del TIMER1
                ;Calculo de tiempo de interrupcion del TIMER1
        ;TMR1 = 65535-((Tiempo deseado (mS) * Fosc (KHz))/(Prescaler * 4))- 1
        ;53034 = 65535-((100*4000)/(8*4))-1 =0xCF24  Son 100mS
        movlw    0x0B
        movwf    TMR1H        ;Cargo parte alta del TIMER1
        movlw    0xDA       
        movwf    TMR1L        ;Cargo parte baja del TIMER1
        movlw    .200        ;Los valores utilizados en este programa estan mal
        movwf    Conta1        ;calculados por eso hubo que ajustar algunas repeticiones
        movlw    .1        ;Se deberia de haber usado 0xCF24
        movwf    Conta2        ; = 1 hora
        movlw    .1            ;Cargo la cantidad de hora del intervalo
        movwf    Dias        ;120hs / 24hs = 5 dias

;----------------------------------------------------------------------------------
Control
            clrwdt            ;Restaura/Limpia el WDT
        bcf        PORTD,4        ;Aseguro contacto desconectado
         bsf        PORTC,3        ;Conecto rele entrada se enclava con el de salida

        btfss    PORTD,1        ;Abrio detector de entrada?
        goto    Control        ;No, vuelvo a controlar
        call    Retardo1s    ;Si, hago un retardo de 1 segundo
        
        btfss    PORTD,1        ;Vuelvo a preguntar para confirmar
        goto    Control        ;No, Falsa alarma, vuelvo a controlar
        
        movlw    .3            ;Si, cargo Reintentos de arranque
        movwf    Reintentos    ;
Encendido
        movlw    .3            ;Cargo Vigilia que repite la espera a que se estabilice
        movwf    Vigilia        ;

        decfsz    Reintentos    ;decremento Reintentos y pregunto si llego a 0
        goto    Arranque    ;No, voy a Arranque
        goto    Alarma        ;Si voy a Alarma

Arranque
        bsf        PORTD,4        ;Conecto contacto
        call    Retardo1s    ;Espera 1 segundo antes de iniciar el arranque   
        bsf        PORTC,4        ;Acciono burro
        bsf        PORTC,5        ;Acciono cebador
        bcf        PORTC,3        ;Desconecto rele entrada se enclava con el de salida
        call    Retardo3s    ;Funciona burro y cebador 3 segundos
        bcf        PORTC,4        ;Apago burro
        bcf        PORTC,5        ;Apago cebador

Estabilizacion
        call    Retardo3s    ;Espera 3 segundos a que se estabilice
        btfss    PORTD,0        ;Controlo si tengo salida
        goto    Espera        ;No, no tengo salida, voy a Espera               
        btfss    PORTD,0        ;Si, tengo salida, Controlo de nuevo
        goto    Alarma        ;No, voy a alarma
        goto    Marcha        ;Si, tengo salida voy a la rutina de marcha

Espera
        decfsz    Vigilia            ;Decrementos Vigilia
        goto    Estabilizacion    ;No llego a Cero, Vuelvo a Estabilizacion
        goto    Encendido        ;Si, llego a Cero y no levanto presion de aceite

Marcha
        bsf        PORTC,6        ;Conecto rele salida que esta enclavado con el rele
                            ;de entrada e inicio bucle de marcha

Bucle10m
        movlw    .10            ;recargo marcha minima
        movwf    MarchaMin    ;

Marcha_Min
        call    Retardo1m    ;hago un retardo de 1 minuto que repetire 10 veces
        btfss    PORTD,0        ;Controlo si tengo salida
        goto    Alarma        ;No tengo salida
        decfsz    MarchaMin    ;Si, hay salida, decremento marcha minima
        goto    Marcha_Min    ;aun no agoto marcha minima

        btfsc    PORTD,1        ;Agoto bucle de marcha. Cerro detector de entrada?           
        goto    Bucle10m    ;No, recargo marcha minima y le doy otros 10 minutos
        goto    Detener        ;Si, voy a detener el generador y restaurar el sistema

Detener
        bcf        PORTD,4        ;Apago generador Desconecto contacto
        call    Retardo1s    ;Espera 1 segundo antes de iniciar transferencia
        bcf        PORTC,6        ;desconecto rele salida me habilita rele de entrada
        bcf        PORTC,4        ;aseguro burro apagado
        bcf        PORTC,5        ;aseguro cebador apagado
        bsf        PORTC,3        ;reconecto rele entrada me inhabilita rele de salida
        goto    Control        ;reinicio control de estado

;;---------------------------------------------------------------------------------
Alarma
        bcf        PORTD,4        ;Apago generador Desconecto contacto
        call    Retardo1s    ;Espera 1 segundo antes de iniciar transferencia
        bsf        PORTC,3        ;reconecto rele entrada
        bcf        PORTD,7        ;Apago aviso de prueba
        bcf        PORTC,6        ;desconecto rele salida
        bcf        PORTC,4        ;aseguro burro apagado
        bcf        PORTC,5        ;aseguro cebador apagado
         bsf        PORTC,7        ;conecto alarma audible
        call    Retardo1m    ;hago un retardo de 1 minuto
        bcf        PORTC,7        ;desconecto alarma audible
        goto    Control        ;       

;----------------------------------------------------------------------------------
;Temporizar 1/2 segundo mediante el TMR0. Este, con un preescaler de 256, evoluciona cada
;256uS. Se carga con 158 para realizar una temporización de 25mS. Los 50 mS se repiten 40
;veces para conseguir un segundo aproximadamente.
Retardo1s                        ; 1 segundo
        movlw    .40
        movwf    Delay
Delay_1        movlw    .158
        movwf    TMR0        ;Inicia el TMR0
        bcf        INTCON,T0IF    ;Restaura el flag del TMR0
Delay_2        clrwdt                ;Restaura/Limpia el WDT
        btfss    INTCON,T0IF    ;Han pasado 50 mS ??
        goto    Delay_2        ;Todavía no
        decfsz    Delay,F        ;Se ha repetido 10 veces ??
        goto    Delay_1        ;No
            return            ;Si, vuelve
;------------------------------------------------------------------------------
Retardo3s                    ; 3 segundos
        movlw    .255        ;SI BAJA BAJA EL TIEMPO 
        movwf    Delay
Delay_12    movlw    .210        ;Con 194 da 4 segundos. Con 210 da 3 segundos
        movwf    TMR0        ;Inicia el TMR0
        bcf        INTCON,T0IF    ;Restaura el flag del TMR0
Delay_22        clrwdt                ;Restaura/Limpia el WDT
        btfss    INTCON,T0IF    ;Han pasado 50 mS ??
        goto    Delay_22        ;Todavía no
        decfsz    Delay,F        ;Se ha repetido 100 veces ??
        goto    Delay_12        ;No
            return            ;Si, vuelve
;;--------------------------------------------------------------------
Retardo1m                ; 1 minuto
        movlw    .15            ;SI BAJA BAJA EL TIEMPO 
        movwf    Conta3        ;Con .255 aca aprox 70.75 min
Retardo3_1
        movlw    .255        ;SI BAJA BAJA EL TIEMPO
        movwf    Delay        ;
Delay_123    movlw    .195    ;Con .1 aca aprox 4 min. SI BAJA SUBE EL TIEMPO
        movwf    TMR0        ;Inicia el TMR0
        bcf        INTCON,T0IF    ;Restaura el flag del TMR0
Delay_223        clrwdt            ;Restaura/Limpia el WDT
        btfss    INTCON,T0IF    ;Cambio el Flag?
        goto    Delay_223    ;Todavía no
        decfsz    Delay,F        ;Se agoto el Delay ??
        goto    Delay_123    ;No

        decfsz    Conta3        ;Si,
        goto    Retardo3_1    ;
        RETURN

;----------------------------------------------------------------------
Int_TMR1
        clrwdt                ;Restaura/Limpia el WDT
Conta_1
        decf    Conta1,f    ;Decremento segundo contador y controlo
        btfsc    STATUS,Z    ;si desbordo mediante el Bit Z
        goto    Conta_2        ;Si voy a controlar el proximo contador,
        goto    Salgo1        ;No salgo recargando los valores para el TIMER
                            ;y los decrementados

Conta_2
        decf    Conta2,f    ;Decremento segundo contador y controlo
        btfsc    STATUS,Z    ;si desbordo mediante el Bit Z
        goto    Conta_3        ;Si voy a controlar el proximo contador, ya pasaron
                            ;Conta2 * Conta1 * interrupciones
        goto    Salgo2        ;No salgo recargando los valores para el TIMER
                            ;y los decrementados

Conta_3
        decf    Dias,f        ;Decremento segundo contador y controlo
        btfsc    STATUS,Z    ;si desbordo mediante el Bit Z
        goto    Fin            ;Si voy a controlar el proximo contador, ya pasaron
                            ;Dias * Conta2 * Conta1 * interrupciones
        goto    Salgo3        ;No salgo recargando los valores para el TIMER
                            ;y los decrementados


Salgo1
        bcf        PIR1,0        ;pone a cero la bandera de desborde del TIMER1
    ;Recargo los valores del TIMER1
        movlw    0x0B
        movwf    TMR1H        ;Cargo parte alta del TIMER1
        movlw    0xDA       
        movwf    TMR1L        ;Cargo parte baja del TIMER1
Ret_int       
        RETFIE
Salgo2
        movlw    .200        ;
        movwf    Conta1        ;Recargo el Conta1
        goto    Salgo1        ;

Salgo3
        movlw    .1            ;
        movwf    Conta2        ;Recargo el Conta2
        goto    Salgo2        ;
Fin
        movlw    .1    ;
        movwf    Dias        ;Recargo Dias

Pru_Func
        btfsc    PORTD,0        ;Mira si esta activo el PORTD,0 Hay señal de salida?
        goto    Ret_int        ;Si esta conectado esta en marcha NO HACE FALTA PRUEBA
                            ;Retorno de la Interrupcion sin hacer nada
        bsf        PORTD,7        ;No continuo en la interrupcion Aviso de Prueba

        movlw    .3            ;Cargo Reintentos de arranque
        movwf    Reintentos     ;

Arranque_2
        bsf        PORTD,4        ;Conecto contacto
        bsf        PORTC,4        ;Acciono burro
        bsf        PORTC,5        ;Acciono cebador
        call    Retardo3s    ;Funciona burro y cebador 3 segundos
        bcf        PORTC,4        ;Apago burro
        bcf        PORTC,5        ;Apago cebador

        call    Retardo3s    ;Espera 3 segundos a que se estabilice
        btfss    PORTD,0        ;Controlo si tengo salida
        goto    Espera_2    ;No, no tengo salida, voy a Espera_2
        call    Retardo1m    ;Si, tengo salida, fubciona 1 minuto
        bcf        PORTD,4        ;Apago generador Desconecto contacto
        bcf        PORTD,7        ;Desconecto aviso de prueba

        goto    Salgo3        ;Prueba terminada, salgo de la interrupcion

Espera_2
        decfsz    Reintentos    ;Decrementos Reintentos
        goto    Arranque_2    ;No llego a Cero, Vuelvo a Arranque_2
        goto    Alarma        ;Si, llego a Cero y no levanto presion de aceite
        
;-------------------------------------------------------------------------
            end

¿Estás seguro de que el problema es el Timer1 y no el WTD?¿Has probado desabilitar el WTD para ver si funciona todo correctamente?

No revisé el código en su totalidad porque es muy largo y me tendría que poner a indentarlo para tratar de entenderlo, pero mi consejo es que, si no podés debugearlo en el simulador, trates de aislar el problema anulando de a partes el programa hasta encontrar adónde está la falla.

PD: Tenés comentado que T1CON,0 es la bandera de desborde del Timer1, cuando en realidad es el encendido del mismo. No te va a afectar al funcionamiento del programa, pero te puede confundir.
 
Hola, ya hice un monton de pruebas y nada. Voy a comenzar con una lista de variaciones para poder descartar prolijamente.
El resto del programa funciona correctamente, ya lo probe y no tuve inconvenientes.
En algun momento le anule el WDT , por eso figura que lo refresco en algunos lados, pero no di con la solucion.

Continuare hasta la victoria !!!!!!!
 
Hola, hace mucho no ando por aqui y veo que han cambiado algunas cosas :oops:.
Me esta complicando un programa en ASM y necesitaba asistencia de alguien con mas experiencia.
Adjunto el codigo y comento que el problema es que se cuelga la Interrupcion por TIMER1, funciona un par de veces y luego no reacciona mas.
No he podido encontrar la falla.
Algun almita caricativa que le de un vistaso y me oriente donde me equivoque ?
GRACIAS
Independientemente de la causa de su problema, le sugiero que escriba TODA la rutina de interrupción en el BANCO 0 de memoria y para retornar bien , se asegure que lo hace al BANCO CORRECTO controlando el BANCO de SALTO correcto constantemente durante el programa. Es tediosos pero vale la pena hacerlo para no llorar.

Cuando ocurre que se cuelga con una interrupción es porque no se vuelve, porque la condición no se ha dado, o se vuelve al banco INCORRECTO, por mal control de las variables , a las que está sujeta. 👇Tambien por desbordamiento de la PILA DEL PC- STACK ( ese chip tiene solo 3)

------------------------------------------------------------------------------------------
org 0x00 ;Vector de Reset
goto Inicio


org 0x04
goto Int_TMR1 <- QUITE ESTA LINEA y escriba la rutina de interrupción justo debajo
-----------------------------------------------------------------------------------------

Int_TMR1
clrwdt ;Restaura/Limpia el WDT
Conta_1
decf Conta1,f ;Decremento segundo contador y controlo
btfsc STATUS,Z ;si desbordo mediante el Bit Z
goto Conta_2 ;Si voy a controlar el proximo contador,
goto Salgo1 ;No salgo recargando los valores para el TIMER
;y los decrementados

Conta_2
decf Conta2,f ;Decremento segundo contador y controlo
btfsc STATUS,Z ;si desbordo mediante el Bit Z
goto Conta_3 ;Si voy a controlar el proximo contador, ya pasaron
;Conta2 * Conta1 * interrupciones
goto Salgo2 ;No salgo recargando los valores para el TIMER
;y los decrementados

Conta_3
decf Dias,f ;Decremento segundo contador y controlo
btfsc STATUS,Z ;si desbordo mediante el Bit Z
goto Fin ;Si voy a controlar el proximo contador, ya pasaron
;Dias * Conta2 * Conta1 * interrupciones
goto Salgo3 ;No salgo recargando los valores para el TIMER
;y los decrementados


Salgo1
bcf PIR1,0 ;pone a cero la bandera de desborde del TIMER1
;Recargo los valores del TIMER1
movlw 0x0B
movwf TMR1H ;Cargo parte alta del TIMER1
movlw 0xA
movwf TMR1L ;Cargo parte baja del TIMER1
Ret_int
RETFIE
---------------------------------------------------------------------------------------

Hola, ya hice un monton de pruebas y nada. Voy a comenzar con una lista de variaciones para poder descartar prolijamente.
El resto del programa funciona correctamente, ya lo probe y no tuve inconvenientes.
En algun momento le anule el WDT , por eso figura que lo refresco en algunos lados, pero no di con la solucion.

Continuare hasta la victoria !!!!!!!
Use el MODO TRACE y va a encontrar el problema, tiene que poner puntos de stop en el programa para debugearlo y asi ver que es lo que está mal para retornar.
 
Última edición:
Me faltó poner eso en mi respuesta anterior.

Vi varias modificaciones de variables sin llamar al banco correspondiente (banksel VARIABLE). Me ha pasado de solucionar errores raros simplemente agregando el llamado al banco en las variables.

Para no renegar, siempre hago los llamados antes de modificar una variable, por más que ya haya llamado al banco antes.
 
Bien, unmonje estoy probando lo que decis,

Use el MODO TRACE y va a encontrar el problema, tiene que poner puntos de stop en el programa para debugearlo y asi ver que es lo que está mal para retornar.
NO SE COMO :mad::mad:
Antes de ponerse a PROGRAMAR hay que aprender a usar los recursos del editor/compilador/emulador
EL emulador es quien le permite hacer esas COSAS.
No se apure porque aprender a usar la herramienta, me llevo varios meses.
Casi nada, si se compara el tiempo que le llevo a los creadores de la aplicación terminarla.

Al ponerse en MODO TRACE, se ejecuta un solo paso de programa a la vez y luego se continua con la siguiente instrucción, sea esta verdadera o falsa y sus resultado. Si hubo un salto, salta a la linea de programa correspondiente segun el procesador que usted usa.

Le estoy dado una pista de solución, pero la VIA de ese tren, la tiene que encontrar vuestro cerebro.
 
Última edición:
Antes de ponerse a PROGRAMAR hay que aprender a usar los recursos del editor/compilador/emulador
EL emulador es quien le permite hacer esas COSAS.
No se apure porque aprender a usar la herramienta, me llevo varios meses.
Casi nada, si se compara el tiempo que le llevo a los creadores de la aplicación terminarla.

Al ponerse en MODO TRACE, se ejecuta un solo paso de programa a la vez y luego se continua con la siguiente instrucción, sea esta verdadera o falsa y sus resultado. Si hubo un salto, salta a la linea de programa correspondiente segun el procesador que usted usa.

Le estoy dado una pista de solución, pero la VIA de ese tren, la tiene que encontrar vuestro cerebro.
Llevo un tiempo programando (no demasiado en verdad) y nunca tuve la ocasión o necesidad de usar una interrupcion por eso es que me esta costando, igual que me costo aprender todo lo anterior je je.
Me pondre a investigar para aprender un poco mas del emulador, lo suyo es un consejo muy apropiado.

Por ahora con las opiniones y pistas recibidas logre que funcione casi correctamente. Hice unas variaciones por mi cuenta, en vez de volver a Control vuelvo a inicio y asi hace casi lo que corresponde.
Y digo casi por que "algunas veces" al cumplir el ciclo del TIMER se saltea la rutina que debe cumplir y comienza de nuevo. El problema lo veo en Pru_Func
Ya lo voy a vencer 💪💪, solo es cuestion de aprender mas.
Gracias mil
 
Revisa bien el código. Me maree un poco pero en la rutina de interrupción, cuando saltas a "fin" chequeas "btfsc PORTD,0" si es 0 pasa a saltar a varios lados y de ahí se va al programa inicial, no llega a "salir" nunca de la interrupción y por salir me refiero a dar por terminada esa etapa.

Puede que ese no sea el problema pero ahí veo un error feo.

Resumido: Puede pasar a "Alarma" y de ahí se va a "Control" sin ver un "RETFIE" jamás.

Además, busca en internet y añade la rutina para salvar el registro "STATUS" y "W" al entrar a la interrupción, evitara que el programa se vuelva loco. Este puede ser el segundo problema.
 
Atrás
Arriba