4. Hi3861 UART串口通信驱动实现

任务说明

本案例在鸿蒙南向设备(以Hi3861为例)上,使用GPIO中断功能实现按键触发中断并处理。目标是通过中断方式替代轮询检测,提高按键响应效率。完成本案例后,按键按下时CPU不再持续查询引脚电平,而是由硬件中断唤醒处理函数执行相应逻辑。

硬件连接

  • 按键一端接GPIO5(对应Hi3861的GPIO05),另一端接GND
  • GPIO5配置为上拉输入,按键按下时引脚电平由高变低,产生下降沿中断

实现代码


#include <stdio.h>
#include <unistd.h>
#include "ohos_init.h"
#include "cmsis_os2.h"
#include "iot_gpio.h"
#include "iot_gpio_ex.h"
#include "iot_watchdog.h"

#define KEY_GPIO 5
#define TASK_STACK_SIZE 1024
#define TASK_PRIORITY 25

static volatile int g_keyPressCount = 0;
static volatile int g_interruptTriggered = 0;

/* 按键中断处理函数 */
static void KeyGpioInterruptHandler(char *arg)
{
    (void)arg;
    g_interruptTriggered = 1;
    g_keyPressCount++;
    printf("GPIO interrupt triggered, count=%d\n", g_keyPressCount);
}

/* 业务任务:处理中断标志 */
static void *KeyProcessTask(void *args)
{
    (void)args;
    while (1) {
        if (g_interruptTriggered) {
            g_interruptTriggered = 0;
            /* 实际业务处理:此处可添加按键消抖、事件分发等逻辑 */
            printf("Key pressed, processing...\n");
        }
        usleep(10000); /* 10ms轮询标志位,非阻塞 */
    }
    return NULL;
}

/* 按键中断初始化 */
static void KeyInterruptInit(void)
{
    IoTWatchDogDisable();

    /* 初始化GPIO5为上拉输入 */
    IoTGpioInit(KEY_GPIO);
    IoTGpioSetDir(KEY_GPIO, IOT_GPIO_DIR_IN);
    IoTGpioSetPull(KEY_GPIO, IOT_GPIO_PULL_UP);

    /* 注册中断:下降沿触发 */
    IoTGpioRegisterIsrFunc(KEY_GPIO, IOT_INT_TYPE_EDGE, IOT_GPIO_EDGE_FALL_LEVEL_LOW,
                           KeyGpioInterruptHandler, NULL);

    printf("Key interrupt initialized on GPIO%d\n", KEY_GPIO);
}

/* 创建业务处理任务 */
static void KeyTaskCreate(void)
{
    osThreadAttr_t attr = {0};
    attr.name = "KeyProcessTask";
    attr.stack_size = TASK_STACK_SIZE;
    attr.priority = TASK_PRIORITY;

    if (osThreadNew((osThreadFunc_t)KeyProcessTask, NULL, &attr) == NULL) {
        printf("Failed to create key process task\n");
    }
}

/* 入口函数 */
static void KeyInterruptDemoEntry(void)
{
    KeyInterruptInit();
    KeyTaskCreate();
}

SYS_RUN(KeyInterruptDemoEntry);

代码说明

  • 中断注册:IoTGpioRegisterIsrFunc将GPIO5配置为下降沿触发中断,按键按下时硬件自动调用KeyGpioInterruptHandler。
  • 中断处理:回调函数中仅设置标志位并计数,避免在中断上下文中执行耗时操作。
  • 业务处理:独立任务KeyProcessTask轮询标志位(10ms间隔),检测到中断后执行实际业务逻辑。该设计将中断处理与业务逻辑分离,符合嵌入式实时系统规范。

编译与烧录

  1. 将上述代码保存至app/demo/src/key_interrupt_demo.c,并在BUILD.gn中添加该源文件。
  2. 在鸿蒙源码根目录执行hb build编译固件。
  3. 使用HiBurn工具将生成的Hi3861_wifiiot_app_allinone.bin烧录至开发板。

验证方法

  1. 烧录完成后,开发板串口输出Key interrupt initialized on GPIO5,表明中断初始化成功。
  2. 按下按键(GPIO5接地),串口应立即输出GPIO interrupt triggered, count=1,随后输出Key pressed, processing...。
  3. 连续多次按键,count值依次递增,每次按键均触发一次中断处理。

判定标准:每次按键均产生一次中断输出,且count计数与按键次数一致,说明中断方式按键处理功能正常。若按键无响应或计数异常,检查GPIO5接线及上拉配置是否正确。

中断触发时序

t0 t4 GPIO5 按下(低电平) 释放(高电平) 中断标志 置1 处理任务 业务处理 触发 轮询标志 下降沿中断 上升沿

上图展示了按键中断的完整时序:按键按下产生下降沿,硬件触发中断回调置标志位;业务任务轮询到标志后执行处理,按键释放后电平恢复高电平,等待下一次按下。