Linux 串口调试软件,UNIX环境串口调试软件。支持设置串口特征字、波特率和奇偶校验位,支持输入报文和拷贝报文进行发送,发送后等待接收,直到10秒超时;支持接收模式,一直接收和打印报文

C/C++ 同时被 3 个专栏收录
10 篇文章 0 订阅
7 篇文章 0 订阅
3 篇文章 0 订阅
/* Linux 串口调试软件,UNIX环境串口调试软件 
   支持设置串口特征字、波特率和奇偶校验位,支持输入报文和拷贝报文进行发送,
   发送后等待接收,直到10秒超时;支持接收模式,一直接收和打印报文 */
#include<stdio.h>      /*标准输入输出定义*/  
#include<stdlib.h>     /*标准函数库定义*/  
#include<unistd.h>     /*Unix 标准函数定义*/  
#include<sys/types.h>   
#include<sys/stat.h>     
#include<fcntl.h>      /*文件控制定义*/  
#include<termios.h>    /*PPSIX 终端控制定义*/  
#include<errno.h>      /*错误号定义*/  
#include<string.h>  

// 宏定义  
#define FALSE  0  
#define TRUE   1 
#define BUFF_SIZE 4200

typedef unsigned char uint8;
typedef unsigned int uint32;
   
/*******************************************************************
* 名称:        COM_Open
* 功能:        打开串口并返回串口设备文件描述
* 入口参数:    fd    :文件描述符     port :串口号(ttyS0,ttyS1,ttyS2)
* 出口参数:    正确返回为1,错误返回为0
*******************************************************************/  
int COM_Open(int fd,char* port)  
{  
    fd = open( port, O_RDWR|O_NOCTTY|O_NDELAY);  
    if (FALSE == fd)  
    {  
        perror("Can't Open Serial Port");  
        return(FALSE);  
    }  
    //恢复串口为阻塞状态                                 
    if(fcntl(fd, F_SETFL, 0) < 0)  
    {  
        printf("fcntl failed!\n");  
        return(FALSE);  
    }       
    else  
    {  
        printf("fcntl=%d\n",fcntl(fd, F_SETFL,0));  
    }  
    //测试是否为终端设备      
    if(0 == isatty(STDIN_FILENO))  
    {  
        printf("standard input is not a terminal device\n");  
        return(FALSE);  
    }  
    else  
    {
        printf("isatty success!\n");  
    }                
    printf("fd=%d\n",fd);
    return fd;  
}

/*******************************************************************
* 名称:         COM_Close
* 功能:         关闭串口并返回串口设备文件描述
* 入口参数:    fd    :文件描述符     port :串口号(ttyS0,ttyS1,ttyS2)
* 出口参数:     void
*******************************************************************/  
void COM_Close(int fd)  
{  
    close(fd);  
}  
   
/*******************************************************************
* 名称:        COM_Set
* 功能:         设置串口数据位,停止位和效验位
* 入口参数:    fd        串口文件描述符
*                speed     串口速度
*               flow_ctrl   数据流控制
*                  databits   数据位   取值为 7 或者8
*                  stopbits   停止位   取值为 1 或者2
*                parity     效验类型 取值为N,E,O,,S
*出口参数:      正确返回为1,错误返回为0
*******************************************************************/  
int COM_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;  
            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_oflag &= ~OPOST;  
    
    options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);  
    //options.c_lflag &= ~(ISIG | ICANON);  
     
    //设置等待时间和最小接收字符  
    options.c_cc[VTIME] = 1; /* 读取一个字符等待1*(1/10)s */    
    options.c_cc[VMIN] = 1; /* 读取字符的最少个数为1 */  
     
    //如果发生数据溢出,接收数据,但是不再读取 刷新收到的数据但是不读  
    tcflush(fd,TCIFLUSH);  
     
    //激活配置 (将修改后的termios数据设置到串口中)  
    if (tcsetattr(fd,TCSANOW,&options) != 0)    
    {  
        perror("com set error!\n");    
        return (FALSE);   
    }  
    return (TRUE);   
}

/*******************************************************************
* 名称:        COM_Init
* 功能:        串口初始化
* 入口参数:    fd       :  文件描述符    
*               speed  :  串口速度
*               flow_ctrl  数据流控制
*               databits   数据位   取值为 7 或者8
*               stopbits   停止位   取值为 1 或者2
*               parity     效验类型 取值为N,E,O,,S
* 出口参数:    正确返回为1,错误返回为0
*******************************************************************/  
int COM_Init(int fd, int speed,int flow_ctrl,int databits,int stopbits,int parity)  
{  
    int err;
    //设置串口数据帧格式  
    if (COM_Set(fd,speed,0,8,1,parity) == FALSE)  
    {
        return FALSE;  
    }  
    else  
    {  
        return  TRUE;  
    }  
}  
   
/*******************************************************************
* 名称:        COM_Recv
* 功能:        接收串口数据
* 入口参数:    fd                  :文件描述符     
*               rcv_buf     :接收串口中数据存入rcv_buf缓冲区中
*               data_len    :一帧数据的长度
* 出口参数:    正确返回接收长度,错误返回为0
*******************************************************************/  
int COM_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  
    {  
        printf("COM_Recv timeout!");
        return 0;  
    }
}

/********************************************************************
* 名称:         COM_Send
* 功能:      发送数据
* 入口参数:  fd          :文件描述符     
*             send_buf    :存放串口发送数据
*                data_len    :一帧数据的个数
* 出口参数:  正确返回为1,错误返回为0
*******************************************************************/  
int COM_Send(int fd, char *send_buf,int data_len)  
{  
    int len = 0;  
     
    len = write(fd,send_buf,data_len);  
    if (len == data_len )  
    {  
        //printf("send data is %s\n",send_buf);
        return len;  
    }       
    else     
    {  
        tcflush(fd,TCOFLUSH);  
        return FALSE;  
    }  
}   
   
int main(int argc, char **argv)  
{  
    int fd;                             // 文件描述符  
    int err;                            // 返回调用函数的状态
    int speed = 115200;
    char parity = 'N';  
    unsigned int tmpU32 = 0;
    int buff_len = 0;
    int len;
    int i;
    uint8 Buff[BUFF_SIZE+1] = {0};
    
    if ((argc != 2)&&(argc != 3)&&(argc != 4))
    {  
        printf("Usage: %s /dev/ttyXX 0(send data)/1(receive data) \n",argv[0]);
        printf("Example:./a.out /dev/tty0 0 9600-E (send mode,9600-E-8-1)\n");
        printf("Example:./a.out /dev/tty0 (default:send and recv mode,115200-N-8-1)\n");
        return 0;  
    }  
    fd = COM_Open(fd, argv[1]); // 打开串口,返回文件描述符
    if (fd <= 0)
    {
        printf("Open Port err! fd=%d %s\n", fd, argv[1]);
        return 0;
    }
    else
    {
        printf("Open Port ok! fd=%d %s\n", fd, argv[1]);
    }
    
    do
    {
        if (4 == argc)
        {
            sscanf(argv[3], "%d-%c", &speed, &parity);
        }
        
        err = COM_Init(fd,speed,0,8,1, parity);
        if (err)
            printf("Set  Port ok! fd=%d %s %d-%c-8-1\n", fd,argv[1], speed, parity);
        else
            printf("Set  Port err! fd=%d err=%d %s %d-%c-8-1\n", fd,err,argv[1], speed, parity);
    }while((FALSE == err)&&(tmpU32++ < 5));
    if (FALSE == err)
        return 0;
     
    if((argc == 2)||(0 == strcmp(argv[2], "0")))   // 输入buff,发送,接收
    {
        while (1)
        {
            // 输入准备发送的Buff
            printf("Input hex buff to send, end of Enter. Example:11 22 AA FF\n");
            printf("Buff:");
            i = 0;
            len = 0;
            if (fgets(Buff, sizeof(Buff), stdin) != NULL)
            {
                buff_len = strlen(Buff);
                while(Buff[i] == ' ') i++;
                for (; i < buff_len; i+=2)
                {
                    while(Buff[i] == ' ') 
                    {
                        i++;
                    }
                    if (i >= buff_len-1)
                    {
                        break;
                    }
                    sscanf(Buff+i, "%02X", &tmpU32);
                    Buff[len++] = (uint8)tmpU32;
                }
            }
            
            // 发送数据
            printf("Send len = %d\n", len);
            tcflush(fd, TCIFLUSH);
            len = COM_Send(fd, Buff, len);
            if(len > 0)
            {
                printf("Send:");
                for (i = 0; i < len; i++)
                {
                    printf("%02X ", Buff[i]);
                }
                printf("\n");
                memset(Buff, 0x00, len);
            }
            else
            {
                printf("Send data failed!\n");
                memset(Buff, 0x00, sizeof(Buff));
            }
                
            // 接收数据
            len = COM_Recv(fd, Buff, sizeof(Buff));
            if(len > 0)  
            {  
                printf("Recv len = %d\n",len);  
                printf("Recv:");
                for (i = 0; i < len; i++)
                {
                    printf("%02X ", Buff[i]);
                }
                printf("\n");
                memset(Buff, 0x00, len);
            }
            putchar('\n');
        }  
        COM_Close(fd);               
    }  
    else    // 接收
    {                                        
        while (1) // 循环读取数据  
        {    
            len = COM_Recv(fd, Buff, sizeof(Buff));  
            if(len > 0)  
            {  
                printf("Recv len = %d\n",len);  
                printf("Recv:");
                for (i = 0; i < len; i++)
                {
                    printf("%02X ", Buff[i]);
                }
                printf("\n");
                memset(Buff, 0x00, len);
            }  
            else  
            {  
                printf("Cannot receive data!\n");
                memset(Buff, 0x00, sizeof(Buff));
            }  
        }
        COM_Close(fd);   
    }
    
    printf("Over!\n");
} 

测试:

root@ubuntu:/home/forlinuxsmb/uart# gcc ComTest.c
root@ubuntu:/home/forlinuxsmb/uart# ./a.out /dev/ttyACM1 0 9600-E
fcntl=0
isatty success!
fd=3
Open Port ok! fd=3 /dev/ttyACM1
Set  Port ok! fd=3 /dev/ttyACM1 9600-E-8-1
Input hex buff to send, end of Enter. Example:11 22 AA FF
Buff:11 22 AA FF CC
Send len = 5
Send:11 22 AA FF CC 
Recv len = 5
Recv:11 22 AA FF CC 

Input hex buff to send, end of Enter. Example:11 22 AA FF
Buff:^C

root@ubuntu:/home/forlinuxsmb/uart# ./a.out /dev/ttyACM1
fcntl=0
isatty success!
fd=3
Open Port ok! fd=3 /dev/ttyACM1
Set  Port ok! fd=3 /dev/ttyACM1 115200-N-8-1
Input hex buff to send, end of Enter. Example:11 22 AA FF
Buff:AA 55 33 FF
Send len = 4
Send:AA 55 33 FF 
Recv len = 4
Recv:AA 55 33 FF 

Input hex buff to send, end of Enter. Example:11 22 AA FF
Buff:^C
 

  • 1
    点赞
  • 0
    评论
  • 1
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

相关推荐
©️2020 CSDN 皮肤主题: 游动-白 设计师:白松林 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值