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;
}