查看: 685|回复: 0

[评测分享] 【米尔-STM32MP135入门级开发板测评】 2.RS485通讯测试

[复制链接]
  • TA的每日心情
    奋斗
    2024-4-19 21:11
  • 签到天数: 66 天

    连续签到: 1 天

    [LV.6]常住居民II

    发表于 2023-9-29 18:13:14 | 显示全部楼层 |阅读模式
    分享到:
    1.概述
    RS485是一种串行通信标准,广泛应用于工业控制、自动化系统、建筑物自动化和数据采集等领域。它的名称"RS485"代表"Recommended Standard 485",这个标准定义了一种物理层通信协议,旨在克服早期串行通信标准的一些限制。
    RS485协议的主要特点之一是它使用差分信号传输数据。这意味着它同时传输正极性信号和负极性信号,从而降低了外部电磁干扰对通信的影响。这使得RS485非常适合于噪声较高的工业环境,以及需要长距离通信的应用。RS485支持半双工或全双工通信模式,允许设备在发送和接收数据之间切换,或同时进行双向通信。
    另一个RS485的关键特点是多点通信。多个设备可以连接到同一RS485总线上,每个设备都有一个唯一的地址。当一个设备发送数据时,其他设备可以选择是否接收该数据,从而实现了多点到多点的通信。这种特性使RS485成为分布式控制系统的理想选择,例如工业自动化中的传感器、PLC、仪表和计算机等设备可以通过RS485进行通信

    2.硬件连接
    如下所示为板子的外设接口示意图,引出了RS485引脚,通过USB转RS485与电脑连接。
    1.png

    电路硬件设计,使用的是UART7作为RS485的接口,对应是PE8和PE10,如下所示:
    2.png

    3.软件设计
    #include<stdio.h>
    #include<termios.h>
    #include<linux/ioctl.h>
    #include<linux/serial.h>
    #include<asm-generic/ioctls.h> /* TIOCGRS485 + TIOCSRS485 ioctl definitions */
    #include<unistd.h>
    #include<errno.h>
    #include<fcntl.h>
    #include<sys/types.h>
    #include<sys/stat.h>
    #include<string.h>
    #include<stdlib.h>
    #include<getopt.h>
    typedef enum
    {
          DISABLE = 0,
          ENABLE
    }RS485_ENABLE_t;
    int set_port(intfd, int nSpeed, int nBits, char nEvent, int nStop)
    {
          struct termios newtio, oldtio;
          memset(&oldtio, 0, sizeof(oldtio));
          /* save the old serial port configuration*/
          if (tcgetattr(fd, &oldtio) != 0)
          {
                 perror("set_port/tcgetattr");
                 return -1;
          }
          memset(&newtio, 0, sizeof(newtio));
          /* ignore modem control lines and enablereceiver */
          newtio.c_cflag = newtio.c_cflag |= CLOCAL| CREAD;
          newtio.c_cflag &= ~CSIZE;
          /* set character size */
          switch (nBits)
          {
          case 8:
                 newtio.c_cflag |= CS8;
                 break;
          case 7:
                 newtio.c_cflag |= CS7;
                 break;
          case 6:
                 newtio.c_cflag |= CS6;
                 break;
          case 5:
                 newtio.c_cflag |= CS5;
                 break;
          default:
                 newtio.c_cflag |= CS8;
                 break;
          }
          /* set the parity */
          switch (nEvent)
          {
          case 'o':
          case 'O':
                 newtio.c_cflag |= PARENB;
                 newtio.c_cflag |= PARODD;
                 newtio.c_iflag |= (INPCK | ISTRIP);
                 break;
          case 'e':
          case 'E':
                 newtio.c_cflag |= PARENB;
                 newtio.c_cflag &= ~PARODD;
                 newtio.c_iflag |= (INPCK | ISTRIP);
                 break;
          case 'n':
          case 'N':
                 newtio.c_cflag &= ~PARENB;
                 break;
          default:
                 newtio.c_cflag &= ~PARENB;
                 break;
          }
          /* set the stop bits */
          switch (nStop)
          {
          case 1:
                 newtio.c_cflag &= ~CSTOPB;
                 break;
          case 2:
                 newtio.c_cflag |= CSTOPB;
                 break;
          default:
                 newtio.c_cflag &= ~CSTOPB;
                 break;
          }
          /* set output and input baud rate */
          switch (nSpeed)
          {
          case 0:
                 cfsetospeed(&newtio, B0);
                 cfsetispeed(&newtio, B0);
                 break;
          case 50:
                 cfsetospeed(&newtio, B50);
                 cfsetispeed(&newtio, B50);
                 break;
          case 75:
                 cfsetospeed(&newtio, B75);
                 cfsetispeed(&newtio, B75);
                 break;
          case 110:
                 cfsetospeed(&newtio, B110);
                 cfsetispeed(&newtio, B110);
                 break;
          case 134:
                 cfsetospeed(&newtio, B134);
                 cfsetispeed(&newtio, B134);
                 break;
          case 150:
                 cfsetospeed(&newtio, B150);
                 cfsetispeed(&newtio, B150);
                 break;
          case 200:
                 cfsetospeed(&newtio, B200);
                 cfsetispeed(&newtio, B200);
                 break;
          case 300:
                 cfsetospeed(&newtio, B300);
                 cfsetispeed(&newtio, B300);
                 break;
          case 600:
                 cfsetospeed(&newtio, B600);
                 cfsetispeed(&newtio, B600);
                 break;
          case 1200:
                 cfsetospeed(&newtio, B1200);
                 cfsetispeed(&newtio, B1200);
                 break;
          case 1800:
                 cfsetospeed(&newtio, B1800);
                 cfsetispeed(&newtio, B1800);
                 break;
          case 2400:
                 cfsetospeed(&newtio, B2400);
                 cfsetispeed(&newtio, B2400);
                 break;
          case 4800:
                 cfsetospeed(&newtio, B4800);
                 cfsetispeed(&newtio, B4800);
                 break;
          case 9600:
                 cfsetospeed(&newtio, B9600);
                 cfsetispeed(&newtio, B9600);
                 break;
          case 19200:
                 cfsetospeed(&newtio, B19200);
                 cfsetispeed(&newtio, B19200);
                 break;
          case 38400:
                 cfsetospeed(&newtio, B38400);
                 cfsetispeed(&newtio, B38400);
                 break;
          case 57600:
                 cfsetospeed(&newtio, B57600);
                 cfsetispeed(&newtio, B57600);
                 break;
          case 115200:
                 cfsetospeed(&newtio, B115200);
                 cfsetispeed(&newtio, B115200);
                 break;
          case 230400:
                 cfsetospeed(&newtio, B230400);
                 cfsetispeed(&newtio, B230400);
                 break;
          default:
                 cfsetospeed(&newtio, B115200);
                 cfsetispeed(&newtio, B115200);
                 break;
          }
          /* set timeout in deciseconds for non-canonicalread */
          newtio.c_cc[VTIME] = 0;
          /* set minimum number of characters fornon-canonical read */
          newtio.c_cc[VMIN] = 0;
          /* flushes data received but not read */
          tcflush(fd, TCIFLUSH);
          /* set the parameters associated with theterminal from
                 thetermios structure and the change occurs immediately */
          if ((tcsetattr(fd, TCSANOW, &newtio))!= 0)
          {
                 perror("set_port/tcsetattr");
                 return -1;
          }
          return 0;
    }
    /**
    * @brief: open serial port
    * @Param: dir: serial device path
    */
    intopen_port(char *dir)
    {
          int fd;
          fd = open(dir, O_RDWR);
          if (fd < 0)
          {
                 perror("open_port");
          }
          return fd;
    }

    void print_usage(FILE*stream, int exit_code)
    {
          fprintf(stream, "Usage: option [dev... ] \n");
          fprintf(stream,
                        "\t-h  --help    Display this usage information.\n"
                        "\t-d  --device  The device ttyS[0-3] or ttySCMA[0-1]\n"
                        "\t-b  --baudrate Set the baud rate you canselect\n"
                        "\t               [230400, 115200, 57600, 38400,19200, 9600, 4800, 2400, 1200, 300]\n"
                        "\t-s  --string  Write the device data\n"
                        "\t-e  --1 or 0  Write 1 to enable the rs485_mode(only at atmel)\n");
          exit(exit_code);
    }
    /* PC6 forenable*/
    voidrs485_enable_ya157c(void)
    {
          system("echo 377 >sys/class/gpio/export");
          system("echo out >/sys/class/gpio/P2_1/direction");
          system("echo 1 >/sys/class/gpio/P2_1/value");
    }
    intrs485_enable(const int fd, const RS485_ENABLE_t enable)
    {
          struct serial_rs485 rs485conf;
          int res;
          /* Get configure from device */
          res = ioctl(fd, TIOCGRS485,&rs485conf);
          if (res < 0)
          {
                 perror("Ioctl error on getting485 configure:");
                 close(fd);
                 return res;
          }
          /* Set enable/disable to configure */
          if (enable)
          { // Enable rs485 mode
                 rs485conf.flags |=SER_RS485_ENABLED;
          }
          else
          { // Disable rs485 mode
                 rs485conf.flags &=~(SER_RS485_ENABLED);
          }
          rs485conf.delay_rts_before_send =0x00000004;
          /* Set configure to device */
          res = ioctl(fd, TIOCSRS485,&rs485conf);
          if (res < 0)
          {
                 perror("Ioctl error on setting485 configure:");
                 close(fd);
          }
          return res;
    }
    intchange_bit_rs485(int fd, int value)
    {
          struct serial_rs485 rs485conf;
          int res;
          /* Get configure from device */
          res = ioctl(fd, TIOCGRS485,&rs485conf);
          if (res < 0)
          {
                 perror("Ioctl error on getting485 configure:");
                 close(fd);
                 return res;
          }
          /*rs485 send - recv*/
          if (value == 1)
                 rs485conf.flags |=SER_RS485_RTS_AFTER_SEND;
          else if (value == 0)
                 rs485conf.flags &=~SER_RS485_RTS_AFTER_SEND;
          else
                 ;
          /* Set configure to device */
          res = ioctl(fd, TIOCSRS485,&rs485conf);
          if (res < 0)
          {
                 perror("Ioctl error on setting485 configure:");
                 close(fd);
          }
          return res;
    }
    int main(intargc, char *argv[])
    {
          char *write_buf = "MYiR UARTTEST";
          char read_buf[100];
          int fd, i, len, nread, r;
          pid_t pid;
          int next_option;
          struct termios oldtio;
          int speed;
          char *device;
          int spee_flag = 0, device_flag = 0;
          const char *const short_options ="hd:s:b:e:";
          unsigned int ffl_cnt = 0;
          const struct option long_options[] = {
                 {"help", 0, NULL, 'h'},
                 {"device", 1, NULL, 'd'},
                 {"string", 1, NULL, 's'},
                 {"baudrate", 1, NULL,'b'},
                 {NULL, 0, NULL, 0}};
          if (argc < 2)
          {
                 print_usage(stdout, 0);
                 exit(0);
          }
          while (1)
          {
                 next_option = getopt_long(argc,argv, short_options, long_options, NULL);
                 if (next_option < 0)
                        break;
                 switch (next_option)
                 {
                 case 'h':
                        print_usage(stdout, 0);
                        break;
                 case 'd':
                        device = optarg;
                        device_flag = 1;
                        break;
                 case 'b':
                        speed = atoi(optarg);
                        spee_flag = 1;
                        break;
                 case 's':
                        write_buf = optarg;
                        break;
                 case 'e':
                        r = atoi(optarg);
                        break;
                 case '?':
                        print_usage(stderr, 1);
                        break;
                 default:
                        abort();
                 }
          }
          if ((!device_flag) || (!spee_flag))
          {
                 print_usage(stderr, 1);
                 exit(0);
          }
          /* open serial port */
          fd = open_port(device);
          if (fd < 0)
          {
                 perror("open failed");
                 return -1;
          }
          if (r)
          {
                 rs485_enable_ya157c();
                 // rs485_enable(fd,ENABLE);
          }
          /* set serial port */
          i = set_port(fd, speed, 8, 'N', 1);
          if (i < 0)
          {
                 perror("set_portfailed");
                 return -1;
          }
          // send 4
          write(fd, write_buf, strlen(write_buf));
          write(fd, write_buf, strlen(write_buf));
          write(fd, write_buf, strlen(write_buf));
          write(fd, write_buf, strlen(write_buf));
          usleep(40000); // 40ms
          change_bit_rs485(fd, 0); // recv mode
                                                     //          usleep(500000);
          while (1)
          {
                 nread = read(fd, read_buf,sizeof(read_buf));
                 if (nread > 0)
                 {
                        printf("RECV[%3d]:", nread);
                        for (i = 0; i < nread;i++)
                               printf("0x%02x", read_buf);
                        printf("\n");
                        // send
                        write(fd, write_buf,strlen(write_buf));
                        usleep(40000);                    // 40ms
                        change_bit_rs485(fd, 0); //recv mode
                 }
                 usleep(1000);
          }
          /* restore the old configuration */
          tcsetattr(fd, TCSANOW, &oldtio);
          close(fd);
          return 0;
    }

    4.通信测试
    电脑使用上位机通过USB转RS485与开发板通信,通信配置与开发板配置保持一致。
    3.png

    开发板RS485参数配置如下所示:
    4.png
    通过上位机发送的数据,开发板将上位机发送的数据打印出来,如下所示:数据接收正确
    5.png

    回复

    使用道具 举报

    您需要登录后才可以回帖 注册/登录

    本版积分规则

    关闭

    站长推荐上一条 /3 下一条

    手机版|小黑屋|与非网

    GMT+8, 2024-5-20 16:10 , Processed in 0.115526 second(s), 17 queries , MemCache On.

    ICP经营许可证 苏B2-20140176  苏ICP备14012660号-2   苏州灵动帧格网络科技有限公司 版权所有.

    苏公网安备 32059002001037号

    Powered by Discuz! X3.4

    Copyright © 2001-2024, Tencent Cloud.