|
EDA365欢迎您登录!
您需要 登录 才可以下载或查看,没有帐号?注册
x
在 linux 驱动中字符设备驱动是必须掌握的,本章主要介绍字符设备应用的程序,无论是学习了后面的知识自己写的字符驱动,还是已有的字符驱动,都需要能够写一些简单的应用程序。即使从事 Linux 驱动方面的工作,Linux 驱动写出来之后,也需要由驱动程序员编写简单的应用程序来进行测试的。3 K1 [- y) ^: D0 b4 C U5 ^- w; S
另外,关于驱动部分,迅为电子有专门的驱动实验教程提供给大家学习,大家有了这些基础之后再去学习底层的知识就会很容易了。
1 k; ]3 S0 l6 g2 J! A9 w在本手册的 10.22 章节,大家可以看到这些 C 程序也是可以在 Android 下面运行的,只不过没有图形界面。
: n) E$ d# L8 j. e* m% H+ g$ X本章配套视频为:
! [+ I5 e, q* M( W! z, P% q“视频 06_01 字符设备控制之 main 函数传参数”5 v$ |% T3 g% O1 N3 g- r: y* b1 x
“视频 06_02 字符设备控制之 led 灯”% n1 m6 e; i' [( [
“视频 06_03 字符设备控制之 buzzer 蜂鸣器”
; h+ l0 {. E3 h: y- g# ^& @“视频 06_04 字符设备控制之 ADC 模数转换”3 {9 T& L" ~: e- q: Y- C2 y2 k
17.1 入口 main 函数的参数$ p, _8 m1 \. b$ a% S6 }7 U# a
在和用户交流的过程中,虽然所有人都学习过 C 语言,但是对 C 语言中的 main 函数的用法并不是很清楚。由于后面的实验需要用到这部分知识,这里就占用一个小节,先简单介绍一下 main 函数。5 C2 F& \6 |( \! b" o: |
main 函数简介2 N9 G7 c( P+ E6 C, f
main 函数作为应用程序的入口,在头文件“#include ”中。main 函数需要传参数的时候完整的定义为6 G( N6 M1 c0 O2 d
int main(int argc,char **argv). [0 i7 q7 z8 m& M+ a
参数 argc,表示参数的个数
$ }6 a, C# y& e% \3 {! G% ~ c参数**argv,存储输入字符的数组,argv[0]表示程序名称,argv[1]——argv[n]输入的参数
, `/ i2 ^, |! B6 D8 Q7 R( }( k. O; p不传参数的时候定义为
: e4 `* V" Q- pint main(void) P1 ^' Y, Z$ u b$ f0 E h# {
函数 main 的返回值为类型为 int,用于判断程序执行成功还是失败& n- X; C% g) e$ `
main 函数例程% G- {/ S4 Z$ |
编写简单的 argvc.c 文件测试 main 函数。
6 y$ u/ u0 u* Z% Q; t 5 {; W& O7 M. q' t
如上图所示,将输入的参数第一个和第二个转换成 int 类型,赋值给 i 和 j,最后输出打印。
. e8 K6 q+ ~( _5 b其中 argv[0]为程序名称,这里就是后面要编译的目标文件“argvc”。
3 m8 s5 C0 n8 J7 Q+ t
4 M. m' p1 b0 ~* P/ U编译运行测试
7 O! R$ X" \ B2 @7 `在 Ubuntu 系统下,如下图所示,进入前面实验创建的目录“/home/linuxsystEMCode/”,使用命令“mkdircharcontrol”新建 charcontrol 文件夹,将源码 argvc.c 拷贝进去,进入新建的文件夹 charcontrol,如下图所示。
`: Q d" t: R3 s- V* Q- ]3 L" { ( Q t, F9 T; b
使用命令“ARM-none-linux-gnueabi-gcc -o argvc argvc.c -static”编译 argvc 文件, 如下图所示,使用命令“ls”可以看到生成了 argvc 可执行文件。6 k+ @0 s# l$ ^4 N/ r
n7 p' t9 a! H$ \9 f) `" R
这里介绍 U 盘拷贝代码的方法,也可以编译进文件系统,具体方法参考 10.3.5 小节。 将编译成的可执行文件 argvc,拷贝到 U 盘,启动开发板,插入 U 盘,加载 U 盘,运行程序如下。! e" V, O0 E2 S. z6 X4 r* t) j
![]()
' P/ R' S) Y/ b! l3 s如上图所示,程序成功运行,打印:8 x' ~- [$ C5 ~0 a( |5 y3 {3 L
the Program name is ./mnt/udisk/argvc。
- \$ z. p& Q u) b0 V因为运行的程序就是“./mnt/udisk/argvc”,这是第一个参数$ C* a6 w& ?9 D, h) F6 R% i7 ?
The command line has 2 argument:% E/ h7 y3 x; n
10,11。
1 F: k8 A+ v1 H) g# ^/ w6 a
0 I2 x0 y: ?* k8 [输入的参数是 10 和 11,对应 argv[2]和 argv[2]。' i$ R! p( n! T$ L3 w
17.2 字符类 led 灯7 B3 Q! U3 E9 W6 S+ c4 H
在前面介绍 open 函数的时候,已经提到过如何打开字符类设备,获得句柄的方法和一般文件都是一样。
0 D# B9 w) X* f! V" wLed 灯的设备节点在/dev 目录下,如下图所示,在超级终端可以使用 ls 命令查找。! n( M& i! [$ V4 I5 ]. B6 V4 \3 p$ m4 ~
5 Y, d& l. j0 j6 Z7 d" T0 m! N
由于涉及到硬件知识,这里简单介绍一下硬件原理,如下图所示,led 小灯的硬件原理很简单。% q1 O! J2 q4 L7 W
![]()
3 q2 @, {' X/ H, S& q如上图所示,给 KP_COL0 和 VDD50_EN 网络高电平,三极管 L9014 就会导通,电源 VSYS 就会将电压加到电阻 R 和 led 小灯上,小灯就会亮。
& b/ N2 d1 i: R! ]给 KP_COL0 和 VDD50_EN 网络低电平,三极管 L9014 就会截止,形成断路,小灯灭。
. ^& s* P. L- F i' u1 Y在前面介绍过,如果要给文件进行写操作,那么使用的是 write 函数。对于 led 小灯的操作,使用写函数,理论上也是可以的。但是对于 IO 口(这里的 IO 口指的是硬件上的 IO 口, 不是指 IO 文件)的7 M' u) b8 Z# H7 s( d/ @) s
: s% j2 P" O: M5 K& J# s
操作,Linux 专门设计了一个高效的函数 ioctl。
3 }- W! ?% W& E这个函数在头文件#include中。
7 U# W3 o2 `; F$ O4 ?int ioctl( int fd, int request, int cmd);
: Y6 H& T- h3 _参数 fd,函数 open 返回的句柄。# a3 M7 L. B0 Q, R4 S
参数 request 和参数 cmd,由内核驱动决定具体操作,例如 request 可以代表那个 IO 口,cmd 代表对 IO 进行什么样的操作,也可以反过来。具体的含义由驱动工程师在驱动中 switch 决定。8 X$ j$ q1 T- }8 V
返回值:返回 0 成功;返回-1,出错。% D+ P- i X# D7 d% q+ n6 k
; i0 |& y& U0 @( J' ]
小灯测试例程
( @- n; E# a5 h) p编写简单的 leds.c 文件测试小灯。首先添加头文件,如下图所示。- j, u) y; L8 |" A& i% I- p F
通过 main 参数传过来的参数是 char 字符格式的,如果要传递给 ioctl 函数,需要用到数值转化函数atoi,添加了头文件#include 。9 [: f3 E1 o# T3 l* a
接着由于小灯的数量和命令都是 2,所以对小灯数量和操作数进行宏定义0 @4 h" S8 C! k+ x' |2 N1 W2 j
#define LED_NUM 2
7 V9 Z! Q7 X( l- |#define LED_C 2。
9 ?( o6 k% [# u5 b+ h; ?![]()
6 I; E+ b( K4 J+ j$ k! P s% @$ g然后 main 函数如下图所示。& g2 e L/ S* d
! v; d9 S% X6 z$ C2 K: T. T: ^
如上图所示。$ q. c+ V2 I8 j% u, z ]
第 33 行,调用了 ioctl 函数,将 main 函数的第一个和第二个参数传入驱动。6 a2 j Y4 a- k& P3 n
第 19 行,解释那个参数具体代表什么含义,"argv1 is cmd;argv2 is io”,参数 1 对应命令,参数 2 对应具体那个 led 灯。# ~, ^) ]: _3 b( R* l! H
第 36 行,将打开的设备节点"/dev/leds"关闭。1 p# t; J1 ~: |! l
4 i& p' q/ k9 r0 V7 I; y
编译运行测试4 c: ]0 P& q! W a% j* {$ v
在 Ubuntu 系统下,如下图所示,进入前面实验创建的目录“/home/linuxsystemcode/charcontrol”,将源码 leds.c 拷贝进去,如下图所示。: R0 i) @5 m2 c) I
![]()
! G7 w- s% O0 E2 w @使用命令“arm-none-linux-gnueabi-gcc -o leds leds.c -static”编译 leds 文件,如下图所示,使用命令“ls”可以看到生成了 leds 可执行文件。
3 t _: E1 v B' _4 p: Y - n0 X) j4 z! T+ L y( k5 c9 g& C
这里介绍 U 盘拷贝代码的方法,也可以编译进文件系统,具体方法参考实验 02
/ B) p) R) a2 i: Y/ A/ W6 C, P3 Y将编译成的可执行文件 open,拷贝到 U 盘,启动开发板,插入 U 盘,加载 U 盘,运行程序如下。
' S d$ _ g3 V7 |- g3 z如下图所示,如果不加参数会有提示,然后报错。
/ x. D* P, @; o1 _, K. M![]()
* }, V; ^* l' L* O( `0 o' O0 T如下图所示,使用命令“./mnt/udisk/leds 0 0”运行,可以看到靠近蜂鸣器的小灯灭了。
5 {8 k5 d- r' Y8 F7 p) }5 C9 _![]()
) {$ ~# _+ e- o. W6 c所有参数对小灯的控制如下:
: j1 \* I% p' @! J0 0 靠近蜂鸣器的小灯灭;
, y6 Q. l4 g( i) F! _$ i! _, d5 M! |0 1 靠近按键的小灯灭;1 Y: e: a- v6 Q7 C' |( [
1 0 靠近蜂鸣器的小灯亮;9 T3 B0 w" p, W# i |
1 1 靠近按键的小灯亮。用户可以自行测试一下。
# W" @* Q$ g; U- x7 @* Z* T + T6 u, Z }0 g. w- f2 L
|
|