uart3用作485通信,按照视频文档配置485,但是实验下来只能接收,不能发送;改了设备树也不行

#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <errno.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <termios.h>
#include <stdlib.h>
#include <linux/serial.h>

/* 用到这2个ioctl: TIOCGRS485, TIOCSRS485 */
#include <sys/ioctl.h>

/* set_opt(fd,115200,8,‘N’,1) */
int set_opt(int fd,int nSpeed, int nBits, char nEvent, int nStop)
{
struct termios newtio,oldtio;

if ( tcgetattr( fd,&oldtio) != 0) { 
	perror("SetupSerial 1");
	return -1;
}

bzero( &newtio, sizeof( newtio ) );
newtio.c_cflag |= CLOCAL | CREAD; 
newtio.c_cflag &= ~CSIZE; 

newtio.c_lflag  &= ~(ICANON | ECHO | ECHOE | ISIG);  /*Input*/
newtio.c_oflag  &= ~OPOST;   /*Output*/

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 115200:
	cfsetispeed(&newtio, B115200);
	cfsetospeed(&newtio, B115200);
break;
default:
	cfsetispeed(&newtio, B9600);
	cfsetospeed(&newtio, B9600);
break;
}

if( nStop == 1 )
	newtio.c_cflag &= ~CSTOPB;
else if ( nStop == 2 )
	newtio.c_cflag |= CSTOPB;

newtio.c_cc[VMIN]  = 1;  /* 读数据时的最小字节数: 没读到这些数据我就不返回! */
newtio.c_cc[VTIME] = 0; /* 等待第1个数据的时间: 
                         * 比如VMIN设为10表示至少读到10个数据才返回,
                         * 但是没有数据总不能一直等吧? 可以设置VTIME(单位是10秒)
                         * 假设VTIME=1,表示: 
                         *    10秒内一个数据都没有的话就返回
                         *    如果10秒内至少读到了1个字节,那就继续等待,完全读到VMIN个数据再返回
                         */

tcflush(fd,TCIFLUSH);

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

}

int open_port(char *com)
{
int fd;
struct serial_rs485 rs485conf;
//fd = open(com, O_RDWR|O_NOCTTY|O_NDELAY);
fd = open(com, O_RDWR|O_NOCTTY);
if (-1 == fd){
return(-1);
}

/* 读取rs485conf */
if (ioctl (fd, TIOCGRS485, &rs485conf) < 0) {
/* 处理错误 */
}

/* 使能RS485模式 */
rs485conf.flags |= SER_RS485_ENABLED;

/* 当发送数据时, RTS为1 */
rs485conf.flags |= SER_RS485_RTS_ON_SEND;

/* 或者: 当发送数据时, RTS为0 */
//rs485conf.flags &= ~(SER_RS485_RTS_ON_SEND);

/* 当发送完数据后, RTS为1 */
rs485conf.flags |= SER_RS485_RTS_AFTER_SEND;

/* 或者: 当发送完数据后, RTS为0 */
//rs485conf.flags &= ~(SER_RS485_RTS_AFTER_SEND);

/* 还可以设置: 
 * 发送数据之前先设置RTS信号, 等待一会再发送数据
 * 等多久? delay_rts_before_send(单位ms)
 */
rs485conf.delay_rts_before_send = 0X00000004;

/* 还可以设置: 
 * 发送数据之后, 等待一会再清除RTS信号
 * 等多久? delay_rts_after_send(单位ms)
*/
rs485conf.delay_rts_after_send = 0X00000004;

/* 如果想在发送RS485数据的同时也接收数据, 还可以这样设置 */
rs485conf.flags |= SER_RS485_RX_DURING_TX;

if (ioctl (fd, TIOCSRS485, &rs485conf) < 0) {
/* 处理错误 */
}

/* 使用read()和write()就可以读、写数据了 */

/* 关闭设备 */

// if (close (fd) < 0) {
/* 处理错误 */
// }

  if(fcntl(fd, F_SETFL, 0)<0) /* 设置串口为阻塞状态*/
  {
		printf("fcntl failed!\n");
		return -1;
  }

  return fd;

}

/*

  • ./serial_send_recv
    */
    int main(int argc, char **argv)
    {
    int fd;
    int iRet;
    char c;

    /* 1. open */

    /* 2. setup

    • 115200,8N1
    • RAW mode
    • return data immediately
      */

    /* 3. write and read */

    if (argc != 2)
    {
    printf(“Usage: \n”);
    printf("%s </dev/ttySAC1 or other>\n", argv[0]);
    return -1;
    }

    fd = open_port(argv[1]);
    if (fd < 0)
    {
    printf(“open %s err!\n”, argv[1]);
    return -1;
    }

    iRet = set_opt(fd, 115200, 8, ‘N’, 1);
    if (iRet)
    {
    printf(“set port err!\n”);
    return -1;
    }

    //printf(“Enter a char: “);
    while (1)
    {
    //scanf(”%c”, &c);
    //iRet = write(fd, &c, 1);
    iRet = read(fd, &c, 1);
    if (iRet == 1)
    {
    printf(“get: %02x %c\n”, c, c);
    iRet = write(fd, &c, 1);
    }
    else
    printf(“can not get data\n”);
    }

    return 0;
    }


控制485有个方向控制引脚,搞了没

open_port函数中软件配置了,设备树种也有,

我回看了RS485的视频,竟然没有带大家做实验。
这是我的错,
我先帮你解决这个问题,再补录视频。
设备树里,你把“rts-gpio = <&gpio5 0 GPIO_ATIVE_HIGH>;”加上去,
更新设备树后,
执行: cat /sys/kernel/debug/gpio,
可以看到:
gpio-128 ( |rts ) out lo

然后就可以测试了。

感谢韦老师亲自技术支持,解决如下

  1. 修改设备树
    &uart3 {
    pinctrl-names = “default”;
    pinctrl-0 = <&pinctrl_uart3
    &pinctrl_485_ctl>;
    //pinctrl-0 = <&pinctrl_uart3>;
    //fsl,rs485-gpio-txen = <&gpio5 0 GPIO_ACTIVE_HIGH>;
    rts-gpio = <&gpio5 0 GPIO_ACTIVE_LOW>;
    uart-has-rtscts;
    rs485-rts-active-high;
    //rs485-rts-active-high;
    rs485-rx-during-tx;
    rs485-rts-delay = <100 100>;
    linux,rs485-enabled-at-boot-time;
    status = “okay”;
    };
    2.修改函数 int rs485_enable(const int fd, const int enable)
    增加下面两句,
    /* 当发送数据时, RTS为1 */
    rs485conf.flags |= SER_RS485_RTS_ON_SEND;

     /* 当发送完数据后, RTS为0 */
     rs485conf.flags &= ~(SER_RS485_RTS_AFTER_SEND);
    

至此,实验后,收发数据都OK了