用ASIO读写串行口
ASIO不仅支持网络通信,还能支持串口通信。要让两个设备使用串口通信,关键是要设置好正确的参数,这些参数是:波特率、奇偶校验 位、停止位、字符大小和流量控制。两个串口设备只有设置了相同的参数才能互相交谈。
ASIO提供了boost::asio::serial_port类,它有一个set_option(const SettableSerialPortOption& option)方法就是用于设置上面列举的这些参数的,其中的option可以是:
- serial_port::baud_rate 波特率,构造参数为unsigned int
- serial_port::parity 奇偶校验,构造参数为serial_port::parity::type,enum类型,可以是none, odd, even。
- serial_port::flow_control 流量控制,构造参数为serial_port::flow_control::type,enum类型,可以是none software hardware
- serial_port::stop_bits 停止位,构造参数为serial_port::stop_bits::type,enum类型,可以是one onepointfive two
- serial_port::character_size 字符大小,构造参数为unsigned int
演示代码
#include <iostream>
#include <boost/asio.hpp>
#include <boost/bind.hpp>
using namespace std ;
using namespace boost :: asio ;
int main ( int argc, char * argv [ ] )
{
io_service iosev ;
// 串口COM1, Linux下为“/dev/ttyS0”
serial_port sp (iosev, "COM1" ) ;
// 设置参数
sp. set_option (serial_port :: baud_rate (19200 ) ) ;
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 ) ) ;
// 向串口写数据
write (sp, buffer ( "Hello world", 12 ) ) ;
// 向串口读数据
char buf [100 ] ;
read (sp, buffer (buf ) ) ;
iosev. run ( ) ;
return 0 ;
}
#include <boost/asio.hpp>
#include <boost/bind.hpp>
using namespace std ;
using namespace boost :: asio ;
int main ( int argc, char * argv [ ] )
{
io_service iosev ;
// 串口COM1, Linux下为“/dev/ttyS0”
serial_port sp (iosev, "COM1" ) ;
// 设置参数
sp. set_option (serial_port :: baud_rate (19200 ) ) ;
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 ) ) ;
// 向串口写数据
write (sp, buffer ( "Hello world", 12 ) ) ;
// 向串口读数据
char buf [100 ] ;
read (sp, buffer (buf ) ) ;
iosev. run ( ) ;
return 0 ;
}
上面这段代码有个问题,read(sp, buffer(buf))非得读满100个字符才会返回,串口通信有时我们确实能知道对方发过来的字符长度,有时候是不能的。
如果知道对方发过来的数据里有分隔符的话(比如空格作为分隔),可以使用read_until来读,比如:
boost
::
asio
::
streambuf buf
;
// 一直读到遇到空格为止
read_until (sp, buf, ' ' ) ;
copy (istream_iterator < char > (istream ( &buf ) >>noskipws ),
istream_iterator < char > ( ),
ostream_iterator < char > ( cout ) ) ;
// 一直读到遇到空格为止
read_until (sp, buf, ' ' ) ;
copy (istream_iterator < char > (istream ( &buf ) >>noskipws ),
istream_iterator < char > ( ),
ostream_iterator < char > ( cout ) ) ;
另外一个方法是使用前面说过的异步读写+超时的方式,代码如下:
#include <iostream>
#include <boost/asio.hpp>
#include <boost/bind.hpp>
using namespace std ;
using namespace boost :: asio ;
void handle_read ( char *buf,boost :: system :: error_code ec,
std :: size_t bytes_transferred )
{
cout. write (buf, bytes_transferred ) ;
}
int main ( int argc, char * argv [ ] )
{
io_service iosev ;
serial_port sp (iosev, "COM1" ) ;
sp. set_option (serial_port :: baud_rate (19200 ) ) ;
sp. set_option (serial_port :: flow_control ( ) ) ;
sp. set_option (serial_port :: parity ( ) ) ;
sp. set_option (serial_port :: stop_bits ( ) ) ;
sp. set_option (serial_port :: character_size (8 ) ) ;
write (sp, buffer ( "Hello world", 12 ) ) ;
// 异步读
char buf [100 ] ;
async_read (sp, buffer (buf ), boost :: bind (handle_read, buf, _1, _2 ) ) ;
// 100ms后超时
deadline_timer timer (iosev ) ;
timer. expires_from_now (boost :: posix_time :: millisec (100 ) ) ;
// 超时后调用sp的cancel()方法放弃读取更多字符
timer. async_wait (boost :: bind ( &serial_port :: cancel, boost :: ref (sp ) ) ) ;
iosev. run ( ) ;
return 0 ;
}
#include <boost/asio.hpp>
#include <boost/bind.hpp>
using namespace std ;
using namespace boost :: asio ;
void handle_read ( char *buf,boost :: system :: error_code ec,
std :: size_t bytes_transferred )
{
cout. write (buf, bytes_transferred ) ;
}
int main ( int argc, char * argv [ ] )
{
io_service iosev ;
serial_port sp (iosev, "COM1" ) ;
sp. set_option (serial_port :: baud_rate (19200 ) ) ;
sp. set_option (serial_port :: flow_control ( ) ) ;
sp. set_option (serial_port :: parity ( ) ) ;
sp. set_option (serial_port :: stop_bits ( ) ) ;
sp. set_option (serial_port :: character_size (8 ) ) ;
write (sp, buffer ( "Hello world", 12 ) ) ;
// 异步读
char buf [100 ] ;
async_read (sp, buffer (buf ), boost :: bind (handle_read, buf, _1, _2 ) ) ;
// 100ms后超时
deadline_timer timer (iosev ) ;
timer. expires_from_now (boost :: posix_time :: millisec (100 ) ) ;
// 超时后调用sp的cancel()方法放弃读取更多字符
timer. async_wait (boost :: bind ( &serial_port :: cancel, boost :: ref (sp ) ) ) ;
iosev. run ( ) ;
return 0 ;
}