一、简介
开发板:周立功的MX2000-B-EV-Board
官网资料:MX2000
Linux提供了通过SYSFS的方式控制GPIO,刚好对应Linux下一切皆文件,通过对文件的读写操作就能实现对GPIO控制。
使用 ls /sys/class/gpio 查看该目录,如果没有需要在内核驱动中选择并编译进来Device Drivers > GPIO Support > /sys/class/gpio
从上图可以看出有两个文件export、unexport和多个gpiochipX 类型文件夹,文件作用描述和使用方法如下:
export:用于将指定编号的引脚导出,作为GPIO使用
使用export导出后的GPIO信息如下
active_low:设置value中的值是否翻转,0不翻转,1翻转
翻转 echo 1 > active_low
不翻转:echo 0 > active_low
device: 控制GPIO引脚的设备文件
direction: 设置输出还是输入模式
设置为输入:echo "in" > direction
设置为输出:echo "out" > direction
edge: 控制中断触发模式,引脚被配置为中断后可以使用poll()函数监听引脚
非中断引脚: echo "none" > edge
上升沿触发: echo "rising" > edge
下降沿触发: echo "falling" > edge
边沿触发: echo "both" > edge
power: 设备供电方面的相关信息
subsystem: 符号链接,指向父目录
uevent: 内核与udev(自动设备发现程序)之间的通信接口
value: 输出时,控制高低电平;输入时,获取高低电平
高电平:echo 1 > value
低电平:echo 0 > value
unexport:用于将导出的GPIO删除掉
gpiochipX:当前芯片中包含的GPIO控制器
base:设备所管理的GPIO初始编号
label:设备信息
ngpio:设备所管理的GPIO总数
power:设备供电方面的相关信息
subsystem:符号链接,指向父目录
uevent:内核与udev(自动设备发现程序)之间的通信接口
二、在程序中使用文件对GPIO进行操作(gpio.c gpio.h)
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/fcntl.h>
#include <unistd.h>
#include "gpio.h"
// #include "../../log/log.h"
static const char *TAG = "gpio";
#define fprintf_error(tag, fmt, arg...) do{\
sprintf(stderr,"%s: "fmt"\n", tag, ##arg);\
}while(0)
static int gpio_export(int pin)
{
char path[64] = {0};
sprintf(path, "/sys/class/gpio/gpio%d/value", pin);
if (access(path, F_OK) != GPIO_OK)
{
FILE *fp = fopen("/sys/class/gpio/export", "w");
if (fp == NULL)
{
fprintf_error(TAG, "failed to gpio export\n");
return GPIO_FAIL;
}
fprintf(fp, "%d", pin);
fclose(fp);
}
return GPIO_OK;
}
int gpio_unexport(int pin)
{
char path[64] = {0};
sprintf(path, "/sys/class/gpio/gpio%d/value", pin);
if (access(path, F_OK) == GPIO_OK)
{
FILE *fp = fopen("/sys/class/gpio/unexport", "w");
if (fp == NULL)
{
fprintf_error(TAG, "failed to gpio unexport\n");
return GPIO_FAIL;
}
fprintf(fp, "%d", pin);
fclose(fp);
}
return GPIO_OK;
}
static int gpio_direction(int pin, const char *direction)
{
char path[64] = {0};
sprintf(path, "/sys/class/gpio/gpio%d/direction", pin);
if (access(path, F_OK) != GPIO_OK)
{
FILE *fp = fopen(path, "w");
if (fp == NULL)
{
fprintf_error(TAG, "failed to gpio direction\n");
return GPIO_FAIL;
}
fprintf(fp, "%s", direction);
fclose(fp);
}
return GPIO_OK;
}
int set_gpio_bit(int pin, int level)
{
char path[64] = {0};
sprintf(path, "/sys/class/gpio/gpio%d/value", pin);
if (access(path, F_OK) == GPIO_OK)
{
FILE *fp = fopen(path, "w");
if (fp == NULL)
{
fprintf_error(TAG, "failed to set gpio bit\n");
return GPIO_FAIL;
}
fprintf(fp, "%d", level);
fclose(fp);
}
return GPIO_OK;
}
int get_gpio_bit(int pin)
{
char value = 0;
char path[64] = {0};
sprintf(path, "/sys/class/gpio/gpio%d/value", pin);
if (access(path, F_OK) == GPIO_OK)
{
FILE *fp = fopen(path, "r");
if (fp == NULL)
{
fprintf_error(TAG, "failed to get gpio bit (fopen)\n");
return GPIO_FAIL;
}
if(fread(&value, sizeof(value), 1, fp) < 0)
{
fprintf_error(TAG, "failed to get gpio bit (read)\n");
fclose(fp);
return GPIO_FAIL;
}
fclose(fp);
}
return (atoi(&value));
}
int gpio_output_config(int pin, int level)
{
int ret = GPIO_OK;
ret = gpio_export(pin);
if (ret == GPIO_FAIL)
{
return GPIO_FAIL;
}
ret = gpio_direction(pin, "out");
if (ret == GPIO_FAIL)
{
return GPIO_FAIL;
}
return set_gpio_bit(pin, level);
}
int gpio_input_config(const int pin)
{
int ret = GPIO_OK;
ret = gpio_export(pin);
if (ret == GPIO_FAIL)
{
return GPIO_FAIL;
}
ret = gpio_direction(pin, "in");
if (ret == GPIO_FAIL)
{
return GPIO_FAIL;
}
return GPIO_OK;
}
#ifndef _GPIO_H_
#define _GPIO_H_
enum gpio
{
GPIO_OK = 0,
GPIO_FAIL = -1
};
#define GPIOA_PIN(pin) (pin)
#define GPIOB_PIN(pin) (pin + 32)
#define GPIOC_PIN(pin) (pin + 64)
#define GPIOD_PIN(pin) (pin + 96)
#define GPIOE_PIN(pin) (pin + 128)
int get_gpio_bit(int pin);
int set_gpio_bit(int pin, int level);
int gpio_input_config(int pin);
int gpio_output_config(int pin, int level);
#endif