4.nRF52xx蓝牙学习(GPIOTE与外部中断)
 
 
 
 
   
 
   
 
    
 
     
 
     
 
      
 
     #ifndef __EXIT_H
#define	__EXIT_H
#include "nrf52840.h"
#define KEY_0       11
#define KEY_1       12
void 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] 标志位清零,目的是清除已经处理过的中断事件,以便后续能正确检测新的中断事件
