用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
;
}
上面这段代码有个问题,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
)
)
;
另外一个方法是使用前面说过的异步读写+超时的方式,代码如下:
#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
;
}