打印
[牛人杂谈]

Linux 用户态设置GPIO控制

[复制链接]
881|12
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
#!/bin/bash

echo Exporting pin $1

echo $1> /sys/class/gpio/export

echo Setting direction to out

echo out > /sys/class/gpio/gpio$1/direction

echo Setting pin low

echo 0 > /sys/class/gpio/gpio$1/value

#!/bin/bash

echo Setting pin hight

echo 1 > /sys/class/gpio/gpio$1/value

echo Unexporting pin $1

echo $1> /sys/class/gpio/unexport

最后一定要加上echo $1> /sys/class/gpio/unexport,不然再次执行#./off.sh,就会报echo write Error: Device or resource busy


使用特权

评论回复
沙发
jiekou001|  楼主 | 2020-4-12 17:27 | 只看该作者
nux内核提供了一套在用户态配置GPIO的接口,在/sys/class/gpio/目录下

可以发现其中包含有两个文件export、unexport和若干gpiochipN 类型文件夹

export
用于将指定编号的引脚导出,作为GPIO使用
unexport
用于将导出的GPIO删除掉
gpiochipN
当前芯片中包含的GPIO控制器

使用特权

评论回复
板凳
jiekou001|  楼主 | 2020-4-12 17:28 | 只看该作者
GPIO使用方法
添加设备接口GPIO167
输入:echo 167 > export

可以发现,目录下出现了gpio167,如果执行命令后没有反应,表示当前的GPIO已经用作其他的功能,例如作为IIC的引脚等
删除设备接口GPIO167
输入:echo 167 > unexport



使用特权

评论回复
地板
jiekou001|  楼主 | 2020-4-12 17:29 | 只看该作者
direction
设置输出还是输入模式
设置为输入:echo “in” > direction
设置为输出:echo “out” > direction
value
输出时,控制高低电平;输入时,获取高低电平
高电平:echo 1 > value
低电平:echo 0 > value
edge
控制中断触发模式,引脚被配置为中断后可以使用poll() 函数监听引脚
非中断引脚: echo “none” > edge
上升沿触发:echo “rising” > edge
下降沿触发:echo “falling” > edge
边沿触发:echo “both” > edge

gpiochipN目录
用来管理和控制一组gpio端口的控制器

base
和N相同,表示控制器管理的最小的端口编号。
lable
诊断使用的标志(并不总是唯一的)
ngpio
控制器管理的gpio端口数量(端口范围是:N ~ N+ngpio-1)

使用特权

评论回复
5
jiekou001|  楼主 | 2020-4-12 17:29 | 只看该作者
用户态使用gpio监听中断
比如我想监听PA7上的电平变化(也就是边沿触发),那么应该先向“/sys/class/gpio/gpio7/direction”写入“in”,然后向“/sys/class/gpio/gpio7/edge”写入“both”,然后对”/sys/class/gpio/gpio7/value”执行select/poll操作。

代码如下:

poll_test.c

#include <stdio.h>
#include <fcntl.h>
#include <poll.h>
#include <unistd.h>

int main()
{
    int fd=open("/sys/class/gpio/gpio7/value",O_RDONLY);
    if(fd<0)
    {
        perror("open '/sys/class/gpio/gpio7/value' failed!\n");  
        return -1;
    }
    struct pollfd fds[1];
    fds[0].fd=fd;
    fds[0].events=POLLPRI;
    while(1)
    {
        if(poll(fds,1,0)==-1)
        {
            perror("poll failed!\n");
            return -1;
        }
        if(fds[0].revents&POLLPRI)
        {
            if(lseek(fd,0,SEEK_SET)==-1)
            {
                perror("lseek failed!\n");
                return -1;
            }
            char buffer[16];
            int len;
            if((len=read(fd,buffer,sizeof(buffer)))==-1)
            {
                perror("read failed!\n");
                return -1;
            }
            buffer[len]=0;
            printf("%s",buffer);
        }
    }
    return 0;
}
这个小程序的作用就是就是不断poll(“/sys/class/gpio/gpio7/value”)。一旦poll()返回,就输出PA7的值。

假设代码放在~目录下,然后输入如下命令:

cd ~
gcc poll_test.c -o poll_test
echo in > /sys/class/gpio/gpio7/direction
echo both > /sys/class/gpio/gpio7/edge
./poll_test
用1K电阻把PA7上拉到VCC,然后用一根导线把PA7与GND连接又断开,会发现不断输出1和0(当PA7连上GND的瞬间输出0,与GND断开的瞬间输出1)。说明poll()确实能检测到电平变化。

使用特权

评论回复
6
jiekou001|  楼主 | 2020-4-12 17:30 | 只看该作者
通过sysfs在用户空间使用GPIO中断

通过使用sysfs,Linux GPIO可以支持在用户空间进行GPIO的控制或获取状态。这样可以使用简单的工具,比如“echo”来设置输出GPIO的电平或使用“cat”来读取输入GPIO的当前值。
1、配置内核中sysfs下的GPIO支持
       要想在用户空间访问GPIO,需要在sysfs中使能GPIO支持。
Symbol: GPIO_SYSFS [=n]
  Type  : boolean
  Prompt: /sys/class/gpio/... (sysfs interface)
  Defined at drivers/gpio/Kconfig:51
  Depends on: GPIOLIB [=y] && SYSFS [=y] && EXPERIMENTAL [=y]
  Location:
   -> Device Drivers
     -> GPIO Support (GPIOLIB [=y])
2、在用户空间是能GPIO
       即将GPIO导出到用户空间之中。
------------------------------------
GPIO = 22
cd = /sys/class/gpio
ls
echo $GPIO > export
ls
------------------------------------
       注意:开始ls时,gpio22并不存在,第二个ls时,gpio22才存在。
       设置为输入并获取当前值:
------------------------------------
cd /sys/class/gpio/gpio$GPIO
echo "in" > direction
cat value
------------------------------------
       设置为输出并设置值:
------------------------------------
cd /sys/class/gpio/gpio$GPIO
echo "out" > direction
echo 1 > value 或 echo 0 > value
------------------------------------
3、用作中断
       先将GPIO配置为输入,然后使用poll()来阻塞程序直到GPIO的输入电平发生改变,关键是使用POLLPRI而不是POLLIN来侦听事件;或者使用select()。
4、查看GPIO配置
       配置内核来使能debugfs
Symbol: DEBUG_FS [=y]
  Type  : boolean
  Prompt: Debug Filesystem
    Defined at lib/Kconfig.debug:77
    Location:
    -> Kernel hacking
       启动目标硬件并挂载debugfs
mount -t debugfs none /sys/kernel/debug
       查看引脚配置
cat /sys/kernel/debug/gpio

poll示例:
memset((void *)xfds, 0, sizeof(xfds));
xfds[0].fd = fd;
xfds[0].events = POLLPRI;
ret = poll(xfds, 1, -1);
if(ret <= 0)
ERREXIT("poll value");
if(xfds[0].revents & POLLPRI)
{
/* get value */
ret = lseek(fd, 0, SEEK_SET);
if(ret < 0)
ERREXIT("lseek value");
ret = read(fd, buf, 2);
buf[1] = '\0';
printf("read ret = %d, value = %s\n", ret, buf);
if(ret != 2)
ERREXIT("read value");
}


select示例:
FD_ZERO(&exceptfds);
FD_SET(fd, &exceptfds);
ret = select(fd+1,NULL,NULL,&exceptfds,NULL);
if(ret < 0)
ERREXIT("select value");
//else if(ret > 0)
if(ret > 0)
{
/* get value */
ret = lseek(fd, 0, SEEK_SET);
if(ret < 0)
ERREXIT("lseek value");
ret = read(fd, buf, 2);
buf[1] = '\0';
printf("read ret = %d, value = %x\n", ret, buf[0]);
if(ret != 2)
ERREXIT("read value");
}

使用特权

评论回复
7
598330983| | 2020-4-12 18:42 | 只看该作者
步骤很详细啊。

使用特权

评论回复
8
xuanhuanzi| | 2020-4-12 23:43 | 只看该作者
echo是个命令

使用特权

评论回复
9
nawu| | 2020-5-5 15:46 | 只看该作者
非常感谢楼主分享

使用特权

评论回复
10
qcliu| | 2020-5-5 15:47 | 只看该作者
这是什么语言啊

使用特权

评论回复
11
tfqi| | 2020-5-5 15:47 | 只看该作者
跑的linux的系统?

使用特权

评论回复
12
wiba| | 2020-5-5 15:48 | 只看该作者
一层的内容没看太明白

使用特权

评论回复
13
zljiu| | 2020-5-5 15:48 | 只看该作者
非常感谢楼主分享

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

134

主题

1321

帖子

2

粉丝