Input Key
该示例使用 GPIO 中断功能,检测 GPIO 的输入信号。
首先将 GPIO 配置为输入并打开中断功能。当输入信号变化触发中断,中断服务处理函数会打印输入电平信息。
环境需求
该示例支持以下开发套件:
Hardware Platforms |
Board Name |
---|---|
RTL8752H HDK |
RTL8752H EVB |
更多信息请参考 快速入门。
硬件连线
连接 P4_0 和外部输入信号。
编译和下载
该示例的工程路径如下:
Project file: board\evb\io_sample\GPIO\Input_key\mdk
Project file: board\evb\io_sample\GPIO\Input_key\gcc
请按照以下步骤操作构建并运行该示例:
打开工程文件。
按照 快速入门 中 编译 APP Image 给出的步骤构建目标文件。
编译成功后,在路径
mdk\bin
或gcc\bin
下会生成 app binapp_MP_xxx.bin
文件。按下 reset 按键,开始运行。
测试验证
控制外部输入信号从高电平变为低电平,P4_0 检测到下降沿信号触发中断,显示如下 log。
[app] app_handle_io_msg: GPIO input msg.
代码介绍
该章节分为以下几个部分:
源码路径
工程路径:
sdk\board\evb\io_sample\GPIO\Input_key
源码路径:
sdk\src\sample\io_sample\GPIO\Input_key
该工程的工程文件代码结构如下:
└── Project: input_key
└── secure_only_app
└── include
├── app_define.h
└── rom_uuid.h
├── cmsis includes CMSIS header files and startup files
├── overlay_mgr.c
├── system_rtl876x.c
└── startup_rtl876x.s
├── lib includes all binary symbol files that user application is built on
├── rtl8752h_sdk.lib
├── gap_utils.lib
└── ROM.lib
├── peripheral includes all peripheral drivers and module code used by the application
├── rtl876x_rcc.c
├── rtl876x_pinmux.c
├── rtl876x_nvic.c
└── rtl876x_gpio.c
├── profile
└── app includes the ble_peripheral user application implementation
├── main.c
├── ancs.c
├── app.c
├── app_task.c
└── io_gpio.c
初始化
当 EVB 复位启动时,调用 main()
函数,将执行以下流程:
int main(void)
{
extern uint32_t random_seed_value;
srand(random_seed_value);
board_init();
le_gap_init(APP_MAX_LINKS);
gap_lib_init();
app_le_gap_init();
app_le_profile_init();
pwr_mgr_init();
task_init();
os_sched_start();
return 0;
}
备注
le_gap_init()
,gap_lib_init()
,app_le_gap_init
,app_le_profile_init
等为 privacy 管理模块相关的初始化,参考 LE Peripheral Privacy 中的初始化流程介绍。
与外设相关的初始化流程具体如下:
在
board_init
中,执行board_gpio_init
,该函数为 PAD/PINMUX 设置,包含如下流程:配置 PAD:设置引脚、PINMUX 模式、PowerOn、内部上拉、输出失能。
配置 PINMUX:分配引脚为 GPIO 功能。
在执行
os_sched_start()
开启任务调度后,在app_main_task
主任务内,执行driver_init
对外设驱动进行初始化配置。在
driver_init
中执行driver_gpio_init
,该函数为 GPIO 外设的初始化,包含如下流程:使能 RCC 时钟。
配置 GPIO 模式为输入模式。
使能 GPIO 中断。
设置 GPIO 中断触发模式为边沿触发,设置 GPIO 中断极性为下降沿触发。
开启 GPIO Debounce 功能,配置去抖时间。
屏蔽 GPIO 外部中断,使能 GPIO 中断,清除 GPIO 中断标志位,取消屏蔽 GPIO 外部中断。
void driver_gpio_init(void) { /* Initialize GPIO peripheral */ RCC_PeriphClockCmd(APBPeriph_GPIO, APBPeriph_GPIO_CLOCK, ENABLE); GPIO_InitTypeDef GPIO_InitStruct; GPIO_StructInit(&GPIO_InitStruct); GPIO_InitStruct.GPIO_Pin = GPIO_PIN_INPUT; GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN; GPIO_InitStruct.GPIO_ITCmd = ENABLE; GPIO_InitStruct.GPIO_ITTrigger = GPIO_INT_Trigger_EDGE; GPIO_InitStruct.GPIO_ITPolarity = GPIO_INT_POLARITY_ACTIVE_LOW; GPIO_InitStruct.GPIO_ITDebounce = GPIO_INT_DEBOUNCE_ENABLE; GPIO_InitStruct.GPIO_DebounceTime = 10;/* unit:ms , can be 1~64 ms */ GPIO_Init(&GPIO_InitStruct); GPIO_MaskINTConfig(GPIO_PIN_INPUT, ENABLE); GPIO_INTConfig(GPIO_PIN_INPUT, ENABLE); GPIO_ClearINTPendingBit(GPIO_PIN_INPUT); GPIO_MaskINTConfig(GPIO_PIN_INPUT, DISABLE); NVIC_InitTypeDef NVIC_InitStruct; NVIC_InitStruct.NVIC_IRQChannel = GPIO_PIN_INPUT_IRQN; NVIC_InitStruct.NVIC_IRQChannelPriority = 3; NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStruct); }
功能实现
当 P4_0 检测到外部有下降沿信号输入时,进入中断服务处理函数
GPIO_Input_Handler
。关闭并屏蔽 GPIO 中断。退出中断函数时清除中断标志位、取消屏蔽和重新使能中断。
定义消息类型
IO_MSG_TYPE_GPIO
,发送 msg 给 task。在 msg 消息处理函数中,当检测到 GPIO 的消息时,打印 GPIO 信息。
void GPIO_Input_Handler(void) { GPIO_INTConfig(GPIO_PIN_INPUT, DISABLE); GPIO_MaskINTConfig(GPIO_PIN_INPUT, ENABLE); T_IO_MSG int_gpio_msg; int_gpio_msg.type = IO_MSG_TYPE_GPIO; int_gpio_msg.subtype = 0; if (false == app_send_msg_to_apptask(&int_gpio_msg)) { APP_PRINT_ERROR0("[io_gpio] GPIO_Input_Handler: Send int_gpio_msg failed!"); GPIO_ClearINTPendingBit(GPIO_PIN_INPUT); return; } GPIO_ClearINTPendingBit(GPIO_PIN_INPUT); GPIO_MaskINTConfig(GPIO_PIN_INPUT, DISABLE); GPIO_INTConfig(GPIO_PIN_INPUT, ENABLE); } void app_handle_io_msg(T_IO_MSG io_msg) { uint16_t msg_type = io_msg.type; switch (msg_type) { ... case IO_MSG_TYPE_GPIO: { APP_PRINT_INFO0("[app] app_handle_io_msg: GPIO input msg."); } break; ... } }
常见问题
GPIO 误触发中断
GPIO 在如下四种模式下会误触发一次中断:
PAD 设置为输入高,采用上升沿触发中断。
PAD 设置为输入高,采用双边沿触发中断。
PAD 设置为输入低,采用下降沿触发中断。
PAD 设置为输入低,采用双边沿触发中断。
为避免中断误触发,在 GPIO 中断配置时应遵循如下设置流程:
屏蔽 GPIO 中断:
GPIO_MaskINTConfig(GPIO_PIN, ENABLE)
。使能 GPIO 中断:
GPIO_INTConfig(GPIO_PIN, ENABLE)
。清除 GPIO 中断标志位:
GPIO_ClearPendingBit(GPIO_PIN)
。取消屏蔽 GPIO 中断:
GPIO_MastINTConfig(GPIO_PIN, DISABLE)
。
若需要更改 GPIO 中断配置时,应遵循如下设置流程:
屏蔽 GPIO 中断:
GPIO_MaskINTConfig(GPIO_PIN, ENABLE)
。修改 GPIO 中断配置(设置中断触发类型和极性):
GPIO_SetITTrigger(GPIO_PIN, GPIO_TriggerMode)
GPIO_SetITPolarity(GPIO_PIN, GPIO_ITPolarity)...
。清除 GPIO 中断标志位:
GPIO_ClearPendingBit(GPIO_PIN)
。取消屏蔽 GPIO 中断:
GPIO_MastINTConfig(GPIO_PIN, DISABLE)
。