😊 转载请全文转载,并标明文章出处
环境介绍
- 操作系统: Window10 企业版
- IDE开发环境: ARM_MDK5 (Keil5)
- SDK版本: SDK_17.0.0
- 硬件开发板: 官方开发板 PCA10040
GPIOTE (TASK/EVENT)
1. 概述介绍
GPIOTE 驱动控制 GPIO 和 GPIOTE 外设,并配置和控制输出和输入引脚。可以将输出引脚配置为手动控制或者通过 GPIOTE 任务进行控制。输入引脚可以配置在不同模式下进行控制。
2. GPIOTE 功能
nRF52832 的GPIOTE共有8个通道,每个通道否可以分配给一个引脚,分配的引脚可以配置为任务模式或时间模式。不能将某个引脚同事分配给多个GPIOTE通道,否则会导致无法预料的错误。
- GPIOTE 每个通道有Set、Clear和Out三个任务,Set和Clear任务对引脚时固定操作,Out 任务可以引脚PIN执行以下操作:
- Set (置位 输出高电平)
- Clear (清零 输出低电平 )
- Toggle (翻转)
- GPIOTE 模块遵循以下输入条件之一,GPIOTE每个通道产生事件:
- Rising edge (上升沿)
- Falling edge (下降沿)
- Any change (任意电平跳变)
3. PIN Events and Tasks (引脚事件和任务)
- GPIOTE模块有许多任务和事件,可以配置GPIOTE模块对单个任务红外事件进行操作GPIO Pin。
- 任务(Set[n]、Clr[n]、Out[n])可用于向单个引脚写入,而事件(IN[n])可有单个引脚输入处发生的变化生成。
- GPIOTE通带被配置用于操作一个任务引脚时,引脚的初始状态时可以配置的,可以通过配置CONFIG[n]寄存器中OUTINIT来设置引脚初始化状态为高电平或低电平。
- 同一个GPIOTE通道中同时触发了有冲突的任务,任务会安装优先级的顺序执行:
优先级 |
任务 |
1 |
OUT |
2 |
CLEAR |
3 |
SET |
4. Port Event (端口事件)
Port 是一个事件,可以从多个输入引脚使用GPIO检测信号的产生。P0.00~P0.31均可以触发Port事件,Port事件使用了GPIO外设的感知机制,也就是如果使用Port事件,必须操作GPIO外设,在GPIO外设中打开引脚的感知功能,注意Port事件寄存器时属于GPIOTE外设的。
Port不需要任何时钟或者其他电源相关的外设,即使外设处于空闲状态,Port事件也可以使能。当CPU和所有外设处于IDLE状态时,Port是啊金可以将CPU从WFI或WFE类型休眠中,以及CPU空闲模式下唤醒,即在系统ON模式下实现最低的功耗。
Port事件页可以作为唤醒源,将系统从System Off模式唤醒,但本质上还是使用了GPIO外设的感知机制唤醒系统。
配置Port事件时,为了防止Port事件产生虚假的中断,用户应首先禁止Port事件中断,然后再配置Port事件,之后通过清零EVENTS_PORT寄存器清除事件,最后使能Port事件中断。
5. GPIOTE 代码实现
5.1 Sdk_config.h 配置
5.1.1 Registers (寄存器版本)
如果配置寄存器版本的话,不许需要在Sdk_config.h文件中配置。
5.1.2 Library (库版本)
添加 GPIOTE 驱动文件 nrfx_gpiote.c ,SDK 路径目录:…\modules\nrfx\drivers\src\nrfx_gpiote.c
头文件引用 “nrf_drv_gpiote.h”。
添加头文件路径:
- …\modules\nrfx\drivers\include
- …\integration\nrfx\legacy
Sdk_config.h 文件配置
Text Editor 配置
- GPIOTE_ENABLED 0
- GPIOTE_CONFIG_NUM_OF_LOW_POWER_EVENTS 4
- GPIOTE_CONFIG_IRQ_PRIORITY 1
- NRFX_GPIOTE_ENABLED 1
- NRFX_GPIOTE_CONFIG_NUM_OF_LOW_POWER_EVENTS 1
- NRFX_GPIOTE_CONFIG_IRQ_PRIORITY 1
- NRFX_GPIOTE_CONFIG_LOG_ENABLED 0
- NRFX_GPIOTE_CONFIG_LOG_LEVEL 3
- NRFX_GPIOTE_CONFIG_INFO_COLOR 0
- NRFX_GPIOTE_CONFIG_DEBUG_COLOR 0
Configuration Wizard 配置
5.2 GPIOTE Registers (寄存器版本)
5.2.1 gpiote.h 配置
#ifndef GPIOTE_H__ #define GPIOTE_H__
#include <stdbool.h> #include <stdint.h> #include "nrf52.h" #include "nrf_gpio.h" #include "nrf_drv_gpiote.h" #include "app_error.h"
#define LIBRARY_VERSION
#define PCA10040_BUTTON1 13 #define PCA10040_BUTTON2 14 #define PCA10040_BUTTON3 15 #define PCA10040_BUTTON4 16
#define PCA10040_LED1 17 #define PCA10040_LED2 18 #define PCA10040_LED3 19 #define PCA10040_LED4 20
void gpiote_init(void);
#endif
|
5.2.2 gpiote.c 配置
#include "gpiote.h"
void gpiote_init(void) {
nrf_gpio_cfg_input(PCA10040_BUTTON1, NRF_GPIO_PIN_PULLUP); nrf_gpio_cfg_input(PCA10040_BUTTON2, NRF_GPIO_PIN_PULLUP); nrf_gpio_cfg_input(PCA10040_BUTTON3, NRF_GPIO_PIN_PULLUP); nrf_gpio_cfg_input(PCA10040_BUTTON4, NRF_GPIO_PIN_PULLUP);
NVIC_EnableIRQ(GPIOTE_IRQn);
NRF_GPIOTE->CONFIG[0] = (GPIOTE_CONFIG_MODE_Event << GPIOTE_CONFIG_MODE_Pos) | (PCA10040_BUTTON1 << GPIOTE_CONFIG_PSEL_Pos) |(GPIOTE_CONFIG_POLARITY_HiToLo << GPIOTE_CONFIG_POLARITY_Pos); NRF_GPIOTE->CONFIG[1] = (GPIOTE_CONFIG_MODE_Event << GPIOTE_CONFIG_MODE_Pos) | (PCA10040_BUTTON2 << GPIOTE_CONFIG_PSEL_Pos) |(GPIOTE_CONFIG_POLARITY_HiToLo << GPIOTE_CONFIG_POLARITY_Pos); NRF_GPIOTE->CONFIG[2] = (GPIOTE_CONFIG_MODE_Event << GPIOTE_CONFIG_MODE_Pos) | (PCA10040_BUTTON3 << GPIOTE_CONFIG_PSEL_Pos) |(GPIOTE_CONFIG_POLARITY_HiToLo << GPIOTE_CONFIG_POLARITY_Pos); NRF_GPIOTE->CONFIG[3] = (GPIOTE_CONFIG_MODE_Event << GPIOTE_CONFIG_MODE_Pos) | (PCA10040_BUTTON4 << GPIOTE_CONFIG_PSEL_Pos) |(GPIOTE_CONFIG_POLARITY_HiToLo << GPIOTE_CONFIG_POLARITY_Pos);
NRF_GPIOTE->INTENSET = GPIOTE_INTENSET_IN0_Set << GPIOTE_INTENSET_IN0_Pos; NRF_GPIOTE->INTENSET = GPIOTE_INTENSET_IN1_Set << GPIOTE_INTENSET_IN1_Pos; NRF_GPIOTE->INTENSET = GPIOTE_INTENSET_IN2_Set << GPIOTE_INTENSET_IN2_Pos; NRF_GPIOTE->INTENSET = GPIOTE_INTENSET_IN3_Set << GPIOTE_INTENSET_IN3_Pos;
}
void GPIOTE_IRQHandler(void) { if(nrf_gpio_pin_read(PCA10040_BUTTON1)== 0) { if ((NRF_GPIOTE->EVENTS_IN[0] == 1) && (NRF_GPIOTE->INTENSET & GPIOTE_INTENSET_IN0_Msk)) { NRF_GPIOTE->EVENTS_IN[0] = 0;
if(nrf_gpio_pin_read(PCA10040_BUTTON1)== 0) { nrf_gpio_pin_toggle(PCA10040_LED1); } } }
if(nrf_gpio_pin_read(PCA10040_BUTTON2)== 0) { if ((NRF_GPIOTE->EVENTS_IN[1] == 1) && (NRF_GPIOTE->INTENSET & GPIOTE_INTENSET_IN1_Msk)) { NRF_GPIOTE->EVENTS_IN[1] = 0;
if(nrf_gpio_pin_read(PCA10040_BUTTON2)== 0) { nrf_gpio_pin_toggle(PCA10040_LED2); } } }
if(nrf_gpio_pin_read(PCA10040_BUTTON3)== 0) { if ((NRF_GPIOTE->EVENTS_IN[2] == 1) && (NRF_GPIOTE->INTENSET & GPIOTE_INTENSET_IN2_Msk)) { NRF_GPIOTE->EVENTS_IN[2] = 0;
if(nrf_gpio_pin_read(PCA10040_BUTTON3)== 0) { nrf_gpio_pin_toggle(PCA10040_LED3); } } }
if(nrf_gpio_pin_read(PCA10040_BUTTON4)== 0) { if ((NRF_GPIOTE->EVENTS_IN[3] == 1) && (NRF_GPIOTE->INTENSET & GPIOTE_INTENSET_IN3_Msk)) { NRF_GPIOTE->EVENTS_IN[3] = 0;
if(nrf_gpio_pin_read(PCA10040_BUTTON4)== 0) { nrf_gpio_pin_toggle(PCA10040_LED4); } } } }
|
5.3 GPIOTE Library (库版本)
5.3.1 gpiote.h 配置
#ifndef GPIOTE_H__ #define GPIOTE_H__
#include <stdbool.h> #include <stdint.h> #include "nrf52.h" #include "nrf_gpio.h" #include "nrf_drv_gpiote.h" #include "app_error.h"
#define REGISTER_VERSION
#define PCA10040_BUTTON1 13 #define PCA10040_BUTTON2 14 #define PCA10040_BUTTON3 15 #define PCA10040_BUTTON4 16
#define PCA10040_LED1 17 #define PCA10040_LED2 18 #define PCA10040_LED3 19 #define PCA10040_LED4 20
void GPIOTE_IRQHandler(void); void gpiote_init(void);
#endif
|
5.3.2 gpiote.c配置
void in_gpiote_handler(nrf_drv_gpiote_pin_t pin, nrf_gpiote_polarity_t action) { switch (pin) { case PCA10040_BUTTON1: nrf_gpio_pin_toggle(PCA10040_LED1); break; case PCA10040_BUTTON2: nrf_gpio_pin_toggle(PCA10040_LED2); break; case PCA10040_BUTTON3: nrf_gpio_pin_toggle(PCA10040_LED3); break; case PCA10040_BUTTON4: nrf_gpio_pin_toggle(PCA10040_LED4); break; default: break; } }
void gpiote_init(void) { ret_code_t err_code;
err_code = nrf_drv_gpiote_init(); APP_ERROR_CHECK(err_code);
nrf_drv_gpiote_in_config_t in_config = GPIOTE_CONFIG_IN_SENSE_HITOLO(true); in_config.pull = NRF_GPIO_PIN_PULLUP;
err_code = nrf_drv_gpiote_in_init(PCA10040_BUTTON1, &in_config, in_gpiote_handler); APP_ERROR_CHECK(err_code); err_code = nrf_drv_gpiote_in_init(PCA10040_BUTTON2, &in_config, in_gpiote_handler); APP_ERROR_CHECK(err_code); err_code = nrf_drv_gpiote_in_init(PCA10040_BUTTON3, &in_config, in_gpiote_handler); APP_ERROR_CHECK(err_code); err_code = nrf_drv_gpiote_in_init(PCA10040_BUTTON4, &in_config, in_gpiote_handler); APP_ERROR_CHECK(err_code);
nrf_drv_gpiote_in_event_enable(PCA10040_BUTTON1, true); nrf_drv_gpiote_in_event_enable(PCA10040_BUTTON2, true); nrf_drv_gpiote_in_event_enable(PCA10040_BUTTON3, true); nrf_drv_gpiote_in_event_enable(PCA10040_BUTTON4, true); }
|
5.4 MAIN.C 调用实现
#include <stdbool.h> #include <stdint.h>
#include "nrf.h" #include "nordic_common.h" #include "boards.h"
#include "nrf_delay.h" #include "nrf_drv_systick.h" #include "nrf_drv_clock.h" #include "nrf_drv_timer.h"
#include "nrf_log.h" #include "nrf_log_ctrl.h" #include "nrf_log_default_backends.h"
#include "nrf_pwr_mgmt.h"
#include "led.h" #include "timer.h" #include "gpiote.h"
int main(void) { gpiote_init(); while (true) {
if (NRF_LOG_PROCESS() == false) { nrf_pwr_mgmt_run(); } } }
|