上一篇文章讲述了如何在nRF52840芯片上,把GPIO配置为输出模式,从而驱动LED,上一篇文章的内容请参看以下链接。
物联网BLE裸机程序开发 -- (1)nRF52840配置GPIO输出驱动LED
Nordic nRF52840芯片上的GPIO管脚,除了可以配置为输出驱动模式之外,还可以配置为输入检测模式,本章节将会讲述如何把nRF52840的GPIO配置为输入检测,并在主循环函数中不断查询按键状态,检测按键的动作,并翻转对应的LED状态。
软件开发前准备:
开发板:Nordic官方开发板nRF52840-DK(PCA10056)。
编译器:SEGGER Embedded Studio v4.22
SDK版本:nRF5_SDK_15.2.0_9412b96
1、在进行软件编写之前,先查看官方开发板(PCA10056)关于按键的原理图,如下图所示。
从原理图可知,开发板上有4个按键,BUTTON1和BUTTON2有默认和可选这两种连接方式,我们选默认连接方式,四个按键分别连接在P0.11、P0.12、P0.24、P0.25这四个GPIO引脚。按键按下时,引脚会连接到GND。因此,四个GPIO引脚需要配置为上拉输入模式。
2、我们基于前面构建的“001_led_blinky”工程来进行软件开发。先复制一份工程,并重命名为“002_button_detect”,完成后打开工程,如下图所示。
3、新建一个“button_gpio.c”和“button_gpio.h”文件,并添加到工程里面,“button_gpio.h”的内容如下图所示。
#ifndef _BUTTON_GPIO_H_
#define _BUTTON_GPIO_H_
#include "nrf_gpio.h"
#include "nordic_common.h"
#define BUTTONS_NUMBER 4
#define BUTTON_1 NRF_GPIO_PIN_MAP(0,11)
#define BUTTON_2 NRF_GPIO_PIN_MAP(0,12)
#define BUTTON_3 NRF_GPIO_PIN_MAP(0,24)
#define BUTTON_4 NRF_GPIO_PIN_MAP(0,25)
#define BUTTON_PULL NRF_GPIO_PIN_PULLUP
#define BUTTONS_ACTIVE_STATE 0
#define BUTTONS_LIST { BUTTON_1, BUTTON_2, BUTTON_3, BUTTON_4 }
bool get_button_state(uint32_t button_index);
void buttons_gpio_init(void);
#endif
使用NRF_GPIO_PIN_MAP() 宏进行引脚端口和编号之间的转换,BUTTONS_ACTIVE_STATE表示按键的触发电平,BUTTONS_LIST表示按键的编号列表。
4、关于“button_gpio.c”文件的内容,如下图所示。
#include "button_gpio.h"
#include
#include
static uint8_t m_button_list[BUTTONS_NUMBER] = BUTTONS_LIST;
bool get_button_state(uint32_t button_index) {
ASSERT(button_index < BUTTONS_NUMBER);
bool pin_set = nrf_gpio_pin_read(m_button_list[button_index]) ? true : false;
return (pin_set == (BUTTONS_ACTIVE_STATE ? true : false));
}
void buttons_gpio_init(void) {
uint32_t i;
for (i = 0; i < BUTTONS_NUMBER; ++i){
nrf_gpio_cfg_input(m_button_list[i], BUTTON_PULL);
}
}
5、先来看一下buttons_gpio_init ()函数,这个函数是调用了nrf_gpio_cfg_input()函数来把按键的四个引脚配置为输出模式的,nrf_gpio_cfg_input()函数的原型,如下图所示。
__STATIC_INLINE void nrf_gpio_cfg_input(uint32_t pin_number, nrf_gpio_pin_pull_t pull_config)
{
nrf_gpio_cfg(
pin_number,
NRF_GPIO_PIN_DIR_INPUT,
NRF_GPIO_PIN_INPUT_CONNECT,
pull_config,
NRF_GPIO_PIN_S0S1,
NRF_GPIO_PIN_NOSENSE);
}
由函数原型可知,函数的参数pin_number为引脚编号0 ~ 47,pull_config表示是否配置为上下拉或无上下拉。
6、对于nrf_gpio_cfg_input()函数,实际上是调用了nrf_gpio_cfg()函数进行配置,不难发现,除了pin_number和pull_config是用户自定义之外,其他参数均采用了默认值。因此,如果使用nrf_gpio_cfg_input()函数进行引脚配置,对应的GPIO会被配置为:输入方向、连接输入缓冲区、逻辑0和逻辑1标准驱动能力、关闭引脚电平感知。对于普通的引脚输入检测,使用默认参数即可。
7、再来看看get_button_state()函数,这个函数是用来获取按键状态的。实际上,这个函数是调用了nrf_gpio_pin_read()函数来获取引脚的状态,nrf_gpio_pin_read()的函数原型如下图所示。
__STATIC_INLINE uint32_t nrf_gpio_pin_read(uint32_t pin_number)
{
NRF_GPIO_Type * reg = nrf_gpio_pin_port_decode(&pin_number);
return ((nrf_gpio_port_in_read(reg) >> pin_number) & 1UL);
}
继续跟踪nrf_gpio_port_in_read()函数,该函数是返回GPIO引脚的IN寄存器的值,函数的原型如下图所示。
__STATIC_INLINE uint32_t nrf_gpio_port_in_read(NRF_GPIO_Type const * p_reg)
{
return p_reg->IN;
}
8、完成了按键的相关操作函数编写后,再来编写main.c文件,主函数int main(void)的内容如下图所示。
#include
#include
#include "nrf_delay.h"
#include "led_gpio.h"
#include "button_gpio.h"
int main(void)
{
leds_gpio_init();
buttons_gpio_init();
while (true)
{
if(get_button_state(0)){
nrf_delay_ms(200);
if(get_button_state(0))set_led_toggle(0);
}
if(get_button_state(1)){
nrf_delay_ms(200);
if(get_button_state(1))set_led_toggle(1);
}
if(get_button_state(2)){
nrf_delay_ms(200);
if(get_button_state(2))set_led_toggle(2);
}
if(get_button_state(3)){
nrf_delay_ms(200);
if(get_button_state(3))set_led_toggle(3);
}
}
}
在主函数里面,首先调用了leds_gpio_init()和buttons_gpio_init(),进行LED和BUTTON的初始化。然后在主循环函数里面,不断检测四个按键,只要长按某一个按键,对应的LED灯就会以200ms的间隔进行闪烁。
9、连接好开发板,点击“Debug->Go”或按F5,即可编译程序并且把程序下载到开发板运行,程序的运行情况如以下视频所示。
https://www.bilibili.com/video/BV1Q541147iz/
10、源码下载链接:https://github.com/embediot/bluetooth_low_energy