Linux C++ 串口通信工具类

3 篇文章 1 订阅

标题

提示:Linux下的C++ 串口工具类,通过子线程监听串口数据


一、串口工具类头文件

#pragma once
#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>
#include <string>
#include <thread>
#include <memory.h>
#include <iostream>
using namespace std;

class SerialPort
{

public:
    SerialPort(const std::string &path);
    ~SerialPort();
    enum BaudRate	//波特率 枚举 
    {
        BR0 = 0000000,
        BR50 = 0000001,
        BR75 = 0000002,
        BR110 = 0000003,
        BR134 = 0000004,
        BR150 = 0000005,
        BR200 = 0000006,
        BR300 = 0000007,
        BR600 = 0000010,
        BR1200 = 0000011,
        BR1800 = 0000012,
        BR2400 = 0000013,
        BR4800 = 0000014,
        BR9600 = 0000015,
        BR19200 = 0000016,
        BR38400 = 0000017,
        BR57600 = 0010001,
        BR115200 = 0010002,
        BR230400 = 0010003,
        BR460800 = 0010004,
        BR500000 = 0010005,
        BR576000 = 0010006,
        BR921600 = 0010007,
        BR1000000 = 0010010,
        BR1152000 = 0010011,
        BR1500000 = 0010012,
        BR2000000 = 0010013,
        BR2500000 = 0010014,
        BR3000000 = 0010015,
        BR3500000 = 0010016,
        BR4000000 = 0010017
    };

    enum DataBits //数据位
    {
        DataBits5,
        DataBits6,
        DataBits7,
        DataBits8,
    };

    enum StopBits	//停止位
    {
        StopBits1,
        StopBits2
    };

    enum Parity 	//校验位
    {
        ParityNone,
        ParityEven,
        PariteMark,
        ParityOdd,
        ParitySpace
    };

    struct OpenOptions	//串口参数结构体
    {
        bool autoOpen;
        BaudRate baudRate;
        DataBits dataBits;
        StopBits stopBits;
        Parity parity;
        bool xon;
        bool xoff;
        bool xany;
        int vmin;
        int vtime;
    };
    static BaudRate BaudRateMake(unsigned long baudrate);
    static const OpenOptions defaultOptions;
	
	//串口打开
    bool open();
    bool open(const std::string &path, const OpenOptions &options);

    bool isOpen() const;
	
	//写数据
    int write(const void *data, int length);
    //读数据
    int read(void *data, int length);
	//串口及监听线程关闭
    void close();
	//串口监听线程
    void openThread();

protected:
    void termiosOptions(termios &tios, const OpenOptions &options);

private:
    std::string _path;          //port address
    OpenOptions _open_options;  //port data
    int _tty_fd;                //opened port
    bool _is_open = false;      //open state
};
//重载操作符
bool operator==(const SerialPort::OpenOptions &lhs, const SerialPort::OpenOptions &rhs);
bool operator!=(const SerialPort::OpenOptions &lhs, const SerialPort::OpenOptions &rhs);

二、串口工具类cpp文件

1 构造及析构

#include "SerialPort.h"
SerialPort::SerialPort(const std::string &path)
{
    _path = path;
    _open_options = SerialPort::defaultOptions;
}
SerialPort::~SerialPort()
{
    close();
}

2 默认串口参数定义

const SerialPort::OpenOptions SerialPort::defaultOptions = {
    true,             //    bool autoOpen;
    SerialPort::BR115200,     //    BaudRate baudRate;
    SerialPort::DataBits8,  //    DataBits dataBits;
    SerialPort::StopBits1,  //    StopBits stopBits;
    SerialPort::ParityNone, //    Parity parity;
    false,            //    input xon       允许输入时对XON/XOFF流进行控制
    false,            //    input xoff      允许输入时对XON/XOFF流进行控制
    false,            //    input xany      输入任何字符将重启停止的输出
    0,                //    c_cc vmin       设置非规范模式下的超时时长和最小字符数:阻塞模式起作用
    50,               //    c_cc vtime      VTIME与VMIN配合使用,是指限定的传输或等待的最长时间 单位:0.1S
};

3 波特率转换

unsigned long 格式的波特率,转换为linux串口支持的格式

SerialPort::BaudRate SerialPort::BaudRateMake(unsigned long baudrate)
{
    switch (baudrate)
    {
    case 50:
        return BR50;
    case 75:
        return BR75;
    case 134:
        return BR134;
    case 150:
        return BR150;
    case 200:
        return BR200;
    case 300:
        return BR300;
    case 600:
        return BR600;
    case 1200:
        return BR1200;
    case 1800:
        return BR1800;
    case 2400:
        return BR2400;
    case 4800:
        return BR4800;
    case 9600:
        return BR9600;
    case 19200:
        return BR19200;
    case 38400:
        return BR38400;
    case 57600:
        return BR57600;
    case 115200:
        return BR115200;
    case 230400:
        return BR230400;
    case 460800:
        return BR460800;
    case 500000:
        return BR500000;
    case 576000:
        return BR576000;
    case 921600:
        return BR921600;
    case 1000000:
        return BR1000000;
    case 1152000:
        return BR1152000;
    case 1500000:
        return BR1500000;
    case 2000000:
        return BR2000000;
    case 2500000:
        return BR2500000;
    case 3000000:
        return BR3000000;
    case 3500000:
        return BR3500000;
    case 4000000:
        return BR4000000;
    default:
        break;
    }
    return BR0;
}

4 打开串口

bool SerialPort::open(const std::string &path, const OpenOptions &options)
{
    if (_path != path)
        _path = path;
    if (_open_options != options)
        _open_options = options;
    /* O_RDWR 读写方式打开;
     * O_NOCTTY 不允许进程管理串口(不太理解,一般都选上);
     * O_NDELAY 非阻塞(默认为阻塞,打开后也可以使用fcntl()重新设置)
     * O_NONBLOCK 如果路径名指向 FIFO/块文件/字符文件,则把文件的打开和后继 I/O设置为非阻塞模式
     * O_RDWR | O_NOCTTY                阻塞模式
     * O_RDWR | O_NOCTTY | O_NONBLOCK   非阻塞模式
     */
    _tty_fd = ::open(path.c_str(), O_RDWR | O_NOCTTY | O_NONBLOCK);
    if (_tty_fd < 0)
    {
        return false;
    }

    struct termios tios;
    termiosOptions(tios, options);
    tcsetattr(_tty_fd, TCSANOW, &tios); // TCSANOW立刻对值进行修改
    tcflush(_tty_fd, TCIOFLUSH);        // 清除所有正在发生的I/O数据。
    _is_open = true;
    return _is_open;
}

bool SerialPort::open()
{
    _is_open = open(_path, _open_options);
    return _is_open;
}

void SerialPort::termiosOptions(termios &tios, const OpenOptions &options)
{

    tcgetattr(_tty_fd, &tios);

    cfmakeraw(&tios);
    tios.c_cflag &= ~(CSIZE | CRTSCTS);
    tios.c_iflag &= ~(IXON | IXOFF | IXANY | IGNPAR);
    tios.c_lflag &= ~(ECHOK | ECHOCTL | ECHOKE);
    tios.c_oflag &= ~(OPOST | ONLCR);

    cfsetispeed(&tios, options.baudRate);
    cfsetospeed(&tios, options.baudRate);

    tios.c_iflag |= (options.xon ? IXON : 0) | (options.xoff ? IXOFF : 0) | (options.xany ? IXANY : 0);

    // data bits

    int databits[] = {CS5, CS6, CS7, CS8};
    tios.c_cflag &= ~0x30;
    tios.c_cflag |= databits[options.dataBits];

    // stop bits
    if (options.stopBits == StopBits2)
    {
        tios.c_cflag |= CSTOPB;
    }
    else
    {
        tios.c_cflag &= ~CSTOPB;
    }

    // parity
    if (options.parity == ParityNone)
    {
        tios.c_cflag &= ~PARENB;
    }
    else
    {
        tios.c_cflag |= PARENB;

        if (options.parity == PariteMark)
        {
            tios.c_cflag |= PARMRK;
        }
        else
        {
            tios.c_cflag &= ~PARMRK;
        }

        if (options.parity == ParityOdd)
        {
            tios.c_cflag |= PARODD;
        }
        else
        {
            tios.c_cflag &= ~PARODD;
        }
    }

    tios.c_cc[VMIN] = options.vmin;
    tios.c_cc[VTIME] = options.vtime;
}

bool SerialPort::isOpen() const
{
    return _is_open;
}

5 读写数据

int SerialPort::write(const void *data, int length)
{
    return ::write(_tty_fd, data, length);
}

int SerialPort::read(void *data, int length)
{
    return ::read(_tty_fd, data, length);
}

6 关闭串口及串口监听线程

void SerialPort::close()
{
    if(_is_open){
        ::close(_tty_fd);
        _is_open = false;
    } 
}

7串口监听线程

void SerialPort::openThread()
{
    thread serverThread(
        [&]()->void
        {
            char buffer[1024];
            int ret = 0;
            // signalInt.emit(10);
            
            while (_is_open)
            {
                memset(buffer, 0, 1024);
                ret = this->read(buffer, 1024);
                if (ret > 0)
                {
                	cout << "success: buffer=\t";
                    cout << ret << "\t";
                    cout << buffer << endl;
                }
            }
            return;
        });

    serverThread.detach();
}

监听线程采用detach模式,通过标志位控制线程是否结束。

8 重载操作符

重载操作符,用于判断串口参数是否相同

bool operator==(const SerialPort::OpenOptions &lhs, const SerialPort::OpenOptions &rhs)
{
    return lhs.autoOpen == rhs.autoOpen && lhs.baudRate == rhs.baudRate && lhs.dataBits == rhs.dataBits && lhs.parity == rhs.parity && lhs.stopBits == rhs.stopBits && lhs.vmin == rhs.vmin && lhs.vtime == rhs.vtime && lhs.xon == rhs.xon && lhs.xoff == rhs.xoff && lhs.xany == rhs.xany;
}

bool operator!=(const SerialPort::OpenOptions &lhs, const SerialPort::OpenOptions &rhs)
{
    return !(lhs == rhs);
}

三、串口类使用

#include <iostream>
#include "SerialPort.h"
#include <memory.h>
using namespace std;

int main()
{
	SerialPort port1;
	// /dev/ttyS1为linux下串口地址
	port1.open("/dev/ttyS1", SerialPort::defaultOptions);
	if (port1.isOpen())
		{
			cout << "port open success!" << endl;
		}
		else
		{
			cout << "port open failed!" << endl;
			return 0;
		}

	port1.openThread();

	unsigned char temp[10];
	memset(temp, 48, 10);

	temp[0] = 0x20;
	port1.write(temp, 10);
	
	sleep(20);//Linux下单位s
	port1.close();//关闭串口及结束线程
	
	return 0;
}

四、参考资源

基于linux的串口C++ 工具类及使用完整工程:https://download.csdn.net/download/qq_40778196/87715790

  • 1
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
目 录 第1章 ARM微处理器概述 1.1 ARM-Advanced RISC Machines 1.2 ARM微处理器的应用领域及特点 1.2.1 ARM微处理器的应用领域 1.2.2 ARM微处理器的特点 1.3 ARM微处理器系列 1.3.1 ARM7微处理器系列 1.3.2 ARM9微处理器系列 1.3.3 ARM9E微处理器系列 1.3.4 ARM10E微处理器系列 1.3.5 SecurCore微处理器系列 1.3.6 StrongARM微处理器系列 1.3.7 Xscale处理器 1.4 ARM微处理器结构 1.4.1 RISC体系结构 1.4.2 ARM微处理器的寄存器结构 1.4.3 ARM微处理器的指令结构 1.5 ARM微处理器的应用选型 1.6 本章小节 第2章 ARM微处理器的编程模型 2.1 ARM微处理器的工作状态 2.2 ARM体系结构的存储器格式 2.3 指令长度及数据类型 2.4 处理器模式 2.5 寄存器组织 2.5.1 ARM状态下的寄存器组织 2.5.2 Thumb状态下的寄存器组织 2.5.3 程序状态寄存器 2.6 异常(Exceptions) 2.6.1 ARM体系结构所支持的异常类型 2.6.2 对异常的响应 2.6.3 从异常返回 2.6.4 各类异常的具体描述 2.6.5 异常进入/退出小节 2.6.6 异常向量(Exception Vectors) 2.6.7 异常优先级(Exception Priorities) 2.6.8 应用程序中的异常处理 2.7 本章小节 第3章 ARM微处理器的指令系统 3.1 ARM微处理器的指令集概述 3.1.1 ARM微处理器的指令的分类与格式 3.1.2 指令的条件域 3.2 ARM指令的寻址方式 3.2.1 立即寻址 3.2.2 寄存器寻址 3.2.2 寄存器间接寻址 3.2.3 基址变址寻址 3.2.4 多寄存器寻址 3.2.5 相对寻址 3.2.6 堆栈寻址 3.3 ARM指令集 3.3.1 跳转指令 3.3.2 数据处理指令 3.3.3 乘法指令与乘加指令 3.3.4 程序状态寄存器访问指令 3.3.5 加载/存储指令 3.3.6 批量数据加载/存储指令 3.3.7 数据交换指令 3.3.8 移位指令(操作) 3.3.9 协处理器指令 3.3.10 异常产生指令 3.4 Thumb指令及应用 3.5 本章小节 第4章 ARM程序设计基础 4.1 ARM汇编器所支持的伪指令 4.1.1 符号定义(Symbol Definition)伪指令 4.1.2 数据定义(Data Definition)伪指令 4.1.3 汇编控制(Assembly Control)伪指令 4.1.4 其他常用的伪指令 4.2 汇编语言的语句格式 4.2.1 在汇编语言程序中常用的符号 4.2.2 汇编语言程序中的表达式和运算符 4.3 汇编语言的程序结构 4.3.1 汇编语言的程序结构 4.3.2 汇编语言的子程序调用 4.3.3 汇编语言程序示例 4.3.4 汇编语言与C/C++的混合编程 4.4 本章小节 第5章 应用系统设计与调试 5.1 系统设计概述 5.2 S3C4510B概述 5.2.1 S3C4510B及片内外围简介 5.2.2 S3C4510B的引脚分布及信号描述 5.2.3 CPU内核概述及特殊功能寄存器(Special Registers) 5.2.4 S3C4510B的系统管理器(System Manager) 5.3 系统的硬件选型与单元电路设计 5.3.1 S3C4510B芯片及引脚分析 5.3.2 电源电路 5.3.3 晶振电路与复位电路 5.3.4 Flash存储器接口电路 5.3.5 SDRAM接口电路 5.3.6 串行接口电路 5.3.7 IIC接口电路 5.3.8 JTAG接口电路 5.3.9 10M/100M以太网接口电路 5.3.10 通用I/O接口电路 5.4 硬件系统的调试 5.4.1 电源、晶振及复位电路 5.4.2 S3C4510B及JTAG接口电路 5.4.3 SDRAM接口电路的调试 5.4.4 Flash接口电路的调试 5.4.5 10M/100M以太网接口电路 5.5 印刷电路板的设计注意事项 5.5.1 电源质量与分配 5.5.2 同类型信号线的分布 5.6 本章小节 第6章 部件工作原理与编程示例 6.1 嵌入式系统的程序设计方法 6.2 应用程序编程示例 6.2.1 通用I/O口工作原理与编程示例 6.2.2 串行通讯工作原理与编程示例 6.2.3 中断控制器工作原理与编程示例 6.2.4 定时器工作原理与编程示例 6.2.5 GDMA工作原理与编程示例 6.2.5 IIC总线控制器工作原理
要在Linux下使用C++实现串口通信,你可以使用Linux系统提供的串口API。下面是一个简单的例子,展示如何使用C++Linux下实现串口通信: ```c++ #include <iostream> #include <fcntl.h> #include <termios.h> #include <unistd.h> #include <cstring> using namespace std; int main() { int fd; struct termios options; // 打开串口设备 fd = open("/dev/ttyUSB0", O_RDWR | O_NOCTTY | O_NDELAY); if (fd == -1) { cout << "无法打开串口设备!" << endl; return -1; } // 配置串口 tcgetattr(fd, &options); cfsetispeed(&options, B9600); cfsetospeed(&options, B9600); options.c_cflag |= CLOCAL; options.c_cflag |= CREAD; options.c_cflag &= ~CSIZE; options.c_cflag |= CS8; options.c_cflag &= ~PARENB; options.c_cflag &= ~CSTOPB; options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); options.c_oflag &= ~OPOST; options.c_cc[VMIN] = 0; options.c_cc[VTIME] = 10; tcsetattr(fd, TCSANOW, &options); // 发送数据 char tx_buffer[] = "Hello, world!"; int tx_length = strlen(tx_buffer); int bytes_written = write(fd, tx_buffer, tx_length); if (bytes_written < 0) { cout << "写入数据失败!" << endl; close(fd); return -1; } // 接收数据 char rx_buffer[256]; int rx_length = read(fd, rx_buffer, 256); if (rx_length < 0) { cout << "读取数据失败!" << endl; close(fd); return -1; } else { rx_buffer[rx_length] = '\0'; cout << "收到数据:" << rx_buffer << endl; } // 关闭串口设备 close(fd); return 0; } ``` 在这个例子中,我们首先打开了一个串口设备(这里假设是`/dev/ttyUSB0`),然后配置了串口的波特率、数据位、停止位和校验位等参数。接下来,我们发送了一段数据,并读取了从串口设备返回的数据。最后,我们关闭了串口设备。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

不会抓狼的羊

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值