PDA

View Full Version : Slave PIC to be used like CD4021 chip



Ioannis
- 9th September 2008, 22:21
This is a little weird but, has anyone used a PIC as a slave device like the 4021 PISO (Parallel Input Serial Output)?

I am trying to use some 4021 as Digital inputs and also get some analog values (8) and all read by the master controller through a Shiftin command.

The idea is to use a 65 bit buffer, 64 bits for the 8x8bit analog values, and 1 bit for the input of the device, so other can connect on the bus, like another 4021 or another 8 analog input device.

My main problem is how to shift the 65 bit array (preferably not in assembly...).

Thanks,
Ioannis

skimask
- 10th September 2008, 00:37
I don't see why it wouldn't work...as long as the PIC was clocked fast enough for you...
I don't quite see what you're getting at as far as hardware though...
Are you going to use a large PIC to get 64/65 bits and then shift them out, or the other way around?
Could you draw up a rough block diagram?

Charles Linquis
- 10th September 2008, 02:14
I have done what you describe. The "shifting" was done using SEROUT2 and SERIN2. The "master" PIC sent out 4 bytes of data (in my case) and the "slave" took the bytes
and loaded them into a buffer. The data was followed by a checksum byte. If the checksum matched, the data was written to the port pins. I used a second wire between the two PICs to act as an ACK to indicate a successful trasmission (a pulse LOW was proof that the data got to the slave). The data rate was 19.2 kbaud. Crystals were used on both parts. I used open-collector drive on both lines and 2K pull-ups. The PICs were 6' or so apart.

skimask
- 10th September 2008, 02:25
So, this might be something like an 18F8723, grabbing 64 bits worth of digital data from the various ports and funneling it out the serial port? A 64bit, single chip PISO?

Charles Linquis
- 10th September 2008, 03:46
You apparently are aware of my "chip of choice"!

skimask
- 10th September 2008, 04:26
You apparently are aware of my "chip of choice"!
Started off with the 'broken' 8720, moved up along the way as they've came out.
http://web.ndak.net/jdgrotte/tqfp6480adapter/tqfpadapter.html
Use it a lot, especially when I need to write 'sloppy' code with a lot of debugging type info. I use the extra pins for LEDs, LCDs, switches, etc.
Later on, clean up the code, get it down to size and put it on a 40 pin version of the '8723 (i.e. 18F452/4620/4685, whatever). Have a few of a second version that'll allow the '8723 to plug into a 28-pin socket. Same principle applies.
Very few code changes required as long as I don't use an '8723 specific module or function.

Darrel Taylor
- 10th September 2008, 04:42
Now I read Ioannis' post very different.

I think the idea looks something like this ...

http://www.darreltaylor.com/files/4021_PIC.GIF

Where the PIC would have a 64-bit shift register, derived from 8 analog inputs, with a serial IN and OUT pin that would make it PART of a long chain of shift registers.

Anywhere close Ioannis?
<br>

Ioannis
- 10th September 2008, 07:26
Hi Boys.

I am sorry Skimask I did not put a schematic or something but was home, late night.

Darrel, that was exaclty the idea and setup! I may say that except you are reading posts very clearly, I think you read minds too!

Charles, your idea is really the oposite of this. And very dependent on the clock. With the circuit that I would post, but Darrel got me, as always he is one step ahead, there is no critical timing needed.

So the PIC would need a 65 bit buffer to store the 64 bits of the analog values and 1 bit for the previous PISO device. This is not limited to one previous of course. PIC does not know what is before it. It just puts on Sout pin the data of its buffer. The buffer fills from the 8 analog and after that, with the Sin data as arrive on each Clock of the relative pin.

It looks like RS232 serial communication but is not RS232. It is just serial 8 bit data transfer without start-stop bits and sychronous relative to the Clock line.

The point for my difficulty is to shift in PBP the 65 bit buffer.

Ioannis

P.S. Sorry for the long post...

Melanie
- 10th September 2008, 09:57
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

Darrel Taylor
- 10th September 2008, 10:29
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.


'************************************************* ***************
'* 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,

Ioannis
- 10th September 2008, 10:43
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

Darrel Taylor
- 10th September 2008, 11:03
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>

Ioannis
- 10th September 2008, 21:10
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.

Darrel Taylor
- 10th September 2008, 21:54
One more bug. On the main the first If/Then needs a gosub.
Ahhh, yes it does. Good catch.


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.
DOH!

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. :o

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>

Darrel Taylor
- 10th September 2008, 22:26
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?

'************************************************* ***************
'* 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

Ioannis
- 11th September 2008, 07:58
Thank Darrel. You tempted me to use the new 88x series as I am used to the old 87x ones. But I had a look over the 16F690 and I think is the best for the job and cheaper too. It has the RS-Flip Flop also for anyone willing to do Touch sensors for buttons.

Thanks for the efforts very much.

Ioannis

Darrel Taylor
- 11th September 2008, 09:35
16F690!

Dang it, don't have one of those either.
I really need to expand my inventory.

Looks like it'll do the job for sure.
Hope it all works out.

DT

Ioannis
- 11th September 2008, 12:34
Thanks again. You are #1!

Ioannis