Ubuntu 17.04编译串口发送16进制数据包报了个神奇的错误

来源:互联网 发布:python 获取 roe 编辑:程序博客网 时间:2024/06/06 02:54

调试系统环境:Ubuntu 17.04 +  Clion 17.1

今天在调试Ubuntu 系统通过串口发送16进制数据时,我发现了一个很神奇的问题现象。

先看看下面的代码:

    //char  *data = "hello world dhs!";    char  data[9] = {0x11,0x22,0x33,0x11,0x22,0x33,0x11,0x22,0x33};    //data[0] = 0xAA;    //int datalen = strlen(data);        //send data    //while (1)    {        for (int i = 0; i < 100; i++)        {            SendLen = PortSend(fd, data, 9);            if (SendLen > 0) {                printf("No %d send %d data.\n", i, SendLen);            } else {                printf("Error: send failed.\n");            }            sleep(1);        }    }

然后在Clion 中进行编译,发现编译很完美,并能够通过 xgcom(一款Linux下的带GUI的串口调试助手)接收到16进制数据。

再看看以下代码:

    //char  *data = "hello world dhs!";    char  data[2] = {0x11,0x22,0x33,0x11,0x22,0x33,0x11,0x22,0x88};    //data[0] = 0xAA;    //int datalen = strlen(data);        //send data    //while (1)    {        for (int i = 0; i < 100; i++)        {            SendLen = PortSend(fd, data, 2);            if (SendLen > 0) {                printf("No %d send %d data.\n", i, SendLen);            } else {                printf("Error: send failed.\n");            }            sleep(1);        }    }

然后再Clion中编译源代码时,就发现报错了,错误信息如下:

/home/dhs/桌面/serial_dhs/serail (cpp)/serial.cpp:305:66: error: narrowing conversion of ‘136’ from ‘int’ to ‘char’ inside { } [-Wnarrowing]     char  data[9] = {0x11,0x22,0x33,0x11,0x22,0x33,0x11,0x22,0x88};                                                                  ^CMakeFiles/serail.dir/build.make:62: recipe for target 'CMakeFiles/serail.dir/serial.cpp.o' failedmake[3]: *** [CMakeFiles/serail.dir/serial.cpp.o] Error 1CMakeFiles/Makefile2:67: recipe for target 'CMakeFiles/serail.dir/all' failedmake[2]: *** [CMakeFiles/serail.dir/all] Error 2CMakeFiles/Makefile2:79: recipe for target 'CMakeFiles/serail.dir/rule' failedmake[1]: *** [CMakeFiles/serail.dir/rule] Error 2Makefile:118: recipe for target 'serail' failedmake: *** [serail] Error 2
经过我多次测试,终于发现了一个很神奇的错误现象。
当发送的16进制数据包中有数据大于255时,便会编译报错。

因此,我认为在串口发送16进制数据时可能使用了int数据类型作转换,也就是说在同类的程序中也很有可能会发生这种错误。

所以,我在此将其提出,一是想给自己一个警示,同时也是希望能够解决它的数据传输问题。(问题是我需要收发16进制数据形式的大小超过255.。。。)

最后,我把整个的代码贴出来如下(主要是在网上找改的程序):

#include <stdio.h>              // printf   #include <fcntl.h>              // open   #include <string.h>             // bzero   #include <stdlib.h>             // exit   #include <sys/times.h>          // times   #include <sys/types.h>          // pid_t   #include <termios.h>            //termios, tcgetattr(), tcsetattr()#include <unistd.h>#include <sys/ioctl.h>          // ioctl#define TTY_DEV "/dev/ttyUSB"   //端口路径#define TIMEOUT_SEC(buflen,baud) (buflen*20/baud+2)  //接收超时   #define TIMEOUT_USEC 0//串口结构typedef struct{    char prompt;        //prompt after reciving data    int  baudrate;      //baudrate    char databit;       //data bits, 5, 6, 7, 8    char debug;         //debug mode, 0: none, 1: debug    char echo;          //echo mode, 0: none, 1: echo    char fctl;          //flow control, 0: none, 1: hardware, 2: software    char tty;           //tty: 0, 1, 2, 3, 4, 5, 6, 7    char parity;        //parity 0: none, 1: odd, 2: even    char stopbit;       //stop bits, 1, 2    const int reserved; //reserved, must be zero}portinfo_t;typedef portinfo_t *pportinfo_t;/** * 打开串口,返回文件描述符 * pportinfo: 待设置的串口信息*/int PortOpen(pportinfo_t pportinfo);/** * 设置串口 * fdcom: 串口文件描述符, pportinfo: 待设置的串口信息*/int PortSet(int fdcom, const pportinfo_t pportinfo);/** * 关闭串口 * fdcom:串口文件描述符*/void PortClose(int fdcom);/** * 发送数据 * fdcom:串口描述符, data:待发送数据, datalen:数据长度 * 返回实际发送长度*/int PortSend(int fdcom, char *data, int datalen);/** * 接收数据 * fdcom:串口描述符, data:接收缓冲区, datalen:接收长度, baudrate:波特率 * 返回实际读入的长度*/int PortRecv(int fdcom, char *data, int datalen, int baudrate);/*******************************************  *  获得端口名称 ********************************************/char *get_ptty(pportinfo_t pportinfo){    char *ptty;    switch(pportinfo->tty){        case '0':{            ptty = TTY_DEV"0";        }break;        case '1':{            ptty = TTY_DEV"1";        }break;        case '2':{            ptty = TTY_DEV"2";        }break;    }    return(ptty);}/*******************************************  *  波特率转换函数(请确认是否正确) ********************************************/int convbaud(unsigned long int baudrate){    switch(baudrate){        case 2400:            return B2400;        case 4800:            return B4800;        case 9600:            return B9600;        case 19200:            return B19200;        case 38400:            return B38400;        case 57600:            return B57600;        case 115200:            return B115200;        default:            return B9600;    }}/*******************************************  *  Setup comm attr  *  fdcom: 串口文件描述符,pportinfo: 待设置的端口信息(请确认)  * ********************************************/int PortSet(int fdcom, const pportinfo_t pportinfo){    struct termios termios_old, termios_new;    int     baudrate, tmp;    char    databit, stopbit, parity, fctl;    bzero(&termios_old, sizeof(termios_old));    bzero(&termios_new, sizeof(termios_new));    cfmakeraw(&termios_new);    tcgetattr(fdcom, &termios_old);         //get the serial port attributions    /*------------设置端口属性----------------*/    //baudrates       baudrate = convbaud(pportinfo->baudrate);    cfsetispeed(&termios_new, baudrate);        //填入串口输入端的波特率       cfsetospeed(&termios_new, baudrate);        //填入串口输出端的波特率       termios_new.c_cflag |= CLOCAL;              //控制模式,保证程序不会成为端口的占有者    termios_new.c_cflag |= CREAD;               //控制模式,使能端口读取输入的数据    // 控制模式:flow control    fctl = pportinfo-> fctl;    switch(fctl){        case '0':{            termios_new.c_cflag &= ~CRTSCTS;            //no flow control        }break;        case '1':{            termios_new.c_cflag |= CRTSCTS;             //hardware flow control        }break;        case '2':{            termios_new.c_iflag |= IXON | IXOFF |IXANY; //software flow control           }break;    }    //控制模式,data bits       termios_new.c_cflag &= ~CSIZE;      //控制模式,屏蔽字符大小位       databit = pportinfo -> databit;    switch(databit){        case '5':            termios_new.c_cflag |= CS5;        case '6':            termios_new.c_cflag |= CS6;        case '7':            termios_new.c_cflag |= CS7;        default:            termios_new.c_cflag |= CS8;    }    //控制模式 parity check       parity = pportinfo -> parity;    switch(parity){        case '0':{            termios_new.c_cflag &= ~PARENB;     //no parity check           }break;        case '1':{            termios_new.c_cflag |= PARENB;      //odd check               termios_new.c_cflag &= ~PARODD;        }break;        case '2':{            termios_new.c_cflag |= PARENB;      //even check               termios_new.c_cflag |= PARODD;        }break;    }    //控制模式,stop bits       stopbit = pportinfo -> stopbit;    if(stopbit == '2'){        termios_new.c_cflag |= CSTOPB;  //2 stop bits       }    else{        termios_new.c_cflag &= ~CSTOPB; //1 stop bits       }    //other attributions default       termios_new.c_oflag &= ~OPOST;          //输出模式, 原始数据输出    termios_new.c_cc[VMIN]  = 0;            //控制字符, 所要读取字符的最小数量    termios_new.c_cc[VTIME] = 1;            //控制字符, 读取第一个字符的等待时间    unit: (1/10)second       tcflush(fdcom, TCIFLUSH);               //溢出的数据可以接收,但不读       tmp = tcsetattr(fdcom, TCSANOW, &termios_new);  //设置新属性,TCSANOW:所有改变立即生效    //tcgetattr(fdcom, &termios_old);    return(tmp);}/*******************************************  *  Open serial port  *  tty: 端口号 ttyS0, ttyS1, ....  *  返回值为串口文件描述符 ********************************************/int PortOpen(pportinfo_t pportinfo){    int  fdcom;  //串口文件描述符    char *ptty;    ptty = get_ptty(pportinfo);    //fdcom = open(ptty, O_RDWR | O_NOCTTY | O_NONBLOCK | O_NDELAY);       fdcom = open(ptty, O_RDWR | O_NOCTTY | O_NONBLOCK);    return (fdcom);}/*******************************************  *  Close serial port ********************************************/void PortClose(int fdcom){    close(fdcom);}/********************************************  *  send data  *  fdcom: 串口描述符,data: 待发送数据,datalen: 数据长度  *  返回实际发送长度 *********************************************/int PortSend(int fdcom, char *data, int datalen){    int len = 0;    len = write(fdcom, data, datalen);  //实际写入的长度       if(len == datalen){        return (len);    }    else{        tcflush(fdcom, TCOFLUSH);        return -1;    }}/*******************************************  *  receive data  *  返回实际读入的字节数  * ********************************************/int PortRecv(int fdcom, char *data, int datalen, int baudrate){    int readlen, fs_sel;    fd_set  fs_read;    struct timeval tv_timeout;    FD_ZERO(&fs_read);    FD_SET(fdcom, &fs_read);    tv_timeout.tv_sec  = TIMEOUT_SEC(datalen, baudrate);    tv_timeout.tv_usec = TIMEOUT_USEC;    fs_sel = select(fdcom + 1, &fs_read, NULL, NULL, &tv_timeout);    if(fs_sel){        readlen = read(fdcom, data, datalen);        return(readlen);    }    else{        return(-1);    }    //return (readlen);}//*************************Test*********************************   int main(int argc, char *argv[]) {    int fd = -1, SendLen = 0, RecvLen = 0;    struct termios termios_cur;    char RecvBuf[10] = {0};    portinfo_t portinfo = {            '0',                            // print prompt after receiving            9600,                           // baudrate: 9600            '8',                            // databit: 8            '0',                            // debug: off            '1',                            // echo: on            '1',                            // flow control: hardware            '0',                            // default tty: COM1            '0',                            // parity: none            '1',                            // stopbit: 1             0                              // reserved    };    /*     if(argc != 2){         printf("Usage: <type 0 -- send 1 -- receive>\n");         printf("   eg:");         printf("        MyPort 0");         exit(-1);     }    */    fd = PortOpen(&portinfo);    if (fd < 0) {        printf("Error: open serial port error.\n");        exit(1);    }    PortSet(fd, &portinfo);    //char  *data = "hello world dhs!";    char  data[9] = {0x11,0x22,0x33,0x11,0x22,0x33,0x11,0x22,0x88};    //data[0] = 0xAA;    int datalen = strlen(data);        //send data    //while (1)    {        for (int i = 0; i < 100; i++)        {            SendLen = PortSend(fd, data, 9);            if (SendLen > 0) {                printf("No %d send %d data.\n", i, SendLen);            } else {                printf("Error: send failed.\n");            }            sleep(1);        }    }        PortClose(fd);    /**        for(;;)        {            RecvLen = PortRecv(fd, RecvBuf, 10, portinfo.baudrate);            if(RecvLen>0){                for(i=0; i<RecvLen; i++){                    printf("Receive data No %d is %x.\n", i, RecvBuf[i]);                }                printf("Total frame length is %d.\n", RecvLen);            }            else{                printf("E                rror: receive error.\n");            }            sleep(2);        }    */    return 0;}


原创粉丝点击