2. Accessing the "TRIS" and "OPTION_REG" Registers in the Mid-Range PICmicro MCUs
This is an action that many people have trouble understanding. In the
mid-range PICmicro MCUs, the "TRIS" and "OPTION_REG" registers (along with some other
special purpose registers) are located in "Bank 1" and can only be accessed when the eight
bit address is in the FSR register (and the "INDF" register is accessed) or when the "RP0"
bit of "STATUS" is set. If the latter method is used, then the most significant bit of the
eight bit address should be inverted to avoid MPASM assembler messages. The "TRIS" and "OPTION"
instructions should not be used in the mid-range PICmicro devices.
To access Bank 1 Registers using the FSR register:
movlw Reg ; Load FSR with the Register Address
movf INDF, w ; Access the Register with "movf" or "movwf"
; Instruction Executed
To access Bank 1 Registers by selecting the correct Bank:
bsf STATUS, RP0 ; Execute in "Bank 1"
movf Reg ^ 0x080, w ; Access the register with bit 7 inverted
bcf STATUS, RP0 ; Return to "Bank 0"
I recommend that execution should normally take place in Bank 0 at all
times to avoid confusion over which bank is active in subroutines or interrupt handlers.
3. Accessing all pins in the PIC12C50X and PIC16C505 Devices
The PIC12C50x and PIC16C505 microcontrollers have the ability to use
internal reset and clocking functions. To take advantage of these features, the
programmer that is used should be able to set the "Calibration Value" (a "movlw" instruction
at the end of program memory). With the calibration value set, the application should start
with the following code:
__CONFIG _MCLRE_OFF & _IntRC_OSC ; Add Application Specific
; “CP” and “WDT” parameters
org 0
movf OSCCAL
movlw 0x0FF ^ (1 << T0CS)
option
; All I/O pins are NOW Available and Internal 4 MHz Clock is Running
; - Start Application
4. Accessing all pins in the PIC12C67X Devices
The mid-range processor architecture offer similar capabilities as the
low-end processor architecture PIC12C5XX and PIC16C505. To enable all the I/O pins as
output, a programmer with the capability of creating the "Calibration Subroutine"
(simply a "retlw" instruction at the end of program memory) should be used with the
start of the application having the code:
__CONFIG _MCLRE_OFF & _CP_OFF & _PWRTE_ON & _WDT_OFF & _INTRC_OSC
org 0
bsf STATUS, RP0 ; Setup the PICMicro
ifndef Debug
call 0x03FF ; Read the Calibration Value
else
nop
endif
errorlevel 1, -219
movwf OSCCAL ^ 0x080
errorlevel 1, +219
In MPLAB, the "Calibration Subroutine" is not automatically set up for the
PIC12C67X device, so the "Debug" define is specified to skip over the call to the "OSCCAL"
register.
5. PICmicro MCU Interrupt Handler Skeletons
The mid-range PICmicro MCU Interrupt Handler uses the following "skeleton"
where "_w" can be accessed in any bank and "_status", "_fsr" and "_pclath" can be accessed
only in Bank 0. "FSR" and "PCLATH" are optionally saved depending on how the application
executes.
org 4
Int
movwf _w ; Save the Context Registers
movf STATUS, w
bcf STATUS, RP0 ; Change to Bank 0
bcf STATUS, RP1
movwf _status
movf FSR, w
movwf _fsr
movf PCLATH, w
movwf _pclath
clrf PCLATH
: ; Interrupts are Handled Here
movf _pclath, w ; Restore the Context Registers
movwf PCLATH
movf _fsr, w
movwf FSR
movf _status, w
movwf STATUS
swapf _w, f
swapf _w, w
retfie
The PIC17CXXX uses the Interrupt Handler Skeleton shown below. Note that the
PIC17CXXX has different interrupt vector addresses and this code may be placed at different
locations or repeated.
Int
movpf ALUSTA, _alusta
movpf BSR, _bsr
movpf WREG, _wreg
movpf PCLATH, _pclath
: ; Interrupt Handler Code.
movfp _pclath, PCLATH
movfp _wreg, WREG
movfp _bsr, BSR
movfp _alusta, ALUSTA
retfie
The PIC18CXXX can access memory anywhere within the device using the "movff"
instruction (which doesn't affect the "STATUS" register). This makes the PIC18CXXX interrupt
handler skeleton quite simple:
Int
movwf _w ; Save Context Registers
movff STATUS, _status
movff BSR, _bsr
: ; Interrupt Handler Code
movff _bsr, BSR ; Restore Context Registers
movf _w, w
movff _status, STATUS
retfie
6. "Safe" TMR0 Polling Loop
When polling TMR0 to reach Zero, it is important to use the following code
which does not return the contents of TMR0. If TMR0 is written to, the prescaler will be
reset and if the prescaler is set to 2:1, then TMR0 will increment at half the expected
speed. If the prescaler is greater than 2:1, then TMR0 will never change.
movf TMRO, w ; Load “w” with the contents of TMRO
btfss STATUS, Z ; Skip if the Result is Equal to Zero
goto $ - 2
7. PIC16F84 EEPROM Access
The following macros will allow you to read and write to the PIC16F84's
data EEPROM. Note that the Address/Data values are constants. If Variable values are to
be used, then the "movlw Address"/"movlw Data" instructions should be changed to
"movf Address, w"/"movf Data, w" instructions.
EEPROMRead Macro Address
movlw Address ; Address is a Constant
movwf EEADR ; "EEADR" in Bank 0
bsf STATUS, RPO
bsf EECON1, ^ 0x08, RD
bcf STATUS, RPO
movf EEDATA, w ; w = EEPROM [Address]
endm
EEPROMWrite Macro Address, Data
movlw Data
movwf EEDATA
movlw Address
movwf EEADR
bsf STATUS,RPO
bsf EECON1 ^ 0x080, WREN
bcf STATUS, C ; Save the INTCON, GIE in the Carry Flag
btfsc INTCON, GIE
bsf STATUS, C
bcf INTCON,GIE
movlw 0x055 ; Critical Code
movwf EECON2 ^ 0x080 ; Critical Code
movlw 0x0AA ; Critical Code
movwf EECON2 ^ 0x080 ; Critical Code
bsf EECON1 ^ 0x080, WR; Critical Code
btfsc STATUS, C ; Restore Interrupts if Required
bsf INTCON, GIE
btfsc EECON1 ^ 0x080, WR; Poll for Operation Ended
goto $ - 1
bcf EECON1 ^ 0x080, WREN
bcf STATUS, RPO
endm
8. PIC16F87X EEPROM Access
The PIC16F87X accesses data EEPROM similarly, but with small differences
due to the inclusion of the program memory Flash access capability built into the Data
EEPROM Access Registers. The following macros provide the same function as the ones in
the PIC16F84 macros.
EEPROMRead Macro Address
movlw Address
bsf STATUS, RP1 ; EEPROM Registers in Banks 2 and 3
bcf STATUS, RP0
movwf EEADR ^ 0x0100
bsf STATUS, RPO
bcf EECON1 ^ 0x0180, EEPGD
bsf EECON1 ^ 0x0180, RD
bcf STATUS, RPO
movf EEDATA ^ 0x0100, w
bcf STATUS, RP1
endm
EEPROMWrite Macro Address, Data
movlw Data
bsf STATUS, RP1
movwf EEDATA
movlw Address
movwf EEADR
bsf STATUS,RPO
bcf EECON1 ^ 0x0180, EEPGD
bsf EECON1 ^ 0x0180, WREN
bcf STATUS, C ; Save the INTCON, GIE in the Carry Flag
btfsc INTCON, GIE
bsf STATUS, C
bcf INTCON,GIE
movlw 0x055 ; Critical Code
movwf EECON2 ^ 0x0180 ; Critical Code
movlw 0x0AA ; Critical Code
movwf EECON2 ^ 0x0180 ; Critical Code
bsf EECON1 ^ 0x0180, WR ; Critical Code
btfsc STATUS, C ; Restore Interrupts if Required
bsf INTCON, GIE
btfsc EECON1 ^ 0x0180, WR ; Poll for Operation Ended
goto $ - 1
bcf EECON1 ^ 0x0180, WREN
bcf STATUS, RPO
bcf STATUS, RP1
endm
9. PIC16F87X program memory Flash Access
The PIC16F87X microcontrollers can read and write their program memory
in a similar manner to the Data Memory except that the address range is 8,192 instructions
and the data size is fourteen bits. This requires the inclusion of second registers for
these values. Note that in the "FlashRead" macro, "Data" is a sixteen bit variable for the
instruction contents.
FlashRead Macro Address, Data
bsf STATUS, RP1
movlw LOW Address
movwf EEADR ^ 0x0100
movlw HIGH Address
movwf EEADRH ^ 0x0100
bsf STATUS, RPO
bsf EECON1 ^ 0x0180, EEPGD
bsf EECON1 ^ 0x0180, RD
nop ; Instruction Read In Here
nop
bcf STATUS, RPO
movf EEDATA, w
movwf Data ; Store Lo Byte of Program Memory
movwf EEDATAH, w
movwf Data + 1 ; Store Hi Byte of Program Memory
bcf STATUS, RP1
endm
FlashWrite Macro Address, Data
bsf STATUS, RP1
movlw LOW Address
movwf EEADR
movlw HIGH Address
movwf EEADRH
movlw LOW Data
movwf EEDATA
movlw HIGH Data ; Maximum 0x03F for 14 bit Word Size
movwf EEDATAH
bsf STATUS, RPO
bsf EECON1 ^ 0x0180, EEPGO
bsf EECON1 ^ 0x0180, WREN
bcf INTCON, GIE ; Critically Timed Code
movlw 0x055 ; Critically Timed Code
movwf EECON2 ^ 0x0180 ; Critically Timed Code
movlw 0x0AA ; Critically Timed Code
movwf EECON2 ^ 0x0180, OR ; Critically Timed Code
nop ; Operation Executes
nop ; Operation Executes
bcf EECON1 ^ 0x0180, WREN
bsf INTCON, GIE
bcf STATUS, RP1
endm
10. USART Operation
Before setting up the USART for use with the PICmicro, the clock
divisor value has to be calculated. This is done using the formula listed below. The
BRGH bit is used to specify fast or slow operations. Due to problems with early
PICmicro MCUs, the BRGH bit should always be reset to ensure the code will work in all
devices.
SPBRG = (Fosc / (Data Rate x 16 x (4 ** (1 - BRGH)))) - 1
The following Macro is used to Initialize the PICmicro MCU's USART and
enable the receiver and transmitter:
USARTSetup Macro DataRate ; "DataRate" is the SPBRG Value
bsf STATUS, RP0
bcf TXSTA, SYNCH ; Not in Synchronous mode
bcf TXSTA, BRGH ; BRGH =0
movlw DataRate ; Set USART Data Rate
movwf SPBRG
bcf STATUS, RP0 ; Enable serial port
bsf RCSTA, SPEN ; Enable the Receiver
bsf STATUS, RP0
bcf TXSTA, TX9 ; Only 8 bits to send
bsf TXSTA, TXEN ; Enable Data Transmit
bcf TCSTA ^ 0x080, RX9 ; Eight Bits to Receive
bcf STATUS, RPO
endm
To transmit a byte, the TXIF bit of PIR1 is polled, waiting for the
holding register to be empty as is shown in the "USARTtx" macro below. In the MPLAB IDE simulator,
the operation of the USART is not simulated, so when simulating the application, the "Debug" label
must be defined, else the application will loop forever waiting for the TXIF bit to become set.
USARTtx Macro ; Send the Character in "w"
ifndef Debug
btfss PIR1, TXIF ; Wait for Holding Register to be Empty
goto $ - 1
else
nop
nop
endif
movwf TXREG ; Send the Byte
bcf PIR1, TXIF ; Reset the Interrupt Request Flag
endm
To receive a bit, the RCIF bit of PIR1 is polled as is shown in the macro
below:
USARTrx Macro ; Wait for a Character and return in "w"
btfss PIR1, RCIF ; Wait for Received Character Set
goto $ - 1
movf RCREG, w ; Get the Received Character
bcf PIR1, RCIF ; Clear the Character Present Flag
endm
11. Reading a value using the ADC
Using the ADC in the PIC16C7XX parts is actually quite easy to do. First the
appropriate pin operation is selected by writing to the "ADCON1" register as specified in the
PICmicro MCU's data sheet. Next, the "TAD" value is selected in such a way that it will have a
period of 1.6 to 6.4 usecs. I have not included code for these operations as they are different
for different PICmicro MCU part numbers and their values can be found in the data sheets.
With the ADC parameters set up, the following macro can be used to read an
eight bit ADC value:
ADCRead Macro Speed ; Read the ADC for the PICmicro running at "Speed"
variable DlayCount
DlayCount = 250000000 / Speed ; Calculate the number of Cycles in 20 msecs
DlayCount = 375 / DlayCount
movlw DlayCount
addlw 0x0FF ; Delay 20 usec for Holding
btfss STATUS, Z ; Capacitor to Stabilize
goto $ - 2
bsf ADCON0, GO ; start the ADC conversion
btfsc ADCON0, GO ; Wait for the ADC Conversion
goto $ - 1 ; to End
movf ADRES, w ; Read the ADC result
12. PIC17CXX Program Memory Read/Write
The feature that I really like in the PIC17CXX is its ability connect to external
devices and read and write to them. In the book, I discuss the PIC17CXX's ability to program its
own program memory, but in the following two macros, I show how the PIC17CXX can access external
memory using the "Table I/O" instructions:
TABLERead Macro Address
movlw HIGH Address ; Set up Table Pointer
movwf TBLPTRH
movlw LOW Address
movwf TABLPTRL
tablrd 0, 0, WREG ; Update Latch Register
tlrd 1, WREG ; Read High Byte
movwf Destination + 1
tablrd 0, 0, WREG ; Read Low Byte
movwf Destination
endm
TABLEWrite Macro Address, Data
movlw HIGH Address
movwf TBLPTRH
movlw LOW Address
movwf TBLPTRL
movlw HIGH Data
tlwt 1, WREG
movlw LOW Data
tablwt 0,0,WREG
endm