Linux应用层操作IO实践经历

1、概述

本文主要讲述在应用层控制gpio,内核的设备树修改在此不做说明。

2、原理

1.设备树添加对应IO;

2.在应用层设置对应IO的配置;

3.打开对应IO的文件,写入或者读取对应IO目录下的“value”的文件;

3、代码

.h文件

#ifndef _LED_H_
#define _LED_H_

#define FALSE  -1
#define TRUE   0

enum
{
    LED0=0,
    LED1,
    LED2,
    LED3,
    LED4,
    LED5,
    LED6,
    LED7,
};

struct gpio_t 
{
    unsigned char gpio;
    char number[10];
    char direction[100];
    char gpio_path[100];
    int  fd;
};

extern struct gpio_t led_control[8];
extern struct gpio_t swtich_obtain[8];

static int gpio_config(struct gpio_t *gpio,int index,const char *attr, const char *val);
int gpio_init(struct gpio_t *gpio,int index);
int gpio_set(struct gpio_t *gpio,int index);
int gpio_reset(struct gpio_t *gpio,int index);
int gpio_read(struct gpio_t *gpio,int index);
void LED_init(void);

#endif

.c文件

#include "led.h"  

struct gpio_t led_control[8]=
{
    {LED0,"503","out",""},
    {LED1,"504","out",""},
    {LED2,"505","out",""},
    {LED3,"506","out",""},
    {LED4,"507","out",""},
    {LED5,"508","out",""},
    {LED6,"509","out",""},   
    {LED7,"510","out",""},
};

/**
  * 函数名称    static int gpio_config(struct gpio_t *gpio,int index,const char *attr, const char *val)
  * 函数功能    目标引脚功能配置
  * 输入参数    gpio: 引脚功能定义
  *            index:目标引脚名称
  *            attr:配置文件(未调用gpio_init,直接配置引脚会失败)
  *            val: 配置功能
  * 函数返回值  0:    函数执行成功
  *            -1/fd:函数执行失败
  */
static int gpio_config(struct gpio_t *gpio,int index,const char *attr, const char *val)
{
    char file_path[100];
    int len;
    int fd;
    char result[100] = "";

    sprintf(file_path, "%s/%s", gpio[index].gpio_path, attr);
    if (0 > (fd = open(file_path, O_WRONLY)))
    {
        strcat(result, gpio[index].gpio_path);
        strcat(result, " gpio config open ");
        strcat(result, "failed");
        LOG_INFO(LOG_DEBUG, "%s", result);

        return fd;
    }

    len = strlen(val);
    if (len != write(fd, val, len))
    {
        strcat(result, gpio[index].gpio_path);
        strcat(result, " gpio config write ");
        strcat(result, "failed");
        LOG_INFO(LOG_DEBUG, "%s", result);

        close(fd);
        return -1;
    }

    close(fd);  /* 关闭文件 */
    return 0;
}

/**
  * 函数名称    int gpio_init(int index)
  * 函数功能    目标引脚功能初始化(第一次初始化时,未存在配置对应引脚文件情况需要优化!(第一次使用失败,再次初始化一次))
  * 输入参数    gpio:引脚功能定义
  *            index:目标引脚名称
  * 函数返回值  0 :函数执行成功
  *            -1:函数执行失败
  */
int gpio_init(struct gpio_t *gpio,int index)
{
    /* 判断指定编号的GPIO是否导出 */
    sprintf(gpio[index].gpio_path, "/sys/class/gpio/gpio%s", gpio[index].number);
    if (access(gpio[index].gpio_path, F_OK))          /* 如果目录不存在 则需要导出 */
    {
        int fd;
        int len;
        char result[100] = "";

        if (0 > (fd = open("/sys/class/gpio/export", O_WRONLY)))
        {
            strcat(result, gpio[index].gpio_path);
            strcat(result, " gpio init open ");
            strcat(result, "failed");
            LOG_INFO(LOG_DEBUG, "%s", result);

            return -1;
        }

        len = strlen(gpio[index].number);
        if (len != write(fd, gpio[index].number, len)) /* 导出gpio文件 */
        {
            strcat(result, gpio[index].gpio_path);
            strcat(result, " gpio init write ");
            strcat(result, "failed");
            LOG_INFO(LOG_DEBUG, "%s", result);

            close(fd);
            return -1;
        }

        close(fd);                                     /* 关闭文件 */
    }
    if(strcmp(gpio[index].direction, "out")==0)
    {
        /* 配置为输出模式 */
        if (gpio_config(gpio,index,"direction", gpio[index].direction))
        return -1;

        /* 极性设置 */
        if (gpio_config(gpio,index,"active_low", "0"))
        return -1;
    }
    else if(strcmp(gpio[index].direction, "in")==0)
    {
        /* 配置为输入模式 */
        if (gpio_config(gpio,index,"direction", "in"))
            return -1;

        /* 极性设置 */
        if (gpio_config(gpio,index,"active_low", "0"))
            return -1;

        /* 配置为非中断方式 */
        if (gpio_config(gpio,index,"edge", "none"))
            return -1;
    }
    else
    {
        return -1;
    }    
    /* 退出程序 */
    return 0;
}

/**
  * 函数名称    int gpio_set(int gpio,int index)
  * 函数功能    设置目标引脚高电平
  * 输入参数    gpio:引脚功能定义
  *            index:目标引脚名称
  * 函数返回值  0 :函数执行成功
  *            -1:函数执行失败
  */
int gpio_set(struct gpio_t *gpio,int index)
{
    char result[100] = "";

    /* 控制GPIO输出高电平 */
    if (gpio_config(gpio,index,"value", "1")==0)
    {
        return 0;
    }
    else
    {
        strcat(result, gpio[index].gpio_path);
        strcat(result, " gpio set ");
        strcat(result, "failed");
        LOG_INFO(LOG_DEBUG, "%s", result);

        return -1;
    }

}

/**
  * 函数名称    int gpio_reset(int index)
  * 函数功能    设置目标引脚低电平
  * 输入参数    gpio:引脚功能定义
  *            index:目标引脚名称
  * 函数返回值  0 :函数执行成功
  *            -1:函数执行失败
  */
int gpio_reset(struct gpio_t *gpio,int index)
{
    char result[100] = "";

    /* 控制GPIO输出低电平 */
    if (gpio_config(gpio,index,"value", "0")==0)
    {
        return 0;
    }
    else
    {
        strcat(result, gpio[index].gpio_path);
        strcat(result, " gpio reset ");
        strcat(result, "failed");
        LOG_INFO(LOG_DEBUG, "%s", result);

        return -1;
    }
}

/**
  * 函数名称    int gpio_read(int index)
  * 函数功能    读取目标引脚高低电平状态
  * 输入参数    gpio:引脚功能定义
  *            index:目标引脚名称
  * 函数返回值  value:0: 低电平
  *                  1: 高电平
  *                  -1:读取电平失败
  */
int gpio_read(struct gpio_t *gpio,int index)
{
    char file_path[100];
    char val;
    int fd;
    char result[100] = "";

    /* 读取GPIO电平状态 */
    sprintf(file_path,  "/sys/class/gpio/gpio%s/%s", gpio[index].number, "value");
    if (0 > (fd = open(file_path, O_RDONLY)))
    {
        LOG_INFO(LOG_DEBUG, "%s", "open error");
        return -1;
    }

    if (0 > read(fd, &val, 1))
    {
        LOG_INFO(LOG_DEBUG, "%s", "read error");
        close(fd);
        return -1;
    }
    close(fd);
    if((unsigned char)val==0x31)
    {
        return 1;
    }
    else if((unsigned char)val==0x30)
    {
        return 0;
    }
    else
    {
        strcat(result, gpio[index].gpio_path);
        strcat(result, " gpio read ");
        strcat(result, "failed");
        LOG_INFO(LOG_DEBUG, "%s", result);

        return -1;
    }
}

/**
  * 函数名称    void LED_init(void)
  * 函数功能    led灯io初始化
  * 输入参数    无
  * 函数返回值  无
  */
void LED_init(void)
{
    int i=0;
    /* 初始化LED */
    for(i=0;i<8;i++)
    {
        gpio_init(led_control,i);
        gpio_set(led_control,i);/* 引脚拉高,led灯灭 */
    }
}





 main.c文件

/* 系统相关串口,IO功能头文件 */
#include<stdio.h>               /* 标准输入输出定义 */
#include<stdlib.h>              /* 标准函数库定义 */
#include<unistd.h>              /* Unix 标准函数定义 */
#include<sys/types.h> 
#include<sys/stat.h>   
#include<fcntl.h>               /* 文件控制定义 */
#include<termios.h>             /* PPSIX 终端控制定义 */
#include<string.h>
#include <sys/time.h>
#include <ctype.h>

#include "led.h"

int main()
{
    unsigned char i=0U;

    LED_init();

    for(i=0U;i<LED7;i++)
    {
        gpio_set(led_control,i);
    }
}

4、总结

上述方法可以控制IO,进行IO功能的写入与读取,但使用此方法控制IO写时序,会存在控制周期长,例如adc采集频率不够,建议对调用IO有时间要求的宝子们,研究一下mmap功能或者直接控制寄存器的方法去控制IO。

如果宝子们对上述代码有什么疑惑,可以评论区留言,我看到必回。如果文章反响不错,之后我也会继续写下去。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值