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:

      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

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.

  ;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
        inc R0 ;go to next byte in REQMEM
        djnz R2,noUCe
          ;here the length went back to 0, so reset pointer
          mov R0,#REQMEM
  ;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
    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
      inc R1
      djnz R3,noUCe2
        mov R1,#REQMEM ;Go to beginning of ram if all bytes are processed
  • \$\begingroup\$ The question can use some more context, like app-level protocol (i.e. how and when the function is called), required data rate, and (in)ability to use interrupts. \$\endgroup\$ – vnp Nov 7 '18 at 2:35

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.