【北京迅为】嵌入式学习之Linux系统编程篇 https://www.bilibili.com/video/BV1zV411e7Cy/ 个人学习笔记
文章目录
- 应用层操作 LED 的两种方式
- sysfs 方式控制 LED
- 控制方法
- 原理简介
- 编写 LED 应用程序
应用层操作 LED 的两种方式
应用层操作底层硬件有两种方法,分别是:
- 通过 /dev 目录下的设备节点来控制设备
- 通过 sysfs 文件系统控制设备
这两种方法之前的笔记都有提及,第一种方法是直接写 led 的驱动,定义一个新的字符设备或者杂项设备,然后在应用层操作 /dev 下的设备节点;第二种方法使用了 sysfs 文件系统,部分简单设备(如 LED、GPIO)的驱动在实现时会将设备的一些属性导出到用户空间 sysfs 文件系统,用户可以直接在用户层访问和修改这些设备的属性数据。
sysfs 方式控制 LED
控制方法
下面介绍如何使用 sysfs 方式控制 LED,在命令行终端进入 /sys/class/leds 目录,
该目录下的 work 即为 iTOP-3568 开发板上的 LED 接口,这是一个目录文件,进入该目录,会出现多个文件,
brightness 表示 LED 的亮度,可取范围为 0 ~ max_brightness(不过 iTOP-3568 的 LED 不支持亮度调节,brightness 非 0 表示灯亮,0 表示灯灭)
max_brightness 即 LED 设备最大亮度,该属性只读
trigger 表示 LED 灯的触发方式,可取值包括:none(无触发)、disk-activity(硬盘活动触发)、nand-disk(nand flash 活动触发)、mdt(mtd 设备活动触发)、timer(定时器触发)和 heartbeat(系统心跳触发)
亮灯操作:
echo 1 > brightness
灭灯操作:
echo 0 > birghtness
让 LED 闪烁:
echo tiemr > trigger
虽然上面提到 trigger 可以有很多种类型,但我所用的开发板系统只支持 none 和 timer 两种触发方式。
原理简介
sysfs 下的 LED 设备在内核中属于 LED 子系统驱动框架,LED 子系统实际就是一个 leds 类,用户层可以通过 sysfs 文件系统对 LED 进行控制。
LED 子系统驱动源码在 kernel/drivers/leds/ 目录下的 led-gpio.c 中( led-class.c 和 led-core.c 两个文件也很重要),要让系统支持 LED 子系统,需要在内核配置中打开这三个文件的编译,在 kernel/drivers/leds/Makefile 中可以查看这三个文件的配置名:
然后在内核配置中将它们打开(其中 CONFIG_NEW_LEDS 在打开 LED Support 后就固定打开了,即第一行 LED Support)
以下是 CONFIG_LEDS_GPIO 的帮助信息,
从上面的帮助信息,我们可以得知:向 sysfs 添加 leds 设备的前提是平台设备文件或者设备树里有 leds 的配置信息。
iTOP-3568 使用的是设备树,打开相应的设备树文件,可以看到 leds 节点,LED 子设备的匹配值为 "gpio-leds"
(在 led-gpio.c 中定义了 compatible 属性),节点 leds
下的 work 子节点对应的便是开发板 sysfs 下的 work 目录,该节点下定义了 gpios 等属性。
根据原理图可以得知:iTOP-3568 开发板的 LED 对应的 IO 接口为 GPIO0_B7,与设备树里的 gpios = <&gpio0 RK_PB7 GPIO_ACTIVE_HIGH>;
对应。设备树里的 gpio 属性是 sysfs 点灯的关键。
LED 子系统的驱动和设备配置完成后,我们就能在开发板 /sys/class/leds 目录下操作 LED 设备了。
编写 LED 应用程序
上面只提到了如何在命令行操作 LED,下面介绍一下如何在应用程序中操作 /sys/class/leds 下的 LED 设备。
程序代码:
参考原教程
#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_BRIGHTNESS "/sys/class/leds/work/brightness"
#define LED_TRIGGER "/sys/class/leds/work/trigger"
int main(int argc, char** argv)
{
int fd1, fd2;
int ret = 0;
// 判断输入的参数
if(argc != 3)
{
printf("The right format: ./app <LED_BRIGHTNESS> <LED_TRIGGER>\n");
return 0;
}
// 打开 LED_BRIGHTNESS 文件
fd1 = open(LED_BRIGHTNESS, O_RDWR);
if(fd1 < 0)
{
printf("%s open failed.\n", LED_BRIGHTNESS);
return 0;
}
printf("%s open successfully.\n", LED_BRIGHTNESS);
// 打开 LED_TRIGGER 文件
fd2 = open(LED_TRIGGER, O_RDWR);
if(fd2 < 0)
{
printf("%s open failed.\n", LED_TRIGGER);
return 0;
}
printf("%s open successfully.\n", LED_TRIGGER);
// 操作 LED 亮灭
if(!strcmp(argv[1], "on"))
{
write(fd1, "1", 1);
}
else if(!strcmp(argv[1], "off"))
{
write(fd1, "0", 1);
}
else // 无效参数
{
printf("ERROR: LED_BRIGHTNESS is invalid.\n");
}
// 操作 LED 触发方式
if(!strcmp(argv[2], "none"))
{
write(fd2, "none", 4);
}
else if(!strcmp(argv[2], "timer"))
{
write(fd2, "timer", 5);
}
else // 无效参数
{
printf("ERROR: LED_TRIGGER is invalid.\n");
}
// 关闭设备文件
close(fd1);
close(fd2);
return 0;
}
测试结果:
此时开发板上的 LED 开始规律性闪烁(实物就不展示了)。
个人认为,操作 sysfs 最简单的方式应该是直接使用系统调用,如 system("echo 1 > /sys/class/leds/work/brightness");