RS485 half-duplex test code

/*************************************************************************
	> File Name: serial.c
	> Author: lancz
	> Mail:
	> Created Time: 2019年09月26日 星期四 20时18分14秒
 ************************************************************************/
#include <fcntl.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h> 
#include <unistd.h>
#include <stdint.h>
#include <string.h>
#include <termios.h>
#include <pthread.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/timeb.h>
#include <linux/serial.h>

typedef struct{
  int speed;
  int name;
}SysHalUartSpeedMap_t;

const SysHalUartSpeedMap_t  SysHalUartSpeedMap[] = {
  { B1000000, 1000000 },               
  { B500000,  500000 },               
  { B460800,  460800 },               
  { B230400,  230400 },
  { B115200,  115200 },
  { B38400,   38400 },
  { B19200,   19200 },
  { B9600,    9600 },
  { B4800,    4800 },
  { B2400,    2400 },
  { B1200,    1200 },
};

static void sysHalUartSetSpeed(int fd, int speed)
{
  uint8_t i; 
  struct termios opt;

  if(0 != tcgetattr(fd,&opt)) return;
  for(i = 0; i < sizeof(SysHalUartSpeedMap)/sizeof(SysHalUartSpeedMap[0]); i++){
    if(speed == SysHalUartSpeedMap[i].name){
      tcflush(fd,TCIOFLUSH);

			printf("set speed = %d\n",speed);
      cfsetispeed(&opt,SysHalUartSpeedMap[i].speed);
      cfsetospeed(&opt,SysHalUartSpeedMap[i].speed);
    
      if(0 != tcsetattr(fd,TCSANOW,&opt)){
        printf("tcset attr error \n");
        return ;
      }
      tcflush(fd,TCIOFLUSH);
      break;
    }
  }
}


/**
* @brief:sysHalUartSetParity 
*
* @param: fd
* @param: bits
* @param: stopBit
* @param: parity
*
* @return 
*
* @author:
* @date:2018-05-10
*/
static int sysHalUartSetParity(int fd, int bits, int stopBit, char parity)
{
  struct termios opt;
  if(0 != tcgetattr(fd,&opt)) return -1;

	printf("configure uart, bit = %d,stopbit = %d, parity = %d\n",bits,stopBit,parity);
  /* config bit */
  opt.c_cflag &= ~CSIZE;
  switch(bits){
  case 7:
    opt.c_cflag |= CS7;
    break;
  case 8:
    opt.c_cflag |= CS8;
    break;
  default: 
    printf("Error uart bit size.\n"); return -1;
  }

  /* config parity */
  switch(parity){
    case 'n':
    case 'N':
      opt.c_cflag &= ~PARENB;
      opt.c_iflag &= ~INPCK;
      break;
    case 'o':
    case 'O':
      opt.c_cflag |= (PARODD | PARENB);
      opt.c_iflag |= INPCK;
      break;
    case 'e':
    case 'E':
      opt.c_cflag |= PARENB;
      opt.c_cflag &= ~PARODD;
      opt.c_iflag |= INPCK;
      break;
    case 's':
    case 'S':
      opt.c_cflag &= ~PARENB;
      opt.c_iflag &= ~CSTOPB;
      break;
    default:
      printf("error parity");
      return -1;
  }

  /* config stopbit */
  switch(stopBit){
    case 1:
      opt.c_cflag &= ~CSTOPB;
      break;
    case 2:
      opt.c_cflag |= CSTOPB;
      break;
    default:
      printf("error stop bit config.\n");
      return -1;
  }
  
  opt.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
	opt.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON);
  opt.c_oflag &= ~OPOST;

  tcflush(fd,TCIFLUSH);
  opt.c_cc[VTIME] = 5;
  opt.c_cc[VMIN] = 0;

#if defined(ENABLE_HW_CTS)
	opt.c_cflag |= CRTSCTS;
#endif 
  
  if(0 != tcsetattr(fd, TCSANOW, &opt)){
    printf("Error config uart attr.\n");
    return -1;
  }
  
  return 0;
}

void main(void)
{
  fd_set fds;
  struct timeval tv;
  char temp[512] = {0};
  int fd = open("/dev/ttyS2",O_RDWR | O_NOCTTY | O_NDELAY);
  
  sysHalUartSetSpeed(fd, 9600);
  sysHalUartSetParity(fd, 8, 1,'E');
  
  system("echo 85 > /sys/class/gpio/unexport");
  system("echo 85 > /sys/class/gpio/export");
  system("echo out > /sys/class/gpio/PC21/direction");
  system("echo 0 > /sys/class/gpio/PC21/value");

  tv.tv_sec = 0;
  tv.tv_usec = 5000;
  while(1) {
    FD_ZERO(&fds);
    FD_SET(fd, &fds);
    if (select(fd + 1, &fds, NULL, NULL, &tv) < 0) {
      perror("select error");
    }

    if (FD_ISSET(fd, &fds)) {
      int n = read(fd, temp, sizeof(temp));
      if (n > 0) {
        for (int i = 0; i < n; i++)
          printf("%02X ", temp[i]);
        printf("\n");
      }
    }
  
    system("echo 1 > /sys/class/gpio/PC21/value;sync");
    write(fd, "hello world", 11);
    usleep(11 * 1000 * 8);
    system("echo 0 > /sys/class/gpio/PC21/value;sync");
  }
}

小记:
(1) 当在arm linux 上运行PC端的程序时会报类似编译的错误。
(2) rs485半双工通讯在没有硬件自动控制同步的情况下,需要由应用程序来同步。

You may also like...

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据