正点原子阿尔法监测GPIO中断触发

文章介绍了如何利用poll函数监听GPIO中断,在Linux系统下编写GPIO中断程序,包括配置GPIO为输入模式、设置中断触发方式,以及读取中断事件。程序会阻塞等待直到有中断发生,然后读取并打印中断触发时的电平状态。

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

目录

一、poll函数介绍

二、GPIO中断程序编写

三、运行可执行程序

四、作者自述


一、poll函数介绍

1. poll函数events标志       

        本实验为GPIO中断触发实验,所以需要一个机制能够检测中断的触发,中断的优先级高于主程序运行的优先级,而poll函数刚好提供了一个监听高优先级事件的标志,所以本实验采用poll函数去监听IO口有无触发中断。

2.struct pollfd结构体

struct pollfd {
int fd;
short events; 
short revents; 
};
tips: fd 是一个文件描述符,struct pollfd 结构体中的 events 和 revents 都是位掩码,调用者初始化 events 来指定需要为文件描述符 fd 做检查的事件。当 poll()函数返回时,revents 变量由 poll()函数内部进行设置,用于说明文件描述符 fd 发生了哪些事件(注意,poll()没有更改 events 量),我们可以对 revents 进行检查,判断文件描述符 fd 发生了什么事件。
3.events和revents标志

 tips:POLLIN、POLLRDNORMPOLLRDBANDPOLLPRIPOLLRDHUP与数据可读相关;POLLOUTPOLLWRNORMPOLLWRBAND与可写数据相关;POLLERR、POLLHUPPOLLNVAL)是设定在 revents 变量中用来返回有关文件描述符的附加信息,如果在 events 变量中指定了这三个标志,则会被忽略。

二、GPIO中断程序编写

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <poll.h>
#include <sys/stat.h>
#include <sys/types.h>

static char gpio_path[100];

static int gpio_config(const char *attr,const char *val)
{
    char file_path[100];
    int len,fd;

    //配置gpio电气属性
    sprintf(file_path,"%s/%s",gpio_path,attr);
    fd = open(file_path,O_WRONLY);//只写方式打开文件
    if(fd < 0)
    {
        fprintf(stderr,"打开%s文件失败!!!\n",file_path);
        return -1;
    }

    len = strlen(val);
    if(write(fd,val,len) != len)  //配置模式参数
    {
        perror("write error");
        close(fd);
        return -1;
    }

    close(fd);
    return 0;

}

int main(int argc,char *argv[])
{
    struct pollfd pfd;
    char file_path[100];
    int ret;
    char val;

    //检验命令行传入参数
    if(argc != 2)
    {
        fprintf(stderr,"usage:%s<gpio>\n",argv[0]);
        exit(-1);
    }

    //判断需要操作的GPIO是否导出
    sprintf(gpio_path,"/sys/class/gpio/gpio%s",argv[1]);
    ret = access(gpio_path,F_OK);
    if(ret != 0)  //目录不存在
    {
        int fd,len;

        fd = open("/sys/class/gpio/export",O_WRONLY);//只写方式打开文件
        if(fd < 0)
        {
            perror("open error");
            exit(-1);
        }

        len = strlen(argv[1]);
        //导出gpio
        if(write(fd,argv[1],len) != len)
        {
            fprintf(stderr,"导出gpio失败\n");
            close(fd);
            exit(-1);
        }
        close(fd); //关闭export文件
    }

    //配置为输入模式
    ret = gpio_config("direction","in");
    if(ret < 0)
    {
        fprintf(stderr,"配置输入模式出错\n");
        exit(-1);
    }

    //配置极性
    ret = gpio_config("active_low","0");
    if(ret < 0)
    {
        fprintf(stderr,"配置极性出错\n");
        exit(-1);
    }

    //配置中断出发方式,上升沿和下降沿(边沿触发)
    ret = gpio_config("edge","both");
    if(ret < 0)
    {
        fprintf(stderr,"配置触发方式出错\n");
        exit(-1);
    }

    //打开value属性文件
    sprintf(file_path,"%s/%s",gpio_path,"value");
    pfd.fd = open(file_path,O_RDONLY);
    if(pfd.fd < 0)
    {
        fprintf(stderr,"打开value属性文件出错\n");
        exit(-1);
    }

    //poll监听事件
    pfd.events = POLLPRI;//指定监听事件,只关心高优先级数据可读
    ret = read(pfd.fd,&val,1); //先读取一次清除标志
    if(ret < 0)
    {
        fprintf(stderr,"读取中断事件出错\n");
        exit(-1);
    }

    for(;;)
    {
        ret = poll(&pfd,1,-1);//阻塞监听知道有事件发生
        if(ret < 0)
        {
            fprintf(stderr,"poll error");
            exit(-1);
        }
        //返回 0 表示该调用在任意一个文件描述符成为就绪态之前就超时了。
        else if(ret == 0)
        {
            fprintf(stderr,"poll timeout\n");
            continue;//回到for循环继续执行
        }

        //检查高优先级数据是否可读
        if(pfd.revents & POLLPRI)
        {
            ret = lseek(pfd.fd,0,SEEK_SET);//将光标位置移到头部
            if(ret < 0)
            {
                perror("lseek error");
                exit(-1);
            }
            
            //往value属性文件里面读取一个数据
            ret = read(pfd.fd,&val,1);
            if(ret < 0)
            {
                perror("read error");
                exit(-1);
            }

            printf("GPIO中断触发<value=%c>\n",val);
        }
    }
    exit(0);

}

三、运行可执行程序

1.交叉编译源文件

 arm-linux-gnueabihf-gcc gpio_exti.c -o gpio_extiAPP

2.运行可执行文件

./gpio_extiAPP 1
tips:”gpio_extiAPP“为可执行文件程序名。”1“为gpio端口

 tips:本实验为GPIO边沿触发中断实验,可以将gpio1交替连接到3.3V和GND端口模拟上升沿和下降沿,查看GPIO端口电平变化状态。

四、作者自述

        记录生活。

### 正点原子 GPIO 的配置方法 正点原子开发板通常会提供详细的文档来指导开发者如何配置 GPIO。以下是关于正点原子 GPIO 配置的一些核心要点: #### 1. **GPIO 初始化** STM32 中的 GPIO 是通过寄存器进行控制的,在正点原子的教程中,初始化过程一般分为以下几个方面: - 设置端口模式(输入/输出) - 配置上下拉电阻 - 设定速度和类型 在正点原子的 HAL 库版本中,可以通过 `HAL_GPIO_Init` 函数完成初始化操作。以下是一个典型的代码示例[^1]: ```c // 定义 GPIO 结构体变量 GPIO_InitTypeDef GPIO_InitStruct = {0}; // 启用 GPIOA 时钟 __HAL_RCC_GPIOA_CLK_ENABLE(); // 配置 PA0 为推挽输出模式 GPIO_InitStruct.Pin = GPIO_PIN_0; // 选择引脚 GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;// 推挽输出模式 GPIO_InitStruct.Pull = GPIO_NOPULL; // 不带上下拉 GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; // 输出速度低 HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); // 调用初始化函数 ``` 上述代码展示了如何将 STM32 的 PA0 配置为推挽输出模式。 --- #### 2. **读取与设置 GPIO 值** 一旦完成了 GPIO 的初始化,可以使用以下两个函数分别实现对 GPIO 的读取和写入操作: - 写入:`HAL_GPIO_WritePin` - 读取:`HAL_GPIO_ReadPin` 下面是一些简单的例子: ```c // 将 PA0 设置为高电平 HAL_GPIO_WritePin(GPIOA, GPIO_PIN_0, GPIO_PIN_SET); // 将 PA0 设置为低电平 HAL_GPIO_WritePin(GPIOA, GPIO_PIN_0, GPIO_PIN_RESET); // 读取 PA0 的状态 if (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) == GPIO_PIN_SET) { // 如果 PA0 为高电平,则执行某些逻辑 } ``` --- #### 3. **中断配置** 如果需要使用外部中断功能,还需要额外配置 NVIC 和 EXTI 寄存器。正点原子提供了相应的库函数简化这一流程。以下是一个基本的例子: ```c // 启用 SYSCFG 时钟 __HAL_RCC_SYSCFG_CLK_ENABLE(); // 配置 PA0 作为上升沿触发的外部中断线 SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOA, EXTI_PinSource0); // 配置 EXTI 线路参数 EXTI_InitTypeDef EXTI_InitStruct; EXTI_InitStruct.Line = EXTI_Line0; // 外部中断线路 0 EXTI_InitStruct.Mode = EXTI_Mode_Interrupt; // 中断模式 EXTI_InitStruct.Trigger = EXTI_Trigger_Rising;// 上升沿触发 EXTI_InitStruct.LineCmd = ENABLE; // 使能该线路 EXTI_Init(&EXTI_InitStruct); // 配置 NVIC 参数 NVIC_InitTypeDef NVIC_InitStruct; NVIC_InitStruct.NVIC_IRQChannel = EXTI0_IRQn; // 中断通道 NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0x00; // 抢占优先级 NVIC_InitStruct.NVIC_IRQChannelSubPriority = 0x00; // 子优先级 NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE; // 使能中断通道 NVIC_Init(&NVIC_InitStruct); ``` 以上代码实现了对外部中断的功能支持。 --- #### 4. **注意事项** - 在实际项目中,建议仔细阅读正点原子提供的用户手册以及官方数据手册中的相关内容。 - 若遇到复杂的外设驱动需求,可能需要结合具体的硬件设计调整软件部分。 - 对于初学者来说,推荐先熟悉基础的 GPIO 功能再逐步深入到高级特性如 DMA 或定时器同步等。 ---
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值