如果说 nRF Connect SDK Fundamentals 第一课是完成开发环境搭建与入门实操的基础,那么第二课《Reading buttons and controlling LEDs》则是真正打通SDK 与硬件交互的关键一课。本课以 GPIO(通用输入输出)外设为核心案例,从设备树(Devicetree)的硬件描述规范,到设备驱动模型的解耦设计,再到 GPIO 通用 API 的实际调用,层层拆解 nRF Connect SDK 与硬件的交互逻辑,同时通过轮询和中断两种方式实现按键读取与 LED 控制的实操练习,让开发者真正掌握嵌入式开发中最基础也最核心的硬件操作能力。
课程定位:掌握 SDK 硬件交互的核心底层逻辑
在嵌入式固件开发中,应用程序与硬件的交互是开发的核心环节,而 nRF Connect SDK 并非采用传统头文件定义硬件的方式,而是基于 Zephyr RTOS 实现了一套标准化、模块化的硬件描述与驱动调用体系。
本课作为 SDK 硬件操作的入门核心,以按键读取和 LED 控制这一经典场景为切入点,围绕设备树、设备驱动模型、GPIO 通用 API三大核心知识点展开,同时对第一课中运行的 Blinky 示例进行逐行拆解,让开发者理解代码背后的硬件交互逻辑。最终通过两个实操练习,分别掌握轮询和中断两种 GPIO 操作方式,其中中断方式更是嵌入式开发中低功耗设计的基础方法,为后续复杂外设开发和低功耗项目设计打下坚实基础。
本课的学习对象同样面向嵌入式软件工程师、固件开发人员,以及想要深入理解微控制器硬件交互的开发者,是掌握 nRF Connect SDK 开发的必备进阶内容。
核心学习目标:吃透硬件交互的全流程体系
完成本课程学习后,开发者将建立起 nRF Connect SDK 中硬件交互的完整知识体系,核心掌握以下能力:
- 理解设备树(Devicetree)的核心概念,能读懂板级(.dts)、SoC 级(.dtsi)设备树文件,知晓设备树绑定文件(.yaml)的作用与compatible属性的意义;
- 掌握 nRF Connect SDK 的设备驱动模型,理解驱动 API 与驱动实现的解耦设计,学会通过设备指针获取并使用硬件外设;
- 熟练使用 GPIO 通用 API(<zephyr/drivers/gpio.h>),能完成 GPIO 引脚的初始化、配置、读写操作,以及中断的配置与回调处理;
- 能逐行解析 Blinky 示例代码,理解 LED 闪烁的底层实现逻辑;
- 掌握轮询和中断两种方式实现按键读取与 LED 控制,理解两种方式的优劣并能根据场景选择使用;
- 建立嵌入式开发中低功耗设计的基础思维,理解中断方式对 CPU 资源和功耗的优化作用。
核心知识模块:从硬件描述到驱动调用的三层拆解
本课的核心知识围绕硬件描述 - 驱动模型 - 外设 API三层架构展开,层层递进,让开发者理解 “SDK 如何描述硬件、如何调用驱动、如何操作外设” 的完整逻辑,所有知识点均以 GPIO 外设为案例落地,做到理论与实践结合。
模块一:设备树(Devicetree)——SDK 的硬件描述语言
nRF Connect SDK 摒弃了传统在.h 文件中定义硬件的方式,采用设备树这一层次化的数据结构描述硬件,小到开发板的 LED/GPIO 引脚配置,大到 SoC 的外设内存映射地址,均由设备树统一定义,这也是 SDK 实现代码可移植性的核心基础。
- 设备树基础结构:以树状结构组织节点,包含根节点/、子节点和子子节点,节点可添加标签(唯一简写)和属性(名值对,支持字符串、字节、数字等类型),节点路径采用类 Unix 的斜杠分隔方式;
- 核心设备树文件类型
- 板级设备树(.dts):描述具体开发板的硬件细节,如 nRF52833 DK 的 LED、按键引脚映射,存放在<install_path>\zephyr\boards\nordic\对应目录;
- SoC 级设备树(.dtsi):分为基础 SoC 文件和SoC 变体文件,描述 SoC 的外设、内存地址、引脚等底层信息,i代表 Include,可被其他设备树文件引用,存放在<install_path>\zephyr\dts\arm\nordic\;
- 引脚控制设备树(-pinctrl.dtsi):描述 UART、SPI 等外设的引脚配置,包含默认、睡眠等不同状态的引脚映射;
3. 设备树绑定文件(.yaml):定义节点的compatible属性(设备兼容性标识),声明节点的必选 / 可选属性,是设备树节点与驱动匹配的依据,SDK 自带的绑定文件存放在<install_path>\zephyr\dts\bindings\;
4. 别名(Aliases):在/aliases节点中为硬件节点定义别名(如led0对应开发板第一个 LED),让应用代码无需硬编码节点名称,实现跨板级代码可移植;
5. 设备树的代码调用:通过 SDK 提供的宏从设备树中获取硬件信息,常用宏包括DT_NODELABEL()(通过节点标签获取节点标识)、DT_ALIAS()(通过别名获取节点标识)、DT_PROP()(获取节点属性值)。
关键注意点:nRF54 系列 DK 的 LED / 按键 PCB 丝印标签(如 LED0)已与设备树中的节点名称完全对齐,而前代 DK(如 nRF52833 DK)的 PCB 丝印 LED1 对应设备树中的 led0,开发时需注意区分。
模块二:设备驱动模型 ——API 与实现的解耦设计
要操作硬件外设,必须通过设备驱动实现,而 nRF Connect SDK 的设备驱动模型采用高度解耦的设计:驱动 API 与驱动底层实现相分离,应用程序只需调用通用 API,无需关注底层硬件的驱动实现,这也是 SDK 能在 nRF54/nRF53/nRF52 等系列芯片间无缝移植的核心原因。
- 核心设计优势:切换底层驱动实现无需修改应用代码,只需更换设备树配置,大幅提升代码的可维护性和可移植性;
- 设备指针的获取:应用程序通过设备指针与硬件交互,推荐使用DEVICE_DT_GET()宏(传入设备树节点标识),相比传统的device_get_binding(),该宏会在编译阶段检查设备是否存在 / 使能,避免运行时错误,且无运行时字符串比较的性能损耗;
- 设备就绪检查:获取设备指针后,必须通过device_is_ready()检查设备是否完成初始化,确保外设可正常使用;
- 外设专属 API 封装:大部分外设(如 GPIO)提供了专属的宏和函数,替代通用的DEVICE_DT_GET()和device_is_ready(),能从设备树中收集更多外设信息,减少应用代码的配置工作,如 GPIO 的GPIO_DT_SPEC_GET()和gpio_is_ready_dt()。
模块三:GPIO 通用 API—— 实操控制输入输出外设
GPIO 是嵌入式开发中最基础的外设,本课以 <zephyr/drivers/gpio.h> 为核心,讲解 GPIO 通用 API 的完整使用流程,涵盖初始化 - 配置 - 读写 - 中断全操作,是控制 LED、按键、开关等外设的基础。
- GPIO 核心数据结构:gpio_dt_spec,封装了 GPIO 外设的设备指针、引脚号、配置标志,通过GPIO_DT_SPEC_GET()宏从设备树中直接获取,无需手动解析硬件信息;
- GPIO 基本操作流程
- 初始化:通过GPIO_DT_SPEC_GET()获取gpio_dt_spec结构,调用gpio_is_ready_dt()检查设备就绪;
- 配置:通过gpio_pin_configure_dt()配置引脚为输入 / 输出,可结合标志位设置上拉 / 下拉、高 / 低有效等特性;
- 写操作:通过gpio_pin_set_dt()设置输出引脚电平,gpio_pin_toggle_dt()翻转输出引脚电平(控制 LED 核心函数);
- 读操作:支持轮询和中断两种方式,是本课实操的核心重点。
3. 两种读操作方式的优劣对比
- 轮询方式:通过gpio_pin_get_dt()持续读取输入引脚电平,实现简单,但持续占用 CPU 资源,功耗高,仅适用于简单测试场景;
- 中断方式:硬件触发中断通知 CPU 引脚状态变化,CPU 可休眠等待,功耗低、资源占用少,是嵌入式开发的推荐方式,也是低功耗设计的基础。
4. GPIO 中断配置完整步骤
- 调用gpio_pin_interrupt_configure_dt()配置中断触发条件(上升沿 / 下降沿 / 电平变化等);
- 定义中断回调函数(ISR),实现引脚状态变化后的业务逻辑(如翻转 LED);
- 定义gpio_callback类型变量,存储回调函数和引脚掩码;
- 通过gpio_init_callback()初始化回调变量,绑定回调函数和目标引脚;
- 通过gpio_add_callback()将回调函数添加到 GPIO 外设,完成中断配置。
经典案例拆解:逐行读懂 Blinky 示例的底层逻辑
- 在掌握了设备树、驱动模型和 GPIO API 后,本课对第一课中运行的 Blinky 示例进行逐行解析,让开发者理解 “LED 闪烁” 这一简单功能背后的完整硬件交互逻辑,该示例位于<install_path>\zephyr\samples\basic\blinky。
- 头文件引入:引入 <zephyr/kernel.h>(提供k_msleep()睡眠函数)和 <zephyr/drivers/gpio.h>(GPIO 通用 API);
- 设备树节点获取:通过DT_ALIAS(led0)获取 LED0 的设备树节点标识,定义为LED0_NODE,实现跨板级可移植;
- GPIO 结构初始化:通过GPIO_DT_SPEC_GET(LED0_NODE, gpios)从设备树中获取 LED 对应的gpio_dt_spec结构,封装设备指针、引脚号和配置标志;
- 设备就绪检查:调用gpio_is_ready_dt()检查 GPIO 设备是否初始化完成,未就绪则直接退出;
- GPIO 引脚配置:通过gpio_pin_configure_dt()将引脚配置为低有效输出(GPIO_OUTPUT_ACTIVE);
- 无限循环翻转电平:在while(1)循环中,通过gpio_pin_toggle_dt()翻转 LED 引脚电平,调用k_msleep()实现延时,最终形成 LED 闪烁效果。
整个 Blinky 示例的核心是通过设备树获取硬件信息,通过 GPIO 通用 API 操作硬件,无任何硬编码的硬件参数,这也是 nRF Connect SDK 代码可移植性的体现。
实操练习:两种方式实现按键控制 LED,理解低功耗设计
本课的实操环节分为两个练习,分别以轮询和中断方式实现按键按下控制 LED 翻转的功能,其中练习 1(轮询)因解析问题暂未获取具体内容,练习 2(中断)为核心实操,完整覆盖 GPIO 中断的配置与使用,也是嵌入式开发的实际常用方式。
核心实操:中断方式实现按键控制 LED
练习 2 基于中断方式实现功能,核心是完成 GPIO 中断的全配置流程,同时通过修改睡眠时间实现CPU 低功耗,具体步骤如下:
- 打开现有工程,加载课程对应的练习代码基址;
- 调用gpio_pin_interrupt_configure_dt()为按键引脚配置中断,触发条件为电平变为有效态(GPIO_INT_EDGE_TO_ACTIVE);
- 定义中断回调函数button_pressed(),函数内调用gpio_pin_toggle_dt()实现 LED 翻转;
- 定义gpio_callback类型静态变量button_cb_data,存储中断回调相关信息;
- 通过gpio_init_callback()初始化回调变量,绑定回调函数button_pressed()和按键引脚的位掩码;
- 通过gpio_add_callback()将回调函数添加到按键对应的 GPIO 外设,完成中断注册;
- 移除主循环中的轮询代码,仅保留睡眠函数,将睡眠时间从 100ms 改为 10 分钟(10*60*1000),让 CPU 进入深度休眠;
- 编译工程并烧录到开发板,按下按键即可触发中断,实现 LED 翻转。
核心原理:无按键操作时,CPU 因长时间睡眠进入空闲态,功耗极低;当按键按下时,硬件触发中断唤醒 CPU,执行回调函数翻转 LED 后,CPU 再次进入休眠,这是嵌入式低功耗开发的经典实现方式。
课后测评:检验硬件交互知识的掌握程度
与第一课一致,本课配套了专属的课后小测(quiz-2),测评内容围绕设备树的结构与使用、设备驱动模型的解耦设计、GPIO 通用 API 的操作、中断配置流程、Blinky 示例解析等核心知识点展开,通过测评可快速发现学习中的薄弱环节,及时查漏补缺,确保掌握硬件交互的核心逻辑。
本课的学习价值:搭建 SDK 硬件开发的基础框架
nRF Connect SDK Fundamentals 第二课是从 “环境搭建” 到 “实际硬件开发” 的关键转折点,本课讲解的设备树、设备驱动模型、GPIO API三大核心知识点,并非仅适用于 GPIO 外设,而是 nRF Connect SDK 操作所有外设的通用框架 —— 后续课程中讲解的 UART、I2C、SPI 等外设,均基于这一框架实现。
同时,本课引入的中断方式和低功耗思维,是嵌入式开发的核心设计理念,尤其对于 Nordic 主打的低功耗无线产品开发,更是不可或缺的基础能力。学好本课,相当于搭建起 nRF Connect SDK 硬件开发的基础框架,为后续复杂外设开发、无线协议开发、低功耗项目设计铺平道路。
从硬件描述到驱动调用,从 GPIO 基础操作到中断低功耗设计,第二课让开发者真正走进 nRF Connect SDK 的硬件开发世界,实现了从 “会跑代码” 到 “懂代码背后逻辑” 的跨越。