封装了一下Linux下的串口操作

serial.h:

#ifndef _SERIAL_H_
#define _SERIAL_H_

#include <cstddef>
#include <termios.h>

class Serial
{

public:
    Serial();
    int openPort(const char *path);
    int set(speed_t speed);
    int send(const void *buf, size_t size, int sec, int msec, bool clBuf);
    int recv(void *buf, size_t size, int sec, int msec);
    int closePort();

private:
    int fd;
};

#endif // _SERIAL_H_

serial.cpp:

#include "serial.h"
#include <iostream>
#include <fcntl.h>
#include <sys/select.h>
#include <unistd.h>

Serial::Serial()
{
    fd = -1;
}

int Serial::openPort(const char *path)
{
    fd = open(path, O_RDWR);
    if (fd == -1)
    {
        return -1;
    }

    return 0;
}

int Serial::set(speed_t speed)
{
    struct termios options;

    if (fd == -1)
    {
        std::cout << __LINE__ << " serial fd error" << std::endl;
        return -1;
    }
    // 获取当前串口设置
    tcgetattr(fd, &options);
    // 设置串口工作在本地模式
    options.c_cflag |= CLOCAL | CREAD;
    cfmakeraw(&options);
    // 设置波特率
    if (cfsetispeed(&options, speed) < 0 || cfsetospeed(&options, speed) < 0)
    {
        perror("set speed fail");
        return -1;
    }
    // 8位数据位
    options.c_cflag &= ~CSIZE; // 用数据位掩码清空数据位设置
    options.c_cflag |= CS8;
    // 无奇偶校验
    options.c_cflag &= ~PARENB;
    // 一个停止位
    options.c_cflag &= ~CSTOPB;
    // 设置最小等待时间和最少字符数量
    options.c_cc[VTIME] = 0;
    options.c_cc[VMIN] = 1;
    // 清空输入和输出缓冲区
    tcflush(fd, TCIOFLUSH);
    // 配置生效
    if (tcsetattr(fd, TCSANOW, &options) < 0)
    {
        perror("tcsetattr fail");
        return -1;
    }

    return 0;
}

int Serial::send(const void *buf, size_t size, int sec, int msec, bool clBuf)
{
    int ret = -1;
    uint8_t tempBuf[1024];
    fd_set write_set;
    struct timeval tv;

    if (fd == -1)
    {
        std::cout << __LINE__ << " serial fd error" << std::endl;
        return -1;
    }
    // clBuf为true时清空接收缓冲区中的数据,确保在发送数据之前不会有未读取的数据残留
    if (clBuf)
    {
        tcflush(fd, TCIFLUSH);
    }
    FD_ZERO(&write_set);
    FD_SET(fd, &write_set);
    tv.tv_sec = sec;
    tv.tv_usec = msec * 1000;
    ret = select(fd + 1, 0, &write_set, 0, &tv);
    switch (ret)
    {
    case 0:
        break;
    case -1:
        break;
    default:
        if (FD_ISSET(fd, &write_set))
        {
            ret = write(fd, buf, size);
        }
        break;
    }

    return ret;
}

int Serial::recv(void *buf, size_t size, int sec, int msec)
{
    int ret = -1;
    fd_set read_set;
    struct timeval tv;

    if (fd == -1)
    {
        std::cout << __LINE__ << " serial fd error" << std::endl;
        return -1;
    }

    FD_ZERO(&read_set);
    FD_SET(fd, &read_set);
    tv.tv_sec = sec;
    tv.tv_usec = msec * 1000;
    ret = select(fd + 1, &read_set, 0, 0, &tv);
    switch (ret)
    {
    case 0:
        break;
    case -1:
        break;
    default:
        if (FD_ISSET(fd, &read_set))
        {
            ret = read(fd, buf, size);
        }
        break;
    }

    return ret;
}

int Serial::closePort()
{
    int ret;

    ret = close(fd);
    fd = -1;

    return ret;
}

Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐