简单的串行通信实用程序

一个简单的串行通信库,带有串行端口枚举器

介绍

在嵌入式设计中,需要与 PC 进行通信的通道是很常见的。最简单的方法是串行通信,因为每个微控制器都有 UART 端口来与外界进行串行通信。但在计算机上,这并不总是那么容易。

在这里,我提出了一个非常简单的串行通信库,具有非阻塞读取和不依赖事件的功能,这可能是一个优势,具体取决于我们需要的软件类型。

除此之外,我还提供了一个非常有用的串行端口枚举器,以及一个简单的Timer 类,它允许我们测量间隔并自动执行一些操作。此类timer 不是事件驱动的,因此您必须轮询间隔的状态以了解是否该执行某些操作。

在以后的文章中,我将解释如何使用事件驱动的计时器来真正实现功能的自动化。但就目前而言,这个简单的功能timer 对于我们的应用程序来说已经足够了。

使用代码

在代码中,我使用三个独立的库。一种用于串行通信,一种用于计时,一种用于 PC 中可用端口的摘要。我分别上传每个库以及使用它们的示例项目。

RS232库

该库为 PC 的 COM 端口带来了简单易用的界面。标题提供了这些功能:

C++
#ifndef rs232_INCLUDED#define rs232_INCLUDED#ifdef __cplusplusextern "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>#endifint 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 中可用串行端口的简单方法。它并不完美,但效果很好。

C++
#ifndef LISTPORTS_H#define LISTPORTS_H#define VERSION_LISTPORTS 0x00020000#ifdef __cplusplusextern "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
要使用它,只需在代码中定义您想要对列出的端口执行的操作
C++
typedef BOOL (CALLBACK* LISTPORTS_CALLBACK)(LPVOID              lpCallbackValue,
                                            LISTPORTS_PORTINFO* lpPortInfo);

定义。在示例中,我提供:

C++
string comPorts[4]; // Vector containing available portsint 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 编写。

这个例子

该示例只是一个控制台应用程序,模拟一个非常简单的终端,该终端发送一个字符或string 到端口广告以显示连接到它的设备的响应。它是使用Code::Blocks Windows 7 编写的。

C++
#include <iostream>#include "rs232.h"#include "timerclass.h"#include "listports.h"#include <tchar.h>using namespace std;

string comPorts[4]; // Vector containing available portsint 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;

  }
}

包含库之后是端口列表器的回调函数的定义。它显示可用的端口并将其名称存储在string.

然后在main 函数中,首先调用该ListPort 函数并再次显示可用端口。询问所需的端口并尝试打开它。如果端口打开,程序将进入无限循环,直到用户键入“退出”。

在循环中,程序要求发送消息并将其放在 COM 端口上。

C++
RS232_SendBuf(cport_nr, (unsigned char*) outBuffer.c_str(), outBuffer.size());

等待 100 毫秒并轮询端口以获取响应:

C++
n = RS232_PollComport(cport_nr, buf, 4096);

如果有任何消息,则会显示在屏幕上:

C++
if(n>0)
    {
        buf[n]=0;
        cout << "Received: " << buf << endl << endl;
    }

在捕获过程中,与充当回声器的 Arduino 板进行通信。

图1


Powered By Z-BlogPHP 1.5.2 Zero

175.es

. theme by Plat together