I have an AT89S52 and an AT89C4051 microcontroller (both in the 8052 family) in which the bit lines of the data bus, one control pin and one status pin are connected together. In code, the data bus is labelled "D", the status pin is labelled "ACK" and the control pin is labelled "ACT".
The AT89S52 does many tasks, it cannot afford to hold up other tasks over data transfer to the AT89C4051.
The AT89C4051 is ok with putting everything else on hold when it communicates with the AT89S52.
My code for processing one byte from the AT89C4051 to AT89S52 is as follows:
uCdat: mov D,A ;Prepare to send one byte clr ACT ;Send one byte now jb ACK,$ ;Wait until remote received it mov D,#0FFh ;Tristate bus setb ACT ;Tell remote were ready jnb ACK,$ ;Wait until remote has data mov A,D ;Read result ret
It simply takes the value of the local accumulator, sends it down to AT89S52 and waits until AT89S52 has a response then its stored back in the local accumulator. This is perfect for the AT89C4051 but not for the AT89S52 since its a busy microcontroller.
I made the following code as an attempt to receive a set of data from the AT89C4051 to memory and send code back. I feel I have to do one byte at a time back and forth and the direction in which data is sent is the level of the ACT and ACK lines.
The local memory format is as follows.
data at start address of REQMEM represents number of data bytes to follow and can be any value from 0 to 15.
So if REQMEM = 2, then REQMEM+1 = 1st byte of data and REQMEM+2 = 2nd (and last) byte of data.
I'd like to know if this code can be simplified, but still can be run asynchronously. This function will be called very frequently from the busy AT89S52.
miniuCdat: ;UCIO=memory bit for data direction: 0=incoming, 1=outgoing jb UCIO,noucinc ;mode here is accept data... jb ACT,noUdat ;...only if remote lowered ACT line mov D,#0FFh ;tristate data line setb UCIO ;change mode to "send result" mov A,D ;get a byte from remote clr ACK ;tell remote we got byte ;REQRES=memory bit to know what were doing. ;REQRES: 0=requesting data. 1=sending result jb REQRES,noUdat ;here we store data into local request memory (REQMEM) mov @R0,A cjne R0,#REQMEM,noUCs ;We are on byte 1 which is length of data anl A,#0Fh ;make length 15 bytes max mov R2,A inc R2 ;make counter = length + 1 noUCs: inc R0 ;go to next byte in REQMEM djnz R2,noUCe ;here the length went back to 0, so reset pointer mov R0,#REQMEM noUCe: noUdat: ret noucinc: ;Here we are sending a 1-byte response back... jnb ACT,noUdat2 ;...only if remote raised the ACT line mov A,@R1 ;Load byte from memory jb REQRES,noUdat2b ;If we are requesting data clr A ;Make zero as the result noUdat2b: mov D,A ;Send result out to data line setb ACK ;Tell remote we sent data out clr UCIO ;switch mode to "accept data" jnb REQRES,noUdat2 cjne R1,#REQMEM,noUCs2 ;Again, 1st byte is length anl A,#0Fh mov R3,A inc R3 noUCs2: inc R1 djnz R3,noUCe2 mov R1,#REQMEM ;Go to beginning of ram if all bytes are processed noUCe2: noUdat2: ret