STC89C I/O Ports push-pull

The (English) datasheet contains Chapter 4, which explains how the I/O ports work as standard in the traditional 8051 way: so-called ‘quasi-bidirectional’. In this mode, when a ‘1’ is written to a port bit, the I/O floats high, with a weak pull-up resistor, and external devices are able to pull the pin low, so the port can work as both an output and an input. If you’re using the pin as an output, say to drive an LED, then the pin can only sink current (or source current very weakly); and to use the pin as an input, say a momentary push button that connects it to GND, your program has to write a ‘1’ to that I/O and then read the same I/O to see if the button is pressed and pulling the pin low.

The datasheet describes (sections 4.2 – 4.4) how the I/O can be reconfigured into one of three other modes: push-pull output, input-only, or open-drain output. However, nowhere (as far as I can see) does it explain how to actually configure the microcontroller into these other modes. Certainly, the newer STC devices, like the STC8, can be configured to do this, as I explain below. My experiments, so far, seem to indicate that the STC89 can’t, and the datasheet is a misleading fiction, where the whole of chapter 4 has just been cut-and-pasted from the datasheets that really apply to the newer microcontrollers in the STC range.

How it works on the STC8

Let’s consider Port 1 as an example. The STC8 has the usual port sfr (special function register), P1 at location 0x90, but it also has two other sfrs, P1M1, and P1M0, at locations 0x91 and 0x92 respectively. You can control the mode of each I/O bit individually, but to keep it simple, let’s say you want to configure all eight bits of the port in the same mode: these are the values you’d write to the P1M1 and P1M0 registers:

Push-pull output0x000xFF
Input only0xFF0x00
Open-drain output0xFF0xFF

Of course, there are corresponding PxM1 and PxM0 registers for each of the I/O ports.

Now if the STC89 family also had configurable I/O, we’d expect it to have the appropriate sfrs (possibly at different addresses to the STC8 ones), but if we look at the STC89C51RC-RD-en datasheet, section 5.1, we find that P1 is located at the same 0x90 address, but that 0x91 and 0x92 are just blank. I wrote a program that assumed P1M1 and P1M0 were at those addresses, and tested it, but the port just remained in the standard quasi-bidirectional mode. Here’s my test program (for SDCC):

// test whether STC89 can actually do push-pull, etc. or if the datasheet is just wrong

#include <8052.h>

__sfr __at (0x91)  P1M1; // these are the addresses for the STC8, following P1 at 0x90.
__sfr __at (0x92)  P1M0; // the STC89 datasheet has P1 at the same 0x90 address, but nothing at 0x91, 0x92

void delay(unsigned int ms) { // delay approximiately ms milliseconds
  unsigned int i;
  while (ms--) {
    for (i = 0; i < 230; i++) { // 230 seems about right for 6T (fast) mode

void main(void) {
  P1M0 = 0xAA;
  P1M1 = 0xF0; // this (should) give P1.0/1 as quasi-bidirectional; P1.2/3 as push-pull; P1.4/5 as input only; P1.6/7 as open-drain output
  while (1) {
    P1 = 0x00; // all port bits low
    P1 = 0xFF; // all port bits high
    delay(500); // roughly one-second cycle
    // result - it doesn't work - all 8 outputs work in quasi-bidirectional mode, where they can pull low hard and only pull high weakly

And here’s the resulting ihx (hex) file.


If anyone has any more information on this topic, maybe confirmation that I’m right, or the actual addresses for P1M1 and P1M0 on the STC89 if they do exist, I’d be grateful if they’d leave some comments.


Leave a Reply

Your email address will not be published.