网站系统建设招标图片手机显示wordpress
CSerialPort教程4.3.x (2) - CSerialPort源码简介
前言
CSerialPort项目是一个基于C/C++的轻量级开源跨平台串口类库,可以轻松实现跨平台多操作系统的串口读写,同时还支持C#, Java, Python, Node.js等。
CSerialPort项目的开源协议自 V3.0.0.171216 版本后采用GNU Lesser General Public License v3.0
为了让开发者更好的使用CSerialPort进行开发,特编写基于4.3.x版本的CSerialPort教程系列。
CSerialPort项目地址:
- https://github.com/itas109/CSerialPort
 - https://gitee.com/itas109/CSerialPort
 
本文对CSerialPort 4.3.0版本源码进行简介。
1. CSerialPort源码目录结构
CSerialPort # root
+--- .clang-format # code format 代码规范
├── bindings # 第三方语言接口
│   ├── c # c interface c接口
│   ├── csharp # csharp interface c#接口
│   ├── java # java interface java接口
│   ├── javascript # javascript interface javascript接口
│   └── python # python interface python接口
├── CHANGELOG.md # change log 修改日志
├── cmake # cross compile 交叉编译
├── CMakeLists.txt
├── doc # document 文档
├── examples # example 示例程序
│   ├── CommMFC # CSerialPort MFC Demo MFC程序示例
│   ├── CommNoGui # CSerialPort No Gui Demo 无界面程序示例
│   ├── CommQT # CSerialPort QT Demo QT程序示例
│   ├── CommTui # CSerialPort tui Demo 文本界面程序示例
│   ├── CommWXWidgets # CSerialPort wxwidgets Demo wxwidgets界面程序示例
├── include # headers 头文件
│   └── CSerialPort
│       ├── ibuffer.hpp # lightweight cross-platform buffer library 轻量级跨平台缓冲区类
│       ├── ithread.hpp # lightweight cross-platform thread library 轻量级跨平台线程类
│       ├── itimer.hpp # lightweight cross-platform timer library 轻量级跨平台定时器类
│       ├── iutils.hpp # lightweight cross-platform utils library 轻量级跨平台工具类
│       ├── SerialPortBase.h # CSerialPort Base class 串口基类
│       ├── SerialPort_global.h # Global difine of CSerialPort 串口全局定义 
│       ├── SerialPort.h # lightweight cross-platform serial port library 轻量级跨平台串口类库
│       ├── SerialPortInfoBase.h # CSerialPortInfo Base class 串口信息辅助类基类
│       ├── SerialPortInfo.h # CSerialPortInfo class 串口信息辅助类
│       ├── SerialPortInfoUnixBase.h # CSerialPortInfo unix class unix串口信息辅助类基类
│       ├── SerialPortInfoWinBase.h # CSerialPortInfo windows class windows串口信息辅助类基类
│       ├── SerialPortListener.h # CSerialPortListener interface class 串口事件监听接口类
│       ├── SerialPortUnixBase.h # CSerialPort unix Base class unix串口基类
│       ├── SerialPort_version.h # CSerialPort version 版本定义
│       └── SerialPortWinBase.h # CSerialPort Windows Base class windows串口基类
├── lib # lib 库目录
├── LICENSE # LGPL3.0 license
├── pic # picture 图片
├── README.md
├── README_zh_CN.md
├── src # source 源代码
├── test # unit test 单元测试
└── VERSION # version 版本号
 
2. CSerialPort常用函数
2.1 串口信息相关函数
2.1.1 获取串口信息列表函数 availablePortInfos
该函数获取串口信息列表,主要包括:
- 串口名称 (如COM2)
 - 描述信息 (如USB-SERIAL CH340)
 - 硬件id (如USB\VID_1A86&PID_7523&REV_0264)
 
static vector<SerialPortInfo> itas109::CSerialPortInfo::availablePortInfos()
 
2.2 串口操作相关函数
2.2.1 串口初始化函数 init
该函数用于串口初始化。
void itas109::CSerialPort::init(const char *portName,                                 // 串口名称 Windows:COM1 Linux:/dev/ttyS0int baudRate = itas109::BaudRate9600,                 // 波特率itas109::Parity parity = itas109::ParityNone,         // 校验位itas109::DataBits dataBits = itas109::DataBits8,      // 数据位itas109::StopBits stopbits = itas109::StopOne,        // 停止位itas109::FlowControl flowControl = itas109::FlowNone, // 流控制unsigned int readBufferSize = 4096                    // 读取缓冲区大小
)
 
注意:
- 5位数据位不能使用2位停止位
 - 1.5位停止位不能使用5位数据位
 - POSIX系统8位数据位不能使用0校验
 - windows数据位范围为4 - 8
 - 1.5位停止位仅对windows有效
 - 停止位数字1表示StopOneAndHalf,即1.5位停止位,并非1位停止位
 
2.2.2 打开串口函数 open
该函数用于打开串口。
bool itas109::CSerialPort::open()
 
true表示打开成功,false表示打开失败。
打开失败可用itas109::CSerialPort::getLastError()获取错误码
2.2.3 关闭串口函数 close
该函数用于关闭串口。
void itas109::CSerialPort::close()
 
2.2.4 是否打开串口成功函数 isOpen
该函数用于获取是否打开串口成功。
bool itas109::CSerialPort::isOpen()
 
true表示串口打开成功,false表示串口打开失败。
2.2.5 向串口写入数据函数 writeData
该函数用于向串口写入数据。
int itas109::CSerialPort::writeData(const void *data, // 待写入数据int maxSize       // 写入长度
)
 
成功则返回写入字节数,失败则返回-1。
写入失败可用itas109::CSerialPort::getLastError()获取错误码。
2.2.6 从串口读取指定长度数据函数 readData
该函数用于从串口读取指定长度数据。
int readData(void *data,  // 读取结果int size     // 读取长度
)
 
正常则返回读取字节数,失败则返回-1。
读取失败可用itas109::CSerialPort::getLastError()获取错误码。
注意:
 CSerialPort异步操作模式下,需要配合connectReadEvent函数使用。详见第三节的代码示例。
2.2.7 从串口读取所有数据函数 readAllData
该函数用于从串口读取所有数据。
int itas109::CSerialPort::readAllData(void *data // 读取结果
)
 
正常则返回读取字节数,失败则返回-1。
读取失败可用itas109::CSerialPort::getLastError()获取错误码。
注意:
 CSerialPort异步操作模式下,需要配合connectReadEvent函数使用。详见第三节的代码示例。
2.2.8 绑定读取事件函数 connectReadEvent
该函数用于异步模式(默认)下,绑定读取响应的结果。
需要继承CSerialPortListener,并实现onReadEvent虚函数。详见第三节的代码示例。
class MyListener : public CSerialPortListener
{
public:void onReadEvent(const char *portName, unsigned int readBufferLen){}
}
 
2.2.9 获取CSerialPort版本信息函数 getVersion
该函数用于获取CSerialPort版本信息。
std::string itas109::CSerialPort::getVersion()
 
返回CSerialPort版本信息,如https://github.com/itas109/CSerialPort - V4.3.0.230215
2.2.10 错误码 SerialPortError
| 错误码数值 | 错误码宏定义 | 错误码说明 | 
|---|---|---|
| -1 | ErrorUnknown | unknown error 未知错误 | 
| 0 | ErrorOK | ok 成功 | 
| 1 | ErrorFail | general error一般性错误 | 
| 2 | ErrorNotImplemented | not implemented 未实现 | 
| 3 | ErrorInner | inner error 内部错误(如内存访问异常等) | 
| 4 | ErrorNullPointer | null pointer error 空指针错误 | 
| 5 | ErrorInvalidParam | invalid parameter error 无效的参数 | 
| 6 | ErrorAccessDenied | access denied error 权限错误 | 
| 7 | ErrorOutOfMemory | out of memory 内存不足 | 
| 8 | ErrorTimeout | time out error 超时 | 
| 9 | ErrorNotInit | not init 未初始化 | 
| 10 | ErrorInitFailed | init failed 初始化失败 | 
| 11 | ErrorAlreadyExist | already exist 已经存在 | 
| 12 | ErrorNotExist | not exist 不存在 | 
| 13 | ErrorAlreadyOpen | already open 已经打开 | 
| 14 | ErrorNotOpen | not open 未打开 | 
| 15 | ErrorOpenFailed | open failed 打开失败 | 
| 16 | ErrorCloseFailed | close failed 关闭失败 | 
| 17 | ErrorWriteFailed | write failed 写入失败 | 
| 18 | ErrorReadFailed | read failed 读取失败 | 
3. CSerialPort简单代码示例
- 操作步骤
 
$ mkdir CSerialPortDemo
$ cd CSerialPortDemo
$ git clone https://github.com/itas109/CSerialPort
$ touch CSerialPortDemo.cpp
$ touch CMakeLists.txt
$ mkdir bin 
$ cd bin
$ cmake ..
$ cmake --build .
 
- 目录结构
 
$ tree
.
+--- CMakeLists.txt
+--- CSerialPort
|   +--- include
|   +--- src
|   +--- ...
+--- CSerialPortDemo.cpp
 
- CSerialPortDemo.cpp
 
注意:接收函数需要继承CSerialPortListener
#include <iostream>#include "CSerialPort/SerialPort.h"
#include "CSerialPort/SerialPortInfo.h"#include <vector>
using namespace itas109;
using namespace std;class MyListener : public CSerialPortListener
{
public:MyListener(CSerialPort *sp): p_sp(sp){};void onReadEvent(const char *portName, unsigned int readBufferLen){if (readBufferLen > 0){char *data = new char[readBufferLen + 1]; // '\0'if (data){// readint recLen = p_sp->readData(data, readBufferLen);if (recLen > 0){data[recLen] = '\0';std::cout << portName << ", Length: " << recLen << ", Str: " << data << std::endl;}delete[] data;data = NULL;}}};private:CSerialPort *p_sp;
};int main()
{CSerialPort sp;MyListener listener(&sp);std::cout << "Version : " << sp.getVersion() << std::endl << std::endl;vector<SerialPortInfo> m_availablePortsList = CSerialPortInfo::availablePortInfos();std::cout << "availableFriendlyPorts: " << std::endl;for (size_t i = 1; i <= m_availablePortsList.size(); ++i){SerialPortInfo serialPortInfo = m_availablePortsList[i - 1];std::cout << i << " - " << serialPortInfo.portName << " " << serialPortInfo.description << " " << serialPortInfo.hardwareId << std::endl;}if (m_availablePortsList.size() == 0){std::cout << "No valid port" << std::endl;}else{std::cout << std::endl;int input = -1;do{std::cout << "Please Input The Index Of Port(1 - " << m_availablePortsList.size() << ")" << std::endl;std::cin >> input;if (input >= 1 && input <= m_availablePortsList.size()){break;}} while (true);const char *portName = m_availablePortsList[input - 1].portName;std::cout << "Port Name: " << portName << std::endl;sp.init(portName,              // windows:COM1 Linux:/dev/ttyS0itas109::BaudRate9600, // baudrateitas109::ParityNone,   // parityitas109::DataBits8,    // data bititas109::StopOne,      // stop bititas109::FlowNone,     // flow4096                   // read buffer size);sp.setReadIntervalTimeout(0); // read interval timeout 0ms// sp.setOperateMode(itas109::SynchronousOperate);sp.open();std::cout << "Open " << portName << (sp.isOpen() ? " Success. " : " Failed. ");std::cout << "Code: " << sp.getLastError() << ", Message: " << sp.getLastErrorMsg() << std::endl;// 绑定读取函数sp.connectReadEvent(&listener);// 写入数据sp.writeData("itas109", 7);for (;;){}}return 0;
}
 
- CMakeLists.txt
 
cmake_minimum_required(VERSION 2.8.12)project(CSerialPortDemo)if(APPLE)find_library(IOKIT_LIBRARY IOKit)find_library(FOUNDATION_LIBRARY Foundation)
endif()include_directories(CSerialPort/include)
file(GLOB_RECURSE COMMON_SOURCES CSerialPort/src/SerialPort.cpp CSerialPort/src/SerialPortBase.cpp CSerialPort/src/SerialPortInfo.cpp CSerialPort/src/SerialPortInfoBase.cpp)
if (CMAKE_HOST_WIN32)file(GLOB_RECURSE OS_ABOUT_SOURCES CSerialPort/src/SerialPortInfoWinBase.cpp CSerialPort/src/SerialPortWinBase.cpp)
elseif (CMAKE_HOST_UNIX)file(GLOB_RECURSE OS_ABOUT_SOURCES CSerialPort/src/SerialPortInfoUnixBase.cpp CSerialPort/src/SerialPortUnixBase.cpp)
endif ()	add_executable( ${PROJECT_NAME} CSerialPortDemo.cpp ${COMMON_SOURCES} ${OS_ABOUT_SOURCES})if (WIN32)target_link_libraries( ${PROJECT_NAME} setupapi )
elseif (APPLE)target_link_libraries( ${PROJECT_NAME} ${FOUNDATION_LIBRARY} ${IOKIT_LIBRARY})
elseif (UNIX)target_link_libraries( ${PROJECT_NAME} pthread )
endif ()
 
- 运行结果(windows下环回测试)
 
Version : https://github.com/itas109/CSerialPort - V4.3.0.230215availableFriendlyPorts:
1 - COM1 USB-SERIAL CH340  USB\VID_1A86&PID_7523&REV_0264Please Input The Index Of Port(1 - 1)
1
Port Name: COM1
Open COM1 Success. Code: 0, Message: success
COM1, Length: 7, Str: itas109
 
License
License under CC BY-NC-ND 4.0: 署名-非商业使用-禁止演绎
Reference:
- https://github.com/itas109/CSerialPort
 - https://gitee.com/itas109/CSerialPort
 - https://blog.csdn.net/itas109
 
