关于linux的GPIO子系统:https://blog.csdn.net/mirkerson/article/details/8464290
用法总结:
1. 通过向文件/sys/class/gpio/export 写入io号生成相应io口的节点:
echo 204 > /sys/class/gpio/export
此时/sys/class/gpio目录下边生成一个gpio204的目录
2.通过向/sys/class/gpio/gpio204/direction 写入in 或者out 设置io口为输入或者输出:
echo in > /sys/class/gpio/gpio204/direction
3.输出模式下通过向/sys/class/gpio/gpio204/value 写入0 或者 1设置io口为低电平或者高电平:
echo 1 > /sys/class/gpio/gpio204/value
4.输入模式下通过向/sys/class/gpio/gpio204/edge 写入"none", "rising", "falling","both"设置输入口的模式:
none表示引脚为输入,不是中断引脚
rising表示引脚为中断输入,上升沿触发
falling表示引脚为中断输入,下降沿触发
both表示引脚为中断输入,边沿触发
echo both > /sys/class/gpio/gpio204/edge
为了使用poll()或者select()监听io口的变化,我们需要先把io口设置为中断模式。对于是both,falling还是rising依赖具体硬件的中断的触发方式。
关键代码:
void GpioApi::run()
{
struct pollfd fds[20];
int i = 0;
foreach (int fd, mapListenIo.keys())
{
fds[i].fd = fd;
fds[i].events = POLLPRI;
i++;
}
runFlag = true;
while(runFlag)
{
int ret = poll(fds, i,-1);
if( ret == -1 )
{
printf("[GpioApi]:run: poll failed ! error message:%s\n", strerror(errno));
break;
}
for(int j=0; j<i; j++)
{
if( fds[j].revents & POLLPRI)
{
int gpio_fd = fds[j].fd;
ret = lseek(gpio_fd,0,SEEK_SET);
if( ret == -1 )
{
printf("[GpioApi]:run: lseek failed ! error message:%s\n", strerror(errno));
break;
}
char buf[2];
int ret = read(gpio_fd,buf,sizeof(buf));
if( ret == -1 )
{
printf("[GpioApi]:run: read failed ! error message:%s\n", strerror(errno));
break;
}
IO_NUM ioNum = mapListenIo.value(gpio_fd);
emit ioChanged(ioNum, buf[0]-48);
// qDebug()<<ret<<ioNum<<"ioChanged"<<buf[0];
}
}
}
}
遇到问题:使用poll监听的时候,io口电平发生了变化,但poll事件没有被触发,而使用select也不能正常触发。
解决办法:写入中断触发方式的时候,先写入一次其他触发方式,然后再写入你需要的触发方式,edge文件变化下就可以正常触发了。
封装类GpioApi使用示例:
GpioApi ioTest = new GpioApi(this);
ioTest->addOutIO(GpioApi::IO_C_0);
ioTest->addInIO(GpioApi::IO_G_11);
ioTest->addInIO(GpioApi::IO_G_10);
ioTest->addInIO(GpioApi::IO_G_12);
ioTest->setOutIO(GpioApi::IO_C_0, 1);
ioTest->start();
封装类GpioApi的完整代码下载: