linux串口测试例程

本文介绍了一种基于全志A64开发板的串口通信测试方法,包括自发自收测试和与电脑串口助手的交互测试。通过设置串口参数如波特率、数据位、停止位和校验位,实现稳定的数据收发。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

例程有两种基本用法

一、短接tx rx,自发自收

短接开发板待测串口的tx和rx,运行如下例程,

$ ./uart_test  /dev/ttyS1  "ti is loop test"

二、用电脑的串口助手进行收发测试

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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值