|
|
EDA365欢迎您登录!
您需要 登录 才可以下载或查看,没有帐号?注册
x
在 linux 驱动中字符设备驱动是必须掌握的,本章主要介绍字符设备应用的程序,无论是学习了后面的知识自己写的字符驱动,还是已有的字符驱动,都需要能够写一些简单的应用程序。即使从事 Linux 驱动方面的工作,Linux 驱动写出来之后,也需要由驱动程序员编写简单的应用程序来进行测试的。, [3 K \: `% d5 q
另外,关于驱动部分,迅为电子有专门的驱动实验教程提供给大家学习,大家有了这些基础之后再去学习底层的知识就会很容易了。$ f" R: k5 O" b6 m6 U
在本手册的 10.22 章节,大家可以看到这些 C 程序也是可以在 Android 下面运行的,只不过没有图形界面。
) I5 B8 H4 j z! V' M7 t6 y2 A本章配套视频为:$ f- J7 f- A, f) e/ H2 L
“视频 06_01 字符设备控制之 main 函数传参数”9 \( G v' N6 j- y- |
“视频 06_02 字符设备控制之 led 灯”
. D' }4 x. v! ^9 g$ f" `; H1 f, k0 ^5 J“视频 06_03 字符设备控制之 buzzer 蜂鸣器”: \- ?5 I( r, C$ a' {; o1 ~
“视频 06_04 字符设备控制之 ADC 模数转换”
) g0 p$ b' {( k$ ~17.1 入口 main 函数的参数' P8 t% A4 o6 p$ |
在和用户交流的过程中,虽然所有人都学习过 C 语言,但是对 C 语言中的 main 函数的用法并不是很清楚。由于后面的实验需要用到这部分知识,这里就占用一个小节,先简单介绍一下 main 函数。& E1 G' ~7 ^7 e- T8 w& p5 }
main 函数简介
! Z1 c& i/ J4 \% J+ T& ^9 lmain 函数作为应用程序的入口,在头文件“#include ”中。main 函数需要传参数的时候完整的定义为
- y: x5 f/ N* T+ rint main(int argc,char **argv)
; k2 _: O' p0 g0 t3 ?, W参数 argc,表示参数的个数
! C/ {# O$ V5 K( ~; n" L. E( b参数**argv,存储输入字符的数组,argv[0]表示程序名称,argv[1]——argv[n]输入的参数8 E# b" v, X; u# T7 T; ]
不传参数的时候定义为
1 B/ a3 h: |( C: P/ bint main(void)
7 ~6 K4 g; R- m9 |) I! \# g' p函数 main 的返回值为类型为 int,用于判断程序执行成功还是失败
$ d. T$ m' q: J5 r/ D' L# amain 函数例程
. m5 i/ G9 w$ |2 j编写简单的 argvc.c 文件测试 main 函数。# F& q# C% Y7 f6 n* }
" c- b9 @4 |( v# K4 K
如上图所示,将输入的参数第一个和第二个转换成 int 类型,赋值给 i 和 j,最后输出打印。+ N! y( M- i! X
其中 argv[0]为程序名称,这里就是后面要编译的目标文件“argvc”。* y6 M0 A6 f; k; ~7 \4 W
R- R. P3 {5 I
编译运行测试8 h5 h2 Z5 z- ?# {" v
在 Ubuntu 系统下,如下图所示,进入前面实验创建的目录“/home/linuxsystEMCode/”,使用命令“mkdircharcontrol”新建 charcontrol 文件夹,将源码 argvc.c 拷贝进去,进入新建的文件夹 charcontrol,如下图所示。9 d( ~( q1 v ~) j/ q2 f8 m
0 R& u: k R1 z y4 v
使用命令“ARM-none-linux-gnueabi-gcc -o argvc argvc.c -static”编译 argvc 文件, 如下图所示,使用命令“ls”可以看到生成了 argvc 可执行文件。
& {' m- R9 }; K- G% v 9 t& _# D) g' O) G# p/ w
这里介绍 U 盘拷贝代码的方法,也可以编译进文件系统,具体方法参考 10.3.5 小节。 将编译成的可执行文件 argvc,拷贝到 U 盘,启动开发板,插入 U 盘,加载 U 盘,运行程序如下。
' U/ M% `3 n5 R3 e / D9 \1 ]7 {8 x% b' ~
如上图所示,程序成功运行,打印:5 p. G8 Z$ C0 F/ Z& Z
the Program name is ./mnt/udisk/argvc。# M& J' A. Y; i
因为运行的程序就是“./mnt/udisk/argvc”,这是第一个参数
+ | x/ V/ G1 ~- d4 yThe command line has 2 argument:
1 ]" q( V& X8 B: h) s0 b& r+ v# U10,11。+ B N+ ?8 `7 F# C
, n( C# X+ O+ z; U. U s
输入的参数是 10 和 11,对应 argv[2]和 argv[2]。' ?# P; W% t6 w5 \) z
17.2 字符类 led 灯
1 H8 x. c4 G7 O B在前面介绍 open 函数的时候,已经提到过如何打开字符类设备,获得句柄的方法和一般文件都是一样。
* K, t" M& b, _# ?0 ZLed 灯的设备节点在/dev 目录下,如下图所示,在超级终端可以使用 ls 命令查找。
1 s. C' M* ]! w2 Q4 ]) g![]()
' j, y( r: P0 p由于涉及到硬件知识,这里简单介绍一下硬件原理,如下图所示,led 小灯的硬件原理很简单。
0 a6 N5 O" [5 ~![]()
1 b0 n; [; |8 W, o( V如上图所示,给 KP_COL0 和 VDD50_EN 网络高电平,三极管 L9014 就会导通,电源 VSYS 就会将电压加到电阻 R 和 led 小灯上,小灯就会亮。
& B/ Z8 T1 H8 _给 KP_COL0 和 VDD50_EN 网络低电平,三极管 L9014 就会截止,形成断路,小灯灭。
4 F `* I8 y( D, P" w! e( |9 H在前面介绍过,如果要给文件进行写操作,那么使用的是 write 函数。对于 led 小灯的操作,使用写函数,理论上也是可以的。但是对于 IO 口(这里的 IO 口指的是硬件上的 IO 口, 不是指 IO 文件)的- S% w# A/ o2 z% k5 j4 _
* Z! z% H+ M" z操作,Linux 专门设计了一个高效的函数 ioctl。 f5 r* n# ^- S' S' {, |# _! B' ~
这个函数在头文件#include中。* ~ \0 J6 W$ X$ _4 }6 T4 i
int ioctl( int fd, int request, int cmd);
8 F1 k8 a5 Z: m- h& G: Q参数 fd,函数 open 返回的句柄。
- e0 p* g k" H% t5 ]( M参数 request 和参数 cmd,由内核驱动决定具体操作,例如 request 可以代表那个 IO 口,cmd 代表对 IO 进行什么样的操作,也可以反过来。具体的含义由驱动工程师在驱动中 switch 决定。5 }7 f' K; d# a
返回值:返回 0 成功;返回-1,出错。7 c; p' R8 `* m0 U F" S
+ `* V, T% _' f5 a
小灯测试例程! H j# A4 S4 F4 _/ @( g
编写简单的 leds.c 文件测试小灯。首先添加头文件,如下图所示。2 K1 j) k! W ^
通过 main 参数传过来的参数是 char 字符格式的,如果要传递给 ioctl 函数,需要用到数值转化函数atoi,添加了头文件#include 。
- i: h, i5 P2 Z) ~接着由于小灯的数量和命令都是 2,所以对小灯数量和操作数进行宏定义( R/ v5 }" H6 T. q" ?: z
#define LED_NUM 2
( e$ \; J' t1 Z8 q- p- @# r4 M#define LED_C 2。0 M/ g4 E8 O# ^9 b+ L
u, B- \* f* l8 h
然后 main 函数如下图所示。' w5 w9 @) I, P/ F
![]()
# T0 E2 H6 o: y) A如上图所示。
% T1 b2 M: o; D: O6 y Q$ ?/ T第 33 行,调用了 ioctl 函数,将 main 函数的第一个和第二个参数传入驱动。$ H- l+ [4 V) r q% n) e6 w2 C
第 19 行,解释那个参数具体代表什么含义,"argv1 is cmd;argv2 is io”,参数 1 对应命令,参数 2 对应具体那个 led 灯。9 P. D2 X$ z; Q, |1 [" M1 \2 k
第 36 行,将打开的设备节点"/dev/leds"关闭。
# N" Z2 u; d6 N3 ]9 Q" y5 c. ^, X4 o4 [2 g
编译运行测试: @, k& o q5 _3 G# {0 u+ P
在 Ubuntu 系统下,如下图所示,进入前面实验创建的目录“/home/linuxsystemcode/charcontrol”,将源码 leds.c 拷贝进去,如下图所示。, g1 V2 _1 H/ @ K, W l
" C+ U* n/ H: `- B( [1 f1 A
使用命令“arm-none-linux-gnueabi-gcc -o leds leds.c -static”编译 leds 文件,如下图所示,使用命令“ls”可以看到生成了 leds 可执行文件。2 R6 r% l9 M. m
![]()
, E9 n* S% c) B: D$ q+ A5 ?6 k* \这里介绍 U 盘拷贝代码的方法,也可以编译进文件系统,具体方法参考实验 02
- X1 @3 N# k) Q# ?9 [1 ~" c; r( ?将编译成的可执行文件 open,拷贝到 U 盘,启动开发板,插入 U 盘,加载 U 盘,运行程序如下。
5 B- A$ i7 `& o( f! |; J0 e& ]如下图所示,如果不加参数会有提示,然后报错。
* `0 e: S# f- p4 }: B d; E 4 O& E- v3 a% [ [2 M1 b- f
如下图所示,使用命令“./mnt/udisk/leds 0 0”运行,可以看到靠近蜂鸣器的小灯灭了。
0 T/ C4 x# A: t. `1 g) U: B![]()
2 r$ F2 }2 Q! \( |所有参数对小灯的控制如下:
( R. o- v! z6 s A& y# w0 0 靠近蜂鸣器的小灯灭;/ Y/ J0 _8 P% }* J1 ~
0 1 靠近按键的小灯灭;
8 [! Y3 l* p0 e6 H5 f1 0 靠近蜂鸣器的小灯亮;* | s$ H2 s& s' D5 \
1 1 靠近按键的小灯亮。用户可以自行测试一下。8 h; z+ i0 t2 L* `2 M) c. \ a0 i
![]()
8 g8 _. S9 s) Y7 I1 G5 _* a; N |
|