Skip to Content

HC11 Serial I/O

Serial Communications

We said earlier that the HC11 has the ability to do serial communication, which is what hexmon uses when you tested your board out, and also how it downloads your program into EEPROM. Serial communication is done through PORT D, but the way it is programmed is quite different than other ports.
 

Basic concepts of serial communications

Parallel communication is when all the bits of a value are sent to the receiver at the same time, i.e., in parallel. To do this you need a wire for each bit. This is the way a CPU sends and receives data from memory, and disks, and things like that. Parallel communication needs alot of wires, but it can be very fast.

Serial communication sends each bit one at a time. You only need one (data) wire in this case, so this matches well when you need to communicate over long wires, like phone or network lines. All networks use serial communication, and some devices, like printers, often can use serial communication.

A simplex connection sends data in only one direction. One data wire is needed.

A half-duplex connection sends data in both directions, but not at the same time. One data wire is needed, and its direction is switched back and forth.

A full duplex connection sends data in both directions simultaneously. Two data wires are needed, one in each direction.

Our phone cord connections from the Miniboard to a PC are full duplex connections. In the diagrams in your manual, one pin (wire) was labelled RxD (Receive Data), one was TxD (Transmit Data), and the other two are tied together as GND (Ground). Having a ground wire improves the signal quality between the two endpoints, and since a regular phone cord has four wires, this connection simply uses two as ground.

Both sides must, of course, agree on a signalling protocol to be able to transmit data. That is, they need to agree on what voltage levels mean what, and when and how fast the signals will change. The protocol that the HC11 uses with the PC is called RS-232, and is a very commonly used protocol for serial communication between nearby devices (it doesn't work over a long distance like a modem does).

The speed at which the serial communication takes place is called the baud rate. This is the same "baud" that is used to describe modems, because they also do serial communication (but with different protocols). Some standard baud rates for RS-232 links are 2400 bps (bits per second), 4800 bps, 9600 bps, 19.2 Kbps (kilo-bps), and faster. We will use 9600 bps for the HC11-to-PC.

With the way RS-232 works, 10 bits are transmitted for every byte of data. This is because the transmitter and receiver have to agree when data starts and stops. So, a question: How many bytes of data can be transmitted per second using 9600bps?  Another question: How long does it take to send one byte of data? How many HC11 cycles go bye during a one-byte transmission?

In answering the above questions, you see that 9600 bps is pretty slow compared to how fast the CPU goes. In this class, hopefully you are learning that everything is pretty slow compared to how fast a CPU goes. The CPU has to constantly wait for things to happen outside of itself. Pretty boring, eh?
 

Setting up Serial I/O on the HC11

First, you have to specify the baud rate that you want to communicate at. This is done by setting the BAUD register ($102B), or at least parts of it. Its bits are:

  • Bit 7: TCLR -- it does something, I'm sure
  • Bit 6: 0, not used
  • Bits 5,4: SCP1 and SCP0 -- these bits selected a prescaler divide factor
  • Bit 3: RCKB -- it does something, I'm sure
  • Bits 2-0: SCR2, SCR1, and SCR0 -- these bits select another (rate control) divide factor

It is a bit confusing, but you have to combine the selection of the prescaler divide factor (SCP0-1) with the selection of a rate control divide factor (SCR0-2) to get a certain baud rate. Furthermore, it is dependent on how fast your clock (crystal) is. The two tables are shown in the book on pages 373 and 374, and in the Reference Manual on page 9-8. The Miniboard's crystal is 8Mhz, giving a 2Mhz clock. There are different ways to get 9600 baud on the Miniboard, but one is to set SCP0-1 to 11 and SCR0-2 to 000. Thus, if you load register A with %00110000, and then store this to BAUD, you will set your HC11 to be using 9600 baud.

The other step you need to take during initialization is to actually turn the serial communication on, just like we had to turn the analog-to-digital subsystem on. This is done using the SCCR2 register ($102D).  There are bits that allow you to turn on transmission and reception independently. The bits in the SCCR2 are:

  • Bit 7: TIE -- transmitter interrupt enable
  • Bit 6: TCIE -- transmit complete interrupt enable
  • Bit 5: RIE -- receiver interrupt enable
  • Bit 4: ILIE -- idle line interrupt enable
  • Bit 3: TE -- transmission enable. this must be 1 to be able to send data from the HC11
  • Bit 2: RE -- receive enable. this must be 1 to be able to receive data to the HC11
  • Bit 1: RWU --
  • Bit 0: SBK --

So, at the minimum, bits 2 and 3 of SCCR2 must be set to 1 to enable full duplex (both way) sending of data. For now we will ignore bits 4-7, just make sure to leave them 0.

When actually sending and receiving data, the register SCSR ($102E) is used. Remember, serial I/O is much slower than the CPU, so we must test to see if the previous data has already been sent before we can send again. The bits of SCSR are:

  • Bit 7: TDRE -- transmit data register empty. when this is 1, it is safe to transmit another byte.
  • Bit 6: TC -- transmit complete. even though TDRE is ready, transmission of the previous byte is not necessarily finished. this flag tells you when it is. we normally won't use this.
  • Bit 5: RDRF -- receive data register full. when this is 1, a byte is ready to be read
  • Bit 4: IDLE -- if this bit is 1, the receive data line has been idle for at least a 1-byte time
  • Bit 3: OR -- overrun error. when this is 1, your program didn't read a byte fast enough, and the next incoming byte had no where to go, so it was lost.
  • Bit 2: NF -- noise flag. if this is 1, some electrical noise probably ruined your incoming data
  • Bit 1: FE -- framing error. if this is 1, errors about when the byte ended have ocurred.
  • Bit 0: 0 -- always 0, not implemented

So, to transmit a byte, your program just waits until TDRE is 1, then transmits it. To receive a byte, your program waits until RDRF is 1, then receives it. But how do we do the actual transmit and receive?

Very, very simply. Just write a byte to SCDR ($102F) to transmit, and read a byte from SCDR to receive. Notice that the value you read from location SCDR has no relation to the value you write to the same location. It just means that the HC11 uses the same address to send and receive data.



(This section can be ignored. We will not cover it yet.)

Of course, rather than waiting, we can use interrupts, which are enabled in SCCR2. With the transmit interrupt (TIE, bit 7) you have to be careful, because it will keep interrupting as long as the transmitter is not busy. So you cannot just leave this interrupt enabled constantly. You should only enable it when you have a long sequence of bytes to transmit, and then should disable when you are done with that sequence.

The receive interrupt (RIE, bit 5) is harmless to leave on, as long as your program can handle incoming characters.

The other interrupts in SCCR2 (TCIE and ILIE, bits 6 and 4) are not needed by us.

The interrupt vector (i.e., the address in the interrupt table) for serial communications is FFD6,D7. This is where you put the address of your interrupt service routine, or interrupt handler. But, you must note that your interrupt routine must handle five different conditions. This one routine handles receive, transmit, idle, and error interrupts -- it's up to you to tell the difference! You do this simply by testing the flags in SCSR -- in other words, test TDRE and if it is 1 then transmit if you need to, test RDRF and receive a byte if it is 1, test others and do whatever you need to.



 

ASCII character representation

When you use hexmon and send commands to the Miniboard, like "r00000054", each character that you type is a byte that is sent to the Miniboard. The question is, what byte value is 'r', and how did we know that?

Well, an agreed-upon standard for byte values representing characters is the ASCII standard (American Standard Code for Information Interchange), and it assigns a number value to each character you can type, including punctuation (and some that you cannot type). So, for example, the character 'A' is decimal value 65, or hex $41, and 'a' is decimal 97, or hex $61. The letters are numerically in order for upper and lower case, so 'B' is $42, 'b' is $62, and on all the way to 'Z' and 'z'. (question: how do you capitalize an ASCII letter?) In between 'Z' ($5A) and 'a' ($61) is a few punctuation characters ('[' is $5B, '\' is $5C, ']' is $5D,...).

We started by asking what 'r' is, but actually, the '0's are not numerically zero, and '5' is not numerically five. Rather the character '0' that we type has an ASCII value of decimal 48, hex $30, and the characters for each of the digits is in order from '0': '1' is $31, '2' is $32',..., '9' is $39.

On a Unix workstation, you can type in the command "man ascii", and you will see a chart of all of the ASCII characters.

ASCII originally used 7-bit characters, and so only had 128 possible characters. ISO 8859-1 extended that to 8-bit characters (different manufacturers had already used 8-bit characters, with the upper 128 values being proprietary characters (like line-drawing on MS-DOS)).

But even 256 values is not nearly enough to represent, for example, Chinese characters. ISO 8859-1 does well with basic European languages with the various accented characters, but that's about it.

A new standard called Unicode (ISO 10646 -- Universal Character Set (UCS)) has been devised that uses 16-bit characters. With 16 bits -- i.e., 65,534 different values -- every character of every known language (including all the many thousands of Asian lanuage characters) can have it's own unique value. One nice thing about Unicode is that values with the upper byte of $00 map directly to ISO 8859-1, and thus to ASCII. So 8-bit ASCII characters will be around for a while. An encoding of Unicode called UTF is popular as a method to preserve backwards compatibility with ASCII strings.

On our Linux workstations, "man unicode"  and "man utf-8" will give you more information.