使用libgpiod获取GPIO输出模式的值

本文讲述了作者在Linux环境中从sysfs转向gpiod子系统进行GPIO控制的经历,遇到的问题是读取输出模式GPIO口值时保持原有模式的困难,通过gpioset的as-is选项尝试并给出了自定义读取输出状态的示例代码。
摘要由CSDN通过智能技术生成

写一篇随意一点的博客吧,因为我的时间总是不够用。虽然简单,我怀疑本篇文章能帮到不少人。帮人就是我的乐趣。我希望解决了温饱问题的同志们,积极参与社会治理活动中来。只有每个人出一份力,我们的社会才会变得美好。只有社会美好,我们以及我们的子孙才能美好。

世界是他们的,但也是我们的,但终究还是我们的!!每天看30分钟的负能量,我任然充满正能量。

最近我使用的Linux环境完全弃用了sysfs的gpio系统。那么我就只能使用gpiod子系统。gpiod提供了许多工具,例如gpioget、gpioset、gpioinfo等。这些指令的使用在网上都有教程。如果我们使用c语言编程控制GPIO会使用到libgpiod库。

我碰到一个问题,就是读取输出模式下的GPIO口的值,我没有找到合适的工具。因为gpioget会把要操作的GPIO口先设置为输入模式,这明显不满足我的要求。在网上找了一下,找到了gpiogetas-is选项。该选项说是保留GPIO原有的模式。然后就根据帮助信息尝试,果然不可以,这个命令还是改变了GPIO口的输出方向,非吾之所想。但是也介绍一下,命令如下。

# gpioset  5 12=1
# 
# gpioget -B as-is 5 12
1
# gpioset  5 12=0
# 
# gpioget -B as-is 5 12
0
# 

帮助信息如下:

# gpioset --help
Usage: gpioset [OPTIONS] <chip name/number> <offset1>=<value1> <offset2>=<value2> ...

Set GPIO line values of a GPIO chip and maintain the state until the process exits

Options:
  -h, --help:		display this message and exit
  -v, --version:	display the version and exit
  -l, --active-low:	set the line active state to low
  -B, --bias=[as-is|disable|pull-down|pull-up] (defaults to 'as-is'):
		set the line bias
  -D, --drive=[push-pull|open-drain|open-source] (defaults to 'push-pull'):
		set the line drive mode
  -m, --mode=[exit|wait|time|signal] (defaults to 'exit'):
		tell the program what to do after setting values
  -s, --sec=SEC:	specify the number of seconds to wait (only valid for --mode=time)
  -u, --usec=USEC:	specify the number of microseconds to wait (only valid for --mode=time)
  -b, --background:	after setting values: detach from the controlling terminal

Biases:
  as-is:	leave bias unchanged
  disable:	disable bias
  pull-up:	enable pull-up
  pull-down:	enable pull-down

Drives:
  push-pull:	drive the line both high and low
  open-drain:	drive the line low or go high impedance
  open-source:	drive the line high or go high impedance

Modes:
  exit:		set values and exit immediately
  wait:		set values and wait for user to press ENTER
  time:		set values and sleep for a specified amount of time
  signal:	set values and wait for SIGINT or SIGTERM

如果你的开发环境没有as-is选项,那么你可自己写一个。下面是我写的一个读取输出状态的GPIO口值的示例程序。

#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>

#include <gpiod.h>

#define GPIO_CHIP_PREFIX "gpiochip"

static void usage(char **argv)
{
    fprintf(stderr, "Usage:\n");
    fprintf(stderr, "%s group_number line_number\n", argv[0]);
}

static int extract_gpio_group_line_number(char **argv, int *r_group_num, int *r_line_num)
{
    if (!r_group_num || !r_line_num) {
        return -1;
    }
    const char *g_str, *l_str;
    if (0 == strncasecmp(argv[1], GPIO_CHIP_PREFIX, strlen(GPIO_CHIP_PREFIX))) {
        g_str = argv[1] + strlen(GPIO_CHIP_PREFIX);
    } else {
        g_str = argv[1];
    }

    if (0 == strncasecmp(argv[2], GPIO_CHIP_PREFIX, strlen(GPIO_CHIP_PREFIX))) {
        l_str = argv[2] + strlen(GPIO_CHIP_PREFIX);
    } else {
        l_str = argv[2];
    }

    char *endptr = NULL;
    int group_num = strtol(g_str, &endptr, 10);
    if (endptr == g_str || *endptr != '\0' || group_num < 0) {
        fprintf(stderr, "The GPIO Group number error, %s\n", g_str);
        return -2;
    }

    int line_num = strtol(l_str, &endptr, 10);
    if (endptr == l_str || *endptr != '\0' || line_num < 0 || line_num >= 32) {
        fprintf(stderr, "The GPIO Line number error, %s\n", l_str);
        return -3;
    }

    *r_group_num = group_num;
    *r_line_num = line_num;
    return 0;
}

int main(int argc, char **argv)
{
    if (argc != 3) {
        usage(argv);
        return -1;
    }

    int group_num, line_num;
    int ret = extract_gpio_group_line_number(argv, &group_num, &line_num);
    if (ret != 0) {
        usage(argv);
        return ret;
    }

    char chipname[32];
    snprintf(chipname, sizeof(chipname), "gpiochip%d", group_num);

    struct gpiod_chip *chip = gpiod_chip_open_by_name(chipname);
    if (!chip) {
        fprintf(stderr, "Open chip:%s failed, reasion:%s\n", chipname, strerror(errno));
        return -1;
    }

    struct gpiod_line *line = gpiod_chip_get_line(chip, line_num);
    if (!line) {
        fprintf(stderr, "Get line:%d failed, reasion:%s\n", line_num, strerror(errno));
        goto close_chip;
    }

    /* ref : https://libgpiod-dlang.dpldocs.info/source/gpiod.d.html#L1025 */
    struct gpiod_line_request_config conf;
    memset(&conf, 0, sizeof(conf));

    /* just a label for gpio */
    conf.consumer = "snoop";

    /* request gpio and do not change the current mode */
    conf.request_type = GPIOD_LINE_REQUEST_DIRECTION_AS_IS;

    /* up down pull flags */
    conf.flags = 0;

    ret = gpiod_line_request(line, &conf, 0 /* default value */);
    if (ret < 0) {
        fprintf(stderr, "Request line(%s %d) as-is  is failed, reasion:%s\n", chipname, line_num, strerror(errno));
        goto release_line;
    }

    int value;
    /* Read input */
    value = gpiod_line_get_value(line);
    if (value < 0) {
        fprintf(stderr, "Read line input failed, reasion:%s\n", strerror(errno));
        goto release_line;
    }
    printf("%d\n", value);

release_line:
    gpiod_line_release(line);
close_chip:
    gpiod_chip_close(chip);

    return 0;
}

测试过程如下:

~# gpioget 5 12
0
~# gpioinfo  | grep PF12
	line  12:       "PF12"       unused   input  active-high 
~# 
~# ./gpiosnoop 5 12
0
~# ./gpiosnoop 5 12
0
~# ./gpiosnoop 5 12
0
~# ./gpiosnoop 5 12
0
~# gpioinfo  | grep PF12
	line  12:       "PF12"       unused   input  active-high 
~# 
~# gpioset 5 12=1
~# ./gpiosnoop 5 12
1
~# ./gpiosnoop 5 12
1
~# gpioinfo  | grep PF12
	line  12:       "PF12"       unused  output  active-high 
~# gpioinfo  | grep PF12
	line  12:       "PF12"       unused  output  active-high 
~# ./gpiosnoop 5 12
1
~# ./gpiosnoop 5 12
1
~# ./gpiosnoop 5 12
1
~# gpioinfo  | grep PF12
	line  12:       "PF12"       unused  output  active-high 
~# 
~# ./gpiosnoop gpiochip5 12
1
~# ./gpiosnoop gpiochip5 12x
The GPIO Line number error, 12x
Usage:
./gpiosnoop group_number line_number
~# 

如果你喜欢我的理想,请加入我们,行动起来。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值