回答

收藏

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

#板卡评测 #板卡评测 1407 人阅读 | 0 人回复 | 2023-09-29

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

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

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

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与开发板通信,通信配置与开发板配置保持一致。

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

分享到:
回复

使用道具 举报

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

本版积分规则

关闭

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