A Numeric Example
Links Mentioned
None

Links
Home
AWC

Microchip
PicList



Home
Introducing the PIC
Selecting a PIC
A Programmer
Hardware Tools
Software Tools
Downloading
Fixing the Blink
A Numeric Example
The Details
Special Registers
PIC Instructions



Using the APP-II's serial port it is easy to interact with your program. Consider this program, that converts decimal to hexadecimal:

<<NOTE: If you want to know what an instruction does and it is underlined, just click on it!>>

 

;Simple Program Example
PROCESSOR 16F873
__CONFIG 0x3FF6
INCLUDE <P16F873.INC>
INCLUDE <app2.inc>


CHAR EQU 0x20
DECNUM EQU 0x21


org 0
goto start

org 5
start:
; Init Serial Port
movlw HIGH SerialSetup
movwf PCLATH
call SerialSetup
clrf PCLATH
main:
clrf DECNUM    ; DECNUM=0 
; Send a ?
movlw HIGH SerialTransmit
movwf PCLATH
movlw '?'
call SerialTransmit
clrf PCLATH
iloop:
; Read a character
movlw HIGH SerialReceive
movwf PCLATH
call SerialReceive
clrf PCLATH
; If Enter go to cr
movwf CHAR
sublw .13
btfsc STATUS,Z
goto cr
; Not enter, must be a number
; So subtract 0 from it
movlw '0'
subwf CHAR,f
; Multiply running total by 10
movf DECNUM,W
addwf DECNUM,W ; W=DECNUM * 2
bcf STATUS,C
rlf DECNUM,F
bcf STATUS,C
rlf DECNUM,F
bcf STATUS,C
rlf DECNUM,F ; DECNUM=DECNUM * 8
addwf DECNUM,F ; DECNUM = (DECNUM*8) + (DECNUM*2) = 10*DECNUM
movf CHAR,W
addwf DECNUM,F
goto iloop
cr:
movlw DECNUM
movwf FSR
movlw HIGH Hexout
movwf PCLATH
call Hexout
movlw HIGH SerialTransmit
movwf PCLATH
movlw .13
call SerialTransmit
goto main


END 

You can try the program first to see how it works.

Unless you turn local echo on, you'll be typing blind. When you hit enter, the APP-II will echo back the number you typed, an equal sign, and the hex equivalent. Then you'll see another question mark and you can enter another number.

If you skim the code, you'll see that some addwf operations store their result in the W register and some store their result in the register you are using. This is common with math operations on the PIC. The trick is to look at the last part of the instruction. So:

   addwf  SOMEVAR,W

adds W and SOMEVAR and puts the result in the W register. However:

   addwf  SOMEVAR,F

does the same computation, but it stores the result in the SOMEVAR register. This offers a great deal of flexibility since you don't have to move everything out of W.

The movf instruction moves a register. It can also take a W or F modifier. It makes sense that if you want to move SOMEVAR to W you'd write:

   movf  SOMEVAR,W

However, what is the meaning of this next statement?

   movf  SOMEVAR,F

This moves the SOMEVAR register to itself. At first this seems like nonsense until you realize that moving things around sets certain flags in the STATUS register. So, for example, if SOMEVAR is zero in the above example, the STATUS register's Z bit will be set. Otherwise, it will be cleared.

One other thing to notice about this code is that the calls to the APP-II's ROM routines require a change in the bank. The PIC's goto and call instructions only have room for the lower bits of the program counter (the special register, PCL, that tells the current program location).

Think about a phone number in a small town. All the numbers have the same first three digits. So if you don't have enough room, you just write down the last four digits. That's the same thing here. The goto and call instructions just set the last bits of the PCL register. The top bits come from the PCLATH register.

So to call the non-local APP-II routines, you have to write code like this:

movlw HIGH SerialSetup
movwf PCLATH
call SerialSetup
clrf PCLATH

The first instruction loads the high bits of the target label. The second instruction stores that value in PCLATH. The call executes the code, and automatically uses the value in PCLATH. Finally, the last line zeros out PCLATH so any subsequent call or goto will use zeros for the topmost bits (which is what we want since we are at the start of the APP-II's memory space).

The other thing that confuses beginners is how to do conditional jumps. The PIC doesn't have a conditional goto instruction. Instead, you test a bit in a register and skip the next instruction based on the state of that bit. Here's how the program tests for a carriage return (decimal value 13):

movwf CHAR      ; get character in W
sublw .13       ; Subtract 13 from character
btfsc STATUS,Z  ; Test STATUS, Z bit (zero bit) and skip if clear  
goto cr         ; If it was set, goto cr
; here if not carriage return

Wow! This module is already long enough, but let me describe the algorithm in use. When you start typing a number, the PIC zeros a register (DECNUM). When you enter each character, the PCI multiplies DECNUM by 10, and then adds the value (the character minus '0') into DECNUM. So if you enter 153 it goes something like this:

DECNUM Entered character
0  
0 1
10 5
15 3
153 <ENTER>

Multiplying by 10 might sound hard on the PIC, but it is easy. The trick is realize that shifting a number left by 1 bit multiplies it by 2; shift it twice, you multiply by 4. Three shifts multiplies by 8. Then it is easy to figure it like this:

  10 * x = 8 * x + 2 * x = (x shifted by 3) + (x shifted by 1)

Whew! If you are still with me, you are doing great! Read the code again until you are comfortable with it. Then take a break and try the next module.

Back Next