UMBC CMSC 391 -- Programming Microcontrollers  


General Serial Data Communications

There are specialized IC chips known as Universal Asynchronous Receiver Transmitters (UART) that handle the task of converting an 8-bit parallel data byte to a 10-bit serial stream as well has converting the 10-bit stream back to 8-bit data. It is now built into the 8051 as port pins 3.0 (RXD and 3.1 (TXD) To send you send data into the SBUF register, to receive, you read from from the SBUF register, well, sort of. The SPFs PCON (controls data rates), SCON (controls data communications), and TMOD (controls the timers) have to be initialized properly first.

When the 8051 is powered on or rest, the following code (relevant to to serial I/O) gets called:


;initialize the serial port, auto baud detect if necessary
	acall	autobaud	;set up the serial port
	;mov	a, th1
	;lcall	phex
So in turn, we get sent down to:
;to do automatic baud rate detection, we assume the user will
;press the carriage return, which will cause this bit pattern
;to appear on port 3 pin 0 (CR = ascii code 13, assume 8N1 format)
;
;	       0 1 0 1 1 0 0 0 0 1
;	       | |	       | |
; start bit----+ +--lsb	  msb--+ +----stop bit
;
;we'll start timer #1 in 16 bit mode at the transition between the
;start bit and the LSB and stop it between the MBS and stop bit.
;That will give approx the number of cpu cycles for 8 bits.  Divide
;by 8 for one bit and by 16 since the built-in UART takes 16 timer
;overflows for each bit.  We need to be careful about roundoff during
;division and the result has to be inverted since timer #1 counts up.  Of
;course, timer #1 gets used in 8-bit auto reload mode for generating the
;built-in UART's baud rate once we know what the reload value should be.


autobaud:
	mov	a, #baud_const	;skip if user supplied baud rate constant
	jnz	autoend_jmp
	mov	a, baud_save+3	;is there a value from a previous boot?
	xrl	baud_save+2, #01010101b
	xrl	baud_save+1, #11001100b
	xrl	baud_save+0, #00011101b
	cjne	a, baud_save+2, autob1
	cjne	a, baud_save+1, autob1
	cjne	a, baud_save+0, autob1
autoend_jmp:
	ajmp	autoend

autob1: ;wait for inactivity

PCON is the Power Mode Control SFR, but only two bits are used for power control. (3 bits are not even used!) Bit 7 (SMOD) is the Serial baud rate modify bit. Set to 1 by program to double baud rate using timer 1 for modes 1, 2 and 3. Cleared to zero by program to user timer 1 baud rate. PCON is not bit addressable. MOVing a value into PCON is not a problem when turning on the 8051 because there is no valid data in any bit at this time, however, at other times, it would be better to ORL the bit to set the bit.

	mov	pcon, #0x80	;configure uart, fast baud

SCON is the Serial Port Control SFR. It is a bit more complex, and its components are:

BitSymbol
7 SM0
6 SM1
5 SM2
4 REN
3 TB8
2 RB8
1 TI
0 RI
SM0 and SM1 combined control the mode, as described in the following table:
SM0SM1 Mode Description
00 0 Serial data enters and exits through RXD. TXD outputs the shift clock. 8 bits are transmitted/received (LSB first). The baud rate is fixed at 1/12 the oscillator frequency.
01 1 10 bits are transmitted through TXD or rceived through RXD: a start bit (0), 8 data bits (LSB first) and a stop bit (1). On receive the stop bit goes into RB8 (SCON.2). The baud rate is variable.
10 2 11 bits are transmitted trough TXD or eceived through RXD: start bit(0), 8 data bits (LSB first), a programmable 9th data bit, and a stop bit(1). On Transmit, the 9th data bit (TB8) in SCON) can be assigned the value of 0 or 1. Or, for example, the parity bit (P, in the PSW) could be moved into TB8. On receive, the 9th data bit goes into RB8 in SCON, while the stop bit is ignored. The baud rate is programmable to either 1/32 or 1/64 the oscillator frequency.
11 3 11 bits are transmitted through TXD or recieved through TRXD: a start bit (0), 8 data bits (LSB first), a programmable 9th data bit and a stop bit (1). In fact, Mode 3 is the same as Mode 2 in all respects except baud rate. The baud rate in Mode 3 is variable.
The Phillips manual states: "In all four modes, transmission is initiated by any instruction that uses SBUF as a destination register. Reception is initiated in Mode 0 by the condition RI = 0 and REN = 1. Reception is initiated in the others modes by the incoming start bit if REN = 1."

Only the bit SM2 has not been describred. It is the multiprocessor communications bit.


	mov	scon, #0x42	;configure uart, but receive disabled
	mov	tmod, #0x11	;get timers ready for action (16 bit mode)
	clr	a
	mov	tcon, a
	mov	tl0, a
	mov	th0, a
	mov	tl1, a
	mov	th1, a

	;make sure there is no activity on the line
	;before we actually begin looking for the carriage return
	mov	r0, #200
autob1b:mov	r1, #30
autob1c:jnb	p3.0, autob1
	djnz	r1, autob1c
	djnz	r0, autob1b

autob2: ;look for the bits of the carriage return
	jb	p3.0, autob2	;wait for start bit
	jb	p3.0, autob2
	jb	p3.0, autob2	;  check it a few more times to make
	jb	p3.0, autob2	;  sure we don't trigger on some noise
	jb	p3.0, autob2
autob2b:jnb	p3.0, autob2b	;wait for bit #0 to begin
	setb	tr1		;and now we're timing it
autob2c:jb	tf1, autob1	;check for timeout while waiting
	jb	p3.0, autob2c	;wait for bit #1 to begin
autob2d:jb	tf1, autob1	;check for timeout while waiting
	jnb	p3.0, autob2d	;wait for bit #2 to begin
autob2e:jb	tf1, autob1	;check for timeout while waiting
	jb	p3.0, autob2e	;wait for bit #4 to begin
	setb	tr0		;start timing last 4 bits
autob2f:jb	tf1, autob1	;check for timeout while waiting
	jnb	p3.0, autob2f	;wait for stop bit to begin
	clr	tr1		;stop timing (both timers)
	clr	tr0

	jb	tf1, autob1	;check for timeout one last time

http://www.prjc.com/tech/8051/autobaud.html states: Quote

Available Baud Rates

Because the 8051's UART requires timer1, which is clocked by the crystal (divided by 12), the only baud rates which the 8051's hardware can produce are:

Baud = Crystal / ( 12 * 16 * N )

where "N" is an integer from 1 to 255. This code will select the available baud rate which is the closest to what was received. Usually, an error of about 2.5% will still manage to communicate without trouble, but much beyond that will be problematic, if it works at all. Many crystals are available which are exact multiples of the standard baud rates. Usually these crystals provide faster baud rates than simply switching to a faster crystal. For example, a 4 MHz crystal provides 1200 baud. Switching to 8 MHz only increases the maximum to 2400 baud, but switching to a 3.6864 MHz crystal will allow 19200 baud!

Unquote

For a crystal of 22.1184Mhz, the maximum buad rate is 115,200 with an error of zero percent.


	;compute the baud rate based on timer1
	mov	a, tl1
	rlc	a
	mov	b, a
	mov	a, th1
	rlc	a
	jc	autob1		;error if timer0 > 32767
	mov	c, b.7
	addc	a, #0
	cpl	a
	inc	a		;now a has the value to load into th1
	jz	autob1		;error if baud rate too fast

	;after we get the carriage return, we need to make sure there
	;isn't any "crap" on the serial line, as there is in the case
	;were we get the letter E (and conclude the wrong baud rate).
	;unfortunately the simple approach of just looking at the line
	;for silence doesn't work, because we have to accept the case
	;where the user's terminal emulation is configured to send a
	;line feed after the carriage return.  The best thing to do is
	;use the uart and look see if it receives anything

autob3: mov	th1, a		;config timer1
	mov	tl1, #255	;start asap!
	mov	tmod, #0x21	;autoreload mode
	setb	ren		;turn on the uart
	setb	tr1		;turn on timer1 for its clock

	mov	a, th1
	cpl	a
	inc	a
	mov	r1, a
autob3b:mov	r0, #255
autob3c:djnz	r0, autob3c
	djnz	r1, autob3b

	jnb	ri, autob4
	;if we got here, there was some stuff after the carriage
	;return, so we'll read it and see if it was the line feed
	clr	ri
	mov	a, sbuf
	anl	a, #01111111b
	add	a, #246
	jz	autob4		;ok if 0A, the line feed character
	add	a, #5
	jz	autob4		;of if 05, since we may have missed start bit
autob1_jmp:
	ljmp	autob1
autob4:
	;compute the baud rate based on timer0, check against timer1 value
	mov	a, tl0
	rlc	a
	mov	r0, a
	mov	a, th0
	rlc	a
	mov	r1, a
	jc	autob1_jmp	;error if timer0 > 32767
	mov	a, r0
	rlc	a
	mov	b, a
	mov	a, r1
	rlc	a
	mov	c, b.7
	addc	a, #0
	jz	autob1_jmp	;error if baud too fast!
	cpl	a
	inc	a
	cjne	a, th1, autob1_jmp
	;acc has th1 value at this point

autoend:mov	baud_save+3, a
	mov	baud_save+2, a	;store the baud rate for next warm boot.
	mov	baud_save+1, a
	mov	baud_save+0, a
	xrl	baud_save+2, #01010101b
	xrl	baud_save+1, #11001100b 
	xrl	baud_save+0, #00011101b 
	mov	th1, a
	mov	tl1, a
	mov	tmod, #0x21	;set timer #1 for 8 bit auto-reload
	mov	pcon, #0x80	;configure built-in uart
	mov	scon, #0x52
	setb	tr1		;start the baud rate timer
	ret


©2004, Gary L. Burt