MCS-51

Tutorials

EX-F320

LED Timer
Serial

C8051F340/380

LED Timer
Serial

C8051F V2.1 (F020)

LED Timer
Serial

C8051F300 Dev. B. Mod.

LED Timer
Serial

C8051F V2.1 (F120)

LED Timer
Serial
Dhrystone

51 MCU SCM

Serial

STC89 DEMO BOARD

LED Timer
Serial

EZ-USB FX2LP

LED Timer
Serial
Dhrystone

colecovision.eu

ColecoVision

STM8

MCS-51

LLVM+SDCC

Contact

Getting started with MCS-51 development using free software: Serial output on the C8051F020

This short tutorial is about serial output on the C8051F V2.1 with an C8051F020 presenting a simple "Hello World" program. Boards are widely available via different channels. The one used here was bought on ebay. The author used a Debian GNU/Linux system, but the tutorial should work for other Linux distributions, *BSD or other Unices.

The tools we use are

Hardware setup

C8051F V2.1 board with Demo running

The C8051F V2.1 board is connected to the host computer via a U-EC6 to write the demo onto the board, while power is supplied via an extra cable. For serial ouput we attach a serial cable to the RS232 header.

Get SDCC

Depending on your operating system there might be an easy way to install SDCC 3.5.0 or newer using a package system or similar (e.g. apt-get install sdcc on Debian). While SDCC 3.4.0 should be sufficient for this tutorial, you might want to try a newer version in case you encounter any bugs.

SDCC binaries or a source tarball can be downloaded from its website.

Get ec2writeflash

ec2writeflash is part of the ec2-new package. The ec2-new source can be found at its GitHub location, where there is also a download link for a zip archive of the sources. To compile it, a C compiler, such as gcc, autotools and some necessary libraries need to be installed. Unzip the archive (e.g. using unzip stm8flash-master.zip) change into the directory stm8flash-master and type autoreconf; automake --add-missing; libtoolize; autoreconf; ./configure && make. In case there are any errors, such as header files not found, check that all necessary libraries are installed.

The Demo

We present a simple Demo that repeatedly outputs "Hello World!", once per second. Since the uncalibrated internal oscillator of the C8051F020 is not accurate enough for serial RS232 I/O, we need to use the external 22.1184 Mhz crystal of the C8051F V2.1 board. Here is the C code:

// Source code under CC0 1.0
#include <stdbool.h>
#include <stdio.h>

#include <C8051F020.h>

volatile unsigned long int clocktime;
volatile bool clockupdate;
volatile bool external_clock;

void clockinc(void) __interrupt(1)
{
	if(!external_clock)
	{
		TH0 = (65536 - 167) / 256;
		TL0 = (65536 - 167) % 256;
	}
	else
	{
		TH0 = (65536 - 1843) / 256;
		TL0 = (65536 - 1843) % 256;
	}
	clocktime++;
	clockupdate = true;
}

unsigned long int clock(void)
{
	unsigned long int ctmp;

	do
	{
		clockupdate = false;
		ctmp = clocktime;
	} while (clockupdate);
	
	return(ctmp);
}

int putchar(int c)
{
	while(!(SCON0 & 0x02));
	SCON0 &= ~0x02;
	SBUF0 = c;
	return (c);
}

unsigned char _sdcc_external_startup(void)
{
	// Disable watchdog timer
	WDTCN = 0xde;
	WDTCN = 0xad;

	return 0;  // perform normal initialization
}

void main(void)
{
	unsigned long int oldclock;

	// Initialize I/O pins
	XBR0 = 0x04;
	XBR2 = 0x40;
	P0MDOUT= 0x01;

	// Configure timer for 2 Mhz default SYSCLK
	// 1000 ticks per second
	external_clock = false;
	TH0 = (65536 - 167) / 256;
	TL0 = (65536 - 167) % 256;
	TMOD = 0x01;
	IE |= 0x82;
	TCON |= 0x10; // Start timer

	// Switch to external crystal oscillator
	OSCXCN = 0x67;
	oldclock = clock();
	while(clock() - oldclock < 3);
	while(!(OSCXCN & 0x80));
	OSCICN = 0x08;

	// Configure timer for 22.1184 Mhz SYSCLK
	// 1000 ticks per second
	external_clock = true;

	// Configure UART for 9600 baud, 8 data bits, 1 stop bit.
	TMOD = 0x21;
	SCON0 = 0x40;
	TH1 = 250;
	TCON |= 0x40;
	SCON0 |= 0x02;		

	for(;;)
	{
		oldclock = clock();

		printf("Hello World!\n");

		while(clock() - oldclock < 1000); // Wait 1s.
	}
}

SDCC is a freestanding, not a hosted implemenatation of C, and allows main to return void. In SDCC up to SDCC 3.6.0 putchar() used to return void. This is not standard compliant and was changed to int in current SDCC versions. The printf() from the standard library uses putchar() for output. Since putchar() is device-specific we need to supply it. In this case we want it to output data using UART0.

The demo can be compiled simply by invocing sdcc using sdcc -mmcs51 --std-c99 serial.c assuming the C code is in led.c. The option -mmcs51 selects the target port (mcs51). An .ihx file with a name corresponding to the source file will be generated.

Put the demo onto the board

Assuming the board is connected to a U-EC6 attached via USB, ec2writeflash --port USB --hex serial.ihx --run will write the demo onto the board. You can see the "Hello world" by attaching a serial cable to the DB9 connector on the RS232 board, and using a terminal program configured for 9600 baud, no parity, 8 bits, 1 stop bit and no flow control.


More about ec2writeflash

ec2writeflash is part of ec2drv once written by Ricky White. Since ec2drv is no longer maintained, we use the version from the ec2-new fork.

More about SDCC

SDCC was initially written by Sandeep Dutta for the MCS-51, and has a relatively conservative architecture (see Sandeep Dutta, "Anatomy of a Compiler", 2000). It has been extended by various contributors and more recently, incorporated some cutting-edge technologies, in particular in register allocation (see Philipp Klaus Krause, "Optimal Register Allocation in Polynomial Time", 2013 and "Bytewise Register Allocation", 2015). However the mcs51 backend does not have all the fancy features and optimizations that some newer backends have.

SDCC is a C compiler that aims to be compliant with the C standards.

Important compiler options for MCS-51 developers include: