Linux驱动开发应用层 2 点亮一个LED

server/2024/12/23 14:58:40/

目录

sysfs-toc" style="margin-left:40px;">先来聊聊sysfs

sysfs%E7%9A%84%E5%85%B7%E5%A4%87%E7%9A%84%E4%BC%98%E5%8A%BF-toc" style="margin-left:120px;">sysfs的具备的优势

C%A8%E5%93%AA%E9%87%8C%EF%BC%9F-toc" style="margin-left:40px;">LED在哪里?


sysfs">先来聊聊sysfs

我们下面首先简单聊一下sysfs。他很重要的原因是因为我们跟底下的设备打交道,就是可以透过我们的sysfs来操作我们底层的设备,

sysfs是Linux内核中的一个虚拟文件系统,用于提供内核对象、设备驱动、内核参数以及其他内核空间信息与用户空间之间的交互接口。sysfs通过在文件系统中创建一系列虚拟文件和目录,允许用户空间程序访问和控制内核的各种设置和信息。sysfs的出现,极大地简化了内核和用户空间之间的交互方式,尤其是在硬件管理、内核配置和设备管理等方面。sysfs通过提供一个结构化的接口,使得用户无需直接与复杂的内核代码交互即可进行设备控制、驱动配置和调试。

sysfs本质上是通过内核模块将内核空间的信息暴露到用户空间,具体来说,它利用文件系统的接口机制,通过将内核的数据结构映射为文件系统的文件和目录结构来实现。这些文件和目录实际上并不对应实际的磁盘文件,而是虚拟文件,读取或写入这些文件时,内核会根据文件内容执行相应的操作。sysfs的目录结构类似于Unix的文件系统层级,通常包含以下几个重要部分:

目录说明
/sys/class包含与设备类别相关的文件夹。例如,/sys/class/net用于网络接口,/sys/class/block用于块设备等。
/sys/devices表示系统中所有设备的层级结构。每个设备都对应一个目录,设备的属性、状态信息等存放在对应的目录下。
/sys/kernel包含内核相关的参数和信息,例如内存、内核版本等。
/sys/fs包含与文件系统相关的信息。
/sys/module包含当前加载的内核模块信息。
/sys/power包含与电源管理相关的信息和设置。
/sys/firmware包含与固件相关的信息。

sysfs中,每个目录和文件都对应着内核中的某个对象或参数。例如,网络设备的状态可以在/sys/class/net/eth0目录下找到,通过读取或修改该目录中的文件,用户就可以获取或修改网卡的配置信息。

sysfs%E7%9A%84%E5%85%B7%E5%A4%87%E7%9A%84%E4%BC%98%E5%8A%BF">sysfs的具备的优势

无非就是下面四个点:

简化内核与用户空间的交互sysfs为内核空间和用户空间提供了一个简单而一致的接口。用户空间程序通过标准的文件系统API(如openreadwrite)与内核进行交互,而不需要了解内核内部的复杂数据结构和API。

统一管理sysfs将不同类型的设备和内核信息按照逻辑分组,提供了一个统一的管理接口,使得用户可以方便地获取和控制系统中的各种设备和内核参数。

灵活性和扩展性:设备驱动可以在sysfs中创建自定义的文件和目录,从而暴露设备的特定信息或控制接口。这使得sysfs具有很强的灵活性,可以适应不同类型的设备和需求。

实时性:通过sysfs,用户空间可以动态获取设备的状态信息,这对于需要实时监控或调试的场景非常有用。

C%A8%E5%93%AA%E9%87%8C%EF%BC%9F">LED在哪里?

所以我们回到我们的主题:我们的LED在哪里呢?

我们使用正点原子的板子,只提供了一个LED默认的用以操作。这里我们在/sys/class/leds可以找到我们的说法。

root@ATK-IMX6U:~/app# cd /sys/class/
root@ATK-IMX6U:/sys/class# ls
ata_device  bluetooth  hwmon      leds      net           rc           scsi_host   ubi
ata_link    dma        i2c-dev    mdio_bus  power_supply  regulator    sound       udc
ata_port    drm        icm20608   mem       ppp           rfkill       spidev      vc
backlight   firmware   ieee80211  misc      pps           rtc          spi_master  video4linux
bdi         gpio       input      mmc_host  ptp           scsi_device  thermal     vtconsole
block       graphics   lcd        mtd       pwm           scsi_disk    tty         watchdog
root@ATK-IMX6U:/sys/class# cd leds
root@ATK-IMX6U:/sys/class/leds# ls
beep  mmc0::  mmc1::  sys-led

进入sys-led文件夹,就可以看到如下的东西:

root@ATK-IMX6U:/sys/class/leds/sys-led# ls -lh
total 0
-rw-r--r-- 1 root root 4.0K Jul 30 09:55 brightness
lrwxrwxrwx 1 root root    0 Jul 30 09:55 device -> ../../../leds
-r--r--r-- 1 root root 4.0K Jul 30 09:55 max_brightness
drwxr-xr-x 2 root root    0 Jul 30 09:55 power
lrwxrwxrwx 1 root root    0 Jul 30 09:55 subsystem -> ../../../../../class/leds
-rw-r--r-- 1 root root 4.0K Jul 30 09:55 trigger
-rw-r--r-- 1 root root 4.0K Jul 30 09:55 uevent

如果只是想要控制LED的输出状态,我们只需要关心这些就OK:

  • brightness:翻译过来就是亮度的意思,该属性文件可读可写;所以这个属性文件是用于设置 LED的亮度等级或者获取当前LED 的亮度等级,譬如 brightness 等于 0 表示LED 灭,brightness 为正整数表示LED 亮,其值越大、LED 越亮;对于 PWM 控制的LED 来说,这通常是适用的,因为它存在亮度等级的问题,不同的亮度等级对应不同的占空比,自然LED 的亮度也是不同的;但对于GPIO控制(控制 GPIO 输出高低电平)的 LED 来说,通常不存在亮度等级这样的说法,只有 LED 亮(brightness 等于 0)和 LED 灭(brightness 为非 0 值的正整数)两种状态,ALPHA/Mini I.MX6U 开发板上的这颗LED 就是如此,所以自然就不存在亮度等级一说,只有亮和灭两种亮度等级。

  • max_brightness:该属性文件只能被读取,不能写,用于获取 LED 设备的最大亮度等级。

  • trigger:触发模式,该属性文件可读可写,读表示获取LED 当前的触发模式,写表示设置LED 的触发模式。不同的触发模式其触发条件不同,LED 设备会根据不同的触发条件自动控制其亮、灭状态,通过cat 命令查看该属性文件,可获取LED 支持的所有触发模式以及LED 当前被设置的触发模式

我们当然可以查看我们的trigger文件来看看到底是什么:

root@ATK-IMX6U:/sys/class/leds/sys-led# cat trigger 
none rc-feedback nand-disk mmc0 mmc1 timer oneshot [heartbeat] backlight gpio 

方括号([heartbeat])括起来的表示当前LED 对应的触发模式,none 表示无触发,常用的触发模式包括none(无触发)、mmc0(当对 mmc0 设备发起读写操作的时候 LED 会闪烁)、timer(LED 会有规律的一亮一灭,被定时器控制住)、heartbeat(心跳呼吸模式,LED 模仿人的心跳呼吸那样亮灭变化)

现在,我们就可以试试看操作一下:

root@ATK-IMX6U:/sys/class/leds/sys-led# echo "none" > trigger
root@ATK-IMX6U:/sys/class/leds/sys-led# echo "backlight" > trigger
root@ATK-IMX6U:/sys/class/leds/sys-led# cat trigger
none rc-feedback nand-disk mmc0 mmc1 timer oneshot heartbeat [backlight] gpio 
root@ATK-IMX6U:/sys/class/leds/sys-led# echo "oneshot" > trigger
root@ATK-IMX6U:/sys/class/leds/sys-led# cat trigger
none rc-feedback nand-disk mmc0 mmc1 timer [oneshot] heartbeat backlight gpio 
root@ATK-IMX6U:/sys/class/leds/sys-led# echo "timer" > trigger
root@ATK-IMX6U:/sys/class/leds/sys-led# echo "1" > brightness 
root@ATK-IMX6U:/sys/class/leds/sys-led# echo "0" > brightness 

可以观察板子的现象,变化还是很明显的。我们下面写代码玩!

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
​
static const char* LED_TRIGGER_FILE = "/sys/class/leds/sys-led/trigger";
static const char* LED_BRIGHTNESS_FILE = "/sys/class/leds/sys-led/brightness";
static const char* ON = "1";
static const char* OFF = "0";
​
​
static void inline inform_usage(const char* app_name)
{fprintf(stderr, "usage:> \n""brightness control: %s <on|off>\n""trigger mode control: %s <trigger> <type>\n", app_name, app_name);
}
​
static u_int8_t inline control_trigger_type_interface(const char* instructions_type)
{int fd = open(LED_TRIGGER_FILE, O_WRONLY);if(fd < 0) {perror("open file:> ");return 0;}int len = strlen(instructions_type);if(len != write(fd, instructions_type, len)){perror("write error");return 0;}return 1;
}
​
​
static u_int8_t inline control_brightness_impl(const char* value)
{int fd = open(LED_BRIGHTNESS_FILE, O_WRONLY);if(fd < 0) {perror("open file:> ");return 0;}if(!control_trigger_type_interface("none")) return 0;if( 1 != write(fd, value, 1)){perror("write led brigtness");return 0;}close(fd);return 1;
}
​
static u_int8_t inline control_brightness_interface(const char* instructions)
{const char* ptr_at_what = ON;if(!strcmp(instructions, "on")){return control_brightness_impl(ptr_at_what);}else if(!strcmp(instructions, "off")){ptr_at_what = OFF;return control_brightness_impl(ptr_at_what);}else{fprintf(stderr, "invalid argument! rejection!");return 0;}
}
​
int main(int argc, char* argv[])
{if(argc < 2 || argc > 3){inform_usage(argv[0]);return -1;}
​if(argc == 2 && !control_brightness_interface(argv[1])){inform_usage(argv[0]);}
​if(argc == 3){if(strcmp("trigger", argv[1])){inform_usage(argv[0]);return -1;}else{control_trigger_type_interface(argv[2]);}}
​
}

代码并不复杂,就是对文件进行读写操作!现在可以把文件上传到板子上(如何上传,如何调试请参考笔者的博文:嵌入式Linux应用层开发——调试专篇(关于使用GDB调试远程下位机开发板的应用层程序办法 + VSCode更好的界面调试体验提升)-CSDN博客)


http://www.ppmy.cn/server/152519.html

相关文章

【Python系列】Python 中的逻辑表达式解析:`not all(...)`的应用

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

HDR视频技术之八:色域映射

在之前的色调映射章节中提到&#xff1a; 在色调映射环节&#xff0c; 为了便于操作&#xff0c; 且不使图像颜色产生巨大失真&#xff0c; 色调映射算法通常会仅处理图像亮度信息&#xff0c; 将 HDR 图像亮度映射到 SDR图像亮度域中&#xff0c; 通过原 HDR 图像的颜色信息&a…

分布式专题(8)之MongoDB存储原理多文档事务详解

一、MongoDB存储原理 存储引擎是数据库的组件&#xff0c;负责管理数据如何存储在内存和磁盘上&#xff0c;MongoDB支持多个存储引擎&#xff0c;因为不同的存储引擎对特定的工作负载表现更好&#xff0c;选择合适的存储引擎可以显著影响应用程序的性能。 1.1 WiredTiger介绍 …

「Mac畅玩鸿蒙与硬件46」UI互动应用篇23 - 自定义天气预报组件

本篇将带你实现一个自定义天气预报组件。用户可以通过选择不同城市来获取相应的天气信息&#xff0c;页面会显示当前城市的天气图标、温度及天气描述。这一功能适合用于动态展示天气信息的小型应用。 关键词 UI互动应用天气预报数据绑定动态展示状态管理 一、功能说明 自定义…

微服务详细教程之nacos和sentinel实战

前言 上一篇文章中已经介绍了java的高并发编程中的问题&#xff0c;现在主要介绍微服相关的问题&#xff0c;其中在网上面经中经常出现的几个微服问题。这也是我们工作中经常遇到的几个问题。 一.微服务有哪些好处&#xff1f; 微服务优点很多&#xff0c;但是我们通常说一个东…

在linux系统的docker中安装GitLab

一、安装GitLab&#xff1a; 在安装了docker之后就是下载安装GitLab了&#xff0c;在linux系统中输入命令&#xff1a;docker search gitlab就可以看到很多项目&#xff0c;一般安装第一个&#xff0c;它是英文版的&#xff0c;如果英文不好可以安装twang2218/gitlab-ce-zh。 …

ASP.NET Core - 依赖注入 自动批量注入

依赖注入配置变形 随着业务的增长&#xff0c;我们项目工作中的类型、服务越来越多&#xff0c;而每一个服务的依赖注入关系都需要在入口文件通过Service.Add{}方法去进行注册&#xff0c;这将是非常麻烦的&#xff0c;入口文件需要频繁改动&#xff0c;而且代码组织管理也会变…

JAVA数字人创作文案视频链接提取数字人源码小程序+公众号+APP+H5

JAVA数字人创作文案提取与生成系统&#xff1a;全能型内容创作与运营解决方案 在当今数字化内容井喷的时代&#xff0c;如何高效、创新地生产并传播内容&#xff0c;成为了众多内容创作者、商户乃至企业面临的重要课题。我们的JAVA数字人创作文案提取与生成系统&#xff0c;正…