您的第一个 Nexus 应用程序¶
This tutorial guides you through creating your first Nexus application from scratch. You'll learn how to set up a project, configure the build system, and create a simple LED blinky application.
学习目标¶
完成本教程后,您将能够:
理解 Nexus 应用程序的基本结构
了解如何为 Nexus 项目配置 CMake
能够初始化 HAL 子系统
创建和控制 GPIO 设备
构建应用程序并烧录到硬件
前置条件¶
开始之前,请确保您已:
Completed the Environment Setup guide
A supported development board (we'll use STM32F4 Discovery)
已安装 ARM GCC 工具链
用于烧录的 OpenOCD 或 ST-Link 工具
参见
构建系统 - Build system overview
硬件抽象层 (HAL) - HAL API documentation
STM32F4 平台 Guide - STM32F4 platform guide
GPIO Control 教程 - GPIO control tutorial
Kconfig 教程 - Configuration tutorial
步骤 1:创建项目结构¶
首先,为您的项目创建一个新目录:
mkdir my_first_nexus_app
cd my_first_nexus_app
创建以下目录结构:
my_first_nexus_app/
├── CMakeLists.txt
├── main.c
└── nexus/ (git submodule or copy of Nexus)
步骤 2:添加 Nexus 依赖¶
您可以通过两种方式将 Nexus 添加到项目中:
Option A: Git Submodule (Recommended)
git init
git submodule add https://github.com/X-Gen-Lab/nexus.git nexus
git submodule update --init --recursive
Option B: Copy Nexus
cp -r /path/to/nexus ./nexus
步骤 3:创建 CMakeLists.txt¶
创建包含以下内容的 CMakeLists.txt:
cmake_minimum_required(VERSION 3.16)
# Project name and language
project(my_first_nexus_app C ASM)
# Set C standard
set(CMAKE_C_STANDARD 11)
set(CMAKE_C_STANDARD_REQUIRED ON)
# Add Nexus as subdirectory
add_subdirectory(nexus)
# Create executable
add_executable(${PROJECT_NAME}
main.c
)
# Link against Nexus libraries
target_link_libraries(${PROJECT_NAME} PRIVATE
nexus::hal
nexus::platform
)
# Set output name
set_target_properties(${PROJECT_NAME} PROPERTIES
OUTPUT_NAME "app"
)
Understanding the CMakeLists.txt:
add_subdirectory(nexus)- Includes Nexus build systemnexus::hal- Links the Hardware Abstraction Layernexus::platform- Links platform-specific code
步骤 4:编写您的第一个应用程序¶
创建一个简单的 LED 闪烁程序 main.c:
/**
* \file main.c
* \brief My First Nexus Application
* \author Your Name
*/
#include "hal/hal.h"
/*-----------------------------------------------------------------------*/
/* Configuration */
/*-----------------------------------------------------------------------*/
/** LED pin definitions for STM32F4 Discovery */
#define LED_PORT HAL_GPIO_PORT_D
#define LED_PIN 12 /* Green LED */
/** Blink delay in milliseconds */
#define BLINK_DELAY_MS 500
/*-----------------------------------------------------------------------*/
/* Helper Functions */
/*-----------------------------------------------------------------------*/
/**
* \brief Initialize LED GPIO
* \return HAL_OK on success, error code otherwise
*/
static hal_status_t led_init(void) {
/* Configure GPIO as output */
hal_gpio_config_t config = {
.direction = HAL_GPIO_DIR_OUTPUT,
.pull = HAL_GPIO_PULL_NONE,
.output_mode = HAL_GPIO_OUTPUT_PP,
.speed = HAL_GPIO_SPEED_LOW,
.init_level = HAL_GPIO_LEVEL_LOW
};
/* Initialize GPIO */
return hal_gpio_init(LED_PORT, LED_PIN, &config);
}
/*-----------------------------------------------------------------------*/
/* Main Function */
/*-----------------------------------------------------------------------*/
/**
* \brief Main entry point
* \return Should never return
*/
int main(void) {
/* Initialize HAL subsystem */
if (hal_init() != HAL_OK) {
/* Initialization failed - stay in error loop */
while (1) {
/* Error state */
}
}
/* Initialize LED */
if (led_init() != HAL_OK) {
/* LED initialization failed */
while (1) {
/* Error state */
}
}
/* Main loop: blink LED */
while (1) {
/* Toggle LED state */
hal_gpio_toggle(LED_PORT, LED_PIN);
/* Wait for blink period */
hal_delay_ms(BLINK_DELAY_MS);
}
return 0;
}
Understanding the Code:
HAL Initialization:
hal_init()initializes the HAL subsystem, including system clock, SysTick timer, and platform-specific hardware.GPIO Configuration: The
hal_gpio_config_tstructure defines GPIO behavior:direction: Input or output modepull: Pull-up, pull-down, or noneoutput_mode: Push-pull or open-drainspeed: GPIO speed (low, medium, high, very high)init_level: Initial output level (high or low)
GPIO Operations:
hal_gpio_init(): Initialize GPIO with configurationhal_gpio_toggle(): Toggle GPIO output statehal_delay_ms(): Blocking delay in milliseconds
Step 5: Build for Native Platform (Testing)¶
First, let's build for the native platform to test our code structure:
# Configure for native platform
CMake -B build-native -DNEXUS_PLATFORM=native
# Build
CMake --build build-native
# Run (LED operations will be simulated)
./build-native/app
本地平台适用于:
在没有硬件的情况下测试应用程序逻辑
运行单元测试
在开发机器上调试
步骤 6:为 STM32F4 构建¶
现在让我们为实际目标硬件构建:
# Configure for STM32F4 with ARM toolchain
CMake -B build-stm32f4 \
-DCMAKE_TOOLCHAIN_FILE=nexus/CMake/toolchains/arm-none-eabi.CMake \
-DNEXUS_PLATFORM=stm32f4
# Build
CMake --build build-stm32f4
这将创建 build-stm32f4/app.elf 和 build-stm32f4/app.bin 文件。
步骤 7:烧录到硬件¶
Using OpenOCD:
# Flash with OpenOCD
openocd -f interface/stlink.cfg -f target/stm32f4x.cfg \
-c "program build-stm32f4/app.elf verify reset exit"
Using ST-Link Utility (Windows):
打开 ST-Link 实用程序
连接到开发板
在地址
0x08000000加载build-stm32f4/app.bin点击"编程和验证"
Using st-flash (Linux/macOS):
st-flash write build-stm32f4/app.bin 0x08000000
步骤 8:验证运行¶
After flashing:
The green LED (PD12) on the STM32F4 Discovery board should blink
LED 应该每 500 毫秒切换一次
按下复位按钮重启应用程序
如果 LED 不闪烁:
检查开发板是否通电
验证是否配置了正确的 LED 引脚
检查应用程序是否成功烧录
Try debugging with GDB (see 测试)
Understanding HAL 初始化¶
The hal_init() function performs several important tasks:
System Clock Configuration: Sets up the main system clock (typically 168 MHz for STM32F4)
SysTick Timer: Configures the SysTick timer for
hal_delay_ms()andhal_get_tick()FPU Initialization: Enables the Floating Point Unit (if available)
Platform-Specific Setup: Initializes platform-specific hardware
Always call hal_init() before using any HAL functions.
GPIO 配置 Options¶
hal_gpio_config_t 结构提供了细粒度控制:
Direction:
HAL_GPIO_DIR_INPUT: Configure as inputHAL_GPIO_DIR_OUTPUT: Configure as output
Pull Resistors:
HAL_GPIO_PULL_NONE: No pull resistorHAL_GPIO_PULL_UP: Enable pull-up resistorHAL_GPIO_PULL_DOWN: Enable pull-down resistor
Output Mode:
HAL_GPIO_OUTPUT_PP: Push-pull output (can drive high and low)HAL_GPIO_OUTPUT_OD: Open-drain output (can only pull low)
Speed:
HAL_GPIO_SPEED_LOW: Low speed (2 MHz)HAL_GPIO_SPEED_MEDIUM: Medium speed (25 MHz)HAL_GPIO_SPEED_HIGH: High speed (50 MHz)HAL_GPIO_SPEED_VERY_HIGH: Very high speed (100 MHz)
对于 LED 控制,低速就足够了。对于高频信号使用更高的速度。
常见问题和解决方案¶
Issue: Build fails with "nexus not found"
Solution: Ensure Nexus is properly added as a subdirectory and the path in add_subdirectory() is correct.
Issue: Linker errors about undefined references
Solution: Make sure you're linking against the correct Nexus libraries (nexus::hal and nexus::platform).
Issue: Application doesn't run after flashing
Solution:
- Verify the correct flash address (0x08000000 for STM32F4)
- Check that the toolchain file is specified correctly
- Ensure the platform is set to stm32f4
Issue: LED doesn't blink
Solution:
- Verify the LED pin number matches your board
- Check that hal_init() succeeded
- Try a longer delay to make blinking more visible
下一步¶
恭喜!您已创建了第一个 Nexus 应用程序。现在您可以:
GPIO Control 教程 - Learn advanced GPIO techniques
UART Communication 教程 - Add serial communication
使用 OSAL 的多任务 - Create multi-tasking applications
探索 硬件抽象层 (HAL) 了解更多 HAL 特性
附加练习¶
尝试这些练习来巩固您的学习:
Multiple LEDs: Modify the code to blink all four LEDs on the STM32F4 Discovery board in sequence
Variable Speed: Add a button to change the blink speed when pressed
Pattern: Create a custom blink pattern (e.g., two quick blinks, pause, repeat)
Error Handling: Add more robust error handling with LED error indicators
示例:闪烁多个 LED¶
/* LED definitions */
#define LED_GREEN_PORT HAL_GPIO_PORT_D
#define LED_GREEN_PIN 12
#define LED_ORANGE_PORT HAL_GPIO_PORT_D
#define LED_ORANGE_PIN 13
#define LED_RED_PORT HAL_GPIO_PORT_D
#define LED_RED_PIN 14
#define LED_BLUE_PORT HAL_GPIO_PORT_D
#define LED_BLUE_PIN 15
/* Initialize all LEDs */
static hal_status_t leds_init(void) {
hal_gpio_config_t config = {
.direction = HAL_GPIO_DIR_OUTPUT,
.pull = HAL_GPIO_PULL_NONE,
.output_mode = HAL_GPIO_OUTPUT_PP,
.speed = HAL_GPIO_SPEED_LOW,
.init_level = HAL_GPIO_LEVEL_LOW
};
if (hal_gpio_init(LED_GREEN_PORT, LED_GREEN_PIN, &config) != HAL_OK) {
return HAL_ERR_FAIL;
}
if (hal_gpio_init(LED_ORANGE_PORT, LED_ORANGE_PIN, &config) != HAL_OK) {
return HAL_ERR_FAIL;
}
if (hal_gpio_init(LED_RED_PORT, LED_RED_PIN, &config) != HAL_OK) {
return HAL_ERR_FAIL;
}
if (hal_gpio_init(LED_BLUE_PORT, LED_BLUE_PIN, &config) != HAL_OK) {
return HAL_ERR_FAIL;
}
return HAL_OK;
}
/* Main loop with sequence */
while (1) {
hal_gpio_toggle(LED_GREEN_PORT, LED_GREEN_PIN);
hal_delay_ms(250);
hal_gpio_toggle(LED_ORANGE_PORT, LED_ORANGE_PIN);
hal_delay_ms(250);
hal_gpio_toggle(LED_RED_PORT, LED_RED_PIN);
hal_delay_ms(250);
hal_gpio_toggle(LED_BLUE_PORT, LED_BLUE_PIN);
hal_delay_ms(250);
}
最佳实践¶
Always Initialize HAL First: Call
hal_init()before using any HAL functionsCheck Return Values: Always check return values from HAL functions for errors
Use Appropriate GPIO Speed: Don't use high-speed GPIO for slow signals (wastes power)
Document Pin Assignments: Clearly document which pins are used for what purpose
Error Handling: Implement proper error handling with visual indicators (LEDs)
Code Organization: Keep initialization code separate from main loop logic
Use Meaningful Names: Use descriptive names for constants and functions
资源¶
硬件抽象层 (HAL) - Complete HAL API documentation
STM32F4 平台 Guide - STM32F4-specific information
构建系统 - Advanced build configuration