Linux驱动之串口驱动程序分析
- 格式:pdf
- 大小:350.75 KB
- 文档页数:22
基于Linux操作系统下串口调试助手的设计黎爱琼;陈家林;谈宏华【摘要】为了方便在Linux操作系统下进行串口调试以及能在嵌入式系统开发板上直观地观察到串行数据传输,在Redhad 9.0下的Qt Designer编程环境下设计了串口调试助手.首先在Qt下以一种图形化的编程方式完成串口调试助手界面的设计,再将其生成源代码,然后在源代码中添加串口驱动,完成串口调试助手的设计.经实践证明,该串口调试助手在Redhad 9.0操作系统上运行良好.利用交叉编译程序将其移植到S3C2410的Linux 2.4上后也能够正常运行极大地方便了调试工作.【期刊名称】《现代电子技术》【年(卷),期】2006(029)016【总页数】3页(P88-90)【关键词】嵌入式系统;Linux操作系统;Qt;串口驱动【作者】黎爱琼;陈家林;谈宏华【作者单位】武汉工程大学,湖北,武汉,430073;武汉工程大学,湖北,武汉,430073;武汉工程大学,湖北,武汉,430073【正文语种】中文【中图分类】TN873串口是计算机一种应用广泛的接口,几乎在每种操作系统以及需要进行数据传送的装置上都支持串口操作。
在Linux操作系统下,如果要进行串口测试,可以使用系统自带的minicom,但这个环境在调试时不方便,设置麻烦,不直观。
如果有像Windows操作系统下的串口调试助手,在Linux下进行串口调试将极大地提高调试效率。
设备驱动程序是构成Linux内核的主要部分,在高特权的内核环境下运行,如果他们出错会导致灾难性的后果。
驱动程序的设计是设备开发的难点之一。
Linux操作系统体现了I/O软件目标分层设计的思想,为应用程序提供了一致的访问接口,Linux I/O系统分层以及各层次的功能如图1所示。
所有与设备相关的代码都要在驱动程序里完成。
Linux操作系统为编程者写好了第4层软件,为用户程序提供了一致的接口,驱动程序则要遵循这种标准。
linux 虚拟串口实现方法概述及解释说明1. 引言1.1 概述本文将介绍Linux下实现虚拟串口的方法,并对每种方法进行解释说明。
虚拟串口指的是一种软件仿真的串口设备,可以模拟物理串口的功能,实现数据的收发和传输。
在Linux系统中,使用虚拟串口可以满足一些特定场景下的需求,如开发、测试和调试等。
1.2 文章结构本文按照以下结构进行组织:- 第一部分为引言,对文章进行概述,并介绍文章的结构和目标;- 第二部分将介绍虚拟串口的背景知识,包括串口通信原理、虚拟串口定义与作用以及Linux中虚拟串口的应用场景;- 第三部分将详细介绍Linux下实现虚拟串口的三种方法:内核模块方式、用户空间模拟方式和设备树(DT)方式;- 第四部分将对每种实现方法进行解释说明,包括其原理、特点和适用情况;- 第五部分为总结与展望,对文章内容进行总结并展望未来发展方向。
1.3 目的本文旨在提供一个全面且清晰的介绍Linux下实现虚拟串口方法的资料,帮助读者理解虚拟串口的概念和原理,并根据实际需求选择合适的实现方法。
通过阅读本文,读者将了解到不同实现方法的优缺点,以及它们在不同场景下的应用情况。
同时,本文也对未来虚拟串口技术的发展进行展望。
2. 虚拟串口的背景:2.1 串口通信的基本原理:串口是一种用于在计算机和外部设备之间进行数据传输的通信接口。
它通过一个物理连接,使用一组控制信号和数据信号来实现双向通信。
串口通信具有简单、可靠、广泛应用等特点,因此在许多领域都得到了广泛应用,如电脑与打印机、调制解调器、路由器等设备之间的连接。
2.2 虚拟串口的定义与作用:虚拟串口是对物理串口进行仿真或模拟的一种技术。
它通过软件方式模拟了一个不存在的串行接口,使得应用程序可以通过虚拟串口与外部设备进行通信。
虚拟串口具有操作灵活、易于扩展等特点,可以提供与物理串口相似或更强大的功能。
2.3 虚拟串口在Linux中的应用场景:在Linux系统中,虚拟串口广泛应用于各种嵌入式系统开发和调试场景。
Linux下串口编程遇到的接收数据错误及原因Linux下串口編程遇到的接收數据錯誤及原因近日在调试串口的时候发现,另一设备向我ARM板的串口发送0x0d,我接收之后变成了0x0a,这是问题一;另外当对方向我发送一串数据,如果其中有0x11,那么我总是漏收此数,这是问题二。
由于问题莫名其妙,以为是笔记本的USB转232线缆的问题,换,问题依旧。
以为是对方设备的问题,采用串口调试助手模拟通讯设备与ARM板通讯,问题依旧。
无奈才去查看资料,最终得以解决,现总结如下: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> //POSIX中断控制定义#include <errno.h> //错误号定义2.打开串口串口位于/dev中,可作为标准文件的形式打开,其中:串口1 /dev/ttyS0串口2 /dev/ttyS1代码如下:int fd;fd = open(“/dev/ttyS0”, O_RDWR);if(fd == -1){Perror(“串口1打开失败!”);}//else//fcntl(fd, F_SETFL, FNDELAY);除了使用O_RDWR标志之外,通常还会使用O_NOCTTY和O_NDELAY这两个标志。
O_NOCTTY:告诉Unix这个程序不想成为“控制终端”控制的程序,不说明这个标志的话,任何输入都会影响你的程序。
linux下的串⼝通信原理及编程实例linux下的串⼝通信原理及编程实例⼀、串⼝的基本原理1 串⼝通讯串⼝通讯(Serial Communication),是指外设和计算机间,通过数据信号线、地线等,按位进⾏传输数据的⼀种通讯⽅式。
串⼝是⼀种接⼝标准,它规定了接⼝的电⽓标准,没有规定接⼝插件电缆以及使⽤的协议。
2 串⼝通讯的数据格式 ⼀个字符⼀个字符地传输,每个字符⼀位⼀位地传输,并且传输⼀个字符时,总是以“起始位”开始,以“停⽌位”结束,字符之间没有固定的时间间隔要求。
每⼀个字符的前⾯都有⼀位起始位(低电平),字符本⾝由7位数据位组成,接着字符后⾯是⼀位校验位(检验位可以是奇校验、偶校验或⽆校验位),最后是⼀位或⼀位半或⼆位停⽌位,停⽌位后⾯是不定长的空闲位,停⽌位和空闲位都规定为⾼电平。
实际传输时每⼀位的信号宽度与波特率有关,波特率越⾼,宽度越⼩,在进⾏传输之前,双⽅⼀定要使⽤同⼀个波特率设置。
3 通讯⽅式单⼯模式(Simplex Communication)的数据传输是单向的。
通信双⽅中,⼀⽅固定为发送端,⼀⽅则固定为接收端。
信息只能沿⼀个⽅向传输,使⽤⼀根传输线。
半双⼯模式(Half Duplex)通信使⽤同⼀根传输线,既可以发送数据⼜可以接收数据,但不能同时进⾏发送和接收。
数据传输允许数据在两个⽅向上传输,但是,在任何时刻只能由其中的⼀⽅发送数据,另⼀⽅接收数据。
因此半双⼯模式既可以使⽤⼀条数据线,也可以使⽤两条数据线。
半双⼯通信中每端需有⼀个收发切换电⼦开关,通过切换来决定数据向哪个⽅向传输。
因为有切换,所以会产⽣时间延迟,信息传输效率低些。
全双⼯模式(Full Duplex)通信允许数据同时在两个⽅向上传输。
因此,全双⼯通信是两个单⼯通信⽅式的结合,它要求发送设备和接收设备都有独⽴的接收和发送能⼒。
在全双⼯模式中,每⼀端都有发送器和接收器,有两条传输线,信息传输效率⾼。
显然,在其它参数都⼀样的情况下,全双⼯⽐半双⼯传输速度要快,效率要⾼。
linux设备驱动,tty串口编程2011-12-04 08:56:33分类:LINUXXC2440开发板上已经含有S3C2440的3个串口驱动,我们只要知道各个串口的设备名称就可以了,204 s3c2410_serial ,204是串口的主设备号。
s3c2410_serial是设备名称,在 dev目录下 ls 一下就可以发现ptyd0 s3c2410_serial0 ttysaptyd1 s3c2410_serial1 ttysbptyd2 s3c2410_serial2 ttyscs3c2410_serial0,s3c2410_serial1,s3c2410_serial2 分别是串口1、2、3的设备名称下面是测试源码,打开串口1、2,程序执行后,串口1的波特率变为9600,这时候你的串口终端就没有反应了(串口1波特率默认115200),把终端软件串口1 波特率改为9600后,连接终端,回车一下,然后输入几个‘1’后,画面如上图。
这时用telnet工具登陆开发板,执行ps 查看现有运行的程序,找到tty [root@XC2440 /root]# psPID USER TIME COMMAND1 root 0:04 init2 root 0:00 [kthreadd]3 root 0:00 [ksoftirqd/0]5 root 0:00 [kworker/u:0]6 root 0:00 [khelper]7 root 0:00 [kworker/u:1]10 root 0:00 [netns]236 root 0:00 [sync_supers]238 root 0:00 [bdi-default]240 root 0:00 [kblockd]249 root 0:00 [khubd]252 root 0:00 [kseriod]258 root 0:00 [kmmcd]347 root 0:00 [rpciod]349 root 0:00 [kworker/0:1]355 root 0:00 [kswapd0]356 root 0:00 [aio]357 root 0:00 [nfsiod]358 root 0:00 [crypto]901 root 0:00 [mtdblock0]906 root 0:00 [mtdblock1]911 root 0:00 [mtdblock2]916 root 0:00 [mtdblock3]1028 root 0:00 [usbhid_resumer]1049 root 0:00 [yaffs-bg-1]1060 root 0:00 vsftpd /etc/vsftpd.conf1065 root 0:00 -/bin/sh1067 root 0:00 /usr/sbin/telnetd -l /bin/login1070 root 0:18 /usr/local/qtopia/bin/qpe -qws1071 root 0:00 boa1072 root 0:00 [kworker/0:2]1085 root 0:02 /usr/local/qtopia/bin/quicklauncher1086 root 0:00 /usr/local/qtopia/bin/qss1089 root 0:02 /usr/local/qtopia/bin/quicklauncher1098 root 0:00 [flush-31:3]1100 root 0:00 ./tty1101 root 0:00 -ash1104 root 0:00 ps[root@XC2440 /root]# kill 1100执行 kill 1100 后tty测试程序就被终止了,这时串口终端就可以用了,回车一下Terminated[@XC2440 pub]#Please press Enter to activate this console.Processing /etc/profile...Done[root@XC2440 /]#[root@XC2440 /]#测试代码如下:#include <errno.h>#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <sys/ioctl.h>#include <sys/types.h>#include <errno.h>#include <termios.h>#include <sys/time.h>#include <signal.h>#include <string.h>#include <fcntl.h>#include <asm/param.h>#include "pthread.h"//#include "serial_set.h"/******************************************************************* * 函数名称: set_opt* 功能描述:设置串口基本参数* 输入参数: fd 打开的串口标识符(通过open_port函数返回)nSpeed 波特率 2400、4800、9600、115200nBits 数据位 7、8nEvent 奇偶校验 'O' 'N' 'E'nStop 停止位 1、2* 输出参数:无* 返回值: 0 设置成功-1 设置过程出错* 其它说明:无* 修改日期版本号修改人修改内容*-------------------------------------------------------------------- * 2010/09/27 V1.0 *** 创建函数***********************************************************************/int set_opt(int fd,int nSpeed, int nBits, char nEvent, int nStop) {struct termios newtio,oldtio;//保存测试现有串口参数设置,在这里如果串口号等出错,会有相关的出错信息if ( tcgetattr( fd,&oldtio) != 0){perror("SetupSerial 1");return -1;}//extern void bzero(void *s, int n); 置字节字符串s的前n个字节为零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 'O':newtio.c_cflag |= PARENB;newtio.c_cflag |= PARODD;newtio.c_iflag |= (INPCK | ISTRIP);break;case 'E':newtio.c_iflag |= (INPCK | ISTRIP);newtio.c_cflag &= ~PARODD; break;case 'N':newtio.c_cflag &= ~PARENB; break;}//设置波特率switch( nSpeed ){case 2400:cfsetispeed(&newtio, B2400); cfsetospeed(&newtio, B2400); break;case 4800:cfsetispeed(&newtio, B4800); cfsetospeed(&newtio, B4800); break;case 9600:cfsetispeed(&newtio, B9600); cfsetospeed(&newtio, B9600); break;case 115200:cfsetispeed(&newtio, B115200); cfsetospeed(&newtio, B115200); break;default:cfsetispeed(&newtio, B9600); cfsetospeed(&newtio, B9600); break;}//设置停止位if( nStop == 1 )newtio.c_cflag &= ~CSTOPB; else if ( nStop == 2 )//设置等待时间和最小接收字符newtio.c_cc[VTIME] = 0;newtio.c_cc[VMIN] = 0;//处理未接收字符tcflush(fd,TCIFLUSH);//激活新配置if((tcsetattr(fd,TCSANOW,&newtio))!=0){perror("com set error");//打印com set error及出错原因return -1;}printf("set done!\n");return 0;}/******************************************************************** *** 函数名称: open_port* 功能描述:打开指定串口* 输入参数: fd 文件描述符comport 串口号(1、2、3)* 输出参数:无* 返回值:出错返回 -1成功返回 fd文件描述符* 其它说明:无* 修改日期版本号修改人修改内容*-------------------------------------------------------------------- * 2010/09/27 V1.0 *** 创建函数********************************************************************* **//*static struct uart_driver s3c24xx_uart_drv = {.owner = THIS_MODULE,.dev_name = "s3c2410_serial",.nr = CONFIG_SERIAL_SAMSUNG_UARTS,.cons = S3C24XX_SERIAL_CONSOLE,.driver_name = S3C24XX_SERIAL_NAME,.major = S3C24XX_SERIAL_MAJOR,.minor = S3C24XX_SERIAL_MINOR,};*/int open_port(int fd,int comport){//char *dev[]={"/dev/ttyS0","/dev/ttyS1","/dev/ttyS2"}; long vdisable;//没用//打开串口if (comport==1){//fd = open("/dev/ttySAC0",O_RDWR|O_NOCTTY|O_NDELAY);fd = open("/dev/s3c2410_serial0",O_RDWR|O_NOCTTY|O_NDELAY); if (-1 == fd){perror("Can't Open s3c2410_serial0");return(-1);}elseprintf("open s3c2410_serial0 .....\n");}else if(comport==2){fd = open("/dev/s3c2410_serial1",O_RDWR|O_NOCTTY|O_NDELAY); if (-1 == fd){perror("Can't Open s3c2410_serial1");return(-1);}elseprintf("open s3c2410_serial1 .....\n");}else if (comport==3){fd = open("/dev/s3c2410_serial2",O_RDWR|O_NOCTTY|O_NDELAY);if (-1 == fd){perror("Can't Open s3c2410_serial2");return(-1);}elseprintf("open s3c2410_serial2 .....\n");}else if (comport==4){fd = open("/dev/s3c2410_serial3",O_RDWR|O_NOCTTY|O_NDELAY);if (-1 == fd){perror("Can't Open s3c2410_serial3");return(-1);}elseprintf("open s3c2410_serial3 .....\n");}//恢复串口的状态为阻塞状态,用于等待串口数据的读入if(fcntl(fd, F_SETFL, 0) < 0)printf("fcntl failed!\n");elseprintf("fcntl=%d\n",fcntl(fd, F_SETFL,0));//测试打开的文件描述符是否引用一个终端设备,以进一步确认串口是否正确打开if(isatty(STDIN_FILENO)==0)printf("standard input is not a terminal device\n");elseprintf("isatty success!\n");printf("fd-open=%d\n",fd);return fd;}unsigned int val=0;int main(int argc, char **argv){long ret=0;int receNum=0,receFlag=0;unsigned char ReceBuf[512],SendBuf[512];int fd,fdd;int nread,i;unsigned char buff[512];struct timeval timeout;bzero(buff, 512);if((fdd=open_port(fdd,2)) < 0)//打开串口 2{printf("open_port error2\n");return -1;}if((i=set_opt(fdd,9600,8,'N',1)) < 0)//设置串口 9600 8 N 1 {printf("set_opt error2\n");return -1;}printf("fd=%d\n",fdd);if((fd=open_port(fd,1)) < 0)//打开串口 1{printf("open_port error1\n");return -1;}if((i=set_opt(fd,9600,8,'N',1)) < 0)//设置串口 9600 8 N 1 {printf("set_opt error1\n");return -1;}printf("fd=%d\n",fd);_sec=1;//设置定时器_usec=0;while (1){nread = read(fd,buff,256);//读串口数据非阻塞if(nread>0){memcpy(&ReceBuf[receNum],buff,nread);receFlag=2;receNum +=nread; if(receNum>511)receNum=0;printf("nread = %d\n",nread);printf("%s\n",buff);bzero(buff,nread);//清空}else{//printf("main\n");if(receFlag>1)receFlag--;if(receFlag==1){write(fd,ReceBuf,receNum);//写数据receNum=0;receFlag=0;}_sec=0;_usec=20000;//设置时间 20MS 读取一下串口数据ret=select(0,NULL,NULL,NULL,&timeout);}}close(fdd);close(fd);return 0;}。
Linux gadget驱动应用之 USB串口Linux gadget驱动应用之 USB串口Linux内核中usb设备侧驱动程序分成3个层次:UDC驱动程序、Gadget API 和Gadget驱动程序。
UDC驱动程序(USB控制器)直接访问硬件,控制USB设备和主机间的底层通信,向上层提供与硬件相关操作的回调函数。
Gadget API是UDC驱动程序回调函数的简单包装,这部分程序内核都已经写好。
Gadget驱动程序具体控制USB设备功能的实现,使设备表现出“U盘”、“虚拟串口”等特性。
简单看个usb 虚拟串口例子Overview--------The gadget serial driver is a Linux USB gadget driver, a USB device side driver. It runs on a Linux system that has USB device side hardware; for example, a PDA, an embedded Linux system, or a PC with a USB development card.The gadget serial driver talks over USB to either a CDC ACM driver or a generic USB serial driver running on a host PC.Host--------------------------------------| Host-Side CDC ACM USB Host || Operating | or | Controller | USB| System | Generic USB | Driver |--------| (Linux or | Serial | and | || Windows) Driver USB Stack | |-------------------------------------- ||||Gadget |-------------------------------------- || Gadget USB Periph. | || Device-Side | Gadget | Controller | || Linux | Serial | Driver |--------| Operating | Driver | and || System USB Stack |--------------------------------------On the device-side Linux system, the gadget serial driver looks like a serial device.On the host-side system, the gadget serial device looks like a CDC ACM compliant class device or a simple vendor specific device with bulk in and bulk out endpoints, and it is treated similarly to other serial devices.The host side driver can potentially be any ACM compliant driver or any driver that can talk to a device with a simple bulk in/out interface. Gadget serial has been tested with the Linux ACM driver, the Windows usbser.sys ACM driver, and the Linux USB generic serial driver.With the gadget serial driver and the host side ACM or generic serial driver running, you should be able to communicate between the host and the gadget side systems as if they were connected by a serial cable.The gadget serial driver only provides simple unreliable data communication. It does not yet handle flow control or many other features of normal serial devices.usb-serial功能体验硬件:at91sam9263内核:2.6.27<*> USB Gadget Support --->USB Peripheral Controller (AT91 USB Device Port) --->AT91 USB Device Port<M> USB Gadget Drivers<M> Gadget Zero(DEVELOPMENT)<M> Ethernet Gadget (with CDC Ethernet support)[*] RNDIS support<M> Gadget Filesystem(EXPERIMENTAL)<M> File-backed Storage Gadget<M> Serial Gadget<M> Printer Gadget<M> CDC Composite Device(Ethernet and ACM)简单解释下Gadget Zero, 类似于 dummy hcd, 该驱动用于测试 udc 驱动。
分析ttySn驱动之前先明确几个概念(1)/dev/ttySn:串口端口终端,是使用串口计算机终端连接的终端设备,对应我们具体的串口设备(2)/dev/tty:如果当前进程有控制终端的话,那么/dev/tty就是当前进程的控制终端的特殊设备文件可用ps -ef来查看,对于你登录的shell /dev/tty就是你使用的终端(3)/dev/ttyn /dev/console:控制台终端开始分析之前来看2张图:图1line discipline表示这条终端“线程”的输入与输出规范设置,主要用来进行输入/输出数据的预定义处理,处理完后,将数据交给serial _core,最后serial _core会调用具体的rk_serial.c 的操作。
用户想要访问linux的串口设备,在用户空间通过read/write/ioctl等,首先通过设备文件(字符设备)和tty_core交互,tty_core根据交互类型选择tty_driver或者line discipline执行,如果是ioctl这交给tty_driver(这里是servila_core)去处理,如果是read/write这交给line discipline去处理。
图2再看第二张图,一个uart_driver通常会注册一段设备号.即在用户空间会看到uart_driver对应有多个设备节点。
例如:/dev/ttyS0 /dev/ttyS1 每个设备节点是对应一个具体硬件的,这样就可做到对多个硬件设备的统一管理,而每个设备文件应该对应一个uart_port,也就是说:uart_device要和多个uart_port关系起来。
并且每个uart_port对应一个circ_buf(用来接收数据),所以uart_port 必须要和这个缓存区关系起来。
有了上面的理解,我们开始进入代码去研究具体的实现过程以RK3288 平台作为媒介去研究tty_core源码在:kernel/drivers/tty/tty_io.c这个文件主要将tty注册成一个char dev,对应上面的tty_core的部分。
linux设备驱动之8250串口驱动一:前言前一段时间自己实践了一下8250芯片串口驱动的编写。
今天就在此基础上分析一下linux kernel自带的串口驱动。
毕竟只有对比专业的驱动代码才能更好的进步,同以往一样,基于linix kernel2.6.25.相应驱动代码位于:linux-2.6.25/drivers/serial/8250.c。
二:8250串口驱动初始化相应的初始化函数为serial8250_init().代码如下:static int __init serial8250_init(void){int ret, i;if (nr_uarts > UART_NR)nr_uarts = UART_NR;printk(KERN_INFO "Serial: 8250/16550 driver $Revision: 1.90 $ ""%d ports, IRQ sharing %sabled\n", nr_uarts,share_irqs ? "en" : "dis");for (i = 0; i < NR_IRQS; i++)spin_lock_init(&irq_lists[i].lock);ret = uart_register_driver(&serial8250_reg);if (ret)goto out;serial8250_isa_devs = platform_device_alloc("serial8250",PLAT8250_DEV_LEGACY);if (!serial8250_isa_devs) {ret = -ENOMEM;goto unreg_uart_drv;}ret = platform_device_add(serial8250_isa_devs);if (ret)goto put_dev;serial8250_register_ports(&serial8250_reg, &serial8250_isa_devs->dev);ret = platform_driver_register(&serial8250_isa_driver);if (ret == 0)goto out;platform_device_del(serial8250_isa_devs);put_dev:platform_device_put(serial8250_isa_devs);unreg_uart_drv:uart_unregister_driver(&serial8250_reg);out:return ret;}这段代码涉及到的知识要求,如platform ,uart等我们在之前都已经做过详细的分析。
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下串口驱动测试程序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的板子上,然后一边发送一边接受,这样如果发送的数据和接受的数据相同,则测试成功。