;**********************************************************
; PIC assembler software routines for reading from and
writing to the EEPROM memory of
; a PIC16F84 (or PIC16C84).
; When programming your PIC, activate the power up timer and
disable the watchdog timer (unless
; you add to this code to handle the watchdog timer).
; Written by Glenn Pure (Glenn.Pure@pcug.org.au). Please
mail any significant improvements you
; may make to this code (and the accompanying C software) as
I might be able to use them myself!
;**********************************************************
; Processor is PIC16C84
#DEFINE
PIC16C84
; Include file for PIC16C84
INCLUDE <P16C84.INC>
;--------------------------------------------
; Setup configurations fuses for processor; must first
declare processor
__CONFIG B'00000000011001' ; XT oscillator, power up time active
;--------------------------------------------
; Assembler constants
BIT_CNT EQU 0x0f ;
bit counter register address (number of bits)
BYT_CNT EQU 0x10 ;
byte counter register address (number of bytes)
BITS EQU 8 ;
number of bits to read or write
BYTES EQU 64 ;
number of bytes to read or write
AA EQU 0x0c ;
General purpose register AA
BB EQU 0x0d ;
General purpose register BB
CC EQU 0x0e ;
General purpose register CC
;--------------------------------------------
;Jump past interrupt handler
ORG 0x00
BEGIN GOTO BOOTUP
;Interupt handler: Note, when interupt is actioned by
processor, it automatically pushes the
;program counter onto the stack and resets INTCON:GIE.
ORG 0x04 ;
Start location for interupt handler
BTFSC INTCON,INTF ; Is this a request to read/write EEPROM memory?
GOTO PC_DATA ;
If interupt pin (RB0/INT) interupt received, jump to
;
service routine for this. This routine responsible for
;
popping program counter from stack (with RETFIE) if needed
;***********************************************************************************************
;Bootup code: set interupt status and correct status for I/O
ports
BOOTUP MOVLW B'10010000' ; initialise interupt status
MOVWF INTCON ;
GIE enabled, RB0/INT pin interupt enabled,
;
all others off & all flags cleared
BSF STATUS,RP0 ;
Select register page 1
MOVLW B'11100000'
MOVWF TRISA ;
set RA0 to RA4 as outputs
MOVLW B'11111011'
MOVWF TRISB ;
set PORT B, pin RB2 to output, all the rest are inputs
MOVLW B'00010110' ; set up TMR0 to on, use internal clock, prescaler 128
;
INT pin interupt is falling edge, weak pull-ups on port B
MOVWF OPTION_REG ; (note: timer not used here)
BCF STATUS,RP0 ;
reset register addressing to page 00
;Waste time
DO_NIL NOP
NOP
NOP
NOP
NOP
NOP
GOTO DO_NIL
;***********************************************************************************************
; Routine for read/write of data from PC parallel port.
; The following lines are used for I/O (these may be changed
except for RB0/INT which is used
; to receive the initial interupt that signal entry to this
block of code. That is, you may
; use any I/O port pin on the PIC to replace pin assignments
below - obviously, the code
; will need to be modified accordingly):
; Note: Port B is set with internal pull-up resistors
active. Default state of all Port B input
; pins is therefore high.
; RB0/INT The interupt to enter the routines below is on
falling edge of RB0/INT. On PC side,
; connected
to [note output pin of printer port here].
; RB1 on the PIC is for serial data in to PIC. On the PC
side, it is connected to [note output
; pin of
printer port here].
; During
initiation of I/O, this line is also used to signal when data from PC is ready.
; RB2 on the PIC is for serial data out. On the PC side, it
is connected to [note input pin
; of printer
port here]
; Bits are
output most significant bit first. RB2 is also used to signal whether PIC is
; ready or
not to receive data from PC (high = ready)
; RB2 is also
used during the initial handshake to establish I/O.
; RB3 on the PIC is clock input for data read and write
operations. On the PC side,
; it is
connected to [note output pin of printer port here].
; RB6 on the PIC is read/write input signal. low = write to
PIC; high = read PIC. On the PC side,
; it is
connected to [note output pin of printer port here].
; RA0 on the PIC is an output signal to the PC used to
signal when EERAM write is completed
; during the
reprogramming of EERAM by the computer. A high signals the write is complete.
; On the PC
side, it is connected to [note input pin of printer port here].
; The following constants are used:
; BIT_CNT (RAM address): counter for number of bits read
from PIC or received for writing.
; (also used
as a time out counter to abort main routine if PC doesn't respond in time)
; BYT_CNT (RAM address): counter for number of bytes to read
from PIC or received for writing.
; EEDATA (PIC register): contains current byte of data being
sent to PC or received for writing.
; BITS (constant): number of bits per byte.
; BYTE (constant): number of bytes to read from PIC or
received for writing.
; A fresh RB0/INT interupt is needed to enter either read or
write routines. Each routine
; exits completely from this block of code when done. To get
into read or write routines, the
; 'handshake' code is first executed.
PC_DATA BCF STATUS,RP0 ;
ensure register addressing at page 0
BSF PORTB,2 ;
initialise RB2 output (to high)
;
Note: code from here on relies on polling the inputs
;
Interupts are not used and GIE was disabled by interupt
;
handling routine before control was passed to here.
;***********************************
;Handshake section
MOVLW BYTES ;
load counter with number of bytes to read or write
MOVWF BYT_CNT
MOVLW D'50' ;
Load loop counter via W: RB1 must cycle low-high 50 times
MOVWF AA
B1_LOOP CLRF BB ;
Reset 'time-out' counter
PORTOK BTFSC PORTB,1 ; Now check for low-high-low sequence on RB1 to
be sure
;
PC port handshake is OK: first check for high on RB1
GOTO RB1_OK1 ;
RB1 is high: check for next low on RB1
DECFSZ BB,1
GOTO PORTOK ;
Otherwise, keep checking RB1
GOTO IOQUIT ;
If 'timed out', abort I/O mode
RB1_OK1 CLRF BB ;
RB1 went high: now reset time-out timer
BCF PORTB,2 ;
then signal PC by reseting RB2 output from controller
NOP ; (separate port
write from port read with NOP)
RB1_OK2 BTFSS PORTB,1 ; Now check for low on RB1
GOTO NXT_B1 ;
RB1 low: check for next high on RB1 (or if loop done, exit)
DECFSZ BB,1
GOTO RB1_OK2 ;
Otherwise, keep checking RB1
GOTO IOQUIT ;
If timed out, abort I/O mode
NXT_B1 BSF PORTB,2 ;
Set RB2 output high to complete current cycle
DECFSZ AA,1 ;
Check if main handshake loop completed
GOTO B1_LOOP ;
Keep looping if not; otherwise skip to complete the handshake
MOVLW 0x4F ;
Acknowledge PC connection: output "OK"
MOVWF EEDATA ;
First load and output "O"
CALL BYT_OUT
MOVLW 0x4B ;
Then load "K"
MOVWF EEDATA
CALL BYT_OUT ;
and output it
BCF PORTB,2 ;
make sure RB2 is low in case write routine is entered
BTFSC PORTB,6 ; Now check for read or write: RB6 low = write;
high = read
GOTO PIC_RD ;
If high, go to the PIC read routine (ie output to PC)
;
Otherwise, start full write to all EERAM (next instruction)
;*****************************************
; Routine to write fresh data from PC to controller
PIC_WR CALL BYT_IN ;
Fetch start address for writing from PC
SUBLW 0x0F ;
Check for error condition from BYT_IN before continuing
BTFSC STATUS,Z ; Zero flag will be clear if no error
GOTO IOQUIT ;
Exit if error
MOVF EEDATA,0 ; Place the start address in EEADR (via W)
MOVWF EEADR
SUBWF BYT_CNT,1 ; Now set counter for correct number of bytes to write
WR_NXT BCF PORTA,0 ;
Clear the output that signals that last byte written OK
CALL BYT_IN ;
Fetch byte to write from PC
SUBLW 0x0F ;
Check for error condition from BYT_IN before writing byte
BTFSC STATUS,Z ; Zero flag will be clear if no error
GOTO IOQUIT ;
Exit if error
CALL EE_WR ;
Otherwise continue: write to current EERAM location
BSF PORTA,0 ;
Send RA0 high to signal byte successfully written
; Wait for ack from computer before fetching and writing the
next byte
CLRF CC ;
Set time-out counters
CLRF BB
WR_ACK BTFSC PORTB,1 ; Wait until RB1 input is high: this is ack from
PC
GOTO ACK_OK ;
If high, write the next byte
DECFSZ BB,1 ;
If still low, check if time-out occur
GOTO WR_ACK ;
If not timed-out, re-check for high on RB1
DECFSZ CC,1 ;
Otherwise, decement outer loop counter
GOTO WR_ACK ;
Continue reading if counter not zero
GOTO IOQUIT ;
Otherwise abort
; prepare to receive and write next byte
ACK_OK INCF EEADR,1 ;
Point to next EERAM address
DECFSZ BYT_CNT,1 ; Then check if bytes written = BYTES, if so: finish
GOTO WR_NXT ;
If not done, then get next byte to write
BCF PORTA,0 ;
Set RA0 output low before finishing (not essential)
IOQUIT BSF PORTB,2 ;
GOTO BOOTUP ;
All done
; Function to input a byte to PIC on RB1, starting with
least significant bit
BYT_IN MOVLW BITS ;
First, reload bit counter
MOVWF BIT_CNT
NXT_IN BSF PORTB,2 ;
Set RB2 high to signal PIC is ready for data
CLRF BB ;
Set time-out counter
B3_LO BTFSC PORTB,3 ; Main loop to monitor clock input (RB3) and keep
count
;
of the number of bits received.
GOTO B3_HI ;
If B3 is high, fetch bit on RB1 and process
NOP ; Lengthen time
allowed for RB3 to change
DECFSZ BB,1 ;
Check if 'time-out' occurred: if so, quit
GOTO B3_LO ;
Otherwise, keep checking RB3
RETLW 0x0F ;
If 'timed out', set error status and return
;
(write value hex 0F to W to signal error condition)
B3_HI MOVLW D'5' ;
Make sure RB3 stays high: debounce the input
MOVWF CC ;
Set debounce counter
DEBNC1 BTFSS PORTB,3 ; Check RB3 is still high
GOTO B3_LO ;
If not, go back and continue checking til high
DECFSZ CC,1 ;
Otherwise, keep cycling through debounce
GOTO DEBNC1
BCF PORTB,2 ;
RB3 input debounced: now set RB2 low to signal not ready for data
BCF STATUS,C ;
Clear carry bit in preparation for reading of RB1
BTFSC PORTB,1 ; Read received bit (on RB1)
BSF STATUS,C ;
Set carry bit if RB1 is high; otherwise, bit stays clear
RRF EEDATA,1 ;
Either way, shift the read bit right through EEDATA
CLRF BB ;
Set time-out counter
H_L1 BTFSS PORTB,3 ; Wait until RB3 input is low
GOTO DEC_BIT ;
If low, decrement bit counter and continue
DECFSZ BB,1 ;
If still high, check if time-out occur
GOTO H_L1 ;
If not timed-out, re-check for low on RB3
RETLW 0x0F ;
Otherwise flag error and abort
DEC_BIT MOVLW D'5' ;
First, debounce the input
MOVWF CC ;
Set debounce counter
DEBNC2 BTFSC PORTB,3 ; Check RB3 is still low
GOTO H_L1 ;
If not, go back and continue checking til low
DECFSZ CC,1 ;
Otherwise, keep cycling through debounce
GOTO DEBNC2
DECFSZ BIT_CNT,1 ; RB3 input debounced: Check if 8 bits received
GOTO NXT_IN ;
If not, fetch next bit
RETLW 0 ;
Otherwise return with W cleared
;***********************************************************************************************
; Routine to read contents of PIC to PC
PIC_RD CLRF EEADR ;
Set start address for read
CLRF CC ;
Clear general register used for checksum
RD_NXT CALL EE_RD ;
Read current EERAM address: result placed in EEDATA
MOVF EEDATA,0 ; Calculate checksum in CC via W
ADDWF CC,1
CALL BYT_OUT ;
Output the byte
SUBLW 0x5A ;
Check for error condition from BYT_OUT before outputing next byte
BTFSC STATUS,Z ; Zero flag will be clear if no error
GOTO IOQUIT ;
If error: exit now
INCF EEADR,1 ;
Point to next EERAM address
DECFSZ BYT_CNT,1 ; Then check if bytes read = BYTES, if so: finish
GOTO RD_NXT ;
If not done, then get next byte
MOVF CC,0 ;
If done, output checksum
MOVWF EEDATA
CALL BYT_OUT ;
(PC to check for output of 0xF0 to confirm success)
GOTO IOQUIT ;
All done: exit
; Function to output a byte on RB2, starting with most
significant bit
; Note, PC should wait a few microseconds after sending RB3
high before reading bit to ensure
; new bit has been placed on RB2. Data to be output must be
put in EEDATA by calling routine
BYT_OUT MOVLW BITS ;
First, reload bit counter
MOVWF BIT_CNT
RLF_BIT RLF EEDATA,1 ;
Prepare first/next bit for output: via Carry bit
BCF PORTB,2 ;
Set RB2 low as default output
BTFSC STATUS,C ; Output 1 or 0 mirroring value in 'Carry'
BSF PORTB,2 ;
Set bit output of RB2 if Carry bit was high
CLRF BB ;
Set 'time out' counter
CHK_RB3 BTFSC PORTB,3 ; Wait until RB3 input is high: means PC now
reading last bit
GOTO NXT_OUT ;
RB3 high: complete cycle & prepare next bit for output
DECFSZ BB,1
GOTO CHK_RB3 ;
Otherwise, keep checking RB3
RETLW 0x5A ;
If 'timed out', set error status and return
NXT_OUT CLRF BB ;
Set 'time out' counter
H_L2 BTFSS PORTB,3 ; Now check for next falling edge on RB3 (signals
previous
;
bit of data has been read.)
GOTO CHK_BIT ;
If low, get ready to output next bit (or exit)
DECFSZ BB,1
GOTO H_L2 ;
Otherwise, keep checking RB3
RETLW 0x5A ;
If 'timed out', set error status and return
CHK_BIT DECFSZ BIT_CNT,1 ; Now check if 8 bits have been output
GOTO RLF_BIT ;
Output next bit
RETLW 0 ;
Otherwise return with 0 in W
;***********************************************************************************************
; Functions to read and write EERAM
; Read function: requires user to place EERAM address in
EEADR prior to call. Results of read
; are put in EEDATA
EE_RD BSF STATUS,RP0 ;
Go to RAM page 1
BSF EECON1,RD ;
Instruction to read current EERAM address
BCF STATUS,RP0 ;
Go to RAM page 0; data is now in EEDATA register in page 0
RETURN ; [return is a
two cycle instruction]
; Write function: requires user to place EERAM address to
write in EEADR prior to call. User also
; responsible for disabling interupts prior to calling this
function. Data to be written is to
; be placed in EEDATA before calling this function.
EE_WR BSF STATUS,RP0 ;
first go to RAM page 1
BSF EECON1,WREN ;
Enable EERAM write
MOVLW 0x55 ;
Write cycle for EERAM
MOVWF EECON2
MOVLW 0xAA
MOVWF EECON2
BSF EECON1,WR
WR_ON BTFSS EECON1,EEIF ; Poll until write is completed
GOTO WR_ON ;
Keep looping until EEIF goes high
BCF EECON1,WREN ;
Once write has started, can disable EERAM write
BCF EECON1,EEIF ;
When done, clear EE write interupt flag
BCF STATUS,RP0 ;
Return to RAM page 0
RETURN ; Done!
;***********************************************************************************************
END ; end of code
Перейти:
/Главная/
CBuild/
JavaScript 1.2-5.6/
Delifi6/
I2C контроллеры/
AVR контроллеры/
ПЛИС/
AHDL/
VHDL/
LPT EPP/ LPT ECP/ PCI/ COM port/ I2C/ RS-232/
Используются технологии uCoz
|