打开主菜单

谷雨文档中心 β

更改

NRF52832DK基础实验

添加5,170字节2019年7月2日 (二) 16:52
03_按键中断输入实验(int)
在IAR的Workspace中点开Application,双击main.c文件,打开main.c。<syntaxhighlight lang="c" line="1">
//******************************************************************************
// fn :main
//
// brief : 主程序入口
//
// param : none
//
// return : none
int main(void)
{
bsp_board_init LED_Init(BSP_INIT_LEDS|BSP_INIT_BUTTONS); //配置按键与LEDLED 初始化 BTN_Init(); //BTN 初始化
for(;;) { //循环点亮熄灭LED,间隔500ms while for(trueuint8_t i = 0; i < BUTTONS_NUMBER ; i++)
{
//轮询按键引脚电平变化 for (int i = 0; i < BUTTONS_NUMBER; i++) { if(bsp_board_button_state_getBTN_state_get(i)) { //按钮按下,点亮相应LED bsp_board_led_on LED_On(i); } else { //按键释放,熄灭LED bsp_board_led_off LED_Off(i); } } nrf_delay_ms(100); //延时100ms
}
nrf_delay_ms(100);
}
}
</syntaxhighlight>在bsp_board_init函数中,根据传入的BSP_INIT_LEDS和BSP_INIT_BUTTONS,将初始化NRF52832DK评估板LED与按键。其中LED将GPIO引脚初始化为输出,按键初始化上拉输入。此实验中只是用GPIO输入,所以只能采用轮询的方式,周期性查询按键引脚电平状态。当按键按下,bsp_board_button_state_get函数返回true,否则返回false。在LED_Init函数中调用nrf_gpio_range_cfg_output,将初始化NRF52832DK评估板LED引脚。LED将GPIO引脚初始化为输出。BTN_Init函数中调用nrf_gpio_range_cfg_input按键初始化上拉输入。此实验中只是用GPIO输入,所以只能采用轮询的方式,周期性查询按键引脚电平状态。当按键按下,BTN_state_get函数返回true,否则返回false。
为增加互动性,将用4个LED分别指示4个按键状态。按键按下点亮LED,按键释放熄灭LED。其代码实现如while中的for循环。bsp_board_led_on点亮指定LED,bsp_board_led_off熄灭LED。按键释放熄灭LED。其代码实现如while中的for循环。LED_On点亮指定LED,LED_Off熄灭LED。
==== 实验现象 ====
=== 03_按键中断输入实验(int) ===
02_按键输入实验是采用轮询方式不断查询引脚电平状态。引脚默认为高电平,当按下按键后,引脚会变成低电平。而此实验将使用nRF52832的GPIOTE边沿中断方式来监测按键动作。中断方式监测按键,带来了高灵敏性,主要原因是按键按下会产生电平抖动,为此要加入消抖。由02的原理图中可以见,没有硬件上的消抖,所以只能在驱动程序上进行消抖操作。02_按键输入实验是采用轮询方式不断查询引脚电平状态。引脚默认为高电平,当按下按键后,引脚会变成低电平。而此实验将使用nRF52832的GPIOTE边沿中断方式来监测按键动作。中断方式监测按键,带来了高灵敏度,高效率,同时也增加了按键按下不可靠性。主要原因按键按下会产生电平抖动。要求高可靠性可以为此要加入消抖。由02的原理图中可以见,没有硬件上的消抖,所以只能在驱动程序上进行消抖操作(此例程中没加入消抖)。 在例子中,使用了RF52832的GPIOTE功能,GPIOTE与GPIO使用上有所区别。但是如果一个引脚使用了GPIOTE功能,GPIO功能将不启作用,引脚上的所有操作将由GPIOTE支配,直到GPIOTE失能。 如果开发者要详细了解GPIOTE可以查看nRF52832的芯片手册《nRF52832_OPS.PDF》。《nRF52832 Objective Product Specification v0.6.3》 ==== 代码分析 ====开发者打开谷雨物联提供的peripheral_ghostyu文件夹中03_key_press_int工程(IAR工程)。 在IAR的Workspace中点开Application,双击main.c文件,打开main.c。<syntaxhighlight lang="c" line="1">//******************************************************************************// fn :main//// brief : 主程序入口//// param : none//// return : noneint main(void){ GPIOTE_Init(); LED_Init(); //LED 初始化 BTN_Init(); //BTN 初始化  for(;;) { //循环,间隔100ms nrf_delay_ms(100); }}</syntaxhighlight>在例程中使用了GPIOTE功能,所以在main函数开始处就初始化GPIOTE驱动(在使用gpiote相关函数之前,一定要先调用gpiote初始化函数nrf_drv_gpiote_init,否则可能产生不可预知问题)。接着配置LED引脚。在代码中提供两种方式,一种与02实验一至,另一种是gpiote方式。它们通过LED_GPOITE宏进行选择编译。这里主要介绍GPIOTE方式。<syntaxhighlight lang="c" line="1">//******************************************************************************// fn :LED_Init//// brief : 初始化LED引脚为输出模式,并熄灭LED//// param : none//// return : nonevoid LED_Init(void){#if defined(LED_GPIOTE) uint8_t i = 0; //配置LED引脚为输出模式 nrf_drv_gpiote_out_config_t out_config = GPIOTE_CONFIG_OUT_SIMPLE(true); //置LED引脚为高电平,即LED灭 for(i = 0 ; i < LEDS_NUMBER; i++) { nrf_drv_gpiote_out_init(Leds[i], &out_config); }#else uint8_t i = 0; //配置LED引脚为输出模式 nrf_gpio_range_cfg_output(LED_START, LED_STOP); //置LED引脚为高电平,即LED灭 for(i = 0 ; i < LEDS_NUMBER; i++) { nrf_gpio_pin_set(Leds[i]); } #endif}</syntaxhighlight>nRF52832的GPIOTE只有8个通道,所以每个通道都要进行配置。在LED引脚中,选择简单的输出配置即GPIOTE_CONFIG_OUT_SIMPLE,它是一个宏。是对nrf_drv_gpiote_out_config_t类型成员初始化结构体。其中参数表示引脚配置成GPIOTE时默认引脚状态。 nrf_drv_gpiote_out_init函数将对指定引脚进行GPIOTE_CONFIG_OUT_SIMPLE配置。<syntaxhighlight lang="c" line="1">//******************************************************************************// fn :Btn_Init//// brief : 初始化Btn引脚为输入,全边沿敏感模式//// param : none//// return : nonevoid BTN_Init(void){ //创建引脚配置结构 nrf_drv_gpiote_in_config_t btn_config = GPIOTE_CONFIG_IN_SENSE_TOGGLE(true); btn_config.pull = NRF_GPIO_PIN_PULLUP; //配置Btn引脚为边沿敏感 for(uint8_t i = 0 ; i < BUTTONS_NUMBER ; i++) { nrf_drv_gpiote_in_init(Btns[i], &btn_config, BTN_pin_handler); nrf_drv_gpiote_in_event_enable(Btns[i], true); }}</syntaxhighlight>BTN_Init函数是对按键的引脚进行TOGGLE sense输入配置。其中GPIOTE_CONFIG_IN_SENSE_TOGGLE也宏,是对nrf_drv_gpiote_in_config_t类型成员初始化结构体。参数true表示使用IN_EVENT配置,而非PORT_EVENT。由于按键外部硬件没有上拉,所以这里要配置成上拉,即pull成员变量设置成NRF_GPIO_PIN_PULLUP。 nrf_drv_gpiote_in_init函数将按键引脚配置成GPIOTE_CONFIG_IN_SENSE_TOGGLE模式,同时要传入中断回调函数。最后要调用nrf_drv_gpiote_in_event_enable函数使能引脚IN_EVENT。 中断方式采集按键,是一种异步方式,所以在回调函数中要进行逻辑上的处理。然而在这个例程中,四个按键使用同一个回调函数。所以要在回调函数中要进行按按键识别,包括按键位置识别,还有按键动作。<syntaxhighlight lang="c" line="1">//******************************************************************************// fn :BTN_pin_handler//// brief : BTN引脚边沿中断回调函数//// param : pin -> 引脚号// action -> 极性变化形为//// return : nonevoid BTN_pin_handler(nrf_drv_gpiote_pin_t pin, nrf_gpiote_polarity_t action){ bool flag = false; switch(pin) { case BUTTON_1: case BUTTON_2: case BUTTON_3: case BUTTON_4: flag = true; break; default: break; } if(flag) { uint8_t idx = BTN_Pin_To_Idx(pin); //读取pin电平状态 if(nrf_drv_gpiote_in_is_set(pin)) { LED_Off(idx); //按键释放,熄灭LED } else { LED_On(idx); //按键按下,点亮LED } }}</syntaxhighlight>其中flag是有效按键动作的标记。只有是BUTTON_1,BUTTON_2,BUTTON_3,BUTTON_4按键才是有效动作。通过nrf_drv_gpiote_in_is_set查询引脚当前电平状态,确定按键是按下,还是释放动作。并根据按键动作,点亮或熄灭LED。
119
个编辑