概述
接口说明
GPIO(General Purpose Input/Output)即通用输入输出端口,以下简称 I/O 端口。I/O 端口可提供输入、输出或中断三类功能,是嵌入式领域最常见,最基础的硬件设备。
在介绍SylixOS中的GPIO驱动如何编写前,我们先来了解下应用层是如何调用GPIO的,要先会用之后,才能更好的去开发驱动以及进行测试。对于应用层来说,GPIO就是 /dev/gpiofd
目录下的某个设备文件,通过标准文件函数就能够操作。鉴于GPIO使用的一些固有特点,以及为了简化接口,SylixOS又进一步封装标准文件函数得到三个简洁的GPIO操作函数,文件关闭依旧使用close
函数。
/*********************************************************************************************************
** 函数名称: gpiofd
** 功能描述: 打开 gpiofd 文件
** 输 入 : gpio gpio 号
** flags 打开标志 GFD_CLOEXEC / GFD_NONBLOCK
** gpio_flags gpio 属性标志
** 输 出 : gpiofd 文件描述符
*********************************************************************************************************/
int gpiofd(unsigned int gpio, int flags, int gpio_flags);
/*********************************************************************************************************
** 函数名称: gpiofd_read
** 功能描述: 读取 gpiofd 文件
** 输 入 : fd 文件描述符
** value 读取缓冲
** 输 出 : 0 : 成功 -1 : 失败
*********************************************************************************************************/
int gpiofd_read(int fd, uint8_t *value);
/*********************************************************************************************************
** 函数名称: gpiofd_write
** 功能描述: 写 gpiofd 文件
** 输 入 : fd 文件描述符
** value 写入数据
** 输 出 : 0 : 成功 -1 : 失败
*********************************************************************************************************/
int gpiofd_write(int fd, uint8_t value);
- 使用这三个操作函数需要先包含头文件
<sys/gpiofd.h>
。 - 函数
gpiofd
用于打开一个GPIO设备文件,但参数gpio
并不是文件名而是数字编号。为提高可读性GPIO数字编号可以通过宏定义来表示,另一篇博客 《SylixOS中GPIO序号宏定义》中有详细实现及说明。 - 参数
flags
与open
函数的第二个参数意义相似,即可以是O_RDONLY,O_RDWR,O_RDWR
等,但内部其实都是按照O_RDWR
参数来操作的; - 参数
gpio_flags
是与GPIO特性相关的标识,它可以是多个位标识的组合。参考下表:
位标识名称 | 解释 |
---|---|
GPIO_FLAG_DIR_OUT | 设置GPIO为输出功能 |
GPIO_FLAG_DIR_IN | 设置GPIO为输入功能 |
GPIO_FLAG_IN | 与GPIO_FLAG_DIR_IN相同 |
GPIO_FLAG_OUT_INIT_LOW | 设置GPIO为输出功能,同时初始化输出低电平 |
GPIO_FLAG_OUT_INIT_HIGH | 设置GPIO为输出功能,同时初始化输出高电平 |
GPIO_FLAG_OPEN_DRAIN | 设置GPIO输出为漏极输出模式 |
GPIO_FLAG_OPEN_SOURCE | 设置GPIO输出为源极输出模式 |
GPIO_FLAG_PULL_DEFAULT | 使用默认上拉/下拉模式 |
GPIO_FLAG_PULL_UP | 使用上拉电阻模式 |
GPIO_FLAG_PULL_DOWN | 使用下拉电阻模式 |
GPIO_FLAG_PULL_DISABLE | 禁止上拉/下拉模式 |
GPIO_FLAG_TRIG_FALL | 设置GPIO为中断功能,并且下降沿触发中断 |
GPIO_FLAG_TRIG_RISE | 设置GPIO为中断功能,并且上升沿触发中断 |
GPIO_FLAG_TRIG_LEVEL | 设置GPIO为中断功能,并且电平触发中断 |
要想使用GPIO的中断功能,首先要在打开设备时设置其 gpio_flags
参数为响应的中断模式。其次因为 GPIO 设备文件读写都是非阻塞的,还要借助 select
函数进行阻塞及超时功能。当一个具有中断功能的GPIO产生中断时,内核会唤醒所有通过调用select等待该GPIO文件描述符可读状态的线程,通知线程中断产生。当select正确返回时,线程处理相应的事务,这类似于完成了一次中断服务。
注意当使用了 GPIO_FLAG_TRIG_LEVE
标识时,我们仅能用 GPIO_FLAG_TRIG_FALL
与 GPIO_FLAG_TRIG_RISE
中的一个与其组合使用,分别表示低电平触发和高电平触发。当没有使用 GPIO_FLAG_TRIG_LEVE
时,我们可以将 GPIO_FLAG_TRIG_FALL
和GPIO_FLAG_TRIG_RISE
组合使用表示双边沿触发。
完整例程
/*********************************************************************************************************
**
** 中国软件开源组织
**
** 嵌入式实时操作系统
**
** SylixOS(TM) LW : long wing
**
** Copyright All Rights Reserved
**
**--------------文件信息--------------------------------------------------------------------------------
**
** 文 件 名: gpioExample.c
**
** 创 建 人: Hou.JinYu (侯进宇)
**
** 文件创建日期: 2017 年 12 月 13 日
**
** 描 述: gpio 例程,针对NXP i.MX-RT1050 EVK开发版。
** 因为连接板载 LED01 的引脚同时也连接了 enet 的复位脚,硬件冲突故不能使用。
** LED02 只是一个空闲的gpio(为J22.7),需要用户连接LED或万用表来检测电平变化。
*********************************************************************************************************/
#include <stdio.h>
#include <sys/select.h>
#include <sys/gpiofd.h>
#include "gpio/gpio.h"
#include "config.h"
/*********************************************************************************************************
引脚宏定义
********************************************************************************************************/
#define KEY08 GPIO_E_00 /* GPIO5--00 */
#define LED01 GPIO_A_09 /* GPIO1--09 */
#define LED02 GPIO_A_18 /* GPIO1--18 */
/*********************************************************************************************************
** 函数名称: gpioExample1
** 功能描述: gpio 轮询读取例程
** 输 入: NONE
** 输 出: ERROR_CODE
*********************************************************************************************************/
static int gpioExample1 (void)
{
int keyfd;
int ledfd;
uint8_t value;
printf("Gpio poll example. Waiting press the key SW8.n");
keyfd = gpiofd(KEY08, O_RDWR, GPIO_FLAG_IN); /* 打开 KEY 的 GPIO 文件 */
if (keyfd < 0) {
printf("open gpio %d failed!n", KEY08);
return (PX_ERROR);
}
ledfd = gpiofd(LED02, O_RDWR, GPIO_FLAG_OUT_INIT_LOW); /* 打开 LED 的 GPIO 文件 */
if (ledfd < 0) {
printf("open gpio %d failed!n", LED02);
close(keyfd);
return (PX_ERROR);
}
while (1) {
gpiofd_read(keyfd, &value); /* 读取当前按键值 */
printf("The key value = %dn", value);
gpiofd_write(ledfd, value & 0x01); /* 设置LED引脚输出 */
sleep(1);
}
close(keyfd); /* 关闭 KEY 的 GPIO 文件 */
close(ledfd); /* 关闭 LED 的 GPIO 文件 */
return (ERROR_NONE);
}
SHELL_CMD_REG("gpioExample1", gpioExample1);
/*********************************************************************************************************
** 函数名称: gpioExample2
** 功能描述: gpio 中断例程
** 输 入: NONE
** 输 出: ERROR_CODE
*********************************************************************************************************/
static int gpioExample2 (void)
{
int n = 0;
fd_set fdset;
int ret;
int keyfd;
int ledfd;
printf("Gpio interrupt example. Waiting press the key SW8.n");
keyfd = gpiofd(KEY08, O_RDWR, GPIO_FLAG_TRIG_FALL); /* 打开 KEY 的 GPIO 文件 */
if (keyfd < 0) {
printf("open gpio %d failed!n", KEY08);
return (PX_ERROR);
}
ledfd = gpiofd(LED02, O_RDWR, GPIO_FLAG_OUT_INIT_LOW); /* 打开 LED 的 GPIO 文件 */
if (ledfd < 0) {
printf("open gpio %d failed!n", LED02);
close(keyfd);
return (PX_ERROR);
}
FD_ZERO(&fdset);
while (1) {
FD_SET(keyfd, &fdset);
ret = select(keyfd + 1, &fdset, NULL, NULL, NULL); /* 调用 select 等待按键被按下 */
if (ret == 1) {
printf("The key effective, n = %dn", n++);
gpiofd_write(ledfd, n & 0x01); /* 设置LED引脚输出 */
} else if (ret < 0) {
printf("select error!n");
break;
}
}
close(keyfd); /* 关闭 KEY 的 GPIO 文件 */
close(ledfd); /* 关闭 LED 的 GPIO 文件 */
return (ERROR_NONE);
}
SHELL_CMD_REG("gpioExample2", gpioExample2);
/*********************************************************************************************************
END
*********************************************************************************************************/
实验步骤
1.输入如命令 gpioExample1
,启动查询方式的gpio例程;
2.此时控制台每秒输出一次按键值,按下按键可看到按键值会变为0。LED引脚也会按照按键状态改变而改变。
3.复位系统,输入命令 gpioExample2
,启动中断方式的gpio例程;
4.按下按键会触发下降沿中断,从而唤醒一次select函数。每按一次按键会打印出按动次数,同时LED变化一次。
最后
以上就是幽默河马为你收集整理的在应用层使用GPIO的全部内容,希望文章能够帮你解决在应用层使用GPIO所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复