NOTE (18-12-2012): Since posting this, I have updated SerialSend to add some additional useful features and make more robust. The updated version is available from the SerialSend page.
When I’m building robots, I sometimes find it useful to send short commands from the PC to a microcontroller (usually a dsPIC30F4011) in real-time via a USB-to-serial adapter. At the moment, one of the engineers in my Robotics module (Anthony Gaule) is trying to send commands from a machine vision program running on his laptop to a miniature SCARA arm that he has built (controlled by a dsPIC30F4011). Here’s the little Windows program of mine that he’s using. It just sends one word of text to an external device via a user-specified COM port. Binary download (from my github page):
SerialSend.exe (18kB, 6-12-2011)
Here’s the full source code:
// // SerialSend.c - This program sends text via serial port // Written by Ted Burke - last updated 6-12-2011 // // Command line arguments are used to specify the text // to send and the serial port to use. The baud rate used // is currently always 38400 baud. The text cannot contain // any spaces. // // argv[1] = device name // argv[2] = text to send // // To compile with MinGW: // // gcc -o SerialSend.exe SerialSend.c // // To compile with cl, the Microsoft compiler: // // cl SerialSend.c // // To run (this example sends the characters "S365" via COM1): // // SerialSend COM1 S356 // // References: // // Robertson Bayer, "Windows Serial Port Programming", March 30, 2008 // (I used code from Bayer's serial port tutorial as my starting point) // #include <windows.h> #include <stdio.h> int main(int argc, char *argv[]) { // Declare variables and structures HANDLE hSerial; DCB dcbSerialParams = {0}; COMMTIMEOUTS timeouts = {0}; DWORD dwBytesWritten = 0; char dev_name[MAX_PATH]; char text_to_send[MAX_PATH]; // Parse command line arguments if (argc < 3) { fprintf(stderr, "Usage:\n\n\tSerialSend DEVICE_NAME TEXT_TO_SEND\n"); return 1; } strcpy(dev_name, argv[1]); strcpy(text_to_send, argv[2]); // Open the specified serial port (first command line argument) fprintf(stderr, "Opening serial port %s...", dev_name); hSerial = CreateFile(argv[1], GENERIC_READ|GENERIC_WRITE, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); if (hSerial==INVALID_HANDLE_VALUE) { fprintf(stderr, "Error\n"); return 1; } fprintf(stderr, "OK\n"); // Set device parameters (38400 baud, 1 start bit, // 1 stop bit, no parity) dcbSerialParams.DCBlength = sizeof(dcbSerialParams); if (GetCommState(hSerial, &dcbSerialParams) == 0) { fprintf(stderr, "Error getting device state\n"); CloseHandle(hSerial); return 1; } dcbSerialParams.BaudRate = CBR_38400; dcbSerialParams.ByteSize = 8; dcbSerialParams.StopBits = ONESTOPBIT; dcbSerialParams.Parity = NOPARITY; if(SetCommState(hSerial, &dcbSerialParams) == 0) { fprintf(stderr, "Error setting device parameters\n"); CloseHandle(hSerial); return 1; } // Set COM port timeout settings timeouts.ReadIntervalTimeout = 50; timeouts.ReadTotalTimeoutConstant = 50; timeouts.ReadTotalTimeoutMultiplier = 10; timeouts.WriteTotalTimeoutConstant = 50; timeouts.WriteTotalTimeoutMultiplier = 10; if(SetCommTimeouts(hSerial, &timeouts) == 0) { fprintf(stderr, "Error setting timeouts\n"); CloseHandle(hSerial); return 1; } // Send specified text (second command line argument; // cannot contain spaces) fprintf(stderr, "Sending text: %s\n", text_to_send); if(!WriteFile(hSerial, text_to_send, strlen(text_to_send), &dwBytesWritten, NULL)) { fprintf(stderr, "Error writing text to %s\n", dev_name); } else { fprintf(stderr, "%d bytes written to %s\n", dwBytesWritten, dev_name); } // Close serial port fprintf(stderr, "Closing serial port..."); if (CloseHandle(hSerial) == 0) { fprintf(stderr, "Error\n", dev_name); return 1; } fprintf(stderr, "OK\n"); // exit normally return 0; }
I’m planning to develop this program a little further to make it more flexible so that it can be used in a wider variety of applications. Features I’m thinking of adding include:
- Send longer strings, including ones that contain spaces.
- Select baud rate.
- Specify a time delay between transmitted bytes.
- List available serial ports.
- Default to first serial port.
- Default to highest numbered serial port.
- Send the contents of a file.
Thanks! This has helped a lot! I just had to find out how to use COM ports larger than 9. That’s also not straightforward in windows.
Thanks R, I’m delighted you found it useful!
Did you find your answer to COMs over 9?
This works with batchloaf’s awesome little exe.
SendSerial \\.\COMxx E=MC2
wow amazing ,,thanks sir
The code you have here is able to send spaces if the 2nd argument is in quotes when run. Anyway, this works great, except I had to change the baud rate (not a big deal), and I had to add a \r\n to the send to get my device (projector) to work with the output sent.
Great, glad you found it useful. I’ve found myself using it quite a bit, so I suppose I should tidy it up a bit (e.g. configurable baudrate etc). Anyway, thanks for the feedback.
Works a treat.
I noticed in your REM statements:
“017 // To compile with cl, the Microsoft compiler:
018 //
019 // cl SerialSend.c
Does this mean the code could be compiled with Visual Studio 2012 C++
Could certainly use this program if I new how to modify it.
Hi Richard,
Yes, there should be no problem compiling this with Visual Studio. I suppose you’d need to create a new “Win32” project. If you’re using the New Project Wizard, I think you’ll want to select something like “Empty project”. Unfortunately, I can’t remember the exact details of creating a new project in Visual Studio because it’s been quite a while.
By the way, if you have Visual Studio installed, then cl.exe is already on your computer. In the Visual Studio group in your program menu you may find something like “Visual Studio command line” or somthing like that which opens a console window with the path set for running cl. The command I suggest in the code comments can be run in this console window.
Ted
Thanks for the quick reply.
Sunday morning was free so I compiled it “Win32” project and with the wizard “Empty project” I don’t think I made any mistakes. Displayed 2 warnings and 2 errors.
Line(21): warning C4996: ‘strcpy’: This function or variable may be unsafe. Consider using strcpy_s instead. h(110) : see declaration of ‘strcpy’
Line(22): warning C4996: ‘strcpy’: This function or variable may be unsafe. Consider using strcpy_s instead. h(110) : see declaration of ‘strcpy’
Line(27): error C2664: ‘CreateFileW’ : cannot convert parameter 1 from ‘char *’ to ‘LPCWSTR’
Line(26): error IntelliSense:argument of type “char*” is incompatable with parameter of type “LPCWSTR”
I changed the ‘strcpy’ to ‘strcpy_s’ as suggested above which fixed the 2 warnings and now only left with the 2 errors.
Getting close. Cheers Richard
Hi Richard,
Oh yes, I remember seeing this before. The basic problem here is that when Visual Studio creates a new project, by default it sets the character type to Unicode in the project settings. To facilitate programs that represent strings either with Unicode (multi-byte characters) or single-byte characters, many Win32 functions (including CreateFile) come in two versions, one which expects string arguments in Unicode format and one which expects single-byte character strings. For example, the two versions of CreateFile are CreateFileW (the Unicode version) and CreateFileA (the single-byte character version). When you compile your project, Visual Studio actually substitutes one or other of these for your CreateFile call. Which one it uses depends on the project settings. Since your project is probably set to use Unicode strings, Visual Studio is probably using “CreateFileW” which expects a Unicode string for the filename. However, your filename is actually a single-byte character string.
Anyway, to cut a long story short, there are a few different solutions to this. Two easy ones are:
You only need to do one or the other of those solutions – not both. Let me know how you get on.
Ted
You where spot on Ted. I took the easy road this time and just added a capital A. Compiled perfectly and this is where I’m sure the fun part starts, learning how to modify the code to suit my needs. I have learnt a lot about C++ in the past few days, as this is my first experience with Visual Studio 2012. I know there is a lot more to learn about C++.
Thanks very much for your help.
Cheers Richard
You’re very welcome! Best of luck with whatever you’re working on.
By the way, if you’re interested in Win32 programming using C/C++, check out theForger’s Win32 tutorial. It’s not a C++ tutorial, but it’s the best introduction I found to the Win32 API and got me up and running really fast.
Ted
hi
i have been surfing fr a long tym and didnt find anytng helpful after reading your blog i feel u will definitely be a grt help to me..i am doin a project in vc++ 6.0 standard edition where i a have to ” send 5 bytes to comport via rs 232″ without any gui. so my project will be basically a simple c prg to send bytes which i am unable to do since a month:(plz help
Hi Sharmistha,
I should be able to help you with this. If you can provide the following details, I’ll sketch out some simple example code.
Don’t worry, we should probably have your problem solved very soon!
Regards,
Ted
hello
thanks a lot for replying…
1.yes…it is d same comport number…however my sir has told i can use any com port here its just it has to receive the bytes from the c program.
2.yes, i am sending 5 bytes only it can be random 5 bytes like 0xAA, 0x00, 0x11,0xBB,0x95.
so on…
3. i am using windows xp and visual c++6.0 version standard edition.
hope to get a reply soon…
regards
sharmistha
hello
thanks a lot for replying…
1.yes…it is d same comport number…however my sir has told i can use any com port here its just it has to receive the bytes from the c program.
2.yes, i am sending 5 bytes only it can be random 5 bytes like 0xAA, 0×00, 0×11,0xBB,0×95.
so on…
3. i am using windows xp and visual c++6.0 version standard edition.
hope to get a reply soon…
regards
sharmistha
Reply
Please have a look at my two new posts:
Writing bytes to a serial port in C
Simple trick for sending characters to a serial port in Windows
can u help me to read bytes in a serial port in c
Hi Ramesh,
I spent a while yesterday trying to prepare a simple C example of reading the serial port. However, I’m having a problem because my USB-to-serial adapter doesn’t work in Windows 8, so I can’t debug the code on my new laptop 😦
I’ll need to track down another USB-to-serial adapter. Once I do, I’ll post the example.
Ted
okay..thanks buddy
Hi Ted ,
I know its not possible to read and write a serial port in c language simultaneously
i think we can do it in C threads…. can u jst help me to do read/write serial port in C threads
hi
that was really amazing:) i am so much thankful to u…and would like to keep updating you about my project 🙂
would like to ask you one more thing in place of the decimal values can i send hex values like”0xaa, 0xbb…etc and in place of com22 i can replace it by com 1 right?
if not plz correct me !!!
thanks again:)
sharmistha
Hi Sharmistha,
You’re welcome. There’s no problem replacing the 5 byte values I used with arbitrary hex values. Just modify lines 26 to 30 as follows:
Also, to use COM1 instead of COM22, just replace “\\\\.\\COM22” with “\\\\.\\COM1” wherever it appears in the program (just line 40, I think).
Let me know how you get on.
Regards,
Ted
hi ted
thanks to you the program is working fine with com1 and the hex values..i have conected the port with rs 232 pin to the oscilloscope and we could see the pulses corresponding to the 5 bytes send….so it worked:)
regards
sharmistha
Bravo! That’s great news. Best of luck with the rest of your project.
Ted
Pingback: C and Arduino
Hi,
I want to send this hexadecimal string: 100201000a0b1003100201063c001e00251003100201093c00341003
I am using this command: SerialSend.exe /baudrate 4800 /devnum 05 “0x100201000a0b1003100201063c001e00251003100201093c00341003”
I do not find anything wrong,
I cann’t specify the parity Even.
Regards
Rafa K.
For such simple task it might be easier to simply download some RS232 terminal program.
For example docklight has many options and among those also to define strings to send or parts of the string, and use joker signs to be prompted for those parts of string sent. Great features and also scripting.
Their homepage is
http://docklight.de/
Still great tutorial there! 🙂
Hi Schutki,
The original purpose of SerialSend was to facilitate extremely lightweight scripting of simple command transmission from PC to serial-connected device. It was primarily intended either for use in a batch file or to be called from a C program using the system() function. Of course, there are a number of serial comms programs for Windows that support scripting, but they tend to be more substantial applications and all the ones I’m aware of are commercial products which either must be paid for or have some legal restrictions on their use. SerialSend is very lightweight, very simple, and it’s open source. It certainly won’t do all the things a more advanced program will do, but if someone wants to modify for their own needs they can; if they want to deploy it (or a modified version of it) as part of solution for a customer or whatever that’s no problem. All you need to do is include the one little exe file in your folder and it’s ready to go.
For me, the most useful feature of SerialSend is that it can automatically find the highest available serial port number and send the message to it. This gets around the problem of my USB-to-serial converter being assigned a different number each time it’s plugged in. This feature is not included in the early version shown in this post, but it’s in the current version, which is here.
Ted