南阳做网站aokuo,《基层建设》官方网站,郑州建设教育培训中心,学网页设计软件开发点亮 LED 应用层操控硬件的两种方式
背景 Linux系统将所有内容视作文件#xff0c;包括硬件设备#xff0c;通过文件I/O方式与硬件交互 设备文件#xff0c;如字符设备文件与块设备文件#xff0c;是硬件设备提供给应用层的接口 应用层通过设备文件进行I/O操作#xff…点亮 LED 应用层操控硬件的两种方式
背景 Linux系统将所有内容视作文件包括硬件设备通过文件I/O方式与硬件交互 设备文件如字符设备文件与块设备文件是硬件设备提供给应用层的接口 应用层通过设备文件进行I/O操作以控制硬件如显示屏、串口等 设备文件位于/dev/目录被称为设备节点 除了设备节点硬件设备还可以通过sysfs文件系统进行控制
sysfs 文件系统 sysfs是一种基于内存的虚拟文件系统与devfs、proc文件系统类似用于向应用层提供内核信息 sysfs主要功能是对系统设备进行管理展示系统硬件的层次结构 sysfs通过分级的文件目录结构展示设备驱动模型中各组件的层次关系 sysfs提供机制显式描述内核对象、对象属性及对象间关系并将这些信息导出到用户空间
sysfs 与/sys sysfs文件系统被挂载在/sys目录下为Linux系统如启动ALPHA/Mini I.MX6U开发板时的标准组成部分 /sys 目录 /sys目录下的子目录包括block、bus、class、dev、devices、firmware等每个目录下含有多个文件或子目录反映系统的不同方面 /sys 目录结构 /sys/devices目录是sysfs中的核心存放系统中所有设备的信息是管理设备的主要目录结构 /sys/bus、/sys/class、/sys/dev等目录通过不同的方式如按总线类型、功能分类、设备号组织设备信息且这些目录下的文件通常链接到/sys/device 设备的属性和数据通过目录下的文件称为属性文件体现通过读写这些文件可以访问或控制设备的属性和状态
小结 应用层控制底层硬件通常通过两种方式 /dev/目录下的设备文件设备节点 /sys/目录下的设备属性文件 选择使用/dev/目录或/sys/目录来操控设备依赖于设备的功能类型和设备驱动的实现方式 简单的设备如LED和GPIO倾向于使用sysfs方式其驱动会将设备属性导出到用户空间的sysfs文件系统中 复杂的设备如LCD屏幕、触摸屏和摄像头则通常通过设备节点来进行控制
标准接口与非标准接口 Linux内核引入了设备驱动框架概念以降低驱动开发难度和实现接口标准化 内核为各种常见设备如LED、输入设备、FrameBuffer、视频设备、PWM设备等设计了一套标准的驱动实现框架 设备驱动框架为驱动开发和应用层提供统一的接口规范简化了开发过程 使用设备驱动框架开发的驱动程序提供标准化接口而不使用框架开发的驱动程序则提供非标准化接口 对于一些不属于任何标准分类的硬件外设如杂项设备misc device其驱动程序通常提供非标准接口具体控制方法由驱动工程师掌握 嵌入式系统中许多硬件外设的驱动程序都是定制的提供非标准化接口
LED 硬件控制方式
ALPHA/Mini I.MX6U 开发板出厂系统的 LED 设备是基于 Linux 内核标准 LED 驱动框架注册的使用 sysfs 方式控制没有在/dev 目录下的设备节点
/sys/class/leds 目录下存放了所有的 LED 设备其中包括sys-led。目录下关注的主要是三个属性文件 brightness用于设置和获取 LED 的亮度等级 对于 PWM 控制的 LED亮度等级对应不同的占空比但对于 GPIO 控制的 LED只有亮和灭两种亮度等级 max_brightness用于获取 LED 设备的最大亮度等级 只能被读取不能写 trigger用于获取和设置 LED 的触发模式 none无触发 mmc0当对 mmc0 设备发起读写操作的时候 LED 会闪烁 timerLED 会有规律的一亮一灭被定时器控制住 heartbeat心跳呼吸模式LED 模仿人的心跳呼吸那样亮灭变化
可以通过 echo 命令进行控制 LED 的亮度和触发模式还可以编写应用程序使用 write()、read()函数对这些属性文件进行 I/O 操作以达到控制 LED 的效果 echo timer trigger //将 LED 触发模式设置为 timer echo none trigger //将 LED 触发模式设置为 none echo 1 brightness //点亮 LED echo 0 brightness//熄灭 LED 使用 cat 读取以及 echo 写入到属性文件中的均是字符串应用程序中通过 write()向属性文件写入数据以及使用 read()读取的数据也是字符串 ASCII 编码的
编写 LED 应用程序
开始程序的入口点
校验传参检查 argc 是否小于 2
如果是则展示 USAGE 消息程序异常退出状态为 -1
打开文件 尝试打开 trigger 文件得到文件描述符 fd1 如果 fd1 小于 0打印 “open error”程序异常退出状态为 -1 尝试打开 brightness 文件得到文件描述符 fd2 如果 fd2 小于 0打印 “open error”程序异常退出状态为 -1
如果 fd2 小于 0打印 “open error”程序异常退出状态为 -1 如果 argv[1] 等于 “on” 写 “none” 到 fd1写 “1” 到 fd2 如果 argv[1] 等于 “off” 写 “none” 到 fd1写 “0” 到 fd2 如果 argv[1] 等于 “trigger” 检查 argc 是否等于 3 如果不是则展示 USAGE 消息程序异常退出状态为 -1 尝试写 argv[2] 到 fd1 如果写操作返回值小于 0打印 “write error” 如果没有匹配的参数则展示 USAGE 消息
正常退出程序正常退出返回状态 0
#include stdio.h
#include stdlib.h
#include sys/types.h
#include sys/stat.h
#include fcntl.h
#include unistd.h
#include string.h#define LED_TRIGGER /sys/class/leds/sys-led/trigger
#define LED_BRIGHTNESS /sys/class/leds/sys-led/brightness
//定义了控制LED触发模式和亮度的文件路径
#define USAGE() fprintf(stderr, usage:\n \ %s on|off\n \ %s trigger type\n, argv[0], argv[0])
//fprintf函数用于格式化输出
//stderr表示标准错误输出流
// \ 是续行符表示这一行未结束下一行是本行的延续int main(int argc, char *argv[])
{int fd1, fd2;/* 校验传参 *///如果参数为1个则报错if (2 argc) {USAGE();exit(-1);}/* 打开文件 */fd1 open(LED_TRIGGER, O_RDWR); //返回一个文件描述符if (0 fd1) {perror(open error);exit(-1);}fd2 open(LED_BRIGHTNESS, O_RDWR);if (0 fd2) {perror(open error);exit(-1);}/* 根据传参控制LED *///strcmp函数返回0表示两个字符串相等if (!strcmp(argv[1], on)) {write(fd1, none, 4); //先将触发模式设置为none//将字符串none写入文件描述符fd1所指向的文件,4表示写入的字节数write(fd2, 1, 1); //点亮LED}else if (!strcmp(argv[1], off)) {write(fd1, none, 4); //先将触发模式设置为nonewrite(fd2, 0, 1); //LED灭}else if (!strcmp(argv[1], trigger)) {if (3 ! argc) {USAGE();exit(-1);}if (0 write(fd1, argv[2], strlen(argv[2])))perror(write error);}elseUSAGE();exit(0);
}
在开发板上测试
通过gcc 编译器获得可执行文件后移植到开发板
./testApp on # 点亮 LED
./testApp off # 熄灭 LED ./testApp trigger heartbeat # 将 LED 触发模式设置为 heartbeat