mini2440应用例程学习(一)—— led-player

环境: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

#!/bin/sh<br>

base=led-player  //定义一个变量方便引用led-player程序<br>

# See how we were called.

case "$1" in      
//开关机时传递的参数,开机为start,关机为stop

  start)

                /usr/bin/$base
&   //开机运行该脚本时自动运行led-player于后台

        ;;

  stop)           //关机运行该脚本时终止led-player进程

        pid=`/bin/pidof $base//获取led-player进程号(反引号在shell中表示执行命令)

        if
[ -n "$pid"
]; then       //若字符长度非0,则执行kill -9 pid(led-player进程号)

                kill -9 $pid

        fi

        ;;

esac

exit 0

②  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

#include <stdio.h>

#include <stdlib.h>

#include <unistd.h>

#include <sys/ioctl.h>

#include <sys/types.h>

#include <sys/stat.h>

#include <fcntl.h>

#include <sys/select.h>

#include <sys/time.h>

#include <string.h>

static
int led_fd;      //静态变量,没有初始化则默认为0

static
int type = 1;

static
void push_leds(void)

{

        static
unsigned step;

        unsigned led_bitmap;

        int
i;

        switch(type) {

        case
0:             //当type变量值为0时,实现循环流水灯效果,即1-2-3-4-3-2-1如此循环

                if
(step >= 6) {

                        step = 0;

                }

                if
(step < 3) {       

                        led_bitmap = 1 << step;

                } else
{

                        led_bitmap = 1 << (6 - step);

                }

                break;

        case
1:    /*默认type变量值为1,实现累加器功能,即0000-0001-0010-0011-0100-0101...依次累加(1表示灯亮)*/

                if
(step > 255) {

                        step = 0;

                }

                led_bitmap = step;     //此时led_bitmap为8位二进制数

                break;

        default:

                led_bitmap = 0;

        }

        step++;      //每次调用执行本函数则step自加1

        for
(i = 0; i < 4; i++) {              

                ioctl(led_fd, led_bitmap & 1, i);   //控制leds设备,分四次写入相应的值,估计i是写入驱动设备的位置参数

                led_bitmap >>= 1;

        }

}

int
main(void)

{

        int
led_control_pipe;

        int
null_writer_fd;    // for read endpoint not blocking when control process exit

        double
period = 0.5;

        led_fd = open("/dev/leds0", 0);           //以只读方式打开设备leds0

        if
(led_fd < 0) {

                led_fd = open("/dev/leds", 0);     //mini2440开发板上的是这个设备

        }

        if
(led_fd < 0) {

                perror("open device leds");

                exit(1);

        }

        unlink("/tmp/led-control");                //删除指定文件

        mkfifo("/tmp/led-control", 0666);      //创建指定命名管道文件,权限为0666(首位0表示这个数为八进制数)

        led_control_pipe = open("/tmp/led-control", O_RDONLY | O_NONBLOCK);

        if
(led_control_pipe < 0) {

                perror("open control pipe for read");

                exit(1);

        }

        null_writer_fd = open("/tmp/led-control", O_WRONLY | O_NONBLOCK);

        if
(null_writer_fd < 0) {

                perror("open control pipe for write");

                exit(1);

        }

        for
(;;) {

                fd_set rds;

                struct
timeval step;

                int
ret;

                FD_ZERO(&rds);                            //将rds描述符集清零

                FD_SET(led_control_pipe, &rds);     //将rds描述符集中描述符led_control_pipe对应的位置1

                step.tv_sec  = period;       

                step.tv_usec = (period - step.tv_sec) * 1000000L;

                ret = select(led_control_pipe + 1, &rds, NULL, NULL, &step);  //只关心readfds描述符集,其他两个为NULL

                if
(ret < 0) {                                

                        perror("select");

                        exit(1);

                }

                if
(ret == 0) {                                      //指定等待时间已超过而指定的描述符还没准备好

                        push_leds();

                } else
if (FD_ISSET(led_control_pipe, &rds)) {

                        static
char buffer[200];

                        for
(;;) {

                                char
c;

                                int
len = strlen(buffer);

                                if
(len >= sizeof
buffer - 1) {

                                        memset(buffer, 0, sizeof
buffer);         //对buffer数组初始化

                                        break;

                                }

                                if
(read(led_control_pipe, &c, 1) != 1) {   //从命名管道文件led-control中读取一个字节

                                        break;

                                }

                                if
(c == ‘\r‘) {                              //读出字符为回车符,则忽略后面的语句,重新循环

                                        continue;

                                }

                                if
(c == ‘\n‘) {                             //读出字符为换行符

                                        int
tmp_type;

                                        double
tmp_period;

                                        if
(sscanf(buffer,"%d%lf", &tmp_type, &tmp_period) == 2) {

                                                type = tmp_type;

                                                period = tmp_period;

                                        }

                                        fprintf(stderr, "type is %d, period is %lf\n", type, period);     //将参数type、period输出到终端显示

                                        memset(buffer, 0, sizeof
buffer);        //成功取完一次参数,将buffer数组清零

                                        break;

                                }

                                buffer[len] = c;        //将读到的字符写入buffer数组(前面的程序已经实现舍弃回车符和换行符)

                        }

                }

        }

        close(led_fd);        //关掉leds设备

        return
0;

}

参考资料:
 
         ①《Unix环境高级编程》
    
      ②《嵌入式Linux应用程序开发详解》(华清远见-电子版)
 
         ③《C Primer Plus中文版》
 
         ④mini2440用户手册
    
      ⑤源码来自mini2440开发板自带光盘盘

mini2440应用例程学习(一)—— led-player

时间: 2024-08-01 19:59:48

mini2440应用例程学习(一)—— led-player的相关文章

led液晶显示屏播放器LED Player详细使用教程

LED Player显示屏播放器是一个专业的LED屏显播放器,给用户带来全新操控体验的高能单双色软件,更方便易用,更具性价比,更多显示效果,led显示屏播放器支持多页面多分区的节目编辑,提供了丰富灵活的视频切换功能.分区特效,以及三维特效动画.该软件搭建了一个能让您充分发挥创意的平台,让显示屏的显示效果得到完美展现. LEDPlayer支持ZH系列接收卡.发送卡,支持一台PC机控制多个LED显示屏, 支持对LED显示屏的智能参数设置. 一.屏参设置: 打开LED Player 6.0软件,点击[

JAVAweb例程学习源码分享,超级全!

JAVAweb例程学习源码分享,超级全!我自己也从里面学习到了很多东西! 1.BBS论坛系统(jsp+sql)2.ERP管理系统(jsp+servlet)3.OA办公自动化管理系统(Struts1.2+Hibernate3.0+Spring2+DWR)4.博客系统(struts+hibernate+spring)5.车辆管理系统(struts+hibernate+spring+oracle)6.家庭理财系统(java+applet)7.教材订购系统(jsp+servlet+mysql)8.酒店管

caffe笔记之例程学习

学习notebook自带例程Classification with HDF5 data时遇到了一些问题,认真把模型文件看了一遍. 模型定义中有一点比较容易被误解,信号在有向图中是自下而上流动的,并不是自上而下. 层的结构定义如下: 1 name:层名称 2 type:层类型 3 top:出口 4 bottom:入口 Each layer type defines three critical computations: setup, forward, and backward. Setup: i

开始看《第二行代码》及官方第一个例程学习(部分)

本来是想先看看官方的例子学的,结果第一个就碰到问题了...果然有点不合适,上网找了一些书籍,发现第一行代码不错,可惜是基于eclipse的,偶然看到出第二版了,还基于Android studio  我立马决定照着这本教材学!!!开始之前我就想先找找书上例子的源码,结果发现书上开头几页已经写了网址了,去github找到后就是复制链接 然后下载git,用Android studio 导入进去,具体上网搜,导入进去之后可能会有一点错误,反正我的是有些东西没装,点下面错误里的内容就自动安装能直接编译运行

caffe笔记之例程学习(三)

原文链接:caffe.berkeleyvision.org/tutorial/layers.html 创建caffe模型,首先要在protocol buffer 定义文件(prototxt)中定义结构. 在caffe环境中,图像的明显特征是其空间结构. Convolution: Documents: 1 Parameters (ConvolutionParameter convolution_param) 2 3 Required 4 num_output (c_o): 输出数(filter数)

跟韦老师学习嵌入式-LED总结

本文内容由浅入深主要介绍了JZ2440的LED裸板程序,LED的简单驱动程序 一.LED裸板程序 arm开发板的裸板程序和51单片机类似,需要通过配置寄存器来实现.s3c2440有130个I/O口,共分为A-J共9组. 1.硬件原理图: JZ2440的硬件连接图,如下图所示: 从图中可以看出LED1.LED2.LED3.LED4这四个LED灯分别于GPB5-GPB8相连,因此需要通过控制GPB5-GPB8的寄存器的输出来控制,LED等的亮灭. 2.寄存器的配置 s3c2440的I/O口可以用于输

驱动学习之LED驱动框架

一:什么是驱动框架  (1)内核中驱动部分维护者针对每个种类的驱动设计一套成熟的.标准的.典型的驱动实现,然后把不同厂家的同类硬件驱动中相同的部分抽出来自己实现好,再把不同部分留出接口给具体的驱动开发工程师来实现,这就叫驱动框架.  (2)内核维护者在内核中设计了一些统一管控系统资源的体系,这些体系让内核能够对资源在各个驱动之间的使用统一协调和分配,保证整个内核的稳定健康运行.譬如系统中所有的GPIO就属于系统资源,每个驱动模块如果要使用某个GPIO就要先调用特殊的接口先申请,申请到后使用,使用

caffe笔记之例程学习(二)

Classification with HDF5 data 1.导入库 1 import os 2 import h5py 3 import shutil 4 import sklearn 5 import tempfile 6 import numpy as np 7 import pandas as pd 8 import sklearn.datasets 9 import sklearn.linear_model 10 import matplotlib.pyplot as plt 11

WLGK-51单片机接口技术基础实验 ——LED闪烁灯

WLGK-51单片机接口技术基础实验-LED闪烁灯 当我们开始接触单片机,首先接触的第一个实验就是LED灯的使用,类似于我们学习软件开始接触的第一个程序"HelloWorld",这个实验是带领我们走入"软硬件综合使用"的一个很好入门示例,51单片机是他的一个载体.下面小伙伴们,让我们一起来揭开LED的神秘面纱吧! 万立高科官网:www.wanligaoke.com 万立高科官方商城:http://www.wlgkbj.com 万立高科淘宝直销店铺:https://r