linux 串口自环测试程序。两种不同的方法。select ,以及多线程方法。
select
uart_sendrecv_notv.rar
多线程方法
sertest.rar
select
![](https://i-blog.csdnimg.cn/blog_migrate/f5eb4426879d9c4b4b2deb15679e0746.png)
点击(此处)折叠或打开
- #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 <unistd.h>
- #include <string.h>
- #define DEVICE "/dev/ttyUSB0"
-
- #define S_TIMEOUT 1
-
- int serial_fd = 0;
-
- //打开串口并初始化设置
-
- init_serial(void)
- {
- serial_fd = open(DEVICE, O_RDWR | O_NOCTTY | O_NDELAY);
- if (serial_fd < 0) {
- perror("open");
- return -1;
- }
-
- //串口主要设置结构体termios <termios.h>
- struct termios options;
-
- /**1. tcgetattr函数用于获取与终端相关的参数。
- *参数fd为终端的文件描述符,返回的结果保存在termios结构体中
- */
- tcgetattr(serial_fd, &options);
- /**2. 修改所获得的参数*/
- options.c_cflag |= (CLOCAL | CREAD);//设置控制模式状态,本地连接,接收使能
- options.c_cflag &= ~CSIZE;//字符长度,设置数据位之前一定要屏掉这个位
- options.c_cflag &= ~CRTSCTS;//无硬件流控
- options.c_cflag |= CS8;//8位数据长度
- options.c_cflag &= ~CSTOPB;//1位停止位
- options.c_iflag |= IGNPAR;//无奇偶检验位
- options.c_oflag = 0; //输出模式
- options.c_lflag = 0; //不激活终端模式
- cfsetospeed(&options, B115200);//设置波特率
-
- /**3. 设置新属性,TCSANOW:所有改变立即生效*/
- tcflush(serial_fd, TCIFLUSH);//溢出数据可以接收,但不读
- tcsetattr(serial_fd, TCSANOW, &options);
-
- return 0;
- }
-
- /**
- *串口发送数据
- *@fd:串口描述符
- *@data:待发送数据
- *@datalen:数据长度
- */
- unsigned int total_send = 0 ;
- int uart_send(int fd, char *data, int datalen)
- {
- int len = 0;
- len = write(fd, data, datalen);//实际写入的长度
- if(len == datalen) {
- total_send += len ;
- printf("total_send is %d\n",total_send);
- return len;
- } else {
- tcflush(fd, TCOFLUSH);//TCOFLUSH刷新写入的数据但不传送
- return -1;
- }
- return 0;
- }
-
- /**
- *串口接收数据
- *要求启动后,在pc端发送ascii文件
- */
- unsigned int total_length = 0 ;
- int uart_recv(int fd, char *data, int datalen)
- {
- int len=0, ret = 0;
- fd_set fs_read;
- struct timeval tv_timeout;
-
- FD_ZERO(&fs_read);
- FD_SET(fd, &fs_read);
-
- #ifdef S_TIMEOUT
- tv_timeout.tv_sec = (10*20/115200+2);
- tv_timeout.tv_usec = 0;
- ret = select(fd+1, &fs_read, NULL, NULL, NULL);
- #elif
- ret = select(fd+1, &fs_read, NULL, NULL, tv_timeout);
- #endif
-
- // printf("ret = %d\n", ret);
- //如果返回0,代表在描述符状态改变前已超过timeout时间,错误返回-1
-
- if (FD_ISSET(fd, &fs_read)) {
- len = read(fd, data, datalen);
- total_length += len ;
- printf("total len = %d\n", total_length);
- return len;
- } else {
- perror("select");
- return -1;
- }
-
- return 0;
- }
-
- int main(int argc, char **argv)
- {
- init_serial();
-
- char buf[]="hello world";
- char buf1[11] ;
- memset(buf1,0,sizeof(char)*11);
-
- while(1)
- {
- uart_send(serial_fd, buf, 11);
- printf("\n");
- sleep(1);
- //if(uart_recv(serial_fd, buf1, 11) > 0)
- uart_recv(serial_fd, buf1, 11);
- printf("receive: %s\n", buf1);
- memset(buf1,0,sizeof(char)*11);
- }
-
- close(serial_fd);
- return 0;
- }
多线程方法
![](https://i-blog.csdnimg.cn/blog_migrate/f5eb4426879d9c4b4b2deb15679e0746.png)
点击(此处)折叠或打开
- /****************************************************************************
- *
- * Copyright (c) 2006 Dave Hylands <dhylands@gmail.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- *
- ****************************************************************************/
- /**
- *
- * sertest.c
- *
- * PURPOSE:
- *
- * This implements a sample program for accessing the serial port.
- *
- *****************************************************************************/
-
- /* ---- Include Files ---------------------------------------------------- */
-
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <errno.h>
- #include <fcntl.h>
- #include <sys/ioctl.h>
- #include <sys/unistd.h>
- #include <pthread.h>
- #include <signal.h>
- #include <getopt.h>
- #include <termios.h>
-
- /* ---- Public Variables ------------------------------------------------- */
-
- int gFd = -1;
-
- int gVal;
-
- /* ---- Private Constants and Types -------------------------------------- */
- /* ---- Private Variables ------------------------------------------------ */
-
- struct option gLongOption[] =
- {
- // option A Flag V (has_arg, flag, val)
- // ----------- - ---- ---
- { "baud", 1, NULL, 'b' },
- { "debug", 0, NULL, 'd' },
- { "help", 0, NULL, 'h' },
- { "port", 1, NULL, 'p' },
- { "verbose", 0, NULL, 'v' },
- { 0 },
-
- };
-
- struct
- {
- speed_t speed;
- unsigned baudRate;
- } gBaudTable[] =
- {
- { B50, 50 },
- { B75, 75 },
- { B110, 110 },
- { B134, 134 },
- { B150, 150 },
- { B200, 200 },
- { B300, 300 },
- { B600, 600 },
- { B1200, 1200 },
- { B1800, 1800 },
- { B2400, 2400 },
- { B4800, 4800 },
- { B9600, 9600 },
- { B19200, 19200 },
- { B38400, 38400 },
- { B57600, 57600 },
- { B115200, 115200 },
- { B230400, 230400 }
- };
-
- #define ARRAY_LEN(x) ( sizeof( x ) / sizeof( x[ 0 ]))
-
- int gVerbose = 0;
- int gDebug = 0;
-
- int gPortFd = -1;
-
- /* ---- Private Function Prototypes -------------------------------------- */
-
- void *ReadSerialThread( void *param );
- void *ReadStdinThread( void *param );
- char *StrMaxCpy( char *dst, const char *src, size_t maxLen );
- char *StrMaxCat( char *dst, const char *src, size_t maxLen );
- void Usage( void );
-
- /* ---- Functions -------------------------------------------------------- */
-
- #if defined(__CYGWIN__)
- // Cygwin seems to be missing cfmakeraw, so we provide a copy here.
- static void cfmakeraw(struct termios *termios_p)
- {
- termios_p->c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL|IXON);
- termios_p->c_oflag &= ~OPOST;
- termios_p->c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN);
- termios_p->c_cflag &= ~(CSIZE|PARENB);
- termios_p->c_cflag |= CS8;
- }
- #endif /* defined(__CYGWIN__) */
-
-
-
- /***************************************************************************
- *
- * main
- *
- ****************************************************************************/
-
- int main( int argc, char **argv )
- {
- int sig;
- int rc;
- int opt;
- char devName[ 40 ];
- const char *baudStr = NULL;
- const char *portStr = "ttyS2";
- speed_t baudRate;
- sigset_t termSig;
- pthread_t readSerialThreadId;
- pthread_t readStdinThreadId;
- struct termios stdin_tio;
- struct termios stdin_tio_org;
-
- struct termios attr;
-
- // Parse the command line options
-
- while (( opt = getopt_long( argc, argv, "b:dhp:v", gLongOption, NULL )) > 0 )
- {
- switch ( opt )
- {
- case 'b':
- {
- baudStr = optarg;
- break;
- }
-
- case 'd':
- {
- gDebug = 1;
- break;
- }
-
- case 'p':
- {
- portStr = optarg;
- break;
- }
-
- case 'v':
- {
- gVerbose = 1;
- break;
- }
- case '?':
- case 'h':
- {
- Usage();
- return 1;
- }
- }
- }
-
- devName[ 0 ] = '\0';
- if ( portStr[ 0 ] != '/' )
- {
- StrMaxCpy( devName, "/dev/", sizeof( devName ));
- }
- StrMaxCat( devName, portStr, sizeof( devName ));
-
-
- baudRate = B0;
- if ( baudStr == NULL )
- {
- baudRate = B9600;
- }
- else
- {
- int baudIdx;
- int testBaud = atoi( baudStr );
-
- for ( baudIdx = 0; baudIdx < ARRAY_LEN( gBaudTable ); baudIdx++ )
- {
- if ( gBaudTable[ baudIdx ].baudRate == testBaud )
- {
- baudRate = gBaudTable[ baudIdx ].speed;
- break;
- }
- }
-
- if ( baudRate == B0 )
- {
- fprintf( stderr, "Unrecognized baud rate: '%s'\n", baudStr );
- exit( 1 );
- }
- }
-
- // Open the serial port initially using O_NONBLOCK so that we won't block waiting for
- // carrier detect.
-
- if (( gPortFd = open( devName, O_RDWR | O_EXCL | O_NONBLOCK )) < 0 )
- {
- fprintf( stderr, "Unable to open serial port '%s': %s\n", devName, strerror( errno ));
- exit( 2 );
- }
-
- // Now that the serial port is open, we can turn off the non-blocking behaviour (for us we want
- // the reads to have blocking semantics).
-
- fcntl( gPortFd, F_SETFL, fcntl( gPortFd, F_GETFL ) & ~O_NONBLOCK );
-
- if ( tcgetattr( gPortFd, &attr ) < 0 )
- {
- fprintf( stderr, "Call to tcgetattr failed: %s\n", strerror( errno ));
- exit( 3 );
- }
-
- cfmakeraw( &attr );
-
- // CLOCAL - Disable modem control lines
- // CREAD - Enable Receiver
-
- attr.c_cflag |= ( CLOCAL | CREAD );
-
- cfsetispeed( &attr, baudRate );
- cfsetospeed( &attr, baudRate );
-
- if ( tcsetattr( gPortFd, TCSAFLUSH, &attr ) < 0 )
- {
- fprintf( stderr, "Call to tcsetattr failed: %s\n", strerror( errno ));
- exit( 4 );
- }
-
- // Put stdin & stdout in unbuffered mode.
-
- setbuf( stdin, NULL );
- setbuf( stdout, NULL );
-
- sigemptyset( &termSig );
- sigaddset( &termSig, SIGINT );
- sigaddset( &termSig, SIGTERM );
-
- pthread_sigmask( SIG_BLOCK, &termSig, NULL );
-
- // Put stdin in raw mode (i.e. turn off canonical mode). Canonical mode
- // causes the driver to wait for the RETURN character so that line editing
- // can take place. We also want to turn off ECHO.
-
- if ( tcgetattr( fileno( stdin ), &stdin_tio_org ) < 0 )
- {
- fprintf( stderr, "Unable to retrieve terminal settings: %s\n", strerror( errno ));
- exit( 5 );
- }
-
- stdin_tio = stdin_tio_org;
- stdin_tio.c_lflag &= ~( ICANON | ECHO );
- stdin_tio.c_cc[VTIME] = 0;
- stdin_tio.c_cc[VMIN] = 1;
-
- if ( tcsetattr( fileno( stdin ), TCSANOW, &stdin_tio ) < 0 )
- {
- fprintf( stderr, "Unable to update terminal settings: %s\n", strerror( errno ));
- exit( 6 );
- }
-
- // Kick off the serial port reader thread.
-
- rc = pthread_create( &readSerialThreadId, NULL, ReadSerialThread, NULL );
- if ( rc != 0 )
- {
- fprintf( stderr, "Error creating ReadSerialThread: %s\n", strerror( rc ));
- exit( 7 );
- }
-
- // Kick off the stdin reader thread
-
- rc = pthread_create( &readStdinThreadId, NULL, ReadStdinThread, NULL );
- if ( rc != 0 )
- {
- fprintf( stderr, "Error creating ReadStdinThread: %s\n", strerror( rc ));
- exit( 7 );
- }
-
- // Wait for a termmination signal
-
- if (( rc = sigwait( &termSig, &sig )) != 0 )
- {
- fprintf( stderr, "sigwait failed\n" );
- }
- else
- {
- fprintf( stderr, "Exiting...\n" );
- }
-
- pthread_cancel( readSerialThreadId );
- pthread_cancel( readStdinThreadId );
-
- // Restore stdin back to the way it was when we started
-
- if ( tcsetattr( fileno( stdin ), TCSANOW, &stdin_tio_org ) < 0 )
- {
- fprintf( stderr, "Unable to update terminal settings: %s\n", strerror( errno ));
- exit( 6 );
- }
-
- // Unblock the termination signals so the user can kill us if we hang up
- // waiting for the reader threads to exit.
-
- pthread_sigmask( SIG_UNBLOCK, &termSig, NULL );
-
- pthread_join( readSerialThreadId, NULL );
- pthread_join( readStdinThreadId, NULL );
-
- close( gPortFd );
-
- if ( gVerbose )
- {
- fprintf( stderr, "Done\n" );
- }
-
- exit( 0 );
- return 0; // Get rid of warning about not returning anything
- }
-
- /***************************************************************************/
- /**
- * Thread which processes the incoming serial data.
- */
-
- void *ReadSerialThread( void *param )
- {
- while ( 1 )
- {
- char ch;
- int bytesRead;
-
- if (( bytesRead = read( gPortFd, &ch, 10 )) < 0 )
- {
- fprintf( stderr, "Serial port read failed: %s\n", strerror( errno ));
- exit( 1 );
- }
-
- if ( gDebug )
- {
- if (( ch < ' ' ) || ( ch > '~' ))
- {
- fprintf( stderr, "Serial Read: 0x%02x '.'\n", ch );
- }
- else
- {
- fprintf( stderr, "Serial Read: 0x%02x '%c'\n", ch, ch );
- }
-
- }
-
- putc( ch, stdout );
- }
-
- return NULL;
-
- } // ReadSerialThread
-
- /***************************************************************************/
- /**
- * Thread which processes the incoming serial from stdin.
- */
-
- void *ReadStdinThread( void *param )
- {
- while ( 1 )
- {
- char ch;
- int chInt = fgetc( stdin );
- if ( chInt < 0 )
- {
- fprintf( stderr, "Error reading stdin...\n" );
- break;
- }
- ch = (char)chInt;
-
- if ( gDebug )
- {
- if (( ch < ' ' ) || ( ch > '~' ))
- {
- fprintf( stderr, "stdin Read: 0x%02x '.'\n", ch );
- }
- else
- {
- fprintf( stderr, "stdin Read: 0x%02x '%c'\n", ch, ch );
- }
-
- }
-
- if ( write( gPortFd, &ch, 1 ) != 1 )
- {
- fprintf( stderr, "write to serial port failed: %s\n", strerror( errno ));
- break;
- }
- }
-
- return NULL;
-
- } // ReadStdinThread
-
- /***************************************************************************/
- /**
- * Concatenates source to the destination, but makes sure that the
- * destination string (including terminating null), doesn't exceed maxLen.
- *
- * @param dst (mod) String to concatnate onto.
- * @param src (in) String to being added to the end of @a dst.
- * @param maxLen (in) Maximum length that @a dst is allowed to be.
- *
- * @return A pointer to the destination string.
- */
-
- char *StrMaxCat( char *dst, const char *src, size_t maxLen )
- {
- size_t dstLen = strlen( dst );
-
- if ( dstLen < maxLen )
- {
- StrMaxCpy( &dst[ dstLen ], src, maxLen - dstLen );
- }
-
- return dst;
-
- } /* StrMaxCat */
-
- /***************************************************************************/
- /**
- * Copies the source to the destination, but makes sure that the
- * destination string (including terminating null), doesn't exceed
- * maxLen.
- *
- * @param dst (out) Place to store the string copy.
- * @param src (in) String to copy.
- * @param maxLen (in) Maximum number of characters to copy into @a dst.
- *
- * @return A pointer to the destination string.
- */
-
- char *StrMaxCpy( char *dst, const char *src, size_t maxLen )
- {
- if ( maxLen < 1 )
- {
- /*
- * There's no room in the buffer?
- */
-
- return "";
- }
-
- if ( maxLen == 1 )
- {
- /*
- * There's only room for the terminating null character
- */
-
- dst[ 0 ] = '\0';
- return dst;
- }
-
- /*
- * The Visual C++ version of strncpy writes to every single character
- * of the destination buffer, so we use a length one character smaller
- * and write in our own null (if required).
- *
- * This allows the caller to store a sentinel in the last byte of the
- * buffer to detect overflows (if desired).
- */
-
- strncpy( dst, src, maxLen - 1 );
- if (( strlen( src ) + 1 ) >= maxLen )
- {
- /*
- * The string exactly fits, or probably overflows the buffer.
- * Write in the terminating null character since strncpy doesn't in
- * this particular case.
- *
- * We don't do this arbitrarily so that the caller can use a sentinel
- * in the very end of the buffer to detect buffer overflows.
- */
-
- dst[ maxLen - 1 ] = '\0';
- }
-
- return dst;
-
- } /* StrMaxCpy */
-
- /***************************************************************************
- *
- * Usage
- *
- ****************************************************************************/
-
- void Usage()
- {
- fprintf( stderr, "Usage: sertest [option(s)]\n" );
- fprintf( stderr, " Download a program via serial/i2c\n" );
- fprintf( stderr, "\n" );
- fprintf( stderr, " -b, --baud=baud Set the baudrate used\n" );
- fprintf( stderr, " -d, --debug Turn on debug output\n" );
- fprintf( stderr, " -h, --help Display this message\n" );
- fprintf( stderr, " -p, --port=port Set the I/O port\n" );
- fprintf( stderr, " -v, --verbose Turn on verbose messages\n" );
-
- } // Usage