Bascom and AVR, 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 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.
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.
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:
The RS-232 baud-rate (old term for communication speed, check your telecommunications history book or go to
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:
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:
$regfile = "2313def.dat"
$crystal = 4000000
$baud = 9600
Config Pind.6 = Output
Dim Firstnumber As Integer
Dim Secondnumber As Integer
Dim Sum As Integer
Firstnumber = 0
Secondnumber = 0
Input "Enter first number : " , Firstnumber
Input "Enter second number: " , Secondnumber
Sum = Firstnumber + Secondnumber
Print "Sum: " ; Sum
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
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
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
Print "Enter bin-code: "
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
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
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
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.
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:
$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
Print #1 , "text: "
Input #2 , Tstr
Print #1 , Tstr
Print #1 , "number: "
Input #2 , Num
Print #1 , Num
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 :
so that after the close the i/o pins can be used for another purpose.