24 鸿蒙LiteOS GPIO中断实战:从原理到上升沿/下降沿详解
鸿蒙LiteOS GPIO中断实战:从原理到上升沿/下降沿详解
哔站视频《【RK2206 鸿蒙LiteOS 实战 09】GPIO中断实战(上):从原理到上升沿/下降沿详解》:https://www.bilibili.com/video/BV16XLh6wEWw/?vd_source=3a9dd7a328acafb09dd1b8d05f3e2bf7
一、前言
在嵌入式、鸿蒙LiteOS开发里,几乎所有外设都离不开GPIO。
比如:
- 检测按键按下、松开
- 接收传感器的电平信号
- 外部设备触发信号
- 低功耗、高实时性的事件响应
这些场景如果用while(1)轮询方式,会大量占用CPU、实时性差、容易丢信号。
所以GPIO中断,才是工业/产品级的正确做法。
本文从什么是GPIO开始讲起,只讲中断方式,通俗易懂、源码可直接用。
问题:
最重要问题,为什么按了一下,系统就能检测到按键按下?
- 什么是 GPIO (如何和原理图对应起来)
- 为什么要用 GPIO 中断?(什么是中断,还有其他方式吗)
- 什么是上升沿、下降沿?(实际中如何体现出来)
- 什么是双边沿?
- 中断函数里不能做什么?
二、什么是 GPIO?
GPIO = General Purpose Input Output(通用输入输出口)
你可以把它理解为单片机的“手脚”:
- 输入模式:用来读外部信号(按键、传感器、电平)
- 输出模式:用来控制外部设备(LED、继电器、蜂鸣器)
一句话:
GPIO 就是单片机与外部世界通信的最基础接口。
而我们今天要讲的GPIO 中断,是 GPIO 最强大、最高效的功能。
三、什么是 GPIO 中断?为什么要用中断?
1. 什么是中断?
中断就是:
平时CPU干自己的事,一旦外部引脚电平发生变化,CPU立刻停下手中任务,去处理触发事件。
2. 为什么要用中断?(对比轮询)
- 轮询方式:while(1) 一直读引脚 →占CPU、实时性差
- 中断方式:电平变化才触发 →不占CPU、响应极快、不丢信号
所以:
按键、传感器、外部触发 → 必须用 GPIO 中断!
四、什么是上升沿、下降沿?
GPIO 中断是电平跳变触发,必须先懂这 3 个概念:
1. 上升沿 Rising Edge
低电平 → 高电平(0 变 1)的一瞬间
✅ 典型场景:
- 按键按下
- 传感器信号生效
- 外部设备开始工作
2. 下降沿 Falling Edge
高电平 → 低电平(1 变 0)的一瞬间
✅ 典型场景:
- 按键松开
- 传感器信号结束
- 外部设备断开
3. 双边沿 Both Edge
只要电平发生变化(上升 + 下降)就触发
五、一句话记忆(永不忘记)
- 上升沿 = 低变高(0→1)
- 下降沿 = 高变低(1→0)
- 沿 = 电平跳变的那一瞬间
六、鸿蒙LiteOS GPIO 中断 完整代码(可直接用)
#include<stdio.h>#include<unistd.h>#include"los_task.h"#include"ohos_init.h"#include"lz_hardware.h"#defineGPIO_TESTGPIO0_PC5/* 中断触发次数 */staticunsignedintm_gpio_interrupt_count=0;/*************************************************************** * 函数名称: gpio_isr_func * 说 明: GPIO中断服务函数 ***************************************************************/voidgpio_isr_func(void*args){m_gpio_interrupt_count++;}/*************************************************************** * 函数名称: gpio_process * 说 明: GPIO中断初始化与测试 ***************************************************************/voidgpio_process(){unsignedintret;/* 1. 初始化GPIO */LzGpioInit(GPIO_TEST);/* 2. 引脚复用配置 */PinctrlSet(GPIO_TEST,MUX_FUNC0,PULL_KEEP,DRIVE_LEVEL0);/* 3. 中断必须设置为输入模式 */LzGpioSetDir(GPIO_TEST,LZGPIO_DIR_IN);/* 4. 注册中断:上升沿触发 */ret=LzGpioRegisterIsrFunc(GPIO_TEST,LZGPIO_INT_EDGE_RISING,gpio_isr_func,NULL);if(ret!=LZ_HARDWARE_SUCCESS){printf("LzGpioRegisterIsrFunc failed(%d)\n",ret);return;}m_gpio_interrupt_count=0;/* 5. 使能中断 */LzGpioEnableIsr(GPIO_TEST);while(1){printf("***************GPIO Interrupt Example*************\n");printf("gpio interrupt count = %d\n",m_gpio_interrupt_count);printf("\n");sleep(1);}}/*************************************************************** * 函数名称: gpio_example ***************************************************************/voidgpio_example(){unsignedintthread_id;TSK_INIT_PARAM_S task={0};task.pfnTaskEntry=(TSK_ENTRY_FUNC)gpio_process;task.uwStackSize=2048;task.pcName="gpio_process";task.usTaskPrio=24;LOS_TaskCreate(&thread_id,&task);}APP_FEATURE_INIT(gpio_example);七、GPIO 中断配置 5 步标准流程
- GPIO 初始化
- 引脚复用配置
- 设置为输入模式(中断必须是输入)
- 注册中断 + 选择边沿触发
- 开启中断使能
八、中断服务函数 3 条铁律(必看)
中断函数里绝对不能:
- ❌ 不能
sleep、delay - ❌ 不能
printf - ❌ 不能写复杂逻辑、死循环
只能做:
- ✅ 变量++
- ✅ 标志位置1
- ✅ 简单标记
九、触发方式 与 实际场景对应
| 触发方式 | 宏定义 | 适用场景 |
|---|---|---|
| 上升沿 | LZGPIO_INT_EDGE_RISING | 按键按下 |
| 下降沿 | LZGPIO_INT_EDGE_FALLING | 按键松开 |
| 双边沿 | LZGPIO_INT_EDGE_BOTH | 电平变化就触发 |
十、运行效果
十一、总结
- GPIO 是单片机与外部通信的基础接口
- GPIO 中断 = 高实时、不占CPU、产品级用法
- 上升沿:0→1,下降沿:1→0
- 中断函数必须简短、快速、无阻塞
- 按键、传感器、外部信号 → 优先使用中断方式
