C++编程笔记:串口通信在windows环境和linux环境下的异同和代码实现

1. 串口通信流程

不管是对于windows还是linux,串口通信的流程都是以下4步: 
1. 打开串口 
2. 设置串口 
3. 发送、接收数据 
4. 关闭串口

1.1 头文件配置

  • windows下:
#include <Windows.h>       /*Windows API函数库*/
  •  
  • linux下:
#include     <fcntl.h>      /*文件控制定义*/
#include     <termios.h>    /*POSIX 终端控制定义*/
#include     <stdio.h>      /*标准输入输出定义*/
#include     <stdlib.h>     /*标准函数库定义*/
#include     <unistd.h>     /*Unix 标准函数定义*/
#include     <sys/types.h>
#include     <sys/stat.h>

1.2 打开串口

  • windows下: 
    用CreateFile函数来打开串口句柄,首先看到,该类中的串口句柄为HANDLE SerialHandle;该句柄在应用CreateFile()函数创建后,就得到了指定了的串口句柄,其后,几乎所有的函数要对串口进行操作时,必须通过SerialHandle进行。
HANDLE SerialHandle;

char buf[256] = {};
sprintf(buf, "\\\\.\\%s", com);         //格式化字符串
//打开串口
SerialHandle = CreateFileA(buf, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0);    //同步模式打开串口

if (SerialHandle == INVALID_HANDLE_VALUE)           //打开串口失败
        return false;
  • linux下: 
    在Linux下串口文件是位于/dev下,串口1为/dev/ttySO,串口2为/dev/ttySl,通过调用open()打开串口设备,返回一个整形文件句柄,以后所有的端口操作都针对这个句柄进行。如果open()出错,则返回.1。open()函数带有2个参数,其中参数1为要打开的设备文件名,参数2为打开方式。
int fd; 
//打开串口
fd = open(com, O_RDWR|O_NOCTTY|O_NDELAY);       //O_RDWR 读写方式打开;O_NOCTTY 不允许进程管理串口(不太理解,一般都选上);O_NDELAY 非阻塞(默认为阻塞,打开后也可以使用fcntl()重新设置)

if (-1 == fd)
    return false;

1.3 设置串口

  • windows下: 
    在打开通讯设备句柄后,常常需要对串口进行一些初始化配置工作。这需要通过一个DCB结构来进行。DCB结构包含了诸如波特率、数据位数、奇偶校验和停止位数等信息。在查询或配置串口的属性时,都要用DCB结构来作为缓冲区。一般用CreateFile打开串口后,可以调用GetCommState函数来获取串口的初始配置。要修改串口的配置,应该先修改DCB结构,然后再调用SetCommState函数设置串口。
    //设置串口参数
    //读串口原来的参数设置
    DCB dcb;
    GetCommState(SerialHandle, &dcb);   //串口打开方式

    //串口参数配置 
    dcb.DCBlength = sizeof(DCB);
    dcb.BaudRate = 9600;
    dcb.ByteSize = 8;
    dcb.Parity = EVENPARITY;
    dcb.StopBits = ONESTOPBIT;
    dcb.fBinary = TRUE;                 //  二进制数据模式
    dcb.fParity = TRUE;

    if (!SetCommState(SerialHandle, &dcb))
        return false;

    SetupComm(SerialHandle, 1024, 1024);    //设置缓冲区
    return true;
  • linux下: 
    进行串口操作之前,先要对串口通讯的波特率、校验位、输入/输出方式等参数进行设置。Linux下的串口设置实际上是根据POSIX规范来设置的。POSIX规范是由IEEE提出的,用于定义一系列可移植的操作系统接口。串口设置的所有参数都包含在Termios结构中。Linux提供了两个函数对termios进行操作,它们是tcgetattr()和tcsetattr()。tcgetattr()函数获得指定串口的设置情况,tesetattr()函数用来设置串口的参数。
    //串口参数配置 
    struct termios options;                     // 串口配置结构体
    tcgetattr(fd,&options);                     // 获取串口原来的参数设置
    bzero(&options,sizeof(options));

    options.c_cflag  |= B9600 | CLOCAL | CREAD; // 设置波特率,本地连接,接收使能
    options.c_cflag &= ~CSIZE;                     // 屏蔽数据位
    options.c_cflag  |= CS8;                    // 数据位为 8 ,CS7 for 7 
    options.c_cflag &= ~CSTOPB;                // 一位停止位, 两位停止为 |= CSTOPB
    options.c_cflag |= PARENB;                  // 有校验
    options.c_cflag &= ~PARODD;                // 偶校验

    tcflush(fd, TCIOFLUSH);                     // 清除所有正在发生的I/O数据。
    if(tcsetattr(fd, TCSANOW, &options)!=0)     // TCSANOW立刻对值进行修改
        return  false;          

    return true;

1.4 发送、接收数据

  • windows下: 
    使用ReadFile和WriteFile读写串口,在用ReadFile和WriteFile读写串口时,既可以同步执行,也可以重叠执行。在同步执行时,函数直到操作完成后才返回。这意味着同步执行时线程会被阻塞,从而导致效率下降。在重叠执行时,即使操作还未完成,这两个函数也会立即返回,费时的I/O操作在后台进行。ReadFile函数只要在串口输入缓冲区中读人指定数量的字符,就算完成操作。而WriteFile函数不但要把指定数量的字符拷入到输出缓冲区,而且要等这些字符从串行口送出去后才算完成操作。
    //发送数据
    char pData[] = {};
    DWORD WriteNum = 0;
    if (WriteFile(SerialHandle, pData, sizeof(pData), &WriteNum, 0))
            return true;

    return false;
  • linux下: 
    串口配置完成后,把串口当作文件来读写。调用write()函数读写端口,返回实际读写的字节数,如果有错误发生则返回一1。在主线程中写数据,因为写是可以控制的,write 
    (fd,&WriteData,sizeof(WriteData));而读的时候不知道数据什么时候会到,所以要建立一个线程专门用来读数据,在这个线程中,循环地用Read读串口。在程序结束时关闭串口close(fd)。串口配置完成后,把串口当作文件来读写。调用read()函数读写端口,返回实际读写的字节数,如果有错误发生则返回一1。
    //发送数据
    char pData[] = {};
    int WriteNum = write(fd,pDataOpenO01,sizeof(pDataOpenO01));
    if (WriteNum!=-1)
        return false;

    return true;

1.5 关闭串口

  • windows下: 
    调用ClosePort()函数来关闭串口。
    if (SerialHandle != INVALID_HANDLE_VALUE)
    {
        CloseHandle(SerialHandle);
        SerialHandle = INVALID_HANDLE_VALUE;
        return true;
    }
    else
        return false;
  • linux下: 
    关闭串口就是关闭文件。使用close()关闭打开的串口,唯一的参数是打开串口的文件描述符。
    int flag=close(fd);
    if (flag!=0)
        return false;

    return true;

Reference

猜你喜欢

转载自blog.csdn.net/qqwangfan/article/details/81178560