|
|
EDA365欢迎您登录!
您需要 登录 才可以下载或查看,没有帐号?注册
x
在 linux 驱动中字符设备驱动是必须掌握的,本章主要介绍字符设备应用的程序,无论是学习了后面的知识自己写的字符驱动,还是已有的字符驱动,都需要能够写一些简单的应用程序。即使从事 Linux 驱动方面的工作,Linux 驱动写出来之后,也需要由驱动程序员编写简单的应用程序来进行测试的。2 [1 `; x$ f* Z5 I% P1 \6 N: O
另外,关于驱动部分,迅为电子有专门的驱动实验教程提供给大家学习,大家有了这些基础之后再去学习底层的知识就会很容易了。
: V2 K; V+ j5 k在本手册的 10.22 章节,大家可以看到这些 C 程序也是可以在 Android 下面运行的,只不过没有图形界面。
8 @+ h, E; w1 n本章配套视频为:" O, [+ M1 I' e4 m3 R' M* `3 r
“视频 06_01 字符设备控制之 main 函数传参数”0 U0 b* m ?- n% x
“视频 06_02 字符设备控制之 led 灯”
0 p, ~$ R4 S% A) `( ?2 d8 f“视频 06_03 字符设备控制之 buzzer 蜂鸣器”( |6 Y- w+ ]$ }: G1 l0 A+ J
“视频 06_04 字符设备控制之 ADC 模数转换”
W: p& U+ e+ p8 p$ H( Q8 E17.1 入口 main 函数的参数2 f" O! b, V; @7 H
在和用户交流的过程中,虽然所有人都学习过 C 语言,但是对 C 语言中的 main 函数的用法并不是很清楚。由于后面的实验需要用到这部分知识,这里就占用一个小节,先简单介绍一下 main 函数。* q; _+ b) o0 U0 ~" E2 {
main 函数简介
. R5 @4 L4 I, y. R+ y! C+ wmain 函数作为应用程序的入口,在头文件“#include ”中。main 函数需要传参数的时候完整的定义为* ~- N8 ?8 i" H+ W/ r% u8 J% w0 c
int main(int argc,char **argv)
* e# x, [; q/ F2 l参数 argc,表示参数的个数$ ], S1 F2 L- v0 ~2 N$ {( H# X
参数**argv,存储输入字符的数组,argv[0]表示程序名称,argv[1]——argv[n]输入的参数4 k* f% X0 A0 K: j
不传参数的时候定义为
& ^- I/ [( e" B# d2 jint main(void)3 {4 a J* h- i1 w9 Q
函数 main 的返回值为类型为 int,用于判断程序执行成功还是失败
1 m- I( Y% H4 Y. T$ B4 q7 }& @& f1 dmain 函数例程2 @& |& k* n7 p" `! H. U) @* q
编写简单的 argvc.c 文件测试 main 函数。2 G. S( ?, P W& |8 r* P6 D: {
![]()
+ k9 e, z; w6 D5 k* W- K如上图所示,将输入的参数第一个和第二个转换成 int 类型,赋值给 i 和 j,最后输出打印。7 _) ?3 A! k$ R6 x$ {
其中 argv[0]为程序名称,这里就是后面要编译的目标文件“argvc”。4 ~6 `1 S8 P; ^* i7 i
0 h3 i* S' e* v' C
编译运行测试* _* x7 b/ M0 c* N" j1 X
在 Ubuntu 系统下,如下图所示,进入前面实验创建的目录“/home/linuxsystEMCode/”,使用命令“mkdircharcontrol”新建 charcontrol 文件夹,将源码 argvc.c 拷贝进去,进入新建的文件夹 charcontrol,如下图所示。
0 I8 W1 `5 b7 l' r8 k ! n7 J, u% {/ _0 K
使用命令“ARM-none-linux-gnueabi-gcc -o argvc argvc.c -static”编译 argvc 文件, 如下图所示,使用命令“ls”可以看到生成了 argvc 可执行文件。
6 G9 k( F/ `& x/ k![]()
1 a; i8 Z) _- {! Z这里介绍 U 盘拷贝代码的方法,也可以编译进文件系统,具体方法参考 10.3.5 小节。 将编译成的可执行文件 argvc,拷贝到 U 盘,启动开发板,插入 U 盘,加载 U 盘,运行程序如下。- q% X" r3 d! h) T
1 v* b8 D9 a% @* f
如上图所示,程序成功运行,打印:/ [$ l' B8 B0 e/ h; B
the Program name is ./mnt/udisk/argvc。
4 C$ O+ ~7 c: D# ?) E7 p! o因为运行的程序就是“./mnt/udisk/argvc”,这是第一个参数2 U1 m: o- B* J
The command line has 2 argument:
\3 r! ^& n: J( {10,11。
2 {) @" q* L \1 k5 W. ?) a' m0 u* T1 A" V$ i4 u# R
输入的参数是 10 和 11,对应 argv[2]和 argv[2]。
& a) `5 ^0 R" l3 s0 e17.2 字符类 led 灯, l, X! j* n, Q0 p( t! Y
在前面介绍 open 函数的时候,已经提到过如何打开字符类设备,获得句柄的方法和一般文件都是一样。
7 q+ T; k$ d0 K5 pLed 灯的设备节点在/dev 目录下,如下图所示,在超级终端可以使用 ls 命令查找。6 x C+ q' i$ k3 N( J
% |1 e: \# {8 M1 q/ h- }
由于涉及到硬件知识,这里简单介绍一下硬件原理,如下图所示,led 小灯的硬件原理很简单。
6 H' v, i- O& D/ h0 a![]()
7 J. ^2 v1 ^' i% A如上图所示,给 KP_COL0 和 VDD50_EN 网络高电平,三极管 L9014 就会导通,电源 VSYS 就会将电压加到电阻 R 和 led 小灯上,小灯就会亮。3 ^, A* I, \: p- W3 f; Y* e& l
给 KP_COL0 和 VDD50_EN 网络低电平,三极管 L9014 就会截止,形成断路,小灯灭。, Y! }! L$ g! B
在前面介绍过,如果要给文件进行写操作,那么使用的是 write 函数。对于 led 小灯的操作,使用写函数,理论上也是可以的。但是对于 IO 口(这里的 IO 口指的是硬件上的 IO 口, 不是指 IO 文件)的+ p/ s4 H1 k2 p+ h, [
/ |! ^2 p! F3 S; R; i操作,Linux 专门设计了一个高效的函数 ioctl。
& ?8 m. e; `# f. F9 k1 c$ @. ]0 ~这个函数在头文件#include中。
: y# y, a3 ~0 f8 aint ioctl( int fd, int request, int cmd);0 \" U) }9 D9 @9 ?( a
参数 fd,函数 open 返回的句柄。7 Z9 F2 j" i; h; G( H' _' N# N
参数 request 和参数 cmd,由内核驱动决定具体操作,例如 request 可以代表那个 IO 口,cmd 代表对 IO 进行什么样的操作,也可以反过来。具体的含义由驱动工程师在驱动中 switch 决定。
" l" w' U& Q( q; A- k! q5 a: Z) k返回值:返回 0 成功;返回-1,出错。
/ x1 Y1 Y$ i( ~/ n& C& R5 `
7 y- m1 G$ p; l小灯测试例程1 o) ?7 F) Y( r. O' T
编写简单的 leds.c 文件测试小灯。首先添加头文件,如下图所示。* m% l) J5 Q/ e$ Y! N
通过 main 参数传过来的参数是 char 字符格式的,如果要传递给 ioctl 函数,需要用到数值转化函数atoi,添加了头文件#include 。# ^% E, F% H! E4 x a4 U; P
接着由于小灯的数量和命令都是 2,所以对小灯数量和操作数进行宏定义6 p1 M- q# u, q1 J0 d2 L, |" f
#define LED_NUM 2& P F& k! G, U3 n
#define LED_C 2。% h/ H. i/ [# X; c
![]()
: N" S' q; k% w5 Z然后 main 函数如下图所示。0 ^3 B% C/ S" j- G: s
![]()
) s U& e. ^6 e. h5 ]: q如上图所示。% M$ I) J8 o! G- e# i% ]+ J5 x
第 33 行,调用了 ioctl 函数,将 main 函数的第一个和第二个参数传入驱动。# V# z) h7 i) u7 T3 W F
第 19 行,解释那个参数具体代表什么含义,"argv1 is cmd;argv2 is io”,参数 1 对应命令,参数 2 对应具体那个 led 灯。5 L( p+ o! W# k1 ]% }' p/ o8 H
第 36 行,将打开的设备节点"/dev/leds"关闭。
. ~+ ]" u- p4 o" Z4 i5 n
0 b4 g6 I' N" f% P: w: a; k! D/ C H编译运行测试
9 ~- O0 x+ P3 s, N在 Ubuntu 系统下,如下图所示,进入前面实验创建的目录“/home/linuxsystemcode/charcontrol”,将源码 leds.c 拷贝进去,如下图所示。
2 C) e$ t* y: |' t0 _![]()
; F4 D: y8 `. [% ~' Y5 o使用命令“arm-none-linux-gnueabi-gcc -o leds leds.c -static”编译 leds 文件,如下图所示,使用命令“ls”可以看到生成了 leds 可执行文件。$ f) p, P" @' S- l: ]* N
; [# N6 s6 l; K6 J1 |
这里介绍 U 盘拷贝代码的方法,也可以编译进文件系统,具体方法参考实验 02
6 J7 I+ D ~- d" @/ y4 j将编译成的可执行文件 open,拷贝到 U 盘,启动开发板,插入 U 盘,加载 U 盘,运行程序如下。8 \9 V. b, y/ e; S5 m5 V6 b
如下图所示,如果不加参数会有提示,然后报错。+ [ d; u# [! G# O# u6 h' d
" }2 O1 ~# p7 `! Z9 B: Q; k0 H, }
如下图所示,使用命令“./mnt/udisk/leds 0 0”运行,可以看到靠近蜂鸣器的小灯灭了。( K* x6 r7 C2 ^ r4 j! n3 P0 r8 c1 R
$ m* n7 N1 o: l: l/ a4 T
所有参数对小灯的控制如下:
) m: Q# r3 L3 W9 V+ ^! [0 0 靠近蜂鸣器的小灯灭;! a7 W3 U% r0 U+ U0 X u- E
0 1 靠近按键的小灯灭;- {* L9 M9 M6 e% _, N+ `9 [
1 0 靠近蜂鸣器的小灯亮;
2 ?; S c7 P+ ?8 @0 D1 1 靠近按键的小灯亮。用户可以自行测试一下。! a9 S: I* V) V E
& }3 f. w+ v( |
|
|