Serial Communications between a PC and an Arduino Using Lazarus / Free Pascal

I’ve communicated between a PC and an Arduino via UDP in the past, but I have never tried to use the serial connection (USB) on the Arduino. So in this experiment I have setup an arduino with various sensors and send commands from a PC to read sensors.

Since Lazarus / Free Pascal is my language of choice on the PC, the PC side will be written in that language. There are lots of examples of using C, Python, Processing, etc. on the PC side. If that is what you are trying to do, go do some googling.

As far as hardware goes, on the arduino I have a slide switch, motion detector, and LED. I want to allow the PC to read the position of the slide switch. If the switch is on, then it reads the motion detector. If motion is detected, then the PC sends a command to turn on the LED. I also want to play a wave file. Since that is not overly easy on the Arduino, once the PC detects motion it will play a wave file itself.

To allow the PC to talk to the Arduino, I setup a simple protocol. The PC will send a single byte ‘command’ to the arduino:

1 – Is Switch On?
2 – Is motion detected?
3 – Turn LED on
4 – Turn LED off
5 – Alive Packet (sent by Arduino only)

The arduino responds by echoing the command and if there is any additional information, it is appended after the command, so the PC would transmit a “1” to determine if the slide switch is on. If it is, the arduino will return “1T”.

I decided to ‘packetize’ these commands with a header that contains a check sum and the length of the packet. This allows me to verify if the data got transmitted correctly. Not that I really expect that to be a problem over this USB cable, but I want to do it as part of the exercise in case I ever need the ability.

A header is prefixed to the command. This is a very simple header:

start byte    length        function
0             1             checksum
1             2             length of packet
3             n             payload which consists of:
 3             1             Command
 4             n             response

The schematic for my hardware is as follows:


and here is the actual hardware:


I’ll go thru some of the highlights of the  Free Pascal program on the PC side first. The full source code is too long to post directly, so a download is available below.

I wrote the program to run as a console program (e.g. character mode, not windowed). I probably wouldn’t do that for a production program, but it simplifies the source code so you can more easily look at the source to understand what it does.

I used the serial library called synaser. This was one of the libraries recommended on the Lazarus site:

I haven’t made it that far yet, but I expect this library to work on linux as well. It appears it was designed to do that.

I will admit I had a heck of a time getting synaser to work for me. I spent several hours and was about to get a different library. I started with the waitingData and recvByte methods and simply could not get it to work (see Nov 2015 update at end). Bytes were being dropped. I attempted to use recvString and it had issues as well.

I wish I know exactly what I did to get things running. I suspect it was switching the waitingData method to the canRead method. But I don’t have a serial protocol analyzer and couldn’t see exactly what was happening on the line so I may have been doing something stupid and accidently fixed it. This library seems to be well used so I figure the problem was mine. I just am not sure what that problem was.

Since this is a test program I don’t spend a lot of trouble dealing with error conditions (I check but I just bomb the program). Also, I don’t tend to write object-oriented code and definitely not when I’m just messing around.

My coding is very ‘different’ from most. I am very old school and expect things to align. When they do I can very quickly find what I want when looking thru code. So there is A LOT of white space.

The outer block is quite simple: if the switch is on and we get motion, turn on the LED and play a sound:



while (true) do begin

    if isSwitchOn then
        if isMotionDetected then begin


    sleep(1*1000);                                            // normally check once a second
    end; // while;

In the isSwitchOn and isMotionDetected procedures, we send a simple command to the arduino via p2a_sendStr, then read the response from the arduino using p2a_getstr:


s := '';
if not p2a_getStr(s) then begin
    writeln('p2a_sendStr returned false');

Then we act on the response:

if (uppercase(s[2]) = 'T') then
    isMotionDetected := true
    isMotionDetected := false;

The p2a_getStr procedure calls ‘private’ procedures to receive the packet from the serial port and then decode it (checking and removing the header):

// get the next packet from the arduino
if (not p2a_i_recvPacket(packet)) then begin

// decode the packet. if any error, return false
if (not p2a_i_decodePacket(packet, s)) then begin

The p2a_i_recvPacket procedure is the one I had the most trouble with, getting data consistently from the serial port. Changing this may cause problems.

Because I couldn’t get synaser’s recvString method to work, I simply watch for characters and append them to the packet as I build it. When I get a linefeed, I’m done. To prevent the program from hanging if LF is never received, I have a 5 second timeout in my own code that will cause the infinite while to be exited.

Also note that while I exit on LF, I need to eat the CR character that proceeds it.

t := incSecond(now, 5);

// initialize packet, then read bytes until LF occurs
packet := '';
while (true) do begin
    if compareDateTime(now, t) > 0 then begin
        writeln('Timeout waiting for arduino response.');
        if commPort.WaitingData = 0 then
           c := commPort.RecvByte(100);
           case chr(c) of
               #10: break;
               #13: begin end;
                  s := s + chr(c);
               end; // case
        p2a_i_recvPacket := false;
    end; // while

Now that we have a packet it will need to be decoded. This is done by p2a_i_decodePacket.  Decode will check the physical packet length, then the logical packet length, and finally get a checksum of the packet and verify the data didn’t change during transit:

s := '';
// verify physical packet isn't too short
if (length(packet) < 4) then begin

// verify imbedded len is within acceptable range
len := p2a_i_getPacketLen(packet);
if ((len < 3) or (len > maxPacketLen)) then begin

// verify cksum received matches cksum computed
cksum := p2a_i_computeChecksum(packet);
if (chr(cksum) <> packet[1]) then begin

// transfer the packet payload to s
for k := 4 to len do
    s := s + packet[k];

p2a_i_decodePacket := true;

The p2a_i_computeChecksum procedure calculates a very simple, quick and dirty, single byte checksum. Since the packet is being transmitted over a serial connection, I need to make sure I don’t generate something that is going to cause problems for the hardware. I’m sure this procedure would make a purist choke, but as my boss used to say, “it’s good enough for who it’s for”.

I compute the checksum by XOR’ing all bytes in the packet (except the checksum byte). If the first bit is set I force it to 0. Finally if the result is < 32, I set a bit to bring it back into the displayable part of the character set.

cksum := 0;

for k := 2 to p2a_i_getPacketLen(packet) do begin
    cksum := cksum xor ord(packet[k]);
    end; // for

// Clear high order bit as it might have trouble being transmitted.
// also turn any control characters into a normal character.
cksum := cksum and $7F;
if (cksum < $20) then
    cksum := cksum or $20;

p2a_i_computeChecksum := cksum;

Those are the key points to the Free Pascal code on the PC side. All of the hardware is monitored/activated in the same manner. So let’s look at the arduino side.

There is honestly very little on the arduino side of note. If you are familiar with programming the arduino, there will be nothing here to surprise you.

The setup function assigns the various pins to the hardware devices.

Inside of the loop function, the motion detector is checked for motion. If motion is detected, a timer starts and keeps being advanced as long as there is motion. Once the motion stops long enough, the timer pops.

Commands are retrieved from the serial port and then executed in the loop function. This should be pretty self-explanatory:

        if (strlen(s) == 0)

        switch (s[0]) {
            case '0':                                            // no command received
            case '1':                                         // is SW on?
                if (digitalRead(swPin) == HIGH)
            case '2':                                            // is motion detected?
                if (motionDetected())
            case '3':                                         // turn LED on
                digitalWrite(externalLEDPin, HIGH);
            case '4':                                            // turn LED off
                digitalWrite(externalLEDPin, LOW);
            case '5':                                            // alive packet
                digitalWrite(internalLEDPin, HIGH);
                aliveTimeout = millis() + (10L * 1000L);    // when to turn alive LED out again

Note that the functions I use in the arduino are named the same as those for the PC and do the same thing. So in the example above, “a2p_sendStr(“5″)” will send the PC back the string “5”.

And a2p_sendStr calls a2p_i_encodePacket and a2p_i_xmitpacket on the arduino just as on the PC. So if you figure out the code on either side; the other side works exactly the same.

recvPacket and xmitPacket read the serial line just as any other arduino app would do. There is nothing surprising there:

void a2p_i_xmitPacket(
    char*                                 packet
    ) {
    int                                    i;
    int                                    len;

    len = a2p_i_getPacketLen(packet);

    for (i = 0; i <= len-1; i = i + 1) {


    } // a2p_i_xmitPacket

Honestly, encode, decode, and computeChecksum work exactly the same way as they did on the PC, I simply rewrote them in C for the arduino.

Once implemented, this experiment works perfect. I can communicate with the arduino from the PC and I have no issues with dropped characters. Response is not instantaneous at the PC – on avg it will take 1/2 a second for the PC to respond to movement since the loop timeout is 1s. But that is more than adequate for any kind of hardware monitoring I would expect to do from a PC.

All of the source can be found in this zip file:

Here is a video demoing the hardware:

Nov 2015 Update:

Started working on a new Pascal program requiring the use of the Synapse library. Again, I could not get recvbyte to work properly e.g.:

// this is psuedo-code - not syntactically correct

while (socket.waitingData> 0) do begin

This would print 1 character in the packet and be done.

A little more experimenting and I discovered the recvByte method clears waitingDatathe waitingData count. So you might enter the while statement with 5 characters, but after you read the first character, the next iteration has waitingData set to 0 rather than 4.

To get around this problem, I need to know the characters waiting and read them all before calling waitingData again. Something like this:

i := socket.datawaiting;
for k := 1 to i do 

I think this is the first implementation of a “byte available” type of function that gets cleared when you retrieve a single byte. Kind of stupid, but at least know I and now you know.

This entry was posted in c-arduino, c-lazarus and tagged , . Bookmark the permalink.

14 Responses to Serial Communications between a PC and an Arduino Using Lazarus / Free Pascal

  1. Pingback: Serial Communications (USB) between a Raspberry Pi and an Arduino Using Lazarus / Free Pascal | Big Dan the Blogging Man

  2. Pingback: UDP Communications between a PC and an Arduino Using Lazarus / Free Pascal | Big Dan the Blogging Man

  3. Pingback: TCP Communications between a PC and an Arduino Using Lazarus / Free Pascal | Big Dan the Blogging Man

  4. I fear the Link to the source is dead. I could not load it
    I would be glad ich you send me the code or post a link I can use.

  5. Maxi DMaxiD says:

    good job!!
    can create a library?

    • A grateful dude says:

      Thankyou very much. I was thinking on killing my self due to that recvString not working and dropping data like crazy. Using waitingData seems to work for some reason.

  6. Gerard says:

    Very nice information! My question concerning Serial Communication PC -Arduino using Lazarus: How did you make Lazarus accept Synaser software so I can use Serial communication in Lazarus? Thanks!

  7. ikin says:

    I have no arduino, but I have another micro controller, how does the arduino work? I want emulate the arduino using VSPE and H-Term, what should I send from H-Term?

  8. Frank says:

    There is one piece I do not understand. The function PacketLen loops through the header at positions 2 and 3 where the variable len is first multiplied by 10 and then overwritten:
    len := len * 10;
    len := ord(packet[i]) – ord(‘0’);

    before exiting the loop…

    • Dan TheMan says:

      You found a bug, Frank. Since this program never generates a packet > 9 bytes, the bug isn’t encountered.

      Line 514, “len := ord(packet[i]) – ord(‘0’);” should read “len := len + ord(packet[i]) – ord(‘0’);”

      Also, I never laid out the record structure in this program.

      Byte 1 [I use the option that starts string bytes at 1 NOT 1]: check sum.
      Byte 2-3 Length of packet
      Byte 4-n Payload.

  9. Reid Simonsen says:

    I am curious if you were able to control several Arduino with single PC on RS485?

  10. Dan TheMan says:

    I’ve never used RS-485. Using RS-232, there should be no issue using multiple COM ports on the PC to communicate to multiple Arduinos. Just have a different process or thread on the PC to handle each COM port. But that requires individual wiring to each Arduino.

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.