Linux系统下的UART测试程序详解 (linux uart测试程序)

引言

UART是一种常用的串行通信接口,常用于单片机和外围设备之间进行数据传输。Linux系统下提供了丰富的串口通信工具和库函数,可以非常方便地进行串口通信测试和开发。本文将介绍Linux系统下的UART测试程序,详细讲解其原理、实现和使用方法。

一、UART简介

UART(Universal Asynchronous Receiver/Tranitter)是一个通用异步串行接口,它可以支持异步传输和少量同步传输。在UART串口通信中,数据以字节为单位通过串行通信线路进行传输,通信线路包括一条单向数据线(TX)和一条单向接收线(RX),同时还有一个以上的控制线(如CTS、RTS等)。

在UART通信中,数据传输是以一定波特率进行的。波特率表示传输速率,即单位时间内传输的比特数。例如,对于波特率为9600 bps的UART串口通信,每秒可以传输9600个比特(即9600/8=1200个字节)的数据。波特率越高,传输速度越快,但是传输距离越短,误码率越高。

二、UART测试程序原理

Linux系统下提供了多种测试UART串口通信的工具和库函数,例如minicom、stty、termios等。这些工具和库函数都是基于系统调用函数编写的,主要目的是为了方便用户进行串口通信的测试和开发。而本文将介绍一种基于C语言的UART测试程序,它可以直接调用串口设备文件的读写函数进行数据的收发。具体原理如下:

1. 打开串口设备文件

在Linux系统下,每个串口都会被表示为一个设备文件,例如/dev/ttyS0、/dev/ttyS1等。在UART测试程序中,首先需要打开指定的串口设备文件,以便后续进行数据的读写。

2. 设置串口参数

在进行串口通信时,需要设置一些参数,如波特率、数据位、校验位、停止位等。通过串口控制寄存器,可以对这些参数进行设置。在UART测试程序中,可以通过调用tcgetattr和tcsetattr等函数设置指定的串口参数。

3. 发送数据

在UART测试程序中,可以通过调用write函数向串口发送数据。write函数会将指定的数据写入串口设备文件,发送给外部设备。

4. 接收数据

在UART测试程序中,可以通过调用read函数从串口接收数据。read函数会从串口设备文件中读取数据,存储到缓冲区中,供后续进行处理。

5. 关闭串口设备文件

在串口通信完成后,需要关闭打开的串口设备文件,以便下次进行访问。

三、UART测试程序实现

基于上述原理,可以编写C语言程序实现UART测试功能。下面给出一段完整的UART测试程序代码:

#include

#include

#include

#include

#include

int set_interface_attribs (int fd, int speed, int parity)

{

struct termios tty;

memset (&tty, 0, sizeof tty);

if (tcgetattr (fd, &tty) != 0)

{

perror (“error %s from tcgetattr”);

return -1;

}

cfsetospeed (&tty, speed);

cfsetispeed (&tty, speed);

tty.c_cflag = (tty.c_cflag & ~CSIZE) | CS8; // 8-bit chars

// disable IGNBRK for miatched speed tests; otherwise receive break

// as \000 chars

tty.c_iflag &= ~IGNBRK; // disable break processing

tty.c_lflag = 0; // no signaling chars, no echo,

// no canonical processing

tty.c_oflag = 0; // no remapping, no delays

tty.c_cc[VMIN] = 0; // read doesn’t block

tty.c_cc[VTIME] = 5; // 0.5 seconds read timeout

tty.c_iflag &= ~(IXON | IXOFF | IXANY); // shut off xon/xoff ctrl

tty.c_cflag |= (CLOCAL | CREAD);// ignore modem controls,

// enable reading

tty.c_cflag &= ~(PARENB | PARODD); // shut off parity

tty.c_cflag |= parity;

tty.c_cflag &= ~CSTOPB;

tty.c_cflag &= ~CRTSCTS;

if (tcsetattr (fd, TCSANOW, &tty) != 0)

{

perror (“error %s from tcsetattr”);

return -1;

}

return 0;

}

void set_blocking (int fd, int should_block)

{

struct termios tty;

memset (&tty, 0, sizeof tty);

if (tcgetattr (fd, &tty) != 0)

{

perror (“error %s from tggetattr”);

return;

}

tty.c_cc[VMIN] = should_block ? 1 : 0;

tty.c_cc[VTIME] = 5; // 0.5 seconds read timeout

if (tcsetattr (fd, TCSANOW, &tty) != 0)

perror (“error %s setting term attributes”);

}

int mn()

{

char buf[256];

int fd = open(“/dev/ttyS0”, O_RDWR | O_NOCTTY | O_SYNC);

if (fd

{

perror(“error opening”);

return -1;

}

set_interface_attribs(fd, B9600, 0); // set speed to 9600 bps, 8n1 (no parity)

set_blocking(fd, 0); // set no blocking

write(fd, “hello\n”, 6); // send 6 character greeting

usleep ((6 + 25) * 100); // sleep enough to tranit the 6 plus

// receive 25: approx 100 uS per char tranit

int n = read(fd, buf, sizeof buf); // read up to 100 characters if ready to read

printf(“received %d bytes: %s\n”, n, buf);

close(fd);

return 0;

}

本段代码中,首先通过调用open函数打开指定的串口设备文件(/dev/ttyS0),然后通过tcgetattr和tcsetattr函数设置串口参数(波特率为9600,数据位为8位,校验位为无,停止位为1位)。通过write函数向串口发送一条数据“hello\n”,并通过read函数从串口接收数据,存储到buf缓冲区中。

在进行编译时,需要将此代码保存为uart_test.c文件,并通过gcc命令进行编译:

$ gcc uart_test.c -o uart_test

四、UART测试程序使用方法

在Linux系统上,进行UART测试时需要先连接好串口线,将串口设备连接到计算机上。然后,执行上述编译好的uart_test程序即可进行测试。如果测试通过,可以在终端上看到接收到的数据。

需要注意的是,在Linux系统下,串口设备文件的权限可能需要进行修改才能进行读写操作。可以通过chmod命令进行修改,例如:

$ sudo chmod 666 /dev/ttyS0

这条命令将/dev/ttyS0串口设备文件的权限设置为666,即所有用户都有读写权限。

结论

相关问题拓展阅读:

linux下uart的文件节点是怎样创建的

(1)试验目的:掌握通过文件系统操作UART设备的方烂槐法.

  (2)在linux中,所有设备都是以文件的形式被打开并进行读/写慎橘操作的,本饥孝友试验中使用POSIX兼容的文件操作接口函数对底层设备进行操作.其中,POSIX是Portable Operating System Interface for UNIX的首字母缩写,是一套IEEE和ISO标准.

如何在S3C2440上linux操作系统下将串口的波特率提高以致921600

就是把串口的波特率提上去,硬件环境呢,就是采用飞凌的TE2440-II(比较古老了,大家勿喷)操作系统是linux2.6.28,大家都知道,正常情况下,Linux下串口波特率更高到115200,因为我们特殊需要的原因,需要把波特率提高到至少460800,当然最理想的结果就是波特率达到921600,大的背景就是这个样子了。

然后先考究硬件,看看在硬件上到底能不能满足我们的要求,主控芯片S3C2440,在UART一章说在系统时钟下,波特率更高可达115200,然后注释中说如果Pclk达到60M,可以实现921600,我就按他说的,将主频提高,顺便将pclk提高到了60M,发现921600根本实现不了,230400波特率虽然能通,但是错误率很高,根本无法用,然后我又尝试着将Pclk提高到了70M,通过这种饮鸩止渴的方式,波特率可以提高到230400并且稳定传输,但是更高的波特率则无法实现,而Pclk不能无限提高,因为我们开发板还连接了触摸屏,在Pclk70M的情况下,触摸屏经常重启,说明这个方案不可行,所以就pass掉了,下面简单说一下我怎么更改的系统时钟Fclk,Hclk,Pclk。这三个时钟的关系以及计算方法我就不赘述了,我主要参考博客

进行修改

1)首先找到bootloader中 INC文件夹下的Option.inc文件,打开以后,找到如下代码段,这段代码就是主频400M时对应的M,P和S值设置,需要更改主频的话虚野更改其中相应的数值几个(后来我发现,其实这个地方不改也行,因为最终起作用的是第二步)

CLKDIV_VAL EQU5

;1:4:8

M_MDIV EQU

127 ;127

M_PDIV EQU

2 ;2

M_SDIV EQU

1 ; 2440A

|

M_SDIV EQU

0 ; 2440X

>

>

2)找到u2440mon.c,然后在main()函数中找到如下代码,修改case2中的mpll_val = (92flags & UPF_SPD_MASK) == UPF_SPD_CUST)

quot = port->custom_divisor;

else

quot = s3c24xx_serial_getclk(port, &clksrc, &clk, baud);

/* check to see if we need to change clock source */

if (ourport->clksrc != clksrc || ourport->baudclk != clk) {

s3c24xx_serial_setsource(port, clksrc);

if (ourport->baudclk != NULL && !IS_ERR(ourport->baudclk)) {

clk_disable(ourport->baudclk);

ourport->baudclk = NULL;

}

clk_enable(clk);

ourport->clksrc = clksrc;

ourport->baudclk = clk;

}

其中,uart_get_baud_rate()函数用于计算出上位机程序到设置的波特率的值,经我调试得知,上位机波特率从2400到921600都可以被准确的计算出来;所以这个函数跳过,然后看最后那个if语句,这个语句的作用是产看目前的时钟源是否与设置的时钟源相同,如果不相同,则按照设置的时钟源进行更改,这里面还涉及linux下的关于管理时钟的一个结构体clk结构体,参照博客

以及

我找到了linux下的mach-dk2440.c这个文件,这个文件中定义了串口所用的clk结构体,这也是linux系统启动时对串口的初始化配置结构体都在这,但是我更改过这个地方,让他初始化配置是首选fclk作为串口的时钟源,但是我发现这并没有效果,所以继续寻找中。

这样就剩下一个函数可以考虑了,s3c24xx_serial_getclk(),进入这个函数你会发现,这个函数是对串口时钟及波特率一个全面的配置,进入这个函数中,就有个结构体tmp_clksrc,这个结构体很关键,他的内容如下:

static struct s3c24xx_uart_clksrc tmp_clksrc = {

.name = “pclk”,

.min_baud

= 0,

.max_baud

= 0,

.divisor

= 1,

};

从这个名字中就可以看出,它把串口的时钟源内定成为了pclk,这也是罪魁祸首,但是当我把name更改为fclk时,整个系统就无法启动了,包括前面说的更改mach-dk2440.c中初始化配置,也是无法启动,后来在配置串口是做了一个判断,当波特率低于202300时,才有系统源配置不变,当波特率高于202300时,不在采用tmp_clksrc这个结构体,而是采用我自己定义的一个结构体,当然就是把name改成fclk,发现虽然只是能够更改 里面部分参数的时钟源,而正在的时钟源还是pclk,说明我的更改根本么有生效,由于这个linux调用太庞杂了,我就抱着试试看的态度,也是没有办法的办法,在配置完串口时钟的代码之后,添加了如下几行代码,直接更改S3C2440的寄存器,我知道这样做是很不“道德”的,而且很容易引起系统混乱,但是我只是这么试试,没想到还真的有用。

在 samsung.c文件中添加

if (baud >=)

{

printk(“baud >=@samsung.c\n”);

__raw_writel(0x1fc5,S3C24XX_VA_UART0 + S3C2410_UCON);

__raw_writel(0x0fc5,S3C24XX_VA_UART1 + S3C2410_UCON);

__raw_writel(0x8fc5,S3C24XX_VA_UART2 + S3C2410_UCON);

__raw_writel(32,S3C24XX_VA_UART0 + S3C2410_UCON+0x24);//保证控制台的波特率还是115200用于显示

__raw_writel(3,S3C24XX_VA_UART1 + S3C2410_UCON+0x24);//921600

//__raw_writel(3,S3C24XX_VA_UART1 + S3C2410_UCON+0x24);

}

上面这段代码经我多次试验得到的,因为一开始用的系统主时钟fclk为400M,这样算出来UBRDIV1分频应该为3,但是这样的话错误率比较高,还是导致无法传输,至此我终于明白手册上为什么说pclk在60M 可以实现921600了,因为用60M时钟计算的话,分频UBRDIV1为3.069,最接近整数3,所以在这个错误率下可以实现921600的波特率传输,所以我将系统时钟fclk设置为420M,其中MDIV=97,PDIV=1,SDIV=1,而ucon0=0x1fc5,ucon1=0x0fc5,ucon2=0x8fc5,这样n=1+6=7,所以串口的时钟源为fclk/n=60M,可以得到精确的921600波特率,所以实现我刚开始的目标,其实要实现其他的波特率也可以,比如460800,计算后主时钟fclk(尽量算出的分频UBRDIV1最贴近整数),然后就可以实现了。

在这还有个小想法,提高串口波特率,还可以使用USB转串口,因为USB转串口可以实现921600,而linux中以及集成了USB转串口的驱动,只需要在调用串口的那个open函数中改为调用USB转串口的节点即可,当然,这个方案我没有试,因为我们就一个USB口,而且还被占用了,所以希望有需要的朋友可以试一下。

用 stty 命令 (使用前请确认你的终端设备确实支持这个速率), 比如

stty# 设置 baud rate 到

stty speed    # 查看当前终端 baud rate

# 如果不是设置当洞销前终端段游,则用下面的命令纳燃游设置指定终端设备

stty -F /dev/

88、四时田园杂兴范大成

88、四时田园杂兴 范大成

linux uart测试程序的介绍就聊到这里吧,感谢你花时间阅读本站内容,更多关于linux uart测试程序,Linux系统下的UART测试程序详解,linux下uart的文件节点是怎样创建的,如何在S3C2440上linux操作系统下将串口的波特率提高以致921600的信息别忘了在本站进行查找喔。


数据运维技术 » Linux系统下的UART测试程序详解 (linux uart测试程序)