Controlling an Arduino

Controlling an Arduino

  • By :
  • Comment : 0
Controlling an Arduino

In this article we will create a small Serial Port terminal program for use in communicating with many single board computers or serial terminals. Here, I use an Arduino however, the serial terminal can be used with any device that contains a serial port and can accept standard ASCII characters. My intention is to present this simple project to give a foundation on which we can build a more complex system in a future article.

Arduino Uno
Arduin Uno

The Arduino Single Board Computer is an amazing little device. For those of us who grew up hacking hardware it is astounding to think that for $30 you can have a little computer with more horse power under the hood than my first several machines had! If you are familiar with some of the first personal computers like the Commodore, Vic 20, Dream 6800, Tandy’s Color Computer and Model I & II, or Apple I & II, or even the first IBM PCs, then you can appreciate the power and capabilities of such a small device and the ease of use. For those of you who are not old enough to have experienced these old machines with amazement, you will still find the Arduino a wonderful little piece of work.

Arduino Mega 2560
Arduino Mega 2560

So what is a single board computer? Well, simply put, they are computers designed such that all the components are placed on a single printed circuit board (PCB) or printed wiring board (PWB).  They are usually designed using a micro-controller but some use micro-processors. The difference is that a micro-controller integrates most, if not  all of it’s support logic and usually some I/O devices right onto a single chip with a scaled down or special purpose micro-processor. Micro-controllers are typically used in embedded systems where specialized hardware and software are required. They far out number micro-processors in use today. So what is the Arduino good for? The Arduino was designed to be a prototyping, hobbyist, and educational system. It is built around the ATMEL ATmega family of micro-controllers and comes in many version. I have used the Arduino for more than a few personal projects such as, digital tachometer for radio controlled aircraft, lathes and mills, stepper motor controllers, PCB etchant tank controller, reflow oven controller, and tDCS (Trans-cranial Direct Current Stimulation) controller. I’ve also used it in flight control systems for model aircraft and model rocketry. I’ve used a lot of micro-controllers over the years. Some very simple and some very complex. The Arduino is a delight to work with. Best of all, the Arduino is Open-Hardware and the development tools are Open-Source. So you can buy, build, and sell your own Arduino clones or develop a version of your own.

Arduino Leonardo
Arduino Leonardo

So why are we talking about the Arduino in an article on Gambas? Well, as developers we often need to develop our own tools. Much like a machinist must make his own tooling, and Gambas is the perfect platform to create tools for micro-controllers of all kinds. In this article we are going to build a useful tool for your hardware hacking habit. A simple, yet useful Serial Terminal. We’ll use this terminal in future projects and what you learn here will be very useful if you ever need to support any protocol over a serial connection. So let’s get started.

So what is serial communications anyway?

Computing devices usually work with data that is represented by more than one bit in width. The width of this data representation is referred to as the bit-width or buss width. When sending these bits to another device you can simply send each bit in parallel using multiple conductors. However, you must also provide additional signals to tell the sender when it is safe to send data (if the receiver is not listening then the sent data will only be ignored and lost). There must also be signals to notify the receiver when the data is stable and ready to be read. This all works great if the device you are communicating with is close. Sending all the bits at once speeds up the communications. However, when the distance increases, there are all kinds of issues that arise.parallel-comm Reflection occurs when the impedance of the transmission line and source and sink ports are not match.This can cause havoc with the communications as bits that were sent get bounced back and forth along the wire much like waves in an aquarium. These waves can even be powerful enough to harm the port drivers. Then there is the issue of Cross-talk, the magnetic coupling of conductors in close proximity to each other. Which causes the signals on two or more conductors to be mixed together. To solve these issues, termination devices are used to balance the impedance and shielding is added to each signal to reduce cross-talk and interference from external noise. The cost and complexity of cabling, termination, and the more powerful drivers needed for long distances begins to add up quickly. To solve the issues with parallel communications over long distances, methods were devised to send the data over fewer conductors. This meant fewer conductors, fewer terminators and less cross talk. So how do you send multiple signals over a single line? Well, how do you put a 100 students into a single class room when the door only fits one at a time? You line them up in single file and send them through one at a time! Serial communications does just that. It takes all the data bits and sends them over the wire one at a time and in order. Mux-Select-A Mux-Select-B Mux-Select-C Serial communications systems must not only include the control signals of the parallel port but it must also provide some mechanism to keep the Multipler (Mux) and Demultiplexer (DeMux) in sync. To accomplish this the RS232 serial standard that is typically used on most PCs and Data Terminals, uses a predetermined start and stop bit pattern. However, some other serial communications standards use a transmission clock line to keep both ends in sync. Gambas includes a handful of communications components. These are all wrapped up in the gb.net component. I personally think the naming of this component is unfortunate, as it causes some confusion about where to find non-network communications components, “gb.comm” might have been a better choice… The gb.net component provides a consistent interface for most of its sub-components. These include a DNSClient, Serial RS232, ServerSocket, Socket, and UDPSocket sub-components.  It is the Serial RS232 sub-component we are interested in here.

Understanding RS232

It is helpful to understand the ins and outs of RS232 before we get to writing our code. In the early 1960s, a standards committee, today known as the Electronic Industries Association, developed a common interface standard for data communications devices.  These devices were linked by telephone voice lines, and required an acoustic modem at each end for signal translation. While these systems were simple, there remained many opportunities for errors to occur when transmitting and receiving data. So standards were developed to ensure reliable communication and to enable the interconnection of equipment produced by different manufacturers. From these early ideas, the RS232 standard was created. It specified signal voltages, signal timing, signal function, and protocol for information exchange, and mechanical connector specification.

Over the many years since this standard was developed, the Electronic Industries Association (EIA) has published modifications. Some of these changes are minor, like changing the name from RS232 to EIA232. However, some signal lines were renamed and various new ones were added, including a shield conductor. Most of the computers manufactured from the early 80’s to the early 2000’s provided an RS/EIA 232 serial port. In recent years many manufacturers have dropped the serial port in favor of the Universal Serial Port, which reduces the number of conductor while increasing the speed of communications. However, for industrial control and harsh environments USB is not piratical. Still, USB to RS/EIA 232 adapters are prevalent and relatively inexpensive. Much of today’s modern hardware devices use some form of simplified RS/EIA 232 communications system. Since no simplified standard was produced, many different implementations have been created. Most recently it has become popular to reduce the voltages on the buss and convert the low voltage 232 system to USB. The Arduino and many other modern devices do this. Many using the FTDI FT232 converter chip.

Image of FTDI FT232 Demo Baord
FTDI FT232 Demo Baord

Using RS-232 the data bits are preceded by a start bit. This bit give the receiver an opportunity to synchronize with the data. Next, the data bits are sent in either 5,6,7 or 8 bit packets. Then, the data is followed by one or two stop bits.  This allows the receiver to check the transition frame for errors. Its all very simple. When transmission is asynchronous, the least significant bit is usually transmitted first. However, synchronous systems usually transmit the most significant bit first. But both can be found. These formats are known as Big Indian and Little Indian. The original RS-232 standard required the transmitter to send signals of +25 volts for an unset data bit and -25 for volts for a set data bit. Astute readers might notice that this is an inverted signal. The voltage levels for the control lines however are not inverted. For the control lines a set bit is designated by the line being driven to +25 and the line is driven to -25 for an unset bit control signal. The receive signal levels are specified at much lower voltages. This allows for a greater signal loss in transmitting and helps to offset the effect of long cabling on the signals rise and fall times.  The RS-232 receiver must accept a data bit as being set when the line voltage reaches -3 volts. An unset bit is determined by a +3 volt signal on the line. Most modern computers do not actually send these voltage levels. More often than not, the signals are translated to the 0 – 5 volt range or even the 0 – 3 volt range. If you are connecting to old or industrial equipment however, you may find higher voltages.

RS-232 Control Signals

In order that data can be exchanged over RS-232, the control signals must indicate that the equipment at either end is ready to send and receive data. This can be achieved in a number of ways however, one of the more common ways is to use the RTS , CTS, and DTR lines. The transmitting device sets the Request To Send (RTS) line. Next, the receiving device sets the Clear To Send (CTS) line. Next, the transmitting device sets the Data Terminal Ready (DTR) line, indicating that it is ready to begin transmission. Next the data is sent to the receiver.  At the end of the transmission, DTR and RTS are unset by the transmitter and then the receiver then unset’s the CTS line. This series of handshake controls was designed to allow the transmitter to request control of the communications from the related receiver and then to let the receiver to inform the transmitter that the control had been acquired. This way, communications only takes place when both transmitter and receiver are ready. Some systems forego hand shaking all together in favor of speed. While other use a software version of handshaking. What ever the handshaking type chosen it is important that both devices be configured alike.

RS-232 Speed

The speed of the data flow over RS-232 is most typically measured in Baud. Baud is the symbol rate of transmission and should not be confused with gross bit rate expressed in bit/s. The term baud has sometimes incorrectly been used to mean bit rate since these rates are the same in old modems as well as in the simplest digital communication equipment which uses only one bit per symbol. In more advanced modems and data transmission techniques however, a symbol may have more than two states, so it may represent more than one bit. In the early days of digital equipment the speeds were very slow. 75 to 300 Baud was typical. Today, speeds range from 75 baud to 91.6k baud or higher can be found. It is important that both the transmitter and receiver both be set to use the same baud rate or synchronization cannot occur.

Enough formalities. Let us get started on code!

The gb.net serial component is designed to allow to communicate using a serial interface using over an RS-232 serial link. This class inherits from the Stream class. So it is possible to use standard streams methods to send and receive data, and to close the port. Basic usage is very simple:

  • Setup Communications Parameters
  • Open the Comm Port
  • Read/Write Data
  • Close the Port

This is all very straight forward. The only real questions are, “What are to Communications Parameters?” and “How do you read and write data?”. If you’ve used serial communications before you will find that the serial component supports the typical serial port parameters. To get serial communications working, the two devices must operate with the same settings for baud-rate, data bits, stop bits, parity, and flow control. We want our design to allow these parameters as well as the communications port to be user select-able. We also want to store our settings between uses so we do not have to set these parameters each time we restart the program. We also want to support local echo of the lines we type at the terminal and an auto line feed  feature for received data. The auto line feed is handy when working with devices that simply send an unending data stream. Open Gambas 3 and create a new project. Ensure that the following components are selected.

  • gb
  • gb.form
  • gb.net
  • gb.qt4
  • gb.qt4.ext
  • gb.settings

Select the form in the editor. Add a TextBox to the form to allow the user to type the port to be used. Add a label for the port and give it the text “Serial Port”. Give the text box a name of tbPort. Next add five (5) ComboBox items to the form. These will be named cbBaudrate, cbFlowControl, cbDataBits, cbStopBits, and cbParity. For the cbBaudrate edit the List value in the properties panel to include the following values (one value per line). 110, 150, 300, 1200, 2400, 4800, 9600, 19200, 38400, 57600, 115200, 230400, 460800, and 921600. Note that your machines comm port may not support all these values. Then click OK.

Next, edit the List property for the cbFlowControl item to include the values: None, Hardware, Software, and Both.

The list of values for the cbDatBits combo box should read: 5, 6, 7, and 8.

For the cbStopBits combo set the list values to 1, and 2.

The cbParity list should contain the values: None, Even, and Odd.

Next add eight (8) CheckBox items to the form. These should be named chkCTS, chkRTS, chkDTR, chkDCD, chkDSR, chkRNG, chkAutoLineFeed, and chkLocalEcho, respectively.

Next we need a place to display the communication between the client and the host. So add a Text Area item and name it taRxData. Clear any value in the text field. Add a Label for the RxData text area.

Now we need a place to enter text to send to the client. So add a TextBox. This time name it tbTxData and clear anything in the Text property. Then add an associated label.

Last, add three buttons. Name them btnSend, btnConnect, and btnClose respectively. Set the Text property for each as Send, Connect, and Close respectively. Once you have this all laid out to your liking open the forms code in the editor. Fig. show the layout I used but feel free to change this to suit your fancy.

Serial Terminal
fig. Serial Terminal

The code for this project will reveal my C legacy. I don’t like having to fish values from GUI components. So I create private class properties. This also allows me to easily convert the values to other data-types as needed by other functions. Ok, add the code shown in listing 1 to the top of your code file.

The next step is to setup our form open method. This method needs to first read our settings file to configure out window’s position and size. Then it must create our comm port object and set it’s parameters either per those stored in our settings file or from the values found in the gui. The gb.settings component allows us to store our applications settings between uses. The settings component saves all our settings in a file xyz where xyz is the name of our application. The settings file is a plain text file that contains key/value pairs. The key/value pairs may be stored in section of the file called Slots. Slots are named sections of the file that help in associating various key/value pairs with a particular object of function.

listing 1
' Gambas class file 
 
Private Comm As SerialPort 
Private bConnected As Boolean = False 
Private rxData As String 
Private iParity As Integer 
Private iDataBits As Integer 
Private iStopBits As Integer 
Private iFlowControl As Integer 
Private iBaudRate As Integer 
 
Public sConfig As Settings 
 
Private bAutoLineFeed As Boolean = False 
Private bLocalEcho As Boolean = False

Slot names are bracketed by square braces as in [Slot-Name]. Settings files may also contain comments. Any line that begins with a hash ‘#’ character or a semicolon is considered a comment line and is ignored by the settings file reader. Most of the settings file will contain value lines containing key/value pairs. A value line contains the key value pairs separated by and ‘=’ equal sign. String values are quoted and numerical values remain unquoted in the file. To retrieve a value from the file by indexing the file with the key name ie.: Settings[“key”, Default-Value]. If the key is not found in the file, the default value is returned. We can set a key in the file to a value by assigning the value to the key ie.: Settings[‘key”] = “value”. If the key is stored in a Slot we simply place the slot name before the key and separate them with a slash ‘/’ ie.: Settings[“slot/key”]. This format may look familiar to Windows users. The format is very much like a Windows ini file. It clean and works well.

We will want to store more than our window size and position in our settings file. We also want to store the values of the various parameters for the comm port. Refer to listing 2. Here you can see that we first set our application’s window size and position. Next we create the serial port object. This must be done before we attempt to set any serial port parameters or there will be no object to work with. Next we set the communications parameters to the port object. Note that we provide default values in case there is no settings file. As will happen if this is the first time the program has been ran.

Listing 2
Public Sub Form_Open()
  'Update Window position and size
  'from settings file if exists
  Me.Top = Settings["Window/Top", Me.TOP]
  Me.Left = Settings["Window/Left", Me.Left]
  Me.Height = Settings["Window/Height", Me.Height]
  Me.Width = Settings["Window/Width", Me.Width]
 
  'Create our Comm Port Object
  Comm = New SerialPort As "Comm"
 
  'Set default values for communications
  tbPort.Text = Settings["PortName", "/dev/ttyS0"]
  cbBaudrate.Text = Settings["Speed", "19200"]
  cbDataBits.Text = Settings["DataBits", "8"]
  cbStopBits.Text = Settings["StopBits", "2"]
  cbParity.Text = Settings["Parity", "None"]
  cbFlowControl.Text = Settings["FlowControl", "None"]
  chkAutoLineFeed.Value = Settings["AutoLineFeed"]
  chkLocalEcho.Value = Settings["LocalEcho"]
End

As long as we’re working on the form we might as well tackle the form closure. When the form closes we want to save all our settings we have set while running the program. The code in listing 3 provides the code to handle this. Note that we trim any excess white space from the values taken from the gui.

Listing 3
Public Sub Form_Close()
  ' Save window settings when application closes
  Settings["Window/Top"] = Me.Top
  Settings["Window/Left"] = Me.Left
  Settings["Window/Height"] = Me.Height
  Settings["Window/Width"] = Me.Width
 
  'Save communication settings
  Settings["PortName"] = Trim(tbPort.Text)
  Settings["Speed"] = Trim(cbBaudrate.Text)
  Settings["DataBits"] = Trim(cbDataBits.Text)
  Settings["StopBits"] = Trim(cbStopBits.Text)
  Settings["Parity"] = Trim(cbParity.Text)
  Settings["FlowControl"] = Trim(cbFlowControl.Text)
  Settings["AutoLineFeed"] = chkAutoLineFeed.Value
  Settings["LocalEcho"] = chkLocalEcho.Value
End

Now we are going to need a couple of methods to help with printing messages to the user.We will display error and other mmessages in the RxData text area. The user will be looking at this window for received data so this is the most practical place to display this information. Listing 4 shows two simple methods that handle this for us. We also include a method for displaying data on in the RxData text area.

Lisintg 4
' Write Error message to RxData Text Area
Public Sub WriteError(msg As String)
  Dim ErrMsg As String
  ErrMsg = "\nError: " & msg & "\n"
  taRxData.Text = taRxData.Text & ErrMsg 
End
 
' Write Notice message to RxData Text Area
Public Sub WriteMsg(msg As String)
  Dim NtcMsg As String
  NtcMsg = "Notice: " & msg & "\n"
  taRxData.Text = taRxData.Text & NtcMsg 
End
 
' Write Data message to RxData Text Area
Public Sub WriteData(msg As String)
  Dim lf As String
  If bAutolineFeed Then
    lf = "\n"
  Else
    lf = ""
  Endif
  taRxData.Text = taRxData.Text & msg
End

Now we need to handle the change event for the Combo Boxes in our gui. Refer to listing 5. We’ll start with the cbBaudrate_Change event. When the user chooses a new selection from the Baudrate combo box the Change event is triggered. The cbBaudrate_Change method is called when this event is triggered. The first thing we must do is check to see if the port is currently connected.
> >The Gambas Docs online don’t state state that baudrate changes only occur when the port is disconnected but this seems to be the case on the three machines I have tested it on. <&lt

If the port is connected we need to notify the user that the baud-rate change will not take place until the port is closed and re-opened. We use the WriteError method for that. If the port is open, then we make sure the value selected is not an empty string. If it is, we set a default value. Then we move on and set the iBaudrate variable. We cast the text value selected in cbBaudRate to a CInt for use with the SerialPort object. Then we set the Comm ports baudrate (just in case other systems differ from mine) and display a message to the user that the baudrate has changed. The Data bits and Stop bits are handled in the same fashion.

Listing 5
'Handle Gui Changes
Public Sub cbBaudrate_Change()
  'if connected we cannot change the baudrate until next connection
  If bConnected Then
    WriteError("Baudrate change will not take effect until port is closed and reopened!")
  Else
    If cbBaudrate.Text = "" Then
      cbBaudrate.Text = "19200"
    Endif
    iBaudRate = CInt(cbBaudrate.Text)
    Comm.Speed = iBaudRate
    WriteMsg("Baudrate changed to " &amp; cbBaudrate.Text)
  Endif
End
 
Public Sub cbDataBits_Change()
  If bConnected Then 
    WriteError("Cannot change Dat Bits while Port is Open!")
  Else
    If cbDataBits.Text = "" Then
      cbDataBits.Text = "8"
    Endif
    iDataBits = CInt(cbDataBits.Text)
    WriteMsg("Data Bits changed to " &amp; cbDataBits.Text)
  Endif
End
 
Public Sub cbStopBits_Change()
 If bConnected Then 
    WriteError("Cannot change Dat Bits while Port is Open!")
  Else
    If cbStopBits.Text = "" Then
      cbStopBits.Text = 2
    Endif
    iStopBits = CInt(cbStopBits.Text)
    WriteMsg("Stop Bits changed to " &amp; cbStopBits.Text)
  Endif
End

The next method we need to tackle is the cbFlowControl_Change event method. The FlowControl property of the SerialPort object requires the use of special defined values. So we can’t just use the text we get from querying the combo box. So we set up a Select statement and test each possible value. If a matching value is found we set the iFlowControl variable appropriately. Before we can do this however, we need to make sure the port is closed and is not, we display a error message to the user. Again, we handle the Parity change in the same fashion.

Listing 6
Public Sub cbFlowControl_Change()
  If bConnected Then
    WriteError("Cannot change Flow Control while Port is Open!")
  Else
    ' FlowControl uses pre-defined values
    Select cbFlowControl.Text
      Case "None"
        iFlowControl = Comm.None
      Case "Both"
        iFlowControl = Comm.Both
      Case "Hardware"
        iFlowControl = Comm.Hardware
      Case "Software"
        iFlowControl = Comm.Software
      Case Else
        iFlowControl = Comm.None
        cbFlowControl.Text = cbFlowControl.Find("None")
    End Select
    Comm.FlowControl = iFlowControl
    WriteMsg("Flow Control changed to " &amp; cbFlowControl.Text)
  Endif
End
 
Public Sub cbParity_Change()
  If bConnected Then
    WriteError("Cannot change Parity while Port is Open!")
  Else
    Select cbParity.Text
      Case "None"
        iParity = Comm.None
      Case "Even"
        iParity = Comm.Even
      Case "Odd"
        iParity = Comm.Odd
      Case Else
        iParity = Comm.None
        cbParity.Text = "None"
    End Select
    WriteMsg("Parity has changed to " &amp; cbParity.Text)
  Endif
End

Now we want to handle those times when we changed the DTR and RTS which are the only port control lines we have direct control over. Lsting 7 shows how we do this. In both cases we must test to see if the port is open. If it is, we can change the value, otherwise we can only read the value. If the port is closed we simply notify the user that this change can’t take place when the port is open.

Listing 7
'Handle Set and Reset of DTR and RTS Control lines
Public Sub chkDTR_Click()
  If bConnected Then
    Comm.DTR = chkDTR.Value
  Else
    WriteError("DTR can only be set When the port is open!")
  Endif
End
 
Public Sub chkRTS_Click()
  If bConnected Then
    Comm.RTS = chkRTS.Value
  Else
    WriteError("RTS can only be set When the port is open!")
  Endif
End

Next, we handle the Click events for the Auto Line Feed and Local Echo check boxes. These methods only need to set the appropriate class variables. See listing 8.

Listing 8
Public Sub chkAutoLineFeed_Click()
  bAutoLineFeed = chkAutoLineFeed.Value 
End
 
Public Sub chkLocalEcho_Click()
  bLocalEcho = chkLocalEcho.Value 
End

Now we need to handle all the button click events. Refer to listing 9. Here we Simply pass the call on to our custom handler methods.

Listing 9
Public Sub btnSend_Click()
  PortWrite()
End
 
Public Sub tbTxData_KeyRelease()
  If key.Code = key.Return Then
    PortWrite()
  Endif
End
 
Public Sub btnConnect_Click()
  Connect()
End
 
Public Sub btnClose_Click()
 PortClose()
End

Ok, until now all the code we’ve written has been what I call house keeping code. Stuff you need to do but it doesn’t really do anything exciting. Now we get into the meat of the app. The Connect method sets the communications parameters for our SerialPort object. Then it sets the bConnected variable to false, as the port is initially closed. Next we notify the user we are attempting to connect. We attempt to open the comm port. If successful we display a message informing the user, otherwise an error message is displayed.

Closing the port is as important as opening it. The PortClose method attempts to cleanly close the port. It first displays a message to the user informing them that the port is being closed. If the attempt fails, an error message is displayed, otherwise the user is informed that the port has closed.

The PortWrite method first test if the port is open, then it uses the stream Write method to send data to the client device. If an error occurs an error message is written to the RxData text area. If the bLocalEcho variable is set, the text entered in to the tbTxData text box is appended to the taRxData text area. If the port is close an error message is displayed to the user.

The PortRead method work in a similar fashion. The stream Read method is used to retrieve data from the port.

Listing 10
Public Sub Connect()
  ' Assumes that the Comm port object
  ' has already been created
  Comm.PortName = tbPort.Text
  Comm.Speed = iBaudrate
  Comm.Parity = iParity
  Comm.DataBits = iDataBits
  Comm.StopBits = iStopBits
  Comm.FlowControl = iFlowControl
 
  bConnected = False
  WriteMsg("Opening Port " &amp; tbPort.Text &amp; " port; \n")
  Try Comm.Open()
  If Error Then
    WriteError("Cannot Open " &amp; tbPort.Text &amp; " port; " &amp; Error.Text)
  Else
    WriteError("Connection Established On Port " &amp; tbPort.Text &amp; " port; " &amp; Error.Text)
    bConnected = True
  Endif
 
End
 
Public Sub PortClose()
  If bConnected Then
    WriteMsg("Closing Port " &amp; tbPort.Text &amp; " port;")
    Try Comm.Close()
    If Error Then
      WriteError("Can't Close " &amp; tbPort.Text)
    Else
      bConnected = False
    Endif
  Else
    WriteMsg("Port already closed")
  Endif  
End
 
Public Sub PortWrite()
  If bConnected Then
    Try Write #Comm, tbTxData.Text
    If Error Then
      WriteError("Can't Write " &amp; tbPort.Text &amp; " port; " &amp; Error.Text)
    Endif
    If bLocalEcho Then 
      WriteData(tbTxData.Text)
    Endif
    tbTxData.Text = ""
  Else
    WriteError("Port not open")
  Endif
End
 
Public Sub PortRead()
  Dim s As String
  If bConnected Then
    Try Read #Comm, s, Lof(Comm)
      WriteData(s)
    If Error Then
      WriteError("Can't Read " &amp; tbPort.Text &amp; " port; " &amp; Error.Text)
    Endif
  Else
    WriteMsg("Port Not Open")
  Endif
End

Gambas is an event driven language. So most of the magic happens via events. The SerialPort object fires an event when the port receives data from the client. The Comm_Read method handles this event and forwards the call to the PortRead method which does the not-so-heavy lifting for the method. Then we provide on Change event handlers for each of the port control lines. These do nothing more than update the appropriate check box for the signal.

Listing 11
' Handle Port Events
Public Sub Comm_Read()
  PortRead()
End
 
Public Sub Comm_RNGChange(iVal As Boolean)
  chkRNG.Value = iVal
End
 
Public Sub Comm_DTRChange(iVal As Boolean)
  chkDTR.Value = iVal
End
 
Public Sub Comm_DSRChange(iVal As Boolean)
  chkDSR.Value = iVal
End
 
Public Sub Comm_CTSChange(iVal As Boolean)
  chkCTS.Value = iVal
End
 
Public Sub Comm_DCDChange(iVal As Boolean)
  chkDCD.Value = iVal
End
 
Public Sub Comm_RTSChange(iVal As Boolean)
  chkRTS.Value = iVal
End

So there you have it! A simple serial terminal in less than 300 lines of code. To use the serial terminal, connect a serial communications device such as the Arduino to your computer’s serial port. If you are using an Arduino you may find that the port provided USB driver is named something like ttyACMx where x is a digit. You’ll need a program on the Arduino that responds to serial communications. I used the Example SerialResponseASCII example located in the Example->Communications directory.

To use this example code simply open the Arduino studio application and Open the example. Then upload it to your Arduino. Once done, close the Arduino studio and open the serial terminal. Configure the serial terminal with a Baudrate of 9600, Data bits = 8, Stop bits = 2, Parity and flow control = none. Then click the connect button. Within a few seconds you should see the connection succeed and three comma separated values should be scrolling down the screen. Next type an “A” into the TxData text box and press the return key or click the send button. The scrolling values should stop. send another value and the Arduino should respond with a set of non-zero values. Fig. below shows the serial terminal connected to an Arduino Uno connected via USB to my development machine.

SerialTerminal-Screenshot

If you would like to learn more about serial communications or RS232, a Google searhc will bring up much information.

You can download the project source code here: Serial-Terminal.tar.

Print Friendly, PDF & Email

editor

Leave a Reply