树莓派通过sysfs操作GPIO时fopen权限拒绝问题求助
问题分析与解决
问题根源
首次运行程序时,导出GPIO引脚后立刻访问/sys/class/gpio/gpio18/direction出现权限拒绝,核心原因是:内核创建GPIO相关文件后,udev守护进程需要一小段时间执行权限配置规则(将文件的组权限设置为gpio组)。程序导出引脚后立刻尝试打开文件,此时udev还未完成权限修改——即便当前用户已加入gpio组,也无法获取读写权限。第二次运行时,udev早已完成权限配置,因此能正常访问。
解决方案
导出GPIO后,不要立刻访问文件,而是通过循环重试打开文件(添加超时限制),等待udev完成权限更新。这种方式既避免了固定延时的不确定性,又能保证程序稳定执行。
修改后的代码示例
#include <stdio.h> #include <string.h> #include <errno.h> #include <stdlib.h> #include <unistd.h> #define MAX_RETRIES 10 #define RETRY_DELAY 200000 // 200ms,单位微秒 int main(int argc, char const* argv[]) { // 导出GPIO引脚 FILE* p_gpio_line = fopen("/sys/class/gpio/export", "w"); if (!p_gpio_line) { printf("Cannot open export file.\n"); perror("fopen"); exit(1); } // 确保完整写入引脚号,检查返回值 if (fwrite("18", sizeof(char), 2, p_gpio_line) != 2) { printf("Failed to write to export file.\n"); fclose(p_gpio_line); exit(1); } fclose(p_gpio_line); // 循环尝试打开direction文件,仅针对权限错误重试 FILE* p_gpio_direction = NULL; int retries = 0; while (retries < MAX_RETRIES) { p_gpio_direction = fopen("/sys/class/gpio/gpio18/direction", "r+"); if (p_gpio_direction) { break; } // 非权限错误直接退出,避免无意义重试 if (errno != EACCES) { printf("Cannot open direction file.\n"); perror("fopen"); exit(1); } retries++; usleep(RETRY_DELAY); } if (!p_gpio_direction) { printf("Failed to open direction file after %d retries.\n", MAX_RETRIES); exit(1); } // 设置引脚方向为输出(示例) fwrite("out", sizeof(char), 3, p_gpio_direction); fclose(p_gpio_direction); return 0; }
额外说明
- 加入了
export文件写入的返回值检查,避免因写入不完整导致的异常。 - 重试逻辑仅针对
EACCES(权限拒绝)错误,其他错误直接退出,提升程序健壮性。 - 延时时间和重试次数可根据实际系统调整,确保udev有足够时间完成权限配置。
内容的提问来源于stack exchange,提问作者First dev
相关产品推荐
相关产品推荐

