I'm trying to do a direct two-way communication between two AT89C2051 microcontrollers with only two GPIO pins so that I have other GPIO lines free for other tasks.
P3.7 is the data wire, and P3.2 (INT0) is the control wire, and they are externally pulled high to VCC (of 5 volts) through 10K resistors.
One microcontroller has an 18.432Mhz crystal connected to it so I can connect it to my computer at a clean 9600bps baud. The other microcontroller is connected to a 20Mhz crystal (which is the highest speed lowest-priced compact crystal I ordered from the internet) for fast memory and wireless communication.
Initially I was going to reserve 4 GPIO pins for data communication but I wouldn't have any free for other tasks such as memory and LED manipulation.
This is my idea behind the two wires.
The sender loads P3.7 with the one bit and then sends P3.2 low then waits a bit for remote processing. This repeats until the whole byte is sent.
When the receiver receives data, the interrupt is supposed to be executed (from the remote sender making P3.2 low) and the byte received from P3.7 is stored in a temporary location until all bytes are received which a counter tracks. Once all are received, a flag is set.
The sending seems to be ok, but the receiving always stalls.
Do I need to adjust my timings or is there a better approach of doing half-duplex bi-directional communication with only two wires connected to the same pins (with pull-up resistors) on both micros?
Here is my code for reference. I have to remove the first line of code after programming the first chip to ensure the correct code is on each chip.
UNIT equ 1h ;1 = 8051 to interface to PC, 0 = 8051 to interface to radio.
RDATS EQU 40h ;remote data temp
RDAT EQU 42h
RDATCT EQU 41h
RDI EQU 0h ;remote-data-interrupt bit
CT EQU 1h ;carry temp - receive
CTS EQU 2h ;carry temp - send
org 0h
ljmp main
;INT 0 natural address is here (03h)
ljmp intZ
org 002Bh
;called
intZ:
clr EX0
ifdef UNIT
clr P3.4 ;This is supposed to execute on 8051 connected to PC but does not.
endif
mov CT,C
push ACC
mov C,P3.7
mov A,RDATS
RLC A
mov RDATS,A
inc RDATCT
mov A,RDATCT
cjne A,#8h,no8
setb RDI
mov RDAT,RDATS
mov RDATCT,#0h
no8:
jnb P3.2,$
pop ACC
mov C,CT
ifdef UNIT
setb P3.4
endif
setb EX0
reti
sendrdat:
clr EX0
mov CTS,C
mov R7,#8h
push ACC
sendrmore:
clr C
rlc A
mov P3.7,C
clr P3.2
nop
nop
setb P3.2
djnz R7,sendrmore
pop ACC
mov C,CTS
setb EX0
ret
serialin:
clr RI
jnb RI,$
mov A,SBUF
ret
serialout:
clr TI
mov SBUF,A
jnb TI,$
ret
pserial:
rewr:
clr A
movc A,@A+DPTR
jz exl
acall serialout
inc DPTR
ajmp rewr
exl:
ret
main:
mov RDAT,#0h
mov RDATS,#0h
mov RDATCT,#0h
clr RDI
mov P3,#0FFh
mov P1,#0FFh
mov SP,#50h ;skip most ram so SP doesnt be wrecked
mov scon,#50h
mov tmod,#020h
mov 087h,#80h ;pcon.7
mov TH1,#0F6h ;9600 baud on 18.432Mhz
setb EX0
setb EA
setb TR1
IFDEF UNIT
ajmp PCmode
ELSE
ajmp RADmode
ENDIF
;branch
PCmode:
clr RI
jnb RI,$
mov DPTR,#ptest1
acall pserial
;send 0AAh to remote 8051
mov A,#0AAh
acall sendrdat
mov DPTR,#ptest2
acall pserial
; code stalls here forever.
; It should only stall until remote 8051 calls this one.
rwait:
nop ;no overloading processor
jnb RDI,rwait
;RDAT = remote byte received
mov A,RDAT
push ACC
mov DPTR,#ptestr
acall pserial
pop ACC
acall serialout
mov A,#0Dh
acall serialout
mov A,#0Ah
acall serialout
mov DPTR,#ptestdone
acall pserial
sjmp $
RADmode:
;radio mode... only obey commands at this time
nop
jnb RDI,RADmode
clr RDI
mov A,RDAT
cjne A,#0AAh,nosig ;AAh=get signature = 41h (A)
mov A,#041h
acall sendrdat
nosig:
ajmp RADmode
sjmp $
ptest1:
db 'Sending data to unit 2...',0Dh,0Ah,00h
ptest2:
db 'Receiving data from unit 2...',0Dh,0Ah,00h
ptestr:
db 'Received: ',00h
ptestdone:
db 'This is a test that worked!',0Dh,0Ah,00h
END