简单的串口通信工具






4.80/5 (9投票s)
一个简单的串口通信库,包含串口枚举器
引言
在嵌入式设计中,与PC进行通信是很常见的需求。最简单的方法就是串口通信,因为每个微控制器都有UART端口来实现与外界的串口通信。但在计算机上,并不总是那么容易。
在这里,我提供了一个非常简单的串口通信库,具有非阻塞读取和不依赖事件的特性,这在根据软件类型不同时可能是一个优势。
同时,我还提供了一个串口枚举器,这非常有用,以及一个简单的Timer
类,它将允许我们测量间隔并自动执行某些操作。这个timer
类不是事件驱动的,因此您需要轮询间隔的状态才能知道是否该执行某些操作。
在未来的文章中,我将解释如何使用事件驱动的定时器来真正地自动化一个函数。但目前,这个简单的timer
对于我们的应用来说已经足够了。
Using the Code
在代码中,我使用了三个独立的库。一个用于串口通信,一个用于计时,一个用于总结PC中可用的串口。我分别上传了每个库和一个使用它们的示例项目。
RS232 库
这个库提供了一个简单易用的COM端口接口。头文件提供了这些函数
#ifndef rs232_INCLUDED
#define rs232_INCLUDED
#ifdef __cplusplus
extern "C" {
#endif
#include <stdio.h>
#include <string.h>
#ifdef __linux__
#include <termios.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <limits.h>
#else
#include <windows.h>
#endif
int RS232_OpenComport(int, int);
int RS232_PollComport(int, unsigned char *, int);
int RS232_SendByte(int, unsigned char);
int RS232_SendBuf(int, unsigned char *, int);
void RS232_CloseComport(int);
void RS232_cputs(int, const char *);
int RS232_IsDCDEnabled(int);
int RS232_IsCTSEnabled(int);
int RS232_IsDSREnabled(int);
void RS232_enableDTR(int);
void RS232_disableDTR(int);
void RS232_enableRTS(int);
void RS232_disableRTS(int);
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif
这个库由 Teunis van Beelen 编写,更多信息请访问 这里。
COM 端口枚举器
这个库提供了一种简单的枚举PC中可用串口的方法。它并不完美,但可以正常工作。
#ifndef LISTPORTS_H
#define LISTPORTS_H
#define VERSION_LISTPORTS 0x00020000
#ifdef __cplusplus
extern "C"{
#endif
#include <windows.h>
typedef struct
{
LPCTSTR lpPortName; /* "COM1", etc. */
LPCTSTR lpFriendlyName; /* Suitable to describe the port, as for */
/* instance "Infrared serial port (COM4)" */
LPCTSTR lpTechnology; /* "BIOS","INFRARED","USB", etc. */
}LISTPORTS_PORTINFO;
typedef BOOL (CALLBACK* LISTPORTS_CALLBACK)(LPVOID lpCallbackValue,
LISTPORTS_PORTINFO* lpPortInfo);
/* User provided callback funtion that receives the information on each
* serial port available.
* The strings provided on the LISTPORTS_INFO are not to be referenced after
* the callback returns; instead make copies of them for later use.
* If the callback returns FALSE, port enumeration is aborted.
*/
BOOL ListPorts(LISTPORTS_CALLBACK lpCallback,LPVOID lpCallbackValue);
/* Lists serial ports available on the system, passing the information on
* each port on succesive calls to lpCallback.
* lpCallbackValue, treated opaquely by ListPorts(), is intended to carry
* information internal to the callback routine.
* Returns TRUE if succesful, otherwise error code can be retrieved via
* GetLastError().
*/
#ifdef __cplusplus
}
#endif
#elif VERSION_LISTPORTS!=0x00020000
#error You have included two LISTPORTS.H with different version numbers
#endif
typedef BOOL (CALLBACK* LISTPORTS_CALLBACK)(LPVOID lpCallbackValue,
LISTPORTS_PORTINFO* lpPortInfo);
定义中。在示例中,我提供的是
string comPorts[4]; // Vector containing available ports
int port_cnt=0;
/* Callback function that list the available ports */
static BOOL CALLBACK callback(LPVOID lpCallbackValue,LISTPORTS_PORTINFO* lpPortInfo)
{
_tprintf(
TEXT("\"%s\" \"%s\" \"%s\"\n"),
lpPortInfo->lpPortName,lpPortInfo->lpTechnology,lpPortInfo->lpFriendlyName);
comPorts[port_cnt] = lpPortInfo->lpPortName;
port_cnt++;
return TRUE;
}
这个库由 Joaquín Mª López Muñoz 编写。
示例
该示例只是一个控制台应用程序,模拟一个非常简单的终端,将一个字符或字符串
发送到端口,并显示连接到它的设备的响应。它使用 Code::Blocks
在 Windows 7 上编写。
#include <iostream>
#include "rs232.h"
#include "timerclass.h"
#include "listports.h"
#include <tchar.h>
using namespace std;
string comPorts[4]; // Vector containing available ports
int port_cnt=0;
/* Definition of the Callback function that list the available ports */
static BOOL CALLBACK callback(LPVOID lpCallbackValue,LISTPORTS_PORTINFO* lpPortInfo)
{
_tprintf(
TEXT("\"%s\" \"%s\" \"%s\"\n"),
lpPortInfo->lpPortName,lpPortInfo->lpTechnology,lpPortInfo->lpFriendlyName);
comPorts[port_cnt] = lpPortInfo->lpPortName;
port_cnt++;
return TRUE;
}
int main(int argc, char* argv[])
{
int n;
unsigned char buf[4096];
int cport_nr = 4;
int bdrate = 9600;
//unsigned char outBuffer[128];
string outBuffer;
ListPorts(callback,NULL); //Calling to the list ports function
cout << "Available ports: " << endl;
for(int i=0; i<port_cnt; i++)
{
cout << (i+1) << ": " << comPorts[i] << endl;
}
cout << endl << "Choose a port ";
cin >> cport_nr;
cport_nr--; // according to rs232.h, the port numbers start on 0 for COM1
if(RS232_OpenComport(cport_nr, bdrate)) //Open the port
{
cout << "Can not open com port " << comPorts[cport_nr];
return(0);
}
while(1)
{
//n = RS232_PollComport(cport_nr, buf, 4095);
cout << "Type message to send" << endl << "Type 'quit' to exit" << endl;
cin >> outBuffer;
if(outBuffer == "quit")
{
RS232_CloseComport(cport_nr);
return 0;
}
RS232_SendBuf(cport_nr, (unsigned char*) outBuffer.c_str(), outBuffer.size());
Sleep(100);
n = RS232_PollComport(cport_nr, buf, 4096);
if(n>0)
{
buf[n]=0;
cout << "Received: " << buf << endl << endl;
}
buf[0]=0;
}
}
在包含库之后,是端口监听器回调函数的定义。它显示可用的端口并将它们的名称存储在字符串
中。
然后在 main
函数中,首先调用 ListPort
函数并再次显示可用的端口。询问所需的端口并尝试打开它。如果端口已打开,程序将进入一个无限循环,直到用户输入 'quit'。
在循环中,程序会询问要发送的消息并将其放入 COM 端口。
RS232_SendBuf(cport_nr, (unsigned char*) outBuffer.c_str(), outBuffer.size());
等待 100 毫秒并轮询端口以获取响应
n = RS232_PollComport(cport_nr, buf, 4096);
如果有任何消息,它将显示在屏幕上
if(n>0)
{
buf[n]=0;
cout << "Received: " << buf << endl << endl;
}
在截图中,它正在与充当回显器的 Arduino 板进行通信。