Linux应用编程 - sysfs方式操作GPIO

简介:

        应用层想要对底层硬件进行操控,通常可以通过两种方式                        

  • /dev/目录下的设备文件(设备节点)
  • /sys/目录下设备的属性文件

        通常情况下,简单地设备会使用 sysfs 方式操控,如 LED、GPIO 等。较复杂的设备通常会使用设备节点的方式,如 LCD、触摸屏、摄像头等。

首先,配置内核启用sysfs GPIO支持

CONFIG_GPIO_SYSFS=y

一、命令操作GPIO

以GPIO1_IO03为例,对应gpio编号为3

1、GPIO输出

$ echo 3 > /sys/class/gpio/export                          //导出编号为3的GPIO,生成gpio3
$ echo out > /sys/class/gpio/gpio3/direction         //设置输出 out:输出 in:输入
$ echo 1 > /sys/class/gpio/gpio3/value                 //输出高电平 1:高电平 0:低电平
$ echo 3 > /sys/class/gpio/unexport                     //删除导出的编号为3的GPIO

2、GPIO输入

配置输入前也要导出gpio,不再赘述

$ echo in > /sys/class/gpio/gpio3/direction           //设置输出 out:输出 in:输入

$ cat /sys/class/gpio/gpio3/value                          //查看输入电平

二、代码操作GPIO

1、设置gpio输出

/*
*****************************************************************************************
*	函 数 名: sysfs_gpio_set
*	功能说明: 设置gpio电平状态
*	形    参: u32GpioNum : gpio编号
*             u32Value   : 1:高电平,0:低电平
*	返 回 值: 0:成功,-1:失败
*****************************************************************************************
*/
s32 sysfs_gpio_set(u32 u32GpioNum, u32 u32Value)
{
    u8 u8Buf[2]     ={0,};
    u8 u8Fname[128] = {0,};
    FILE *fp        = NULL;
    
/* 1.引脚导出, 类似于:echo 3 > /sys/class/gpio/export */
    sprintf((char *)u8Fname, "/sys/class/gpio/export");    

    if (NULL == (fp = fopen((char *)u8Fname, "w"))){
        LOG_ERR("Cannot open %s.\n", u8Fname);
        return -1;
    }
    fprintf(fp, "%d", u32GpioNum);              //gpio编号写入 fp文件
    fclose(fp);
    
/* 2.设置方向,类似于:echo out > /sys/class/gpio/gpio3/direction */
    memset(u8Fname, 0x0, sizeof(u8)*128);
    sprintf(u8Fname, "/sys/class/gpio/gpio%d/direction", u32GpioNum);
    if (NULL == (fp = fopen(u8Fname, "rb+")))
    {
        LOG_ERR("Cannot open %s.\n", u8Fname);
        return -1;
    }
    fprintf(fp, "out");                         //设置方向,"out"写入 fp
    fclose(fp);
    
/* 3.设置gpio输出电平,类似于:echo 1 > /sys/class/gpio/gpio3/value */
    memset(u8Fname, 0x0, sizeof(u8)*128);
    sprintf((char *)u8Fname, "/sys/class/gpio/gpio%d/value", u32GpioNum);

    if (NULL == (fp=fopen((char *)u8Fname, "rb+"))){
        LOG_ERR("Cannot open %s.\n", u8Fname);
        return -1;
    }
    u8Buf[0] = u32Value + 0x30;                         //把数字转为ASCII码
    fwrite(u8Buf, sizeof(u8), sizeof(u8Buf)-1, fp);     //写入gpio电平,
    fclose(fp);
    
/* 4.取消导出, 类似于:echo 3 > /sys/class/gpio/unexport */
    sprintf((char *)u8Fname, "/sys/class/gpio/unexport");

    if (NULL == (fp = fopen((char *)u8Fname, "w"))){
        LOG_ERR("Cannot open %s.\n", u8Fname);
        return -1;
    }
    fprintf(fp, "%d", u32GpioNum);
    fclose(fp);

    return 0;
}

2、获取gpio输入电平状态

/*
*****************************************************************************************
*	函 数 名: sysfs_gpio_get
*	功能说明: 获取gpio电平状态
*	形    参: u32GpioNum : gpio编号
*	返 回 值: 返回1:高电平,返回0:低电平
*****************************************************************************************
*/
s32 sysfs_gpio_get(u32 u32GpioNum)
{
    u8 u8Buf[8] = {0};
    u8 u8Fname[128] = {0,};
    FILE *fp        = NULL;
    
/* 1.引脚导出, 等价于:echo 3 > /sys/class/gpio/export */
    sprintf((char *)u8Fname, "/sys/class/gpio/export");

    if (NULL == (fp = fopen((char *)u8Fname, "w"))){
        LOG_ERR("Cannot open %s.\n", u8Fname);
        return -1;
    }
    fprintf(fp, "%d", u32GpioNum);                  //gpio编号写入 fp文件
    fclose(fp);
    
/* 2.设置方向,等价于:echo in > /sys/class/gpio/gpio3/direction */
    memset(u8Fname, 0x0, sizeof(u8)*128);
    sprintf(u8Fname, "/sys/class/gpio/gpio%d/direction", u32GpioNum);
    if (NULL == (fp = fopen(u8Fname, "rb+")))
    {
        LOG_ERR("Cannot open %s.\n", u8Fname);
        return -1;
    }
    fprintf(fp, "in");                              //设置方向,"in"写入 fp
    fclose(fp);
    
/* 3.获取gpio电平,类似于:cat /sys/class/gpio/gpio3/value */
    memset(u8Fname, 0x0, sizeof(u8)*128);
    sprintf((char *)u8Fname, "/sys/class/gpio/gpio%d/value", u32GpioNum);

    if (NULL == (fp=fopen((char *)u8Fname, "rb+"))){
        LOG_ERR("Cannot open %s.\n", u8Fname);
        return -1;
    }
    fread(u8Buf, sizeof(u8), sizeof(u8), fp);       //读到 gpio电平, 字符串格式
    fclose(fp);
    
/* 4.取消导出, 等价于:echo 3 > /sys/class/gpio/unexport */
    sprintf((char *)u8Fname, "/sys/class/gpio/unexport");
    
    if (NULL == (fp = fopen((char *)u8Fname, "w"))){
        LOG_ERR("Cannot open %s.\n", u8Fname);
        return -1;
    }
    fprintf(fp, "%d", u32GpioNum);
    fclose(fp);

    return atoi((char *)u8Buf);         //返回gpio电平
}

3、应用代码测试

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include "hal.h"
#include "hal_gpio.h"

/* LED  GPIO1_IO03 gpionum = (1 - 1) * 32 + 3 = 3  */
int main(int argc, char* argv[])
{
    int i;
    u32 u32Gpio, u32Io, u32GpioNum;

    /* GPIO1_IO03 转换num */
    u32Gpio = 1;
    u32Io = 3;
    u32GpioNum = (u32Gpio - 1) * 32 + u32Io;
    
    if (argc != 2 || !strcmp(argv[1], "--help") || !strcmp(argv[1], "-h")) {
		printf("Usage: %s"
			"0 : off\n"
			"1 : on\n"
			"2 : flip\n"
			"\n", argv[0]);
		return -1;
	}

    switch((int)argv[1]) {
        case 0:
            sysfs_gpio_set(u32GpioNum, 0);
            break;

        case 1: 
            sysfs_gpio_set(u32GpioNum, 1);
            break;
        case 2:
            for (i = 0; i < 3; i++) {
                sysfs_gpio_set(u32GpioNum, 1);
                sleep(1);
                sysfs_gpio_set(u32GpioNum, 0);
                sleep(1);
            }
            break;
            
        default:
            return -1;
    }

    return 0;
}

测试结果:

$ ./gpio_test 0                        //gpio3输出低电平

$ ./gpio_test 1                        //gpio3输出高电平

$ ./gpio_test 2                        //gpio3高低电平翻转

三、命令查看GPIO状态

$ cat /sys/kernel/debug/gpio 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值