# Fixed Point Arithmetic Methods (Using 32bit Integers)

Submitted by:

Glenn Clark
VersaTech Electronics

The programs and drawings shown below are taken from the examples section of the manual.

It is fairly common to deal with fractional results when designing controllers. This is a display or calculation restraint because the units of measure are directly dictated by the sensors in the controller. A controller with an LCD screen or other, more elaborate output capabilities should be able to present data in an expected format. The TICkit 62 does not have a floating point library in its current version, but it still can display numbers with fractional components.

The TICkit 62 has a signed LONG type number which is a 32 bit integer variable type. This size of integer can display 9 digits of accuracy. Assume we are dealing with numbers from our sensors which are no greater than 4096 ( 12 bit ). This number only requires 4 digits to represent its full range. If we use a LONG type to represent this number during calculation or display, we can scale the meaning of this number by as much as 100000. In other words, we define one as being 100000 and we display our numbers with a decimal point 5 places to the left. The number one will display as 1.00000 which is exactly what you expect.

The key to making this easy is the format versions of the long numeric output functions. There are three versions of this on the TICkit release disk. Function lcd_fmt() is for displaying formatted longs on an LCD, function con_fmt() is for displaying formatted longs on the debug console, and function rs_fmt() is for displaying formatted longs to an rs232 device. To make clear how these functions work and how they are used, a copy of the con_fmt function is shown below. The meanings of the format characters are explained in the source for the function.

```;Routine to output a Long Number to the LCD display (Signed)

; Meanings of format string characters
; '\$' print a \$; '.' print a .
; '#' print a number ( leading zeros will not be printed )
; '0' print a number ( leading zeros will print from this digit on )
; 'X' hold a place but to not print the number

FUNCTION none con_fmt
PARAM long in_data    ; Data to print
PARAM word pointer     ; Data format string
LOCAL long tempnum     ; Copy of print data
LOCAL word hpointer    ; Copy of string pointer
LOCAL long divisor 1l  ; Divisor , used by routine
LOCAL byte tempchr        ; Data hold variable
LOCAL byte first 0b    ; flags register
LOCAL byte tempdig     ; temporary digit
BEGIN
; this section counts the number of digits and determines what
; the most significant digit's divisor will be as a result.
=( tempnum, in_data )
=( hpointer, pointer ) ; Store format string start
WHILE tempchr
IF ==( tempchr, '#' )
=( divisor, *( divisor, 10b ))
ELSEIF ==( tempchr, '0' )
=( divisor, *( divisor, 10b ))
ELSEIF ==( tempchr, 'X' )
=( divisor, *( divisor, 10b ))
ENDIF

++( hpointer )
LOOP

; Check for negative: displays sign and
; make number positive for conversion
IF <( tempnum, 0b )
con_out_char( '-' )
=( tempnum, -( 0l, tempnum ))
ENDIF

; Check for overflow of number: If divisor too large,
; write an * to indicate
; Then do conversion on remaining modulus of divisor
IF >( /( tempnum, divisor ), 0b )
con_out_char(  '*' )
=( tempnum, %( tempnum, divisor ))
ENDIF```
```    ; Begin actual conversion and display loop here
=( divisor, /( divisor, 10b ))
=( hpointer, pointer )    ; Store format string start
WHILE >=( divisor, 1b )
IF ==( tempchr, '.' )
con_out_char( tempchr )
ELSEIF ==( tempchr, '\$' )
con_out_char( tempchr )
ELSEIF ==( tempchr, 'X' )
=( tempnum, %( tempnum, divisor ))
=( divisor, /( divisor, 10b ))
ELSEIF ==( tempchr, '0' )
=( tempdig, trunc_byte( /( tempnum, divisor )))
=( tempdig, +( tempdig, '0' ))
=( first, 0xffb )
con_out_char( tempdig )
=( tempnum, %( tempnum, divisor ))
=( divisor, /( divisor, 10b ))
ELSEIF ==( tempchr, '#' )
=( tempdig, trunc_byte( /( tempnum, divisor )))
=( tempdig, +( tempdig, '0' ))
IF <>( tempdig, '0' )
=( first, 0xffb )
ENDIF

IF first
con_out_char( tempdig )
ENDIF

=( tempnum, %( tempnum, divisor ))
=( divisor, /( divisor, 10b ))
ELSE
con_out_char( tempchr )
ENDIF

++( hpointer )
LOOP
ENDFUN```

A typical application for this sort of thing would be to display the output of a 12 bit ratio metric A/D reading in volts. Rather than show the whole program, only a fragment which relates to this discussion is shown. The variable ad_in is a word variable that contains the value read for an LTC1298 12 bit A/D in a 5 volt system. This means that 0 is 0 volts and 4095 is 5 volts and all values in between are assumed to be linearly related.

```    ; 12 bits can display three decimal points but needs 4 to
; completely hold the number. Therefore lets assign one to
; be the value 10000. To produce the number of volts from
; the value read we need to divide 5 times the reading by
; 4096.

GLOBAL long conv_result

=( conv_result, *( 50000, ad_in ))
=( conv_result, /( conv_result, 4096 ))
con_fmt( conv_result, "#.000X" )
con_string( " Volts" )```

Protean Logic Inc. Copyright 05/06/04         Top of Page