- 物联网
- 嵌入式
- 操作系统
- 实时系统
【免费下载链接】RIOT
RIOT - The friendly OS for IoT
本文以 RIOT 仓库中的 examples/basic/hello-world 官方示例为主体,系统讲解 RIOT 应用工程的目录结构、
main.c入口程序,以及 RIOT 独特 Makefile 构建系统的核心变量(APPLICATION、BOARD、RIOTBASE、DEVELHELP、QUIET等)的语义与底层实现,最终引导读者在 native 模拟平台与真实硬件板卡上完成编译、烧录与运行,为后续开发任意 RIOT 应用打下坚实基础。
一、示例概览:RIOT 应用的最小形态
hello-world是 RIOT 官方示例集中最基础的一个应用,位于仓库的 examples/basic/hello-world/ 目录。它的全部内容只有三个文件:
examples/basic/hello-world/ ├── Makefile # 应用构建配置(RIOT 构建系统的入口) ├── README.md # 官方说明文档 └── main.c # 应用入口源码其作用正如 README 所述:在嵌入式应用中打印那句经典的Hello World!。这个示例的首要目的并不是演示 C 语言本身,而是让你完整走一遍 RIOT 应用的组织流程——应用如何命名、如何选择板卡、如何定位 RIOT 源码根目录、如何接入 RIOT 的 Makefile 构建系统。
在 RIOT 的 examples/basic 目录下,还并列着blinky、default、filesystem、ipc_pingpong、saul、timer_periodic_wakeup等示例,它们与hello-world遵循完全相同的工程组织规范,因此掌握本示例就等于掌握了 RIOT 所有示例乃至自研应用的工程骨架。
二、入口源码 main.c:标准 C 与 RIOT 专属宏
main.c的完整内容如下(见 examples/basic/hello-world/main.c):
#include <stdio.h> int main(void) { puts("Hello World!"); printf("You are running RIOT on a(n) %s board.\n", RIOT_BOARD); printf("This board features a(n) %s CPU.\n", RIOT_CPU); return 0; }这段代码看起来与任何 C 语言的入门示例无异,但其中暗含了 RIOT 的两个核心机制:
main()是应用唯一入口:RIOT 与裸机程序一样,应用从main()开始执行。RIOT 内核在启动时会完成硬件初始化、调度器与线程系统的建立,然后调用应用的main()进入用户逻辑。RIOT_BOARD与RIOT_CPU是编译期宏:它们并非 C 语言内置符号,而是 RIOT 构建系统在编译时通过预处理器注入的字符串宏。在 Makefile.include 中可以看到它们的定义方式:
BOARDDEF = $(call uppercase_and_underscore,$(BOARD)) CPUDEF = $(call uppercase_and_underscore,$(CPU)) CFLAGS += -DRIOT_APPLICATION=\"$(APPLICATION)\" CFLAGS += -DBOARD_$(BOARDDEF)=\"$(BOARD)\" -DRIOT_BOARD=BOARD_$(BOARDDEF) CFLAGS += -DCPU_$(CPUDEF)=\"$(CPU)\" -DRIOT_CPU=CPU_$(CPUDEF)也就是说,当你以BOARD=native64构建时,编译器会自动获得-DBOARD_NATIVE64="native64" -DRIOT_BOARD=BOARD_NATIVE64以及对应的RIOT_CPU定义。因此无论在哪块板卡上编译,printf输出的都是当前构建目标的真实板卡名与 CPU 名——这正是同一份源码可以跨板卡运行的直接体现。
三、Makefile 核心变量详解:RIOT 构建系统的五个关键点
hello-world的 Makefile 全文如下:
# name of your application APPLICATION = hello-world # If no BOARD is found in the environment, use this default: BOARD ?= native # This has to be the absolute path to the RIOT base directory: RIOTBASE ?= $(CURDIR)/../../.. # Comment this out to disable code in RIOT that does safety checking # which is not needed in a production environment but helps in the # development process: DEVELHELP ?= 1 # Change this to 0 show compiler invocation lines by default: QUIET ?= 1 include $(RIOTBASE)/Makefile.includeREADME 中强调的五个要点,逐一对应如下:
1.APPLICATION:应用名称
应用必须有一个名字,惯例是与所在目录同名(这里是hello-world)。构建系统会以它为前缀生成可执行文件:默认输出为bin/$(BOARD)/$(APPLICATION).elf(ELF 规则见 Makefile.include)。此外,APPLICATION还会被注入为-DRIOT_APPLICATION=\"$(APPLICATION)\"宏,并作为应用模块application_$(APPLICATION)的名称参与链接(见 Makefile.include)。
2.BOARD:目标板卡
BOARD ?= native声明了默认板卡,其中?=表示仅当环境中未定义BOARD时才生效。因此你可以随时用命令行覆盖默认值:
make BOARD=msba2 # README 中的经典示例 make BOARD=nrf52840dk # 切换到 nRF52840DK make BOARD=samr21-xpro # 切换到 SAM R21 Xplained Pro这一机制正是 RIOT "一次编写、处处编译" 的基石——同一份main.c与 Makefile,只需要更换BOARD变量即可面向不同硬件构建。
3.RIOTBASE:RIOT 根目录
RIOTBASE保存 RIOT 源码检出目录的绝对或相对路径。当应用位于 RIOT 仓库内部时,通常用$(CURDIR)(GNU Make 内置的当前目录变量)拼出相对路径:本示例位于仓库根目录下三级,因此是$(CURDIR)/../../..。
值得一提的是,若你在 RIOT 仓库之外开发应用,可以不写这一行——因为 Makefile.include 会兜底:
RIOTBASE ?= $(_riotbase)其中_riotbase基于LAST_MAKEFILEDIR(最后包含的 Makefile 所在目录,即Makefile.include自身所在目录)求值,从而自动推导出 RIOT 根目录。显式设置RIOTBASE则适用于把应用放在仓库内的场景。
4.DEVELHELP:开发期安全检查
DEVELHELP ?= 1开启 RIOT 的开发期辅助代码(断言、内存越界检测等安全检查)。这类检查在生产环境中不需要,但在开发阶段非常有价值。其底层实现在 Makefile.include:
DEVELHELP ?= 0 ifeq ($(DEVELHELP),1) CFLAGS += -DDEVELHELP endif即当DEVELHELP=1时,向所有源文件注入-DDEVELHELP宏,RIOT 内核与模块据此启用额外的安全检查逻辑。发布正式产品前,可将其注释掉或置 0 以缩减代码体积。
5.QUIET:编译输出详略开关
QUIET取值为1或0:1隐藏冗长的编译命令行(默认,仅显示简洁摘要);0显示每条完整的编译器调用。其在 Makefile.include 的实现是:
QUIET ?= 1 QUIETER ?= 0 ifeq ($(QUIET),1) Q=@ # 抑制命令回显 MAKEFLAGS += --no-print-directory else Q= endif构建规则中的每个命令都以$(Q)开头,Q为@时命令不回显,为空时完整回显。需要排查编译参数(如确认-DRIOT_BOARD是否正确注入)时,执行make QUIET=0即可看到全部编译器调用。
6. 最后一行:接入构建系统
Makefile 的最后一行必须是include $(RIOTBASE)/Makefile.include。这一行将 RIOT 的整套构建系统(约 1139 行的核心逻辑:板卡解析、特性检查、模块依赖、链接规则、烧录与终端目标等)全部引入当前应用,此后你就能使用make、make flash、make term等一系列标准目标了。RIOT 要求它位于文件末尾,因为其内部规则会依赖应用 Makefile 中已定义的变量。
四、构建到运行:在 native 平台上的无硬件体验
BOARD=native(以及native64、native32)是 RIOT 最具特色的板卡之一。按照 boards/native64/doc.md 的说明,native 板卡通过系统调用与信号在 API 层面模拟硬件,让你把完整的 RIOT 软件栈编译成本机进程直接运行,无需任何开发板。
在 hello-world 目录执行:
make # 默认 BOARD=native,自动选择 64/32 位变体随后运行生成的可执行文件(native 的 "烧录" 就是直接运行进程):
make term即可看到输出:
Hello World! You are running RIOT on a(n) native64 board. This board features a(n) native CPU.make term实际调用的是 Makefile.include 中定义的终端目标,通过TERMPROG(native 下即应用进程本身)打开串口/终端。这样,即使没有硬件,你也能完成 RIOT 应用的开发、调试与逻辑验证——这也是学习本示例的最低成本路径。
五、面向真实硬件:交叉编译、烧录与终端
当需要部署到真实板卡时,只需覆盖BOARD。例如使用 STM32 平台(以nucleo-f401re为例)或 Nordic nRF 平台(nrf52840dk):
make BOARD=nucleo-f401re # 交叉编译 make BOARD=nrf52840dk flash # 编译并烧录 make BOARD=nrf52840dk term # 打开串口终端观察输出流程要点:
- 交叉编译:RIOT 会根据
CPU自动选择对应的交叉工具链(GNU/LLVM),无需手工配置CC; - 烧录:
make flash调用板卡对应的PROGRAMMER(如 OpenOCD、JLink、pyocd 等),烧录文件默认为$(BINDIR)/$(APPLICATION).elf; - 串口终端:
make term通过TERMPROG(通常为 pyterm)连接板卡串口,你将在其中看到与 native 平台一致的Hello World!输出以及正确的板卡名。
例如以BOARD=nrf52840dk构建时,宏展开后printf将输出You are running RIOT on a(n) nrf52840dk board.,证明同一份源码在真实硬件上无需任何修改即可运行。
六、常用构建目标速查
接入Makefile.include后,hello-world 自动获得以下常用目标(定义见 Makefile.include):
| 命令 | 作用 |
|---|---|
make | 默认目标all,编译并链接生成bin/$(BOARD)/$(APPLICATION).elf |
make BOARD=<板卡> | 覆盖默认板卡后重新构建 |
make flash | 编译并烧录到目标板卡 |
make flash-only | 仅烧录(不重新编译) |
make term | 打开串口/仿真终端 |
make debug | 启动调试器(需板卡支持) |
make clean | 清理当前板卡的构建产物bin/$(BOARD) |
make distclean | 清理全部板卡的构建产物 |
make QUIET=0 | 显示完整编译器调用,便于排错 |
make print-size | 打印固件体积(text/data/bss) |
七、小结
hello-world虽然只有两个源文件,却是理解 RIOT 应用开发范式的最佳起点:它完整展示了 RIOT 应用的目录组织、main.c入口约定、RIOT_BOARD/RIOT_CPU编译期宏注入,以及APPLICATION、BOARD、RIOTBASE、DEVELHELP、QUIET五个核心 Makefile 变量的语义与底层实现。掌握这些内容后,无论是阅读 examples/basic 下的其他示例,还是从零编写自己的 RIOT 应用,你都能迅速上手——只需复制本目录骨架,修改APPLICATION名称与业务代码,再选定BOARD即可。
- 物联网
- 嵌入式
- 操作系统
- 实时系统
【免费下载链接】RIOT
RIOT - The friendly OS for IoT
相关推荐
YOLO-World工业部署案例:从Python Demo到嵌入式系统移植
YOLO World工业部署案例:从Python Demo到嵌入式系统移植 工业视觉部署的痛点与解决方案 你是否还在为目标检测模型从实验室到产线的落地发愁?YO
人工智能计算机视觉深度学习RIOT Blinky 例程深度解析:以 GPIO 点亮首块移植开发板的“Hello World”
RIOT Blinky 例程深度解析:以 GPIO 点亮首块移植开发板的“Hello World” 导读 Blinky(闪烁 LED)是 RIOT 操作系统中最
物联网嵌入式操作系统实时系统从零创建 RIOT 应用:Hello World 项目搭建、Makefile 构建与运行全指南
从零创建 RIOT 应用:Hello World 项目搭建、Makefile 构建与运行全指南 导读 本篇指南以 RIOT 官方入门教程"Creating a
物联网嵌入式操作系统实时系统
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考