linux串口测试程序

合集下载

07实验七 Linux环境下的串行通信实验

07实验七 Linux环境下的串行通信实验

连接驱动器的使能端,使得当RTS设置成高(逻辑1)时,有效RS485驱动器;设置RTS为低 时,使驱动器处于三态,这时候实际上从总线上断开了驱动器,从而允许其他节点可以使 用同一传输线。当使用RTS时,必须确保发送数据前将RTS设置成高,在发送完数据的最 后一位后,将RTS线设成低。。另一种可选方法是自动发送数据控制。这种方法要求特殊 的电路,当数据传输时自动使能或无效驱动器。它减少了软件开销和程序员的潜在错误。
五、基础知识
串行通信 1、基本原理 串行端口的本质功能是作为CPU和串行设备间的编码转换器。当数据从CPU经过串行 端口发送出去时,字节数据转换为串行的位。在接收数据时,串行的位被转换为字节数据。 串口是系统资源的一部分,应用程序要使用串口进行通信,必须在使用之前向操作系统提 出资源申请要求(打开串口),通信完成后必须释放资源(关闭串口)。 2、串口通信的基本任务 (1) 实现数据格式化:因为来自CPU的是普通的并行数据,所以,接口电路应具有实 现不同串行通信方式下的数据格式化的任务。在异步通信方式下,接口自动生成起止式的 帧数据格式。在面向字符的同步方式下,接口要在待传送的数据块前加上同步字符。 (2) 进行串-并转换:串行传送,数据是一位一位串行传送的,而计算机处理数据是 并行数据。所以当数据由计算机送至数据发送器时,首先把串行数据转换为并行数才能送 入计算机处理。因此串并转换是串行接口电路的重要任务。 (3) 控制数据传输速率:串行通信接口电路应具有对数据传输速率——波特率进行选 择和控制的能力。 (4) 进行错误检测:在发送时接口电路对传送的字符数据自动生成奇偶校验位或其他 校验码。在接收时,接口电路检查字符的奇偶校验或其他校验码,确定是否发生传送错误。 (5) 进行TTL与EIA电平转换:CPU和终端均采用TTL电平及正逻辑,它们与EIA采用

嵌入式linux串口应用程序编写流程

嵌入式linux串口应用程序编写流程

嵌入式linux串口应用程序编写流程嵌入式Linux系统提供了丰富的串口接口,可以通过串口与其他设备进行通信,这为开发嵌入式系统提供了很多可能性。

下面是编写嵌入式Linux串口应用程序的流程:1. 确定串口设备:首先要确定要使用的串口设备,可以使用命令`ls /dev/tty*`来查看系统中可用的串口设备列表。

根据需要选择合适的串口设备。

2. 打开串口设备:在Linux系统中,使用文件的方式来操作串口设备。

可以使用C语言中的open函数来打开串口设备文件,并返回串口设备的文件描述符。

例如:`int serial_fd = open("/dev/ttyUSB0", O_RDWR | O_NOCTTY | O_NDELAY);`。

其中,`O_RDWR`表示以读写模式打开串口设备,`O_NOCTTY`表示打开设备后不会成为该进程的控制终端,`O_NDELAY`表示非阻塞模式。

3. 配置串口参数:打开串口设备后,需要配置串口参数,包括波特率、数据位、停止位、校验位等。

可以使用C语言中的termios库来进行串口参数的配置。

例如:```cstruct termios serial_config;tcgetattr(serial_fd, &serial_config);cfsetispeed(&serial_config, B115200);cfsetospeed(&serial_config, B115200);serial_config.c_cflag |= CS8;serial_config.c_cflag &= ~PARENB;serial_config.c_cflag &= ~CSTOPB;tcsetattr(serial_fd, TCSANOW, &serial_config);```上述代码将波特率设置为115200,数据位设置为8位,无校验位,一个停止位。

linux下的串口通信原理及编程实例

linux下的串口通信原理及编程实例

linux下的串⼝通信原理及编程实例linux下的串⼝通信原理及编程实例⼀、串⼝的基本原理1 串⼝通讯串⼝通讯(Serial Communication),是指外设和计算机间,通过数据信号线、地线等,按位进⾏传输数据的⼀种通讯⽅式。

串⼝是⼀种接⼝标准,它规定了接⼝的电⽓标准,没有规定接⼝插件电缆以及使⽤的协议。

2 串⼝通讯的数据格式 ⼀个字符⼀个字符地传输,每个字符⼀位⼀位地传输,并且传输⼀个字符时,总是以“起始位”开始,以“停⽌位”结束,字符之间没有固定的时间间隔要求。

每⼀个字符的前⾯都有⼀位起始位(低电平),字符本⾝由7位数据位组成,接着字符后⾯是⼀位校验位(检验位可以是奇校验、偶校验或⽆校验位),最后是⼀位或⼀位半或⼆位停⽌位,停⽌位后⾯是不定长的空闲位,停⽌位和空闲位都规定为⾼电平。

实际传输时每⼀位的信号宽度与波特率有关,波特率越⾼,宽度越⼩,在进⾏传输之前,双⽅⼀定要使⽤同⼀个波特率设置。

3 通讯⽅式单⼯模式(Simplex Communication)的数据传输是单向的。

通信双⽅中,⼀⽅固定为发送端,⼀⽅则固定为接收端。

信息只能沿⼀个⽅向传输,使⽤⼀根传输线。

半双⼯模式(Half Duplex)通信使⽤同⼀根传输线,既可以发送数据⼜可以接收数据,但不能同时进⾏发送和接收。

数据传输允许数据在两个⽅向上传输,但是,在任何时刻只能由其中的⼀⽅发送数据,另⼀⽅接收数据。

因此半双⼯模式既可以使⽤⼀条数据线,也可以使⽤两条数据线。

半双⼯通信中每端需有⼀个收发切换电⼦开关,通过切换来决定数据向哪个⽅向传输。

因为有切换,所以会产⽣时间延迟,信息传输效率低些。

全双⼯模式(Full Duplex)通信允许数据同时在两个⽅向上传输。

因此,全双⼯通信是两个单⼯通信⽅式的结合,它要求发送设备和接收设备都有独⽴的接收和发送能⼒。

在全双⼯模式中,每⼀端都有发送器和接收器,有两条传输线,信息传输效率⾼。

显然,在其它参数都⼀样的情况下,全双⼯⽐半双⼯传输速度要快,效率要⾼。

Linux串口测试程序

Linux串口测试程序

return g_PCUART_fd; }
uart_init int
( int COM, int BAUD, int databits, int stopbit, int paritybit )
{ int fd_uart;
struct termios options;
if( COM1 == COM ) {
/* ===============================================================================
********************
<lihf> linux串口测试代码
*******************
* Linux版本号2.6.23.17
printf("[ERROR]Uart databits is wrong! \n"); goto ↓uart_init_fail; }
switch( stopbit )
{
case 1 : options.c_cflag &= ~CSTOPB; break; //1位停止位 case 2 : options.c_cflag |= CSTOPB; break; //2位停止位
BAUD = B9600; }
if( cfsetospeed(&options, BAUD) < 0 )
{ printf("[fail] Set uart output baudrate fail!\n"); goto ↓uart_init_fail;
}
if( cfsetispeed(&options, BAUD) < 0 )

Linux C 串口编程

Linux C 串口编程

Linux C 串口编程arch/arm/include/asm/termbits.hstruct termios {tcflag_t c_iflag; /* input mode flags */tcflag_t c_oflag; /* output mode flags */tcflag_t c_cflag; /* control mode flags */tcflag_t c_lflag; /* local mode flags */cc_t c_line; /* line discipline */cc_t c_cc[NCCS]; /* control characters */ };串口的设置主要是设置struct termios结构体的各成员/***测试的时候应用程序在后台运行./serial_test &*/#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>#define DEVICE "/dev/s3c2410_serial0"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函数用于获取与终端相关的参数。

linux c语言串口非标准波特率

linux c语言串口非标准波特率

linux c语言串口非标准波特率在Linux系统中,使用C语言进行串口通信是一种常见的操作。

通常情况下,串口的波特率可以设置为标准的数值,例如9600、115200等。

但是有时候我们也会遇到一些特殊的情况,需要使用非标准的波特率。

本文将介绍如何在Linux系统中使用C语言进行串口通信,并设置非标准的波特率。

首先,我们需要包含一些头文件,以便在程序中使用串口相关的函数。

我们可以使用以下代码来包含这些头文件:```#include <stdio.h>#include <stdlib.h>#include <fcntl.h>#include <termios.h>#include <unistd.h>```接下来,我们需要打开串口设备。

使用open()函数可以打开串口设备。

```cint fd = open("/dev/ttyS0", O_RDWR | O_NOCTTY);if (fd < 0) {perror("Error opening serial port");return -1;}```在上述代码中,我们使用了"/dev/ttyS0"作为串口设备的文件路径。

根据实际情况,你可能需要使用其他的路径,比如"/dev/ttyUSB0"等。

接下来,我们需要配置串口的波特率。

我们可以使用termios结构体,并使用tcgetattr()函数和tcsetattr()函数来设置波特率。

```cstruct termios options;tcgetattr(fd, &options);cfsetispeed(&options, B57600);cfsetospeed(&options, B57600);tcsetattr(fd, TCSANOW, &options);```在上述代码中,我们将波特率设置为57600。

基于linux和Qt的串口通信调试器调的设计及应用

基于linux和Qt的串口通信调试器调的设计及应用

基于linux和Qt的串口通信调试器调的设计及应用摘要:目前基于Linux操作系统的应用开发越来越广泛,Qt是一个跨平台的C++图形用户界面应用程序框架,它可以开发基于Linux上的图形应用程序。

Linux操作系统对串行口提供了很好的支持,为了在Linux系统下能让串口与其它硬件设备方便直观地进行通信,本文介绍了在Ubuntu10.10系统平台Qt-4.7及Qt Creator2.0编程环境下串口调试界面的设计及程序的编写。

关键词:串口通信Linux QT1 Qextserialport 类介绍在Qt类库中并没有特定的串口基础类,现在很多人使用的是第三方写的qextserialport类,它是一个跨平台的串口类,可以很方便地在Qt 中对串口进行读写操作。

本文也使用了该类。

文件下载地址: /projects/qextserialport/files/下载到的文件名为qextserialport-1.2win-alpha。

在linux平台中,我们只需用到其中的四个文件:qextserialbase.cpp和qextserialbase.h以及posix_qextserialport.cpp和posix_qextserialport.h。

其中前两个文件定义了一个QextSerialBase 类,它提供了操作串口所必需的一些变量和函数等;后两个文件定义了一个Posix_QextSerialPort 类,Posix_QextSerialPort类添加了Linux平台下操作串口的一些功能。

2 串口的基本设置串口的基本参数在posix_qextserialport.cpp文件里的构造函数中进行设置,它的最后一个构造函数:Posix_QextSerialPort::Posix_QextSerialPort(const QString &amp; name, const PortSettings&amp;settings, QextSerialBase::QueryMode mode)它共有3个参数,第一个是串口名,第二个是对串口参数的基本设置,第三个是读取串口的方式。

linux c语言 串口读取数据的方法

linux c语言 串口读取数据的方法

linux c语言串口读取数据的方法Linux下使用C语言读取串口数据的方法引言:串口是计算机和外部设备进行通信的一种重要的通信接口。

在Linux系统中,要使用C语言读取串口数据,需要通过打开串口设备文件,设置串口参数,并进行读取数据的操作。

本文将介绍如何通过C语言在Linux下读取串口数据的方法。

目录:1. 了解串口的工作原理2. 打开串口设备文件3. 设置串口参数4. 读取串口数据5. 示例程序6. 总结1. 了解串口的工作原理:在开始编写C语言读取串口数据的方法前,首先需要了解串口的工作原理。

串口是通过硬件电路实现两台设备之间的数据传输,属于一种异步串行通信方式。

典型的串口包含发送数据引脚(TX)、接收数据引脚(RX)、数据位、停止位、奇偶校验位等。

2. 打开串口设备文件:在Linux系统中,每个串口设备都被映射到一个设备文件上,例如/dev/ttyS0代表第一个串口设备,/dev/ttyUSB0代表第一个USB串口设备。

要使用C语言读取串口数据,需要首先打开相应的串口设备文件。

在C语言中,使用open()函数打开串口设备文件。

open()函数的原型如下:cint open(const char *pathname, int flags);其中pathname参数指定要打开的串口设备文件路径,flags参数指定打开方式。

常用的flags参数有O_RDONLY(只读方式打开)、O_WRONLY (只写方式打开)和O_RDWR(读写方式打开)。

例如,要打开第一个串口设备文件,可以调用open()函数如下:cint fd = open("/dev/ttyS0", O_RDWR);if (fd == -1){perror("Error opening serial port");return -1;}当open()函数成功打开串口设备文件时,会返回一个非负整数的文件描述符fd,用于后续的操作。

linux odbc测试用例

linux odbc测试用例

linux odbc测试用例在Linux环境下,测试ODBC(开放数据库连接)的可用性和功能,可以遵循以下步骤:1. 安装ODBC相关软件包:在Linux系统中,可以使用软件包管理器(如apt、yum等)安装ODBC相关的软件包。

以安装FreeTDS(一个ODBC驱动程序)为例,使用以下命令:```sudo apt-get install freetds-dev```2. 配置ODBC数据源:创建一个ODBC数据源配置文件,例如:```sudo nano /etc/odbc.ini```在配置文件中添加以下内容(以SQL Server为例):```[odbc_data_source]Driver = /usr/lib/libtdsodbc.soServer = your_server_addressPort = your_portDatabase = your_databaseUser = your_usernamePassword = your_password```根据实际情况修改上述参数,保存并关闭文件。

3. 测试ODBC连接:使用以下命令测试ODBC连接:```sudo odbc_config --test```如果连接成功,您将看到类似以下内容的输出:```This is the ODBC SQL query test program.It attempts to connect to a database and execute a simple query. The output should contain the results of the query.--------SQL Setup:--------Driver: FreeTDSServer: your_server_addressPort: your_portDatabase: your_databaseUser: your_usernamePassword: your_password--------SQL Query:--------SELECT * FROM your_table--------Query Results:--------id | name1 | Alice2 | Bob3 | Charlie```如果输出显示了查询结果,那么恭喜!您已经成功测试了Linux ODBC。

linux下串口驱动测试程序

linux下串口驱动测试程序

linux下串口驱动测试程序2009-12-26 20:42:20| 分类:技术| 标签:|字号大中小订阅【转载时请注明文章出处:】为了测试串口驱动,我们需要用串口驱动测试程序先向串口写入数据,然后再从串口读出来,以证明串口驱动的正确性。

下面我们来分析一下串口驱动测试程序的流程。

1、串口程序需要的头文件#include <stdio.h> /*标准输入输出定义*/#include <stdlib.h> /*标准函数库定义*/#include <unistd.h> /*Unix 标准函数定义*/#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h> /*文件控制定义*/#include <termios.h> /*PPSIX 终端控制定义*/#include <errno.h> /*错误号定义*/2、打开串口设备fd = open( "/dev/ttyS0", O_RDWR); 我们以/dev/ttyS0即一般机子上的COM1为例。

3、设置串口设备:串口设备的设置主要通过struct termio的结构体来完成:struct termio{ unsigned short c_iflag; /* 输入模式标志 */unsigned short c_oflag; /* 输出模式标志 */unsigned short c_cflag; /* 控制模式标志*/unsigned short c_lflag; /* 当前模式标志 */unsigned char c_line; /* line discipline */unsigned char c_cc[NCC]; /* 控制字 */};我们用下面函数实现具体的串口设置:int setup_port(int fd, int baud, int databits, int parity, int stopbits){struct termio term_attr;if (ioctl(fd, TCGETA, &term_attr) < 0) { //将fd所对应的终端信息存入termio结构,得到当前配置return -1;}memcpy(&oterm_attr, &term_attr, sizeof(struct termio)); //保持当前配置到oterm_attr,用于系统恢复term_attr.c_iflag &= ~(INLCR | IGNCR | ICRNL | ISTRIP);term_attr.c_oflag &= ~(OPOST | ONLCR | OCRNL);term_attr.c_lflag &= ~(ISIG | ECHO | ICANON | NOFLSH);term_attr.c_cflag &= ~CBAUD;term_attr.c_cflag |= CREAD | speed_to_flag(baud); //设置波特率//标志各种标志可选范围term_attr.c_cflag &= ~(CSIZE); //设置数据位长度switch (databits) {case 5:term_attr.c_cflag |= CS5; //设置数据位长度为5,下同break;case 6:term_attr.c_cflag |= CS6;break;case 7:term_attr.c_cflag |= CS7;break;case 8:default:term_attr.c_cflag |= CS8;break;}switch (parity) { //设置奇偶校验位case 1:term_attr.c_cflag |= (PARENB | PARODD); //奇校验break;case 2:term_attr.c_cflag |= PARENB; //偶校验term_attr.c_cflag &= ~(PARODD);break;case 0:default:term_attr.c_cflag &= ~(PARENB); //不校验break;}switch (stopbits) { //设置停止位case 2: //有停止位为两位,下同term_attr.c_cflag |= CSTOPB;break;case 1:default:term_attr.c_cflag &= ~CSTOPB;break;}term_attr.c_cc[VMIN] = 1; //更新设置,并且立即完成term_attr.c_cc[VTIME] = 0; //设置超时if (ioctl(fd, TCSETAW, &term_attr) < 0) { //将更改后的属性加载到设备中return -1;}if (ioctl(fd, TCFLSH, 2) < 0) { //将输入输出队列全部发出,清空串口中队列return -1;}return 0;}4、向串口写入数据:while ( (len = read(0, buf, MAX_BUF_SIZE)) > 0 ) { if (len == 1) { //如果当前缓冲区为空,则写入停止位,发送buf[0] = MY_END_CHAR;buf[1] = 0;write_data(fd, buf, len);break;}i = write_data(fd, buf, len); //发送缓冲区内容if (i == 0) {fprintf(stderr, "Send data error!\n");break;}}5、从串口读数据:len = MAX_BUF_SIZE;while (1) {i = read_data(fd, buf, len); //从串口读取数据if (i > 0) {//count += i;//fprintf(stderr, "Recv %d byte\n", i);printf("%s", buf);if (buf[i-1] == MY_END_CHAR) { //如果读入的倒数第二位为停止位,则中断接受程序break;}}}在具体的测试中,在PC机上gcc编译程序,然后用arm-linux-gcc编程程序发送到友善之臂2440的板子上,然后一边发送一边接受,这样如果发送的数据和接受的数据相同,则测试成功。

linux调试串口程序,脱离硬件

linux调试串口程序,脱离硬件

linux调试串口程序,脱离硬件由于笔记本没有串口,同时没有硬件设备(串口或串口线),并且在ubuntu下不知道有没虚拟串口软件,想要在用虚拟机VM安装的ubuntu系统中调试程序,需要以下条件,VSPD软件(好像只有xp版)和串口调试助手。

Xp(COM3)与ubuntu(COM2)的串口通信调试:1、在XP下安装VSPD,增加一对串口COM2和COM3;2、在XP下运行串口调试助手UartAssist,测试串口是否能够正常使用;3、关闭(关机)ubuntu系统,点击菜单的“虚拟机”->“设置”->“添加”,在接下来的步骤中选择“串口”,选择“物理端口”,选择“COM2”,添加完成,确定。

启动ubuntu系统;4、在XP下用UartAssist连接上COM3,波特率9600,8,1;5、进入ubuntu系统(最好安装VM tools),在Ubuntu软件中心中搜索串口测试软件CuteCom,并安装,在“应用程序”-“ubuntu software center”中搜索选择“CuteCom”,运行(命令行中输入cutecom),Open串口“ttyS0”(这就是刚刚添加的COM2),设置波特率9600,8,1,打开串口;6、在CuteCom中输入hello,回车发送。

7、回到XP中,如果UartAssist正在监听COM3,那么会在UartAssist中接收到hello。

8、最终,xp中的UartAssist便可以和ubuntu中的CuteCom进行通信,便实现xp和linux 的串口通信。

(可以将两端的串口调试软件换成自己的代码)。

ubuntu(COM2)与ubuntu(COM3)串口通信调试:1、2、3、在上面的3的同时多添加一个COM口COM3。

4、这样就可以中ubuntu linux中使用两个串口程序进行串口调试。

Linux串口调试详解

Linux串口调试详解

Linux串⼝调试详解测试平台宿主机平台:Ubuntu 16.04.6⽬标机:iMX6ULL⽬标机内核:Linux 4.1.15⽬标机添加串⼝设备⼀般嵌⼊式主板的默认镜像可能只配置了调试串⼝,并⽤于 console 控制台打印;接下来对怎么样通过设备树来分配引脚⽤于⽤户串⼝通信进⾏描述;前提:⽬标机以及正常烧录 uboot、内核、⽂件系统、dtb等;本⽂仅更新设备树dtb⽂件;设备树⽂件修改在内核源码中找到相关板⼦对应的dtb⽂件;位置: arch/arm/boot/dts ⽬录下本⽂使⽤的板⼦相关⽂件有:imx6ull.dtsi // 官⽅通⽤板层dtsimys-imx6ull-14x14-evk.dts // 基于imx6ull-14x14-evk.dts模板修改mys-imx6ull-14x14-evk-gpmi-weim.dts // ⽤户层dts添加 uart3和uart4 的⽀持,修改 mys-imx6ull-14x14-evk.dts ⽂件如下pinctrl_uart2: uart2grp {fsl,pins = <MX6UL_PAD_UART2_TX_DATA__UART2_DCE_TX 0x1b0b1MX6UL_PAD_UART2_RX_DATA__UART2_DCE_RX 0x1b0b1>;};pinctrl_uart2dte: uart2dtegrp {fsl,pins = <MX6UL_PAD_UART2_TX_DATA__UART2_DTE_RX 0x1b0b1MX6UL_PAD_UART2_RX_DATA__UART2_DTE_TX 0x1b0b1MX6UL_PAD_UART3_RX_DATA__UART2_DTE_CTS 0x1b0b1MX6UL_PAD_UART3_TX_DATA__UART2_DTE_RTS 0x1b0b1>;};/* 增加uart3/4/5的引脚配置 */pinctrl_uart3: uart3grp {fsl,pins = <MX6UL_PAD_UART3_TX_DATA__UART3_DCE_TX 0x1b0b1MX6UL_PAD_UART3_RX_DATA__UART3_DCE_RX 0x1b0b1>;};pinctrl_uart4: uart4grp {fsl,pins = <MX6UL_PAD_UART4_TX_DATA__UART4_DCE_TX 0x1b0b1MX6UL_PAD_UART4_RX_DATA__UART4_DCE_RX 0x1b0b1>;};pinctrl_uart5: uart5grp {fsl,pins = <MX6UL_PAD_UART5_TX_DATA__UART5_DCE_TX 0x1b0b1MX6UL_PAD_UART5_RX_DATA__UART5_DCE_RX 0x1b0b1>;};...../* 使能串⼝ */&uart1 {pinctrl-names = "default";pinctrl-0 = <&pinctrl_uart1>;status = "okay";};&uart2 {pinctrl-names = "default";pinctrl-0 = <&pinctrl_uart2>;/*fsl,uart-has-rtscts;*//* for DTE mode, add below change *//* fsl,dte-mode; *//* pinctrl-0 = <&pinctrl_uart2dte>; */status = "disabled";};/* 增加使⽤串⼝,其中使能3、关闭4/5 */&uart3 {pinctrl-names = "default";pinctrl-0 = <&pinctrl_uart3>;status = "okay";};&uart4 {pinctrl-names = "default";pinctrl-0 = <&pinctrl_uart4>;status = "okay";};/* 这⾥必须注意⼀点,由于UART5和I2C2接⼝的引脚是复⽤的,I2C2默认是使能的所以必须禁⽤I2C2,再使能UART5. */&uart5 {pinctrl-names = "default";pinctrl-0 = <&pinctrl_uart5>;status = "disabled";};然后重新编译⽣成设备树 dtb ⽂件cp arch/arm/configs/mys_imx6_defconfig .configmake ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- dtbs⽣成的 dtb ⽂件:arch/arm/boot/dts/mys-imx6ull-14x14-evk-gpmi-weim.dtb设备树⽂件更新采⽤ MFGTool2 进⾏设备树更新,怎么单独仅更新设备树参见mys-imx6ull-14x14-evk-gpmi-weim.dtb 替换 /Profiles/Wh Linux Update/OS Firmware/files/ 下⾯的 dtb⽂件然后执⾏ mfgtool2-linux-mys-6ulx-nand-dtb.vbsSet wshShell = CreateObject("WScript.shell")wshShell.run "mfgtool2.exe -c ""Wh Linux Update"" -l ""NAND-dtb"" -s ""lite=l"" -s ""6uluboot=14x14evk"" -s ""nand=nand"" -s ""6uldtb=14x14-evk"" -s ""nanddtb=gpmi-weim"" -s ""part_uboot=0"" -s ""part_kernel=1"" -s ""part_dtb=2"" Set wshShell = Nothing更新成功,设备重启之后,看到添加的串⼝设备已⽀持,串⼝驱动实现框架另外的⽂章在分析;串⼝应⽤编程1.串⼝相关操作在Linux下,除了⽹络设备,其余的都是⽂件的形式,串⼝设备也⼀样在/dev下。

简单的Linux串口通信程序

简单的Linux串口通信程序

int fd; /*以读写方式打开串口*/ fd = open( "/dev/ttyS0", O_RDWR); if (-1 == fd){ perror("error"); }
17:43
3. 设置串口
最基本的设置串口包括波特率设置,校验位和停止位设置,数 据位。串口的设置主要是设置struct termios结构体的各成员值。
1
• 实验步骤
– 1.阅读理解源码
• 源码位置:serial\serial.c • 阅读源码方法
– Linux下使用gedit编辑器 – windows下使用SourceInsight软件
– 2.编译应用程序
2
【基础知识】
Linux操作系统从一开始就对串行口提供了很好的支持,为进行
串行通讯提供了大量的函数,本实验主要是为掌握在Linux中进行 串行通讯编程的基本方法。
2. 打开串口
在Linux 下串口文件是位于/dev 下,com1为/dev/ttyS0 ,com2 为/dev/ttyS1 操作系统 串口1 Windows COM1 Linux /dev/ttyS0 串口2 COM2 /dev/ttyS1 USB/RS-232转换器 /dev/ttyUSB0
打开串口是通过使用标准的文件打开函数操作:
struct termios { unsigned short c_iflag; /* 输入模式标志*/ unsigned short c_oflag; /* 输出模式标志*/ unsigned short c_cflag; /* 控制模式标志*/ unsigned short c_lflag; /* local mode flags */ unsigned char c_line; /* line discipline */ unsigned char c_cc[NCC]; /* control characters */ };

linux 串口读写例程

linux 串口读写例程

在 Linux 系统中,你可以使用 C/C++ 编程语言来进行串口的读写操作。

下面是一个简单的示例代码,展示了如何在 Linux 中使用串口进行数据的读取和写入:```c#include <stdio.h>#include <stdlib.h>#include <string.h>#include <fcntl.h>#include <unistd.h>#include <termios.h>int main() {int serial_port = open("/dev/ttyS0", O_RDWR); // 打开串口设备(根据实际情况修改串口号)if (serial_port < 0) {perror("无法打开串口设备");return -1;}struct termios tty;memset(&tty, 0, sizeof(tty));if (tcgetattr(serial_port, &tty) != 0) {perror("无法获取串口属性");return -1;}// 设置串口属性tty.c_cflag &= ~PARENB; // 禁用奇偶校验tty.c_cflag &= ~CSTOPB; // 设置停止位为 1tty.c_cflag |= CS8; // 设置数据位为 8tty.c_cflag &= ~CRTSCTS; // 禁用硬件流控制tty.c_cflag |= CREAD | CLOCAL; // 启用读取和忽略 Modem 控制信号tty.c_iflag &= ~(IXON | IXOFF | IXANY); // 禁用软件流控制tty.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); // 设置为原始模式tty.c_oflag &= ~OPOST; // 禁用输出处理tty.c_cc[VMIN] = 0; // 读取的最小字符数tty.c_cc[VTIME] = 10; // 读取超时时间(单位:0.1秒)if (tcsetattr(serial_port, TCSANOW, &tty) != 0) {perror("无法设置串口属性");return -1;}// 写入数据char write_buffer[] = "Hello, serial port!";int bytes_written = write(serial_port, write_buffer, sizeof(write_buffer));if (bytes_written < 0) {perror("写入数据失败");return -1;}// 读取数据char read_buffer[256];int bytes_read = read(serial_port, read_buffer, sizeof(read_buffer));if (bytes_read < 0) {perror("读取数据失败");return -1;}// 输出读取到的数据printf("读取到的数据:%s\n", read_buffer);close(serial_port); // 关闭串口设备return 0;}```请注意,上述代码需要在 Linux 系统下编译运行。

Linux下使用可视化的串口调试工具cutecom

Linux下使用可视化的串口调试工具cutecom

Linux下使⽤可视化的串⼝调试⼯具cutecom
 在Ubuntu下想直接使⽤像Windows下串⼝调试助⼿⼀样的⼯具。

之前在Fedora下⽤过minicom,不过界⾯还是不够友好。

调试助⼿最重要的就是串⼝连接参数的配置,然后处理数据的收和发即可。

1.软件安装
在Ubuntu下的安装很简单,打开终端,使⽤sudo apt-get install cutecom安装即可。

2.运⾏程序
打开终端,⽤sudo cutecom命令来打开,打开界⾯如下。

3.设置
(1)基本设置
波特率设置为115200,其余的保持默认配置即可;
(2)查找串⼝
连接串⼝到电脑,在终端输⼊dmesg | grep ttyS*指令,会列出拔插的串⼝状态,如下图所⽰
这⾥显⽰串⼝ttyS0接⼊到了系统⾥
(3)连接串⼝
在device⼀栏选择ttyS0,如果列表⾥没有,则直接⼿动输⼊即可,然后点击open device(软件左上⾓按键)即可连接
(4)关闭连接
点击close device(软件左上⾓按键)可以关闭当前的连接
4.传输数据
配置好设置打开串⼝后,就可以进⾏收发数据了。

Linux串口select编程

Linux串口select编程

Linux下串口程序开发串行口是计算机一种常用的接口,具有连接线少,通讯简单,得到广泛的使用。

常用的串口是RS-232-C接口(又称EIA RS-232-C)它是在1970年由美国电子工业协会(EIA)联合贝尔系统、调制解调器厂家及计算机终端生产厂家共同制定的用于串行通讯的标准。

它的全名是"数据终端设备(DTE)和数据通讯设备(DCE)之间串行二进制数据交换接口技术标准"该标准规定采用一个25个脚的DB25连接器,对连接器的每个引脚的信号内容加以规定,还对各种信号的电平加以规定。

传输距离在码元畸变小于4%的情况下,传输电缆长度应为50英尺。

在linux文件中,所有的设备文件一般都位于/dev下,其中串口一、串口二分别对应的设备名依次为“/dev/ttyS0”、“/dev/ttyS1”,可以查看在/dev下的文件以确认。

在linux下面对于串口的读写就可以通过简单的read、write函数来完成,所不同的是只是需要对串口的其他参数另坐配置。

1.串口编程需要用到的头文件#include <stdio.h> // 标准输入输出定义#include <stdlib.h>#include <fcntl.h> // 文件控制定义,主要完成串口通信中对文件的读写操作#include <unistd.h> // linux标准函数定义#include <sys/ioctl.h>#include <termios.h> // POSIX终端控制定义#include <sys/time.h>#include <sys/types.h>2.串口终端函数2.1打开串口设备int fd;char *device = "/dev/tts/0"; // 设备路径,初始使用UART0for(t=1;t<argc;t++) // 获取程序入口时输入的参数{if(!strcmp(argv[t],"-d") && (argc > (t+1))){device = argv[t+1];}}if(!strcmp(device,"/dev/tts/1")) // 不允许使用UART1,因为它已和PC相连。

linux 读取串口数据方法

linux 读取串口数据方法

linux 读取串口数据方法【原创实用版2篇】目录(篇1)一、Linux 读取串口数据的方法概述二、使用 C 语言读取串口数据三、使用 Qt 库读取串口数据四、使用 Python 读取串口数据五、总结正文(篇1)一、Linux 读取串口数据的方法概述在 Linux 系统中,串口是一种常用的设备接口,可以用于接收和发送数据。

Linux 提供了多种方法来读取和操作串口数据。

本文将介绍几种常见的方法,包括使用 C 语言、Qt 库和 Python 语言来读取串口数据。

二、使用 C 语言读取串口数据1.打开串口在 C 语言中,打开串口需要使用 fcntl 函数。

首先,需要包含头文件<fcntl.h>和<termios.h>。

然后,使用以下代码打开串口:```cint fd = open("/dev/ttyS0", O_RDWR);if (fd < 0) {perror("Can"t Open Serial Port");return -1;}```2.设置串口速度打开串口成功后,需要设置串口的波特率、数据位、校验位和停止位等参数。

可以使用以下代码设置串口速度:```cstruct termios tty;if (tcgetattr(fd, &tty)!= 0) {perror("Can"t Get Serial Port Attributes");return -1;}tty.c_cflag &= ~PARENB; // 清除奇偶校验位tty.c_cflag &= ~CSTOPB; // 使用一个停止位tty.c_cflag |= CS8; // 8 位数据位tty.c_cflag &= ~CRTSCTS; // 禁用硬件流控制tty.c_cflag |= CREAD | CLOCAL; // 使能读和忽略 modem 控制线if (tcsetattr(fd, TCSANOW, &tty)!= 0) {perror("Can"t Set Serial Port Attributes");return -1;}```3.读取串口数据使用以下代码读取串口数据:char buf[64];int len = read(fd, buf, sizeof(buf));if (len < 0) {perror("Can"t Read from Serial Port");return -1;}printf("Read data: %s", buf);```三、使用 Qt 库读取串口数据在 Qt 中,可以使用 QSerialPort 类来读取串口数据。

linux 标准dma 测试指令

linux 标准dma 测试指令

linux 标准dma 测试指令在Linux系统中,DirectMemoryAccess(DMA)是一种数据传输方式,它允许硬件设备直接访问内存,而无需通过CPU进行干预。

这种机制可以提高数据传输的效率,特别是在需要大量数据传输的场景下。

然而,DMA操作也有可能引发安全问题,因此对DMA的测试至关重要。

在Linux中,有多种指令可用于测试DMA。

其中最常用的是“dma_test_device”指令,该指令可用于测试DMA控制器和设备之间的通信。

该指令通常需要以root权限运行,以确保足够的权限来进行测试。

要使用dma_test_device指令,请按照以下步骤操作:1.打开终端并切换到root用户。

2.运行以下命令以测试DMA设备:```shellsudodma_test_device<device_name><channel>```其中,<device_name>是你要测试的设备的名称,<channel>是DMA通道号。

例如,如果要测试硬盘控制器上的DMA设备,可以使用以下命令:```shellsudodma_test_device/dev/sdX<channel>```其中X是硬盘设备的字母标识符(例如,/dev/sda)。

dma_test_device指令将执行一系列测试,包括检查DMA传输的正确性、检查设备中断处理程序的正确性,以及检查DMA缓冲区的正确性。

如果测试通过,则表示DMA设备正常工作。

除了dma_test_device指令外,还有其他一些LinuxDMA测试指令,如“dma_alloc_coherent”和“dma_free_coherent”等。

这些指令可用于创建和释放DMA缓冲区,以验证DMA操作的正确性。

在进行DMA测试时,请务必小心,确保只测试已知安全的设备和通道。

此外,还应该定期更新Linux系统和驱动程序,以确保获得最新的安全补丁和修复。

Linux下串口协议控制51单片机

Linux下串口协议控制51单片机

linux下串口协议控制51单片机(涉及多线程操作)/***************************************************************************writen by jingshui 7-17 2011 12:53说明:这是一个linux下串口,多线程测试程序Version 0.26***************************************************************************/ # include <stdio.h># include <unistd.h># include <stdlib.h># include <termios.h># include <fcntl.h># include <string.h># include <sys/time.h># include <sys/types.h># include <pthread.h>int fd;pthread_t thread[2];pthread_mutex_t mutex;/**************************************************************************** 结构体说明:传送控制单片机的信息成员1:select 选择功能模块成员2:control 控制单片机相应的动作*****************************************************************************/ struct protocal{unsigned char select;unsigned char control;};struct protocal ptr[14]={{0xa1,0x01},{0xa1,0x02},{0xa1,0x03},{0xa1,0x04},{0xa1,0x05},{0xa1,0x06},{0xa1,0x07},{0xa1,0x08},{0xb2,0x00},{0xb2,0x03},{0xb2,0x06},{0xb2,0x09},{0xb2,0x0e},{0xc3,0xd4}};/********************************************************************功能说明:设置linux串口参数传入参数:fd nspeed nbit nevent nstop文件句柄波特率数据位奇偶校验停止位返回值: fd 文件句柄********************************************************************/int set_port(int fd ,int nspeed ,int nbits ,char nevent ,int nstop){struct termios newtio,oldtio;if (tcgetattr(fd,&oldtio)!= 0){perror("setup serial");return -1;}bzero(&newtio,sizeof(newtio));newtio.c_cflag |= CLOCAL|CREAD;newtio.c_cflag &= ~CSIZE;switch (nbits){case 7:newtio.c_cflag |= CS7;break;case 8:newtio.c_cflag |= CS8;break;}switch (nevent){case 'N':newtio.c_cflag &= ~PARENB;break;}switch (nspeed){case 9600:cfsetispeed(&newtio,B9600);cfsetospeed(&newtio,B9600);break;}switch (nstop){case 1:newtio.c_cflag &= ~CSTOPB;break;case 2:newtio.c_cflag |= CSTOPB;break;}newtio.c_cc[VTIME]= 0;newtio.c_cc[VMIN]= 14;tcflush(fd,TCIFLUSH);if ((tcsetattr(fd,TCSANOW,&newtio))!= 0){perror("com set");return -1;}return 0;}int open_port(int fd,int comport){if (comport == 1){fd = open ("/dev/ttyUSB0",O_RDWR);if ( -1 == fd ){perror("can't open serial port");return -1;}}return fd;}void write_port(void){int nwrite,i;for (i=0;i<14;i++){nwrite = write(fd,&ptr[i],2);usleep(200000);/*每200ms秒发一次数据*/}}void read_port(void){fd_set rd;int nread,retval;unsigned char msg[14];struct timeval timeout;FD_ZERO(&rd);FD_SET(fd,&rd);_sec = 1;_usec = 0;retval = select (fd+1,&rd,NULL,NULL,&timeout);/*select 实现i/o复用*/ switch (retval){case 0:printf("no data input within 1 seconds.\n");break;case -1:perror("select");break;default:if((nread=read(fd,msg,14))>0){printf("nread=%d,msg=%s\n",nread,msg);}break;}}void *recv_thread(void ){pthread_mutex_lock(&mutex);read_port();pthread_mutex_unlock(&mutex);pthread_exit(NULL);}void *send_thread(void ){pthread_mutex_lock(&mutex);write_port();pthread_mutex_unlock(&mutex);pthread_exit(NULL);}void create_thread(void ){int temp;memset(thread, 0, sizeof(thread));if((temp = pthread_create(&thread[0], NULL,(void *)send_thread, NULL)) != 0) printf("create send_thread failed!\n");if((temp = pthread_create(&thread[1], NULL,(void *)recv_thread, NULL)) != 0) printf("create recev_thread failed!\n");}void wait_thread(void ){if(thread[0] !=0){pthread_join(thread[0],NULL);printf("send_thread end\n");}if(thread[1] !=0){pthread_join(thread[1],NULL);printf("recev_thread end\n");}}int main(void ){int i;if((fd=open_port(fd,1))<0){perror("open_port error");}if((i=set_port(fd,9600,8,'N',1))<0){perror("set_opt error");}/*用默认属性初始化互斥锁*/pthread_mutex_init(&mutex,NULL);int num = 100;while (num){create_thread();wait_thread();num--;}pthread_mutex_destroy(&mutex);close(fd);return 0;}51单片机程序#include <reg52.h>typedef unsigned char uint8;typedef unsigned int uint16;sbit key = P3^2;sbit s1 = P2^0; //选通数码管1sbit s2 = P2^1;sbit s3 = P2^2;sbit s4 = P2^3;sbit en = P2^5; //573锁存使能位sbit buzzer = P2^4; //蜂鸣器选通位sbit key1 = P3^2;sbit key2 = P3^3;sbit key3 = P3^4;sbit key4 = P3^5;sbit key5 = P3^7;uint8 i=0;uint8 r_data[2]; //用来接收数据的缓冲区uint8 code smg[16] = {0xC0,0xF9,0xA4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0x88,0x83,0xc6,0xa1,0x86,0x8e}; unsigned char code pmd[8] = {0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f};unsigned char code s_data1[]="key1 pressed\n";unsigned char code s_data2[]="key2 pressed\n";unsigned char code s_data3[]="key3 pressed\n";unsigned char code s_data4[]="key4 pressed\n";unsigned char code s_data5[]="key5 pressed\n";void init_serial(void) //初始化串口{TMOD = 0x20; //设置定时器1工作方式1;TH1 = 0xFD; //波特率发生器,产生9600的波特率TL1 = 0xFD;PCON = 0x00;SCON = 0x50; //选择串口工作方式1,允许接收EA = 1; //开中断ES = 1;TR1 = 1; //启动定时器}void delay(uint16 i)//20ms{unsigned char j,k;for(j=i;j>0;j--)for(k=115;k>0;k--);}void test_serial1(void ){int i;EA=0;for(i=0;i<sizeof(s_data1);i++){SBUF=s_data1[i];while(TI==0);TI=0;}EA=1;}void test_serial2(void ){int i;EA=0;for(i=0;i<sizeof(s_data2);i++){SBUF=s_data2[i];while(TI==0);TI=0;}EA=1;}void test_serial3(void ){int i;EA=0;for(i=0;i<sizeof(s_data3);i++){SBUF=s_data3[i];while(TI==0);TI=0;}EA=1;}void test_serial4(void ){int i;EA=0;for(i=0;i<sizeof(s_data4);i++){SBUF=s_data4[i];while(TI==0);TI=0;EA=1;}void test_serial5(void ){int i;EA=0;for(i=0;i<sizeof(s_data5);i++){SBUF=s_data5[i];while(TI==0);TI=0;}EA=1;}void led_control(uint8 i) //led控制模块{unsigned char x;if (i>8){P1 = 0xff;delay(10);}else{x = i-1;P1 = pmd[x];delay(80);P1 = 0xff;}}void seg_control(uint8 i) //数码管控制模块{en = 1;s1 = 0;s3 = 0;s2 = 0;s4 = 0;if (i>0x0f)P0 = 0xff;delay(10);}else{P0 = smg[i];delay(80);P0 = 0xff;}}void buzzer_control(uint8 i) //蜂鸣器控制模块{if (i == 0xd4)buzzer = 0;delay(100);buzzer = 1;}void handle_date(){uint8 i = r_data[0];switch(i){case 0xa1:led_control(r_data[1]);break;case 0xb2:seg_control(r_data[1]);break;case 0xc3:buzzer_control(r_data[1]);default:break;}}void readkey(void){RI=0;if(!key1)delay(30);if(!key1){test_serial1();while(!key1);}}if(!key2){delay(30);if(!key2){test_serial2();while(!key2);}}if(!key3){delay(30);if(!key3){test_serial3();while(!key3);}}if(!key4){delay(30);if(!key4){test_serial4();while(!key4);}}if(!key5){delay(30);if(!key5){test_serial5();while(!key5);}}}void main(void ){init_serial();while(1){readkey();}}void server(void ) interrupt 4{ES = 0;RI = 0;r_data[i] = SBUF;if(2 == ++i){handle_date();i = 0;}ES = 1;}/****************************************************************************** *writen by jingshui说明:51单片机检测程序,把从上位机接收的数据发回去。

linux 串口 poll() 工作原理

linux 串口 poll() 工作原理

linux 串口 poll() 工作原理Linux的串口poll()函数是一种用于监测串口设备状态的机制。

它可以用于检测串口是否有数据可读或是否可以写入数据。

在本文中,我们将详细介绍Linux串口poll()函数的工作原理。

我们需要了解什么是串口。

串口是一种用于在计算机和外部设备之间传输数据的接口。

在Linux系统中,串口通常被表示为特殊文件,例如/dev/ttyS0或/dev/ttyUSB0。

通过这些特殊文件,我们可以读取和写入串口数据。

在Linux系统中,我们可以使用poll()函数来监测串口的状态。

poll()函数是一个系统调用,它可以等待一个或多个文件描述符(包括串口文件描述符)上的事件发生。

当有事件发生时,poll()函数将返回,并告诉我们哪个文件描述符上发生了事件。

在使用poll()函数之前,我们需要创建一个pollfd结构体数组,并将需要监测的串口文件描述符加入到数组中。

pollfd结构体定义如下:```cstruct pollfd {int fd; // 文件描述符short events; // 要监测的事件(读、写或错误)short revents; // 实际发生的事件};```在创建pollfd结构体数组后,我们需要设置需要监测的事件。

在串口中,我们通常需要监测以下事件:- POLLIN:表示文件描述符上有数据可读。

- POLLOUT:表示文件描述符上可以写入数据。

- POLLERR:表示文件描述符上发生了错误。

在设置完事件后,我们可以调用poll()函数来等待事件的发生。

poll()函数的原型如下:```cint poll(struct pollfd *fds, nfds_t nfds, int timeout);```其中,fds是指向pollfd结构体数组的指针,nfds是数组中的文件描述符数量,timeout是等待的超时时间(以毫秒为单位)。

如果timeout为负数,则表示无限等待,直到有事件发生为止。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

linux串口测试程序
由于已经完成了第一个HELLO程序,标志着整个编译环境已经没有问题了,下来准备做一下串口测试程序。

由于串口驱动开发板已经作好了,所以就作一个Linux串口测试工具简单的数据收发看看。

Linux串口测试工具网上常见的版本都看起来比较烦琐,下面是一个简单一点的,这个程序功能是收到10个字节后会发前7个字节,如果所发的数据的第一个字节是9则退出。

#include #include #include #include #include #include #include #include
#define BAUDRATE B9600 #define MODEMDEVICE "/dev/ttyUSB1"
int main()
{ int fd,c=0,res;struct termios oldtio,newtio;//intch;static char s1[10],buf[10];printf("start ……\n");/*打开PC的COM1口*/ fd = open(MODEMDEVICE,O_RDWR|O_NOCTTY);if (fd < 0)
{ perror(MODEMDEVICE);exit(1);} printf("open……\n");/*将旧的通讯参数存入oldtio结构*/ tcgetattr(fd,&oldtio);/*初始化新的newtio */ bzero(&newtio,sizeof(newtio));/*8N1*/ newtio.c_cflag = BAUDRATE|CS8|CLOCAL|CREAD;newtio.c_iflag = IGNPAR;newtio.c_oflag = 0;/*正常模式*/ /*newtio.c_lflag = ICANON;*/
/*非正常模式*/ newtio.c_lflag = 0;newtio.c_cc[VTIME] = 0;newtio.c_cc[VMIN] = 10;
tcflush(fd,TCIFLUSH);/*新的temios作为通讯端口参数*/ tcsetattr(fd,TCSANOW,&newtio);printf("writing……\n");
while(1)
{ //printf("read……\n");res = read(fd,buf,10);//res = read(fd,s1,10);//strcat(buf,s1);// res = write(fd,buf,7);printf("buf = %s\n",buf);if(buf[0]==9) break;}
printf("close……\n");close(fd);/*还原旧参数*/ tcsetattr(fd,TCSANOW,&oldtio);return 0;}
还有一点要注意,就是Linux串口测试工具串口有两种工作模式,即正规模式和非正规模式,如果习惯在串口调试器中用16进制发送,此时串口应该为非正规模式才行。

下面是这两种模式的说明Linux串口测试工具正规模式(CANONICAL或者COOKED)
此模式下,终端设备会处理特殊字符,并且数据传输是一次一行的方式,既按回车后才开始发送和接收数据。

例如LINUX的SHELL. Linux串口测试工具非正规模式(NON-CANONICAL
或者RAW)
此模式下,终端设备不会处理特殊字符,并且数据传输是一次一个字符的方式,既不用按回车换行。

例如LINUX的VIM.。

相关文档
最新文档