Introduction: Introduction to 8051 Programming With AT89C2051 (Guest Starring: Arduino)

About: Passionate programmer by day, hardware hacker by night.

The 8051 (also known as MCS-51) is an MCU design from the 80's that remains popular today. Modern 8051-compatible microcontrollers are available from multiple vendors, in all shapes and sizes, and with a wide range of peripherals. In this instructable we will be looking at the AT89C2051 MCU from Atmel.

AT89C2051 is a small (2Kbyte Flash, 128byte RAM), cheap (~$1.40 per chip) microcontroller.
Features:

  • 2.7-6V operation
  • 15 I/O lines
  • 2 timers (16 bit)
  • Internal and external interrupts
  • UART
  • On-chip analog comparator
  • Up to 2MIPS with a 24MHz clock

Step 1: Requirements

Requirements:

  • Linux PC (required software: Arduino IDE, git, make, sdcc)
  • Arduino UNO
  • AT89C2051 chip (DIP20 package)
  • 20-pin ZIF socket
  • Optocoupler (preferably MOSFET-output)
  • Arduino prototyping shield
  • 12V power supply
  • 5V power supply
  • 16MHz crystal oscillator
  • 2x 30pF capacitor
  • 100nF capacitor
  • Diode (ex: 1N400X)
  • Resistors (1K, 3K3)
  • Protoboard
  • Jumpers
  • Copper wire

Check for required software:

which python3
which make
which sdcc
which git

Step 2: Building the Programmer

This section will be brief, as I built my programming shield some time ago. I've attached the schematic and pictures of the assembled board. The PDF of the schematic can be found in the repository.

You will have to program the programmer board:

1. Clone the repository.

git clone https://github.com/piotrb5e3/AT89C2051_programmer.git

2. Open AT89C2051_programmer/AT89_prog/AT89_prog.ino file in Arduino IDE.

3. Build and upload the sketch from the Arduino IDE.

Step 3: Installing Programmer Software

1. Create a python virtual environment.

python3 -m venv venv
. venv/bin/activate

2. Install at89overlord. at89overlord is an Open Source programmer for the AT89C2051 chip written by me.
It's source code can be found here.

pip install at89overlord

3. Verify installation.

at89overlord -h

Step 4: Programming the Chip

1. Clone a simple blink project.

cd ~
git clone https://github.com/piotrb5e3/hello-8051.git
cd hello-8051/

2. Build the application.

make

3. Connect Arduino to the PC, connect the 12V supply, place the AT89C2051 chip in the ZIF socket.

4. Locate Arduino's serial port.

ls /dev/tty*

5. Upload built IntelHex file to the chip. If your Arduino's port is different from /dev/ttyACM0 you have to pass the correct value with the -p command line parameter.

at89overlord -f ./hello.ihx

Step 5: Assembly

Assemble the circuit according to schematic. A PDF version can be found in the repository.

You should see the green LED flash with a frequency of around 0.5Hz.

Step 6: Code Explanation

#include <mcs51/at89x051.h>
#include <stdint.h>

We start by including the AT89X051 header from sdcc. It contains macros for interacting with registers as if they were variables. We also include stdint.h which contains definitions of uint8_t and uint16_t integer types.

// Assuming oscillator is 16MHz
#define INTERRUPTS_PER_SECOND 5208

An interrupt occurs when the Timer0 overflows. It's configured as a single 8bit timer, so this happens every 2^8 processor cycles. One processor cycle takes 12 clock cycles, and thus we arrive at 16000000/12/2^8 = 5208.33333.

volatile uint8_t led_state = 0;
volatile uint16_t timer_counter = INTERRUPTS_PER_SECOND;

We declare the led state control and interrupt counter variables.

void Timer0_ISR(void) __interrupt (1) {
    timer_counter--;
    if(timer_counter == 0) {
        led_state = !led_state;
        timer_counter = INTERRUPTS_PER_SECOND;
    }
}

Every time the Timer0 overflows the counter is decreased. If it's equal to zero it's reset, and the led state is changed. This occurs around once per second, resulting in ~0.5Hz LED blinking frequency.

int main() {
    TMOD = 0x3;     // Timer mode - 8bits, no prescaler. freq = OSCFREQ/12/2^8
    TL0 = 0;        // Clear counter
    TH0 = 0;        // Clear register
    TR0 = 1;        // Set timer to run.
    ET0 = 1;        // Set interrupt.
    EA = 1;         // Set global interrupt.
    while(1) {
        if (led_state) {
            P1 = 0xFF;
        } else {
            P1 = 0x00;
        }
    }
}

We configure the timer module and await changes in the led state control variable.
TMOD is the timer mode control register. TL0 and TH0 are Timer0 control registers. ET0 is the enable-timer0 bit in the timer control register (TCON). TR0 and EA are bits in the interrupt enable register (IE).

Step 7: Additional Resources

Arduino Contest 2017

Participated in the
Arduino Contest 2017