




版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
嵌入式编程技术
课程总体情况成绩:期末考试80%,平时10(考勤+作业),实验10%学时安排:教师授课32学时,实验32学时教材:《从实践中学嵌入式Linux应用程序开发》重点内容:嵌入式文件I/O编程、多任务编程、进程间通信、多线程编程、网络编程、设备驱动编程。补充内容:QT编程(GUI)、BOA移植及编程学习方法:理解+实践3
第2章嵌入式文件I/O编程在Linux系统中,大部分设备都会抽象成一个文件,这样对它们的操作就像对文件的操作一样。在嵌入式应用开发中,文件I/O编程是最常用也是最基本的内容。
4
第2章嵌入式文件I/O编程系统调用及用户编程接口系统调用、用户编程接口、系统命令的概念Linux文件I/O系统概述虚拟文件系统VFS、Linux中文件及文件描述符底层文件I/O操作基本文件操作、文件锁、多路复用嵌入式Linux串口应用编程标准I/O编程文件读写及上锁综合实例5
2.1.1系统调用
2.1Linux系统调用及用户编程接口系统调用是指操作系统提供给用户程序调用的一组“特殊”接口,用户程序可以通过这组“特殊”接口获得操作系统内核提供的服务。例如用户可以通过进程控制相关的系统调用来创建进程、实现进程之间的通信等。在Linux中,为了更好地保护内核空间,将程序的运行空间分为内核空间和用户空间(也称为内核态和用户态),用户进程在通常情况下不允许访问内核数据,也无法使用内核函数,只能在用户空间操作用户数据,调用用户空间的函数。6
2.1.1系统调用
2.1Linux系统调用及用户编程接口Linux系统调用非常精简,它继承了Unix系统调用中最基本的部分。这些系统调用按照功能逻辑大致可以分为进程控制、进程间通信、文件系统控制、存储管理、网络管理、套接字控制、用户管理等几类。7
2.1.2用户编程接口
2.1Linux系统调用及用户编程接口系统调用并不直接与程序员进行交互,实际使用中程序员调用的通常是用户编程接口(API)。例如:创建进程的API函数fork()对应于内核空间的sys_fork()系统调用。一些API函数需要几个系统调用来共同完成函数的功能,也有一些API函数不需要调用系统调用。8
2.1.2用户编程接口
2.1Linux系统调用及用户编程接口在Linux中,用户编程接口(API)遵循了在Unix中最流行的应用编程界面标准——POSIX(PortableOperatingSystemInterface)标准。POSIX标准是由IEEE和ISO/IEC共同开发的标准系统。该标准基于当时现有的Unix实践和经验,描述了操作系统的系统调用编程接口(实际上就是API),用于保证应用程序可以在源代码一级上在多种操作系统上移植运行。这些系统调用编程接口主要是通过C库(libc)实现的。9
2.1.3系统命令
2.1Linux系统调用及用户编程接口系统命令相对API更高了一层,它实际上一个可执行程序,它的内部引用了用户编程接口(API)来实现相应的功能,它们之间的关系如图:10
2.2.1虚拟文件系统
Linux系统成功的关键因素之一就是具有与其他操作系统和谐共存的能力。Linux的文件系统由两层结构构建。第一层是虚拟文件系统(VFS),第二层是各种不同的具体的文件系统。
2.2Linux文件I/O系统概述11
2.2.1虚拟文件系统
2.2Linux文件I/O系统概述
12
2.2.2Linux中文件及文件描述符
Linux目前支持7种文件类型:普通文件、目录文件、链接文件、块设备文件、字符设备文件、管道文件、套接字文件。
对于Linux而言,所有对设备和文件的操作都是使用文件描述符来进行的。文件描述符是一个非负的整数,它是一个索引值,并指向在内核中每个进程打开文件的记录表。当打开一个现存文件或创建一个新文件时,内核就向进程返回一个文件描述符;当需要读写文件时,也需要把文件描述符作为参数传递给相应的函数。
2.2Linux文件I/O系统概述13
2.2.2Linux中文件及文件描述符
基于文件描述符的I/O操作是Linux中最常用的操作之一。例如一个进程启动时,都会打开3个文件:标准输入、标准输出和标准出错处理。2.2Linux文件I/O系统概述文件描述符宏标准输入0STDIN_FILENO标准输出1STDOUT_FILENO标准出错2STDERR_FILENO14
文件I/O操作的系统调用主要有5个函数:open()、read()、write()、lseek()和close()。这些函数的特点是不带缓存,直接对文件(包括设备)进行读写操作。这些函数是Posix的组成部分,但不是ANSIC的组成部分。2.3底层文件I/O操作15
2.3.1基本文件操作open函数是用于打开或创建文件,在打开或创建文件时可以指定文件的属性及用户的权限等各种参数。所需头文件:
#include<sys/types.h> #include<sys/stat.h>
#include<fcntl.h>原型:
intopen(constchar*pathname,intflags,intperms)
2.3底层文件I/O操作16
2.3.1基本文件操作open函数语法要点
2.3底层文件I/O操作17
2.3.1基本文件操作open函数语法要点
2.3底层文件I/O操作18
2.3.1基本文件操作close()函数是用于关闭一个被打开的文件。close函数语法要点:
2.3底层文件I/O操作19
2.3.1基本文件操作read()函数是用于将从指定的文件描述符中读出的数据放到缓存区中,并返回实际读入的字节数。read函数语法要点:
2.3底层文件I/O操作20
2.3.1基本文件操作write()函数是用于向打开的文件写数据,写操作从文件的当前指针位置开始。write函数语法要点:
2.3底层文件I/O操作21
2.3.1基本文件操作lseek()函数是用于在指定的文件描述符中将文件指针定位到相应的位置。lseek函数语法要点:
2.3底层文件I/O操作22
2.3.1基本文件操作lseek()函数是用于在指定的文件描述符中将文件指针定位到相应的位置。lseek函数语法要点:
2.3底层文件I/O操作23
2.3.1基本文件操作函数使用示例:
基本功能:从一个文件(源文件)中读取最后10KB的数据并复制到另一个文件(目标文件)。源文件以只读方式打开,目标文件以只写方式打开。若目标文件不存在,可以创建并设置权限的初始值为644,即文件的所有者可读可写,文件所属组和其他用户只能读。
2.3底层文件I/O操作24
2.3.1基本文件操作#include<unistd.h>#include<sys/types.h>#include<sys/stat.h>#include<fcntl.h>#include<stdlib.h>#include<stdio.h>#define BUFFER_SIZE 1024 /*每次读写缓存大小#define SRC_FILE_NAME "src_file" /*源文件名*/#define DEST_FILE_NAME "dest_file"/*目标文件名*/#define OFFSET 10240 /*复制的数据大小*/2.3底层文件I/O操作25
2.3.1基本文件操作intmain(){ intsrc_file,dest_file; unsignedcharbuff[BUFFER_SIZE]; intreal_read_len; /*以只读方式打开源文件*/ src_file=open(SRC_FILE_NAME,O_RDONLY); /*以只写方式打开目标文件,若此文件不存在则创建该文件,访问权限值为644*/ dest_file=open(DEST_FILE_NAME,O_WRONLY|O_CREAT, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH); if(src_file<0||dest_file<0) { printf("Openfileerror\n"); exit(1); }2.3底层文件I/O操作26
2.3.1基本文件操作 lseek(src_file,-OFFSET,SEEK_END); /*读取源文件的最后10KB数据并写到目标文件中,每次读写1KB*/ while((real_read_len=read(src_file,buff,sizeof(buff)))>0) { write(dest_file,buff,real_read_len); } close(dest_file); close(src_file); return0;}2.3底层文件I/O操作27
2.3.2文件锁在文件已经共享的情况下,为避免竞争共享资源产生错误,Linux通常的方法是给文件上锁。建议性锁:每个要求上锁文件的进程都要检查是否有锁存在,并尊重已有的锁。强制性锁:由内核执行。当一个文件被上锁进行写入操作的时候,内核将阻止其他进程对其进行读写操作。记录锁:对文件的某一记录上锁,又分为读取锁(共享锁)和写入锁(排斥锁)。实现文件上锁的函数:lockf()和fcntl()。2.3底层文件I/O操作28
2.3.2文件锁fcntl()函数具有很丰富的功能,它可以对已打开的文件描述符进行各种操作,不仅包括管理文件锁,还包括获得设置文件描述符和文件描述符标志、文件描述符的复制等很多功能。
2.3底层文件I/O操作29
2.3.2文件锁fcntl()函数语法要点
2.3底层文件I/O操作30
2.3.2文件锁fcntl()函数语法要点
2.3底层文件I/O操作31
2.3.2文件锁fcntl()函数第三个参数lock说明lock为flock类型的结构体,flock的定义为:structflock { shortl_type; off_tl_start; shortl_whence;
off_tl_len; pid_tl_pid;}
2.3底层文件I/O操作32
2.3.2文件锁fcntl()函数第三个参数lock说明
2.3底层文件I/O操作对整个文件加锁:l_start设为0,l_whence设为SEEK_SET,l_len设为0。33
2.3.2文件锁fcntl()使用实例源文件1:lock_set.cintlock_set(intfd,inttype){ structflocklock; lock.l_whence=SEEK_SET; lock.l_start=0; lock.l_len=0; lock.l_type=type; lock.l_pid=-1;
2.3底层文件I/O操作34
2.3.2文件锁fcntl()使用实例 /*判断文件是否可以上锁*/ fcntl(fd,F_GETLK,&lock); if(lock.l_type!=F_UNLCK) { /*判断文件不能上锁的原因*/ if(lock.l_type==F_RDLCK)/*该文件已有读取锁*/ { printf("Readlockalreadysetby%d\n",lock.l_pid); } elseif(lock.l_type==F_WRLCK)/*该文件已有写入锁*/ { printf("Writelockalreadysetby%d\n",lock.l_pid); } }
2.3底层文件I/O操作35
2.3.2文件锁fcntl()使用实例 /*l_type可能已被F_GETLK修改过*/ lock.l_type=type; /*根据不同的type值进行阻塞式上锁或解锁*/ if((fcntl(fd,F_SETLKW,&lock))<0) { printf("Lockfailed:type=%d\n",lock.l_type); return1; }
switch(lock.l_type) { caseF_RDLCK: {
printf("Readlocksetby%d\n",getpid()); } break;
2.3底层文件I/O操作36
2.3.2文件锁fcntl()使用实例 caseF_WRLCK: { printf("Writelocksetby%d\n",getpid()); } break; caseF_UNLCK: { printf("Releaselockby%d\n",getpid()); return1;
} break; default: break; }/*endofswitch*/ return0;
}
2.3底层文件I/O操作37
2.3.2文件锁fcntl()使用实例主程序源文件:write_lock.c#include<unistd.h>#include<sys/file.h>#include<sys/types.h>#include<sys/stat.h>#include<stdio.h>#include<stdlib.h>#include"lock_set.c"intmain(void)
{ intfd; fd=open("hello",O_RDWR|O_CREAT,0644);
2.3底层文件I/O操作38
2.3.2文件锁fcntl()使用实例 if(fd<0)
{ printf("Openfileerror\n"); exit(1); } /*给文件上写入锁*/ lock_set(fd,F_WRLCK); getchar(); /*给文件解锁*/ lock_set(fd,F_UNLCK); getchar(); close(fd); return0;}
2.3底层文件I/O操作39
2.3.2文件锁fcntl()使用实例2——读取锁主程序源文件:fcntl_read.c#include<unistd.h>#include<sys/file.h>#include<sys/types.h>#include<sys/stat.h>#include<stdio.h>#include<stdlib.h>#include"lock_set.c"intmain(void)
{ intfd; fd=open("hello",O_RDWR|O_CREAT,0644);
2.3底层文件I/O操作40
2.3.2文件锁fcntl()使用实例 if(fd<0)
{ printf("Openfileerror\n"); exit(1); } /*给文件上写入锁*/ lock_set(fd,F_RDLCK); getchar(); /*给文件解锁*/ lock_set(fd,F_UNLCK); getchar(); close(fd); return0;}
2.3底层文件I/O操作41
2.3.3多路复用I/O处理模型阻塞I/O模型若所调用的I/O函数没有完成相关的功能,则会使进程挂起,直到相关数据到达才会返回。如:
fcntl(fd,F_SETLKW,&lock);非阻塞模型 当请求的I/O操作不能完成时,则不让进程睡眠,而且立即返回。如open()、read()、write()等操作
2.3底层文件I/O操作42
2.3.3多路复用I/O处理模型I/O多路转接模型
如果请求的I/O操作阻塞,且它不是真正的阻塞I/O,而是让其中的一个函数等待,在这期间,I/O还能进行其他操作。信号驱动I/O模型 在该模型下,进程要定义信号处理程序,系统可以自动捕获特定信号的到来,从而启动I/O。 该模型的好处是当等待数据到达时,主程序继续执行,只有收到SIGIO信号时才去处理数据。2.3底层文件I/O操作43
2.3.3多路复用I/O处理模型异步I/O模型 在这种模型下,进程先让内核启动I/O操作,并在整个操作完成后通知该进程。 与信号驱动I/O的区别:信号驱动I/O由内核通知进程何时可以启动I/O,而异步I/O模型是由内核通知进程I/O操作何时完成。
2.3底层文件I/O操作44
2.3.3多路复用
select()和poll()函数属于I/O多路转接模型,是处理I/O复用的一个高效的方法。
它可以具体设置程序中每一个所关心的文件描述符的条件、希望等待的时间等,从select()和poll()函数返回时,内核会通知用户准备好的文件描述符的数量、已准备好的条件(或事件)等。通过使用select()和poll()函数的返回结果,就可以调用相应的I/O处理函数了。2.3底层文件I/O操作45
2.3.3多路复用select()函数的语法格式:
2.3底层文件I/O操作46
2.3.3多路复用select()函数的语法格式:
2.3底层文件I/O操作47
2.3.3多路复用select()函数根据希望进行的文件操作对文件描述符进行了分类处理,对文件描述符的处理涉及4个宏函数:FD_ZERO(fd_set*set): 清除一个文件描述符集FD_SET(intfd,fd_set*set): 将一个文件描述符加入文 件描符集中FD_CLR(intfd,fd_set*set): 将一个文件描述符从文件 描述符集中清除FD_ISSET(intfd,fd_set*set):如果fd是set的一个元素, 则返回非零值。2.3底层文件I/O操作48
2.3.3多路复用structtimeout结构体的定义(bits/time.h):2.3底层文件I/O操作
structtimeval{__time_ttv_sec;/*Seconds.*/__suseconds_ttv_usec;/*Microseconds.*/};49
2.3.3多路复用——poll()函数poll函数语法格式:
2.3底层文件I/O操作50
2.3.3多路复用——poll()函数poll函数语法格式:intpoll(structpollfd*fds,intnumfds,inttimeout)
2.3底层文件I/O操作51
2.3.3多路复用——poll()函数poll函数语法格式:intpoll(structpollfd*fds,intnumfds,inttimeout)timeout:poll阻塞的超时时间(ms),小于等于0表示无限等待。
2.3底层文件I/O操作52
2.3.3多路复用——实例 通过调用poll()函数来监听三个终端的输入(分别重定向到两个管道文件的虚拟终端以及主程序所运行的虚拟终端)并分别进行相应的处理。
建立一个poll()函数监视的读文件描述符集,其中包含三个文件描述符,分别为标准输入文件描述符和两个管道文件描述符。通过监视主程序的虚拟终端标准输入来实现程序的控制(如程序结束);以两个管道作为数据输入,主程序将从两个管道读取的输入字符串写入到输出文件(屏幕)。
2.3底层文件I/O操作53
2.3.3多路复用——实例#include<fcntl.h>#include<stdio.h>#include<unistd.h>#include<stdlib.h>#include<string.h>#include<time.h>#include<errno.h>#include<poll.h>#defineMAX_BUFFER_SIZE 1024 /*缓冲区大小*/#defineIN_FILES 3 /*多路复用输入文件数目*/#defineTIME_DELAY 60000 /*超时时间秒数:60秒*/#defineMAX(a,b) ((a>b)?(a):(b))
2.3底层文件I/O操作小技巧:查看使用某个函数时需要哪些头文件:man函数名
错误信息处理:
全局变量errnovoidperror(constchar*s);char*strerror(interrno);54
2.3.3多路复用——实例intmain(void){ structpollfdfds[IN_FILES]; charbuf[MAX_BUFFER_SIZE]; inti,res,real_read,maxfd;
/*首先按一定的权限打开两个源文件*/ fds[0].fd=0; if((fds[1].fd=open("in1",O_RDONLY|O_NONBLOCK))<0) { printf("Openin1error\n"); return1; }
2.3底层文件I/O操作55
2.3.3多路复用——实例
if((fds[2].fd=open("in2",O_RDONLY|O_NONBLOCK))<0) { printf("Openin2error\n"); return1; }
/*取出两个文件描述符中的较大者*/ for(i=0;i<IN_FILES;i++) { fds[i].events=POLLIN; }
2.3底层文件I/O操作56
2.3.3多路复用——实例 while(fds[0].events||fds[1].events||fds[2].events) { if(poll(fds,IN_FILES,0)<0) { printf("PollerrororTimeout\n"); return1; }2.3底层文件I/O操作57
2.3.3多路复用——实例for(i=0;i<IN_FILES;i++){ if(fds[i].revents)/*判断在哪个文件上发生了事件*/ { memset(buf,0,MAX_BUFFER_SIZE); real_read=read(fds[i].fd,buf,MAX_BUFFER_SIZE); if(real_read<0) { if(errno!=EAGAIN) { return1;/*系统错误,结束运行*/ } } elseif(!real_read) { close(fds[i].fd); fds[i].events=0;/*取消对该文件的监听*/ }
2.3底层文件I/O操作对不同的输入做相应处理……58
2.3.3多路复用——实例else{ if(i==0)/*如果在标准输入上有数据输入时*/ { if((buf[0]=='q')||(buf[0]=='Q')){ return1;/*输入"q"或"Q"则会退出*/ } } else {/*将读取的数据输出到终端上*/ buf[real_read]='\0'; printf("%s",buf); } }/*endofifreal_read*/ }/*endofifrevents*/ }/*endoffor*/ }/*endofwhile*/ exit(0);}
2.3底层文件I/O操作59
2.3.3多路复用——实例如何验证该多路复用程序?编译程序;创建两个管道;
mknodin1p mknodin2p启动实例程序;启动两个新的虚拟终端,通过输出重定向的方法向管道输出数据。
cat>in1cat>in2在控制终端输入q或Q,退出程序。2.3底层文件I/O操作60
2.4.1串口编程基础知识常见的数据通信的基本方式可分为并行通信与串行通信两种。并行通信是指利用多条数据传输线将一个字数据的各比特位同时传送。它的特点是传输速度快,适用于传输距离短且传输速度较高的通信。串行通信是指利用一条传输线将数据以比特位为单位顺序传送。特点是通信线路简单,利用简单的线缆就可实现通信,降低成本,适用于传输距离长且传输速度较慢的通信。2.4嵌入式Linux串口应用编程61
2.4.1串口编程基础知识串口是计算机一种常用的接口,常用的串口有RS-232-C接口。
DB9串口接口:2.4嵌入式Linux串口应用编程62
2.4.1串口编程基础知识在Linux中,设备文件一般都位于/dev下,其中串口1和串中2对应的设备名称为“/dev/ttyS0”和“/dev/ttyS1”,对串口的读写可以使用简单的read()和write()函数来完成,所不同的是需要对串口的其他参数进行配置。S3C2410X内部有2个独立的UART控制器,每个控制器都可以工作在Interrupt或DMA模式。UART的操作主要可分为以下几个部分:数据发送、数据接收、产生中断、设置波特率、Loopback模式、红外模式以及硬软流控模式。2.4嵌入式Linux串口应用编程63
2.4.2串口配置串口设置主要是设置structtermios结构体的各个成员#include<termios.h>structtermios{ unsignedshortc_iflag; /*输入模式标志*/ unsignedshortc_oflag; /*输出模式标志*/ unsignedshortc_cflag; /*控制模式标志*/ unsignedshortc_lflag; /*本地模式标志*/ unsignedcharc_line; /*线路规程*/ unsignedcharc_cc[NCC]; /*控制特性*/ speed_t c_ispeed; /*输入速度*/ speed_t c_ospeed; /*输出速度*/};
2.4嵌入式Linux串口应用编程64
2.4.2串口配置终端的三种工作模式:规范模式:所有的输入基于行进行处理。用户输入行结束符之前,系统调用read()函数读不到用户输入的任何字符。非规范模式:所有的输入是即时有效的,不需要输入行结束符,也不能进行行编辑,参数MIN(c_cc[VMIN])和TIME(c_cc[VTIME])决定read()函数的调用方式。原始模式:一种特殊的非规范模式,此模式下所有输入数据以字节为单位进行处理,而且终端不可回显。通过在termios结构的c_lflag中设置ICANNO标志来定义终端是以规范模式还是以非规范模式工作;通过调用cfmakeraw()函数可以将终端设置为原始模式。
表2.11-2.152.4嵌入式Linux串口应用编程65
2.4.2串口配置2.4嵌入式Linux串口应用编程66
2.4.2串口配置保存原先串口设置使用函数tcgetattr(fd,&old_cfg)。该函数得到由fd指向的终端的配置参数,并将它们保存于termios结构变量old_cfg中。该函数还可以测试配置是否正确、该串口是否可用等。若调用成功,函数返回值为0,若调用失败,函数返回值为1
if(tcgetattr(fd,&old_cfg)!=0){ perror("tcgetattr"); return-1; }2.4嵌入式Linux串口应用编程67
2.4.2串口配置设置工作模式调用cfmakeraw()函数可以将终端设置为原始模式,在后面的实例中,采用原始模式进行串口数据通信。
cfmakeraw(&new_cfg);2.4嵌入式Linux串口应用编程68
2.4.2串口配置设置波特率设置波特率有专门的函数,用户不能直接通过位掩码来操作。设置波特率的主要函数有:cfsetispeed()和cfsetospeed()。cfsetispeed(&new_cfg,B115200);cfsetospeed(&new_cfg,B115200);2.4嵌入式Linux串口应用编程69
2.4.2串口配置设置字符大小与设置波特率不同,设置字符大小并没有现成可用的函数,需要用位掩码。一般首先去除数据位中的位掩码,再重新按要求设置
new_cfg.c_cflag&=~CSIZE;/*用数据位掩码清空数据位设置*/
new_cfg.c_cflag|=CS8;2.4嵌入式Linux串口应用编程70
2.4.2串口配置设置奇偶校验位设置奇偶校验位需要用到termios中的两个成员:c_cflag和c_iflag。首先要激活c_cflag中的校验位使能标志PARENB和是否要进行校验,这样会对输出数据产生校验位,而输入数据进行校验检查。同时还要激活c_iflag中的对于输入数据的奇偶校验使能(INPCK)。奇校验
new_cfg.c_cflag|=(PARODD|PARENB); new_cfg.c_iflag|=INPCK;偶校验
new_cfg.c_cflag|=PARENB; new_cfg.c_cflag&=~PARODD; new_cfg.c_iflag|=INPCK;2.4嵌入式Linux串口应用编程71
2.4.2串口配置设置停止位设置停止位是通过激活c_cflag中的CSTOPB而实现的。若停止位为一个,则清除CSTOPB,若停止位为两个,则激活CSTOPB。
new_cfg.c_cflag&=~CSTOPB;//将停止位设置为一个比特
new_cfg.c_cflag|=CSTOPB; //将停止位设置为两个比特2.4嵌入式Linux串口应用编程72
2.4.2串口配置设置最少字符和等待时间在对接收字符和等待时间没有特别要求的情况下,可以将其设置为0,则在任何情况下read()函数立即返回,此时串口操作会设置为非阻塞方式。
new_cfg.c_cc[VTIME]=0; new_cfg.c_cc[VMIN]=0;2.4嵌入式Linux串口应用编程73
2.4.2串口配置清除串口缓冲串口在重新设置之前,需要对当前的串口设备进行适当的处理,这时就可调用在<termios.h>中声明的tcdrain()、tcflow()、tcflush()等函数来处理目前串口缓冲中的数据。
inttcdrain(intfd);/*使程序阻塞,直到输出缓冲区的数据全部发送完毕*/
inttcflow(intfd,intaction);/*用于暂停或重新开始输出*/
inttcflush(intfd,intqueue_selector);/*用于清空输入/输出缓冲区*/2.4嵌入式Linux串口应用编程74
2.4.2串口配置清除串口缓冲
tcflush()函数,对于在缓冲区中的尚未传输的数据,或者收到的但是尚未读取的数据,其处理方法取决于queue_selector的值,它可能的取值有以下几种。 TCIFLUSH:对接收到而未被读取的数据进行清空处理。 TCOFLUSH:对尚未传送成功的输出数据进行清空处理。 TCIOFLUSH:包括前两种功能,即对尚未处理的输入输出数据进行清空处理。示例:tcflush(fd,TCIFLUSH);
2.4嵌入式Linux串口应用编程75
2.4.2串口配置激活配置在完成全部串口配置之后,要激活刚才的配置并使配置生效。这里用到的函数是tcsetattr(),它的函数原型是:tcsetattr(intfd,intoptional_actions,conststructtermios*termios_p); 其中参数termios_p是termios类型的新配置变量。 参数optional_actions可能的取值有以下三种: TCSANOW:配置的修改立即生效。 TCSADRAIN:配置的修改在所有写入fd的输出都传输完毕之后生效。 TCSAFLUSH:所有已接受但未读入的输入都将在修改生效之前被丢弃。
2.4嵌入式Linux串口应用编程76
2.4.2串口配置串口配置示例intset_com_config(intfd,intbaud_rate, intdata_bits,charparity,intstop_bits){ structtermiosnew_cfg,old_cfg; intspeed; if(tcgetattr(fd,&old_cfg)!=0) { perror("tcgetattr"); return-1; }
new_cfg=old_cfg;
cfmakeraw(&new_cfg);/*配置为原始模式*/
2.4嵌入式Linux串口应用编程77
2.4.2串口配置串口配置示例 switch(baud_rate) { case2400: { speed=B2400; } ……
default: case115200: { speed=B115200; } break; }
cfsetispeed(&new_cfg,speed); cfsetospeed(&new_cfg,speed);2.4嵌入式Linux串口应用编程78
2.4.2串口配置串口配置示例
new_cfg.c_cflag&=~CSIZE; switch(data_bits)/*设置数据位*/ { case7: {
new_cfg.c_cflag|=CS7; } break; default: case8: {
new_cfg.c_cflag|=CS8; } break; }2.4嵌入式Linux串口应用编程79
2.4.2串口配置串口配置示例 switch(parity)/*设置奇偶校验位*/ { default: case'n': case'N': {
new_cfg.c_cflag&=~PARENB; new_cfg.c_iflag&=~INPCK;
} break; case'o': case'O': {
new_cfg.c_cflag|=(PARODD|PARENB); new_cfg.c_iflag|=INPCK;
} break;2.4嵌入式Linux串口应用编程80
2.4.2串口配置串口配置示例 case'e': case'E': { new_cfg.c_cflag|=PARENB; new_cfg.c_cflag&=~PARODD; new_cfg.c_iflag|=INPCK; } break; }2.4嵌入式Linux串口应用编程81
2.4.2串口配置串口配置示例 switch(stop_bits)/*设置停止位*/ { default: case1: {
new_cfg.c_cflag&=~CSTOPB; } break; case2: {
new_cfg.c_cflag|=CSTOPB; } }2.4嵌入式Linux串口应用编程82
2.4.2串口配置串口配置示例 /*设置等待时间和最小接收字符*/
new_cfg.c_cc[VTIME]=0; new_cfg.c_cc[VMIN]=1; tcflush(fd,TCIFLUSH);/*处理未接收字符*/ if((tcsetattr(fd,TCSANOW,&new_cfg))!=0)/*激活新配置*/ { perror("tcsetattr"); return-1; } return0;}2.4嵌入式Linux串口应用编程83
2.4.3串口使用打开串口使用open函数打开串口fd=open(“/dev/ttyS0”,O_RDWR|O_NOCTTY|O_NDELAY);O_NOCTTY:使打开的文件不成为这个进程的控制终端O_NDELAY:设置为非阻塞方式。通知Linux系统,这个程序不关心DCD信号线所处的状态(端口的另一端是否激活或者停止)。接下来可恢复串口为阻塞状态,用于等待串口数据的读入:fcntl(fd,F_SETFL,0);2.4嵌入式Linux串口应用编程84
2.4.3串口使用打开串口intopen_port(intcom_port){ intfd;#if(COM_TYPE==GNR_COM)/*使用普通串口*/ char*dev[]={"/dev/ttyS0","/dev/ttyS1","/dev/ttyS2"};#else/*使用USB转串口*/ char*dev[]={"/dev/ttyUSB0","/dev/ttyUSB1","/dev/ttyUSB2"};#endif if((com_port<0)||(com_port>MAX_COM_NUM)) { return-1; }
2.4嵌入式Linux串口应用编程85
2.4.3串口使用打开串口
/*打开串口*/ fd=open(dev[com_port-1],O_RDWR|O_NOCTTY|O_NDELAY); if(fd<0) { perror("openserialport"); return(-1); }
if(fcntl(fd,F_SETFL,0)<0)/*恢复串口为阻塞状态*/ { perror("fcntlF_SETFL\n"); }
returnfd;}2.4嵌入式Linux串口应用编程86
2.4.3串口使用读写串口使用read()、write()函数进行串口的读写操作write(fd,buff,strlen(buff));read(fd,buff,BUFFER_SIZE);实例:写串口的程序在宿主机上运行,读串口的程序在目标板上运行,用户在宿主机上输入信息,通过写/读程序发送到目标板上。
2.4嵌入式Linux串口应用编程87
2.4.3串口使用写串口程序
/*com_writer.c*/#include<stdio.h>#include<stdlib.h>#include<string.h>#include<sys/types.h>#include<sys/stat.h>#include<errno.h>#include<termios.h>#include<fcntl.h>#defineHOST_COM_PORT1#defineBUFFER_SIZE1024#defineMAX_COM_NUM4#include“uart_api.h”
/*串口设置和打开函数*/2.4嵌入式Linux串口应用编程88
2.4.3串口使用写串口程序
intmain(void){ intfd; charbuff[BUFFER_SIZE]; if((fd=open_port(HOST_COM_PORT))<0)/*打开串口*/ { perror("open_port"); return1; } if(set_com_config(fd,115200,8,'N',1)<0)/*配置串口*/ { perror("set_com_config"); return1; }2.4嵌入式Linux串口应用编程89
2.4.3串口使用写串口程序
do { printf("Inputsomewords(enter'quit'toexit):");
memset(buff,0,BUFFER_SIZE); if(fgets(buff,BUFFER_SIZE,stdin)==NULL) { perror("fgets"); break; } write(fd,buff,strlen(buff)); }while(strncmp(buff,"quit",4)); close(fd); return0;}2.4嵌入式Linux串口应用编程90
2.4.3串口使用读串口程序
/*com_reader.c*/#include<stdio.h>#include<stdlib.h>#include<string.h>#include<sys/types.h>#include<sys/stat.h>#include<errno.h>#include<termios.h>#include<fcntl.h>#defineTARGET_COM_PORT1#defineBUFFER_SIZE1024#defineMAX_COM_NUM4#include"uart_api.h"2.4嵌入式Linux串口应用编程91
2.4.3串口使用读串口程序
intmain(void){ intfd; charbuff[BUFFER_SIZE];
if((fd=open_port(TARGET_COM_PORT))<0)/*打开串口*/ { perror("open_port"); return1; } if(set_com_config(fd,115200,8,'N',1)<0)/*配置串口*/ { perror("set_com_config"); return1; }2.4嵌入式Linux串口应用编程92
2.4.3串口使用读串口程序
do {
memset(buff,0,BUFFER_SIZE); if(read(fd,buff,BUFFER_SIZE)>0) { printf("Thereceivedwordsare:%s",buff); } }while(strncmp(buff,"quit",4)); close(fd); return0;}2.4嵌入式Linux串口应用编程93
使用底层I/OAPI函数进行文件操作时,Linux必须从用户态切换到内核态,执行相应的请求,然后再返回到用户态。为提高程序的效率,应尽量减少系统调用的次数。标准I/O又称为高级磁盘I/O,在文件I/O的基础上进行了封装,目的是尽可能减少使用read()、write()等系统调用的数量。2.5标准I/O编程94
标准I/O提供了3种类型的缓冲存储:全缓冲:当填满标准I/O缓存后才进行实际的I/O操作。对驻留在磁盘上的文件访问通常是由标准I/O实施全缓冲的;行缓冲:当在输入和输出中遇到行结束符时,标准I/O库执行I/O操作。例如标准输入和标准输出。不带缓冲:不对字符进行缓冲。如果标准I/O函数写若干字符到不带缓冲的流中,则相当于用write系统调用将这些字符写到打开的文件上。2.5标准I/O编程2.5标准I/O编程文件指针标准I/O为每个被使用的文件在内存中开辟一个区域,用来存放文件的相关信息。这些信息被保存在一个由系统定义的结构体类型FILE中。在标准I/O中,流(stream)用FILE*来描述,所有的操作都是围绕流来进行的。FILE的具体定义如下:in<stdio.h>typedefstruct_IO_FILEFILE2.5标准I/O编程文件指针
in<libio.h>struct_IO_FILE{int_flags;……int_fileno;……}
FILE中的成员_fileno保存的就是流所对应的文件描述符。标准I/O库中预定义了3个流:标准输入(stdin)、标准输出(stdout)和标准错误(stderr)。97
2.5.1基本操作1.打开文件
打开文件有三个标准函数,分别为:fopen()、fdopen()和freopen()。它们可以以不同的模式打开,但都返回一个指向FILE的指针,该指针指向对应的I/O流。此后,对文件的读写都是通过这个FILE指针来进行。fopen()可以指定打开文件的路径和模式;fdopen()可以指定打开的文件描述符和模式;freopen()可以指定打开的文件、模式以及特定的I/O 流。2.5标准I/O编程98
2.5.1基本操作1.打开文件
fopen函数:Openafileandcreateanewstreamforit.
2.5标准I/O编程99
2.5.1基本操作1.打开文件
mode类似于open()函数中的flag,可以定义打开文件的访问权限等,下面为mode的各种取值:其中“b”表示打开的文件为二进制文件,而非纯文本文件。
2.5标准I/O编程100
2.5.1基本操作1.打开文件
fdopen()可以指定打开的文件描述符和模式。Createanewstreamthatreferstoanexistingsystemfiledescriptor.
mode取值同fopen
2.5标准I/O编程101
2.5.1基本操作1.打开文件
freopen()除可指定打开的文件、模式外,还可指定特定的I/O流。
Openafile,replacinganexistingstreamwithit.
mode取值同fopen
2.5标准I/O编程102
2.5.1基本操作2.关闭文件 关闭标准流文件的函数为fclose(),该函数将缓冲区内的数据全部写入到文件中,并释放系统所提供的文件资源。
fclose()函数格式:2.5标准I/O编程2.5标准I/O编程2.5.2读写操作1.按字符读/写文件一次读取或写入一个字符,如果流是带缓存的,由I/O函数来处理缓存。(1)函数说明在文件打开之后,可对文件流进行读写等操作。其中读文件的函数为fgetc/getc/getchar,写文件的函数为fputc/putc/putchar。(2)函数格式头文件#include<stdio.h>2.5标准I/O编程2.5.2读写操作1.按字符读/写文件函数原型intfgetc(FILE*stream); /*从指定的文件流中读取一个字符*/intgetc(FILE*stream);/*从指定的文件流中读取一个字符*/intgetchar(void);/*从标准输入读取一个字符*/intfputc(intc,FILE*stream);/*往指定的文件流写入一个字符*/intputc(intc,FILE*stream);/*往指定的文件流写入一个字符*/intputchar(intc);/*往标准输出写入一个字符*/
函数返回值成功:读取成功时返回读取的字符/写入成功时返回0失败:EOF2.5标准I/O编程2.按行读/写文件
一次读取或写入一行,通常以换行符作为一行的结束。(1)函数说明读文件的函数为fgets,写文件的函数为fputs/puts。(2)函数格式头文件#include<stdio.h>
函数原型char*fgets(char*s,intn,FILE*stream);/*从流stream中最多读取n-1个字符存放到缓冲区s*/intfputs(constchar*s,FILE*stream);/*将字符串s输出到流stream*/intputs(constchar*s);/*将字符串s输出到标准输出*/2.5.2读写操作2.5标准I/O编程2.按行读/写文件函数返回值fgets(成功:缓冲区的地址,即s的值/失败:NULL)fputs(成功:1/失败:EOF)puts(成功:字符串的长度加1/失败:EOF)(3)函数调用实例charbuf[20];fgets(buf,20,stdin);//从标准输入最多读取19个字符存放到缓冲区buf里fputs(“Hellotheworld“,stdout);//将字符串Hellotheworld写到标准输出puts(“Hellotheworld“);//将字符串Hellotheworld写到标准输出后再输出换行符2.5标准I/O编程3.按指定格式读/写文件
以指定的格式一次从文件中读取或写入若干个对象,通常用来处理二进制文件。(1)函数说明读文件的函数为fread,写文件的函数为fwrite。(2)函数格式头文件#include<stdio.h>2.5标准I/O编程3.按指定格式读/写文件
函数原型size_tfread/fwrite(void*ptr,/*存放读取/写入记录的缓冲区*/
size_tsize,/*读取/写入的记录大小*/
size_tnmemb,/*读取/写入的记录数*/
FILE*stream);/*要读取/写入的文件流*/
函数返回值成功:返回实际读取/写入的记录数目失败:EOF2.5标准I/O编程3.按指定格式读/写文件(3)函数调用实例FILE*stream;intarray[]={1,2,3,4,5,6,7,8};/*首先使用fopen以只写方式打开文件,之后再调用fwrite写入文件*/stream=fopen("data","w");if(stream==NULL)exit(-1);fwrite(array,sizeof(int),sizeof(array)/sizeof(int),stream);fclose(stream);
2.5标准I/O编程4.刷新流(1)函数说明强制刷新一个流,使该流所有未写的缓冲区数据写入到实际的流中(2)函数格式头文件#include<stdio.h>
函数原型intfflush(FILE*stream);
函数返回值成功:0失败:-12.5标准I/O编程4.刷新流(3)函数调用实例printf(“stdoutisline-buffered“);/*因为标准输出是行缓冲,所以没有遇到’\n’之前输出的内容先保存在标准输出缓冲区里*/sleep(2);//进程睡眠2秒钟fflush(stdout);//刷新标准输出流,缓冲区的内容被送到标准输出2.5标准I/O编程5.文件定位
(1)函数说明文件中有个位置指针,指向当前读写的位置。fseek/rewind可以改变文件的位置指针,ftell返回流式文件的当前位置。(2)函数格式头文件#include<stdio.h>
函数原型voidrewind(FILE*stream);//使位置指针重新指向文件的开始intfseek(FILE*stream,
longoffset,//位移量,以起始点为基准移动的字节数
intwhence);//起始点,SEEK_SET/SEEK_CUR/SEEK_ENDlongftell(FILE*stream);2.5标准I/O编程5.文件定位
函数返回值fseek(成功:0 失败:-1)ftell(成功:文件当前位置 失败:-1L)(3)函数调用实例FILE*fp=fopen(“data“,“r+“);//以读写方式打开文件inti=10;
if(fp==NULL)exit(-1);fseek(fp,0L,SEEK_END);//将文件指针定位到文件末尾fwrite(&i,4,1,fp);//写入新的内容fclose(fp);114
6.格式化输入/输出
2.5标准I/O编程115
6.格式化输入/输出
2.5标准I/O编程116
系统调用、用户(应用)编程接口(API)和系统命令的联系和区别。虚拟文件系统(VFS)及文件描述符。底层文件I/O操作(open,close,read,write,lseek等函数)文件锁(fcntl函数)多路复用(I/O处理的5种模型,poll函数的使用)嵌入式Linux串口编程(structtermios数据结构,tcgetattr,tcsetattr,fcntl,isatty函数)标准I/O(打开/关闭文件、字符I/O、行I/O、格式化I/O)小结117
文件的读写与上锁实验目的通过编写文件读写及上锁的程序,进一步熟悉Linux中文件I/O相关的应用开发,并且熟练掌握open()、read()、write()、fcntl()等函数的使用。实验内容在Linux中FIFO是一种进程之间的管道通信机制。Linux支持完整的FIFO通信机制,本实验通过使用文件操作,仿真FIFO(先进先出)结构以及生产者-消费者运行模型。2.6实验内容118
文件的读写与上锁本实验中需要打开两个虚拟终端,分别运行生产者程序(producer)和消费者程序(customer)。此时两个进程同时对同一个文件进行读写操作。因为这个文件是临界资源,所以可以使用文件锁机制来保证两个进程对文件的访问都是原子操作。先启动生产者进程,它负责创建仿真FIFO结构的文件(其实是一个普通文件)并投入生产,就是按照给定的时间间隔,向FIFO文件写入自动生成的字符(在程序中用宏定义选择使用数字还是使用英文字符),生产周期以及要生产的资源数通过参数传递给进程(默认生产周期为1秒,要生产的资源总数为10个字符,显然默认生产总时间为10秒钟)。后启动的消费者进程按照给定的数目进行消费,首先从文件中读取相应数目的字符并在屏幕上显示,然后从文件中删除刚才消费过的数据。为了仿真FIFO结构,此时需要使用两次拷贝来实现文件内容的偏移。每次消费的资源数通过参数传递给进程,默认值为10个字符。2.6实验内容119
文件的读写与上锁——生产者源程序/*producer.c*/#include<stdio.h>#include<unistd.h>#include<stdlib.h>#include<string.h>#include<fcntl.h>#include“lock_set.c"2.6实验内容120
文件的读写与上锁——生产者源程序constchar*fifo_file="./myfifo"; /*仿真FIFO文件名*/charbuff[MAXLEN]; /*缓冲区*/2.6实验内容121
文件的读写与上锁——生产者源程序constchar*fifo_file="./myfifo"; /*仿真FIFO文件名*/charbuff[MAXLEN]; /*缓冲区*/intproduct(void){ intfd; staticunsignedintcounter=0;
/*打开仿真FIFO文件*/ fd=open(fifo_file,O_CREAT|O_RDWR|O_APPEND,0644)2.6实验内容122
文件的读写与上锁——生产者源程
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2025年中国XPS挤塑保温隔热板市场调查研究报告
- 伐木劳动合同范例
- 公司聘请专家合同范例
- 储存合同范例写
- 冷干机维修合同范例
- 交付首付合同范例
- 分组协议合同范例
- 出租车客运司机合同范例
- 别墅构件租赁合同范例
- 俩人合伙开饭馆合同范例
- ICU重症患者康复护理
- 简单词考研英语5500单词表
- 金茂入职前的在线测评题
- 广东省佛山市2024年中考英语模拟试卷(含答案)
- ISO14644国际标准(中文版)
- DB22T 1189.2-2011 无公害农产品 天麻 第2部分:种子与种麻生产技术规程
- 2024数据智能白皮书
- 2024社工(初)《社会工作实务》考试题库附答案
- 2024年兰州市高三诊断考试(一诊)数学试卷(含答案)
- 办公耗材采购服务方案(技术方案)
- (高清版)JTGT 5532-2023 公路桥梁支座和伸缩装置养护与更换技术规范
评论
0/150
提交评论