C++ boost::asio::serial_port 串口通信类 使用 封装 [大三四八九月实习]
来源:互联网 发布:php源码包下载地址 编辑:程序博客网 时间:2024/05/22 13:03
串口一旦存在后,C++ boost::asio就当串口为一种流(文件流 )来使用。
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 portbool 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 portvoid write_to_serial( const any_type data );//Read data from port which write data just nowvoid read_from_serial();//The asyanc callback function of asyanc_readvoid handle_read( char buf[], boost::system::error_code ec,std::size_t bytes_transferred );//To Call io_service::run function to call asyanc callback funcitonvoid call_handle();private://io_service Objectio_service m_ios;//Serial port Objectserial_port *pSerialPort;//For save com nameany_type m_port;//Serial_port function exceptionboost::system::error_code ec;};
(2)成员函数实现
#include "stdafx.h"#include <string>#include <vector>#include "SerialCom.h"//Define Constructor functionMySerialPort::MySerialPort( const any_type &port_name ):pSerialPort( NULL ){ pSerialPort = new serial_port( m_ios );if ( pSerialPort ){init_port( port_name, 8 );}} //Define destructor functionMySerialPort::~MySerialPort(){ if( pSerialPort ) { delete pSerialPort; } }//Initialize portbool MySerialPort::init_port( const any_type port, const unsigned int char_size ){//New not successif ( !pSerialPort ){return false;} //Open Serial port object pSerialPort->open( port, ec );//Set port argumentpSerialPort->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 serialvoid 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 serialvoid 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 exceptionvoid MySerialPort::call_handle(){ //There can use deadline_timer to cancle serial_port read data//Wait for call callback functionm_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[])try{ {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::serial_port 串口通信类 使用 封装 [大三四八九月实习]
- C++ boost::asio::serial_port 串口通信类 使用 封装
- C++ Boost asio库网络通信 [同/异步] [大三四八九月实习]
- C++ Boost库 asio同步/异步模式[ 定时器来体现 ] [大三四八九月实习]
- BOOST 库 thread类线程使用 [大三四八九月实习]
- [Boost.asio] C++ boost::asio::serial_port 串口通信类
- C++ BOOST库 条件变量[多线程通信]机制 [大三四八九月实习]
- boost库 bind/function的使用 [大三四八九月实习]
- Debian Linux字符界面 Boost 库下载 使用 [大三四八九月实习]
- 多线程执行 [大三四八九月实习]
- 第一个月实习总结 [大三四八九月实习]
- 第二月实习总结 [大三四八九月实习]
- boost asio serial_port 读写串口
- boost asio serial_port 读写串口
- boost::asio::serial_port串口编程
- boost::asio::serial_port 串口编程
- BOOST 在windows的编译及配置(VS2010) [大三四八九月实习]
- BOOST timer库应用[timer库1] [大三四八九月实习]
- 【啊哈,算法】之十、后缀数组,求最长重复子串
- 多任务下看门狗程序实现
- c语言之猴子选大王
- 【初学】Objective-C学习笔记-献给我们敬爱的Hello World!
- 成都网预
- C++ boost::asio::serial_port 串口通信类 使用 封装 [大三四八九月实习]
- UVa 10035 Primary Arithmetic (陷阱较多~)
- HDU 4749 && POJ 3167 KMP
- 武汉公积金新政10日起实行 四种算法取最低值(zz)
- Linux的多任务编程-线程
- 多任务程序看门狗设计
- HDU 4750 && HDU 3938 离线并查集
- C#
- 杭州网预