Linux GPIO读取高低电平

本文详细介绍了如何在Linux用户态设置GPIO控制,包括计算GPIO号、设置输出模式、读写电平及监听中断。提供了一个C程序示例,展示如何导出、设置和读取GPIO引脚状态,以及通过poll()函数监听电平变化。通过这些步骤,读者可以了解如何在用户空间直接控制GPIO引脚的高低电平。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Linux 用户态设置GPIO控制

操作GPIO0_A6作为高电平输出有效, 操作步骤:

1.计算对应的gpio number的值

通过/sys/kernel/debug/gpio查询信息:
cat /sys/kernel/debug/gpio
GPIOs 1000-1031, platform/pinctrl, gpio0:
gpio-1002 ( |3G_power ) out lo
gpio-1004 ( |bt_default_wake_host) in lo
gpio-1005 ( |power ) in hi
gpio-1009 ( |bt_default_reset ) out lo
gpio-1010 ( |reset ) out hi
gpio-1011 ( |pwd_en_3G ) out hi

GPIOs 1032-1063, platform/pinctrl, gpio1:
gpio-1033 ( |led_Test ) in lo
gpio-1034 ( |int-n ) in hi
gpio-1035 ( |vbus-5v ) out hi
gpio-1045 ( |enable ) out lo
gpio-1046 ( |vsel ) out hi
gpio-1049 ( |vsel ) out lo

GPIOs 1064-1095, platform/pinctrl, gpio2:
gpio-1076 ( |camsys_gpio ) out lo
gpio-1083 ( |bt_default_rts ) in hi
gpio-1090 ( |bt_default_wake ) in lo
gpio-1091 ( |camsys_gpio ) out lo

2. 设置该gpio为输出

cd /sys/class/gpio/   
echo 1006 > export   
cd gpio1006/ 
echo out > direction  
echo 1 > value 

参数设置

cd /sys/class/gpio/
可以发现其中包含有两个文件export、unexport和若干gpiochipN 类型文件夹
export
用于将指定编号的引脚导出,作为GPIO使用
unexport
用于将导出的GPIO删除掉
gpiochipN
当前芯片中包含的GPIO控制器

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

删除设备接口GPIO
echo 1006 > unexport

example

用户态使用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()确实能检测到电平变化。

控制GPIO引脚电平

设备的属性文件就相当于一个函数的参数接口。对于 /sys/class/gpio/gpio55/value ,每次对文件执行写入操作时,会触发驱动代码,使用这次写入的内容作为参数来修改 gpio55 的引脚电平;而每次读取操作时,则触发驱动代码将当前 gpio55 的引脚电平更新到 /sys/class/gpio/gpio55/value 文件。

1.导出gpio55到用户空间

echo 55 > /sys/class/gpio/export

2.读取 GPIO1_C7_d 引脚电平

echo 55 > /sys/class/gpio/export         
echo in > /sys/class/gpio/gpio55/direction 
cat /sys/class/gpio/gpio55/value       

3.控制 GPIO1_C7_d 引脚电平

echo out > /sys/class/gpio/gpio55/direction 
echo 1 > /sys/class/gpio/gpio55/value       
echo 0 > /sys/class/gpio/gpio55/value    

4.取消导出gpio55到用户空间

echo 55 > /sys/class/gpio/unexport

控制GPIO(C程序)

在前文中,我们演示了使用 echo 命令修改设备文件,实际上也可以使用 vi 编辑器对文件进行修改,修改时需注意用户权限。在实际的编程中,我们也可以使用C库函数或系统调用来读写设备文件,以达到控制设备的目的。请注意,为了在特定的嵌入式系统上运行程序,通常需要使用交叉编译工具来编译代码,以生成可在目标开发板上执行的可执行文件。接下来,让我们一起探讨具体的实施步骤。

3.1 完整代码

通过以下程序,可以实现 GPIO 引脚的电平控制。

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int main() {
    int gpio_pin;
    
    printf("Please enter the GPIO pin number: ");
    scanf("%d", &gpio_pin);
    
    FILE *export_file = fopen("/sys/class/gpio/export", "w");
    if (export_file == NULL) {
        perror("Failed to open GPIO export file");
        return -1;
    }
    fprintf(export_file, "%d", gpio_pin);
    fclose(export_file);

    char direction_path[50];
    snprintf(direction_path, sizeof(direction_path), "/sys/class/gpio/gpio%d/direction", gpio_pin);
    FILE *direction_file = fopen(direction_path, "w");
    if (direction_file == NULL) {
        perror("Failed to open GPIO direction file");
        return -1;
    }
    fprintf(direction_file, "out");
    fclose(direction_file);

    char value_path[50];
    char cat_command[100];
    snprintf(value_path, sizeof(value_path), "/sys/class/gpio/gpio%d/value", gpio_pin);
    snprintf(cat_command, sizeof(cat_command), "cat %s", value_path);
    FILE *value_file = fopen(value_path, "w");
    if (value_file == NULL) {
        perror("Failed to open GPIO value file");
        return -1;
    }   

    for (int i = 0; i < 3; i++) {
        fprintf(value_file, "1");
        fflush(value_file);

        system(cat_command);
        sleep(1);

        fprintf(value_file, "0");
        fflush(value_file);
        
        system(cat_command);
        sleep(1);
    }

    fclose(value_file);

    FILE *unexport_file = fopen("/sys/class/gpio/unexport", "w");
    if (unexport_file == NULL) {
        perror("Failed to open GPIO unexport file");
        return -1;
    }
    fprintf(unexport_file, "%d", gpio_pin);
    fclose(unexport_file);

    return 0;
}

reference

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

静思心远

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值