Hola.
En el foro me he dado cuenta que casi nadie (si es que nadie) utiliza la instrucción
DIV32 que provee PBP desde la versión 2.42 (creo).
Esta instrucción nos sirve esencialmente para una cosa:
Dividir 31 bits entre 15 bits.Si se van al manual del PBP les muestra el acondicionamiento de esta.
Una breve explicación:
El compilador crea variables o registros propios para hacer operaciones. Si observamos, nos daremos cuenta que existen nombres de registros que no podemos usar (creo R0,R1...).
PBP realiza operaciones de multiplicación y división de 16X16 bits, dando como resultado una operación de 32 bits.
Sin embargo, no era posible accesar de golpe a esos 32 bits, necesitaba uno hacer dos multiplicaciones o divisiones para tomar los 16 de mayor peso (** o /) y los 16 de menor peso (* o //).
La DIV32 nos permite usar esos bits (31) y dividir el resultado entre una cantidad de 15 bits de un solo golpe.
La ventaja, desde mi punto de vista, es que podemos usar los 31 bits (2,147,483,647 en decimal) y realizar operaciones que requieran decimales o fracciones.
Cuando PBP hace cualquier operación, utiliza 4 registros para hacer una operación (multiplicar o dividir) y el resultado se almacena en esos registros.
Como estos registros se utilizan para otras cosas (las cuales no sé pero creo que para los tiempos y demas) el resultado de 31 bits desaparece para dar cabida a lo nuevo.
La DIV32 debe ser utilizada
inmediatamente después de la operación deseada (como lo marca el ejemplo en el manual de PBP) para aprovechar esos 31 bits.
Un ejemplo en concreto.
El FAMOSÍSIMO voltímetro con el AD del µicro.
Si tomamos el valor de cada bit para 10 bits sería= 5v/10bits= 5v/1024= 4.88 milivolts redondeando.
Sacamos su función de transferencia y nos daría algo como esto:
V(o) = 4.88 mV (AD en bits)Lo cual nos supone a nosotros que utilizaremos decimales........ pero PBP no lo puede hacer con decimales.
Qué sucede si metemos esa ecuación en PBP:
el 4.88 se convierte en 4 y nuestro cálculo será erroneo.
¿Pero qué sucede si le metemos 488?
Nosotros sabemos que es 4.88 pero PBP no lo sabe.
Si hacemos esto tendremos:
para AD = 0; V(o)=0
para AD = 1024; V(o)=499,712
499,712 por el redondeo utilizado no es 500,000 de los 5 volts. Perdemos presición.
499,712 es menor a 2,147,483,647; cumplimos con el requisito.
499,712 lo dividimos entre 10 y nos queda:
49,971 porque PBP no acepta decimales; lo dividimos entre 10 para que quepa dentro de los registros máximos de PBP que son 16 bits (word=65,535).
10 es menor a 32,768 que son los 15 bits en los cuales se puede dividir.
¿Qué cantidad es?
pues nosotros sabemos que es 4.9971 volts, perdemos 29 diesmilésimas de volt por el redondeo (lo cual es muuuuuy aceptable).
Este es un programa que siempre les pongo a los alumnos para utilizar el DIV32 con el AD ya que la mayoría de los proyectos usan transductores que proporcionan voltaje, corriente o resistividad.
'****************************************************************
'* Name : Convertidor A/D 10 bits con 4 decimales y contador *
'* en hardware de timer1.BAS *
'* Author : Mario Alberto Camarillo Ramos *
'* Date : 21/11/2005 *
'* Notes : Este es con 4 decimales. Se puede agregar más lí- *
'* neas de ADCIN alternando canales *
'****************************************************************
define OSC 20
DEFINE LCD_DREG PORTB
DEFINE LCD_DBIT 4
DEFINE LCD_RSREG PORTB
DEFINE LCD_RSBIT 1
DEFINE LCD_EREG PORTB
DEFINE LCD_EBIT 2
DEFINE LCD_BITS 4
DEFINE LCD_LINES 2
define NO_CLRWDT 1
Define ADC_BITS 10 ' Set number of bits in result
Define ADC_CLOCK 3 ' Set clock source (3=rc)
Define ADC_SAMPLEUS 50 ' Set sampling time in uS
adval var word ' Create adval to store result
adval1 var word ' para guardar la conversión ya con la fórmula
conejillo var byte ' para hacer trampa
TRISA = %11111111 ' Set PORTA to all input
ADCON1 = %10000010 ' Set PORTA analog and right justify result (para
' tomar todos los 10 bits; justificado a la izquierda
' solo se toman los 8 de mayor peso)
loop: ADCIN 0, adval ' Read channel 0 to adval
conejillo = 488 * adval ' multiplicamos para obtener 1024*488=499712;
' internamente el compilador usa 16x16 resultando
' en un valor de 31 bits de resolución
adval1 = DIV32 10 ' usamos div32 inmediatamente ya que se cuenta con
' el valor TOTAL DE 31 BITS, si no se hace así, el
' resultado de 32 bits se destruiría. De esta
' forma acomodamos para obtener 31 bits de resolu-
' ción ó 2,147,483,647 y dividimos /10 para mover
' el punto a 49971.2 descartando el 2 y quedándo--
' nos con 49971=4.9971 volts 49971 < 65535
Lcdout $FE,1, DEC adval1 dig 4,".", dec adval1 dig 3, dec adval1 dig 2, dec adval1 dig 1, dec adval1 dig 0
pause 2000
goto loop
End
Como ven, ADVAL1 tomará el valor de los cuatro registros (31 bits) divididos entre 10.
En este caso se presentan registros para cada operación, para efectos de explicación. Pero solo necesitamos uno solo (nos ahorramos RAM):
ADCIN 0, adval
adval = 488 * adval
adval = DIV32 10
Observen que inmediatamente después de 488*AD se utliza la DIV32, esto es porque si se hace cualquier otra operación, el resultado se destruye (el de los 31 bits).
El programa propuesto genera 404 palabras para un 16F877 (que es el que más usan por aquí en el foro).
Un voltímetro con 4 decimales con 404 palabras y con LCD y todo....... no está mal.
Von Newman dijo (creo) que un programador no necesita punto flotante porque sabe exactamente dónde está el punto en su cabeza............. yo no soy programador, si tuviera punto flotante lo usaría pero como no tengo, uso lo que pueda
.
Las rutinas de FP de Microchip son útiles y tengo entendido que si funcionan (¿navaismo?) pero creo que alguna vez las observé y requieren crear registros para decimales y enteros, sin mencionar el movedero que hacen para acomodar el punto.
Si navaismo puede compilar ese mismo programa (o el que sea
, no necesita ser navaismo) utilizando las FP de microchip para un 16F877 hágalo y comente los resultados.
Perdímos 29 diesmilésimas de volt en el cálculo por el redondeo inicial y porque tomamos 2 decimales solamente, ¿y si tomamos mas?.
Utilizando 4 decimales tenemos 4.8828 mV/bit
para el peor de los casos:
0; V(o)=0
1024; V(o)= 49,999,872
Dividimos entre 1000 (DIV32 1000)
49,999---> 4.9999 volts
49,999,872 < 2,147,483,647 y
1000 < 32768
Para 5 decimales--->4.88281
0; V(o)=0
1024; V(o)= 499,999,744
Dividimos entre 10,000 (DIV32 10000)
49,999.744---> 4.9999 volts.
Para mas decimales se pasa de 2,147,483,647.
Es muy buena esta herramienta para "sacarle la vuelta" a los decimales, no es propiamente punto flotante porque nosotros debemos saber dónde está el punto pero, ayuda
.
Solo necesitamos linealizar un transductor, o sacar su función de transferencia y listo.
Como vieron, 4 decimales es mas que suficiente de la ecuación original para obtener un resultado óptimo.
Imaginen un AD en ensamblador con 4 puntos decimales; yo ni lo pienso (corrimientos, BTFSS al Status........ y muchas cosas mas).
Bueno, navaismo, ahi está
.
PD: No estaré disponible la noche del Lunes y todo el Martes (tarea de maestria
y trabajo
).