串口一旦存在后, C++ boost::a sio 就当串口为一种流 ( 文件流 ) 来使用

C++ BOOST 库中,通信库都在 asio 下,串口类结构为 boost::asio::serial_port 。串口通信由 asio 组件的 serial_port 类完成。 BOOST 库下的串口通信 serial_port 类的使用跟网络通信相似 [ 网络通信 ] ,只是在进行串口通信前需要初始化串口。下面笔记使用步骤:

1 serial_port 类头文件和命名空间声明

#include  <boost/asio.hpp>

using namespace  boost::asio;

2 serial_port 类实现串口通信步骤

(1) 定义io _service 对象

io_service 对象是使用 boost::asio 库的必需要有的对象。

io_service io_s;

(2) 创建串口对象,传入 io_service 对象,打开串口

serial_port sp(  io_s , "COM1" );

io_s 是步骤 (1) 中定义的 io_service 对象, COM1 为串口名(计算机 --> 属性 --> 设备管理器 --> 端口)。一旦串口被打开, 则此串口就会被当成流来被使用

(1) 如果串口端口不存在,则 try -catch能够获取“系统找不到指定的文件”文件异常。

(2) 如果串口端口没有和实际的串口连接,则try-catch能够获取“设备没有连接”的异常。

(3) 如果在电脑之上连接一个串口线,则用此函数打开对应的端口(如COM4 )就不会出现以上两个异常。如果不在此串口下挂一个设备,则对端口进行读写操作的时候会出现异常,如读串口数据时会在read函数这里卡住。但如果在串口下挂一个设备如51单片机学习板则此函数会返回并读出一定的数据回来(虽不一定正确)。如果将挂在串口下的设备开启,try-catch会捕获“连接到系统上的设备没有发挥作用”或者是read函数又开始不能返回。

(3) 初始化

利用串口类对象初始化串口。串口类对象就是 (2) 中定义的 sp ,串口就是以上的参数 COM1

sp.set_option(  serial_port::baud_rate( 9600 ) ); // 比特率

sp.set_option(  serial_port::flow_control( serial_port::flow_control::none ) ); // 流量控制

sp.set_option(  serial_port::parity( serial_port::parity::none ) ); // 奇偶校验

sp.set_option( serial_port::stop_bits(  serial_port::stop_bits::one ) ); // 停止位

sp.set_option(  serial_port::character_size( 8 ) ); // 数据位

(4) 调用 serial_prot 类的成员函数进行串口通信

如先前所述, serial_port 类成功打开串口后,串口对于 serial_port 类来说就成了一种文件流。咱们就可以使用 serial_port 类中的成员函数往“流”写和读数据了。

向串口发送数据时是采用 boost::asio::serial_port 下含 write 字符串的函数将程序中的数据写入到串口流,接收串口数据时是用含 read 字符串的函数从串口读出数据,再放到程序变量中 。比如用串口对象调用的 write_some() read_some() 一类属于 serial_port 的成员函数,还有在函数内部指明串口对象的 write() read() 等非 serial_port 类的成员函数,但它们是 boost::asio 下的函数。看名就知道“只写 / 读一些”的函数(比如读到空格或者其它特殊字符就会停止读下去)不如“写 / 读”函数功能完好。所以,咱都还是用 write() read() 一类的函数从串口写、读完整的数据串吧。

[1]向串口写数据

write 4 个重载 ( overload) 函数,有 2 种都有接收异常的参数。 [ VS 中选中 write 函数 --> 右键 -->Go To Definition F12 ]

size_t data_len;

boost::system::error_code ec;

data_len = write( *pSerialPort, buffer(data),  ec);

write() 的第一个参数表示 serial_port 对象,第二个参数是写向 ( 传输 ) 串口的数据,第三个参数是 boost 库下的异常参数,如果 write 函数传输数据发生什么异常就会自动抛出此异常给 catch 。向串口成功传进数据则返回写入数据 data 的长度, buffer boost 库的函数,一般的参数都需要 buffer 一下。

[2]读/接收串口数据

如果直接用 read 函数来读取串口流中的数据,则 read 函数在读满变量内存后才会返回 ( char a[6], 则会读满 6 个后才会返回 ) 。而且返回输出字符串的时候还是乱码。使用 read 函数就会阻塞后面代码的执行。

可以使用异步读取 / 接收串口的方式:就算未完全读 / 接收到串口数据,异步读取函数依旧会马上返回执行后续代码,等串口数据读取完毕或者发生异常时 io_service::run() 函数会等待异步读取串口的数据操作,然后调用异步函数指定的回调函数。

提到异步操作,它包含三部分:

  • 异步操作函数。
  • 异步操作函数以形参方式指定的回调函数。
  • io_service::run() 函数的调用。

这三个部分对应的执行流程为:

  • 程序执行到异步操作函数处,异步操作函数立即返回,程序继续执行后续代码。
  • 异步操作函数的功能完成 [ 如读取到与设定缓冲区长度大小一致的数据时 ] 或者出现异常时, io_service::run() 函数机制会自动调用异步操作函数指定的回调函数。如果不 io_service::run() 函数,异步操作函数依然可以实现异步操作流程,只是回调函数不会被执行。

void handle_read(  boost::system::error_code ec,std::size_t bytes_transferred ); // 如果不使用 bind ,则 async_read 函数的回调函数必须为如此形式

async_read( *pPort, buffer(v),  handle_read );

ios.run();

不过,输出 cout<< “\n” << v; 为乱码 [ 在我挂一个单片机设备在串口的情形下 ]

在此种情形下,虽然可以使异步操作函数后续代码被执行。但在没有发生异常或者没有读满设定缓冲区大小时,回调函数不会被调用。所以可以使用 boost 库下的 deadline_timer 为异步操作定时 , 如果超过定时的时间就结束异步函数的异步操作去执行回调函数。

eadline_timer timer(ios);

timer.expires_from_now(boost::posix_time::millisec(100));

// 超时后调用 pSerialPort cancel() 方法放弃读取更多字符

timer.async_wait(boost::bind(&serial_port::cancel,  boost::ref(*pSerialPort)));

以面向过程的方式实现这些步骤可以实现以上功能,但是将其封装称为类的时候会出点错误。

3 将boost串口通信封装成类

将其封装为类时, boost的用法就要遵循按照包装成员函数的套路出发, bind用法

(1)类头文件

#include <iostream>
#include <boost/asio.hpp>
#include <boost/bind.hpp>
using namespace std;
using namespace boost::asio;
typedef string any_type;
class MySerialPort
private:
	//Initialize port
	bool init_port( const any_type port, const unsigned int char_size );
public:
	//Constructor
	//Destructor
        MySerialPort( const any_type &port_name );
	~MySerialPort();
	//Write some data to port
	void write_to_serial( const any_type data );
	//Read data from port which write data just now
	void read_from_serial();
	//The asyanc callback function of asyanc_read
	void handle_read( char buf[], boost::system::error_code ec,
		std::size_t bytes_transferred );
	//To Call io_service::run function to call asyanc callback funciton
	void call_handle();
private:
	//io_service Object
	io_service m_ios;
	//Serial port Object
	serial_port *pSerialPort;
	//For save com name
	any_type m_port;
	//Serial_port function exception
	boost::system::error_code ec;


(2)成员函数实现

#include "stdafx.h"
#include <string>
#include <vector>
#include "SerialCom.h"
//Define Constructor function
MySerialPort::MySerialPort( const any_type &port_name ):pSerialPort( NULL )
        pSerialPort = new serial_port( m_ios );
	if ( pSerialPort ){
		init_port( port_name, 8 );
//Define destructor function
MySerialPort::~MySerialPort()
       if( pSerialPort )
               delete pSerialPort;
//Initialize port
bool MySerialPort::init_port( const any_type port, const unsigned int char_size )
	//New not success
	if ( !pSerialPort ){
		return false;
        //Open Serial port object
        pSerialPort->open( port, ec );
	//Set port argument
	pSerialPort->set_option( serial_port::baud_rate( 9600 ), ec );
	pSerialPort->set_option( serial_port::flow_control( serial_port::flow_control::none ), ec );
	pSerialPort->set_option( serial_port::parity( serial_port::parity::none ), ec );
	pSerialPort->set_option( serial_port::stop_bits( serial_port::stop_bits::one ), ec);
	pSerialPort->set_option( serial_port::character_size( char_size ), ec);
	return true;
//Define wirte_to_serial to write data to serial
void MySerialPort::write_to_serial( const any_type data )
        size_t len = write( *pSerialPort, buffer( data ), ec );
        cout << len << "\t" << data << "\n";
void MySerialPort::handle_read( char buf[], boost::system::error_code ec,
	std::size_t bytes_transferred )
	cout << "\nhandle_read: ";
	cout.write(buf, bytes_transferred);
//Read data from the serial
void MySerialPort::read_from_serial()
       char v[10];
       async_read( *pSerialPort, buffer(v), boost::bind( &MySerialPort::handle_read, this, v, _1, _2) );
//Call handle_read function when async function read complete or come out exception
void MySerialPort::call_handle()
        //There can use deadline_timer to cancle serial_port read data
	//Wait for call callback function
	m_ios.run();


(3) 使用类

VS下的控制台程序就可以,当然首先得配置VS2010与boost库环境:见VS2010 BOOST库配置

// BoostSerialCommunication.cpp : Defines the entry point for the console application.
#ifdef _MSC_VER
#define _WIN32_WINNT        0X0501    
#endif
#define BOOST_REGEX_NO_LIB
#define BOOST_DATE_TIME_SOURCE
#define BOOST_SYSTEM_NO_LIB
#include "stdafx.h"
#include "SerialCom.h"
int _tmain(int argc, _TCHAR* argv[])
	MySerialPort my_Sp( "COM3");
	my_Sp.write_to_serial( "SerialPort" );
	my_Sp.read_from_serial();
	my_Sp.call_handle();
	getchar();
	getchar();
	return 0;
catch(  std::exception &e )
       cout << e.what();
       getchar();

如果async_read读取的数据段长度大于写入串口的数据,则可以正确执行read_from_serial()后续代码,而回调函数handle_read不会被执行指导异常发生或者读满v的长度为止。但整个程序不会为止而阻塞。可以用boost库下的deadline_timer为serial_port读取数据定时,当时间到达时不再继续读取数据即可,立马就会调用回调函数handle_read。不过从串口读出来的数据输出到屏幕之上时为乱码,还没找到原因。

Boost Note Over.

串口一旦存在后,C++ boost::asio就当串口为一种流(文件流 )来使用。C++的BOOST库中,通信库都在asio下,串口类结构为boost::asio::serial_port。串口通信由asio组件的serial_port类完成。BOOST库下的串口通信serial_port类的使用跟网络通信相似[网络通信 ],只是在进行串口通信前需要初始化串口。下面记录使用步骤:1 本文转载自串口通信Serial PortC++实现 串口介绍 串口叫做串行接口,也称串行通信接口,按电气标准及协议来分包括RS-232、RS-422、RS485、USB等。 RS-232-C、RS-422与RS-485标准只对接口的电气特性做出规定,不涉及接插件、电缆或协议。USB是近几年发展起来的新型接口标准,主要应用于高速数据传输领域。 RS-232:也称标准串口,是目前最常用的一种串行通讯接口。它是在1970年由美国电子工业协会(EIA
程序除了要发起IO操作,还要定义一个用于回调的完成处理函数。io_service同样把IO操作转交给操作系统执行,但它不同步等待,而是立即返回。调用io_service的run()成员函数可以等待异步操作完成,当异步操作完成时io_service从操作系统获取结果,在调用handler执行后续逻辑。 1.1 handler回调函数 void handler(const error_code &ec); void handler(const error_code &ec, int signa
boost库有一个asio,支持串口通信。 1、产生一个boost::asio::io_service(前摄模式,似于完成端口,不过,可以针对不同IO对象) 2、构造一个boost::asio::serial_port,有两种方法: (一)boost::asio::serial_port m_serialPort(m_IoService, “COM1”); (二)boost::asio::serial_port m_se 1. 先去 Boost官网 下载最新的Boost版本, 我下载的是boost_1_63_0版本, 解压. 2. 进入解压后目录: cd boost_1_63_0, 执行下面的命令: $ ./bootstrap.sh --prefix=path/to/installation/prefix 使用Boost.Beast和Boost.ASIO的C ++ 17中的HTTP / Websocket库。 Belle使C ++程序能够通过HTTP和Websockets进行异步通信。 它旨在拥有一个直观的API,合理的默认值和出色的性能。 侦听127.0.0.1:8080的HTTP服务器,该服务器响应对路径'/'的POST请求。 # include " belle.hh " namespace Belle = OB::Belle; # include < string> int main () // init the server with local address