测试:
测试源码:

#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<pthread.h>
#include<time.h>
#include<linux/serial.h>
#include<sys/ioctl.h>

#define SEND_SLEEP

#define FALSE  -1  
#define TRUE   0  
#define RS485  0

static char port_name[32];
static char log_name[100];
static int save_log_flag;
static int test_data_len; //测试数据量 M 
static int test_finish = 0;

enum rx_status {
    HEAD1,/*0xFE*/
    HEAD2,/*0xAB*/
    DATA,
    XOR,    
};

static void Sleep(int iSec,int iUsec)
{
    struct timeval tv;
    tv.tv_sec=iSec;
    tv.tv_usec=iUsec;
    select(0,NULL,NULL,NULL,&tv);
}  

int uart_open(char* port)  
{     
    int fd;
    fd = open( port, O_RDWR|O_NOCTTY|O_NDELAY);  
    if (fd < 0)  
    {  
        printf("can't open serial port:%s\n",port);  
        return(FALSE);  
    }  

    if(fcntl(fd, F_SETFL, 0) < 0) 
    {  
        printf("fcntl failed!\n");  
        return(FALSE);  
    } 

    if(0 == isatty(STDIN_FILENO)) 
    {  
        printf("standard input is not a terminal device\n");  
        return(FALSE);  
    } 


    printf("now set rs485 config \n");

#if RS485
    struct serial_rs485 rs485conf;
    memset(&rs485conf,0,sizeof(rs485conf));
    rs485conf.padding[0] = 17;
    rs485conf.delay_rts_after_send = 2000;
    rs485conf.delay_rts_before_send = 2000;
    rs485conf.flags |= SER_RS485_RTS_ON_SEND;
    rs485conf.flags |= SER_RS485_ENABLED;
    ioctl(fd, TIOCSRS485, &rs485conf);

    int ret = ioctl(fd, TIOCSRS485, &rs485conf);
    perror("ioctl");
    printf("ioctrl back:%d\n", ret);

#endif
    return fd;  
}  

void uart_close(int fd)  
{  
    close(fd);  
}  

int uart_set(int fd,int speed,int flow_ctrl,int databits,int stopbits,int parity)  
{       
    int   i;  
    int   status;  
    int   speed_arr[] = { B115200, B19200, B9600, B4800, B2400, B1200, B300};  
    int   name_arr[] = {115200,  19200,  9600,  4800,  2400,  1200,  300};  

    struct termios options;  

    /*tcgetattr(fd,&options)得到与fd指向对象的相关参数,并将它们保存于options,该函数还可以测试配置是否正确,该串口是否可用等。若调用成功,函数返回值为0,若调用失败,函数返回值为-1. 
     */  
    if  ( tcgetattr( fd,&options)  !=  0)  
    {  
        perror("setupSerial 1");      
        return FALSE;   
    }      

    for ( i= 0;  i < sizeof(speed_arr) / sizeof(int);  i++)  
    {  
        if  (speed == name_arr[i])  
        {               
            cfsetispeed(&options, speed_arr[i]);   
            cfsetospeed(&options, speed_arr[i]);    
        }  
    }    

    options.c_cflag |= CLOCAL;  //修改控制模式,保证程序不会占用串口   
    options.c_cflag |= CREAD;   //修改控制模式,使得能够从串口中读取输入数据  

    switch(flow_ctrl)   //设置数据流控制  
    {  

        case 0 :
            options.c_cflag &= ~CRTSCTS;  //不使用流控制  
            options.c_iflag &= ~(IXON | IXOFF | IXANY);            
            break;     

        case 1 : 
            options.c_cflag |= CRTSCTS; //使用硬件流控制  
            break;  
        case 2 :
            options.c_cflag |= IXON | IXOFF | IXANY;//使用软件流控制    
            break;  
    }  


    options.c_cflag &= ~CSIZE;//设置数据位   //屏蔽其他标志位  

    switch (databits)  
    {    
        case 5:  
            options.c_cflag |= CS5;  
            break;  
        case 6:  
            options.c_cflag |= CS6;  
            break;  
        case 7:      
            options.c_cflag |= CS7;  
            break;  
        case 8:      
            options.c_cflag |= CS8;  
            break;    
        default:     
            fprintf(stderr,"Unsupported data size\n");  
            return FALSE;   
    }  

    switch (parity)  //设置校验位  
    {    
        case 'n':  
        case 'N': //无奇偶校验位。  
            options.c_cflag &= ~PARENB;   
            //options.c_iflag &= ~INPCK;      
            break;   
        case 'o':    
        case 'O'://设置为奇校验      
            options.c_cflag |= (PARODD | PARENB);   
            options.c_iflag |= INPCK;               
            break;   
        case 'e':   
        case 'E'://设置为偶校验    
            options.c_cflag |= PARENB;         
            options.c_cflag &= ~PARODD;         
            options.c_iflag |= INPCK;        
            break;  
        case 's':  
        case 'S': //设置为空格   
            options.c_cflag &= ~PARENB;  
            options.c_cflag &= ~CSTOPB;  
            break;   
        default:    
            fprintf(stderr,"Unsupported parity\n");      
            return FALSE;   
    }   

    switch (stopbits)  // 设置停止位   
    {    
        case 1:     
            options.c_cflag &= ~CSTOPB; break;   
        case 2:     
            options.c_cflag |= CSTOPB; break;  
        default:     
            fprintf(stderr,"Unsupported stop bits\n");   
            return FALSE;  
    }  

    options.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP); 

    //修改输出模式,原始数据输出  
    options.c_oflag &= ~OPOST;  

    options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);


    //设置等待时间和最小接收字符  
    options.c_cc[VTIME] = 1; /* 读取一个字符等待1*(1/10)s */    
    options.c_cc[VMIN] = 0; /* 读取字符的最少个数为1 */  

    //如果发生数据溢出,接收数据,但是不再读取 刷新收到的数据但是不读  
    // tcflush(fd,TCIFLUSH);  

    //激活配置 (将修改后的termios数据设置到串口中)  
    if (tcsetattr(fd,TCSANOW,&options) != 0)    
    {  
        perror("com set error!\n");    
        return FALSE;   
    }  
    return TRUE;   
}

int uart_init(int fd, int speed,int flow_ctrl,int databits,int stopbits,int parity)  
{  
    int err;  

    if (uart_set(fd,speed,flow_ctrl,databits,stopbits,parity) == FALSE)    //设置串口数据帧格式  
    {                                                           
        return FALSE;  
    }  else  {  
        return  TRUE;  
    }  
}  


int uart_recv(int fd, char *rcv_buf,int data_len)  
{  
    int len,fs_sel;  
    fd_set fs_read;  

    struct timeval time;  

    FD_ZERO(&fs_read);  
    FD_SET(fd,&fs_read);  

    time.tv_sec = 10;  
    time.tv_usec = 0;  

    //使用select实现串口的多路通信  
    fs_sel = select(fd+1,&fs_read,NULL,NULL,&time);  
    if(fs_sel)  
    {  
        len = read(fd,rcv_buf,data_len);
        return len;  
    }   else  {
        return FALSE;  
    }       
}


int uart_send(int fd, char *send_buf,int data_len)  
{  
    int len = 0;  

    len = write(fd,send_buf,data_len);  
    if (len == data_len )  
    {  
        return len;  
    }  else {                  
        tcflush(fd,TCOFLUSH);  
        return FALSE;  
    }     
}  

void getNowTime(char *cur_time)
{
    struct timespec time;

    clock_gettime(CLOCK_REALTIME, &time);  //获取相对于1970到现在的秒数
    struct tm nowTime;
    localtime_r(&time.tv_sec, &nowTime);    

    sprintf(cur_time, "%04d%02d%02d%02d:%02d:%02d", nowTime.tm_year + 1900, nowTime.tm_mon+1, nowTime.tm_mday, 
            nowTime.tm_hour, nowTime.tm_min, nowTime.tm_sec);    
}

static void * uart_tx_pthread(void *arg)
{
    int ret;
    char ch = 1;
    int count = 0;
    int nM = 0;
    sleep(3);
    while(1){
        ret = uart_send(*(int*)arg, &ch, 1);
        if (ret == 1){
            printf("**send %02x\n", ch);
            if (!(++count % 1048576)){
                printf("send %dM data\n", ++nM);
                if (!--test_data_len){
                    printf("***************** tx finish *****************\n");
                    pthread_exit(NULL);
                }
            }
            //printf("tx: %02x\n", ch);

            //usleep(10000);
            sleep(1);
            ++ch;
        }else{
            printf("tx error\n");
        }
    }
}

/*head(0xfe+0xab) + data(1(0-0xff)+6(random)) + xor*/

static void * uart_rx_pthread(void *arg)
{    
    char ch;
    int len;
    char pre_ch = 0;
    int count;
    char logstr[128];
    int nM = 0;
    while (1) {        
        len = uart_recv(*(int*)arg, &ch, 1); 
        if(len == 1)  
        {
            printf("rx:0x%02x\n", ch);
            if (!(++count % 1048576)){
                printf("*********************** recv %dM data **********************\n", ++nM);
            }
        } else {
            printf("%s:rx 10s timeout!\n",port_name);
            //sprintf(logstr,"echo \"recv %dByte\" >> %s", count, log_name);            
            //system(logstr);    
            //pthread_exit(NULL);
        }
    }
}

int main(int argc, char **argv)  
{
    int fd;
    int err;
    int baud;
    int databit;
    int stopbit;
    char parity;

    printf("usage: ./rs232_test /dev/ttyS1 115200 8 1 N ./uart1.log 2M\n");
    printf("格式 :  程序 设备节点 波特率 数据位 停止位 校验 日志 测试发送数据量\n");
    printf("波特率:300 1200 2400 4800 9600 19200 115200\n");
    printf("数据位: 7 8\n");
    printf("停止位: 1 2\n");
    printf("校验:   N O E S\n");
    if (argc != 8){
        return -1;
    }

    fd = uart_open(argv[1]); 
    if (fd < 0) {
        printf("open %s fail!",argv[1]);
        return fd;
    }


    baud = atoi(argv[2]);
    databit = atoi(argv[3]);
    stopbit = atoi(argv[4]);
    parity = argv[5][0];
    strncpy(log_name, argv[6], 100);
    test_data_len = atoi(argv[7]);

    printf("baud:%d  databit:%d  stopbit:%d  parity:%c log_name:%s  test_data_len:%dM\n", baud, databit, stopbit, parity, log_name, test_data_len);

    err = uart_init(fd,baud,0,databit, stopbit, parity);  

    //create two pthread, one send , another recv
    pthread_t pt1, pt2;

    if (pthread_create(&pt1, NULL, uart_rx_pthread, (void *)&fd) == -1){
        printf("pthread_create failed\n");
        return -1;
    }

    if (pthread_create(&pt2, NULL, uart_tx_pthread, (void *)&fd) == -1){
        printf("pthread_create failed\n");
        return -1;
    }

    sleep(1);

    if (pthread_join(pt1, NULL))                  
    {
        printf("thread is not exit...\n");
        return -2;
    }

    if (pthread_join(pt2, NULL))                  
    {
        printf("thread is not exit...\n");
        return -2;
    }    


    return 0;
}

将源码拷贝到Ubuntu,下进行编译,生成执行文件uart_test。

#arm-linux-gnueabihf-gcc uart_test.c -o uart_test -lpthread

使用跳线帽短接开发板UART1的TX-RX。

1.把编译出来的可执行文件拷贝到开发板


可以看到能正常收发数据。

文档更新时间: 2022-06-23 16:27   作者:Aeeditor