昉·星光VisionFive开发板上,提供了40Pin IO口,可以供我们在实际开发中使用。
这些IO口的具体功能定义,可以通过官方的资料了解:
在Linux系统中,GPIO驱动启用后,对应的挂载点在/sys/class/gpio
这里需要说明一下,在Linux系统上,对于常规的文件,用文件路径来访问文件,这个很好理解。
同样的,对于内外设备,Linux系统上,也把这些各种设备,当成特殊形式的文件来访问。
例如,要查看cpu的信息,那么cat /proc/cpuinfo即可。
而GPIO设备的话,其挂载点就是/sys/class/gpio。
通过官方40Pin的详细文档,我们可以了解每个引脚具体的挂载点:
从上图中,我们可以看到,GPIO0引脚,其对应的sys为448,那么,在系统中,其对应的挂载点,就是 /sys/class/gpio/gpio448
依次类推,我们可以得到,GPIO2引脚,其对应的sys为450,那么其挂载点,就是/sys/class/gpio/gpio450
但是在Linux系统中,具体GPIO的引脚,可能不会开机自动挂载,需要我们先激活,才能使用。
要激活具体的GPIO,也需要使用到一个特殊文件,那就是 /sys/class/gpio/export
如果要激活GPIO1,也就是/sys/class/gpio/gpio448,我们只需要执行下面的命令,即可激活:
echo 448 > /sys/class/gpio/export
该命令相当于告诉 /sys/class/gpio/export,请帮我激活gpio448
执行完该命令后,ls -l /sys/class/gpio,就可以看到gpio448存在了。
提醒:上述命令,需要在root权限下执行,否则执行时会提示没有权限。
激活GPIO0引脚后,我们还需要设置该引脚的功能,是输入,还是输出,那么使用下面的命令,操作/sys/class/gpio/gpio448/direction这个特殊文件即可:
如果是输出,也就是要输出高低电平,例如点亮LED,就使用:
echo out > /sys/class/gpio/gpio448/direction
上面的命令,就相当于告诉 /sys/class/gpio/gpio448/direction ,我要把你gpio448设置为out,也就是输出了。
如果是输入,例如接按键,获取按键状态,就使用:
echo in > /sys/class/gpio/gpio448/direction
上面的命令,就相当于告诉 /sys/class/gpio/gpio448/direction ,我要把你gpio448设置为in,也就是输入了。
设置好了GPIO0对应的功能后,我们就能具体使用了。
这个时侯,我们又要使用到 /sys/class/gpio/gpio448/value 这个特殊文件了。
例如,如果设置好输出,已经在GPIO0上接好了LED,现在要点亮LED了,就执行:
echo 1 > /sys/class/gpio/gpio448/value
这样就表示输出高电平
如果要熄灭对应的LED,就执行:
echo 0 > /sys/class/gpio/gpio448/value
这样就表示输出低电平了
如果设置好输入,在GPIO0上接好了普通按键,现在要获取按键输入状态,就执行:
cat /sys/class/gpio/gpio448/value
那么,显示1,表示按键按下;显示0,则表示按键松开。
在上面的讲解中,我们一共用到了下面的文件:
我们对这几个特殊文件的操作,也就是使用了基础的echo、cat指令,这样的指令,对任何一个普通文件,也可以操作。
所以本质上,对Linux而言,普通文件是文件,而这些GPIO挂载点也是文件,只不过,具体的功能有所不同罢了。
那么,如果你还懂一点bash脚本,会循环的,我命而已通过下面的方式,来闪烁GPIO0上连接的LED,具体指令如下:
# 激活GPIO0 - 448
echo 448 > /sys/class/gpio/export
# 设置GPIO0 - 448 为输出
echo out > /sys/class/gpio/gpio448/direction
# 循环10次:点亮LED,延时1秒,在关闭LED,再延时1秒
for i in 1 2 3 4 5 6 7 8 9 10
do
echo 1 /sys/class/gpio/gpio448/value
sleep 1
echo 0 /sys/class/gpio/gpio448/value
sleep 1
done
如果已经连接好LED到GPIO0,那么执行后,就能看到实际效果了。
小作业:参考上面的讲解,在控制一个LED的基础上,控制3个LED,类似下面的效果:
在上面的讲解中,我们在bash环境下,用echo来写入数据到对应的GPIO对应的文件中,从而操控LED引脚。
那么,到了C语言中,我们要如何操作呢?
实际上,也非常简单,你就把他们当作普通的文件,打开,然后写入或者读取内容就好了。
以下为一段通过GPIO0来闪烁LED的代码,基本功能和上面演示的bash脚本闪烁LED类似:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h> //define O_WRONLY and O_RDONLY
//芯片复位引脚: P1_16
#define SYSFS_GPIO_EXPORT "/sys/class/gpio/export"
#define SYSFS_GPIO_RST_PIN_VAL "448"
#define SYSFS_GPIO_RST_DIR "/sys/class/gpio/gpio448/direction"
#define SYSFS_GPIO_RST_DIR_VAL "OUT"
#define SYSFS_GPIO_RST_VAL "/sys/class/gpio/gpio448/value"
#define SYSFS_GPIO_RST_VAL_H "1"
#define SYSFS_GPIO_RST_VAL_L "0"
int main()
{
int fd;
//打开端口/sys/class/gpio# echo 448 > export
fd = open(SYSFS_GPIO_EXPORT, O_WRONLY);
if(fd == -1)
{
printf("ERR: Radio hard reset pin open error.\n");
return EXIT_FAILURE;
}
write(fd, SYSFS_GPIO_RST_PIN_VAL ,sizeof(SYSFS_GPIO_RST_PIN_VAL));
close(fd);
//设置端口方向/sys/class/gpio/gpio448# echo out > direction
fd = open(SYSFS_GPIO_RST_DIR, O_WRONLY);
if(fd == -1)
{
printf("ERR: Radio hard reset pin direction open error.\n");
return EXIT_FAILURE;
}
write(fd, SYSFS_GPIO_RST_DIR_VAL, sizeof(SYSFS_GPIO_RST_DIR_VAL));
close(fd);
//输出复位信号: 拉高>100ns
fd = open(SYSFS_GPIO_RST_VAL, O_RDWR);
if(fd == -1)
{
printf("ERR: Radio hard reset pin value open error.\n");
return EXIT_FAILURE;
}
while(1)
{
write(fd, SYSFS_GPIO_RST_VAL_H, sizeof(SYSFS_GPIO_RST_VAL_H));
usleep(1000000);
write(fd, SYSFS_GPIO_RST_VAL_L, sizeof(SYSFS_GPIO_RST_VAL_L));
usleep(1000000);
}
close(fd);
printf("INFO: Radio hard reset pin value open error.\n");
return 0;
}
上面C代码的步骤,和我们在bash脚本中操作的步骤一致,都是操作前面说的三个特殊GPIO挂载点对应的文件。
编译该c代码,并执行,就能看到和之前bash脚本执行,同样的结果了。
提醒:上述编译结果的运行,需要在root权限下执行,否则执行时会提示没有权限。
小作业:参考上面的讲解,在控制一个LED的基础上,控制3个LED,达到类似上面bash脚本控制3个LED的效果。
通过上面的讲解,我们能够学习到,如果控制GPIO0,同样的方法,你也可以控制GPIO2、GPIO4等所有你能控制的GPIO,他们无非是不同的文件而已。
不管是在bash脚本中,还是在C语言、C++语言,或者是Python中,都可以按照同样的操作文件的方式来进行操作即可。
小作业:通过控制LED点亮和熄灭的时间间隔,来实现LED灯的渐亮渐灭效果,也就是呼吸灯效果。
本帖最后由 HonestQiao 于 2022-6-11 22:01 编辑