Bascom and AVR, RS-232.


RS-232

RS-232 is nowadays a 'mature' communication standard. It is surprising that a standard, defined in the early sixties, is still widely used today. Formally however, the name RS-232 does not apply to a standard. An American organisation, now known as the Electronic Industries Association, proposed a way to communicate between large mainframe computers and peripheral equipment such as terminals. The proposal was called a Recommended Standard and 232 was not more than a identifying number. Much later this became an official standard, EIA-232. In 1991, the latest version, EIA-232E was published. However, the name RS-232 is still widely used and so shall I in these pages.
RS-232 is a serial communication protocol. It sends information as bit after bit and has two signal levels:

- a voltage between -3 and -25 Volts is a logic one (1)
- a voltage between +3 and +25 Volts is a logic zero (0)



As the picture above shows, the voltage level between -3 and +3 Volts is undefined. In practice this is not so. Most often, any voltage level above 2.5 Volts is seen as a logic zero, anything below as a logic one.
The electrical specification of RS-232 is quite robust, all outputs must be able to sustain a full short-circuit and all inputs must have a schmitt-trigger action. This makes a full-standard RS232 port on a PC much less vulnerable than a TTL-level parallel port.
RS-232 is an a-synchronous protocol, meaning that no separate clock is transmitted with the data. Both sides must know the communication speed (we use the term baud-rate) beforehand. In the original version of RS-232, a maximum speed of 20.000 bits per second was defined. Now, speeds up to 1 Mbit/s are used.
RS-232 defines a complete hardware handshaking system using several wiring pins. We use only the most important three:

- RxD : receive data, pin number 2
- TxD : transmit data, pin number 3
- Ground, pin number 5

These pin numbers refer to a standard male DB9 connecter on your PC or laptop.

UART

UART means Universal Asynchronous Receiver Transmitter. It is the hardware end on both sides of an RS-232 communication link. In the PC or any other computer it is a chip on the motherboard under control of the CPU. In the AVR controller it is a small area on the chip die dedicated to this function. In the AT90S2313 the UART is connected to pin 2 (RxD) and 3 (TxD). As these pins also function as general purpose I/O PortD.0 and PortD.1, you'll have to sacrifice some I/O if you need the UART. A UART takes care of sending and receiving bits. When receiving, it determines when to sample the RxD pin to determine if a zero or one is received. When a complete byte has been received it can interrupt the controller to have this byte read from the UART input buffer. When transmitting, the UART reads a byte from the transmit buffer and sends the corresponding bits with the timing appropriate for the RS-232 speed selected. If the transmit buffer is empty the UART can interrupt the controller to send more bytes to the buffer if there are any.
A UART does not do the level shifting needed to go from the AVR's logic level of 0 and +5 V to the RS-232 range of +3/+25 and -3/-25 Volts. This function is performed by chips like the ubiquitous MAX232 level converter:



A level converter generates the voltages necessary to comply with the RS-232 levels. It also inverts the logic levels! The MAX232 uses internal switching converters and voltage doublers to generate levels of approximately -9 and +9Volts. These voltages lie neatly within the required range.
Max232 pin-compatible converters are available from all mainstream chip manufacturers. Be sure to check the datasheet though, most often the capacitor values used vary between 100nF and 10uF:



I built a Max232 (I used a National Semiconductor DS14C232CM, which is pin-compatible) on a very small piece of PCB and used short stiff wires to insert this board into my breadboard:


Barely visible at the top is a 10k potentiometer I use to tap the -9V supply off pin 6. I use this whenever I need a negative contrast voltage for i.e. a graphics display.

Simple Max
You do not always need a Max232 converter chip. Often the following simple two-transistor converter works as well:



This is of course not a level converter, only an inverter. It works by the grace of tolerant UARTS in PC's and laptops. The voltage on pin 3 of the AT90S2313 is inverted by the left transistor. TxD pin 2 of the DB9 connector will have a voltage level between 0 and app. +5 Volts. Pin 3 of the DB9 connector will see voltage levels between -9 and +9 Volts. The diode on the base of the right transistor limits the -9 Volts to app. -0.7 Volts. A level of +9 Volts will make the transistor conduct, resulting in the RxD pin 3 of the AT90S2313 going from +5 to app. 0 Volts.

Simpler yet
If you only want to transmit data from the controller to a PC you can skip the right transistor.

Note: this simple schematic violates the RS-232 standard. It works in most cases, but make sure you test communications especially when using high speeds.

From AT90S2313 to the PC
A simple schematic with AT90S2313, an LCD and the Max232 would look like this:



RS-232 speed

The RS-232 baud-rate (old term for communication speed, check your telecommunications history book or go to Wikipedia) is determined by your setting of this speed but also by the AVR clock speed. Not all clock speeds will result in a 'neat' baud-rate. In Bascom, you can check this in the Options/Compiler/Communications window:



The important field in this window is Error. It shows the deviation of the AVR internal baud-rate from the one you selected from the Baudrate list. For a clock speed of 4MHz and a baud-rate of 9600, the error is small, you will not notice any communication errors. But for higher baud-rates the Error increases rapidly:



This kind of error will surely result in garbled communication.
Clock speeds that are a multiple of the chosen baud-rate result in a zero error. For example, suppose we would want to communicate between the AVR and a PC with a baud-rate of 115.200. A nice clock speed would be 11.059,200MHz, because 11.059.200 / 115.200 = 96:



Another nice crystal frequency is 3.686,400MHz instead of 4MHz. I checked my junkbox and found the following crystals by dividing the crystal frequency by 115.200 for an integer result:
1.843.200
3.686,400
5.068,800
5.529,600
11.059.200
12.902,400
14.745,600
etcetera.
So, next time you go to a ham-fest or a swap-meet, you better bring your pocket calculator along!

Writing to and reading from an RS-232 port

First specify your RS-232 baud-rate in Options/Compiler/Communication, or use a keyword in your Bascom program:
$Baud = 9600
Writing from the AVR to the RS-232 port is as simple as using the Print command:
Dim Name as String * 12
Dim Age as Integer

Name = "John"
Age = 36

Print "Name: " ; Name ; " Age: " ; Age
will print "Name: John Age: 36" to the RS-232 port.
The Print command may contain a mix of string constants and variables, all separated by a ";".

Reading from the RS-232:
Input "Name: " , Name
Again, the Input command can contain a mix of string constants and variables.
Note that Input uses a "," as separator, where Lcd and Print need a ";"!

A complete program for testing RS-232 communication from the AT90S2313 to the PC may look like this:
rs-232-test.bas
$regfile = "2313def.dat"
$crystal = 4000000
$baud = 9600

Config Pind.6 = Output

Dim Firstnumber As Integer
Dim Secondnumber As Integer
Dim Sum As Integer

Do
  Set Portd.6
  Firstnumber = 0
  Secondnumber = 0
  Input "Enter first number : " , Firstnumber
  Input "Enter second number: " , Secondnumber
  Sum = Firstnumber + Secondnumber
  Print "Sum: " ; Sum
  Reset Portd.6
  Waitms 100
Loop

End
Compile and send the program to the AT90S2313. Then open the Bascom terminal emulator: Tools/Terminal emulator. This is a small program to act as a 'terminal', a device allowing you to type characters which are sent to the PC RS-232 port, then through the Max232 to the AT90S2313. When the AT90S2313 returns characters, the Max232 sends them to the PC's RS-232 port and they will be displayed in the terminal emulator window.
Before doing this, you will have to tell the terminal emulator that you want to use 9600 baud and the PC's COM1 RS-232 port. Open the Terminal/Settings menu:



Reset the AT90S2313, the program asks you for two numbers and returns the sum:



Did you notice that everything you typed after the "Enter..." prompt was echoed back to the terminal emulator? This is a function that Bascom performs automatically. Sometimes this echo function is not useful, for example if you use another PC program to send characters to the AT90S2313 and it cannot handle the echoed characters. Then switch off the echo function:
Echo Off
Variants of the Input command are Inputhex and Inputbin:
Dim Code as Byte
Inputhex "Type two-character hex-code: " , Code
allows you to type hex-codes, for example "A9" for the decimal value 169.
Note that Inputhex does not check if input is only the characters 0-9 and A-F. It will however limit the number of characters interpreted to two.

Inputbin is useful if you have a PC program that sends data that cannot be represented as ASCII code. If you want to send a 16-bit binary value:
Dim Tuneval as Word
Inputbin Tuneval
will read two bytes from the RS-232 port and place them in the Tuneval variable. The number of bytes read is determined by the variable type used. Note that you must always start sending the least significant byte and end with the most significant byte from the value to send.
Let us assume that the value of Tuneword in the PC is 12.320 decimal. That is 0011.0000.0010.0000 binary and 30.20 hexadecimal. (interpunction added for readability)
Test this with:
Dim Tuneval as Word

Do
  Print "Enter bin-code: "
  Inputbin Tuneval
Loop

End
Then in the terminal emulator type first a space (ASCII code 20hex), then a 0 (ASCII code 30hex).

Inputbin has an output equivalent: Printbin. It is a pity there is no Printhex.

Reading one character at the time

Sometimes you only want to know if there is an input character available at the RS-232 port. Then use the Inkey command:
Dim Testchar as Byte

Testchar = 0

While Testchar = 0
  Testchar = Inkey
Wend
This piece of code will stay in the While loop as long as there is no character available. You could add a counter or timer to provide for a time-out function. Or, maybe better:
Dim Testchar as Byte

Do
Loop until Inkey <> 0
Another possibility is the Waitkey and Ischarwaiting commands:
Dim Wtchar as Byte

Wtchar = Waitkey
will wait until a character is available. Problem is that no time-out is possible here so your program may get stuck here!
Or:
Do
Loop until Ischarwaiting = 1
will loop until a character is available, it can then be read with Input or Inkey. The Do Loop offers the possibility of a time-out function.

Software UART

The AT90S2313 and most other AVR controllers has a hardware UART on pins 2 and 3. Sometimes you have to use these pins for another purpose. Bascom has a software UART function that uses extra program space, but you may specify which pins to use for RxD and TxD. The pins to use are specified in the Open command:
Open "Comb.0: 9600 , 8 , n , 1" for Input As #1
Open "Comb.1: 9600 , 8 , n , 1" for Output as #2
uses pin 0 of PortB as receiver (RxD) and pin 1 of PortB as transmitter (TxD). Both are set to a baud-rate of 9600, use 8 databits per character, do not use a parity bit and use one stopbit. In Bascom every reference to #1 will be used for RxD and #2 for TxD:
software-rs232.bas
$regfile = "2313def.dat"
$crystal = 4000000

Config Pind.6 = Output

Dim Tstr As String * 4
Dim Num As Word

'open channel for output
Open "comb.1:9600,8,n,1" For Output As #1
Open "comb.0:9600,8,n,1" For Input As #2

Do
  Set Portd.6
  Waitms 100
  Reset Portd.6
  Print #1 , "text: "
  Input #2 , Tstr
  Print #1 , Tstr
  Print #1 , "number: "
  Input #2 , Num
  Print #1 , Num
Loop

End
Note that the software UART does not echo characters. Also different from the hardware UART implementation is that after every prompt a linefeed/carriage return is used.

The software UART can be used with the Print, Input, Inputhex, Inkey, Waitkey and Ischarwaiting commands. Note the syntax used in Inkey, Waitkey and Ischarwaiting:
Var = Inkey(#2)
Var = Waitkey(#2)
Var = Ischarwaiting(#2)
A software UART channel can be opened, but also closed :
Close #1
Close #2
so that after the close the i/o pins can be used for another purpose.
TOC