简介
笔者在用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设备了
C++实现串口发送
下面展示一个简单的串口发送例程代码
#include <stdio.h>
#include <fcntl.h>
#include <termios.h>
#include <unistd.h>
#include <errno.h>
void main(void)
{
int fd; /*File Descriptor*/
printf("\n +----------------------------------+");
printf("\n | Serial Port Write |");
printf("\n +----------------------------------+");
fd = open("/dev/ttyUSB0", O_RDWR | O_NOCTTY | O_NDELAY);
if (fd == -1) /* Error Checking */
printf("\n Error! in Opening ttyUSB0 ");
else
printf("\n ttyUSB0 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";
//传输字节数
int bytes_written = 0;
//串口写数据
bytes_written = write(fd, write_buffer, sizeof(write_buffer));
printf("\n %s written to ttyUSB0", write_buffer);
printf("\n %d Bytes written to ttyUSB0", bytes_written);
printf("\n +----------------------------------+\n\n");
close(fd);
}
tcgetattr函数用于获取与终端相关的参数。参数fd为终端的文件描述符,返回的结果保存在termios结构体。cfsetispeed和cfsetospeed用于设置接收和发送的波特率,通过write函数实现都串口的发送。
程序中的 /dev/ttyUSB0 表示要指定打开的串口,但这里存在一个问题,ttyUSB0与USB的端口并不是固定的,与插入的串口顺序有关。所以当同时插入多个USB设备时,我们就不可以通过这种方法来打开串口(因为可能存在错乱)。
Ubuntu 多个同型号usb设备固定名称
Ubuntu中,先插入的设备生成的设备文件编号较低,比如usb转串口设备是按照ttyUSB0,ttyUSB1这种方式逐渐生成。所以串口的名称与串口插入顺序有关,且端口不固定,在重启后串口名称和指定顺序可能发生改变。
解决办法: 将端口重映射到固定的名字,并且设置其权限为可读。使用对应的 id 设备映射到固定的名字上。
解决步骤:
- 查找需要固定的usb端口id号
ls /sys/class/tty/ttyUSB* -l
输出结果:
通过拔插设备确定每个usb端口的id号,eg:上图中的1-4:1.0
- 将端口重映射到固定的名字
# 终端键入
sudo vim /etc/udev/rules.d/10-local.rules
添加下面内容:ACTION==“add”,KERNELS==“上述查找的端口id号”, SUBSYSTEMS==“usb”, MODE:=“0777”, SYMLINK+="重映射名字"
eg:
- 保存退出。重新插拔设备(或重启)就会在/dev目录下生成固定的设备名
此时我们要打开指定的串口,只需要将上述例程代码中的ttyUSB0改成自己重映射后的串口名称即可(图中为DownSentry)。
后续
喜欢的话可以关注一下我的公众号技术开发小圈,尤其是对深度学习以及计算机视觉有兴趣的朋友,我会把相关的源码以及更多资料发在上面,希望可以帮助到新入门的大家!