一.ubuntu端注意事项及代码编写
简介
笔者在用Ubuntu系统进行开发时,时常将其作为一个上层处理机构,通过计算传感器获取到的源数据后输出给下层执行,而这个传输过程常常使用串口通信,所以在封装一个方便好用的串口收发库可以有限解决这一需求,本文章将针对C++实现串口收发和简单校验以及指定Ubuntu系统USB设备进行简要介绍。
开放用户串口权限
ubuntu系统中的串口使用权限并没有对用户开放,所以我们在要用代码控制串口收发前还需要开放用户对串口的使用权限(否则会出现找不到串口的情况,只有在加sudo后才能正常运行)。
ttyS设备的用户主是root,而所属的组是dialout,并且owner和group都是有相同的权限的,但others是没有任何权限的。
使用groups命令,我们就明白了:我们在安装Ubuntu时,安装时使用的账户并不会默认加入dialout组,因此该用户就没有权限可以访问ttyS设备了。
# 终端键入
sudo usermod -a -G dialout user_name
重启系统后,用户“user_name”就会加入dialout组了,之后我们就能自由自在地访问ttyS设备了
系统中,想要查看串口号的话,terminal中使用
ls -l /dev/tty*
C++实现串口发送和接收
#include <boost/asio.hpp>
#include <boost/bind.hpp>
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <stdio.h>
#include <fcntl.h>
#include <termios.h>
#include <unistd.h>
#include <errno.h>
using namespace std;
using namespace boost::asio;
using namespace boost::placeholders;
//串口消息队列
int msg_queue[5];
int serial_send(void)
{
//串口发送
int fd; /*File Descriptor*/
printf("\n +----------------------------------+");
printf("\n | Serial Port Write |");
printf("\n +----------------------------------+");
fd = open("/dev/ttyACM0", O_RDWR | O_NOCTTY | O_NDELAY);//使用串口为/dev/ttyACM0
if (fd == -1) /* Error Checking */
printf("\n Error! in Opening ttyACM0 ");
else
printf("\n ttyACM0 Opened Successfully ");
struct termios SerialPortSettings;
tcgetattr(fd, &SerialPortSettings);
//设置波特率
cfsetispeed(&SerialPortSettings, B115200);
cfsetospeed(&SerialPortSettings, B115200);
//设置没有校验
SerialPortSettings.c_cflag &= ~PARENB;
//停止位 = 1
SerialPortSettings.c_cflag &= ~CSTOPB;
SerialPortSettings.c_cflag &= ~CSIZE;
//设置数据位 = 8
SerialPortSettings.c_cflag |= CS8;
SerialPortSettings.c_cflag &= ~CRTSCTS;
SerialPortSettings.c_cflag |= CREAD | CLOCAL;
//关闭软件流动控制
SerialPortSettings.c_iflag &= ~(IXON | IXOFF | IXANY);
//设置操作模式
SerialPortSettings.c_iflag &= ~(ICANON | ECHO | ECHOE | ISIG);
SerialPortSettings.c_oflag &= ~OPOST;
if ((tcsetattr(fd, TCSANOW, &SerialPortSettings)) != 0)
printf("\n ERROR ! in Setting attributes");
else
printf("\n BaudRate = 115200 \n StopBits = 1 \n Parity = none");
//定义传输内容
//char write_buffer[] = "Hello World";
msg_queue[0] = 800;
msg_queue[1] = 1900;
//传输字节数
int bytes_written = 0;
//串口写数据
bytes_written = write(fd, msg_queue, sizeof(msg_queue));
//bytes_written = write(fd, msg_queue, sizeof(msg_queue));
printf("\n %d written to ttyACM0", msg_queue[0]);
printf("\n %d written to ttyACM0", msg_queue[1]);
printf("\n %d Bytes written to ttyACM0", bytes_written);
printf("\n +----------------------------------+\n\n");
close(fd);
return 0;
}
int serial_get(void)
{
//串口接收
io_service iosev;
serial_port sp(iosev, "/dev/ttyACM0");
sp.set_option(serial_port::baud_rate(115200));
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));
while(1)
{
char rxData[100];
std::vector<int> rx_msg;
boost::system::error_code err;
//scanf("%s\n",rxData);
//sp.read_some(buffer(rxData,39),err);
sp.read_some(buffer(rx_msg,39),err);
//std_msgs::String msg;
//std::stringstream ss;
std::cout <<" "<<rxData<<" \n";
}
return 0;
}
对应CMakeists.txt为
cmake_minimum_required(VERSION 2.7)
//根据自己实际情况修改
add_executable(main src/main.cpp)
//主要部分为以下两句
find_package(Threads REQUIRED)
target_link_libraries(main Threads::Threads)
经测试和修改,完善了串口发送和接受代码,使3代码更加整洁高效,如下
#include <boost/asio.hpp>
#include <boost/bind.hpp>
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <stdio.h>
#include <fcntl.h>
#include <termios.h>
#include <unistd.h>
#include <errno.h>
#include <stdlib.h>
using namespace std;
using namespace boost::asio;
using namespace boost::placeholders;
// 串口消息队列
int msg_queue[5];
int color, mode;
io_service iosev;
serial_port sp(iosev, "/dev/ttyACM0");
boost::system::error_code err;
void serial_init()
{
sp.set_option(serial_port::baud_rate(115200));
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));
}
int serial_send(int *msg_temp)
{
for (int i = 0; i < 5; i++)
msg_queue[i] = msg_temp[i];
// 串口写数据
sp.write_some(buffer(msg_queue, sizeof(msg_queue)), err);
std::cout << "written to ttyACM0 " << msg_queue[0] << " " << msg_queue[1] << " " << msg_queue[2] << " " << msg_queue[3] << " " << msg_queue[4] << endl;
return 0;
}
void serial_get(void)
{
// 串口接收
int rxdata[2];
while (1)
{
char rxData[100];
// 串口读取数据,保存在缓冲区rxData
sp.read_some(buffer(rxData, 10), err);
std::istringstream iss(rxData); // 创建字符串输入流
for (size_t i = 0; i < 2; ++i)
{
if (!(iss >> rxdata[i])) // 将字符串转换为整数并保存到数组中
{
std::cerr << "Error: invalid input" << std::endl;
}
}
color = rxdata[0];
mode = rxdata[1];
std::cout << "robot_id = " << color << std::endl;
std::cout << "mode = " << mode << std::endl;
}
}
二.STM32端注意事项及代码编写
代码参考了大疆A板例程的USB部分
经本人测试,可行。