linux 应用层使用gpio

hazing 2020-02-19

  • 使用这个代码之前 首先确认开发版的 “/sys/class/” 目录下有gpio这个文件夹,如果没有就需要配置linux内核
  • linux 应用层使用gpio
    /**
     * @author emlsyx
     * @email 
     * @create date 2020-02-19 19:11:53
     * @modify date 2020-02-19 19:11:53
     * @desc [description]
     */
    #include <stdlib.h>
    #include <stdio.h>
    #include <string.h>
    #include <unistd.h>
    #include <fcntl.h>
    #include <linux/poll.h>
    
    #define err_out(fmt, ...)                                                          do                                                                             {                                                                                  printf(fmt, ##__VA_ARGS__);                                                    printf("<%s>  \"%s()\" %d error\n", __FILE__, __FUNCTION__, __LINE__);     } while (0)
    
    #define open_gpio_file(path, flag, fd)                  do                                                  {                                                       fd = open(path, flag);                              if (fd < 0)                                         {                                                       err_out("\"%s\" open failed \n", path);             return (-1);                                    }                                               } while (0);
    
    /**
     * @brief : gpio 导出
     * @param : pin
     * @retval: 0 成功; -1失败
     */
    static int gpio_export(const int pin)
    {
        int fd, len;
        char buffer[64];
        char path[64];
    
        sprintf(&path[0], "/sys/class/gpio/gpio%d", pin);
        /* 文件不存在时,导出gpio*/
        if (access(path, F_OK) != 0)
        {
            memset(path, 0, 64);
            sprintf(&path[0], "/sys/class/gpio/export");
            open_gpio_file(path, O_WRONLY, fd);
            len = snprintf(buffer, sizeof(buffer), "%d", pin);
    
            if (write(fd, buffer, len) < 0)
            {
                err_out("write failed to export gpio!\n");
                return -1;
            }
            close(fd);
        }
        return 0;
    }
    /**
     * @brief : gpio 卸载
     * @param : pin
     * @retval: 0 成功; -1失败
     */
    static int gpio_unexport(const int pin)
    {
        int fd, len;
        char buffer[64];
        char path[64];
    
        sprintf(&path[0], "/sys/class/gpio/gpio%d", pin);
        /* 文件存在时,卸载gpio*/
        if (access(path, F_OK) == 0)
        {
            memset(path, 0, 64);
            sprintf(&path[0], "/sys/class/gpio/unexport");
            open_gpio_file(path, O_WRONLY, fd);
            len = snprintf(buffer, sizeof(buffer), "%d", pin);
            if (write(fd, buffer, len) < 0)
            {
                err_out("write failed to unexport gpio!\n");
                return -1;
            }
            close(fd);
        }
        return 0;
    }
    
    /**
     * @brief : gpio 方向控制
     * @param : dir 方向(in/out)
     * @retval: 0 成功; -1失败
     */
    static int gpio_direction(const int pin, const char *dir)
    {
        int fd;
        char path[64];
        int w_len = ((dir[0] == ‘i‘) && (dir[1] == ‘n‘)) ? 2 : 3;
    
        snprintf(path, sizeof(path), "/sys/class/gpio/gpio%d/direction", pin);
        open_gpio_file(path, O_WRONLY, fd);
        if (write(fd, dir, w_len) < 0)
        {
            err_out("Failed to set direction!\n");
            return -1;
        }
    
        close(fd);
        return 0;
    }
    
    /**
     * @brief : gpio 写
     * @param : 0 / 1
     * @retval: 0 成功; -1失败
     */
    static int gpio_write(const int pin, const int value)
    {
        int fd;
        char path[64];
        const char *val[] = {"0", "1"};
    
        snprintf(path, sizeof(path), "/sys/class/gpio/gpio%d/value", pin);
        open_gpio_file(path, O_WRONLY, fd);
    
        if (write(fd, val[value], 1) < 0)
        {
            err_out("Failed to write value!\n");
            return -1;
        }
    
        close(fd);
        return 0;
    }
    
    /**
     * @brief : gpio 读
     * @param : 读取的引脚值
     * @retval: 返回引脚的值 0 / 1
     */
    static int gpio_read(const int pin)
    {
        int fd;
        char path[64];
        char value_str[3];
    
        snprintf(path, sizeof(path), "/sys/class/gpio/gpio%d/value", pin);
        open_gpio_file(path, O_RDONLY, fd);
        if (read(fd, value_str, 3) < 0)
        {
            err_out("Failed to read value!\n");
            return -1;
        }
    
        close(fd);
        return (atoi(value_str));
    }
    
    /**
     * @brief : gpio 中断控制
     * @param : 0 none 表示引脚为输入,不是中断引脚
     *   @arg : 1 rising 表示引脚为中断输入,上升沿触发
     *   @arg : 2 falling 表示引脚为中断输入,下降沿触发
     *   @arg : 3 both 表示引脚为中断输入,边沿触发
     * @retval:
     */
    static int gpio_edge(const int pin, int edge)
    {
        int fd;
        char path[64];
        const char *dir_str[] = {"none", "rising", "falling", "both"};
    
        if (edge > 3)
        {
            err_out("Failed edge parameter error\n");
            return -1;
        }
    
        snprintf(path, sizeof(path), "/sys/class/gpio/gpio%d/edge", pin);
        open_gpio_file(path, O_WRONLY, fd);
    
        if (write(fd, dir_str[edge], strlen(dir_str[edge])) < 0)
        {
            err_out("Failed to set edge!\n");
            return -1;
        }
    
        close(fd);
        return 0;
    }
    
    int main()
    {
        char buff[10], res;
        int led_fd, key_fd;
        struct pollfd fds;
    
        /* 按键led指示灯*/
        gpio_export(55);
        gpio_direction(55, "out");
        gpio_write(55, 0);
    
        /* 按键引脚初始化*/
        gpio_export(70);
        gpio_direction(70, "in");
        gpio_edge(70, 2);
        open_gpio_file("/sys/class/gpio/gpio70/value", O_RDONLY, key_fd);
    
        /* poll 操作的文件符号*/
        fds.fd = key_fd;
    
        /* 经测试io中断产生后,正常会发送POLLPRI 这个中断,循环中必须等待这个事件*/
        fds.events = POLLPRI | POLLERR;
    
        /* 真实发生的事件*/
        fds.revents = 0;
        while (1)
        {
            int ret = poll(&fds, 1, -1);
            if (!ret)
            {
                err_out("poll time out\n");
            }
            else
            {
                if (fds.revents & POLLPRI)
                {
                    gpio_write(55, gpio_read(55) ? 0 : 1);
    
                    res = lseek(fds.fd, 0, SEEK_SET); /* 读取按键值*/
                    if (res == -1)
                    {
                        printf("lseek failed!\n");
                        return -1;
                    }
                    res = read(fds.fd, buff, sizeof(buff));
                    if (res == -1)
                    {
                        perror("read failed!\n");
                        return -1;
                    }
                    printf("fds.revents %d key value %s \n", fds.revents, buff);
                }
            }
        }
    
        return 0;
    }

相关推荐