单片机/MCU论坛
直播中

xiaopeng

11年用户 224经验值
擅长:嵌入式技术,处理器/DSP
私信 关注
[文章]

【HD-G2UL-EVM开发板体验】串口UART测试

说明

UART作为最常用的外设之一,通常在一些应用当中都起到了非常关键的作用,因此对其驱动和收发进行测试是非常有必要的。

端口确定

开发板上除了拥有type-C接口的调试串口外还引出了了另外3路uart接口,分别为COM1,COM2,COM3,如下:

图片.png

本次,我就使用COM1来进行收发测试。

程序

开发板配套的资料里面有对UART控制的例程,通过稍加改动就可以作为我们测试的程序。

main函数如下:

int main(int argc, char *argv[])
{
	int fd;
	char send_buffer[100] = "Hello HD-G2UL-EVM\r\n";
	char recv_buffer[100];
	int i, ret;

	if (argc != 2)    //需要传入串口对应的设备名
	{
		fprintf(stderr, "usage:serialtest com_port\n");
		return -1;
	}

	ret = serial_open(argv[1], 9600, SERIAL_PARITY_NO, 8, SERIAL_STOPBIT_ONE, 1000); //调用上面封装好的打开串口函数 传入设备名,波特率,校验位,数据位,停止位以及超时时间
	if (ret == 0)	//打开失败
	{
		fprintf(stderr, "open serial failed\n");
		return -1;
	}

/*	
	for(i=0; i<20; i++)  
	{
		send_buffer[i] = i;
	}	
*/	
	while(1)
	{
		serial_write(send_buffer, strlen(send_buffer));  //写入数据
		//read
		while (serial_poll(1000)>0)	//当另一端传入数据时会接收到数据
		{
			serial_read(recv_buffer, sizeof(recv_buffer));
		}
	}
	
	serial_close();	
	
	return 0;
}

先是调用serial_open函数对UART硬件进行初始化,其中设备名(串口号)需要作为参数传入,其它参数已经被程序指定死了,不可传入。默认波特率9600,8N1。

初始化完成后,进入while(1)循环中,循环发送字符串ello HD-G2UL-EVM,同时查看串口是否有小写接收到,若有则通过控制台打印出来。

其余部分代码如下:

#include <stdio.h>      /* Standard input/output */
#include <fcntl.h>      /* File control definitions */
#include <string.h>
#include <stdlib.h>
#include <termio.h>     /* POSIX terminal control definitions */
#include <sys/time.h>   /* Time structures for select() */
#include <unistd.h>     /* POSIX Symbolic Constants */
#include <assert.h>
#include <errno.h>      /* Error definitions */
#include <sys/mman.h>


#define  CMSPAR 010000000000  

#define SERIAL_FLUSH_TX		1       
#define SERIAL_FLUSH_RX		2

#define SERIAL_PARITY_NO        0
#define SERIAL_PARITY_ODD       1
#define SERIAL_PARITY_EVENT     2
#define SERIAL_PARITY_MARK      3
#define SERIAL_PARITY_SPACE     4

#define SERIAL_STOPBIT_ONE      1
#define SERIAL_STOPBIT_TWO      2

static int serial_fd  = -1;

struct termios old_tios;

static void serial_print_buf(unsigned char *buf,int len) /* 打印输出 */
{
	int i;
	for(i=0;i<len;i++)
		printf("%02X ",buf[i]);
	printf("\n");
}

char *get_serial_dev_name(char *serial_name)   /* 获取串口名称 */
{ 
	if (strcasecmp(serial_name, "COM2") == 0)	/* 传入参函数是COM2(不区分大小写),则返回串口对应的设备节点/dev/ttymxc1 */
		return "/dev/ttymxc1";
	else if (strcasecmp(serial_name, "COM3") == 0)
		return "/dev/ttymxc2";
	else if (strcasecmp(serial_name, "COM4") == 0)
		return "/dev/ttymxc3";
	else if (strcasecmp(serial_name, "COM5") == 0)
		return "/dev/ttymxc4 ";
	else
		//return NULL;
		return serial_name;
}

static int termios_init(struct termios *tios,int baud,int parity,int data_bits,int stop_bits) //串口 传入波特率,校验位,数据位,停止位。
{
	speed_t baud_rate;

	if (tios == NULL)
		return -1;

	tios->c_line  = 0;

	tios->c_cc[VMIN ] = 0;
	tios->c_cc[VTIME] = 0;

	/* configure the input modes... */
	tios->c_iflag =  IGNBRK | IGNPAR | INPCK;


	/* configure the output modes... */
	tios->c_oflag = 0;     /* enable implementation-defined output processing */
	/* configure the control modes... */
	tios->c_cflag = CREAD | CLOCAL; 
	
	if (data_bits == 5)      //对传入的数据位进行判断
		tios->c_cflag |= CS5;
	else if (data_bits == 6)
		tios->c_cflag |= CS6;
	else if (data_bits == 7)
		tios->c_cflag |= CS7;
	else if (data_bits == 8)
		tios->c_cflag |= CS8;
	else
		return -1;

	if (stop_bits == 1)		//对传入的停止位进行判断
		tios->c_cflag &=~ CSTOPB;
	else if (stop_bits == 2)
		tios->c_cflag |= CSTOPB;
	else
		return -1;

	if(parity == 0)			//校验位: 0:无校验 1:奇校验 2:偶校验 3:mark parity 4:space parity
	{ /* none */
		tios->c_cflag &=~ PARENB;
		tios->c_cflag &=~ PARODD;
	}
	else if(parity == 2)
	{ /* even */
		tios->c_cflag |= PARENB;
		tios->c_cflag &=~ PARODD;
	}
	else if(parity == 1)
	{ /* odd */
		tios->c_cflag |= PARENB;
		tios->c_cflag |= PARODD;
	}
    else if (parity == 3)/* 2008.12.17 add for support mark and space parity */
    {
        /* mark */
		tios->c_cflag |= PARENB;
		tios->c_cflag |= CMSPAR;
		tios->c_cflag |= PARODD;
    }
    else if (parity == 4)
    {
        /* space */
		tios->c_cflag |= PARENB;
		tios->c_cflag |= CMSPAR;
    }
	else
		return -1;

	/* configure the local modes... */
	tios->c_lflag = 0;    /* enable implementation-defined input processing   */

	/* Set the baud rate */
	switch(baud)			//对传入的波特率进行判断
	{
		case 110:
			baud_rate = B110;
			break;
		case 300:
			baud_rate = B300;
			break;
		case 600:
			baud_rate = B600;
			break;
		case 1200:
			baud_rate = B1200;
			break;
		case 2400:
			baud_rate = B2400;
			break;
		case 4800:
			baud_rate = B4800;
			break;
		case 9600:
			baud_rate = B9600;
			break;
		case 19200:
			baud_rate = B19200;
			break;
		case 38400:
			baud_rate = B38400;
			break;
		case 57600:
			baud_rate = B57600;
			break;
		case 115200:
			baud_rate = B115200;
			break;
		case 230400:
			baud_rate = B230400;
			break;
		case 460800:
			baud_rate = B460800;
			break;
		case 576000:
			baud_rate = B576000;
			break;
		case 921600:
			baud_rate = B921600;
			break;

		default:
			return -1;
	} 

	if ((cfsetispeed(tios, baud_rate) < 0) ||(cfsetospeed(tios, baud_rate) < 0))
		return -1;
	return 0;
}

//return serial fd, error return -1
int serial_open(char *serial_name, int baud,int parity,int data_bits,int stop_bits,int timeout)  //打开串口
{
	struct termios settings;
	int fd;
	char *serial_dev_name;

	if (serial_fd >= 0)
		return 0;
	if (termios_init(&settings, baud,parity,data_bits,stop_bits) < 0)
		return 0;

	
	serial_dev_name = get_serial_dev_name(serial_name);
	if (serial_dev_name == NULL)
	{
		fprintf(stderr, "invalid serial name:%s\n", serial_name);
		return 0;
	}

	if((fd = open(serial_dev_name, O_RDWR | O_NOCTTY | O_NDELAY))< 0)
		return 0;

	if(tcgetattr(fd, &old_tios) < 0)
	{
		close(fd);
		return 0;
	}

	if(tcsetattr(fd, TCSANOW, &settings) < 0)
	{
		close(fd);
		return 0;
	}

	serial_fd = fd;
	return 1;
}

int serial_close()   	//关闭串口
{
	if (serial_fd < 0)
		return 0;
	tcsetattr(serial_fd, TCSANOW, &(old_tios));
	close(serial_fd);
	serial_fd = -1;
    
	return 1;
}

int serial_flush(int flag)
{
	if (serial_fd < 0)
		return 0;

	if (flag == SERIAL_FLUSH_TX)
		tcflush(serial_fd,TCOFLUSH);
	else if (flag == SERIAL_FLUSH_RX)
		tcflush(serial_fd,TCIFLUSH);
	else if (flag == (SERIAL_FLUSH_RX|SERIAL_FLUSH_TX) )
		tcflush(serial_fd,TCIOFLUSH);
	return 1;
}

int serial_write(char *buf,size_t size)   //串口写入数据
{
	int writesize = 0;

	writesize = write(serial_fd,buf,size);
	//printf("serial write: length=%d, packet: ",writesize);
	//serial_print_buf(buf,writesize);
	return writesize;
}

int serial_read(char *buf,size_t size)   //串口读取数据
{
	int readsize = 0;

	if (size<=0)
		return 0;

	readsize = read(serial_fd,buf,size);
	printf("serial read: length=%d, packet: ",readsize);
	serial_print_buf(buf, readsize);
	return readsize;
}


//return 1: poll ok, 0: timeout, -1: error
int serial_poll(int timeout)
{
	int fd = serial_fd;
	
	fd_set rfds;
	struct timeval tv;
	int sel_res;

	FD_ZERO(&rfds);
	FD_SET(fd, &rfds);
	tv.tv_sec = timeout/1000;
	tv.tv_usec = (timeout % 1000)*1000;
	return select(fd + 1, &rfds, NULL,NULL,&tv);
}

编译运行

图片.png

运行

将可执行程序拷贝到开发板上,运行程序并传入串口设备名:

图片.png

同时可以看到串口助手上,不停的有消息打印出来:

图片.png

同时接收到的消息也可以通过控制台终端打印出来,如上图的控制台截图。

到此,说明UART的收发都是成功的。

结论

该程序运行后得到了预期的效果,下次将分享更多其它内容,欢迎阅读评论

更多回帖

发帖
×
20
完善资料,
赚取积分