Makefile

    1. SOURCE = $(wildcard *.c)
    2. TARGETS = $(patsubst %.c, %, $(SOURCE))
    3. CC = arm-linux-gcc
    4. #CFLAGS = -Wall
    5. LIBS = -lpthread
    6. all:$(TARGETS)
    7. $(TARGETS):%:%.c
    8. $(CC) $< -o $@ $(LIBS)
    9. .PHONY:clean all
    10. clean:
    11. -rm -rf $(TARGETS)

    源代码rs485_test.c

    #include     <stdio.h>
    #include     <stdlib.h>
    #include     <unistd.h> 
    #include     <sys/types.h>
    #include     <sys/stat.h> 
    #include     <fcntl.h> 
    #include     <termios.h>  
    #include     <errno.h>
    #include     <string.h>
    #include     <signal.h>
    #include    <pthread.h>
    #include <linux/serial.h>
    
    
    
    #define FALSE 0
    #define TRUE  1
    
    /* Driver-specific ioctls: ...\linux-3.10.x\include\uapi\asm-generic\ioctls.h */
    #define TIOCGRS485      0x542E
    #define TIOCSRS485      0x542F
    
    int fd;
    
    pthread_t threads[10];
    
    char buff[95];
    
    static struct termios newtios,oldtios; /*termianal settings */
    static int saved_portfd=-1;            /*serial port fd */
    
    
    /* Test GCC version, this structure is consistent in GCC 4.8, thus no need to overwrite */
    //printf("%s, %s\n", __GNUC__, __GNUC_MINOR__);
    #if (__GNUC__ == 4 && __GNUC_MINOR__ == 3)
    
    struct my_serial_rs485
    {
            unsigned long    flags;            /* RS485 feature flags */
            #define SER_RS485_ENABLED        (1 << 0)    /* If enabled */
            #define SER_RS485_RTS_ON_SEND        (1 << 1)    /* Logical level for RTS pin when sending */
            #define SER_RS485_RTS_AFTER_SEND    (1 << 2)    /* Logical level for RTS pin after sent*/
            #define SER_RS485_RX_DURING_TX        (1 << 4)
            unsigned long    delay_rts_before_send;    /* Delay before send (milliseconds) */
            unsigned long    delay_rts_after_send;    /* Delay after send (milliseconds) */
            unsigned long    padding[5];        /* Memory is cheap, new structs are a royal PITA .. */
    };
    
    #endif
    
    
    static void reset_tty_atexit(void)
    {
        if(saved_portfd != -1)
        {
            tcsetattr(saved_portfd,TCSANOW,&oldtios);
        } 
    }
    
    /*cheanup signal handler */
    static void reset_tty_handler(int signal)
    {
        if(saved_portfd != -1)
        {
            tcsetattr(saved_portfd,TCSANOW,&oldtios);
        }
        _exit(EXIT_FAILURE);
    }
    
    static int open_port(const char *portname)
    {
        struct sigaction sa;
        int portfd;
    
        /*open serial port */
        if((portfd = open(portname, O_RDWR |O_NOCTTY, 0)) < 0 )
        {
               printf("open serial port %s fail \n ",portname);
               return portfd;
        }
        return portfd;
        printf("opening serial port:%s\n",portname);
    }
    
    int rs485_set(int portfd,int baude,int c_flow,int bits,char parity,int stop)
    {
        struct termios options;
    
    #if (__GNUC__ == 4 && __GNUC_MINOR__ == 3)
        printf("used my_serial_rs485\n");
        struct my_serial_rs485 rs485conf;
        struct my_serial_rs485 rs485conf_bak;
    #else
        struct serial_rs485 rs485conf;
        struct serial_rs485 rs485conf_bak;
    #endif    
        /*获取终端属性*/
        if(tcgetattr(portfd,&options) < 0)
        {
            perror("tcgetattr error");
            return -1;
        }
    
    
        /*设置输入输出波特率,两者保持一致*/
        switch(baude)
        {
            case 4800:
                cfsetispeed(&options,B4800);
                cfsetospeed(&options,B4800);
                break;
            case 9600:
                cfsetispeed(&options,B9600);
                cfsetospeed(&options,B9600);
                break;
            case 19200:
                cfsetispeed(&options,B19200);
                cfsetospeed(&options,B19200);
                break;
            case 38400:
                cfsetispeed(&options,B38400);
                cfsetospeed(&options,B38400);
                break;
            case 115200:
                    cfsetispeed(&options,B115200);
                    cfsetospeed(&options,B115200);
                    break;
            default:
                fprintf(stderr,"Unkown baude!\n");
                return -1;
        }
    
        /*设置控制模式*/
        options.c_cflag |= CLOCAL;//保证程序不占用串口
        options.c_cflag |= CREAD;//保证程序可以从串口中读取数据,表启用字符接收器,目的是能够从串口中读取输入的数据
    
        /*设置数据流控制*/
        switch(c_flow)
        {
            case 0://不进行流控制
                options.c_cflag &= ~CRTSCTS;
                break;
            case 1://进行硬件流控制
                options.c_cflag |= CRTSCTS;
                break;
            case 2://进行软件流控制
                options.c_cflag |= IXON|IXOFF|IXANY;
                break;
            default:
                fprintf(stderr,"Unkown c_flow!\n");
                return -1;
        }
    
        /*设置数据位*/
        switch(bits)
        {
            case 5:
                options.c_cflag &= ~CSIZE;//屏蔽其它标志位
                options.c_cflag |= CS5;
                break;
            case 6:
                options.c_cflag &= ~CSIZE;//屏蔽其它标志位
                options.c_cflag |= CS6;
                break;
            case 7:
                options.c_cflag &= ~CSIZE;//屏蔽其它标志位
                options.c_cflag |= CS7;
                break;
            case 8:
                options.c_cflag &= ~CSIZE;//屏蔽其它标志位
                options.c_cflag |= CS8;
                break;
            default:
                fprintf(stderr,"Unkown bits!\n");
                return -1;
        }
    
        /*设置校验位*/
        switch(parity)
        {
            /*无奇偶校验位*/
            case 'n':
            case 'N':
                options.c_cflag &= ~PARENB;//PARENB:产生奇偶位,执行奇偶校验
                break;
            /*设为空格,即停止位为2位*/
            case 's':
            case 'S':
                options.c_cflag &= ~PARENB;//PARENB:产生奇偶位,执行奇偶校验
                options.c_cflag &= ~CSTOPB;//CSTOPB:使用两位停止位
                break;
            /*设置奇校验*/
            case 'o':
            case 'O':
                options.c_cflag |= PARENB;//PARENB:产生奇偶位,执行奇偶校验
                options.c_cflag |= PARODD;//PARODD:若设置则为奇校验,否则为偶校验
                options.c_cflag |= INPCK;//INPCK:使奇偶校验起作用
                options.c_cflag |= ISTRIP;//ISTRIP:若设置则有效输入数字被剥离7个字节,否则保留全部8位
                break;
            /*设置偶校验*/
            case 'e':
            case 'E':
                options.c_cflag |= PARENB;//PARENB:产生奇偶位,执行奇偶校验
                options.c_cflag &= ~PARODD;//PARODD:若设置则为奇校验,否则为偶校验
                options.c_cflag |= INPCK;//INPCK:使奇偶校验起作用
                options.c_cflag |= ISTRIP;//ISTRIP:若设置则有效输入数字被剥离7个字节,否则保留全部8位
                break;
            default:
                fprintf(stderr,"Unkown parity!\n");
                return -1;
        }
    
        /*设置停止位*/
        switch(stop)
        {
            case 1:
                options.c_cflag &= ~CSTOPB;//CSTOPB:使用一位停止位
                break;
            case 2:
                options.c_cflag |= CSTOPB;//CSTOPB:使用两位停止位
                break;
            default:
                fprintf(stderr,"Unkown stop!\n");
                return -1;
        }
    
        /*设置输出模式为原始输出*/
        options.c_oflag &= ~(OPOST| ONLCR | OLCUC | OCRNL | ONOCR | ONLRET | OFILL);//OPOST:若设置则按定义的输出处理,否则所有c_oflag失效
    
        /*设置本地模式为原始模式*/
        options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
        /*
         *ICANON:允许规范模式进行输入处理
         *ECHO:允许输入字符的本地回显
         *ECHOE:在接收EPASE时执行Backspace,Space,Backspace组合
         *ISIG:允许信号
         */
    
        /*设置等待时间和最小接受字符*/
        options.c_cc[VTIME] = 0;//可以在select中设置
        options.c_cc[VMIN] = 1;//最少读取一个字符
    
        /*如果发生数据溢出,只接受数据,但是不进行读操作*/
        tcflush(portfd,TCIFLUSH);
    
        /*激活配置*/
        if(tcsetattr(portfd,TCSANOW,&options) < 0)
        {
            perror("tcsetattr failed");
            return -1;
        }
    
        if (ioctl (portfd, TIOCGRS485, &rs485conf) < 0) 
        {
            /* Error handling.*/ 
            printf("ioctl TIOCGRS485 error.\n");
            return -1;
        }
        /* Enable RS485 mode: */
        rs485conf.flags |= SER_RS485_ENABLED;
    
        /* Set logical level for RTS pin equal to 1 when sending: */
        rs485conf.flags |= SER_RS485_RTS_ON_SEND;
        //rs485conf.flags |= SER_RS485_RTS_AFTER_SEND;
    
        /* set logical level for RTS pin equal to 0 after sending: */ 
        rs485conf.flags &= ~(SER_RS485_RTS_AFTER_SEND);
        //rs485conf.flags &= ~(SER_RS485_RTS_ON_SEND);
    
        /* Set rts delay after send, if needed: */
        rs485conf.delay_rts_after_send = 0x80;
    
        if (ioctl (portfd, TIOCSRS485, &rs485conf) < 0)
        {
            /* Error handling.*/ 
            printf("ioctl TIOCSRS485 error.\n");
            return -1;
        }
    
        if (ioctl (portfd, TIOCGRS485, &rs485conf_bak) < 0)
        {
            /* Error handling.*/ 
            printf("ioctl TIOCGRS485 error.\n");
            return -1;
        }
        else
        {
            printf("rs485conf_bak.flags 0x%x.\n", rs485conf_bak.flags);
            printf("rs485conf_bak.delay_rts_before_send 0x%x.\n", rs485conf_bak.delay_rts_before_send);
            printf("rs485conf_bak.delay_rts_after_send 0x%x.\n", rs485conf_bak.delay_rts_after_send);
        }
    
        return portfd;
    }
    
    void * send(void* arg)
    {
        int portfd = (int) arg;
        unsigned int i, j;
        int rev1, rev2;
        char RxBuffer[sizeof(buff)];    
    
        rev1 =0;
        rev2 =0;
    
        printf("send content:%s\n", buff);
        while(rev2 < sizeof(buff))
           {
            rev1 = write(portfd,(buff+rev2),sizeof(buff));
            rev2 += rev1;
           }
        printf("\n send %d byts\n", rev2);
    
    }    
    
    void * receive(void* arg)
    { 
        int portfd = (int) arg;
        unsigned int i, j;
        int rev1, rev2;
        char RxBuffer[sizeof(buff)];
    
    
        rev1 = 0;
        rev2 = 0;
    
        while(rev2 < sizeof(RxBuffer))
        {
            rev1 = read(portfd,(RxBuffer+rev2),sizeof(RxBuffer) - rev2);
            rev2 += rev1;
    
            if(rev1 > 0)
                printf("\n receive %d bytes \n", rev2);
        }
        printf("receive content: %s\n", RxBuffer);
        printf("\n receive %d bytes \n", rev2);
    
    }
    
    /**
    *@breif     main()
    */
    int main(int argc, char **argv)
    {
            const char *tty = NULL;
            unsigned int i;
            int ret;
    
          int baude;
          int c_flow;
          int bits;
          char parity;
          int stop;
    
          if(argc < 1)
            {
                printf("please input /dev/ttySx\n");
            }
          tty = argv[1];
          if( argc < 2)
          {
                printf("format uart_test /dev/ttySx baude stop data_bits parity config_stream\n");
                printf("such as:./uart_test /dev/ttySx 115200 1 8 N 0\n");
                exit(EXIT_FAILURE);
          }
    
            baude  = atoi(argv[2]);            
            stop   = atoi(argv[3]);            
            bits   = atoi(argv[4]);        
            parity = *argv[5];
            c_flow = atoi(argv[6]);
    
            printf("%s\n", tty);
            printf("%d, %d, %d, %c, %d\n", baude, stop, bits, parity, c_flow);
    
        for(i = 0; i < sizeof(buff); i++)
        {
            buff[i] = (i + 0x21);
        }
    
        fd = open_port(tty);
        if (fd < 0)
        {
            printf("open uart error\n");
            return 0;
        }
        ret = rs485_set(fd, baude, c_flow, bits, parity, stop);
        if(ret == -1)
      {
        fprintf(stderr,"rs485_set failed!\n");
        exit(EXIT_FAILURE);
      }
        pthread_create(&threads[0], NULL, send, (void*)(fd));
        pthread_create(&threads[1], NULL, receive, (void*)(fd));
    
        pthread_join(threads[0], NULL);
        pthread_join(threads[1], NULL);
    
        close(fd);
    
      return 0;
    }