Update README.md

This commit is contained in:
Natsume1710
2025-06-17 16:04:24 +08:00
committed by GitHub
parent 6b4f785166
commit 03d2f436d1
+847
View File
@@ -1 +1,848 @@
# 📦 第八层:项目实战与工具链
## ✅ 工程管理
### 🔹 Git 版本控制
#### 1. **Git 分支策略**
- **主干分支(main/master)**:
永远代表可发布的稳定版本,仅接受通过CI/CD验证的代码。
- **开发分支(develop)**:
集成所有新功能的开发,是日常开发的基础分支。
- **特性分支(feature/*)**:
从develop分支创建,用于开发单个新功能或修复问题,完成后合并回develop。
- **发布分支(release/*)**:
从develop分支创建,用于准备发布版本,进行最后的测试和Bug修复。
- **热修复分支(hotfix/*)**:
从main分支创建,用于紧急修复生产环境问题,修复后合并回main和develop。
#### 2. **提交规范**
采用Conventional Commits规范:
```
<类型>[可选范围]: <描述>
[可选正文]
[可选脚注]
```
- **常见类型**:
- `feat`:新功能
- `fix`:修复Bug
- `docs`:文档更新
- `style`:代码格式调整(不影响功能)
- `refactor`:代码重构
- `test`:添加或修改测试
- `chore`:构建或辅助工具的变动
#### 3. **标签管理**
使用语义化版本(SemVer)打标签:
```bash
# 创建标签
git tag v1.0.0
# 推送标签到远程
git push origin v1.0.0
# 查看所有标签
git tag -l
```
### 🔹 Makefile、CMake 构建工具
#### 1. **Makefile 基础**
- **简单示例**:
```makefile
CC = arm-none-eabi-gcc
CFLAGS = -Wall -O2 -mcpu=cortex-m4 -mthumb
LDFLAGS = -Tstm32f4.ld
SRCS = $(wildcard *.c)
OBJS = $(SRCS:.c=.o)
TARGET = firmware.elf
all: $(TARGET)
$(TARGET): $(OBJS)
$(CC) $(LDFLAGS) $(OBJS) -o $@
%.o: %.c
$(CC) $(CFLAGS) -c $< -o $@
clean:
rm -f $(OBJS) $(TARGET)
```
#### 2. **CMake 高级应用**
- **跨平台配置**:
```cmake
cmake_minimum_required(VERSION 3.10)
project(EmbeddedProject C)
# 设置交叉编译工具链
set(CMAKE_SYSTEM_NAME Generic)
set(CMAKE_C_COMPILER arm-none-eabi-gcc)
set(CMAKE_CXX_COMPILER arm-none-eabi-g++)
set(CMAKE_ASM_COMPILER arm-none-eabi-gcc)
set(CMAKE_OBJCOPY arm-none-eabi-objcopy)
# 添加编译选项
add_compile_options(
-mcpu=cortex-m4
-mthumb
-mfloat-abi=hard
-mfpu=fpv4-sp-d16
-Wall
-Wextra
-Os
)
# 添加链接选项
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -T${CMAKE_SOURCE_DIR}/STM32F407VGTx_FLASH.ld")
# 添加源文件
file(GLOB_RECURSE SOURCES "src/*.c" "drivers/*.c")
# 添加可执行文件
add_executable(${PROJECT_NAME}.elf ${SOURCES})
# 添加目标文件
add_custom_target(${PROJECT_NAME}.bin
COMMAND ${CMAKE_OBJCOPY} -O binary ${PROJECT_NAME}.elf ${PROJECT_NAME}.bin
DEPENDS ${PROJECT_NAME}.elf
)
```
### 🔹 Jenkins/GitHub Actions CI 流水线
#### 1. **GitHub Actions 配置**
- **编译与测试工作流**:
```yaml
name: Build and Test
on:
push:
branches: [ main, develop ]
pull_request:
branches: [ main, develop ]
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v3
- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: 3.9
- name: Install dependencies
run: |
sudo apt-get update
sudo apt-get install -y gcc-arm-none-eabi cmake ninja-build
- name: Configure CMake
run: cmake -B build -G Ninja
- name: Build
run: cmake --build build
- name: Run tests
run: |
cd build
ctest --output-on-failure
```
#### 2. **Jenkins 集成**
- **构建脚本示例**:
```groovy
pipeline {
agent any
stages {
stage('Checkout') {
steps {
checkout scm
}
}
stage('Build') {
steps {
sh 'make clean all'
}
}
stage('Test') {
steps {
sh 'make test'
}
}
stage('Code Coverage') {
steps {
sh 'make coverage'
}
post {
always {
junit 'build/test-results/*.xml'
publishCoverage adapters: [coberturaAdapter('build/coverage/coverage.xml')]
}
}
}
stage('Deploy') {
when {
branch 'main'
}
steps {
sh 'make deploy'
}
}
}
}
```
## ✅ 项目实践
### 🔹 嵌入式应用框架设计
#### 1. **分层架构**
```
+----------------------+
| 应用层 |
| (业务逻辑、算法) |
+----------------------+
| 服务层 |
| (任务管理、事件) |
+----------------------+
| 驱动层 |
| (硬件抽象、BSP) |
+----------------------+
| 硬件层 |
| (MCU、外设) |
+----------------------+
```
#### 2. **组件化设计**
- **核心组件**:
- 任务管理器:负责任务创建、调度和通信。
- 事件系统:处理异步事件和回调。
- 配置管理:加载和保存系统配置。
- 日志系统:分级日志记录和输出。
#### 3. **代码结构示例**
```
project/
├── app/ # 应用层
│ ├── main.c # 主程序入口
│ ├── modules/ # 功能模块
│ │ ├── sensor/ # 传感器处理
│ │ ├── comm/ # 通信处理
│ │ └── control/ # 控制逻辑
│ └── config/ # 配置文件
├── services/ # 服务层
│ ├── task_mgr/ # 任务管理器
│ ├── event/ # 事件系统
│ └── utils/ # 工具函数
├── drivers/ # 驱动层
│ ├── bsp/ # 板级支持包
│ ├── hal/ # 硬件抽象层
│ └── periph/ # 外设驱动
└── build/ # 构建系统
├── cmake/ # CMake配置
└── Makefile # Makefile
```
### 🔹 通用 BSP 构建
#### 1. **设计原则**
- **硬件无关性**:上层代码不直接访问硬件寄存器。
- **可移植性**:相同功能代码可在不同硬件平台复用。
- **配置化**:通过配置文件而非修改代码适配不同硬件。
#### 2. **BSP 实现示例**
```c
// bsp_led.h
#ifndef BSP_LED_H
#define BSP_LED_H
#include <stdint.h>
typedef enum {
LED_RED,
LED_GREEN,
LED_BLUE
} led_t;
typedef enum {
LED_OFF,
LED_ON,
LED_TOGGLE
} led_state_t;
// 初始化LED
void bsp_led_init(void);
// 设置LED状态
void bsp_led_set(led_t led, led_state_t state);
#endif
// bsp_led.c (STM32实现)
#include "bsp_led.h"
#include "stm32f4xx_hal.h"
// LED GPIO定义
#define LED_RED_PIN GPIO_PIN_14
#define LED_RED_PORT GPIOG
#define LED_GREEN_PIN GPIO_PIN_13
#define LED_GREEN_PORT GPIOG
#define LED_BLUE_PIN GPIO_PIN_15
#define LED_BLUE_PORT GPIOG
void bsp_led_init(void) {
GPIO_InitTypeDef GPIO_InitStruct = {0};
// 使能GPIO时钟
__HAL_RCC_GPIOG_CLK_ENABLE();
// 配置GPIO引脚
GPIO_InitStruct.Pin = LED_RED_PIN | LED_GREEN_PIN | LED_BLUE_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOG, &GPIO_InitStruct);
// 默认关闭所有LED
HAL_GPIO_WritePin(LED_RED_PORT, LED_RED_PIN, GPIO_PIN_RESET);
HAL_GPIO_WritePin(LED_GREEN_PORT, LED_GREEN_PIN, GPIO_PIN_RESET);
HAL_GPIO_WritePin(LED_BLUE_PORT, LED_BLUE_PIN, GPIO_PIN_RESET);
}
void bsp_led_set(led_t led, led_state_t state) {
GPIO_TypeDef *port;
uint16_t pin;
// 根据LED类型选择GPIO
switch (led) {
case LED_RED:
port = LED_RED_PORT;
pin = LED_RED_PIN;
break;
case LED_GREEN:
port = LED_GREEN_PORT;
pin = LED_GREEN_PIN;
break;
case LED_BLUE:
port = LED_BLUE_PORT;
pin = LED_BLUE_PIN;
break;
default:
return;
}
// 设置LED状态
switch (state) {
case LED_OFF:
HAL_GPIO_WritePin(port, pin, GPIO_PIN_RESET);
break;
case LED_ON:
HAL_GPIO_WritePin(port, pin, GPIO_PIN_SET);
break;
case LED_TOGGLE:
HAL_GPIO_TogglePin(port, pin);
break;
}
}
```
### 🔹 模块化驱动结构
#### 1. **驱动分层**
- **硬件层**:直接操作寄存器的低级驱动。
- **抽象层**:提供统一接口的高级驱动。
- **适配层**:连接抽象层和硬件层的中间层。
#### 2. **SPI驱动示例**
```c
// spi_interface.h (抽象接口)
#ifndef SPI_INTERFACE_H
#define SPI_INTERFACE_H
#include <stdint.h>
typedef struct {
// 初始化SPI
void (*init)(uint32_t baudrate);
// 发送数据
void (*send)(const uint8_t *data, uint32_t length);
// 接收数据
void (*receive)(uint8_t *data, uint32_t length);
// 发送并接收数据
void (*transfer)(const uint8_t *tx_data, uint8_t *rx_data, uint32_t length);
} spi_interface_t;
// 获取SPI接口实例
const spi_interface_t* spi_get_interface(void);
#endif
// spi_stm32.c (STM32实现)
#include "spi_interface.h"
#include "stm32f4xx_hal.h"
static SPI_HandleTypeDef hspi1;
static void spi_init(uint32_t baudrate) {
// 配置SPI参数
hspi1.Instance = SPI1;
hspi1.Init.Mode = SPI_MODE_MASTER;
hspi1.Init.Direction = SPI_DIRECTION_2LINES;
hspi1.Init.DataSize = SPI_DATASIZE_8BIT;
hspi1.Init.CLKPolarity = SPI_POLARITY_LOW;
hspi1.Init.CLKPhase = SPI_PHASE_1EDGE;
hspi1.Init.NSS = SPI_NSS_SOFT;
// 根据波特率计算分频系数
uint32_t prescaler = SPI_BAUDRATEPRESCALER_2;
if (baudrate < 1000000) prescaler = SPI_BAUDRATEPRESCALER_128;
else if (baudrate < 2000000) prescaler = SPI_BAUDRATEPRESCALER_64;
else if (baudrate < 4000000) prescaler = SPI_BAUDRATEPRESCALER_32;
else if (baudrate < 8000000) prescaler = SPI_BAUDRATEPRESCALER_16;
else if (baudrate < 16000000) prescaler = SPI_BAUDRATEPRESCALER_8;
else if (baudrate < 32000000) prescaler = SPI_BAUDRATEPRESCALER_4;
hspi1.Init.BaudRatePrescaler = prescaler;
hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB;
hspi1.Init.TIMode = SPI_TIMODE_DISABLE;
hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
hspi1.Init.CRCPolynomial = 10;
// 初始化SPI
HAL_SPI_Init(&hspi1);
}
static void spi_send(const uint8_t *data, uint32_t length) {
HAL_SPI_Transmit(&hspi1, (uint8_t*)data, length, 1000);
}
static void spi_receive(uint8_t *data, uint32_t length) {
HAL_SPI_Receive(&hspi1, data, length, 1000);
}
static void spi_transfer(const uint8_t *tx_data, uint8_t *rx_data, uint32_t length) {
HAL_SPI_TransmitReceive(&hspi1, (uint8_t*)tx_data, rx_data, length, 1000);
}
// SPI接口实现
static const spi_interface_t spi_impl = {
.init = spi_init,
.send = spi_send,
.receive = spi_receive,
.transfer = spi_transfer
};
// 获取SPI接口实例
const spi_interface_t* spi_get_interface(void) {
return &spi_impl;
}
```
### 🔹 OTA 升级方案设计
#### 1. **双分区架构**
```
Flash布局:
+-------------------+ 0x08000000
| Bootloader | (80KB)
+-------------------+ 0x08014000
| Application A | (448KB)
+-------------------+ 0x08084000
| Application B | (448KB)
+-------------------+ 0x08104000
| Configuration | (16KB)
+-------------------+
```
#### 2. **OTA状态机**
```c
typedef enum {
OTA_IDLE, // 空闲状态
OTA_CHECKING, // 检查更新
OTA_DOWNLOADING, // 下载中
OTA_DOWNLOAD_PAUSED, // 下载暂停
OTA_VERIFYING, // 校验中
OTA_READY, // 准备重启
OTA_UPGRADING, // 升级中
OTA_FAILED // 升级失败
} ota_state_t;
typedef struct {
ota_state_t state;
uint32_t total_size;
uint32_t downloaded_size;
uint8_t progress;
char error_msg[64];
uint8_t firmware_hash[32];
} ota_context_t;
```
#### 3. **OTA流程**
1. **检查更新**:
```c
bool ota_check_update(void) {
// 从服务器获取版本信息
http_response_t response = http_get(UPDATE_SERVER_URL "/version");
if (response.status != 200) {
return false;
}
// 解析服务器版本
uint32_t server_version = parse_version(response.body);
uint32_t current_version = get_current_version();
// 比较版本
return (server_version > current_version);
}
```
2. **下载固件**:
```c
void ota_download_firmware(void) {
// 打开固件下载URL
http_client_t client = http_open(UPDATE_SERVER_URL "/firmware.bin");
if (!client) {
ota_set_state(OTA_FAILED, "Failed to open URL");
return;
}
// 获取文件大小
uint32_t file_size = http_get_content_length(client);
ota_set_total_size(file_size);
// 开始下载
uint8_t buffer[512];
uint32_t bytes_received = 0;
uint32_t bytes_written = 0;
while ((bytes_received = http_read(client, buffer, 512)) > 0) {
// 写入到备份区
if (!flash_write(APPLICATION_B_ADDRESS + bytes_written, buffer, bytes_received)) {
ota_set_state(OTA_FAILED, "Flash write failed");
http_close(client);
return;
}
bytes_written += bytes_received;
ota_update_progress(bytes_written * 100 / file_size);
// 检查是否需要暂停
if (ota_should_pause()) {
http_close(client);
ota_set_state(OTA_DOWNLOAD_PAUSED, "Download paused");
return;
}
}
http_close(client);
ota_set_state(OTA_VERIFYING, "Verifying firmware");
}
```
3. **验证与应用**:
```c
bool ota_verify_firmware(void) {
// 计算下载固件的哈希值
uint8_t calculated_hash[32];
calculate_firmware_hash(APPLICATION_B_ADDRESS, APPLICATION_SIZE, calculated_hash);
// 与服务器提供的哈希值比较
if (memcmp(calculated_hash, ota_get_expected_hash(), 32) != 0) {
return false;
}
// 验证向量表
uint32_t *vector_table = (uint32_t*)APPLICATION_B_ADDRESS;
if (vector_table[0] == 0 || vector_table[1] == 0) {
return false;
}
return true;
}
void ota_apply_update(void) {
// 设置升级标志
set_update_flag(1);
// 保存新固件版本
save_new_version(get_server_version());
// 重启系统
NVIC_SystemReset();
}
```
# 开发工具链安装指南
## 1. **IDE推荐**
### VS Code + PlatformIO
**官网链接**:
- [VS Code](https://code.visualstudio.com/)
- [PlatformIO](https://platformio.org/)
**安装步骤**:
1. 下载并安装 [VS Code](https://code.visualstudio.com/Download)
2. 打开VS Code,点击左侧扩展图标(或按 `Ctrl+Shift+X`)
3. 搜索并安装 **PlatformIO IDE** 扩展
4. 安装完成后,重启VS Code
5. PlatformIO会自动安装所需的工具链和依赖
**验证安装**:
打开VS Code,点击左下角的 **PlatformIO Home** 图标,若能正常打开则安装成功。
### STM32CubeIDE
**官网链接**:
- [STM32CubeIDE](https://www.st.com/en/development-tools/stm32cubeide.html)
**安装步骤**:
1. 访问官网,点击 **Get Software** 下载对应操作系统的安装包
2. 运行安装程序,按照向导完成安装
3. 安装过程中会自动下载并配置STM32CubeMX
**验证安装**:
启动STM32CubeIDE,创建一个新的STM32项目,若能正常编译则安装成功。
### CLion
**官网链接**:
- [CLion](https://www.jetbrains.com/clion/)
**安装步骤**:
1. 下载并安装 [CLion](https://www.jetbrains.com/clion/download/)
2. 安装CMake和MinGW(Windows用户需要):
- CMake:从 [官网](https://cmake.org/download/) 下载并安装
- MinGW:推荐使用 [MSYS2](https://www.msys2.org/) 安装
**验证安装**:
启动CLion,创建一个新的C/C++项目,选择CMake工具链,若能正常编译则安装成功。
## 2. **调试工具**
### OpenOCD
**官网链接**:
- [OpenOCD](http://openocd.org/)
**安装步骤**:
- **Windows**:
1. 从 [GNU MCU Eclipse](https://github.com/gnu-mcu-eclipse/openocd/releases) 下载预编译二进制包
2. 解压到指定目录(如 `C:\openocd`)
3. 将 `bin` 目录添加到系统环境变量
- **Linux**:
```bash
sudo apt-get install openocd # Ubuntu/Debian
sudo yum install openocd # CentOS/RHEL
```
- **macOS**:
```bash
brew install open-ocd
```
**验证安装**:
在终端中运行 `openocd --version`,若显示版本信息则安装成功。
### GDB
**官网链接**:
- [GDB](https://www.gnu.org/software/gdb/)
- [ARM GCC Toolchain](https://developer.arm.com/tools-and-software/open-source-software/developer-tools/gnu-toolchain/gnu-rm)
**安装步骤**:
1. 下载并安装 [ARM GCC Toolchain](https://developer.arm.com/tools-and-software/open-source-software/developer-tools/gnu-toolchain/gnu-rm/downloads)
2. 将 `bin` 目录添加到系统环境变量
**验证安装**:
在终端中运行 `arm-none-eabi-gdb --version`,若显示版本信息则安装成功。
### ST-Link/V2
**官网链接**:
- [ST-Link](https://www.st.com/en/development-tools/st-link-v2.html)
**安装步骤**:
- **Windows**:
1. 从 [ST官网](https://www.st.com/en/development-tools/stsw-link004.html) 下载并安装ST-Link驱动
2. 安装完成后,将ST-Link/V2调试器连接到电脑
- **Linux**:
```bash
sudo apt-get install stlink-tools # Ubuntu/Debian
```
**验证安装**:
在终端中运行 `st-info --version`,若显示版本信息则安装成功。
## 3. **静态代码分析**
### CppCheck
**官网链接**:
- [CppCheck](https://cppcheck.sourceforge.io/)
**安装步骤**:
- **Windows**:
1. 从 [官网](https://cppcheck.sourceforge.io/) 下载安装包
2. 运行安装程序,按照向导完成安装
- **Linux**:
```bash
sudo apt-get install cppcheck # Ubuntu/Debian
sudo yum install cppcheck # CentOS/RHEL
```
- **macOS**:
```bash
brew install cppcheck
```
**验证安装**:
在终端中运行 `cppcheck --version`,若显示版本信息则安装成功。
### Clang-Tidy
**官网链接**:
- [Clang-Tidy](https://clang.llvm.org/extra/clang-tidy/)
**安装步骤**:
- **Windows**:
1. 安装 [LLVM](https://releases.llvm.org/download.html)
2. Clang-Tidy会随LLVM一起安装
- **Linux**:
```bash
sudo apt-get install clang-tidy # Ubuntu/Debian
```
- **macOS**:
```bash
brew install llvm
```
**验证安装**:
在终端中运行 `clang-tidy --version`,若显示版本信息则安装成功。
### SonarQube
**官网链接**:
- [SonarQube](https://www.sonarqube.org/)
**安装步骤**:
1. 下载并安装 [Docker](https://www.docker.com/get-started)
2. 运行SonarQube容器:
```bash
docker run -d --name sonarqube -p 9000:9000 sonarqube
```
3. 访问 [http://localhost:9000](http://localhost:9000),使用默认账号(admin/admin)登录
**验证安装**:
在浏览器中打开 [http://localhost:9000](http://localhost:9000),若能看到SonarQube界面则安装成功。
## 4. **单元测试**
### Unity
**官网链接**:
- [Unity](https://github.com/ThrowTheSwitch/Unity)
**安装步骤**:
1. 从GitHub下载Unity源码:
```bash
git clone https://github.com/ThrowTheSwitch/Unity.git
```
2. 将 `src` 目录添加到项目的头文件搜索路径
**验证安装**:
创建一个简单的测试文件,包含Unity头文件,若能正常编译则安装成功。
### CMock
**官网链接**:
- [CMock](https://github.com/ThrowTheSwitch/CMock)
**安装步骤**:
1. 从GitHub下载CMock源码:
```bash
git clone https://github.com/ThrowTheSwitch/CMock.git
```
2. 将 `src` 目录添加到项目的头文件搜索路径
**验证安装**:
创建一个简单的测试文件,包含CMock头文件,若能正常编译则安装成功。
### Google Test
**官网链接**:
- [Google Test](https://github.com/google/googletest)
**安装步骤**:
1. 从GitHub下载Google Test源码:
```bash
git clone https://github.com/google/googletest.git
```
2. 使用CMake构建并安装:
```bash
cd googletest
mkdir build
cd build
cmake ..
make
sudo make install
```
**验证安装**:
创建一个简单的测试文件,包含Google Test头文件,若能正常编译则安装成功。
## 📚 资源汇总
| **工具** | **官网链接** | **安装指南** |
|------------------|---------------------------------------------|-------------------------------------------|
| VS Code | https://code.visualstudio.com/ | 直接下载安装包 |
| PlatformIO | https://platformio.org/ | VS Code扩展市场安装 |
| STM32CubeIDE | https://www.st.com/en/development-tools/stm32cubeide.html | 官网下载安装包 |
| CLion | https://www.jetbrains.com/clion/ | 官网下载安装包 |
| OpenOCD | http://openocd.org/ | 包管理器或预编译二进制包 |
| GDB | https://www.gnu.org/software/gdb/ | 随ARM GCC Toolchain安装 |
| ST-Link/V2 | https://www.st.com/en/development-tools/st-link-v2.html | 官网下载驱动 |
| CppCheck | https://cppcheck.sourceforge.io/ | 包管理器或安装包 |
| Clang-Tidy | https://clang.llvm.org/extra/clang-tidy/ | 随LLVM安装 |
| SonarQube | https://www.sonarqube.org/ | Docker容器或独立安装 |
| Unity | https://github.com/ThrowTheSwitch/Unity | 从GitHub下载源码 |
| CMock | https://github.com/ThrowTheSwitch/CMock | 从GitHub下载源码 |
| Google Test | https://github.com/google/googletest | CMake构建并安装 |