环境:mini2440开发板
一、led-player程序在mini2440上运行的流程:
① 开机进入系统后,将会自动运行一个LED服务程序(/etc/rc.d/init.d/leds),leds是一个脚本文件,它调用了并运行/usr/bin/led-player。以下是leds脚本的内容:
?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
|
② led-player运行时会在/tmp目录下创建一个led-control管道文件,如果没有向管道写入规定参数,则执行默认累加器模式。向该管道文件发送不同的参数就可以改变led的闪烁模式:
#echo 0 0.2
>/tmp/led-control
运行该命令后,4个用户led将会以每个间隔0.2秒的时间运行跑马灯;
#echo 1
0.2>/tmp/led-control
运行该命令后,4 个用户led 将会以间隔
0.2秒的时间运行累加器;
#/etc/rc.d/init.d/ledsstop
运行该命令后,4 个用户led
将会停止闪动;
#/etc/rc.d/init.d/ledsstart
运行该命令后,4 个用户led
将会重新开始闪动。
二、led-player.c源码文件解读分析:
(1)重温基础知识:
① static修饰词用来声明变量,如果没有初始化变量值,则默认为0;
② open函数的原型为int
open(const chat *pathname,intoflag,…/*多个参数*/),
oflag参数常用取值:
O_RDONLY:只读打开
O_WRONLY:只写打开
O_RDWR:读、写打开
注:很多实现将O_RDONLY定义为0,O_WRONLY定义为1,O_RDWR定义2,以与早期的系统兼容。
O_NONBLOCK:如果pathname指的是一个FIFO、一个块特殊文件或一个字符特殊文件,则此选择项为此文件的本次打开操作和后续的I/O操作设置非阻塞方式。
③ close函数:函数原型为int
close(int filedes);
filedes参数为文件的描述符,当一个进程终止时,它所有的打开文件都由内核自动关,很多程序一般不显示地使用close关闭打开的文件。
④ perror函数:函数原型为void perror(const char
*s);perror( )
用来将上一个函数发生错误的原因输出到标准设备(stderr)。参数s所指的字符串会先打印出,后面再加上错误原因字符串。此错误原因依照全局变量errno
的值来决定要输出的字符串。
⑤ unlink函数:函数原型为int
unlink(const char
*pathname);此函数删除一个现存的目录项,并将由pathname所引用的文件的链接计数减1。如果该文件还有其他链接,则仍可以通过其他链接存取该文件的数据。如果出错,则不对该文件作任何操作。
⑥ mkfifo函数:函数原型为int
mkfifo(const char
*pathname,mode_tmode);FIFO称为命名管道。管道只能由相关进程使用,它们的共同祖先进程创建了管道。但是通过FIFO,不相关的进程也能交换数据。mkfifo函数用于创建FIFO文件,其中mode参数的规格说明与open函数中的mode相同。
⑦ select函数:函数原型为int
select(int nfds,fd_set* readfds, fd_set* writefds,
fd_set* exceptfds, struct timeval*
timeout);被定义在sys/select.h文件里,使用此函数需要要包含头文件sys/time.h。nfds为需要检查的号码最高的文件描述符加1;readfds为由select()监视的读文件描述符集合;writefds为由select()监视的写文件描述符集合;exceptfds为由select()监视的异常处理文件描述符集合;timeout为超时等待时间。为了维护fd_set类型的参数,会使用下面四个宏:FD_SET(),FD_CLR(),
FD_ZERO() 和 FD_ISSET()。这个函数的返回值:
1) 返回-1表示出错。例如在所指定的描述符都没有准备好时捕捉到一个信号;
2) 返回0表示没有描述符准备好。若指定的描述符都没有准备好,而且指定的时间已经超过,则发生这种情况。
3) 返回一个正值说明已经准备好的描述符数。在这种情况下,三个描述符集中仍旧打开的位是对应于已准备好的描述符位。
⑧ fd_set类型:其实是select()机制中的一种数据结构。详见华清远见的《嵌入式Linux应用程序开发详解》。其中select()函数常用的文件描述符处理宏函数有以下几个:
FD_ZERO(fd_set*set):清除一个文件描述符集;
FD_SET(intfd,fd_set
*set):将一个文件描述符加入文件描述符集中;
FD_CLR(intfd,fd_set
*set):将一个文件描述符从文件描述符集中清除;
FD_ISSET(intfd,fd_set
*set):测试该集中的一个给定位是否有变化。
一般来说,在使用select函数之前,首先使用FD_ZERO和FD_SET来初始化文件描述
符集,在使用了select函数时,可循环使用FD_ISSET测试描述符集,在执行完对相关文件描述符测试后,可以使用FD_CLR来清除相应的描述符集。
注:为方便理解select工作机制最好查阅《Unix环境高级编程》的第12章高级I/O。
⑨ struct
timeval结构体:结构体原型为
struct timeval
{
long
tv_sec; /* Seconds. */
long
tv_usec; /*Microseconds. */
};
在select机制中应用时有以下三种情况:
1) timeout=NULL:永远等待。如果捕捉到一个信号则中断此无限期等待。当所有指定的描述符中的一个已准备好或捕捉到一个信号则返回。如果捕捉到一个信号,则select返回-1,errno设置为EINTR。
2) timeout->tv_sec==0&&timeout->tv_usec==0:完全不等待。测试所有指定的描述符并立即返回。这是得到多个描述符的状态而不阻塞select函数的轮询方法。
3) timeout->tv_sec!=||timeout->tv_usec!=0:等待指定的秒数和微秒数。当指定的描述符之一已准
备好,或当指定的时间值已经超过时立即返回。如果在超时时还没有一个描述符准备好,则返回值是0,(如果系统不提供微秒分辨率,则
timeout->tv_usec==0值取整到最近的支持值。)与第一种情况一样,这种等待可被捕捉到的信号中断。
⑩ ioctl函数:函数原型为int
ioctl(int fd, unsigned long cmd, …)
;ioctl是设备驱动程序中对设备的I/O通道进行管理的函数。fd就是用户程序打开设备时使用open函数返回的文件标示符,cmd就是用户程序对设
备的控制命令,后面的省略号是一些补充参数,一般最多一个,有或没有是和cmd的意义相关的。
? memset函数:函数原型为void *memset(void *s, int
ch, size_t n); 将s中前n个字节(typedef unsigned int size_t)用 ch 替换并返回 s 。
? read函数:函数原型为ssize_t read(int
filedes,void *buff, size_t
nbytes);如read成功,则返回读到的字节数,如已到达文件的尾端,则返回0.
? sscanf函数:函数原型为int
sscanf(const char *buf,const char *format,
…);从buf里按照format格式读取相应类型的数据到指定地方。
? fprintf函数:函数原型为int fprintf(FILE *fp,
const char *format,
…);函数将格式化的字符串输出到指定文件fp中。函数成功则返回格式化输出的字节数。(不包括字符串的结尾’\0’),出错返回一个负值,错误原因在error中。
? stderr:标准错误输出,默认输出到终端窗口,文件描述符为2。
(2)led-player源代码及注释
?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 |
|
参考资料:
①《Unix环境高级编程》
②《嵌入式Linux应用程序开发详解》(华清远见-电子版)
③《C Primer Plus中文版》
④mini2440用户手册
⑤源码来自mini2440开发板自带光盘盘
mini2440应用例程学习(一)—— led-player