天天看點

linux序列槽測試例程

例程有兩種基本用法

一、短接tx rx,自發自收

短接開發闆待測序列槽的tx和rx,運作如下例程,

二、用電腦的序列槽助手進行收發測試

1、将開發闆待測序列槽和電腦連接配接起來(用USB轉序列槽連接配接闆)

2、開發闆運作例程(循環讀取序列槽内容并回傳)

$ ./uart_test  /dev/ttyS1
           

3、電腦序列槽助手打開對應的序列槽,發送任意資料,檢視傳回結果。

使用全志的A64開發闆實測,write發送位元組個數幾乎沒有限制,一次就完成。read一次最多讀32個位元組。

例程源碼如下

/*
 *	序列槽測試例程
 *  需要傳參序列槽的裝置檔案,如/dev/ttyS2
 *  若打開序列槽成功,會循環讀取序列槽讀到的内容,然後回傳
 */
 
#include <stdio.h>      /*标準輸入輸出定義*/
#include <stdlib.h>     /*标準函數庫定義*/
#include <string.h>
#include <unistd.h>     /*Unix标準函數定義*/
#include <sys/types.h>  /**/
#include <sys/stat.h>   /**/
#include <fcntl.h>      /*檔案控制定義*/
#include <termios.h>    /*PPSIX終端控制定義*/
#include <errno.h>      /*錯誤号定義*/
#include <sys/time.h>

/*
 * %  0x25
 * ;  0x3B
 * +  0x2B
 * ?  0x3F
 */

#define DEF_BAUD	115200
#define SPEED_CNT	5
#define BUF_SIZE	100

/*用來接收軌道資料*/
char buffer[BUF_SIZE];

int speed_arr[SPEED_CNT] = {
	B9600, B19200, B38400, 
	B57600,	B115200
};

int name_arr[SPEED_CNT] = {
	9600, 19200, 38400,
	57600, 115200
};

/**
*@brief  設定序列槽通信速率
*@param  fd     類型 int  打開序列槽的檔案句柄
*@param  speed  類型 int  序列槽速度
*@return  0 success or -1 err
*/
int set_speed(int fd, int speed)
{
	int i;
	int status;
	struct termios opt;
	
	tcgetattr(fd, &opt);

	for (i= 0; i<SPEED_CNT; i++)
	{
		if (speed == name_arr[i])
		{
			tcflush(fd, TCIOFLUSH);
			/*  設定序列槽的波特率 */
			cfsetispeed(&opt, speed_arr[i]);
			cfsetospeed(&opt, speed_arr[i]);
			status = tcsetattr(fd, TCSANOW, &opt);

			if (status != 0)
			{
				perror("tcsetattr set_speed");
				return -1;
			}
			
			return 0;
     	}
		/*清空所有正在發生的IO資料*/
		tcflush(fd, TCIOFLUSH);
   }
   
	printf("Cannot find suitable speed\n");
	return -1;
}

/**
*@brief   設定序列槽資料位,停止位和效驗位
*@param  fd     類型  int  打開的序列槽檔案句柄*
*@param  databits 類型  int 資料位   取值 為 7 或者8*
*@param  stopbits 類型  int 停止位   取值為 1 或者2*
*@param  parity  類型  int  效驗類型 取值為N,E,O,,S
*@return  0 success or -1 err
*/
int set_parity(int fd, int databits, int stopbits, int parity)
{

	struct termios options;
	if (tcgetattr(fd, &options) != 0)
	{
		perror("tcgetattr");
		return -1;
	}

	options.c_cflag &= ~CSIZE;
	switch (databits) /*設定資料位數*/
	{
		case 7:
			options.c_cflag |= CS7;
			break;
		case 8:
			options.c_cflag |= CS8;
			break;
		default:
			fprintf(stderr, "Unsupported data size\n");

			return -1;
	}
	
	switch (parity)
  	{
		case 'n':
		case 'N':
			options.c_cflag &= ~PARENB;   /* Clear parity enable */
			options.c_iflag &= ~INPCK;     /* Enable parity checking */
			options.c_iflag &= ~(ICRNL|IGNCR);
			options.c_lflag &= ~(ICANON );
			break;
		case 'o':
		case 'O':
			options.c_cflag |= (PARODD | PARENB);  /* 設定為奇效驗*/ 
			options.c_iflag |= INPCK;             /* Disnable parity checking */
			break;
		case 'e':
		case 'E':
			options.c_cflag |= PARENB;     /* Enable parity */
			options.c_cflag &= ~PARODD;   /* 轉換為偶效驗*/  
			options.c_iflag |= INPCK;       /* Disnable parity checking */
			break;
		case 'S':
		case 's':  /*as no parity*/
			options.c_cflag &= ~PARENB;
			options.c_cflag &= ~CSTOPB;
			break;
		default:
			fprintf(stderr, "Unsupported parity\n");
			return -1;
	}

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

	/* Set input parity option */
	if ((parity != 'n') || (parity != 'N'))
  		options.c_iflag |= INPCK;

	/* 若以O_NONBLOCK 方式open,這兩個設定沒有作用,等同于都為0 */
	/* 若非O_NONBLOCK 方式open,具體作用可參考其他部落格,關鍵詞linux VTIME */
    options.c_cc[VTIME] = 10; // 1s
    options.c_cc[VMIN] = 0; 

	/* 清空正讀的資料,且不會讀出 */
	tcflush(fd,TCIFLUSH); 
	
	/*采用原始模式通訊*/
	options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
	options.c_oflag &= ~OPOST;
	
	/*解決發送0x0A的問題*/
	// options.c_iflag &= ~(INLCR | ICRNL | IGNCR);
	// options.c_oflag &= ~(ONLCR | OCRNL | ONOCR | ONLRET);

	/* Update the options and do it NOW */
	if (tcsetattr(fd, TCSANOW, &options) != 0)
  	{
  		perror("SetupSerial 3");
		return -1;
	}

	return 0;
}

/**

*@breif 	main()

*/
int main(int argc, char **argv)
{
	int fd;
	int ret = -1;
	const char *dev = NULL;
	const char *test_string = NULL;
	char *p_buffer = NULL;
	int nread = 0;
	int nwrite = 0;
	
	/* 1、檢測傳參 */
	if (argc < 2 || argc > 3 ) {
		printf("Usage:%s dev_name [self_loop_test_string]\n", argv[0]);
		exit(1);
	}
	dev = argv[1];
	if (NULL != argv[2]) {
		if (strlen(argv[2]) <= BUF_SIZE) {
			test_string = argv[2];
		} else {
			printf("self_loop_test_string must be smaller than %d.\n", BUF_SIZE);
			return 0;
		}
	}
	
	/* 2、打開序列槽 */
	fd = open(dev, O_RDWR | O_NOCTTY | O_NONBLOCK);
	if (-1 == fd) {
		printf("Cannot open %s:%s\n", dev, strerror(errno));
		exit(1);
	}
	printf("==== open %s success ====\n", dev);
	
#if 1
	/* 3、初始化裝置 */
	if (-1 == set_speed(fd, DEF_BAUD)) {
		printf("Cannot set baudrate to 115200\n");
		close(fd);
		exit(1);
	}
	
  	if (-1 == set_parity(fd, 8, 1, 'N')) {
    	printf("Set Parity Error\n");
		close(fd);
    	exit(1);
  	}
#endif

	if (NULL != test_string) {
		/*開始自發自收測試*/
		/* 寫序列槽 */
		do {
			nwrite = write(fd, test_string, strlen(test_string));
		} while(nwrite <= 0);
		printf("send %d bytes data.\n", nwrite);

		/* 清空buffer */
		memset(buffer, 0, BUF_SIZE);
		p_buffer = buffer;
		nread = 0;

		/* 讀序列槽 */
		do {
			ret = read(fd, p_buffer, 64);
			if (ret > 0) {
				printf("read %d bytes data:%s\n", ret, p_buffer);
				p_buffer += ret;
				nread += ret;
			}
		} while(nread < nwrite);
		printf("all read %d bytes data:%s\n", nread, buffer);
		printf("====      test %s      ====\n", (0 == strcmp(buffer, test_string)) ? "success." : "error!!!");

		close(fd);
		return 0;
	}

	/*開始測試*/
	/*循環讀取并回寫序列槽内容*/
	printf("start read and pass back\n");
	while(1) {
		/* 清空buffer */
		memset(buffer, 0, BUF_SIZE);
		/* 讀序列槽 */
		nread = read(fd, buffer, 64);
		if(nread > 0) {
			printf("read %d bytes.\n", nread);
			do {
				ret = write(fd, buffer, nread);
			} while(ret <= 0);

			printf("write %d bytes.\n", ret);
		}

		//printf("block test.\n");
	}
	
	close(fd);
	
	return 0;
}
           

繼續閱讀