Simply treat the 64/65 bit buffer as a Byte or Word Array... Shift it out using the pointers I've given you here...
http://www.picbasic.co.uk/forum/showthread.php?t=544
Simply treat the 64/65 bit buffer as a Byte or Word Array... Shift it out using the pointers I've given you here...
http://www.picbasic.co.uk/forum/showthread.php?t=544
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.
HTH,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
Last edited by Darrel Taylor; - 10th September 2008 at 12:00. Reason: added ANSELH = 0, and X looop var
DT
Thank you all for the tips. Well, Darrel, it is more than a starting point. It is almost done! Thanks a lot. Also, yes 64 bit is OK. I stuck on 65 for some reason...
Soon I will post the results.
Ioannis
Just made a couple changes. I used the same loop var in the interrupt handler. DOH!
Changed it to X, was I.
Also turned off the upper A/D ports.
ANSELH = 0
2 less bugs anyways.
<br>
DT
One more bug. On the main the first If/Then needs a gosub.
I have to admit that your writing style is very clever. Especially I liked the handling of AD inputs with the OR statement. Very clever indeed!
Thanks again!
Ioannis
Edit: Another bug would be the channel selection of A/D module. Since the 883 does not have 5,6 and 7 channel available, it cannot be used as it is the program. Of course it works as is for the bigger cousins 884 and 887.
Last edited by Ioannis; - 10th September 2008 at 22:18.
Ahhh, yes it does. Good catch.
DOH!Another bug would be the channel selection of A/D module. Since the 883 does not have 5,6 and 7 channel available, it cannot be used as it is the program. Of course it works as is for the bigger cousins 884 and 887.
I wish they'd make the datasheets individually. A separate one for each of the 882/883/884/886/887. Instead of jamming a whole series in one sheet so you have to pick out the differences on your own.
OK, there's still more than 8 A/D's in there, I'll have to find a workaround.
Unless you beat me to it.
<br>
DT
Moved pins away from the RB1 - RB3 (AN8 - AN10).
Added GOSUB you found.
Modified A/D channel selection.
Sure wish I had one of these chips. BTW, will you be using a different chip?
Code:'**************************************************************** '* Name : Shift4021.pbp * '* Author : Darrel Taylor * '* Date : 9/9/2008 * '* Version : 1.1 * '* 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.4 ; Serial Clock SerInPin VAR PORTB.5 ; Serial Input Pin SerOutPin VAR PORTB.6 ; 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 ADchannel VAR BYTE ; Actual AD ch being used (5,6,7 missing) 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 = %00000111 ; Turn off upper A/D ports (8,9,10 used) INTF = 0 ; clear INT flag INTE = 1 ; enable INT interrupt ON INTERRUPT goto ParallelLoad ;--------------------------------------------------------------------------- Main: if !GoDone then GOSUB 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 ADchannel = ADidx if ADidx > 4 then ADchannel = ADchannel + 3 ; correct for missing AN 5,6,7 endif ADCON0 = %10000001 | (ADchannel << 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
DT
Bookmarks