I was just trying to visualize what it would take ...
But it seems to have turned into a whole program.
And yup, it uses Melanie's suggestions. 
The idea here is to continuously scan the A/D inputs, saving the results to a buffer array.
When it gets a Parallel Load signal (INT), it copies the buffer to the "Shift" array.
Instead of taking the time to actually shift everything each time, it uses an Index counting down from 63 to put each bit out on the pin.
Each bit that is sent, gets replaced with the Input Bit. After it's finished sending all 64 bits, it wraps around and is now sending the data that was shifted IN like a big circular buffer.
It's written for a 16F883, because it has 8+ A/D inputs and an internal 8mhz OSC, but it should work on other chips too (after changing a few things).
I do not have a 16F883, or a CD4021, so this is completely untested.
It does compile, and I think it's close. Should at least be a good starting point.
Code:
'****************************************************************
'* Name : Shift4021.pbp *
'* Author : Darrel Taylor *
'* Date : 9/9/2008 *
'* Version : 1.0 *
'* Notes : Target = 16F883, Internal 8mhz OSC *
'* Thread : Slave PIC to be used like CD4021 chip *
'* http://www.picbasic.co.uk/forum/showthread.php?t=9544 *
'****************************************************************
@ __config _CONFIG1, _INTOSCIO & _WDT_OFF & _LVP_OFF & _CPD_OFF
DEFINE OSC 8
Clear
PloadPin VAR PORTB.0 ; Parallel Load (INT)
ClkPin VAR PORTB.1 ; Serial Clock
SerInPin VAR PORTB.2 ; Serial Input Pin
SerOutPin VAR PORTB.3 ; Serial Output Pin
ADbuff VAR BYTE[8] ; Buffers the A/D readings
ShiftReg VAR BYTE[8] ; The 64-bit shift register
I VAR BYTE ; Index variables
X VAR BYTE
BitIdx VAR BYTE
ADidx VAR BYTE
ClkState VAR BIT ; for locating clk edges
DataBit VAR BIT ; Serial In read on falling edge
INTE VAR INTCON.4 ; Aliases
INTF VAR INTCON.1
GoDone VAR ADCON0.1
;---------------------------------------------------------------------------
Initialize:
OSCCON = %01110001 ; Internal 8Mhz OSC
INPUT PloadPin ; Input(default), just to make sure
INPUT ClkPin
INPUT SerInPin
LOW SerOutPin ; start with output LOW
ADCON0 = %10000001 ; FOSC/32, CH0, ADON
ANSELH = 0 ; Turn off upper A/D ports
INTF = 0 ; clear INT flag
INTE = 1 ; enable INT interrupt
ON INTERRUPT goto ParallelLoad
;---------------------------------------------------------------------------
Main:
if !GoDone then NextAD ; conversion complete, get results
IF ClkPin then ; wait for Rising edge
if !ClkState then
ClkState = 1
GOSUB NextBit ; Rising edge found, shift data
endif
else ; wait for falling edge
if ClkState then
ClkState = 0
DataBit = SerInPin ; falling edge found, read input
endif
endif
GOTO Main
; ---- Cycle thru each A/D channel, one at a time --------------------------
NextAD:
ADbuff(ADidx) = ADRESH ; save A/D result
ADidx = ADidx + 1 ; point to next A/D channel
if ADidx = 8 then ADidx = 0 ; circle around
ADCON0 = %10000001 | (ADidx << 2) ; Set the A/D ch.
for I = 1 to 5 ; Acquisition time
@ NOP
NEXT I
GoDone = 1 ; Start A/D conversion
RETURN
DISABLE
; ---- Parallel Load -- copy A/D buffer to Shift register ------------------
ParallelLoad:
For X = 0 to 7 ; Copy A/D results
ShiftReg(X) = ADbuff(X)
NEXT X
SerOutPin = ShiftReg.0(63) ; put MSB on Pin
BitIdx = 63 ; start shifting from MSB
DataBit = SerInPin ; read input bit
INTF = 0 ; clear the interrupt flag
RESUME
; ---- Put next bit on the output pin --------------------------------------
NextBit:
ShiftReg.0(BitIdx) = DataBit ; replace bit with the input data
BitIdx = BitIdx - 1 ; point to next bit
if BitIdx.7 = 1 then BitIdx = 63 ; circle back to beginning
SerOutPin = ShiftReg.0(BitIdx) ; put data on output Pin
return
HTH,
Bookmarks