Linux下串口发送数据一段数据后发送不出去(可以正常接收)

本文介绍了一种在Linux环境下解决串口发送数据失败的问题。通过调整串口配置,包括使用正确的波特率设置和初始化方法,成功解决了串口数据发送异常的情况。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Linux下串口发送数据一段数据后发送不出去(可以正常接收),在PC调试时一切正常,但是连接到别的板子上做数据透传时出现了这样的问题

解决办法:是串口的配置有问题,修改代码
用serial_init()初始化ttyS*串口
用open_ttyusb_port()和ttyusb_set_opt() 打开并配置ttyUSB*即可

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <termios.h>

#include "gw_debug.h"
#include "uart.h"



//#define UART_DEBUG
static int support_baud[] = {
    0,     50,    75,    110,    134,    150,   200,
    300,   600,   1200,  1800,   2400,   4800,  9600,
    19200, 38400, 57600, 115200, 230400,
};

int is_support_baud(int baud)
{
    int i = 0;

    for (i = 0; i < ARRAY_SIZE(support_baud); i++)
        if (support_baud[i] == baud)
            return 1;

    return 0;
}

static speed_t int_to_speed(int baud)
{
    if (is_support_baud(baud)) {
        switch (baud) {
        case 0:
            return B0;
        case 50:
            return B50;
        case 75:
            return B75;
        case 110:
            return B110;
        case 134:
            return B134;
        case 150:
            return B150;
        case 200:
            return B200;
        case 300:
            return B300;
        case 600:
            return B600;
        case 1200:
            return B1200;
        case 1800:
            return B1800;
        case 2400:
            return B2400;
        case 4800:
            return B4800;
        case 9600:
            return B9600;
        case 19200:
            return B19200;
        case 38400:
            return B38400;
        case 57600:
            return B57600;
        case 115200:
            return B115200;
        case 230400:
            return B230400;
        default:
            return GW_FAIL;
        }
    }

    return GW_FAIL;
}
#ifdef UART_DEBUG 
static void serial_dump(unsigned char *data, int len)
{
    int i = 0;

    printf("data 0 ~ %d: ", len);
    for (i = 0; i < len; i++)
        printf("%x, ", data[i]);

    printf("\n");
    return;
}
#endif
int serial_init(UART_EX id, int baud)
{
    int fd = -1;
    char name[50] = {0};
    struct termios options;
    speed_t speed;

    if (id < UART_0 || id > UART_3 || !is_support_baud(baud))
        return GW_FAIL;
#if 0
    sprintf(name, "/dev/ttyUSB%d", id);
#else
    sprintf(name, "/dev/ttyS%d", id);
#endif

    fd = open(name, O_RDWR | O_NOCTTY);
    if (fd < 0) {
        perror("Can't open Serial Port");
        return GW_FAIL;
    }

    tcgetattr(fd, &options);

    options.c_cflag |= (CLOCAL | CREAD); //disenable dcd, start read func
    options.c_cflag &= ~CRTSCTS; //close hard stream control
    options.c_cflag &= ~CSIZE;
    options.c_cflag |= CS8; //set data bit 8 (8N1)
    options.c_cflag &= ~(PARENB | CSTOPB); //no use parity check bit and stop bit 1
    options.c_cflag &= ~(ICRNL | IXON);
    options.c_oflag = 0;
    options.c_lflag = 0;

    options.c_iflag &= ~(BRKINT | INPCK | ISTRIP | ICRNL | IXON);

    speed = int_to_speed(baud);
    cfsetispeed(&options, speed);
    cfsetospeed(&options, speed);

    tcsetattr(fd, TCSANOW, &options);

    return fd;
}

int uart_send(int fd, unsigned char *data, int data_len)
{
    int len = 0;

    if (!data || fd < 0 || data_len > UART_DATA_LEN)
        return GW_FAIL;

    len = write(fd, data, data_len);
    if (len == data_len)
        return len;
    else {
        tcflush(fd, TCOFLUSH);
        return GW_FAIL;
    }
}

int uart_recv(int fd, unsigned char *data, int data_len)
{
    int len = 0;

    if (fd < 0 || !data || data_len > UART_DATA_LEN)
        return GW_FAIL;

    len = read(fd, data, data_len);
    if (len < 0)
        return GW_FAIL;
#ifdef UART_DEBUG 
    serial_dump(data, len);
#endif

    return len;
}


int ttyusb_set_opt(int fd,int nSpeed, int nBits, char nEvent, int nStop, int time)
{
  struct termios newtio,oldtio;
  if ( tcgetattr( fd,&oldtio) != 0) { 
    perror("SetupSerial 1");
    return -1;
  }
//  bzero( &newtio, sizeof( newtio ) );
  newtio = oldtio;
  newtio.c_cflag |= CLOCAL | CREAD; 
  newtio.c_cflag &= ~CSIZE; 
  switch( nBits )
  {
  case 7:
    newtio.c_cflag |= CS7;
    break;
  case 8:
    newtio.c_cflag |= CS8;
    break;
  }

  switch( nEvent )
  {
  case 'O':
    newtio.c_cflag |= PARENB;
    newtio.c_cflag |= PARODD;
    newtio.c_iflag |= (INPCK | ISTRIP);
    break;
  case 'E': 
    newtio.c_iflag |= (INPCK | ISTRIP);
    newtio.c_cflag |= PARENB;
    newtio.c_cflag &= ~PARODD;
    break;
  case 'N': 
    newtio.c_cflag &= ~PARENB;
    break;
  }

switch( nSpeed )
  {
  case 2400:
    cfsetispeed(&newtio, B2400);
    cfsetospeed(&newtio, B2400);
    break;
  case 4800:
    cfsetispeed(&newtio, B4800);
    cfsetospeed(&newtio, B4800);
    break;
  case 9600:
    cfsetispeed(&newtio, B9600);
    cfsetospeed(&newtio, B9600);
    break;
  case 57600:
    cfsetispeed(&newtio, B57600);
    cfsetospeed(&newtio, B57600);
    break;
  case 115200:
    cfsetispeed(&newtio, B115200);
    cfsetospeed(&newtio, B115200);
    break;
  default:
    cfsetispeed(&newtio, B57600);
    cfsetospeed(&newtio, B57600);
    break;
  }
  if( nStop == 1 )
    newtio.c_cflag &= ~CSTOPB;
  else if ( nStop == 2 )
  newtio.c_cflag |= CSTOPB;

  newtio.c_cc[VTIME] = time;
  newtio.c_cc[VMIN] = 0;

  tcflush(fd,TCIFLUSH);
  if((tcsetattr(fd,TCSANOW,&newtio))!=0)
  {
    perror("com set error");
    return -1;
  }
  printf("set done!\n");
  return 0;
}

int open_ttyusb_port(int fd,int comport)
{
  char *dev[]={"/dev/ttyUSB0","/dev/ttyUSB1","/dev/ttyUSB2", "/dev/ttyUSB3"};
  long vdisable;
  if (comport==0)
  { fd = open( "/dev/ttyUSB0", O_RDWR|O_NOCTTY|O_NDELAY);
    if (-1 == fd){
      perror("Can't Open Serial Port");
      return(-1);
    }
    else 
      printf("open ttyUSB0 .....\n");
  }
  else if(comport==1)
  { fd = open( "/dev/ttyUSB1", O_RDWR|O_NOCTTY|O_NDELAY);
    if (-1 == fd){
      perror("Can't Open Serial Port");
      return(-1);
    }
    else 
      printf("open ttyUSB1 .....\n");
  }
  else if (comport==2)
  {
    fd = open( "/dev/ttyUSB2", O_RDWR|O_NOCTTY|O_NDELAY);
    if (-1 == fd){
      perror("Can't Open Serial Port");
      return(-1);
    }
    else 
      printf("open ttyUSB2 .....\n");
  }
  else if (comport==3)
  {
    fd = open( "/dev/ttyUSB3", O_RDWR|O_NOCTTY|O_NDELAY);
    if (-1 == fd){
      perror("Can't Open Serial Port");
      return(-1);
    }
    else 
      printf("open ttyUSB3 .....\n");
  }

  if(fcntl(fd, F_SETFL, 0)<0)
    printf("fcntl failed!\n");
  else
    printf("fcntl=%d\n",fcntl(fd, F_SETFL,0));
  if(isatty(STDIN_FILENO)==0)
    printf("standard input is not a terminal device\n");
  else
    printf("isatty success!\n");

  printf("fd-open=%d\n",fd);
  return fd;
}

以下是发送接收逻辑,分别在单独的线程中进行

//发送
while (1) {
        //encodeLen = util_encode(cmd, 2, outbuf, 10);

        ret = uart_send(fd, cmd, sizeof(cmd));
        printf("WRITE[%d]\n", ret);

        sleep(1);
    }

//接收(阻塞接收)
while (1) {
        readLen = uart_recv(fd, buf, SER_BUF_LEN);
        if (readLen < 0) {
            continue;
        }

这个是在论坛别人遇到的相同的情况http://bbs.youkuaiyun.com/topics/310158478

### 在 Linux 中使用串口工具发送数据 #### 工具介绍 在 Linux 系统中,有多种工具可以用于通过串口发送接收数据。以下是几个常用的工具及其功能描述: 1. **Minicom** Minicom 是一个全屏菜单驱动的通信程序,支持串口配置、数据传输等功能。它可以通过图形化界面或者命令行参数完成串口操作[^1]。 2. **Jpnevulator** Jpnevulator 是一款轻量级的串口调试工具,能够捕获并打印 ASCII 数据流以及十六进制数据流。它可以用来监听特定端口上的流量,并允许用户自定义行为模式。例如,`jpnevulator --ascii --timing-print --tty /dev/ttyUSB0:mySerial --read` 可以读取 `/dev/ttyUSB0` 上的数据。 3. **Cutecom** Cutecom 提供了一个简单的 GUI 来管理串口连接设置,适合初学者快速上手。它的主要特点是易于安装和使用,同时具备基本的日志记录能力。 4. **Picocom** Picocom 类似于 minicom,但它更加简洁小巧,专注于提供基础的功能集而无需复杂的配置过程。对于只需要简单交互场景下的开发者来说是一个错的选择。 5. **Screen** Screen 命令也可以作为临时解决方案来访问TTY设备文件(如/dev/pts/*),从而实现基本级别的串行通讯需求。运行 `screen /dev/ttyS0 9600` 将打开指定波特率为9600bps的目标端口进行会话控制[^2]。 #### 发送 Hex 数据示例 如果要从命令行直接向某个已知路径名表示物理硬件接口(比如 USB 转 RS232 设备映射成虚拟字符型特殊文件)写入二进制形式的消息体,则可借助 echo 结合 od 或者 printf 函数完成编码转换工作后再传递给目标句柄对象;另外还可以考虑利用专门设计好的应用程序库函数封装后的API调用方式简化流程处理逻辑复杂度较高的情况。 ```bash echo -e "\x48\x65\x6c\x6c\x6f" > /dev/ttyUSB0 ``` 上述例子展示了如何将字符串 "Hello"(其对应的ASCII码分别是72(H),101(e),108(l),108(l),111(o))转化为十六进位数列并通过重定向符输入到指定位置处。 #### Python 实现方案 除了依赖外部实用程序之外,在某些场合下可能更倾向于采用编程手段达成目的——这里给出一段基于 PySerial 库的小脚本片段演示怎样构建起双向交流机制: ```python import serial ser = serial.Serial('/dev/ttyUSB0', baudrate=9600, timeout=1) if ser.isOpen(): try: message = b'\x48\x65\x6C\x6C\x6F' # 'Hello' bytes_sent = ser.write(message) print(f"{bytes_sent} byte(s) sent.") response = ser.read(size=len(message)) if response != None and len(response)>0 : print("Response:",response.decode()) except Exception as e: print("Error occurred:", str(e)) finally: ser.close() ``` 该代码段首先初始化 Serial 对象实例关联至实际存在的串行链路资源节点地址(/dev/ttyUSB0),接着尝试依次执行写出请求动作与等待回应解析展示环节直至结束清理释放占用状态为止。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值