Performing   MATH
For Australians and English countries, substitute “MATHS” - (We don’t use the word Math!)


Page 11
INDEX

The PIC16F84 or PIC12c508A does not have an inbuilt math co-processor and it seems to have very few mathematical instructions in the instruction-set. 

So, how do you carry out mathematical operations?
Firstly, very few programs (at the level we are discussing) require mathematical operations but when one is required, there are a number of ways of carrying them out. 
In any program, there are different "levels" of mathematical complexity. Merely setting or clearing a bit can be considered as adding or subtracting from a file and rotating left or right is equivalent to multiplying or dividing. 
What we really mean about "Math" is adding, subtracting, multiplying, dividing, percentage, etc - all those features found on a $10.00 calculator. 
The '508A or F84 is not a calculator and very few programs require "calculator-type" operations. However, add, subtract, multiply and divide are available, once you know "how." 
For instance, multiplication can be performed with a series of additions and converting a value to another value can be achieved via a table - rather than using a mathematical equation. Thus a table can be equivalent to percentage or produce a result equal to dividing by 0.075 etc. 
The amount of program space required to produce a mathematical operation depends on the accuracy you require and how much room you can afford for the table or routine. 

Here are some of the ways to produce mathematical results: 

ADDITION and SUBTRACTION
One of the simplest mathematical operations is addition and subtraction. The '508A and F84 have instructions to INCrement or DECrement a file. This is simply "ADD one" or "SUBTRACT one" from a file. You cannot INCrement or DECrement the working register (W), so values have to be moved to a file for these operations to be performed.
On the other hand, you cannot ADD a number (literal) to a file so the number (01 to FF) is firstly put into W then the instruction ADDWF is performed. 
Two files can be added together by firstly loading one file into W (such as MOVF 0C,0 - where F is the first file) then implementing the instruction: ADDWF where F is the second file, such as 0D. Suppose file 0C contains 45h and 0D contains 83h.

The instructions are:

MOVF 0C,0  ;45h is moved into W
ADDWF 0D,0 ;the result is in W

or: 

MOVF 0C,0  ;45h is moved into W
ADDWF 0D,1 ;the result is put into file 0D

Two files can also be added together by decrementing one file and incrementing the other in a loop. The instruction DECFSZ is used to detect when one of the files is zero and the program comes out of the loop. The other file will contain the sum of the two values. 

The advantage of doing this is the incrementing file can be tested during each loop for a particular condition and the program can exit the loop before the two files are fully added, if required.

REMEMBER:
There are a few technical points you must know when incrementing or decrementing. 
A file incremented past FF "rolls over" to 00. If a file containing 00 is decremented, it "rolls over" to FF.
There are two ways to add a number (literal) to a file. 
1. by successive increments, and 
2. by adding a literal to W then ADDing W and the file together. 
It is better to increment a file by successive INC instructions, via a loop. It can be tested after each pass of the loop to see if it has reached a particular value.
To create a loop, a file is loaded with a value and decremented to zero. The instruction DECFSZ decrements the file and causes the program to go to one of two locations, when the file is zero. 
If a condition is created within the loop, such as reaching a particular value, the program can go to "label A" where other operations can be carried out. 

MULTIPLICATION 
Multiplication can be handled as successive additions. 
The ADD instruction is available in the instruction set. 
Performing a multiplication between two files can be a fairly complex operation and the answer will produce up to four digits. This will require up to four files for the answer.
There are three different ways to perform a multiplication operation, depending on the figures you are processing. You can work with decimal numbers and get a decimal result or you can work with hex numbers and get a hex result. 
When operating with hex numbers, the small number is added to the large number in a loop file and the program keeps looping by a value equal to the number in the small file. This can take quite a number of loops and will occupy a long time (in computer terms). The alternative is to perform the multiplication by a "shift" method. This is shown in our third example.  
Here are our three methods:

METHOD 1:
The program below shows how to multiply the number 12 (twelve) in file A with the number 34 (thirty-four) in file B. Thirty-four is added to a file twelve times. 
The value 34 must be converted to a hex value. 34 = 22h and 12 is 0Ch. But since the program has a decrement before any operation is carried out, we must load the file with 0D! This is a clever programming trick! You need four files for the result just in case the two numbers are 99 x 99!

;Clear all files
Multi MOVLW 0D ;0D = thirteen
MOVWF 0D ;0D = 1st count file
X0 DECFSZ 0D ;DECrement the count file
GOTO X1
RETLW 00 ;The multiplication is done
X1 MOVLW 22h ;22h = 34
MOVWF 0E,1 ;Put 22h into file 0E
X2 DECFSZ 0E ;DEC 2nd count file
GOTO X3
GOTO X0
X3 INCF 16h ;INC units file
MOVLW 0A ;Put ten in W
XORWF 16h,0 ;Is file 16h = ten?
BTFSS 03,2 ;Test the Zero flag
GOTO X2 ;No. Go to X2
CLRF 16h ;Yes. Clear file 16h
 INCF 17h ;INC ten's file
MOVLW 0A ;Put ten in W
XORWF 17h ;Is file 17h = ten?
BTFSS 03,2 ;Test the Zero flag
GOTO X2 ;No. Go to X2
CLRF 17h ;Yes. 
INCF 18h ;INC hundreds file
MOVLW 0A  ;Put ten in W
XORWF 18h,0  ;Is file 16h = ten?
BTFSS 03,2 ;Test the Zero flag
GOTO X2 ;No. Go to X2
CLRF 18h  ;Yes. Clear file 16h
INCF 19h  ;INC thousands file
GOTO X2  

METHOD 2:
This method multiplies a hex number in file 0A with a hex number in file 0B. The result is placed in files 0D and 0C, with the high byte in 0D and low byte in 0C.
Example: multiply 6C(in file 0A) by 8E(in file 0B)
6C is called the multiplicand as it is the number being multiplied 
8E is the multiplier
The following routine makes sure the small number is in file 0B so that the multiplication routine takes the shortest time.
MOVF 0A,0 ;Copy the first number into W
SUBWF 0B,0 ;Compare first number with second number
BTFSS 03,0 ;Test the Carry bit. C=1(set) if file 0B > file 0A
RETLW 00 ;Return if carry is Clear. file 0B < file 0A   
MOVF 0A,0 ;Carry bit is Set. 0B > 0A    Copy first number into W
MOVWF 0C ;Put first number into temporary file 0C
MOVF 0B,0 ;Copy second number into W
MOVWF 0A ;Put second number into 0A
MOVF 0C,0 ;Copy first number into W
MOVWF 0B ;Put first number into 0B
RETLW 00 ;File 0A contains the large number and 0B = small number

The following routine multiplies one number by the other by successive additions. This is done in a loop and takes a long time (in computer terms). The program is easy to understand.
multiply 8E(in file 0A) by 6C(in file 0B)
Answer: high byte in 0D,  low byte in 0C
8E will be added to 8E in a loop for 6C loops:
CLRF 0C ;Zero file 
CLRF 0D ;Zero file
Multiply MOVF 0C,0 ;Copy answer file (low byte) into W 
ADDWF 0A,0 ;Add result to high number 
BTFSC 03,0 ;Test for "overflow"  Bit0 will be SET if overflow occurred
INCF 0D,1 ;Overflow occurred, increment high file 
MOVWF 0C ;Put result of additions into file 0C
DECFSZ 0B,1 ;Do 6C loops
GOTO Multiply
RETLW 00

METHOD 3:
The following program multiplies two 8-bit numbers via  8 shifts (8 loops). 
Example: multiply 8E(in file 0A) by 6C(in file 0B)
Answer: high byte in 0D,  low byte in 0B (file 0B contains the low-byte answer!)
File 0E is the count file.

Multilpy MOVF 0A,0 ;Put the value in file 0A (8E) into W.
  CLRF 0D ;Clear high-byte-answer file
  CLRF 0E ;Clear count file
  BSF 0E,3 ;Load file 0E with 8 for decrementing
  RRF 0B,1 ;Put bit0 of file 0B (6C) into carry 

Loop  

BTFSC 03,0 ;Test the carry bit of multiplicand (6C) to see if it is 1.
  ADDWF 0D,1 ;If 1, add 1 to high-byte answer
  RRF 0D,1 ;Shift high-byte answer file right to put Bit0 into carry
  RRF 0B,1 ;Carry-bit will be added as bit7 to low-byte answer file 
  DECFSZ 0E,1 ;Decrement the count file
  GOTO Loop ;Do 8 loops
  RETLW 00 ;Return

The routine above is much more sophisticated than first meets the eye. Here are some of the  hidden features/tricks in the routine:
The first thing to remember is: It takes nine shifts to rotate a file completely to get it back to its original value. 
Each time a shift takes place, the carry-bit is introduced at either the top-end or bottom-end. If the shift is right-shift, the carry bit is introduced as bit 7. (the highest bit)
In the program above, file 0D is shifted right and bit0 is shifted into the "carry." 
In the next instruction, file 0B is shifted right and thus the carry bit from file 0D is in the "carry" of the STATUS register and is transferred into the top position of file 0B. Bit0 of file 0B is now transferred to the carry. 
On the execution of the next loop, the lowest bit of file 0B is in the "carry" and is transferred to the highest bit of file 0D if it is "1." 
In this way, one file "secretly" alters the other. 
To work out exactly how each file is altered, you have to go through each loop. 

A simple way to multiply a file by 2, 4, or 8 is to use the RLF instruction. 
Each time a file is shifted left, the contents are doubled. This operation shifts the highest bit into the "carrier" and the carrier bit into the lowest position (LSB) in the file. The carrier bit could be a zero or one from a previous instruction and it must be cleared before executing an RLF instruction (before each RLF instruction).
A file can also be doubled by loading it into W then ADDing W and the file together. 

CONVERSION 
A number (such as 0 to 100) can be converted to another value using a TABLE. 
Use a formula you have produced to work out values from say zero to 100 and place them in a table. Use CALL Table1, ADDWF 02,1 and RETLW instructions to access the table.
A table can be used for converting or producing "graph values," "lines of best fit," "approximations," "statistical values," "display values" or merely converting any value to another value. The table can even be a list of random numbers, as the micro finds it very difficult to produce these types of numbers. 
The result of a table can be very impressive and the advantage is it does not require a complex routine. 
Mathematical operations can also be carried out (or assisted) by SETing or CLEARing a bit in a file. You can ADD or SUBtract 1, 2, 4, 8, 10h, 20h, 40h or 80h from (or to) the value of a file. You MUST know the value in the file before executing the instruction as SETing a bit that is already a "1" does not increase the value!

COMPARE
Two files can be compared to see if they are the same by using the XOR (exclusive OR) instruction. Place one file in the working register W and XOR W with the other file. If they are both the same, the zero flag will be set. In other words a MATCH = 1. 
The Zero flag in the STATUS register (03h) is bit 2. 

Example: 

MOVF 0C ;put file 0C into W
XORWF 0D ;XOR W with file 0D
BTFSS 03,2  ;Test Zero flag
;The micro will go HERE if different
; The micro will jump HERE if files are a MATCH
The program can be written like this:
MOVF 0C
XORWF 0D
BTFSS 03,2
GOTO D
GOTO MATCH

MASKING
Masking is the operation of changing particular bits in a file to zero. A file consists of a high nibble (the four high bits) and a low nibble (the four low bits). You can zero the high nibble, low nibble or both. An example: zero the high nibble so that the low nibble can be incremented to 9, to produce a decimal value for a decimal counter. 
To zero a high nibble the file is ANDed with 0Fh. The value 0Fh is 0000 1111. When a bit is ANDed with 0, the result is zero. When a bit is ANDed with "1" the bit is unchanged. In this case the high nibble is zeroed and the low nibble remains unchanged. 
To zero a low nibble, the file is ANDed with F0h. The value F0h is 1111 0000. The high nibble remains unchanged and the low nibble is zeroed. 
Masking both nibbles is merely clearing the file. (CLRF) 

MORE THAN AND LESS THAN 
Two files can be compared to see if file 0C is larger than file 0D. 

Example:
File 0C = 20h File 0D = 10h
Place file 0C in W by using the instruction: 
MOVF 0C,0 ;Put 0C into W 
Subtract W (file 0C) from file 0D by using the instruction:
SUBWF 0D,0
Test the carry flag with the instruction:
BTFSS 03,0 ;Test carry flag 
The carry flag will be 0 (CLEAR). This means a borrow occurred and thus the value in file 0C is larger than the value in file 0D.
Example: File 0C = 10h File 0D = 20h
Place file 0C in W by using the instruction: 
MOVF 0C,0 ;Put 0C into W 
Subtract W (file 0C) from file 0D by using the instruction: 
SUBWF 0D,0 
Test the carry flag with the instruction:
BTFSS 03,0  ;Test carry flag 

The carry flag will be (SET). This means a borrow did not occur and thus the value in file 0C is smaller than the value in file 0D. 

PERCENTAGE and TRIG FUNCTIONS
Percentage, and other mathematical operations such as square root and trigonometrical functions are best handled via a table. Routines can be set up for these operations but the simplest is to use a calculator to obtain the results for the range you are working with and put them in a table. 

FRACTIONS
Fractions cannot be handled by the '508A or F84 so alternative methods must be employed. 
Displaying numbers such as temperature in 0.5°C increments can be produced by obtaining the whole number(s) from a table and generating the fraction (the number 5) from the program. The value 40.5°C will be produced by making the table value 1100 0000. Bit 7 will be stripped away in the program to indicate a 0.5 on the display, leaving 0100 0000 as the value 40 for the display. In this way values from 0°C to 79.5°C can be produced. The decimal point is turned on via a transistor or by direct access to the decimal point on the display. 

COUNTING
One of the most requested features of a microcontroller is the ability to produce a count for a display. 
Counters for production-lines, clocks, decrementing counters, tally counters and batch counters are all in heavy demand in industry. 
The '508A and F84 are ideal as the heart of a 5-digit counter with any feature you require, including count-up, count-down, beep output, relay output - all with one to five digits. 
You will need a 4040 counter chip and/or 74c164 shift registers to expand the lines of the '508A to drive the segments in the displays.
The basis of any counter is counting to ten. A file is incremented and when the count reaches ten (0A in hex) the file is zeroed and the next file is incremented. This file is then tested for 0A and if not 0A, the program goes back to polling the input line for another button-press or some other form of input, such as magnetic or optical detection. 

Here is part of the routine to increment a set of files:

INCF 16h ;INC the units file
MOVLW 0A ;Put ten in W
XORWF 16h,0 ;Is file 16h = ten?
BTFSS 03,2 ;Test the Zero flag
GOTO Main ;No. Return to Main routine
CLRF 16h ;Yes. Clear file 16h
INCF 17h ;INC the ten's file
MOVLW 0A ;Put ten in W
XORWF 17h ;Is file 17h = ten?
BTFSS 03,2 ;Test the Zero flag
GOTO Main ;No. Go to Main
CLRF 17h ;Yes.          etc.

The count can be stored as 0-9, in the lower nibble of a set of files, such as 16h, 17h, 18h, 19h etc. This will require the least amount of programming. If you are short of files, both the low and high nibbles of a file can be used but this will require a lot more lines of program to firstly compress the two numbers into a single file and then extract them when needed.  

CONCLUSION
Quite often an operation or “effect” will seem to need a complex mathematical operation. 
This is out of the question with a simple microcontroller. So you will have to look at the situation in a different light and operate on the information in a different way. 
The best solution to anything “mathematically-complex” is a table. Work out the co-relation between the data and the display values and generate a table. The table can be up to 0FFh (this is address location 256 in the programming-space of a ’508A) and the sub-routines must be in the remaining 255 bytes.
But since the CALL instruction only operates to the first 256 locations, it is best to go to the F84 if your program is larger than 256 instructions (including table values). You can get around this CALL limitation in a ‘508A but the complexity of doing it is not worth the burden. See CALL in the Library of Terms and Routines.
Each table value or file can hold a value from 00 to FFh (00 to 255) and you will need a routine to convert from hex to decimal to produce a 3-digit display, if you are going to store values in hex. A simpler approach is to store decimal values in separate files.
Alternatively a single file will store a value from 00 to 99 in decimal without the need for a conversion routine. 
A single file is also capable of storing a value with fractions, from 0 to 79.5 as mentioned above.
If you need to display a 4 or 5 digit number, you can use 4 separate displays or flash the numbers on a single display. It all depends on how often the display is to be viewed and the allowable cost of the project.
See the 2, 3 and 5 digit counting programs in the Experiments section for the 5x7 Display for ideas on how to display large numbers.
Sometimes a display value can be generated afresh, each time it is displayed, as a "count-and-display" routine.
In most cases there is a very simple way around a seemingly complex problem.
It just takes a fresh look at the problem to see how to solve it.  If all fails, use a table. 

NEXT