最近在搞MT7688 + OPENWRT,过程中需要使用一个捕获一个高脉冲已确保消息到达对方子设备,开始直接使用了一个线程一直读,读到电平变化就表示捕获到高脉冲了,但是我发现偶尔会漏掉,本着严谨的态度,我希望使用类似STM32那种外部中断事件触发.
首先我参考了这个博主的方法:
https://blog.csdn.net/qq_37596943/article/details/103750860
但是编译报错:/mnt/Windows_Share/Soft/GatewayApp_V3_2_2/src/dev_model/examples/gpio.c:42:24: fatal error: linux/init.h: No such file or directory
#include <linux/init.h>
随后我尝试解决这个问题搞了两天都没成功,只能想别的方法了,因为我刚搞linux,对Makefile不是很懂,我这又是交叉编译,哭唧唧...
我看着我的gpio.c文件深深的叹了口气, 忽然间我看到我的gpio配置都是直接对GPIO文件进行的操作,所以我想到是否有直接对gpio文件的外部中断文件进行配置呢?
说干就干,我百度谷歌一顿操作,找到了介个博主的方法:
https://blog.csdn.net/qq_31094099/article/details/88714440?spm=1001.2014.3001.5506
茅塞顿开,撸起袖子一顿复制粘贴................搞定! 不过了介个博主的代码不是很全,所以在此贴上我的完全代码:
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <poll.h>
#define FILENAME_SIZE 128
#define GPIO_PATH "/sys/class/gpio"
//导出io
int gpio_export(int pin_number)
{
char buf[FILENAME_SIZE];
int fp;
int length;
if ( gpio_is_exported(pin_number) ) { return GPIO_SUCCESS; }
//write to export file
fp = open(GPIO_PATH "/export", O_WRONLY);
if ( fp == -1)
{
return GPIO_INVALID_RESOURCE;
}
length = snprintf(buf, sizeof(buf), "%d", pin_number);
if (write(fp, buf, length * sizeof(char)) == -1)
{
close(fp);
return GPIO_INVALID_RESOURCE;
}
close(fp);
return gpio_is_exported(pin_number);
}
//开始捕获测试
int ACK_test( void )
{
int fd = -1;
//导出io
if(1 != gpio_export(25))
{
perror("Z_ACK gpio_export failed!\n");
}
//配置成输入
fd = open( "/sys/class/gpio/gpio25/direction", O_RDWR);
if ( fd == -1)
{
perror("open Z_ACK direction failed!\n");
return GPIO_INVALID_RESOURCE;
}
if ( lseek(fd, 0, SEEK_SET) < 0 )
{
close(fd);
perror("lseek Z_ACK direction failed!\n");
return GPIO_INVALID_RESOURCE;
}
if (write( fd, "in", 2 * sizeof(char)) == -1)
{
close(fd);
perror("write Z_ACK direction failed!\n");
return GPIO_ERROR_WRITE;
}
printf("Z_ACK direction ok!\n");
//边沿触发
fd = open( "/sys/class/gpio/gpio25/edge", O_RDWR);
if ( fd == -1)
{
perror("open Z_ACK edge failed!\n");
return GPIO_INVALID_RESOURCE;
}
if ( lseek(fd, 0, SEEK_SET) < 0 )
{
close(fd);
perror("lseek Z_ACK edge failed!\n");
return GPIO_INVALID_RESOURCE;
}
if (write( fd, "both", 4 * sizeof(char)) == -1)
{
close(fd);
perror("write Z_ACK edge failed!\n");
return GPIO_ERROR_WRITE;
}
printf("Z_ACK edge ok!\n");
//开始捕获
fd = open("/sys/class/gpio/gpio25/value",O_RDONLY);
if(fd<0)
{
perror("open Z_ACK failed!\n");
return -1;
}
else { perror("open Z_ACK Ok!\n"); }
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 )
{
//set_ACK(); //能进这里就代表触发事件发生了,我这里是置了一个标志
if(lseek(fd,0,SEEK_SET)==-1)
{
perror("lseek Z_ACK value failed!\n");
return -1;
}
char buffer[16];
int len;
//一定要读取,不然会一直检测到紧急事件
if(( len = read(fd,buffer,sizeof(buffer))) == -1)
{
perror("read Z_ACK value failed!\n");
return -1;
}
buffer[len]=0;
printf("%s",buffer);
}
}
return 0;
}
我这里设置/sys/class/gpio/gpio25/edge是both,因为我需要双边沿触发,这里小伙伴可以选择自己合适的:
edge: 控制中断触发模式,引脚被配置为中断后可以使用poll() 函数监听引脚
非中断引脚: echo “none” > edge
上升沿触发: echo “rising” > edge
下降沿触发: echo “falling” > edge
边沿触发 : echo “both” > edge