简介:
应用层想要对底层硬件进行操控,通常可以通过两种方式
- /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