EDA365电子论坛网
标题:
迅为4412开发板Linux字符设备控制
[打印本页]
作者:
阳阳天
时间:
2021-3-4 14:36
标题:
迅为4412开发板Linux字符设备控制
在 linux 驱动中字符设备驱动是必须掌握的,本章主要介绍字符设备应用的程序,无论是学习了后面的知识自己写的字符驱动,还是已有的字符驱动,都需要能够写一些简单的应用程序。即使从事
Linux
驱动方面的工作,Linux 驱动写出来之后,也需要由驱动程序员编写简单的应用程序来进行测试的。
: ^ ]8 w% K7 c( N1 q: _6 M
另外,关于驱动部分,迅为
电子
有专门的驱动实验教程提供给大家学习,大家有了这些基础之后再去学习底层的知识就会很容易了。
- L7 }( r0 ]3 G1 o7 E% J
在本手册的 10.22 章节,大家可以看到这些 C 程序也是可以在
Android
下面运行的,只不过没有图形界面。
2 ^5 b/ E' D) X4 Z5 l
本章配套视频为:
/ c" c" l; P0 V I& N2 x" z
“视频 06_01 字符设备控制之 main 函数传参数”
2 Q B6 O6 B6 @/ O: T4 G. f. \. E1 s8 r
“视频 06_02 字符设备控制之 led 灯”
! o" {1 ~. ?& ?$ }3 j* u
“视频 06_03 字符设备控制之 buzzer 蜂鸣器”
0 U9 w$ m! ?4 c. q
“视频 06_04 字符设备控制之
ADC
模数转换”
0 B( o- g* @4 y, J- |
17.1 入口 main 函数的参数
3 h2 }2 K$ A! q' ?1 X9 v7 h
在和用户交流的过程中,虽然所有人都学习过 C 语言,但是对 C 语言中的 main 函数的用法并不是很清楚。由于后面的实验需要用到这部分知识,这里就占用一个小节,先简单介绍一下 main 函数。
6 r7 s- U3 m- f8 j
main 函数简介
$ k0 y# j; ^: z M0 S
main 函数作为应用程序的入口,在头文件“#include
”中。main 函数需要传参数的时候完整的定义为
/ T( l4 N3 ^" f7 e4 v6 K' u) s) A
int main(int argc,char **argv)
8 ~6 z6 ?% R, y8 ~8 g; z; G
参数 argc,表示参数的个数
" F3 _. H1 a& H! Z1 y+ e0 b7 l* `$ y
参数**argv,存储输入字符的数组,argv[0]表示程序名称,argv[1]——argv[n]输入的参数
9 K3 i/ O) F' d+ @0 o: |& q' g
不传参数的时候定义为
% @; j. y o# {1 [# L+ A" w
int main(void)
E, Y+ \. T8 [. i
函数 main 的返回值为类型为 int,用于判断程序执行成功还是失败
) U7 `4 a$ x0 {7 V! `+ M, }# H' Q
main 函数例程
1 x" |$ O1 g) l
编写简单的 argvc.c 文件测试 main 函数。
: q+ W K u C9 L: q, o, Y9 M
0 u% a4 D0 v( [$ V
如上图所示,将输入的参数第一个和第二个转换成 int 类型,赋值给 i 和 j,最后输出打印。
4 L. f% R7 `0 W8 Z5 A& i) Q
其中 argv[0]为程序名称,这里就是后面要编译的目标文件“argvc”。
& ^! Y" G/ j; P# [* z$ E& G2 k5 |
3 S. ?) A% ~# k' |6 X
编译运行测试
9 a2 ?6 `% { s) E- Y* s
在
Ubuntu
系统下,如下图所示,进入前面实验创建的目录“/home/linuxsystemcode/”,使用命令“mkdircharcontrol”新建 charcontrol 文件夹,将源码 argvc.c 拷贝进去,进入新建的文件夹 charcontrol,如下图所示。
/ L, v3 Q9 R9 m( f. T% B3 F' l& q
( k* M% p" w4 z# g7 }5 f: Y5 d
使用命令“arm-none-linux-gnueabi-gcc -o argvc argvc.c -static”编译 argvc 文件, 如下图所示,使用命令“ls”可以看到生成了 argvc 可执行文件。
- d) b0 r; T8 L2 R" A
0 r2 f8 n0 q3 }6 x0 ?
这里介绍 U 盘拷贝代码的方法,也可以编译进文件系统,具体方法参考 10.3.5 小节。 将编译成的可执行文件 argvc,拷贝到 U 盘,启动开发板,插入 U 盘,加载 U 盘,运行程序如下。
4 O2 N1 T5 y6 L4 L+ I% s; \
( y8 U/ k; G6 f' ~ o* ~
如上图所示,程序成功运行,打印:
2 F& E, N; R2 R& |" [) z3 L
the Program name is ./mnt/udisk/argvc。
! d" `6 e5 \/ ]! `$ M$ o
因为运行的程序就是“./mnt/udisk/argvc”,这是第一个参数
, K0 p) ~5 S$ S; z2 [% ?
The command line has 2 argument:
! U9 L2 a V# T! } \* P
10,11。
$ u( r* m( @' Y. X
+ V/ e8 t* }: p6 b& r1 L" [8 l, K
输入的参数是 10 和 11,对应 argv[2]和 argv[2]。
0 j# o6 _' y4 i+ r$ x$ ?: L
17.2 字符类 led 灯
+ h) ^, L) ^& R
在前面介绍 open 函数的时候,已经提到过如何打开字符类设备,获得句柄的方法和一般文件都是一样。
9 L Y* p5 {; a1 L! p
Led 灯的设备节点在/dev 目录下,如下图所示,在超级终端可以使用 ls 命令查找。
7 l! i1 S8 _" D
$ {- ]- c1 _& s: G
由于涉及到硬件知识,这里简单介绍一下硬件原理,如下图所示,led 小灯的硬件原理很简单。
5 C: I8 ~' m: X8 t% D
4 l K& e9 P! D3 M
如上图所示,给 KP_COL0 和 VDD50_EN 网络高电平,
三极管
L9014 就会导通,电源 VSYS 就会将
电压
加到
电阻
R 和 led 小灯上,小灯就会亮。
9 S7 B$ B) Q1 \5 U" H2 l! G0 L
给 KP_COL0 和 VDD50_EN 网络低电平,三极管 L9014 就会截止,形成断路,小灯灭。
/ X& r2 ~" l% Y5 d( _
在前面介绍过,如果要给文件进行写操作,那么使用的是 write 函数。对于 led 小灯的操作,使用写函数,理论上也是可以的。但是对于 IO 口(这里的 IO 口指的是硬件上的 IO 口, 不是指 IO 文件)的
F) S# R, q& l
2 s! z" W! s7 c" @- a8 p* E/ Q1 o" g
操作,Linux 专门设计了一个高效的函数 ioctl。
1 \$ p5 b4 s' @% d
这个函数在头文件#include中。
6 u- d* w9 I) }6 Z2 c
int ioctl( int fd, int request, int cmd);
" x( Q+ q) r9 V* Z7 U
参数 fd,函数 open 返回的句柄。
- G' c2 O, I" z8 L y: ^' Q
参数 request 和参数 cmd,由内核驱动决定具体操作,例如 request 可以代表那个 IO 口,cmd 代表对 IO 进行什么样的操作,也可以反过来。具体的含义由驱动工程师在驱动中 switch 决定。
( C* W' X5 u" G d7 R9 r* E
返回值:返回 0 成功;返回-1,出错。
$ d3 Q- V! M( Z @8 X# o, D( P
# }& ?* L0 J, p# F9 l
小灯测试例程
7 r5 x6 J: A' H3 i7 N
编写简单的 leds.c 文件测试小灯。首先添加头文件,如下图所示。
& _5 _+ X- o0 h7 j) C7 l( n0 _
通过 main 参数传过来的参数是 char 字符格式的,如果要传递给 ioctl 函数,需要用到数值转化函数atoi,添加了头文件#include 。
+ F. q% ?9 \1 c. F# p
接着由于小灯的数量和命令都是 2,所以对小灯数量和操作数进行宏定义
! d) D2 m( e. P1 B0 F" B9 l5 E
#define
LED
_NUM 2
- m( C4 g" @5 M
#define LED_C 2。
, K4 m ?) A `. a! B
: _2 ]# Q! M/ S3 t
然后 main 函数如下图所示。
7 a' v! }2 U: ^2 l7 @# O9 Z8 Q! C
^; S- x! r) g. u
如上图所示。
) O* F6 f i4 J: W3 m6 W# [
第 33 行,调用了 ioctl 函数,将 main 函数的第一个和第二个参数传入驱动。
( _( T) V6 \) M7 S6 y
第 19 行,解释那个参数具体代表什么含义,"argv1 is cmd;argv2 is io”,参数 1 对应命令,参数 2 对应具体那个 led 灯。
$ j' U% d; }' V" h6 f0 L
第 36 行,将打开的设备节点"/dev/leds"关闭。
" h' f" O" \! Q' T* T# |
9 F" o4 d: v1 J8 X9 W
编译运行测试
& C! h% e! r8 L- f7 n
在 Ubuntu 系统下,如下图所示,进入前面实验创建的目录“/home/linuxsystemcode/charcontrol”,将源码 leds.c 拷贝进去,如下图所示。
. `; n& M" J; r" P/ Q
. O9 `, j1 r3 p
使用命令“arm-none-linux-gnueabi-gcc -o leds leds.c -static”编译 leds 文件,如下图所示,使用命令“ls”可以看到生成了 leds 可执行文件。
, M# H! H7 g* V5 L( @/ _! G
5 k5 F1 f j0 K0 z! l3 | c
这里介绍 U 盘拷贝代码的方法,也可以编译进文件系统,具体方法参考实验 02
6 D3 m+ I& X# b: l j
将编译成的可执行文件 open,拷贝到 U 盘,启动开发板,插入 U 盘,加载 U 盘,运行程序如下。
% Y6 u8 T# t L1 K7 O+ S
如下图所示,如果不加参数会有提示,然后报错。
2 U# q$ j3 V' M. B- o- C2 `; m; G' D
$ [1 ?: p' f3 N. |# b
如下图所示,使用命令“./mnt/udisk/leds 0 0”运行,可以看到靠近蜂鸣器的小灯灭了。
1 `5 g1 m1 f( ^- e: V
/ V" |# l' N0 l0 g& z4 C
所有参数对小灯的控制如下:
0 i/ }9 V/ F4 L
0 0 靠近蜂鸣器的小灯灭;
+ K2 u4 q8 `2 \1 \9 n
0 1 靠近按键的小灯灭;
* X' B- [ \6 T( S
1 0 靠近蜂鸣器的小灯亮;
8 S$ U8 b: x" f9 o; O
1 1 靠近按键的小灯亮。用户可以自行测试一下。
2 L' C5 A$ n- z2 P: @7 B/ z" a/ k
5 G! _9 g, c+ h+ n* T. H4 A
作者:
modengxian111
时间:
2021-3-5 09:35
介绍的挺详细的
欢迎光临 EDA365电子论坛网 (https://bbs.eda365.com/)
Powered by Discuz! X3.2