What does it do?
The Decision program demonstrates how to make decisions in your programs.
None. But, you will learn about two different ways in which the movf instruction can be used.
Decision programming activity
Now that you've seen the basics of PIC Math instructions, the Decision program demonstrates how to use decision structures in your code. Decision structures are typically composed of math instructions followed by conditional tests of the status register flag bits, allowing you to check for equality, do less than or greater than comparisons, and find zero results.
What you should know before starting
Status register bits
Three of the Status register bits, Z (Zero) bit, DC (Digit Carry) and C (Carry), are affected by all math operations. The code in the decision program will (mostly) perform a subtraction operation and then check the state of these bits to determine if two variables are equal, or which one is greater or smaller. Checking for zero can be done without subtracting.
Remember that during simulation, the state of the Z, DC, and C bits is shown in the bottom status bar of the MPLAB IDE. Their state is represented by the letter state—an upper-case letter means the bit is set, and a lower case letter means the bit is clear. For example, seeing Z dc C indicates that a Carry has taken place, the result of the operation is zero, and no digit carry occurred. Of course, you can also open a watch window to check the Status state.
Each Status register bit corresponds to specific states:
- a zero result of any addition or subtraction will set the Z bit, a non-zero result leaves it cleared;
- an addition overflow (adding two 8-bit numbers to produce a 9 bit result) will set the C bit, effectively making it the 9th bit of the result;
- an addition overflow from the low nybble (the least significant 4 bits) to the high nybble (the most significant 4 bits) in a byte results in the DC flag being set;
- a subtraction operation will set the C bit before subtracting, and borrow from it (if necessary) during the subtraction—1 means no borrow occurred, 0 indicates a borrow took place.
To use this program you will need:
An assembled CHRP 3 board, an optional power supply, a programmer and/or programming cable, and a computer with the MPLAB IDE or MPLAB X software as described in the Output activity.
Create the program
The entire DECISION.ASM program is shown below. Create a Decision project in MPLAB, copy this code into it, and build the program.
;Decision v3.1 January 14, 2013 ;=============================================================================== ;Description: Demonstrates math between constants, constants and registers, ; and registers. ;Configure MPLAB and the microcontroller. include "p16f886.inc" ;Include processor definitions __config _CONFIG1, _DEBUG_OFF & _LVP_OFF & _FCMEN_OFF & _IESO_OFF & _BOR_OFF & _CPD_OFF & _CP_OFF & _MCLRE_ON & _PWRTE_ON & _WDT_OFF & _INTOSCIO __config _CONFIG2, _WRT_OFF & _BOR40V ;Set RAM register equates. num1 equ 20h ;RAM storage register for the first number num2 equ 21h ;RAM storage register for the second number ;Start the program at the reset vector. org 00h ;Reset vector - start of program memory clrf PORTA ;Clear all port outputs before configuring clrf PORTB ;port TRIS registers. Clearing RA4 turns on clrf PORTC ;the Run LED when TRISA is initialized. goto initPorts ;Jump to initialize routine org 05h ;Continue program after the interrupt vector initPorts ;Configures PORTA and PORTB for digital I/O. banksel ANSEL ;Switch register banks clrf ANSEL ;Set all PORTA pins to digital clrf ANSELH ;Set all PORTB pins to digital movlw 01010111b ;Enable Port B pull-ups, TMR0 internal movwf OPTION_REG ;clock, and 256 prescaler banksel TRISA ;Switch register banks movlw 00101111b ;Set piezo and LED pins as outputs and movwf TRISA ;all other PORTA pins as inputs clrf TRISB ;Set all PORTB pins as outputs for LEDs banksel PORTA ;Return to register bank 0 main movlw 6 ;Preload the number registers for later use movwf num1 movlw 0 movwf num2 equalsZero ;Decide if a number is zero by checking the Z flag movf num1,W ;Copy the contents of num1 into W and btfsc STATUS,Z ;check for zero result bsf PORTB,0 ;If zero, turn an LED on movf num2,F ;Evaluate the contents of num2 and btfsc STATUS,Z ;check for zero result bsf PORTB,0 ;If zero, turn an LED on equalsNumber ;Decide if one number equals another by subtracting one number ;from the other and checking for a zero result. movwf num2 ;Copy the contents of W into num2 movf num1,W ;Copy contents of num1 into W and subwf num2,W ;compare with num2 by subtraction btfsc STATUS,Z ;Skip if the result is not zero (Z=0) bsf PORTB,1 ;Turn an LED on if numbers are equal greaterThan ;Decide if one number is larger than another by subtracting ;and checking the Carry/!Borrow bit. Carry is set at the start ;of a subtraction and is borrowed from (cleared) if necessary. movlw 4 ;Preload num2 with a new number movwf num2 movf num1,W ;Copy contents of num1 into W and subwf num2,W ;compare by subtracting from num2 btfss STATUS,C ;Skip if no borrow occurred (C=1) bsf PORTB,2 ;If borrow occurred, num1 > num2 lessThan ;Decide if one number is smaller than another by subtracting ;and checking the Carry/!Borrow bit. As above, but checks the ;opposite order and condition. movf num2,W ;Copy contents of num2 into W and subwf num1,W ;compare with num1 by subtraction btfsc STATUS,C ;Skip if a borrow occurred (C=0) bsf PORTB,3 ;If no borrow occurred, num1 < num2 sleep ;Stop at end of program end
As with Math, you won't need to download this program to your CHRP board—just run it in the MPLAB Sim debugger. Set up a watch window to watch the contents of the W register and file registers 20h and 21h. You can also watch the Status register if you like, or just check the Z, DC and C bits in the status bar at the bottom of the MPLAB window. Step through the program and observe the contents of the registers and Status bits after each step.
How the program works
Similar to the Math program, there is nothing really complex happening in this code. You should be able to fully understand what is happening by working your way through the code or watching the code run in the simulator. There are, however, some hints that might make it easier for you to use decision structures in your programs.
Hint 1 - "Touch it" to check for zero
equalsZero ;Decide if a number is zero by checking the Z flag movf num1,W ;Copy the contents of num1 into W and btfsc STATUS,Z ;check for zero result bsf PORTB,0 ;If zero, turn an LED on movf num2,F ;Evaluate the contents of num2 and btfsc STATUS,Z ;check for zero result bsf PORTB,0 ;If zero, turn an LED on
Both of the above code structures check for zero. The first copies a number into W, the second does not. It's perfectly ok to check the state of a register (zero or non-zero) by moving the register to itself using ,f (essentially, just 'touching' it), with the added advantage that another number can be retained in W during this process.
To demonstrate this, the content of num1 is copied into num2 in the next step, after num2 is checked for zero:
equalsNumber ;Decide if one number equals another by subtracting one number ;from the other and checking for a zero result. movwf num2 ;Copy the contents of W into num2
Hint 2 - Skip over to continue
The PIC microcontroller's bit test and skip instructions skip over one line of code if the condition is true. If the code that will execute if the condition is false fits on one line of code, add it inline (as shown):
movf num1,W ;Copy contents of num1 into W and subwf num2,W ;compare with num2 by subtraction btfsc STATUS,Z ;Skip if the result is not zero (Z=0) bsf PORTB,1 ;Turn an LED on if numbers are equal
In this subroutine, a zero result turns on an LED – an operation that can execute in one line. If the code that needs to execute after a false condition is longer than one line, you'll have to use a goto to branch to a subroutine containing the code, like this:
movf num1,W ;Copy contents of num1 into W and subwf num2,W ;compare with num2 by subtraction btfsc STATUS,Z ;Skip if the result is not zero (Z=0) goto doZeroCode ;Goto a subroutine that handles zero result more code ;Continue executing code if not zero
Hint 3 - Don't destroy your variables
movf num1,W ;Copy contents of num1 into W and subwf num2,W ;compare by subtracting from num2 btfss STATUS,C ;Skip if no borrow occurred (C=1) bsf PORTB,2 ;If borrow occurred, num1 > num2
In the example code, above, W is used to store both the first number for the comparison and also the result of the comparison test. By doing the math in W, the original variables are maintained and are available for use in later subroutines.
Test your knowledge
- How does movf register,W differ from movf register,f?
- What is the order of subtraction in a subwf instruction. How do you know?
- Does the example code in the decision program make it possible to check for one number being less than or equal to another? Why or why not?
Apply your skills
- Modify the Analogue program to compare an analogue input with a fixed threshold, or to compare one analogue input to another, and then indicate the difference using the LEDs. For example, you could check the level of the potentiometer and light an LED if it exceeds the value of 200 and another LED if it falls below 60. Or, you could compare the amount of light seen by Q1 with Q2 and light one LED if Q1's light level is greater and another LED if Q2's light level is greater. Make sure to document your program well.