DragonBoard 410c手把手控制Linux的GPIO
来源:互联网 发布:组合模式 java 编辑:程序博客网 时间:2024/05/21 21:40
上一篇文章中,我们通过操作LED文件位置的brightness文件,控制了LED的亮与灭,并且在DragonBoard 410c上实现了LED的闪烁功能。 同时相信各位也对DragonBoard 410c上的硬件开发有了深入的了解。接下来我们将深入研究其他硬件,并一个一个的手把手进行操作与解释。
背景知识
无论是输出方波信号或者是处理复杂的通讯协议,我们都要直接或者间接的用到GPIO进行输出与输入。 GPIO是芯片与外界进行通讯最常用的资源之一,其重要性不言而喻。同时它也是Linux中最简单的驱动程序之一。 大部分程序都可以使用提供的接口对GPIO进行控制。
DragonBoard 410c上充满了各种形式的GPIO,如高速口或低速口,还有可以复用成通讯口的GPIO。 于是,Linux中使用0~MAX_INT之间的整数标识来明确指定需要调用的GPIO, 而且标识必须是正整数。 Linux中提供了统一的接口来操作GPIO, 再实际控制GPIO前先向各位介绍GPIO的使用方法。
需要使用的函数
首先我们可以检测GPIO端口是否可用(合法):
int gpio_is_valid(int number);
其次我们需要将GPIO端口导出到用户空间,这样我们才可以在shell中进行直接控制:
Int gpio_export(unsigned gpio, bool direction_may_change);
参数direction_may_change表示用户程序是否允许修改gpio的方向,假如可以,则参数direction_may_change为真此外,gpio_export的反函数就是gpio_unexport(), 该函数可以将GPIO结点从用户空间移除。
需要调用的文件
用户空间如何访问gpio呢:一般方法是通过sysfs接口访问gpio,也就是通过操作文件系统中的文件。下面是/sys/class/gpio目录下的三种文件,这三个目录下的文件包含了能够操作GPIO的所有接口:
- export/unexport文件
- gpioN:指代具体的gpio引脚
- gpio_chipN:指代gpio控制器
在进行操作前,开发者必须提前预知以上接口没有device文件与它们连接,接下来对每个文件进行解释:
- export/unexport文件接口:该接口只能写不能读
用户程序通过写入gpio的编号来向内核申请将某个gpio的控制权,并导出到用户空间。当然前提是没有内核代码申请这个gpio端口,比如
echo 19 > export
上述操作会为19号gpio创建一个节点gpio19,此时/sys/class/gpio目录下边生成一个gpio19的目录。/sys/class/gpio/unexport和导出的效果相反,比如:
echo 19 > unexport
上述操作将会移除gpio19这个节点。
- /sys/class/gpio/gpioN:指代某个具体的gpio端口
里边有如下属性文件:
direction 表示gpio端口的方向,读取结果是in或out。该文件也可以写,写入out 时该gpio设为输出同时电平默认为低。写入low或high则不仅可以设置为输出 还可以设置输出的电平。 当然如果内核不支持或者内核代码不愿意,将不会存在这个属性,比如内核调用了gpio_export(N,0)就表示内核不愿意修改gpio端口方向属性
value表示gpio引脚的电平,0(低电平)1(高电平),如果gpio被配置为输出,这个值是可写的,记住任何非零的值都将输出高电平, 如果某个引脚能并且已经被配置为中断,则可以调用poll(2)函数监听该中断,中断触发后poll(2)函数就会返回。
edge表示中断的触发方式,edge文件有如下四个值:”none”, “rising”, “falling”,”both”。- none表示引脚为输入,不是中断引脚
- rising表示引脚为中断输入,上升沿触发
- falling表示引脚为中断输入,下降沿触发
- both表示引脚为中断输入,边沿触发
这个文件节点只有在引脚被配置为输入引脚的时候才存在。 当值是none时可以通过如下方法将变为中断引脚:
echo "both" > edge;
对于是both,falling还是rising依赖具体硬件的中断的触发方式
DragonBoard 410c的LED控制程序编写
头文件
/*============================================================================Name : TogglyGPIO.cAuthor : ZhouJunyuVersion : 0.0.1Copyright : Your copyright noticeDescription : Basic Hardware access, Ansi-style============================================================================*/#include <stdlib.h>#include <stdio.h>#include <fcntl.h>#include <unistd.h>#include <string.h>
定义max_buf以及GPIO的标识符
#define MAX_BUF 10#define GPIO_A 36#define GPIO_B 12
定义GPIO的写函数与读函数以及导入/导出函数
int Export_GPIO(int gpio);int UnExport_GPIO(int gpio);int Write_GPIO(int gpio, int value);int Read_GPIO(int gpio, int *value);
描述主函数功能
本部分首先将指定的GPIO进行export操作,从而在用户空间对GPIO进行控制。 之后通过写函数与读函数对GPIO进行操作。
int main(void){ char c=' '; int ret; int out_value = 1; int in_value = 0; // //将制定的GPIO口export // ret = Export_GPIO(GPIO_A); if(ret != 0) printf("Error exporting GPIO_%d", GPIO_A); ret = Export_GPIO(GPIO_B); if(ret != 0) printf("Error exporting GPIO_%d", GPIO_B); // //向指定的GPIO口写值 // printf("press any key to toggle GPIO_A or 'q' to quit:\n"); while(c != 'q'){ printf("Writing GPIO_%d: value=%d \n", GPIO_A, out_value); ret = Write_GPIO(GPIO_A, out_value); if (ret != 0) printf("Error writing GPIO_%d", GPIO_A); ret = Read_GPIO(GPIO_B, (int*) &in_value); if (ret != 0) printf("Error reading GPIO_%d", GPIO_B); printf("Reading GPIO_%d: value=%d \n", GPIO_B, in_value); out_value = !out_value; c= getchar();} // //将指定的GPIO口进行unexport // ret = UnExport_GPIO(GPIO_A); if(ret != 0) printf("Error UnExporting GPIO_%d", GPIO_A); ret = UnExport_GPIO(GPIO_B); if(ret != 0) printf("Error UnExporting GPIO_%d", GPIO_B); return 0;}
export函数
该函数将GPIO注册,使得该GPIO可以在用户空间进行操作
int Export_GPIO(int gpio){ int fd; char buf[MAX_BUF]; //将指定位置的GPIO进行export //在/sys/class/gpio目录下将生成一个可用的GPIO文件 sprintf(buf, "%d", gpio); //打开export文件夹并对其进行操作 fd = open("/sys/class/gpio/export", O_WRONLY); if(fd < 0) return -1; write(fd, buf, strlen(buf)); close(fd); return 0;}
unexport函数
该函数将GPIO移除出用户空间,使程序无法调用GPIO
int UnExport_GPIO(int gpio){ int fd; char buf[MAX_BUF]; sprintf(buf, "%d", gpio); fd = open("/sys/class/gpio/unexport", O_WRONLY); if(fd < 0) return -1; write(fd, buf, strlen(buf)); close(fd); return 0;}
写GPIO值函数
本函数根据输入的GPIO口标识符以及值,修改GPIO输出的电平
int Write_GPIO(int gpio, int value){ int fd; char buf[MAX_BUF]; //将GPIO方向设置为输出 sprintf(buf, "/sys/class/gpio/gpio%d/direction", gpio); fd = open(buf, O_WRONLY); if(fd<0) return -1; write(fd, "out", 3);// Set out direction close(fd); sprintf(buf, "/sys/class/gpio/gpio%d/value", gpio); fd = open(buf, O_WRONLY); if(fd<0) return -1; // 向GPIO口写值 sprintf(buf, "%d", value); write(fd, buf, strlen(buf)); close(fd); return 0;}
读取GPIO的值函数
这个意思就不言自明了吧
int Read_GPIO(int gpio, int *value){ int fd; char val; char buf[MAX_BUF]; sprintf(buf, "/sys/class/gpio/gpio%d/value", gpio); fd = open(buf, O_RDONLY); if(fd<0) return -1; // 读取GPIO的值 read(fd, &val, 1); *value = atoi(&val); close(fd); return 0;}
总结
运行后,用户可以使用键盘控制GPIO的高低电平,按q键可以退出程序。
效果如下图所示:
GPIO的控制相比起LED可能要复杂一些,但是通过本教程,希望各位能够基本了解如何在DragonBoard 410c的嵌入式Linux下的操作。 可能有人会觉得非常复杂而且难以记住,但是由于Linux系统庞大无比,需要处理无数的硬件与软件特性,自然没有简单的STM32等单片机那么轻松自如。 不过如果学会了这些技巧,那么在以后的开发中,将会如鱼得水。
- DragonBoard 410c手把手控制Linux的GPIO
- DragonBoard 410c手把手Linux控制LED
- DragonBoard 410c手把手Linux开发
- 如何实现DragonBoard 410c GPIO控制(基于linux环境)
- 基于dragonboard 410c的kobuki机器人控制——远程控制
- 基于dragonboard 410c的kobuki机器人简单控制——驱动安装
- 基于DragonBoard 410c的遥控炮台六之控制协议优化(上)
- 基于DragonBoard 410c的遥控炮台七之控制协议优化(中)
- 基于DragonBoard 410c的遥控炮台八之控制协议优化(下)
- 基于Dragonboard 410c的总线控制之I2C(一)
- 基于Dragonboard 410c的总线控制之I2C(二)
- 基于Dragonboard 410c的总线控制之I2C(三)
- 基于Dragonboard 410c的总线控制之UART(一)
- 基于Dragonboard 410c的总线控制之UART(二)
- 基于Dragonboard 410c的总线控制之SPI(一)
- 基于Dragonboard 410c的总线控制之SPI(二)
- PC机如何利用total control控制DragonBoard 410c
- DragonBoard 410c的LittleKernel详解
- 序列化.to_sym
- 编译pycaffe问题
- TextView的setCompoundDrawables不显示问题解决
- kafka java 生产消费程序demo示例
- Mac下搭建Android开发环境
- DragonBoard 410c手把手控制Linux的GPIO
- PL SQL 修改 日期 显示格式
- zookeeper的坑(一)
- 申请iOS开发者账号遇到的一些坑
- clone
- 死锁
- 小故障
- Android知识点总结
- 关于CSS定位的理解