M12345b 2021-06-16 20:25 采纳率: 30%
浏览 26
已结题

大佬们 可以帮忙看一下这个串口通信里面哪里有问题吗?

#include <stdio.h>
#include <fcntl.h>
#include <assert.h>
#include <termios.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <sys/time.h>
#include <sys/types.h>
#include <errno.h>

static int fd;
static int ret;

int uart_open(int fd, const char* pathname);
int uart_config(int fd, int baude, int c_flow, int bits, char parity, int stop);
int safe_read(int fd, char* vptr, size_t len);
int uart_read(int fd, char* r_buf, size_t lenth);//串口读取数据
int uart_close(int fd);

int uart_open(int fd, const char* pathname)
{
    assert(pathname);//检测串口路径是否存在
    fd = open(pathname, O_RDWR | O_NOCTTY | O_NDELAY);//以只读形式、不将此终端作为此进程的终端控制器、非阻塞的形式打开串口
    if (fd == -1)
    {
        perror("uart open failed!");
        return -1;
    }
    if (fcntl(fd, F_SETFL, 0) < 0)//设置串口非阻塞,因为这里是以非阻塞形式打开的,所以第三个参数为0,后面会详细介绍fcntl函数
    {
        perror("fcntl failed!");
        return -1;
    }
    return fd;
}

int uart_config(int fd, int baude, int c_flow, int bits, char parity, int stop)
{
    struct termios uart;
    if (tcgetattr(fd, &uart) != 0)
    {
        perror("tcgetattr failed!");
        return -1;
    }
    switch (baude)
    {
    case 115200:
        cfsetispeed(&uart, B115200);//设置输入波特率
        cfsetospeed(&uart, B115200);//设置输出波特率
        break;
    case 9600:
        cfsetispeed(&uart, B9600);
        cfsetospeed(&uart, B9600);
        break;
    case 19200:
        cfsetispeed(&uart, B19200);
        cfsetospeed(&uart, B19200);
        break;
    case 38400:
        cfsetispeed(&uart, B38400);
        cfsetospeed(&uart, B38400);
        break;
    default:
        fprintf(stderr, "Unknown baude!");
        return -1;
    }
    switch (c_flow)
    {
    case 'N':
    case 'n':
        uart.c_cflag &= ~CRTSCTS;//不进行硬件流控制
        break;
    case 'H':
    case 'h':
        uart.c_cflag |= CRTSCTS;//进行硬件流控制
        break;
    case 'S':
    case 's':
        uart.c_cflag |= (IXON | IXOFF | IXANY);//进行软件流控制
        break;
    default:
        fprintf(stderr, "Unknown c_cflag");
        return -1;
    }

    switch (bits)
    {
    case 5:
        uart.c_cflag &= ~CSIZE;//屏蔽其他标志位
        uart.c_cflag |= CS5;//数据位为5位
        break;
    case 6:
        uart.c_cflag &= ~CSIZE;
        uart.c_cflag |= CS6;
        break;
    case 7:
        uart.c_cflag &= ~CSIZE;
        uart.c_cflag |= CS7;
        break;
    case 8:
        uart.c_cflag &= ~CSIZE;
        uart.c_cflag |= CS8;
        break;
    default:
        fprintf(stderr, "Unknown bits!");
        return -1;
    }
    switch (parity)
    {
    case 'n':
    case 'N':
        uart.c_cflag &= ~PARENB;//PARENB:产生奇偶校验
        uart.c_cflag &= ~INPCK;//INPCK:使奇偶校验起作用
        break;
    case 's':
    case 'S':
        uart.c_cflag &= ~PARENB;
        uart.c_cflag &= ~CSTOPB;//使用两位停止位
        break;
    case 'o':
    case 'O':
        uart.c_cflag |= PARENB;
        uart.c_cflag |= PARODD;//使用奇校验
        uart.c_cflag |= INPCK;
        uart.c_cflag |= ISTRIP;//使字符串剥离第八个字符,即校验位
        break;
    case 'e':
    case 'E':
        uart.c_cflag |= PARENB;
        uart.c_cflag &= ~PARODD;//非奇校验,即偶校验
        uart.c_cflag |= INPCK;
        uart.c_cflag |= ISTRIP;
        break;
    default:
        fprintf(stderr, "Unknown parity!\n");
        return -1;
    }
    switch (stop)
    {
    case 1:
        uart.c_cflag &= ~CSTOPB;//CSTOPB:使用两位停止位
        break;
    case 2:
        uart.c_cflag |= CSTOPB;
        break;
    default:
        fprintf(stderr, "Unknown stop!\n");
        return -1;
    }
    uart.c_oflag &= ~OPOST;//OPOST:表示数据经过处理后输出

    if (tcsetattr(fd, TCSANOW, &uart) < 0)//**配置,失败返回-1
    {
        return -1;
    }
    uart.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);//使串口工作在原始模式下
    uart.c_cc[VTIME] = 0;//设置等待时间为0
    uart.c_cc[VMIN] = 1;//设置最小接受字符为1
    tcflush(fd, TCIFLUSH);//清空输入缓冲区
    if (tcsetattr(fd, TCSANOW, &uart) < 0)//**配置
    {
        perror("tcgetattr failed!");
        return -1;
    }
    return 0;
}

int safe_read(int fd, char* vptr, size_t len)
{
    size_t left;
    left = len;
    ssize_t nread;
    char* ptr;
    ptr = vptr;
    while (left > 0)
    {
        if ((nread = read(fd, ptr, left)) < 0)
        {
            if (errno == nread)
            {
                nread = 0;
            }
            else if (nread == 0)
            {
                break;
            }
        }
        left -= nread;//read成功后,剩余要读取的字节自减
        ptr += nread;//指针向后移,避免后读到的字符覆盖先读到的字符
    }
    return (len - left);
}

int uart_read(int fd, char* r_buf, size_t lenth)
{
    fd_set rfds;
    struct timeval time;
    ssize_t cnt = 0;
    /*将读文件描述符加入描述符集合*/
    FD_ZERO(&rfds);
    FD_SET(fd, &rfds);
    /*设置超时为15s*/
    time.tv_sec = 15;
    time.tv_usec = 0;
    /*实现多路IO*/
    ret = select(fd + 1, &rfds, NULL, NULL, &time);
    switch (ret) {
    case -1:
        fprintf(stderr, "select error!\n");
        break;
    case 0:
        fprintf(stderr, "time over!\n");
        break;
    default:
        cnt = safe_read(fd, r_buf, lenth);
        if (cnt == -1)
        {
            fprintf(stderr, "safe read failed!\n");
            return -1;
        }
        return cnt;
    }
}

int uart_close(int fd)
{
    assert(fd);//assert先检查文件描述符是否存在
    close(fd);
    return 0;
}

int main()
{
    char r_buf[1024];
    bzero(r_buf, 1024);
    fd = uart_open(fd, "/dev/ttyUSB0");//选择的是ttsY1串口
    if (fd == -1)
    {
        fprintf(stderr, "open failed!\n");
        exit(EXIT_FAILURE);
    }
    if (uart_config(fd, 115200, 'N', 8, 'N', 1) == -1)
    {
        fprintf(stderr, "configure failed!\n");
        exit(EXIT_FAILURE);
    }

    while (1)
    {
        char text[5] = "ls\r\n";
        int num = 0;
        if (num < 30)
        {
            write(fd, text, 4);
            printf("send:%s\n", text);
        }

        ret = uart_read(fd, r_buf, 1024);
        if (ret == -1)
        {
            fprintf(stderr, "uart_read failed!\n");
            exit(EXIT_FAILURE);
        }
        printf("buf:%s \n", r_buf);
    }
    ret = close(fd);
    if (ret == -1)
    {
        fprintf(stderr, "close failed!\n");
        exit(EXIT_FAILURE);
    }
    exit(EXIT_SUCCESS);
}
  • 写回答

1条回答 默认 最新

  • QQ3200028121 2021-06-18 14:05
    关注

    184行到187行删掉,本来就是非阻塞方式打开的,肯定会经常出现读不到数据的情况,这个时候需要继续等待数据,而不是跳出

    评论

报告相同问题?

悬赏问题

  • ¥15 逻辑谓词和消解原理的运用
  • ¥15 请求分析基于spring boot+vue的前后端分离的项目
  • ¥15 三菱伺服电机按启动按钮有使能但不动作
  • ¥15 js,页面2返回页面1时定位进入的设备
  • ¥200 关于#c++#的问题,请各位专家解答!网站的邀请码
  • ¥50 导入文件到网吧的电脑并且在重启之后不会被恢复
  • ¥15 (希望可以解决问题)ma和mb文件无法正常打开,打开后是空白,但是有正常内存占用,但可以在打开Maya应用程序后打开场景ma和mb格式。
  • ¥20 ML307A在使用AT命令连接EMQX平台的MQTT时被拒绝
  • ¥20 腾讯企业邮箱邮件可以恢复么
  • ¥15 有人知道怎么将自己的迁移策略布到edgecloudsim上使用吗?