Currently I have two microcontrollers setup in which entire ports are connected to each other (P1.1 connected to P1.1, P1.2 connected to P1.2, etc). I also have two pairs of extra GPIO pins connected as signal lines.

What I want to achieve is a way to send and receive a byte in as little time as possible.

Let's assume that the master requests the slave to add 1 to a number and the slave responds:

Here's my code so far for the slave microcontroller:


jnb SLAVECMD,$  ;wait for command
mov SLAVEDATA,#0FFh ;tristate to allow input
nop             ;wait how many uS?
mov A,SLAVEDATA ;see what number came in
inc A ;add 1
mov SLAVEDATA,A ;produce result
setb SLAVEACK   ;send acknowledgement
jb SLAVECMD,$   ;wait till remote lowers comand line
clr SLAVEACK    ;clear acknowledgement
;transaction complete

And here's the code for the master:

MASTERDATA equ P0 ;Master's P0 connects to slave's P1
MASTERACK equ P3.0 ;Master's P3.0 connects to slave's P2.0
MASTERCMD equ P3.1 ;Master's P3.1 connects to slave's P2.1

mov MASTERDATA,#20h ;Set number to 32
setb MASTERCMD      ;tell slave to increment
jnb MASTERACK,$     ;wait until its done
mov MASTERDATA,#0FFh ;tristate port to allow input
nop                 ;delay by how many uS?
mov A,MASTERDATA    ;Get result here
clr MASTERCMD       ;tell slave were done
jb MASTERACK,$      ;wait until slave understands this

While I believe this code mostly works, I'm just not sure how long to make the program wait between the time the port pins are set to high and the time valid data is read on the pins.

If I don't wait at all, then I will get incorrect data. I believe it has to do with the FET's inside my AT89C4051 and AT89S52 that I am using but the manual does not indicate how long I should wait.

Both micros have the same crystals, capacitors and PCB track arrangements for the crystals and capacitors.

Each capacitor is 33pF ceramic

Each crystal is 22.1184Mhz which came out of the same package

Each PCB track in which the leads of the crystal are connected to is 1.9mm wide.

How do I calculate the minimum number of NOPs in my code so that valid data can be captured on the port pin after tristating it?

Also, because each micro has the same clock driving circuitry, could I replace the stalls (waiting for acknowledgements for example) with three nops? or will I still experience a minor clock drift?

  • \$\begingroup\$ You can't rely on two crystals having the exact same timing. Even two crystals from the same package. They will not be the exact same frequency. Crystals are pretty good, but not that good. Even atomic clocks aren't that good. \$\endgroup\$
    – user253751
    Nov 15, 2019 at 11:26

1 Answer 1


In general, you shouldn't be using timed waits at all. Rather, you should be using a handshake that guarantees that the events on the databus occur in the required order.

Those events are:

  • Master drives data bus
  • Master releases data bus
  • Slave drives data bus
  • Slave releases data bus

Unfortunately, only two additional signals is not enough to manage this process for a bidirectional bus. You'll need at least one other signal connected between the two processors. There are a number of ways you could use such a signal. One of the simplest is to treat it as a read/write signal, controlled by the master CPU.

The transaction would then go something like this.

  1. Master drives data bus, sets read/write low (write) , then asserts the CMD signal.
  2. Slave observes CMD asserted, reads the read/write signal, and then reads data bus and then asserts ACK.
  3. Master observes ACK asserted, tristates the data bus, then negates CMD.
  4. Slave observes CMD negated, and negates ACK.

Note that if the slave is busy with something else when the master starts the transaction, it simply delays asserting ACK in step 2. The master waits as long as necessary.

To transfer the result:

  1. Master leaves data bus tristated, sets read/write high (read), then asserts the CMD signal.
  2. Slave observes CMD asserted, reads the read/write signal. It then drives the result onto data bus and asserts ACK.
  3. Master observes ACK asserted, reads the data bus, then negates CMD.
  4. Slave observes CMD negated, tristates the data bus and negates ACK.

Note that if the slave requires some time to compute its result, it simply delays asserting ACK in step 6, and the master will simply wait as long as needed.

  • \$\begingroup\$ I guess I'll have to go with using a bi-directional nibble bus since you illustrated the need for three control signals \$\endgroup\$ Nov 5, 2018 at 19:42

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.