65.9K
CodeProject 正在变化。 阅读更多。
Home

简单的串口通信工具

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.80/5 (9投票s)

2014年8月29日

CPOL

2分钟阅读

viewsIcon

49777

downloadIcon

124

一个简单的串口通信库,包含串口枚举器

引言

在嵌入式设计中,与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 板进行通信。

© . All rights reserved.