【北京迅为】iTOP-4412全能版使用手册-第十七章 Linux字符设备控制

iTOP-4412全能版采用四核Cortex-A9,主频为1.4GHz-1.6GHz,配备S5M8767 电源管理,集成USB HUB,选用高品质板对板连接器稳定可靠,大厂生产,做工精良。接口一应俱全,开发更简单,搭载全网通4G、支持WIFI、蓝牙、陀螺仪、CAN总线、RS485总线、500万摄像头等模块,稳定运行Android 4.0.3/Android 4.4操作,系统通用Linux-3.0.15+Qt操作系统(QT支持5.7版本),Ubuntu版本:12.04,接口智能分配 方便好用。


第十七章 Linux字符设备控制

在 linux 驱动中字符设备驱动是必须掌握的,本章主要介绍字符设备应用的程序,无论是学习了后面的知识自己写的字符驱动,还是已有的字符驱动,都需要能够写一些简单的应用程序。

即使从事 Linux 驱动方面的工作,Linux 驱动写出来之后,也需要由驱动程序员编写简单的应用程序来进行测试的。

另外,关于驱动部分,迅为电子有专门的驱动实验教程提供给大家学习,大家有了这些基础之后再去学习底层的知识就会很容易了。

在本手册的 10.22 章节,大家可以看到这些 C 程序也是可以在 Android 下面运行的,只不过没有图形界面。

本章配套视频为:

"视频 06_01 字符设备控制之 main 函数传参数"

"视频 06_02 字符设备控制之 led 灯"

"视频 06_03 字符设备控制之 buzzer 蜂鸣器"

"视频 06_04 字符设备控制之 ADC 模数转换"

17.1 入口main函数的参数

在和用户交流的过程中,虽然所有人都学习过 C 语言,但是对 C 语言中的 main 函数的用法并不是很清楚。

由于后面的实验需要用到这部分知识,这里就占用一个小节,先简单介绍一下 main 函数。

main 函数简介

main 函数作为应用程序的入口,在头文件"#include<stdio.h> "中。main 函数需要传参数的时候完整的定义为

int main(int argc,char **argv)

参数 argc,表示参数的个数

参数**argv,存储输入字符的数组,argv0表示程序名称,argv1------argvn输入的参数

不传参数的时候定义为

int main(void)

函数 main 的返回值为类型为 int,用于判断程序执行成功还是失败

main 函数例程

编写简单的 argvc.c 文件测试 main 函数。

如上图所示,将输入的参数第一个和第二个转换成 int 类型,赋值给 i 和 j,最后输出打印。

其中 argv0为程序名称,这里就是后面要编译的目标文件"argvc"。

编译运行测试

在 Ubuntu 系统下,如下图所示,进入前面实验创建的目录"/home/linuxsystemcode/",使用命令"mkdir charcontrol"新建 charcontrol 文件夹,将源码 argvc.c 拷贝进去,进入新建的文件夹 charcontrol,如下图所示。

使用命令"arm-none-linux-gnueabi-gcc -o argvc argvc.c -static"编译 argvc 文件, 如下图所示,使用命令"ls"可以看到生成了 argvc 可执行文件。

这里介绍 U 盘拷贝代码的方法,也可以编译进文件系统,具体方法参考 10.3.5 小节。 将编译成的可执行文件 argvc,拷贝到 U 盘,启动开发板,插入 U 盘,加载 U 盘,运行程序如下。

如上图所示,程序成功运行,打印:

the Program name is ./mnt/udisk/argvc。

因为运行的程序就是"./mnt/udisk/argvc",这是第一个参数

The command line has 2 argument:

10,11。

输入的参数是 10 和 11,对应 argv2和 argv2。

17 . 2 字符类led灯

在前面介绍 open 函数的时候,已经提到过如何打开字符类设备,获得句柄的方法和一般文件都是一样。

Led 灯的设备节点在/dev 目录下,如下图所示,在超级终端可以使用 ls 命令查找。

由于涉及到硬件知识,这里简单介绍一下硬件原理,如下图所示,led 小灯的硬件原理很简单。

如上图所示,给 KP_COL0 和 VDD50_EN 网络高电平,三极管 L9014 就会导通,电源VSYS 就会将电压加到电阻 R 和 led 小灯上,小灯就会亮。

给 KP_COL0 和 VDD50_EN 网络低电平,三极管 L9014 就会截止,形成断路,小灯灭。

在前面介绍过,如果要给文件进行写操作,那么使用的是 write 函数。对于 led 小灯的操作,使用写函数,理论上也是可以的。但是对于 IO 口(这里的 IO 口指的是硬件上的 IO 口, 不是指 IO 文件)的操作,Linux 专门设计了一个高效的函数 ioctl。

这个函数在头文件#include<unistd.h>中。

int ioctl( int fd, int request, int cmd);

参数 fd,函数 open 返回的句柄。

参数 request 和参数 cmd,由内核驱动决定具体操作,例如 request 可以代表那个 IO 口,cmd 代表对 IO 进行什么样的操作,也可以反过来。具体的含义由驱动工程师在驱动中switch 决定。

返回值:返回 0 成功;返回-1,出错。

小灯测试例程

编写简单的 leds.c 文件测试小灯。首先添加头文件,如下图所示。

通过 main 参数传过来的参数是 char 字符格式的,如果要传递给 ioctl 函数,需要用到数值转化函数 atoi,添加了头文件#include <stdlib.h>。

接着由于小灯的数量和命令都是 2,所以对小灯数量和操作数进行宏定义

#define LED_NUM 2

#define LED_C 2。

然后 main 函数如下图所示。

如上图所示。

第 33 行,调用了 ioctl 函数,将 main 函数的第一个和第二个参数传入驱动。

第 19 行,解释那个参数具体代表什么含义,"argv1 is cmd;argv2 is io",参数 1 对应命令,参数 2 对应具体那个 led 灯。

第 36 行,将打开的设备节点"/dev/leds"关闭。

编译运行测试

在 Ubuntu 系统下,如下图所示,进入前面实验创建的目录"/home/linuxsystemcode/charcontrol",将源码 leds.c 拷贝进去,如下图所示。

使用命令"arm-none-linux-gnueabi-gcc -o leds leds.c -static"编译 leds 文件,如下图所示,使用命令"ls"可以看到生成了 leds 可执行文件。

这里介绍 U 盘拷贝代码的方法,也可以编译进文件系统,具体方法参考实验 02

将编译成的可执行文件 open,拷贝到 U 盘,启动开发板,插入 U 盘,加载 U 盘,运行程序如下。

如下图所示,如果不加参数会有提示,然后报错。

如下图所示,使用命令"./mnt/udisk/leds 0 0"运行,可以看到靠近蜂鸣器的小灯灭了。

所有参数对小灯的控制如下:

0 0 靠近蜂鸣器的小灯灭;

0 1 靠近按键的小灯灭;

1 0 靠近蜂鸣器的小灯亮;

1 1 靠近按键的小灯亮。用户可以自行测试一下。

17.3 字符类Buzzer蜂鸣器

和 led 灯类似,蜂鸣器的设备节点也是在/dev 目录下,如下图所示。

蜂鸣器的硬件和 led 灯类似,如下图所示。

如上图所示。

原理图很容易理解,如果网络 MOTOR_PWM 为高电平,则 L9014 导通,蜂鸣器响,如果网络 MOTOR_PWM 为低电平,则 L9014 截止,蜂鸣器则不响。

操作方式和 led 小灯类似。

蜂鸣器测试例程

编写简单的 buzzertest.c 文件测试蜂鸣器。

首先添加头文件,如下图所示,下面新加了几个库文件,一般常用的就是下面几个,写代码的时候,为了方便,可以直接都添加上。

然后 main 函数如下图所示。

如上图代码所示。由于只有一个 IO,底层没有做第三个参数的判断,所以无效

第 16-19 行,对参数 argv1有个简单的判断,命令只能是 0 或者 1。

第 21-24 行,open 函数打开蜂鸣器设备节点

第 26 行,使用 ioctl 函数操作蜂鸣器。

第 27 行,使用 close 函数关闭设备节点。

编译运行测试

在 Ubuntu 系统下,如下图所示,进入前面实验创建的目录"/home/linuxsystemcode/charcontrol",将源码 buzzertest.c 拷贝进去,如下图所示。

使用命令"arm-none-linux-gnueabi-gcc -o buzzertest buzzertest.c -static"编译buzzertest 文件,如下图所示,使用命令"ls"可以看到生成了 buzzertest 可执行文件。

这里介绍 U 盘拷贝代码的方法,也可以编译进文件系统。

将编译成的可执行文件 buzzertest,拷贝到 U 盘,启动开发板,插入 U 盘,加载 U 盘, 运行程序如下。

使用参数 1 和 0,蜂鸣器会响。第二个参数实际上并不起作用。

如下图所示,使用参数 0 和 0,蜂鸣器会停止响。

17 . 4 字符类ADC模数转换

和 led 灯类似,数模转换的设备节点也是在/dev 目录下,如下图所示。

模数转换的硬件部分如下图所示。

如上图所示。

XadcAIN0 网络可以读取到当前输入电压,滑动变阻器 R 移动的时候,1 和 2 之间的电阻R12 改变,滑动变阻器最大电阻为 R13,然后电压 Vadc=R12*VDD1V8_EXT/R13

上面公式中 Vadc 可以通过 4412 读取出来,VDD1V8 和 R13 已知,那么就很容易求出R12 的电阻。如下图所示,在 4412datasheet 中 ADC 章节中有真实的电阻和电压曲线图。

这里将数值做一个简单的换算,

1.8V 对应的是 10K 欧姆,对应的寄存器数值为 0xfff;

0V 对应的是 0 欧姆,对应的寄存器数值为 0x0。

这样做一个简单公式,将读取的数值 r 转化为电阻值 R。

R = r*10000/0xfff,即 R = r*10000/4095。

这个小公式在后面的代码中将会使用到。

模数转换例程

编写简单的 ADC.c 文件测试 adc 的驱动。首先添加头文件,如下图所示。

然后 main 函数如下图所示。

如上图代码所示。

第 14 行,设备节点为 char *adc = "/dev/adc"。

第 21 行,打开设备节点文件。

第 26 行,使用 read 函数,将读取数字赋予 buffer。

第 30 和 31 行,做个简单地换算,将读取的数值转化为电阻值。

编译运行测试

在 Ubuntu 系统下,如下图所示,进入前面实验创建的目录"/home/linuxsystemcode/charcontrol/"将源码 ADC.c 拷贝进去,如下图所示。

使用命令"arm-none-linux-gnueabi-gcc -o ADC ADC.c -static"编译 ADC 文件,如下图所示,使用命令"ls"可以看到生成了 ADC 可执行文件。

这里介绍 U 盘拷贝代码的方法,也可以编译进文件系统,具体方法参考 10.3.5 小节。将编译成的可执行文件 open,拷贝到 U 盘,启动开发板,插入 U 盘,加载 U 盘,运行程序。

如下图所示,使用命令"./mnt/udisk/ADC"即可检测当前电阻值,中间的大段打印参数是多次打印寄存器的数值,在驱动实验中再去介绍。

调整滑动电阻器之后,再次使用测试程序,如下图所示,输出数值会有变化。

滑动变阻器向顺时针旋转,阻值会减小,最小为 0;

滑动变阻器向逆时针旋转,阻值会增大,最大为 10K。

相关推荐
且从容.2 小时前
Ubuntu安装flume
linux·ubuntu·flume
承渊政道3 小时前
Linux网络学习【Reactor反应堆模式】
linux·网络·学习·ubuntu·reactor
不脱发的程序猿3 小时前
GD32串口数据收进内存之后DMA如何处理?
单片机·嵌入式硬件·dma·嵌入式·串口通信·gd32
且从容.5 小时前
ubuntu安装flink
linux·ubuntu·flink
爱和冰阔落7 小时前
【Linux网络】TCP 服务器如何并发处理多个客户端?从 fork、僵尸进程到双重 fork
linux·运维·服务器·网络
程序员沉梦听雨7 小时前
WSL2的安装与使用
linux·wsl
微小的鱼7 小时前
Linux的渲染与显示系统链路
android·java·linux
FPGA小迷弟7 小时前
FPGA 与千兆以太网校验和:从原理到 Verilog 实现
嵌入式硬件·fpga开发·无人机·ai编程·fpga
lisanmengmeng8 小时前
alertmanger 标签 rules 打上分组标签
linux·运维·服务器
Android系统攻城狮8 小时前
Linux FFmpeg深度解析之av_write_frame调用流程与实战(三十三)
linux·运维·服务器·ffmpeg·音视频进阶·ffmpeg音视频