Online PIC Compiler

PIC16F84A Extra Examples

Example 1: MOD of a Number,
R=M (MOD N)

Problem:

In this Example, we find M (MOD N), or in other words the remainder of the integer division M/N, and write the result to register R. We assume that M and N are 1-byte numbers (between 0 and 255).

Solution:

;Declarations
M EQU 0X0C
N EQU 0X0D
R EQU 0X0E

;Initial values
MOVLW 0XAB
MOVWF M; M=0XAB
MOVWF R; initially set R to M
MOVLW 0X05
MOVWF N;N=0x05 and W=N

;Test 0
MOVF N, 1
BTFSS STATUS, 2
GOTO MOD
CLRF R
GOTO INFLOOP

;Taking MOD
MOD
SUBWF R, 1; Subtract N from M until the result is negative
BTFSC STATUS, 0
GOTO MOD
ADDWF R, 1;Add N to R, so as to find the actual result

;STOP PROGRAM
INFLOOP
GOTO INFLOOP

Explanation:

In Declarations part, we allocate an address for each variable in the program. And declared address has to be between 0x0C and 0X4F for PIC16F84A. That's why we started with 0X0C.

In the second part, we define initial values for M and N. For this program we have selected 0XAB (171) and 0X05 (5) for M and N, respectively. Therefore, we will find 171 (mod 5) and write the result to R. M and N values can even be taken from the PORTs.

In part 3, we test whether N is 0 or not. Mod 0 of any number is defined as zero. Thus, we set R to 0 directly and jump to the end of the program. Otherwise, we have to apply the algorithm in the next part. The first line of this part moves N to itself. That operation does not affect the content of any general purpose register. However, it sets Zero Flag in STATUS, if N=0 and clears if N>0. That's why, we test STATUS bit number 2 after MOVF.

Part 4 is implementing the main algorithm here. At this point, we are sure that N is non-zero and R is equal to M. In each step, we subtract N from R and check whether the result is negative or not. If the result is negative it means we have subtracted N from R one more extra time than the sufficient one. The actual result is obtained when R is between 0 and N-1 and one more subtraction results in a negative number. Thus at then end, we add N to R to reach the actual result.

The final part is used to stop the program after calculations.

Example 2: Even Parity

Problem:

In communication networks, it is always possible to encounter bit-wise errors during transmission. There are various algorithms for detection and correction of erronous bits in transmitted data. Even parity check is one of those algoritms. With even parity 1 bit error can be detected. If the data chunks are 7-bit long, the idea is to count the number of ones in 7-bits and complete the number of ones to an even number. If the number of ones in data is 5 (e.g. 110 1110), we set MSB to 1, in order to have an even number of ones in 8-bit number with parity check (e.g. the new number becomes 1110 1110). However, if the number of ones is already even, we write 0 to MSB. (e.g. if the number is 111 1110, with partiy it becomes 0111 1110).

Let's say the data chunk is stored in a register, VALUE. MSB of VALUE is 0 by default. In this example we will count the number of ones in VALUE and if this number is odd, we write 1 to MSB.

Solution 1:

We will first check each bit one by one without using loop

;Declarations
VALUE EQU 0X0C
NOOFONES EQU 0X0D

;Initial values
MOVLW 0X3B;Write a number less than 128(decimal)
MOVWF VALUE; VALUE=0X3B
CLRF NOOFONES

;Count the Number of Ones
BTFSC VALUE, 0
INCF NOOFONES, 1
BTFSC VALUE, 1
INCF NOOFONES, 1
BTFSC VALUE, 2
INCF NOOFONES, 1
BTFSC VALUE, 3
INCF NOOFONES, 1
BTFSC VALUE, 4
INCF NOOFONES, 1
BTFSC VALUE, 5
INCF NOOFONES, 1
BTFSC VALUE, 6
INCF NOOFONES, 1

;Add parity
BTFSC NOOFONES, 0
BSF VALUE, 7

;STOP PROGRAM
INFLOOP
GOTO INFLOOP

Explanation:

In Declarations part, we set two address values: VALUE and NOOFONES. NOOFONES is going to be used to hold the number of ones in value.

In the second part, we define initial values for VALUE and NOOFONES. For this program we have selected 0XAB (171) for VALUE. NOOFONES has to start with 0.

In part 3, we count the number of ones in VALUE. We test every bit in VALUE (0 to 6) and if it is one we add 1 to NOOFONES. Part 4 is checking whether NOOFONES is EVEN or ODD. For any integer, the last bit is 1 if the number is ODD and 0 if it is EVEN. (e.g. 7=111, 6=110). Thus, it is enough to check the last bit to see whether a number is EVEN or ODD.

The final part is added just to stop the program after calculations.

Solution 2:

In the secod solution, we use a loop to count the number of ones in VALUE

;Declarations
VALUE EQU 0X0C
TEMP EQU 0X0D
NOOFONES EQU 0X0E
COUNTER EQU 0X0F

;Initial values
MOVLW 0X3B
MOVWF VALUE; VALUE=0X3B
MOVWF TEMP; TEMP=VALUE
CLRF NOOFONES
MOVLW 0X06
MOVWF COUNTER

;Count the Number of Ones
PARITY
RRF TEMP, 1
BTFSC STATUS, 0
INCF NOOFONES, 1
DECFSZ COUNTER, 1
GOTO PARITY

;Add parity
BTFSC NOOFONES, 0
BSF VALUE, 7

;STOP PROGRAM
INFLOOP
GOTO INFLOOP

Explanation:

In Declarations part, in addition to VALUE and NOOFONES, we set two more addresses for TEMP and COUNTER. COUNTER is used to ensure that our loop is repeated 6 times. TEMP is just the copy of VALUE. We apply the manipulations to TEMP, just to keep VALUE the same after at the end of the program.

Initial value of TEMP has to be the same as VALUE and COUNTER has to be 6.

In the third part, we count the number of ones in TEMP, using a loop which repeats itself 6 times. At each time we shift TEMP to the right one unit. Thus, the LSB of TEMP is shifted to the Carry Flag in STATUS. After rotation, we test the Carry Flag, and if it is 1, we increment NOOFONES. Then we decrement the COUNTER. We continue to process the loop until it becomes zero.

Part 4 is the same as the previous solution.

Again, the final part is used to stop the program after calculations.

Example 3: DECIMAL DIGITS

Problem:

For a predetermined 1-byte number, VALUE, we are going to find the digits in decimal and store them in registers HUNDREDS, TENS and ONES. For example, if VALUE is equal to 197=0XC5, HUNDREDS, TENS and ONES become 1, 9 and 7, respectively.

Solution:

;Declarations
VALUE EQU 0X0C
HUNDREDS EQU 0X0D
TENS EQU 0X0E
ONES EQU 0X0F
TEMP EQU 0X10

;Initial values
MOVLW 0XC5
MOVWF VALUE; VALUE=0XC5
MOVWF TEMP; TEMP=VALUE
CLRF HUNDREDS
CLRF TENS
CLRF ONES

;Count HUNDREDS
MOVLW 0X64;W=100
LOOP_H
INCF HUNDREDS, 1
SUBWF TEMP, 1;Subtract 100 from TEMP
BTFSC STATUS, 0;until the result is negative
GOTO LOOP_H
DECF HUNDREDS, 1
ADDWF TEMP, 1

;Count TENS
MOVLW 0X0A;W=10
LOOP_T
INCF TENS, 1
SUBWF TEMP, 1;Subtract 10 from TEMP
BTFSC STATUS, 0;until the result is negative
GOTO LOOP_T
DECF TENS, 1
ADDWF TEMP, 1

;Count ONES
MOVF TEMP, 0
MOVWF ONES

;STOP PROGRAM
INFLOOP
GOTO INFLOOP

Explanation:

In Declarations part, we define 5 variables: VALUE, TEMP, HUNDREDS, TENS and ONES. Throughout the program, we will work on TEMP, thus VALUE will not be affected. HUNDREDS, TENS and ONES will hold the digits at the end.

In the second part, we define initial values for those registers. VALUE and TEMP are set to 197. HUNDREDS, TENS and ONES are cleared, initially.

In part 3, we count the HUNDREDS digit. The idea here is to subtract 100 from TEMP until the result is less than 0 and count the number of subtractions. For the defined values above, TEMP=197. After the first subtraction the result is 97, which is not negative. Thus we increment HUNDREDS and continue subtracting. In the second step, TEMP becomes 97-100=-3, thus carry flag becomes 0 and we increment HUNDREDS one more time but quit the loop. HUNDREDS is counted as 1 more than the actual digit. Thus, we decrement it once we quit the loop. Moreover, to obtain TEMP without HUNDREDS digit, we add 100 to the result obtained in the loop. new TEMP value becomes -3+100=97 before entering the loop counting TENS digit.

Then we set W to 10 and apply the same algorithm to obtain the digits TENS.

The final value of TEMP, before the next section is 7. Therefore, it is enough to move this number to the register ONES.

The last part is added just to stop the program after calculations.