4.nRF52xx蓝牙学习(GPIOTE与外部中断)








#ifndef __EXIT_H
#define __EXIT_H#include "nrf52840.h"#define KEY_0 11
#define KEY_1 12void EXIT_KEY_Init(void);#endif /* __EXIT_H */
exit.c函数
#include "nrf52840.h"
#include "nrf_gpio.h"
#include "exit.h"
#include "led.h"void Delay(uint32_t temp)
{for(; temp!= 0; temp--);
}
void EXIT_KEY_Init(void)
{nrf_gpio_cfg_input(KEY_0,NRF_GPIO_PIN_PULLUP);//设置管脚位上拉输入nrf_gpio_cfg_input(KEY_1,NRF_GPIO_PIN_PULLUP);//设置管脚位上拉输入NVIC_EnableIRQ(GPIOTE_IRQn);//中断嵌套设置NRF_GPIOTE->CONFIG[0] = (GPIOTE_CONFIG_POLARITY_HiToLo << GPIOTE_CONFIG_POLARITY_Pos)| (11 << GPIOTE_CONFIG_PSEL_Pos) | (GPIOTE_CONFIG_MODE_Event << GPIOTE_CONFIG_MODE_Pos);//中断配置(详细说明请参看青风教程)NRF_GPIOTE->INTENSET = GPIOTE_INTENSET_IN0_Set << GPIOTE_INTENSET_IN0_Pos;// 使能中断类型:NRF_GPIOTE->CONFIG[1] = (GPIOTE_CONFIG_POLARITY_HiToLo << GPIOTE_CONFIG_POLARITY_Pos)| (12<< GPIOTE_CONFIG_PSEL_Pos) | (GPIOTE_CONFIG_MODE_Event << GPIOTE_CONFIG_MODE_Pos);//中断配置(详细说明请参看青风教程)NRF_GPIOTE->INTENSET = GPIOTE_INTENSET_IN1_Set << GPIOTE_INTENSET_IN1_Pos;// 使能中断类型:
}void GPIOTE_IRQHandler(void)
{if(nrf_gpio_pin_read(KEY_0)== 0){if ((NRF_GPIOTE->EVENTS_IN[0] == 1) && (NRF_GPIOTE->INTENSET & GPIOTE_INTENSET_IN0_Msk)){NRF_GPIOTE->EVENTS_IN[0] = 0; //中断事件清零.Delay(10000); if(nrf_gpio_pin_read(KEY_0)== 0){LED1_Toggle();//led灯翻转}}}if(nrf_gpio_pin_read(KEY_1)== 0){if ((NRF_GPIOTE->EVENTS_IN[1] == 1) && (NRF_GPIOTE->INTENSET & GPIOTE_INTENSET_IN1_Msk)){NRF_GPIOTE->EVENTS_IN[1] = 0; //中断事件清零.LED2_Toggle();//led灯翻转}}}
main.c文件:
#include "nrf52840.h"
#include "nrf_gpio.h"
#include "exit.h"
#include "led.h"int main(void)
{LED_Init();LED1_Open();/*config key*/EXIT_KEY_Init(); while(1){}
}
代码个人理解:
1.
nrf_gpio_cfg_input(KEY_0,NRF_GPIO_PIN_PULLUP);//设置管脚位上拉输入
nrf_gpio_cfg_input(KEY_1,NRF_GPIO_PIN_PULLUP);//设置管脚位上拉输入
引脚11,12设为输入模式,并且设置上拉电阻,当按键没按下时,保持高电平,当按键按下时,变成低电平,由高到低产生下降沿,再设置中断为下降沿触发。
2.
NRF_GPIOTE->CONFIG[0] = (GPIOTE_CONFIG_POLARITY_HiToLo << GPIOTE_CONFIG_POLARITY_Pos)
| (11 << GPIOTE_CONFIG_PSEL_Pos)
| (GPIOTE_CONFIG_MODE_Event << GPIOTE_CONFIG_MODE_Pos);
配置中断通道0与引脚11绑定,此代码的功能是对 GPIOTE 模块的通道 0 进行配置,也就是设置该通道的极性、选择引脚,并且指定工作模式。
(1)NRF_GPIOTE是一个结构体,是一个指向 GPIOTE 模块寄存器基地址的指针。在 nRF 系列微控制器里,所有与 GPIOTE 模块相关的寄存器都能通过这个指针来访问。其成员是GPIOTE寄存器TASKS_OUT[8],TASKS_SET[8],
#define NRF_GPIOTE ((NRF_GPIOTE_Type*) NRF_GPIOTE_BASE)
typedef struct { //!< (@ 0x40006000) GPIOTE Structure __OM uint32_t TASKS_OUT[8]; //< (@ 0x00000000) Description collection: Task for writing to pin// specified in CONFIG[n].PSEL. Action on pin// is configured in CONFIG[n].POLARITY. __IM uint32_t RESERVED[4];__OM uint32_t TASKS_SET[8]; //< (@ 0x00000030) Description collection: Task for writing to pin// specified in CONFIG[n].PSEL. Action on pin// is to set it high. __IM uint32_t RESERVED1[4];__OM uint32_t TASKS_CLR[8]; //< (@ 0x00000060) Description collection: Task for writing to pin// specified in CONFIG[n].PSEL. Action on pin// is to set it low. __IM uint32_t RESERVED2[32];__IOM uint32_t EVENTS_IN[8]; //< (@ 0x00000100) Description collection: Event generated from// pin specified in CONFIG[n].PSEL __IM uint32_t RESERVED3[23];__IOM uint32_t EVENTS_PORT; //< (@ 0x0000017C) Event generated from multiple input GPIO pins// with SENSE mechanism enabled __IM uint32_t RESERVED4[97];__IOM uint32_t INTENSET; //< (@ 0x00000304) Enable interrupt __IOM uint32_t INTENCLR; //< (@ 0x00000308) Disable interrupt __IM uint32_t RESERVED5[129];__IOM uint32_t CONFIG[8]; //< (@ 0x00000510) Description collection: Configuration for OUT[n],// SET[n], and CLR[n] tasks and IN[n] event
} NRF_GPIOTE_Type; //< Size = 1328 (0x530)
(2) NRF_GPIOTE->CONFIG[0]
CONFIG
是一个数组,其每个元素都对应着 GPIOTE 模块的一个通道。这里的 CONFIG[0]
表示配置 GPIOTE 模块的通道 0。
(3) (GPIOTE_CONFIG_POLARITY_HiToLo << GPIOTE_CONFIG_POLARITY_Pos)
GPIOTE_CONFIG_POLARITY_HiToLo
:这是一个预定义的常量,代表引脚电平从高到低变化时触发事件或者任务。GPIOTE_CONFIG_POLARITY_Pos
:这同样是一个预定义的常量,代表CONFIG
寄存器中极性配置位的起始位置。<<
是左移运算符,将GPIOTE_CONFIG_POLARITY_HiToLo
的值左移GPIOTE_CONFIG_POLARITY_Pos
位,从而把极性配置值放到CONFIG
寄存器的正确位置。
(4 )(11 << GPIOTE_CONFIG_PSEL_Pos)
11
:这个数值代表要选择的引脚编号,意味着使用第 11 号引脚。GPIOTE_CONFIG_PSEL_Pos
:这是一个预定义的常量,代表CONFIG
寄存器中引脚选择配置位的起始位置。- 左移运算符
<<
把引脚编号 11 左移GPIOTE_CONFIG_PSEL_Pos
位,进而将引脚选择值放到CONFIG
寄存器的正确位置。
(5)(GPIOTE_CONFIG_MODE_Event << GPIOTE_CONFIG_MODE_Pos)
GPIOTE_CONFIG_MODE_Event
:这是一个预定义的常量,代表 GPIOTE 通道工作在事件模式。GPIOTE_CONFIG_MODE_Pos
:这是一个预定义的常量,代表CONFIG
寄存器中工作模式配置位的起始位置。- 左移运算符
<<
把GPIOTE_CONFIG_MODE_Event
的值左移GPIOTE_CONFIG_MODE_Pos
位,将工作模式配置值放到CONFIG
寄存器的正确位置。
(6)|
运算符
|
是按位或运算符,它把上述三个经过移位操作后的值组合起来,最终赋值给 NRF_GPIOTE->CONFIG[0]
,以此完成 GPIOTE 通道 0 的配置。
(7)CONFIG[0] ,通道0,这里与引脚11绑定。
CONFIG[0]是一个32位寄存器,其内容如下 :
A:MODE字段,0-1两位,故GPIOTE_CONFIG_MODE_Pos=0;
B:PSEL字段,8-12五位,故GPIOTE_CONFIG_PSEL_Pos=8;
C:PORT字段,第13位共一位
D:POLARITY字段,16-17共两位,故GPIOTE_CONFIG_POLARITY_Pos=16;
E:OUTINIT字段,第20位共一位。
3.
NRF_GPIOTE->INTENSET = GPIOTE_INTENSET_IN0_Set << GPIOTE_INTENSET_IN0_Pos;
此代码主要用于配置 Nordic Semiconductor 的 nRF 系列微控制器中 GPIOTE(General Purpose Input Output Task and Event)模块的中断使能。具体而言,它开启了 GPIOTE 模块中输入通道 0 的中断功能。
INTENSET 是 GPIOTE 模块中的一个寄存器,其用途是设置中断使能位。当向这个寄存器的某一位写入 1 时,就会使能对应的中断;写入 0 则不会改变该位的状态。
GPIOTE_INTENSET_IN0_Set
这是一个预定义的常量,通常代表一个值为 1 的常量。它表示要使能输入通道 0 的中断。
GPIOTE_INTENSET_IN0_Pos
这也是一个预定义的常量,代表 INTENSET 寄存器中用于控制输入通道 0 中断使能的位的位置。
GPIOTE_INTENSET_IN0_Set << GPIOTE_INTENSET_IN0_Pos
这里使用了左移运算符 <<。左移操作的作用是将 GPIOTE_INTENSET_IN0_Set 的值(即 1)向左移动 GPIOTE_INTENSET_IN0_Pos 位,从而将 1 放置到 INTENSET 寄存器中对应输入通道 0 中断使能的正确位置。
赋值操作
最终,将左移操作的结果赋值给 NRF_GPIOTE->INTENSET 寄存器,这样就完成了对输入通道 0 中断使能的配置。
4.
void GPIOTE_IRQHandler(void)
{
if(nrf_gpio_pin_read(KEY_0)== 0)
{
if ((NRF_GPIOTE->EVENTS_IN[0] == 1) &&
(NRF_GPIOTE->INTENSET & GPIOTE_INTENSET_IN0_Msk))
{
NRF_GPIOTE->EVENTS_IN[0] = 0; //ÖжÏʼþÇåÁã.
Delay(10000);
if(nrf_gpio_pin_read(KEY_0)== 0)
{
LED1_Toggle();//ledµÆ·×ª
}
}
}
这段代码定义了一个名为 GPIOTE_IRQHandler 的中断处理函数,该函数用于处理 GPIOTE(General Purpose Input Output Task and Event)模块产生的中断。当检测到特定按键(KEY_0)按下,并且 GPIOTE 通道 0 产生中断事件时,会对 LED 灯(LED1)进行状态切换操作。同时,为了避免按键抖动,代码中加入了简单的消抖处理。
GPIOTE_IRQHandler 是一个中断处理函数,当 GPIOTE 模块产生中断时,硬件会自动调用这个函数。在 Nordic 的 nRF 系列微控制器中,中断处理函数的命名是固定的,用于处理特定的中断源。
nrf_gpio_pin_read 是一个用于读取 GPIO 引脚电平状态的函数。
KEY_0 是一个宏定义,代表按键所连接的 GPIO 引脚编号。
此条件判断语句用于检测按键 KEY_0 是否被按下。在很多系统中,按键按下时引脚电平为低电平(即 0)
EVENTS_IN[0] 是 GPIOTE 模块中通道 0 的事件标志位。当该位为 1 时,表示通道 0 产生了中断事件。
INTENSET 是 GPIOTE 模块的中断使能设置寄存器。
GPIOTE_INTENSET_IN0_Msk 是一个掩码,用于检查通道 0 的中断使能位是否被设置。
这个条件判断语句用于确认 GPIOTE 通道 0 确实产生了中断事件,并且该通道的中断功能是被使能的。
将 EVENTS_IN[0] 标志位清零,目的是清除已经处理过的中断事件,以便后续能正确检测新的中断事件