文章目录
- 1应用层控制外设的两种方式
- 2 sysfs和/sys关系
- 3 LED控制方式
- 3.1 基本情况
- 3.2 LED属性文件介绍
- 3.3 命令行属性测试
- 3.4 led程序
- 3.5 开发板上测试
1应用层控制外设的两种方式
- 使用设备文件控制
在Linux系统下,一切皆是文件。应用层控制底层硬件同样也是通过文件IO的方式。设备文件可以理解为硬件层向应用层提供的接口
。应用层通过对设备文件IO的操作来操控硬件设备。设备文件通常在/dev/
目录下,所以/dev
目录下的文件成为设备节点。 - 使用sysfs文件系统
还有一种方式是通过sysfs
文件系统控制。sysfs文件系统是基于内存的文件系统,也是一种虚拟文件系统,他的作用是将内核信息已文件形式提供给应用层使用。他的主要功能是对系统设备进行管理,产生一个包含所有硬件层次的试图。
sysfs提供可一种机制,可以显示的描述内核对象、对象属性以及对象间关系,用来导出内核对象的数据、属性到用户空间,以文件目录结构的形式为用户空间提供对这些数据、属性的访问支持。内核对象、对象属性以及对象间关系在用户空间sysfs中的表现如下表:内核中的组成要素 sysfs中的表现 内核对象(硬件设备) 目录 对象属性(设备属性) 文件 对象关系 链接文件 - 总结
应用层对底层硬件控制的两种方式:- /dev/目录下的设备文件(设备节点)
- /sys/目录下设备的属性文件
具体使用哪种方式需要根据不同功能类型设备进行选择,有些设备只能通过设备节点进行操控,而有些文件只能通过sysfs方式进行操控。通常情况下,一般简单的设备会是用sysfs方式操作,例如led、GPIO等。对于复杂的文件,例如LCD、触摸屏、摄像头等,需要使用设备节点操作。
2 sysfs和/sys关系
sysfs文件系统挂载在/sys
目录下。sysfs文件系统中的目录包括block、bus、dev、devices、firmware、fs、kernel、modules、power
等,每个目录下有许多文件或者子目录,对于这些目录的说’‘明如下所示(/sys目录下内容):
-
devices
系统中所有设备存放目录,sysfs管理设备的最重要的目录结构。
-
block
块设备的存放目录,过时的接口
,该目录下的文件通常是连接到’/sys/devices’目录下的文件。
-
bus
所有设备按总线类型分类放置的目录结构,'/sys/devices’目录下的每种设备都是挂载在某种总线下的,例如i2c总线,同样,该目录下的文件也是链接到’sys/devices’目录下的。
-
class
所有设备按照其功能分类放置的目录结构,例如led设备。'/sys/class/input’目录存放着所有输入类设备。
-
dev
按照设备号的方式放置目录结构,该目录下有很多以主设备号:次设备号命令的文件,这些文件都是链接文件,连接到’/sys/devices’目录下。
-
firmware
描述内核中的固件
-
fs
描述系统中所有文件系统,包括文件系统本身和按文件系统分类存放的已挂载点。
-
kernel
内核中所有的可调参的位置
-
module
系统中所有模块信息
-
power
系统中电源选项,有一些属性可以用于控制整个系统的电源状态
系统中所有设备都会在/sys/devices
中体现出来,是sysfs文件系统最重要的目录结构。
3 LED控制方式
3.1 基本情况
硬件情况:使用底板上的DS0 led(用户可以控制的唯一LED)
开发板启动方式:emmc启动
mmc中的系统:正点原子的系统
交叉编译器:arm-linux-guneabihf-
控制方式:sysfs文件系统
控制目录:/sys/class/led
3.2 LED属性文件介绍
进入到/sys/class/led
目录下,该目录中存放着所有的LED设备,目录如下图所示:
可以看到该目录中有一个sys-led
的文件夹,这个就是底板上LED的设备文件,该目录下文件如下图所示:
这里主要关注brightness、max_brightness以及trigger三个文件,这三个都是LED的属性文件。
- brightness:亮度
可读可写,设置led的亮度等级,
0:灭
正整数:pwm控制的led:值越大,led越亮
GPIO控制的led:亮 - max_brightness:最大亮度等级
只读文件 - trigger:触发模式
可读可写,设置当前LED触发模式,读表示获取当前触发模式,写表示设置当前触发模式。
触发模式:方括号[ ]
括起来的表示当前触发模式- none:无触发
- mmc0:对mmc0设备读写时led会闪烁
- timer:有一定规律的亮灭,定时器控制
- heartbeat:心跳呼吸模式
通常系统启动之后,都会将板子上的一颗led设置为heartbeat
触发模式,表示系统正在正常运行。
3.3 命令行属性测试
通过echo
命令进行LED控制
echo timer > trigger // 将led触发模式设置为定时触发
echo none > trigger // 将led触发模式设置为无触发模式
echo 1 > brightness // 点亮led
3.4 led程序
gitee: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_TRIGGER "/sys/class/leds/sys-led/trigger"
#define LED_BRIGHTNESS "/sys/class/leds/sys-led/brightness"
#define USAGE() fprintf(stderr, "usage:\n" \
" %s<on|off>\n" \
" %s<trigger><type>\n", argv[0],argv[0])
int main(int argc, char *argv[])
{
int fd_trigger, fd_brightness;
/* 判断输入参数个数 */
if( argc < 2 ) {
USAGE();
exit(-1);
}
/* 打开文件 */
fd_trigger = open(LED_TRIGGER, O_RDWR);
if (fd_trigger < 0 ) {
perror("open trigger error");
exit(-1);
}
fd_brightness = open(LED_BRIGHTNESS, O_RDWR);
if (fd_brightness < 0 ) {
perror("open brightness error");
exit(-1);
}
/* 判断输入参数 */
if ( !strcmp(argv[1],"on") ) {
write(fd_trigger, "none", 4);
write(fd_brightness, "1", 1);
} else if ( !strcmp(argv[1], "off") ) {
write(fd_trigger, "none", 4);
write(fd_brightness, "0", 1);
} else if ( !strcmp(argv[1], "trigger")) {
if ( argc != 3 ) {
USAGE();
exit(-1);
}
if ( write(fd_trigger, argv[2], strlen(argv[2]) ) < 0 ) {
perror("set trigger faile");
}
} else {
USAGE();
}
close(fd_trigger);
close(fd_brightness);
exit(0);
}
因为是运行在I.MX6ULL平台上,所以要是用交叉编译器编译,makefile文件内容如下:
TARGET ?= led # 目标文件
CROSS_COMPILE ?= arm-linux-gnueabihf- # 交叉编译器
CC = $(CROSS_COMPILE)gcc
LD = $(CROSS_COMPILE)ld
src = led.c # 源码文件
$(TARGET):$(src)
$(CC) -o $@ $<
.PHONY: clean # 伪目标
# 清除工程
clean:
rm -rf *.o $(TARGET)
3.5 开发板上测试
将编译好的二进制文件使用scp
命令发送到开发板上。在开发板中执行下面命令,观察led变化。二进制文件一定要有可执行权限。
./led on // 亮
./led off // 灭
./led trigger heartbeat // 呼吸模式