linux串口通信

Posted 神佑我调参侠

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了linux串口通信相关的知识,希望对你有一定的参考价值。

前言

因为最后我们要将得到的数据传给电控,传输的方式就是串口通信,然而以前我使用的都是python写的,这次开始使用c/c++去写,开始是让学弟写,但是加入工程的时候发现有很多地方都封装不了,于是我打算自己来实现一波,然后封装一下,那现在开始吧。
借鉴:https://blog.csdn.net/AAA375/article/details/100096490

串口引脚

首先我们来看一下串口的引脚,因为我们后期写的代码就是对这些引脚进行操作的,我在第一次看代码的时候也是很蒙的,因为我并不知道那些我不知道的是引脚。。。。

具体怎么用后期直接结合代码查看!

代码书写

导入库

这个吧,直接复制就好

#include     <stdio.h>      /*标准输入输出定义*/
#include     <stdlib.h>     /*标准函数库定义*/
#include     <unistd.h>     /*Unix 标准函数定义*/
#include     <sys/types.h>  /*数据类型,比如一些XXX_t的那种*/
#include     <sys/stat.h>   /*定义了一些返回值的结构,没看明白*/
#include     <fcntl.h>      /*文件控制定义*/
#include     <termios.h>    /*PPSIX 终端控制定义*/
#include     <errno.h>      /*错误号定义*/

打开串口

首先得明白个事,端口不固定,对于不同的设备是不同,对于linux下的话是位于 /dev 下的,串口一 为 /dev/ttyS0,串口二 为 /dev/ttyS1,我们这里用的串口一:

#include     <stdio.h>      /*标准输入输出定义*/
#include     <stdlib.h>     /*标准函数库定义*/
#include     <unistd.h>     /*Unix 标准函数定义*/
#include     <sys/types.h>  /*数据类型,比如一些XXX_t的那种*/
#include     <sys/stat.h>   /*定义了一些返回值的结构,没看明白*/
#include     <fcntl.h>      /*文件控制定义*/
#include     <termios.h>    /*PPSIX 终端控制定义*/
#include     <errno.h>      /*错误号定义*/
#include     <iostream>  

using namespace std;

int main()
    int fd = -1;
    /*以读写方式打开串口*/
    fd = open( "/dev/ttyS0", O_RDWR);
    cout<<fd<<endl;
    if (-1 == fd)
    /* 不能打开串口一*/
        perror(" 提示错误!");
    
    else
         cout<<"打开成功!"<<endl;
    

可以看到我们已经成功打开串口了

设置串口(修改比特率)

在打开串口后我们要进行一些设置,如比特率,效验位等,这些设置是通过一个结构体来设置。

struct termio

   unsigned short  c_iflag; /* 输入模式标志 */ 
    unsigned short  c_oflag;     /* 输出模式标志 */ 
    unsigned short  c_cflag;     /* 控制模式标志*/  
    unsigned short  c_lflag;     /* local mode flags */  
    unsigned char    c_line;           /* line discipline */
    unsigned char    c_cc[NCC];    /* control characters */
;

如果要去看源码的话,是很难理解的,我也是没看懂,但是并不影响我们使用,下面是一个设置波特率的例子:

//比特率配置
int speed_arr[] =  B38400, B19200, B9600, B4800, B2400, B1200, B300,
                  B38400, B19200, B9600, B4800, B2400, B1200, B300, ;

int name_arr[] = 38400,  19200,  9600,  4800,  2400,  1200,  300, 38400, 
                  19200,  9600, 4800, 2400, 1200,  300, ;

void set_speed(int fd, int speed)

    int status;
    //定义结构体
    struct termios Opt;
    //tcgetattr函数用于获取与终端相关的参数。参数fd为终端的文件描述符,返回的结果保存在termios结构体中
    tcgetattr(fd, &Opt);

    for (int i = 0; i < sizeof(speed_arr) / sizeof(int); i++)
    
        if (speed == name_arr[i])
        
        	//清空终端未完成的输入/输出请求及数据。TCIOFLUSH // 清除所有正在发生的I/O数据。
            tcflush(fd, TCIOFLUSH);
            //设置输入速度
            cfsetispeed(&Opt, speed_arr[i]);
            //设置输出速度
            cfsetospeed(&Opt, speed_arr[i]);
            //使用tcsetattr函数将修改后的终端参数设置到标准输入中
            status = tcsetattr(fd, TCSANOW, &Opt);
            if (status != 0)
            
                perror("tcsetattr fd1");
                return;
            
            tcflush(fd, TCIOFLUSH); 
        
    

这里面有几个函数大家可能没见过,但是注释中也写的很明白了,其实就是先获取结构体的参数,然后修改比特率参数,再设置一下,上述一大堆操作就是为了修改比特率。

#include <stdio.h>     /*标准输入输出定义*/
#include <stdlib.h>    /*标准函数库定义*/
#include <unistd.h>    /*Unix 标准函数定义*/
#include <sys/types.h> /*数据类型,比如一些XXX_t的那种*/
#include <sys/stat.h>  /*定义了一些返回值的结构,没看明白*/
#include <fcntl.h>     /*文件控制定义*/
#include <termios.h>   /*PPSIX 终端控制定义*/
#include <errno.h>     /*错误号定义*/
#include <iostream>

using namespace std;

//串口状态变量
int fd = -1;
//比特率配置
int speed_arr[] =  B38400, B19200, B9600, B4800, B2400, B1200, B300,
                  B38400, B19200, B9600, B4800, B2400, B1200, B300, B115200 ;

int name_arr[] = 38400,  19200,  9600,  4800,  2400,  1200,  300, 38400, 
                  19200,  9600, 4800, 2400, 1200,  300,115200 ;

//打开串口
void open_port()

    /*以读写方式打开串口*/
    fd = open("/dev/ttyS0", O_RDWR);
    if (-1 == fd)
    
        /* 不能打开串口一*/
        perror(" 串口打开失败!");
    
    else
    
        cout << "串口打开成功!" << endl;
    


//设置比特率速度
void set_speed(int fd, int speed)

    int status;
    //定义结构体
    struct termios Opt;
    //fd=0标准输入,该函数作用是将fd的状态放入结构体
    tcgetattr(fd, &Opt);
    //使用原始模式
    Opt.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); /*Input*/
    Opt.c_oflag &= ~OPOST; /*Output*/
    cout<<1<<endl;
    for (int i = 0; i < sizeof(speed_arr) / sizeof(int); i++)
    

        if (speed == name_arr[i])
        
            tcflush(fd, TCIOFLUSH);
            cfsetispeed(&Opt, speed_arr[i]);
            cfsetospeed(&Opt, speed_arr[i]);
            status = tcsetattr(fd, TCSANOW, &Opt);
            if (status != 0)
            
                perror("tcsetattr fd1");
                return;
            
            else
                cout<<"比特率速度修改成功"<<endl;
            
            tcflush(fd, TCIOFLUSH); 
        
    


int main()

    open_port();
    set_speed(0,115200);
    return 0;

发送数据

写串口操作是通过write函数来完成的。函数原型如下:

write(int fd, *buffer,length);

参数说明:

(1).fd:文件描述符
(2).*buffer:存储写入数据的数据缓冲区
(3).length:写入缓冲去的数据字节数

函数返回值:
成功返回写入数据的字节数,该值通常等于length,如果写入失败返回-1。
例如:向终端设备发送初始化命令
设置好串口之后,读写串口就很容易了,把串口当作文件读写就是。

#include <stdio.h>     /*标准输入输出定义*/
#include <stdlib.h>    /*标准函数库定义*/
#include <unistd.h>    /*Unix 标准函数定义*/
#include <sys/types.h> /*数据类型,比如一些XXX_t的那种*/
#include <sys/stat.h>  /*定义了一些返回值的结构,没看明白*/
#include <fcntl.h>     /*文件控制定义*/
#include <termios.h>   /*PPSIX 终端控制定义*/
#include <errno.h>     /*错误号定义*/
#include <iostream>

using namespace std;

//串口状态变量
int fd = -1;
//比特率配置
int speed_arr[] =  B38400, B19200, B9600, B4800, B2400, B1200, B300,
                  B38400, B19200, B9600, B4800, B2400, B1200, B300, B115200 ;

int name_arr[] = 38400,  19200,  9600,  4800,  2400,  1200,  300, 38400, 
                  19200,  9600, 4800, 2400, 1200,  300,115200 ;

//打开串口
void open_port()

    /*以读写方式打开串口*/
    fd = open("/dev/ttyS0", O_RDWR);
    if (-1 == fd)
    
        /* 不能打开串口一*/
        perror(" 串口打开失败!");
    
    else
    
        cout << "串口打开成功!" << endl;
    


//设置比特率速度
void set_speed(int fd, int speed)

    int status;
    //定义结构体
    struct termios Opt;
    //fd=0标准输入,该函数作用是将fd的状态放入结构体
    tcgetattr(fd, &Opt);
    //使用原始模式
    //Opt.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); /*Input*/
    //Opt.c_oflag &= ~OPOST; /*Output*/

    for (int i = 0; i < sizeof(speed_arr) / sizeof(int); i++)
    

        if (speed == name_arr[i])
        
            tcflush(fd, TCIOFLUSH);
            cfsetispeed(&Opt, speed_arr[i]);
            cfsetospeed(&Opt, speed_arr[i]);
            status = tcsetattr(fd, TCSANOW, &Opt);
            if (status != 0)
            
                perror("tcsetattr fd1");
                return;
            
            else
                cout<<"比特率速度修改成功"<<endl;
            
            tcflush(fd, TCIOFLUSH); 
        
    


void write_port(char buffer[1024])

    int Length;
    int nByte;
    nByte = write(fd, buffer ,Length);
    cout<<"nByte="<<nByte<<endl;
    cout<<"Length="<<Length<<endl;



void read_port(char buffer[1024])

    cout<<"123"<<endl;
    int nread =read(fd, buffer, 512);
    cout<<"nread"<<nread<<endl;
    cout<<"buffer"<<buffer<<endl;




int main()

    open_port();
    set_speed(0,115200);
    
    while(1)
       
        char buffer[1024]="0x25";
        //read_port(buffer);
        write_port(buffer);
    

    return 0;

#总结
通过上面的学习现在已经可以接送和发送了,但是有点小问题,下篇文章将结合RM来进行实战!

以上是关于linux串口通信的主要内容,如果未能解决你的问题,请参考以下文章

linux串口通信

linux下的qt串口通信

嵌入式Linux裸机开发——UART串口通信

Linux下串口通信工具minicom的用法

linux串口编程(termios)相关的使用问题

linux串口通信