Problema al programar microcontrolador PIC16F84

Iniciado por Fox_Neo, 27 Febrero 2013, 19:09 PM

0 Miembros y 1 Visitante están viendo este tema.

Fox_Neo

Buenas pues tengo un programa que tiene que hacer una suma una multiplicación y una resta (la función es : Y=2(A+B)-C), si el resultado me da correcto siempre y cuando no sea negativo el resultado, por ejemplo hago:Y=2(1+4)-6  me sale 4
pero si hago: Y=2(1+3)-10 me da 252  :o
aqui os dejo el código a ver si veis algo raro:
Código (mpasm) [Seleccionar]
list p=16F84 ;indicamos el pic que se vaa usar
include "P16F84.INC";indicamos la librería del PIC que tiene que cargar
REGA equ 0x11 ;Damos un nombre a esta posición de memoria REGISTRO A
REGB equ 0x12 ;Damos un nombre a esta posición de memoria REGISTRO B DE USUARIO
REGC equ 0x13 ;Damos un nombre a esta posición de memoria REGISTRO C DE USUARIO
REGY equ 0x14 ;Damos un nombre a esta posición de memoria REGISTRO DE USUARIO DE RESULTADO
REGAUX equ 0x15 ;Este registro lo vamos a usar para almacenar temporalmente resultados de pasos de operaciones intermedias
org 0x00 ;vector de reset
goto inicio
org 0x05 ;el programa empieza en la posición 5 de la memoria


        ;*********************
;INICIO DE PROGRAMA
        ;*********************
inicio MOVLW 0X01 ; Como no se puede cargar directamente un valor a una posición de memoria cualquiera, es necesario cargarlo previamente primero en el registro REGW
MOVWF REGA ;Ahora si se puede mover el valor de REGW a una posición de memoria deseada
MOVLW 0X02 ;Con  los siguientes pasa lo mismo
MOVWF REGB
MOVLW 0X0A
MOVWF REGC

;______________________________
BUCLE ; es necesario poner un bucle para que no finalice el programa el programa
;Suma de A+B
MOVF REGA,0 ;CARGA EL VALOR REGA EN W
ADDWF REGB,0 ;SUMA EL VALOR DE W + REGB Y COMO ES 0 SE GUARDA EN W
MOVWF REGAUX ;EL VALOR DE LA SUMA ESTÁ EN EL REGISTRO AUXILIAR como ahora vamos a necesitar usar el registro REGW lo movemos a una posicón de memoria temporal
;Multiplicación 2(A+B) ->(A+B)+(A+B)
ADDWF REGAUX,1 ;SUMA EL VALOR DE W + REGAUX Y COMO ES 0 SE GUARDA EN REGAUX. Como el valor de A+B ya lo teníamos en REGW  y tiene el mismo valor que el REGAUX si se suman ambos será como una multiplicación.
MOVF REGC,0 ;CARGA EL VALOR DE REGC EN W PARA PODER HACER LA RESTA  Y=REGAUX-C ya que la instrución hace la resta  en dirección contraria: F-W
;resta 2(A+B)-C
SUBWF REGAUX,0 ;REALIZA LA RESTA Y LO GUARDA EN W
MOVWF REGY ;CARGAMOS EL RESULTADO EN LA POSICIÓN REGY
GOTO BUCLE ; Devuelve a donde esté la palabra bucle
END ; fin de programa





Uso MPLAB para programarlo y simularlo.
Gracias

Fox_Neo[/size]

Firos

Cuantos bits tiene un registro? 8 bits.

2^8 = 256 (contando el 0 sería 255)


Si un registro tiene una cantidad de 2 y tu le restas 4 estará en 254 si no me equivoco.

Ese es el problema que tienes, realmente el programa esta actuando correctamente pero no interpretas bien los datos.

Cuando los datos son negativos (por debajo de 0) y quieres representarlo en decimal tendrías que complementarlo primero.

Ahí lo que estas haciendo primero es sumar 1+3 = 3 y lo guardas en un registro. Ahora sumas lo que hay en W que realmente es 3 y lo vuelves a sumar con lo que hay en el registro y te da 6. Por lo tanto si ahora le restas 10 tendras -4.

256-4=252

Ahora bien, cogemos el 252 y lo pasamos a binario. 11111100

Le damos la vuelta 00000011 y nos da un 3, le sumamos 1 y tenemos el cuatro que te da en ese resultado 00000100.

Esto es complementarlo a dos.


Ahora bien, ¿como saber cuando un resultado es negativo? tienes que comprobar el BIT C de el STATUS. Que cuando se pone a 1 quiere decir que el resultado es negativo.

Creo que el bit C no se pone a cero solo y no puedes editarlo metiendole un cero, pero si puedes hacerlo con la instrucción BCF (bit clear file).
El final del camino no está determinado, lo determinamos nosotros mismos paso a paso, día a día, y se puede cambiar.

Firos

#2
Cita de: Fox_Neo en 27 Febrero 2013, 19:09 PM

Código (mpasm) [Seleccionar]
list p=16F84
include "P16F84.INC"

REGA equ 0x11 ; REGISTRO A
REGB equ 0x12 ; REGISTRO B DE USUARIO
REGC equ 0x13 ; REGISTRO C DE USUARIO
REGAUX equ 0x15 ; REGISTRO TEMPORAL, AL FINAL CONTIENE EL RESULTADO.

org 0x00 ;vector de reset
goto inicio

org 0x05 ;el programa empieza en la posición 5 de la memoria

; Cargamos registros con los datos.
inicio MOVLW 0X01 ; Carga 01 en W.
MOVWF REGA ; Carga W en REGA
MOVLW 0X02
MOVWF REGB
MOVLW 0X0A
MOVWF REGC

;______________________________
BUCLE ;

MOVF REGA,W ; A+B
ADDWF REGB,W ;     "
MOVWF REGAUX ; A+B+A+B -> REGAUX
ADDWF REGAUX,F                 ;      "
MOVF REGC,W ;
SUBWF REGAUX,F ; REGAUX - REGC -> REGAUX
GOTO BUCLE ;

END




Por cierto, volviendo a ver tu código, te recomiendo que si vas a programar en ASM lo hagas lo mas simple posible o cuando empieces a programar con varios modulos (ADC, RS232, I2C, cualquier cosa) te vas a liar con todo.

Empezando por lo más básico, cuando quieras guardar un fichero en W te aconsejo que lo especifiques con W y no con 0, porque sino luego, no lo veras bien (cuando adquieras experiencia sera otra cosa), y lo mismo cuando quieras guardarlo en un mismo fichero.

Por otro lado, consejos. Optimización, cuanto más pequeño sea el programa mejor. Los microchips tienen mucha memoria, pero cuando hagas programas largos una buena optimización es lo mejor, sobre todo cuando usas tablas para sacar caracteres de frases y trabajas sumandole W a PCL, que en un cambio de página puede significar que el programa no te funcione.

Refiriendome a la Optimización: ¿Realmente te hacen falta tantos registros? Te he eliminado el registro final, el registro temporal sera quien lleve el resultado en ultimo momento.

Acostumbrate a mantenerlo siempre lo mas ordenador posible, o no te aclararás ni tu mismo. Te lo digo por pura experiencia.



Un saludo.
El final del camino no está determinado, lo determinamos nosotros mismos paso a paso, día a día, y se puede cambiar.

Fox_Neo

Muchas gracias por las respuestas Estamos empezando a programar en ensamblador en la asignatura de Sistemas basados en microprocesadores de la  carrera de industrial de electrónica. Umm algo intuí al dia siguiente de poner mi duda que podría ser lo que me pusiste que como era 256 bits y me daba 252 era la resta de 256-4. ¿Estás seguro de que si da 1 es negativo? . Para comprobarlo hice una operación en la cual me diera  252 y el registro STATUS me daba:00011011 como el último bit es 1 signigica que la operación ha dado  positivo.

Con el -4 el registro SATUS me da 00011000 como el primer bit es 0 la operación es negativa.


Respecto a lo de  guardar un fichero en W especificarlo  con w en vez de 0 o 1 ¿Te refieres a dejarlo como una variable y luego cargar en el registro w 1 o 0? porque si no no entiendo por ejemplo en REGA,W como se le da la orden de guardarlo en el registro W o en REGA

Muchas graciasa por la ayuda esta es mi segunda práctica y estoy practicando por mi cuenta, también estoy con la 3º practica que nos han mandado  y es algo liosa si veo que no me sale ya pediré ayuda, ya que veo que sabes programar en ASM. :) Gracias por los consejos

Firos

#4
Es simple compañero.

En las especificaciones de cada comando te suele poner los bits que se ven afectados del STATUS en caso de realizar una operación y la forma de el comando y su uso.


En el caso de hacer una ADDWF, SWAP, INCF, DECF o cualquier otro comando que te permita guardar en F o en W podras hacerlo de las dos maneras.

Por ejemplo, en el caso de el comando ADDWF:

Sintaxis:
ADDWF      f,d
Estados afectados: C, DC, Z

El contenido del registro W se suma al registro F. Si "d" es 0, el resultado se almacena en W; si "d" es 1, el resultado se guarda en el registro "f".


Al programar en MPLAB tienes que tener en cuenta que MPLAB interpretara ciertos comandos y los convertirá automaticamente sin problemas a lo que tendrían que ser realmente. Con esto quiero decir, que si tu en el comando de ADDWF pones:

ADDWF REGX,F -> Suma W con REGX y lo guarda en REGX.

seria lo mismo que poner:

ADDWF REGX,1

Solo que tu, en vez de ver un 1 ves una F y lo identificas mucho mejor.


Podrías hacer lo mismo con el registro W en vez de poner un 0.


La verdad es que de unos PICS a otros varían algunas cosas, pero en los datasheets de cada PIC esta todo. Veras los comandos y los estados afectados al terminar la operación. Cuando termina la operación si ves un estado afectado tendrás que ver por qué ese estado se ve afectado. Es decir, cuando desborda, si rotas un registro con RRF y sale un 1 que se va al C, etc... pero a eso ya llegarás más adelante.

Por eso te digo que en el caso este, como estas realizando una resta, que posiblemente será inferior a 0, tienes que poner una comprobación después de la operación para ver si el estado que te identifica que es negativo está activo.

Termina de testearlo y me cuentas de nuevo. Haz sumas y mira los estados. Haz restas en las que el resultado sea positivo y mira los estados y haz lo mismo con resultados negativos.


Por cierto. Si trabajas normalmente con MPLAB no hace falta que estes cambiando constantemente los numeros dentro de el programa. En esa misma ventana de "File Registers" en la parte de abajo dale a HEX.


Configura los registros de REGX, REGA y tal en las posiciones que te interesen. Por ejemplo en la 30, 40 y el resultado en la 50.

Y hazlo todo con los registros, es decir, muevo el registro A a W, se lo resto a B y lo almaceno en W, luego lo meto en RESU. Algo asi:

list p=16f876, f=INHX8M, r=hex
include "p16f876.inc"

MINU equ 20
SUST equ 30
RESU equ 40

org 0

Inicio         movf SUST,W
subwf MINU,W
movwf RESU


goto Inicio

end



Con esto asi y con la ventana de FILE REGISTERS simplemente tendrás que indicar la cantidad en FILE REGISTERS, das doble click en el registro y pones la cantidad, simulas el programa paso a paso en MPLAB y vas viendo los estados afectados y en las casillas de los registros el resultado.


Por cierto, importante, asegurate también de revisar y borrar los estados afectados después de una operación, porque puede ser que lo siguiente que hagas también dependa de un estado despues de otra acción (aunque no es el caso) y que como esta afectado por la anterior, a lo mejor en esta no se ha visto afectado y te da error. Digamos que en la primera resta te da negativo, los estados se ven afectados y luego en la segunda resta no se ven afectados, como el estado no ha vuelto a su posición inicial el segundo resultado estará mal.


BITS Z, DC y C DE STATUS

Z: Se pone a 1 después de una operación aritmético lógica con resultado 0. Se queda en 0 cuando el resultado lógico es distinto de 0.

DC: Bit de acarreo o debe. Se pone a 1 cuando hay acarreo en el cuarto bit (este no lo usarás prácticamente).

C: Bit de acarreo o debe en las instrucciones ADDWF, ADDLW, SUBLW, SUBWF. Se pone a 1 cuando hay acarreo en el 8 bit.


¿Esto que quiere decir?

- Que en estas operaciones, o en cualquier programa que quieras detectar que es un 0 podrás hacerlo a través de el bit Z de el status con btfsc.

- Compruebas el carry que estará en 0., que se verá afectado después de realizar la resta y tendrás que hacer el "complemento a dos" sobre el resultado que te ha dado para sacar la cantidad exacta. Que es tu caso. Tenías razón. Al estar en 1 indica que es positivo, y al estar en 0 indica que es negativo.



Entonces, en el programa tendríamos que incluir esto:

list p=16f876, f=INHX8M, r=hex
include "p16f876.inc"

MINU equ 21
SUST equ 31
RESU equ 41
SIMB equ  40


org 0

Inicio bcf SIMB,0 ; Borramos indicador de símbolo, que estara en el bit 0 de SIMB.
movf SUST,W ; Movemos el sustraendo a W.
subwf MINU,W ; Restamos sustraendo a minuendo.
movwf RESU ; Guardamos resultado.

btfsc STATUS,C ; ¿Resultado negativo? ¿C=0?
goto Inicio ; No: Vuelve a inicio y hace otra operación.

bsf SIMB,0 ; Si: Incrementa la marca de el símbolo.
movlw b'11111111' ; Es lo mismo que poner 0xFF, la b indica binario.
xorwf RESU,F ; XOR entre F y W, guarda en RESU.
incf RESU,F ; Haciendo XOR con FF le damos la vuelta y sumándole 1 (incrementando 1 con este comando) para terminar el "Complemento a Dos".

goto Inicio ; Vuelve a inicio y hace otra operación.
end



Y, como vemos, he añadido el complemento a 2.


Si te da "11111100" hazle una operación XOR con FF.

11111100
11111111
-----------
00000011

Y le sumas 1, que te dará el cuatro :). No lo he comprobado, pero en teoría debería funcionar. Mañana lo miro, que ya es tarde.


Y ya... rizando el rizo, si sumas dos números que te den un resultado mayor a un byte tendrías que incrementar otro registro al lado de el resultado y... eso ya es otro capítulo.



Vaya testamento... me he liado bastante a escribir. Espero que te haya servido.

Suerte, cualquier duda ya sabes  :)

Un saludo.
El final del camino no está determinado, lo determinamos nosotros mismos paso a paso, día a día, y se puede cambiar.

Fox_Neo

Muchas gracias por las respuestas  y la explicación tan detallada ;D  ya hice la siguiente practica trataba de usar comparaciones y dependiendo de eso hacer una series de operaciones y que se repitieran  con un  bucle. Si me surgen más dudas ya las iré poniendo.
Gracias :)