使用文件IO操作GPIO引脚之花式点灯(/sys/class/gpio)
实验结果:在设备树未驱动该引脚的情况下,也可以通过此方法控制引脚电平。
寄存器点灯、函数点灯、驱动点灯都写过,但是还没有接触这种方式,因此想将其记录下来,首先编写gpio相关函数:
头文件就不写了,gpio.c内容如下:
#include <stdint.h>
#include <stdbool.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <poll.h>
#include <stdio.h>
#include <sys/stat.h>
#include <fcntl.h>
#define CFG_GPIO_DIR "/sys/class/gpio"
#define CFG_GPIO_SYS_FILE_EXPORTED_TIME_IN_100MS 10
int gpio_is_exported(size_t gpio)
{
int fd = 0;
int i;
char buf[64] = {0};
size_t len = 0;
len = snprintf(buf, sizeof(buf), CFG_GPIO_DIR "/gpio%lu/direction", gpio);
fd = open(buf, O_WRONLY);
if (fd >= 0) {
close(fd);
return 1;
}
return 0;
}
int gpio_export(size_t gpio)//112
{
int fd = 0;
int i;
char buf[64] = {0};
size_t len = 0;
if( gpio_is_exported(gpio))
{
return 0; //No need to re-export
}
fd = open(CFG_GPIO_DIR "/export", O_WRONLY); //export文件用于通知系统需要导出控制的GPIO引脚编号
if( fd < 0 )
{
return -1;
}
len = snprintf(buf, sizeof(buf), "%lu", gpio);
write(fd, buf, len); //向export文件写入GPIO编号,使得该GPIO的操作接口从内核空间暴露到用户空间
//成功后生成/sys/class/gpio/gpio112目录,如果没有出现相应的目录,说明此引脚不可导出
close(fd);
/* wait until file is actually available in user space */
for (i = 0; i < CFG_GPIO_SYS_FILE_EXPORTED_TIME_IN_100MS; i++)
{
if( gpio_is_exported(gpio))
{
return 0; //GPIO is present in user space
}
usleep(100 * 1000);
}
return -1;
}
int gpio_unexport(size_t gpio)
{
int fd = 0;
char buf[64] = {0};
size_t len = 0;
fd = open(CFG_GPIO_DIR "/unexport", O_WRONLY); //unexport文件用于通知系统取消导出
if( fd < 0 )
{
return -1;
}
len = snprintf(buf, sizeof(buf), "%lu", gpio);
write(fd, buf, len);
close(fd);
return 0;
}
int gpio_set_direction(size_t gpio, int is_output)
{
int fd = 0;
char buf[64] = {0};
size_t len = 0;
len = snprintf(buf, sizeof(buf), CFG_GPIO_DIR "/gpio%lu/direction", gpio); //GPIO的操作接口包括direction和value等,direction控制GPIO方向
fd = open(buf, O_WRONLY);
if( fd < 0 )
{
return -1;
}
if(is_output)
{
write(fd, "out", 3);
}
else
{
write(fd, "in", 2);
}
close(fd);
return 0;
}
int gpio_set_edge(size_t gpio, int rising, int falling)
{
int fd = 0;
char buf[64] = {0};
size_t len = 0;
len = snprintf(buf, sizeof(buf), CFG_GPIO_DIR "/gpio%lu/edge", gpio); // none表示引脚为输入,不是中断引脚;rising表示引脚为中断输入,上升沿触发;falling表示引脚为中断输入,下降沿触发;both表示引脚为中断输入,边沿触发;
fd = open(buf, O_WRONLY);
if( fd < 0 )
{
return -1;
}
if(rising && falling)
{
write(fd, "both", 4);
}
else if(rising)
{
write(fd, "rising", 6);
}
else
{
write(fd, "falling", 7);
}
close(fd);
return 0;
}
int gpio_set_value(size_t gpio, int value)
{
int fd = 0;
char buf[64] = {0};
size_t len = 0;
len = snprintf(buf, sizeof(buf), CFG_GPIO_DIR "/gpio%lu/value", gpio); //控制gpio的值,value文件中是端口的数值,为1或0
fd = open(buf, O_WRONLY | O_NONBLOCK);
if( fd < 0 )
{
return -1;
}
if (value != 0)
write(fd, "1", 1);
else
write(fd, "0", 1);
close(fd);
return 0;
}
int gpio_get_value(size_t gpio)
{
int fd = 0;
char buf[64] = {0};
size_t len = 0;
int ret, val;
len = snprintf(buf, sizeof(buf), CFG_GPIO_DIR "/gpio%lu/value", gpio);
fd = open(buf, O_RDONLY | O_NONBLOCK);
if( fd < 0 )
{
return -1;
}
ret = read(fd, buf, 1);
if (ret < 0)
{
close(fd);
return -1;
}
val = buf[0] - '0';
close(fd);
return val;
}
然后就是点灯文件了:
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <termio.h>
#include <sys/time.h>
#include <unistd.h>
#include <assert.h>
#include <errno.h>
#include <sys/mman.h>
#include "gpio.h"
#define GPIO_TO_NUM(bank, gpio) (32 * ((bank) - 1) + (gpio))
#define LED_GPIO_NUM GPIO_TO_NUM(4, 16) //112
static int set_led(int is_on)
{
int ret;
ret = gpio_set_value(LED_GPIO_NUM, is_on);
if (ret < 0)
{
fprintf(stderr, "gpio : %d set value(%d) failed!!!!\n", LED_GPIO_NUM, is_on);
return -1;
}
else
return 0;
}
int main(int argc, char *argv[])
{
int ret;
int i;
ret = gpio_export(LED_GPIO_NUM); //将gpio112从内核空间暴露到用户空间
if (ret < 0)
{
fprintf(stderr, "export gpio : %d failed!!!!\n", LED_GPIO_NUM);
return -1;
}
ret = gpio_set_direction(LED_GPIO_NUM, 1); //将gpio112设置为输出引脚
if (ret < 0)
{
fprintf(stderr, "gpio : %d set direction(output) failed!!!!\n", LED_GPIO_NUM);
return -1;
}
for (i = 0; i < 10; i++)
{
set_led(1);
sleep(1);
set_led(0);
sleep(1);
}
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· 写一个简单的SQL生成工具
· AI 智能体引爆开源社区「GitHub 热点速览」
· C#/.NET/.NET Core技术前沿周刊 | 第 29 期(2025年3.1-3.9)