使用libgpiod库中的事件方式监测多个输入事件

 Linux下要同时检测多个GPIO输入的方法有很多,这里我使用libgpiod库中的API实现多个GPIO输入检测,可以达到类似STM32利用外部中断实现输入事件检测的效果,示例代码如下所示:

/* 示例使用的libgpiod库版本为V1.2.1 */
//示例功能是通过libgpiod库捕获GPIO输入事件

#include <stdbool.h>
#include <stdio.h>
#include "gpiod.h"

/* GPIO组路径 */
#define GPIO_CHIP_PATH "/dev/gpiochip0"

/* GPIO组 */
struct gpiod_chip *Test_Gpio_Chip;

/* 电源切换信号输入 */
struct gpiod_line *Gpio_Line_In_Switch;
#define LINE_IN_SWITCH_ID   113  /* PD17 */

/* 脉冲信号输入 */
struct gpiod_line *Gpio_Line_In_PPS;
#define LINE_IN_PPS_ID   115  /* PD19 */

/**
 * 配置GPIO输入
 * 
 * 本函数用于配置GPIO线脚为输入模式,并设置其触发事件。需要指定GPIO芯片、引脚ID号、触发事件以及GPIO线脚的客户端名称。
 * 
 * @param chip 指向GPIO芯片的指针。
 * @param line 指向GPIO线脚的指针的地址,函数执行成功后,会在这里返回配置好的线脚指针。
 * @param line_id 要配置的GPIO线脚的ID。
 * @param edge 触发事件的类型,0表示下降沿触发,1表示上升沿触发,2表示同时触发。
 * @param consumer 指定使用这个GPIO线脚的客户端名称。
 * @return 成功返回0,否则返回错误码。
 * @note 触发事件类型为0表示下降沿触发,1表示上升沿触发,2表示同时触发。
 */
int gpio_input_config(struct gpiod_chip* chip, struct gpiod_line** line, int line_id, int edge, const char* consumer)
{
    struct gpiod_line* tmp_line;
    int ret;
    if (!chip || !consumer || !line)
    {
        return -1;
    }
    tmp_line = gpiod_chip_get_line(chip, line_id);
    if (!tmp_line) 
    {

        return -2;
    }

    if(edge == 0)
    {
        ret = gpiod_line_request_falling_edge_events(tmp_line, consumer);
    }
    else if(edge == 1)
    {
        ret = gpiod_line_request_rising_edge_events(tmp_line, consumer);
    }
    else
    {
        ret = gpiod_line_request_both_edges_events(tmp_line, consumer);
    }

    if (ret < 0) 
    {
        gpiod_line_release(tmp_line);
        return -3;
    }

    *line = tmp_line;
    return ret;
}

/**
 * GPIO清理函数
 * 
 * 本函数用于释放GPIO资源,包括释放GPIO线脚和关闭GPIO芯片。
 */
void gpio_cleanup(void) 
{
    if(Gpio_Line_In_PPS)
    {
        gpiod_line_release(Gpio_Line_In_PPS);
    }
    if(Gpio_Line_In_Switch)
    {
        gpiod_line_release(Gpio_Line_In_Switch);
    }

    if(Test_Gpio_Chip)
    {
        gpiod_chip_close(Test_Gpio_Chip);
    }
}


/**
 * GPIO初始化函数
 * 
 * 本函数用于初始化GPIO,将GPIO配置为输入。
 * 
 * @return 成功返回0,否则返回-1。
 */
int gpio_init(void) 
{
    int init_sta = 0;
    int ret;
    /* 打开芯片GPIO组 */
    Test_Gpio_Chip = gpiod_chip_open(GPIO_CHIP_PATH);
    if (!Test_Gpio_Chip ) 
    {
        return -1;
    }
    
    /* PPS引脚输入配置 */
    ret = gpio_input_config(Test_Gpio_Chip, &Gpio_Line_In_PPS, LINE_IN_PPS_ID, 0, "pps");
    if (ret == 0) 
    {
        init_sta++;
    }
    else
    {
        printf ("gpio %d input config failed: %d\n", LINE_IN_PPS_ID, ret);
    }

    /* 电源切换信号输入配置 */
    ret = gpio_input_config(Test_Gpio_Chip, &Gpio_Line_In_Switch, LINE_IN_SWITCH_ID, 0, "switch");
    if (ret == 0) 
    {
        init_sta++;
    }
    else
    {
        printf ("gpio %d input config failed: %d\n", LINE_IN_SWITCH_ID, ret);
    }    

    /* 如果配置失败,则关闭芯片并返回错误 */
    if (init_sta == 0)
    {
        if(Test_Gpio_Chip)
        {
            gpiod_chip_close(Test_Gpio_Chip);
        }
        return -1;
    }

    return 0;
}



/**
 * GPIO输入事件处理线程
 * 
 * 本函数用于处理GPIO输入事件,通过调用gpiod_line_event_wait和gpiod_line_event_read函数来获取事件。
 * 
 * @param arg 线程参数,这里没有使用。
 */
void* gpio_input_event_thread(void* arg)
{
    struct gpiod_line_bulk gpiod_line_bulk, event_bulk;
    struct gpiod_line_event event;
    int ret;
    gpiod_line_bulk_add(&gpiod_line_bulk, Gpio_Line_In_PPS);
    gpiod_line_bulk_add(&gpiod_line_bulk, Gpio_Line_In_Switch);    
    while(1)
    {
        /* 无限阻塞,直到输入事件到来 */
        ret = gpiod_line_event_wait_bulk(&gpiod_line_bulk, NULL, &event_bulk);
        if (ret < 0)
        {
            printf("gpiod line event wait error\n");
        }
        else if(ret == 0)
        {
            printf("gpiod line event wait timeout\n");
        }
        else
        {
            /* 解析检测到的事件 */
            for(unsigned int i=0; i<event_bulk.num_lines; i++)
            {
                if(gpiod_line_event_read(event_bulk.lines[i], &event) == 0)
                {
                    printf("line %d event happen\n", gpiod_line_offset(event_bulk.lines[i]));
                    /* 还可以根据event中的内容判断当前检测到的事件是上升沿还是下降沿*/
                }                  
            }
        }
    }
}

int main(void) 
{
     if (gpio_init() != 0) 
     {
         printf("gpio init failed\n");
         return 1;
     }

     gpio_input_event_thread(NULL);
     gpio_cleanup();
     return 0;
}

运行结果如下:

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值