# STM32H7 软件使用手册 ## 1. 工程目录导航 **驱动层 (Drivers) → 中间件层 (Middlewares) → 应用层 (Projects)** 。 ### 1.1 Drivers (驱动层) * **BSP (Board Support Package)**: 核心层。对底层 HAL 库进行二次封装,提供 `UART`、`DI/DO`、`ADC/DAC`、`SDRAM` 等标准工控接口。 * `Components`: 外部元器件驱动(如以太网 PHY `LAN8742`、存储芯片 `W25QXX`、触摸屏 `FT5XXX` 等)。 * `STM32H7XX`: 针对具体开发板的硬件层实现。 * **CMSIS**: ARM 官方提供的 Cortex-M 内核通用软件接口。 * **HAL_Driver**: ST 官方硬件抽象层库,提供外设最底层的控制接口。 ### 1.2 Middlewares (中间件层) * **ST_USB_Library**: 负责 USB Host/Device 通信协议。 * **FatFs**: 轻量级文件系统,用于管理 SD 卡、SPI Flash 中的数据文件。 * **LwIP**: 轻量级 TCP/IP 协议栈,支持 HTTP、MQTT、SNTP 等工业通信协议。 ### 1.3 Projects (项目应用层) * **config**: **工程配置中心**。 * `AMKN86xx_Config.h`: 板卡引脚定义与功能开关。 * `stm32h7xx_hal_conf.h`: HAL 库底层配置。 * **src / inc**: **业务逻辑区**。包含 `main.c` (任务调度) 及各功能应用逻辑(如 `io_app.c`)。 * **startup**: 芯片启动汇编文件。 --- ## 2. 框架运行流程 系统从上电到进入任务轮询的完整逻辑如下: ```{mermaid} flowchart TB subgraph Initialization["系统初始化阶段"] Vars["APP_UserVars_Init: 加载系统变量"] APP_Init["APP_Init: 模块化加载入口"] UART_Init["Uart_APPInit: 串口应用初始化"] IO_Init["IO_APPInit: IO 硬件属性配置"] Logo["Logo_Out: 打印版权与版本信息"] Storage["存储初始化: EEPROM / Flash / SDRAM"] Periph["外设启动: ADC / DAC / PWM / CAN"] Middle["中间件启动: LWIP / USBH / WIFI"] end subgraph Polling["主循环任务轮询 (while 1)"] Cnt["UserVars.MCU_RunCnt++ (心跳计数)"] MainLoop{"任务轮询调度"} IO_P["IO_Proc: 数字输入输出扫描"] UART_P["Uart_Proc: 串口协议解析与数据收发"] NET_P["NET_Proc: 以太网/WIFI 协议栈维护"] Other_P["其他处理: 模拟量/RTC/存储应用"] end Start(("系统上电")) --> MPU["MPU_Config: 内存保护设置(解决 DMA Cache 一致性)"] MPU --> Cache["使能 I-Cache & D-Cache"] Cache --> HAL_Init["HAL_Init: 初始化底层库"] HAL_Init --> SysClock["SystemClock_Config: 时钟树配置(H743 @ 480MHz)"] SysClock --> APP_Init APP_Init --> Vars Vars --> UART_Init UART_Init --> IO_Init IO_Init --> Logo Logo --> Storage Storage --> Periph Periph --> Middle Middle --> Test["硬件自检: 核心存储读写测试"] Test --> MainLoop MainLoop --> Cnt Cnt --> IO_P IO_P --> UART_P UART_P --> NET_P NET_P --> Other_P Other_P --> MainLoop ``` --- ## 3. API 手册 ### 3.1 DI/DO 操作 #### 3.1.1 功能使能与引脚定义 ```c #define LED_EN 1 // 开启 LED 驱动 #define DI_EN 1 // 开启输入扫描 (DI1_PIN 等在下方定义) #define DO_EN 1 // 开启输出控制 (DO1_PIN 等在下方定义) #define BUZZER_EN 1 // 开启蜂鸣器 ``` #### 3.1.2 引脚定义 框架支持多达 32 路 DI/DO。可以直接根据硬件原理图修改引脚映射: * **DI 输入**:定义引脚及对应的时钟,例如 `DI1_PIN` 对应 `GPIO_PIN_11`。 * **DO 输出**:定义引脚及初始状态,支持推挽输出配置。 #### 3.1.3 数字输出 (DO / 继电器) | 函数原型 | 功能描述 | 参数说明 | 返回值 | | --- | --- | --- | --- | | **`BSP_DO_Write`** | 控制单路输出状态 | `DOx`: 通道(DO1~DO32),`State`: 1-吸合, 0-释放 | 无 | | **`BSP_DO_WriteAll`** | **高效**批量同步输出 | `Value`: 32位掩码(bit0=DO1) | 无 | | **`BSP_DO_Toggle`** | 翻转指定输出状态 | `DOx`: 通道枚举 | 无 | | **`BSP_DO_Init`** | 初始化 数字输出 | 无| 无 | #### 3.1.4 数字输入 (DI / 开关量) | 函数原型 | 功能描述 | 参数说明 | 返回值 | | --- | --- | --- | --- | | **`BSP_DI_Read`** | 读取单路物理电平 | `DIx`: 通道枚举 (DI1~DI32) | `1`-高电平, `0`-低电平 | | **`BSP_DI_ReadAll`** | **全通道同步读取** | 无 | `uint32_t`: 32路状态掩码 | | **`BSP_DI_Init`** | 初始化 数字输入 | 无 | 无 | #### 3.1.5 指示灯与报警器 (LED & Buzzer) | 函数原型 | 功能描述 | 参数说明 | 返回值 | | --- | --- | --- | --- | | **`BSP_LED_Toggle`** | 翻转 LED (系统心跳灯) | `Led`: LED枚举 (如 LED1) | 无 | | **`BSP_BUZZER_On`** | 开启蜂鸣器 | 无 | 无 | | **`BSP_BUZZER_Toggle`** | 间歇鸣叫控制 | 无 | 无 | --- ### 3.2 UART 串口操作 #### 3.2.1 功能使能与配置定义 在 `AMKN86xx_Config.h` 中,通过宏定义控制各路串口的使能、波特率及功能开关: ```c #define UART1_EN 1 // 开启 UART1 #define UART1_BAUD 115200 // 设置波特率 #define UART1_RX_EN 1 // 开启接收功能 #define UART1_TX_EN 1 // 开启发送功能 ``` #### 3.2.2 端口定义 * **串口 ID**:使用 `UART1_ID` 到 `UART10_ID(UART1~UART10,具体取决于 MCU 型号)` 标识不同的物理端口。 * **缓冲区配置**:每个串口拥有独立的发送/接收环形缓冲区,大小由 `UARTx_TXBUF_SIZE` 宏决定。 #### 3.2.3 串口基础操作 | 函数原型 | 功能描述 | 参数说明 | 返回值 | | --- | --- | --- | --- | | **`BSP_UART_Init`** | 初始化 串口 | `UART_ID`: 串口 ID (UART1_ID ~ UART10_ID) | `0`-成功, `1`-失败 | | **`BSP_UART_Write`** | 向指定串口发送数据 | `UART_ID`: 串口 ID, `pData`: 数据指针, `Len`: 发送长度 | 无 | | **`BSP_UART_Read`** | 从接收缓冲区读取数据 | `UART_ID`: 串口 ID, `pData`: 存储指针, `Len`: 读取长度 | `uint32_t`: 实际读取到的字节数 | | **`BSP_UART_GetRxLength`** | 获取当前接收缓冲区数据长度 | `UART_ID`: 串口 ID | `uint32_t`: 缓冲区待处理字节数 | #### 3.2.4 缓冲区管理 | 函数原型 | 功能描述 | 参数说明 | 返回值 | | --- | --- | --- | --- | | **`BSP_UART_ClearRxBuffer`** | 清空指定串口的接收缓冲区 | `UART_ID`: 串口 ID | 无 | | **`BSP_UART_ClearTxBuffer`** | 清空指定串口的发送缓冲区 | `UART_ID`: 串口 ID | 无 | | **`BSP_UART_GetTxStatus`** | 检查当前发送是否完成 | `UART_ID`: 串口 ID | `1`-空闲, `0`-忙碌 | --- ### 3.3 CAN 通信操作 #### 3.3.1 功能使能与参数定义 ```c #define CAN1_EN 1 // CAN1使能, 1:打开, 0:关闭 #define CAN1_BAUD 1000000 // CAN1波特率 (1Mbps) #define CAN1_SCAN_T 10 // 接收轮询扫描时间间隔 (ms) #define CAN1_TX_T 1000 // 应用层自动发送测试数据的时间间隔 (ms) #define CAN2_EN 1 // CAN2使能 #define CAN2_BAUD 1000000 // CAN2波特率 (1Mbps) ``` #### 3.3.2 引脚与硬件定义 * **CAN ID**:使用 `CAN1_ID` 和 `CAN2_ID` 标识不同的物理端口。 * **硬件接口**:STM32H7 系列采用 FDCAN 控制器,支持经典 CAN 和 CAN FD 协议。 #### 3.3.3 CAN 基础操作 | 函数原型 | 功能描述 | 参数说明 | 返回值 | | --- | --- | --- | --- | | **`BSP_CAN_Init`** | 初始化 CAN | `CAN_ID`: 通道 ID (`CAN1_ID`/`CAN2_ID`) | `0`-成功, `1`-失败 | | **`BSP_CAN_Write`** | 发送一条 CAN 消息 | `CAN_ID`: 通道 ID, `pTxMsg`: 发送结构体指针 (`CAN_TX_MSG`) | `0`-成功, `1`-失败 | | **`BSP_CAN_Read`** | 从接收缓冲区读取数据 | `CAN_ID`: 通道 ID, `pRxMsg`: 接收结构体指针 (`CAN_RX_MSG`) | `0`-成功, `1`-无数据 | | **`BSP_CAN_GetRxMsgNum`** | 获取当前缓冲区未读消息数 | `CAN_ID`: 通道 ID | `uint32_t`: 消息数量 | #### 3.3.4 消息结构定义 | 结构体名称 | 核心成员说明 | 备注 | | --- | --- | --- | | **`CAN_TX_MSG`** | `TxHeader`: 发送属性 (ID/长度/格式), `Data[8]`: 8字节数据 | 用于 `BSP_CAN_Write` | | **`CAN_RX_MSG`** | `RxHeader`: 接收属性 (ID/时间戳/长度), `Data[8]`: 8字节数据 | 用于 `BSP_CAN_Read` | --- ### 3.4 ADC 操作 #### 3.4.1 功能使能与参数定义 ```c #define ADC_EN 1 // ADC 全局使能 (1:开启, 0:关闭) #define AI_NUM 8 /* AI 输入端口数量 */ #define AI_SCAN_T 1000 // 定时扫描处理周期 (单位: ms) #define ADC_AVGNUM 4 // 采样平均次数 (范围 1~64,用于平滑滤波) #define ADC_SAMPLE_TIME ADC_SAMPLETIME_1CYCLE_5 // 采样间隔配置 ``` #### 3.4.2 量程与引脚配置 框架支持对每一路 AI 通道进行独立的使能和量程设置。量程(Range)定义了数据的转换逻辑: * **通道使能**:通过 `AIx_EN` 宏控制(如 `AI1_EN` 至 `AI8_EN`)。 * **量程配置**:支持多种模式,由 `AIx_RANGE` 宏指定: * `0`: 原始采样值 (0~4095) * `1`: 0~+10V * `2`: -10V~+10V * `3`: 0~5V * `5`: 0~+20mA #### 3.4.3 核心 API | 函数原型 | 功能描述 | 参数说明 | 返回值 | | --- | --- | --- | --- | | **`BSP_ADC_Init`** | 初始化 ADC, DMA | 无 | `0`: 成功, `1`: 失败 | | **`BSP_ADC_Read`** | 从缓冲区读取滤波后的各通道采样值 | `pBuf`: 指向存储数组的指针, `len`: 读取通道的数量 | `0`: 成功, `1`: 失败 | | **`BSP_ADC_DMA_Start`** | 启动 ADC 的 DMA 连续采样模式 | 无 | `0`: 成功, `1`: 失败 | | **`BSP_ADC_DMA_Abort`** | 停止 ADC 的 DMA 采样 | 无 | `0`: 成功, `1`: 失败 | --- ### 3.5. DAC 操作 #### 3.5.1 功能使能与参数定义 ```c #define DAC1_EN 1 // DAC1使能 (AO1) #define DAC1_MODE 0 // 模式: 0-手动输出; 1-单次波形; 2-持续波形 #define DAC1_FREQ 1000 // 自动输出频率 (Hz) #define DAC1_SCAN_T 1000 // 定时扫描时间间隔 (ms) #define DAC2_EN 1 // DAC2使能 (AO2) #define DAC2_MODE 0 // 模式同上 ``` #### 3.5.3 核心 API (严格对齐源码) | 函数原型 | 功能描述 | 参数说明 | 返回值 | | --- | --- | --- | --- | | **`BSP_DAC_Init`** | 初始化 DAC | 无 | `0`-成功, `1`-失败 | | **`BSP_DAC_Start`** | 开启指定通道的 DAC 输出转换 | `id`: 通道 ID (`AO1_ID`/`AO2_ID`) | `0`-成功, 其他-失败 | | **`BSP_DAC_Stop`** | 关闭指定通道的 DAC 输出转换 | `id`: 通道 ID | `0`-成功, 其他-失败 | | **`BSP_DAC_SetValue`** | **手动输出模式**:设置 12 位数值 | `id`: 通道 ID, `Value`: 0~4095 | `0`-成功, 其他-失败 | | **`BSP_DAC_SetWave`** | **波形模式**:启动 DMA 循环发送数据 | `id`: ID, `pData`: 数据指针, `Length`: 长度 | `0`-成功, 其他-失败 | | **`BSP_DAC_Ctrl`** | DAC 综合控制接口 (调频、启停) | `id`: 通道 ID, `Cmd`: 命令枚举, `Value`: 参数 | `0`-成功, 其他-失败 | ### 3.6. PWM 操作 #### 3.6.1 功能使能与参数定义 ```c #define PWM1_EN 1 // PWM1 使能 (TIM1) #define PWM1_FREQ 1000 // 初始频率 1kHz #define PWM1_RATE 500 // 初始占空比 50.0% (范围 0~1000) #define PWM_SCAN_T 3000 // 应用层自动调整输出的周期 (ms) ``` #### 3.6.3 核心 API (驱动层接口) | 函数原型 | 功能描述 | 参数说明 | | --- | --- | --- | | **`BSP_PWM_Init`** | 初始化 PWM| 无 | | **`BSP_PWM_Start`** | 开启指定通道的 PWM 输出 | `pwm_id`: PWM1~4_ID, `Channel`: 通道1~4 | | **`BSP_PWM_Stop`** | 停止指定通道的 PWM 输出 | `pwm_id`, `Channel` | | **`BSP_PWM_ConfigFreq`** | 动态修改 PWM 的输出频率 | `pwm_id`, `PWM_Freq` (Hz) | | **`BSP_PWM_ConfigDutyCycle`** | 修改占空比 | `pwm_id`, `Channel`, `PWM_Rate` (0-1000) | | **`BSP_PWM_Set`** | 一键设置频率与四个通道的占空比 | `pwm_id`, `Freq`, `Rate` | --- ### 3.7. FCLK 操作 #### 3.7.1 功能模式定义 | 模式编号 | 模式名称 | 功能描述 | 有效通道 | | --- | --- | --- | --- | | **0** | `FCLK_MODE_COUNT` | **计数模式**:记录脉冲总数 | CH1 | | **1** | `FCLK_MODE_DECODE` | **编码器模式**:支持正交编码器 A/B 相计数 | CH1(A), CH2(B) | | **2** | `FCLK_MODE_FREQ` | **测频模式**:测量输入信号频率 (Hz) | CH1~CH4 | | **3** | `FCLK_MODE_PWMRATE` | **占空比测量**:测量脉冲的占空比百分比 | CH1 | #### 3.7.3 核心 API (驱动层接口) | 函数原型 | 功能描述 | | --- | --- | | **`BSP_FCLK_Init`** | 初始化 FCLK 对应的定时器硬件及 GPIO 模式。 | | **`BSP_FCLK_ReadCount`** | 读取计数模式下的脉冲计数值。 | | **`BSP_FCLK_ReadFreq`** | 读取指定通道的实时频率值(单位:Hz)。 | | **`BSP_FCLK_ReadPwmRate`** | 读取指定通道的 PWM 占空比(0~1000 代表 0.0%~100.0%)。 | ### 3.9. I2C 操作 #### 3.9.1 功能模式 #### 3.9.2 核心 API 定义 | 函数原型 | 功能描述 | 参数说明 | 返回值 | | --- | --- | --- | --- | | **`BSP_I2C_Init`** | 初始化 I2C | `I2C_ID`: 实例ID (如 `I2C1_ID`) | `HAL_StatusTypeDef`: 状态 (0为OK) | | **`BSP_I2C_WriteData`** | 向寄存器写入单字节 | `I2C_ID`: 实例ID,`Addr`: 设备地址,`Reg`: 寄存器地址,`Value`: 写入数据 | `HAL_StatusTypeDef`: 状态 | | **`BSP_I2C_WriteBuffer`** | **批量写入** 数据流 | `I2C_ID`: 实例ID,Addr`: 设备地址,Reg`: 起始地址,`RegSize`: 地址宽度 (8/16Bit),pBuffer`: 数据指针,`Length`: 长度 | `HAL_StatusTypeDef`: 状态 | | **`BSP_I2C_ReadData`** | 读取单字节数据 | `I2C_ID`: 实例ID,`Addr`: 设备地址,`Reg`: 寄存器地址 | `uint8_t`: 读取到的数值 | | **`BSP_I2C_ReadMultiple`** | **批量读取** 寄存器 | `I2C_ID`: 实例ID,`Addr`: 设备地址,`Reg`: 起始地址,`MemAddress`: 地址宽度,`Buffer`: 接收缓存指针,`Length`: 读取长度 | `HAL_StatusTypeDef`: 状态 | | **`BSP_I2C_IsDeviceReady`** | 检查设备是否在线 | `I2C_ID`: 实例ID,`DevAddress`: 设备地址,`Trials`: 尝试次数 | `HAL_StatusTypeDef`: 状态 | --- #### 3.9.3 关键参数说明 * **`I2C_ID`**: 对应硬件物理接口。 * `I2C1_ID`: 外部扩展。 * `I2C2_ID`: 通常连接板载 EEPROM。 * **`RegSize / MemAddress`**: * `I2C_MEMADD_SIZE_8BIT`: 寄存器地址为 8 位。 * `I2C_MEMADD_SIZE_16BIT`: 寄存器地址为 16 位(如大容量 EEPROM)。 * **`I2cxTimeout`**: 驱动内部默认定义为 `I2C_TIMEOUT_MAX`,确保在硬件链路异常时不会导致程序死锁。 ### 3.3. SPI 接口操作 #### 3.3.1 功能使能与配置定义 在驱动头文件及配置文件中,通过宏定义精确控制三路 SPI 接口的硬件使能、DMA 模式及超时机制: * **硬件开关**:通过 `SPI1_EN`、`SPI2_EN`、`SPI3_EN` 控制各路 SPI 是否编译进系统。 * **DMA 支持**:每路接口均可独立开启 DMA 加速(如 `SPI1_DMA_EN`),用于大数据量的高速传输。 * **超时控制**:定义 `SPIx_TIMEOUT_MAX`(默认 1000ms),防止由于硬件链路故障导致的程序死锁。 #### 3.3.2 核心 API 定义 | 函数原型 | 功能描述 | 参数说明 | 返回值 | | --- | --- | --- | --- | | **`BSP_SPI_Init`** | 初始化 SPI | `SPI_ID`: 实例 ID (`SPI1_ID` ~ `SPI3_ID`) | `HAL_StatusTypeDef`: 状态 | | **`BSP_SPI_WriteData`** | **单向发送** 数据流 | `SPI_ID`: 实例 ID, `Data`: 数据指针, `DataLength`: 长度 | `HAL_StatusTypeDef`: 状态 | | **`BSP_SPI_ReadData`** | **单向接收** 数据流 | `SPI_ID`: 实例 ID, `Data`: 接收缓存指针, `DataLength`: 长度 | `HAL_StatusTypeDef`: 状态 | | **`BSP_SPI_WriteReadData`** | **全双工** 同时读写 | `SPI_ID`: 实例 ID, `DataIn`: 发送指针, `DataOut`: 接收指针, `DataLength`: 长度 | `HAL_StatusTypeDef`: 状态 | | **`BSP_SPI_SetSpeed`** | **动态切换** 时钟速率 | `SPI_ID`: 实例 ID, `val`: `1`(高速 9MHz) / `0`(低速) | `HAL_StatusTypeDef`: 状态 | | **`SPI_APPInit`** | 批量初始化已启用的 SPI | 无 | 无 | #### 3.3.4 关键特性说明 * **工作模式**:默认配置为 **主机模式 (Master)**、**双线全双工**、**8位数据宽度**。 * **时钟极性/相位**:采用 **CPOL=1 (High)**,**CPHA=1 (2Edge)** 配置,数据在第二个边沿进行采样。 * **错误自愈机制**:内部封装 `SPI_Error` 函数,在通信返回非 `HAL_OK` 状态时,会自动尝试 `HAL_SPI_DeInit` 并重新执行 `BSP_SPI_Init` 以恢复总线。 * **并发保护**:通过 `SPI_InitFlag` 标志位确保初始化逻辑在系统运行期间仅执行一次,避免资源冲突。 --- ### 3.10 RTC 实时时钟操作 #### 3.10.1 功能使能与配置 在工程配置文件中,通过宏定义控制 RTC 的硬件使能及任务扫描周期: ```c #define RTC_EN 1 // RTC 硬件功能使能开关 #define RTC_SCAN_T 1000 // 定时扫描/读取间隔 (单位: ms) ``` #### 3.10.2 核心 API 定义 驱动程序提供了完整的日期时间设置、读取以及备份寄存器(BKP)的操作接口: | 函数原型 | 功能描述 | 参数说明 | 返回值 | | --- | --- | --- | --- | | **`BSP_RTC_Init`** | 初始化 RTC | 无 | `HAL_StatusTypeDef`: 0为OK | | **`BSP_RTCSetDateTime`** | **设置** 系统日期与时间 | `rtc`: 指向 `RTC_TIME` 结构体的指针 | `HAL_StatusTypeDef`: 状态 | | **`BSP_RTCGetDateTime`** | **读取** 当前日期与时间 | `rtc`: 存储结果的 `RTC_TIME` 结构体指针 | `HAL_StatusTypeDef`: 状态 | | **`BSP_RTC_WriteBackUpFlag`** | 向备份寄存器写入数据 | `BackUpReg`: 寄存器索引, `BackUpFlag`: 写入值 | 无 | | **`BSP_RTC_ReadBackUpFlag`** | 从备份寄存器读取数据 | `BackUpReg`: 寄存器索引 | `uint32_t`: 寄存器存储的数值 | --- #### 3.10.3 关键结构体与参数说明 * **`RTC_TIME` 结构体定义**: 用于统一管理日期和时间数据: * `year`: 年份(相对 2000 年,如 2026 年传 26) * `month`: 月份 (1-12) * `day`: 日期 (1-31) * `hour`: 小时 (0-23) * `minute`: 分钟 (0-59) * `second`: 秒钟 (0-59) * `weekday`: 星期 (1=周一 ~ 7=周日) ### 3.11 SDIO/SD 卡操作 #### 3.11.1 功能模式与配置定义 ```c #define SDCARD_EN 1 // SD卡功能使能 (1: 开启, 0: 关闭) #define SD_SCAN_T 10 // 定时检测/扫描周期 (单位: ms) // 工作模式选择 #define SD_MODE_SDCARD 0 // 标准 SD 卡模式 #define SD_MODE_NAND_FLASH 1 // NAND Flash 模式 #define SD_MODE SD_MODE_NAND_FLASH ``` #### 3.11.3 核心 API 定义 | 函数原型 | 功能描述 | 参数说明 | 返回值 | | --- | --- | --- | --- | | **`BSP_SD_Init`** | 初始化 SDMMC 外设及 SD 卡 | 无 | `HAL_StatusTypeDef`: 0为OK | | **`BSP_SD_ReadBlocks`** | **读取数据块**(同步) | `pData`: 缓存指针, `ReadAddr`: 块地址, `NumOfBlocks`: 块数量, `Timeout`: 超时时间 | `uint8_t`: 0为成功 | | **`BSP_SD_WriteBlocks`** | **写入数据块**(同步) | `pData`: 缓存指针, `WriteAddr`: 块地址, `NumOfBlocks`: 块数量, `Timeout`: 超时时间 | `uint8_t`: 0为成功 | | **`BSP_SD_Erase`** | 擦除指定范围的数据块 | `StartAddr`: 起始地址, `EndAddr`: 结束地址 | `uint8_t`: 0为成功 | | **`BSP_SD_GetCardState`** | 获取当前卡传输状态 | 无 | `uint8_t`: 0-就绪, 1-忙碌 | | **`BSP_SD_Ctrl`** | SD 卡综合控制/查询接口 | `Cmd`: 控制命令, `pData`: 数据指针 | `uint8_t`: 执行结果 | --- #### 3.11.4 关键参数与应用说明 * **传输配置**: * **时钟频率**:默认分频系数 `ClockDiv = 2`。 * **流控**:开启硬件流控 (`HardwareFlowControl`)。 * **总线宽度**:4位模式 (`BusWide = 4B`)。 * **状态识别**: * `MSD_OK (0x00)`: 操作正常。 * `MSD_ERROR (0x01)`: 通信异常。 * `MSD_ERROR_SD_NOT_PRESENT (0x02)`: 未检测到卡。 * **应用逻辑**: * 在 `SD_Proc` 处理任务中,驱动会根据 `SD_SCAN_T` 定时检查卡状态。 * 检测到卡插入后,自动执行 `SD_test()` 进行读写校验,并通过串口输出 `AT+SD=OK` 或 `AT+SD=ERROR` 信息。 ### 3.14 USBH 操作 本模块驱动基于 STM32H7 的 **USB OTG HS** 硬件,配置为 **MSC (Mass Storage Class)** 主机模式。驱动通过状态机管理 U 盘的从物理连接、枚举到原始扇区通信的全过程,不依赖外部文件系统库。 --- #### 3.14.3 核心 API 定义 | 函数原型 | 功能描述 | 参数说明 | 返回值 | | --- | --- | --- | --- | | **`MX_USB_HOST_Init`** | 初始化 USB 主机库 | 无 | 无 | | **`MX_USB_HOST_Process`** | **主机任务进程轮询** | 无 | 无 | | **`USBH_MSC_Read`** | **读取 U 盘原始扇区** | `phost`: 句柄, `lun`: 单元号, `address`: 扇区地址, `pbuf`: 缓存, `length`: 扇区数 | `USBH_StatusTypeDef` | | **`USBH_MSC_Write`** | **写入 U 盘原始扇区** | `phost`: 句柄, `lun`: 单元号, `address`: 扇区地址, `pbuf`: 数据源, `length`: 扇区数 | `USBH_StatusTypeDef` | | **`USBH_MSC_GetLUNInfo`** | 获取磁盘物理参数 | `phost`: 句柄, `lun`: 单元号, `info`: 存储结构体指针 | `USBH_StatusTypeDef` | | **`USBH_MSC_IsReady`** | 检查磁盘是否准备就绪 | `phost`: 主机句柄, `lun`: 逻辑单元号 | `1`: 就绪, `0`: 未就绪 | --- #### 3.14.4 应用逻辑与状态管理 * **状态机运行机制**: USB Host 的核心逻辑由 `MX_USB_HOST_Process()` 驱动,必须在主循环中持续调用。其内部 `Appli_state` 决定了当前应用层可执行的操作: * `APPLICATION_IDLE`: 等待 U 盘插入。 * `APPLICATION_START`: 硬件层检测到连接,开始 USB 枚举。 * `APPLICATION_READY`: **关键状态**。此时 MSC 类已激活,允许调用 Read/Write 函数进行数据交换。 * `APPLICATION_DISCONNECT`: U 盘被拔出,驱动自动重置状态机并释放资源。 * **应用测试逻辑**: 在 `USBH_Proc` 任务中,驱动会实时监控连接状态。一旦检测到状态切换至 `APPLICATION_READY`,会自动触发 `UDisk_Test()`。 * **读写校验**:通过原始块读写测试 U 盘的稳定性。 * **结果输出**:成功则串口打印 `AT+UDISK=OK`,并置位 `UDISK_OK_FLAG`;失败则输出 `AT+UDISK=ERROR`。 ### 3.12 SDRAM 操作 #### 3.12.1 功能使能与地址映射 ```c #define SDRAM_ADDR ((uint32_t)0xC0000000) // SDRAM 起始地址 (Bank 5/6) #define SDRAM_SIZE (32 * 1024 * 1024) // SDRAM 总容量 (32MB) // 显存与应用缓冲区分配 #define SDRAM_LCD_BUF1 ((uint16_t*)SDRAM_ADDR) #define SDRAM_LCD_SIZE (4 * 1024 * 1024) // 每层显存大小 (4MB) #define SDRAM_APP_BUF (SDRAM_ADDR + 8*1024*1024) // 应用数据起始地址 ``` #### 3.12.2 内存布局划分 | 区域名称 | 起始地址 | 偏移大小 | 典型用途 | | --- | --- | --- | --- | | **LCD_BUF1** | `0xC0000000` | 4MB | 显存第 1 层 (Layer 1) | | **LCD_BUF2** | `0xC0040000` | 4MB | 显存第 2 层 (Layer 2) | | **APP_BUF** | `0xC0080000` | 24MB | 应用程序通用缓冲区 | #### 3.12.3 核心 API 定义 | 函数原型 | 功能描述 | 参数说明 | 返回值 | | --- | --- | --- | --- | | **`SDRAM_APPInit`** | 初始化 SDRAM | 无 | 无 | | **`BSP_Sdram_Write`** | 批量写入数据 | `addr`: 目标地址, `pbuf`: 源数据指针, `size`: 字节数 | 无 | | **`BSP_Sdram_Read`** | 批量读取数据 | `addr`: 起始地址, `pbuf`: 接收指针, `size`: 字节数 | 无 | | **`BSP_Sdram_Clear`** | 快速填充/清零 | `addr`: 起始地址, `size`: 长度, `data`: 填充值 | 无 | | **`BSP_FMC_SDRAM_Test`** | 内存读写校验测试 | `test_addr`: 测试地址, `test_size`: 测试长度 | `0`-成功, `-1`-失败 | --- ### 3.13 LTDC 液晶屏操作 #### 3.13.1 核心配置与型号适配 驱动通过宏定义实现对不同分辨率屏幕及显示方向的快速适配,主要参数如下: * **型号定义 (`LCD_PRODUCT`)**: * `0`: ATK-MD0700R (800x480 分辨率) * `1`: ATK-MD0700R (1024x600 分辨率) * **显示旋转 (`LCD_DISP_TYPE`)**:支持 0°、90°、180°、270° 四种显示方向切换。 * **扫描周期 (`LTDC_SCAN_T`)**:默认 `100ms`,用于应用层界面刷新或状态检查。 #### 3.13.2 液晶屏硬件时序 (Timing) 驱动内置了精准的消隐区时序参数(以 800x480 为例),确保图像在屏幕上精确居中且无闪烁: | 时序参数 | 缩写 | 参考值 | 功能说明 | | --- | --- | --- | --- | | **Horizontal Sync** | HSYNC | 20 | 行同步脉冲宽度 | | **Horizontal Back Porch** | HBP | 46 | 行显示后肩(左边框) | | **Horizontal Front Porch** | HFP | 210 | 行显示前肩(右边框) | | **Vertical Sync** | VSYNC | 10 | 帧同步脉冲宽度 | | **Vertical Back Porch** | VBP | 23 | 帧显示后肩(顶边框) | | **Vertical Front Porch** | VFP | 22 | 帧显示前肩(底边框) | #### 3.13.3 图层架构与显存管理 驱动采用**外部 SDRAM** 作为显存(Frame Buffer),支持硬件双图层管理: * **图层 1 (Layer 1)**:全屏背景层。 * **像素格式**:`RGB565`(每个像素 16 位,平衡画质与带宽)。 * **起始地址**:`0xC0000000` (SDRAM 起始位置)。 * **Alpha 混合**:默认 `0xFF`(不透明),支持硬件级透明度调节。 * **显存隔离**:每个图层分配 `2MB` 独立空间 (`LTDC_BUFFER_SIZE`),有效防止多图层操作时的显存溢出。 --- #### 3.13.4 核心 API 接口定义 | 函数原型 | 功能描述 | 参数说明 | 返回值 | | --- | --- | --- | --- | | **`BSP_LTDC_Init`** | **初始化 LTDC** | 无 | 无 | | **`LCD_ClearScreen`** | **全屏清屏** | `color`: 填充的颜色值 (RGB565) | 无 | | **`LCD_DrawPixel`** | **绘制点** | `x`: X坐标, `y`: Y坐标, `color`: 颜色 | 无 | | **`LCD_ReadPixel`** | **读取点颜色** | `x`: X坐标, `y`: Y坐标 | `uint16_t`: 颜色值 | | **`LCD_FillRect`** | **矩形填充** | `x0, y0`: 左上角坐标; `x1, y1`: 右下角坐标; `color`: 颜色 | 无 | | **`LCD_DrawLine`** | **绘制直线** | `x1, y1`: 起点; `x2, y2`: 终点; `color`: 颜色 | 无 | | **`LCD_DrawRect`** | **绘制矩形框** | `x1, y1`: 左上角; `x2, y2`: 右下角; `color`: 颜色 | 无 | | **`LCD_DrawCircle`** | **绘制圆环** | `x0, y0`: 圆心坐标; `r`: 半径; `color`: 颜色 | 无 | | **`LCD_DispChar`** | **显示字符** | `x, y`: 坐标; `num`: 字符ASCII码; `size`: 字号; `color`: 颜色 | 无 | | **`LCD_DispString`** | **显示字符串** | `x, y`: 坐标; `width, height`: 区域限制; `size`: 字号; `p`: 字符串指针; `color`: 颜色 | 无 | | **`LCD_DispNum`** | **显示数字** | `x, y`: 坐标; `num`: 数值; `len`: 位数; `size`: 字号; `color`: 颜色 | 无 | | **`LCD_DispBmp`** | **显示位图** | `_usX, _usY`: 坐标; `_usWidth, _usHeight`: 宽高; `_ptr`: 图片数据指针 | 无 | | **`BSP_LTDC_QuitWinMode`** | **退出窗口模式** | `width, height`: 屏幕宽高; `layer`: 图层索引 | 无 | --- ### 3.12 QSPI 操作 本驱动针对 STM32H7 的 **QUADSPI** 外设进行了 BSP 级封装。它不仅支持标准的 SPI 指令发送,还通过配置控制逻辑,实现了对外部 Flash 芯片的高速间接访问。 --- #### 3.12.3 核心 API 定义 以下 API 屏蔽了复杂的 HAL 库句柄配置,直接面向数据传输和指令交互: | 函数原型 | 功能描述 | 参数说明 | 返回值 | | --- | --- | --- | --- | | **`QSPI_AppInit`** | **QSPI 外设初始化** | 无 | 无 | | **`QSPI_SendCommand`** | **发送 QSPI 指令** | `cmd`: 指令结构体指针, `timeout`: 超时时间 | `int`: 0为成功 | | **`QSPI_WriteBlocking`** | **发送数据流** | `data`: 源数据指针, `timeout`: 超时时间 | `int`: 0为成功 | | **`QSPI_ReadBlocking`** | **接收数据流** | `data`: 接收缓存指针, `timeout`: 超时时间 | `int`: 0为成功 | | **`QSPI_SetSpeed`** | **修改时钟频率** | `val`: 分频系数 (如 `QSPI_DIVCLK_4`) | 无 | --- #### 3.12.4 QSPI 指令传输逻辑 (Command Structure) QSPI 的操作核心在于 **`QSPI_CommandTypeDef`** 结构体。不同于传统 SPI 只发字节,QSPI 的一次通信被划分为五个阶段,BSP 通过配置这些阶段来适配不同的 Flash 协议: 1. **指令阶段 (Instruction)**:定义操作码(如读 ID、擦除)。 2. **地址阶段 (Address)**:发送目标存储地址(支持 24 位或 32 位)。 3. **交替字节阶段 (Alternate Bytes)**:用于某些 Flash 的连续读取模式设置。 4. **空周期阶段 (Dummy Cycles)**:在高速读取时,给 Flash 留出切换总线方向的时间(本驱动中双线读取通常设为 `4`)。 5. **数据阶段 (Data)**:实际承载读取或写入的载荷。 --- #### 3.12.5 应用逻辑与物理配置 * **双线模式逻辑**: 根据 `QSPI_IOMODE_2_LINES` 的配置,驱动在地址和数据阶段会启用两根数据线(IO0, IO1)同时传输。这使得带宽比标准单线 SPI 提升了一倍,同时相比四线模式具有更好的电磁兼容稳定性。 * **时钟稳定性调整**: 驱动中定义了多种分频系数。根据最新的工程反馈,设置 `QSPI_DIVCLK` 为 `4`(4分频)是兼顾 H7 高主频与外部 Flash 建立/保持时间的最佳平衡点。 * **间接模式 (Indirect Mode)**: BSP 采用的是“间接模式”。其逻辑是:CPU 将指令、地址和长度填入 QSPI 寄存器后,硬件自动控制 CS 线、产生时钟并完成数据交换。这种方式比软件模拟 SPI 引脚速度快数十倍。 * **Cache 一致性管理**: 由于 QSPI 常结合 DMA 使用,BSP 在高层逻辑中确保了在读取数据前会对相关内存区域进行 Cache 无效化(Invalidate),防止 CPU 读到过期的旧缓存数据。 --- ### 3.12 QSPI Flash 存储操作 本模块基于 STM32H7 的 **QUADSPI (QSPI)** 接口实现,专门用于驱动外部 NorFlash(如 GD25Q64)。驱动支持单线、双线模式,利用 QSPI 的间接模式实现高速数据读写,并集成了自动轮询(Auto-polling)机制以优化写入效率。 --- #### 3.12.3 核心 API 定义 | 函数原型 | 功能描述 | 参数说明 | 返回值 | | --- | --- | --- | --- | | **`QSPI_AppInit`** | **初始化 QSPI 外设** | 无 | 无 | | **`BSP_W25QXX_Init`** | **初始化 Flash 芯片** | 无 | 无 | | **`BSP_W25QXX_Read`** | **读取数据** (2线模式) | `ReadAddr`: 地址, `NumByteToRead`: 长度, `pBuffer`: 接收缓存 | 无 | | **`BSP_W25QXX_Write`** | **写入数据** (页编程) | `pBuffer`: 数据源, `WriteAddr`: 地址, `NumByteToWrite`: 长度 | 无 | | **`BSP_W25QXX_SectorErase`** | **扇区擦除** (4KB) | `SectorAddr`: 扇区起始地址 | 无 | | **`BSP_W25QXX_ReadID`** | **读取芯片 ID** | 无 | `uint32_t`: 制造商及器件ID | | **`QSPI_SendCommand`** | **发送自定义命令** | `cmd`: 命令结构体, `timeout`: 超时时间 | `int`: 0为成功 | --- #### 3.12.4 关键参数与应用说明 * **传输配置**: * **时钟分频**:`QSPI_DIVCLK_4`。根据 2025.10.12 的优化建议,4分频在高速通信下更为稳定。 * **IO模式**:`QSPI_IOMODE_2_LINES`(双线模式)。在 `BSP_W25QXX_Read` 中使用 1-2-2 模式(1线指令、2线地址、2线数据),平衡了速度与稳定性。 * **容量定义**:固定为 `8MB` (`QSPI_FLASH_SIZE_8MB`),匹配 GD25Q64。 * **硬件机制优化**: * **自动轮询 (Auto-polling)**:在擦除或编程操作后,驱动调用 `BSP_W25QXX_AutoPollingMemReady()`。该功能利用 QSPI 硬件自动循环读取 Flash 的状态寄存器,直到 `BUSY` 位清零,避免了 CPU 频繁软件查询,显著降低了功耗和 CPU 占用。 * **Dummy Cycles**:在双线快速读取模式下配置了 `4` 个空周期,以确保 Flash 芯片有足够时间从地址切换到数据输出。 * **应用逻辑**: * **写前擦除**:NorFlash 物理特性决定了写入前必须先进行擦除(将 0 变为 1)。通常使用 `BSP_W25QXX_SectorErase` 操作 4KB 扇区。 * **页编程限制**:每次 `BSP_W25QXX_Write` 写入长度建议不超过 256 字节(一页),若超过需分次写入。 ### 3.13 EEPROM 存储 操作 本模块驱动基于 STM32H7 的 **I2C总线** 实现,专门用于驱动外部串行 EEPROM(如 AT24C64)。驱动通过 BSP 层封装,支持跨页连续读写,并集成了硬件忙状态检测机制,确保数据写入的可靠性。 --- #### 3.13.1 核心 API 定义 | 函数原型 | 功能描述 | 参数说明 | 返回值 | | --- | --- | --- | --- | | **`BSP_EEPROM_Init`** | **初始化 EEPROM** | 无 | `0`: 成功; `1`: 失败 | | **`BSP_EEPROM_ReadBuffer`** | **连续读取数据** | `pBuffer`: 接收缓存, `ReadAddr`: 起始地址, `NumByteToRead`: 长度 | `0`: 成功; 其他: 错误 | | **`BSP_EEPROM_WriteBuffer`** | **跨页连续写入** | `pBuffer`: 源数据指针, `WriteAddr`: 起始地址, `NumByteToWrite`: 长度 | `0`: 成功; 其他: 错误 | | **`EEPROM_WritePage`** | **单页写入** | `pBuffer`: 数据, `WriteAddr`: 页起始地址, `NumByteToWrite`: 页内长度 | `0`: 成功 | | **`EEPROM_WaitStandbyState`** | **等待就绪** | 无 | `0`: 芯片空闲; 其他: 忙 | --- #### 3.13.2 关键应用逻辑 1. **跨页写入算法(Multi-page Write)**: EEPROM 物理特性限制单次写入不能超过一页(如 32 字节),且不能跨越页边界。`BSP_EEPROM_WriteBuffer` 内部实现了自动分页逻辑: * 计算起始地址在当前页内的偏移。 * 先填满起始页的剩余空间。 * 循环处理中间的完整页。 * 处理最后一页的剩余字节。 ### 3.15 Ethernet 操作 #### 3.15.1 功能概述与模式配置 本驱动方案基于 **STM32H7 ETH MAC** 外设与 **DP83848 PHY** 芯片,使用 **LwIP (Lightweight IP)** 开源协议栈。它支持无操作系统(NO_SYS)环境下的 Raw API 编程,能够实现 TCP/UDP 的客户端与服务端通信。 通过 `config.h` 中的宏定义,可以灵活配置网络的工作模式: ```c #define LWIP_EN 1 // 协议栈总使能 // 工作模式选择 #define LWIP_WKMODE LWIP_WKMODE_SERVER // 可选: CLIENT(客户端), SERVER(服务端), HTTP(网页) #define LWIP_NETYPE LWIP_NETYPE_TCP // 可选: TCP, UDP // 网络地址配置 (静态IP) #define LOCAL_IP "192.168.1.105" // 本机 IP #define LOCAL_PORT 5000 // 本机端口 #define LOCAL_GATEWAY "192.168.1.1" // 网关地址 // 目标地址配置 (仅客户端模式有效) #define DSC_IP "192.168.1.248" // 目标服务器 IP #define DSC_PORT 5001 // 目标端口 ``` #### 3.15.2 硬件抽象层 (HAL & PHY) 驱动层 `ethernetif.c` 实现了 LwIP 与 STM32H7 硬件的对接,主要特性如下: * **PHY 接口**:使用 **RMII** (Reduced Media Independent Interface) 接口连接 DP83848,减少引脚占用。 * **零拷贝接收 (Zero-Copy RX)**: * 定义了专用内存池 `RX_POOL` 和自定义缓冲区 `RxBuff_t`。 * 接收数据时,DMA 直接将数据传输到 LwIP 的 PBUF 内存池中,避免了 CPU 在内存间的数据搬运,显著提高了吞吐量。 * **DMA 描述符**: * `DMARxDscrTab` 和 `DMATxDscrTab` 被定义在 `DMA_SRAM` 区域(通常为 D2 域的 SRAM),以确保 DMA 控制器可以访问。 * **链路检测**: * `ethernet_link_check_state()` 函数周期性读取 PHY 寄存器。若网线热插拔,驱动会自动停止或重启 MAC 外设,实现链路状态的自适应。 #### 3.15.3 核心应用 API 定义 为了简化 LwIP Raw API 的使用,驱动封装了统一的读写接口,应用层无需直接处理复杂的 PCB (Protocol Control Block) 回调。 **1. 通用初始化** | 函数原型 | 功能描述 | 参数说明 | | --- | --- | --- | | **`ethernetif_init`** | 协议栈底层初始化 | `netif`: LwIP 网络接口结构体 | | **`ethernet_link_check_state`** | 物理链路状态机维护 | `netif`: 需在主循环中轮询 | **2. TCP 服务端/客户端 (TCP Echo)** | 函数原型 | 功能描述 | 适用模式 | | --- | --- | --- | | **`tcp_echoserver_init`** | 创建 TCP 监听,绑定本地端口 | TCP Server | | **`tcp_echoclient_connect`** | 连接指定 IP 和端口的服务器 | TCP Client | | **`TCP_Server_Read`** | 从接收缓冲区读取数据 | TCP Server | | **`TCP_Server_Write`** | 发送数据到已连接的客户端 | TCP Server | | **`TCP_Client_Read`** | 读取服务器发来的数据 | TCP Client | | **`TCP_Client_Write`** | 发送数据到服务器 | TCP Client | **3. UDP 通信** | 函数原型 | 功能描述 | 适用模式 | | --- | --- | --- | | **`udp_echoserver_init`** | 初始化 UDP 监听 | UDP Server | | **`udp_echoclient_connect`** | 绑定目标 IP 端口 | UDP Client | | **`UDP_Server_Read`** / **`Write`** | UDP 数据读写接口 | UDP Server | | **`UDP_Client_Read`** / **`Write`** | UDP 数据读写接口 | UDP Client | #### 3.15.4 数据流与缓冲机制 应用层的数据收发采用了**双缓冲**或**环形缓冲**策略来解耦 LwIP 回调与用户逻辑: 1. **接收流程 (Rx)**: * LwIP 内核调用 `tcp_recv` 或 `udp_recv` 回调函数。 * 回调函数将 `pbuf` 中的 payload 数据拷贝到全局缓冲区 `recev_buf[NET_RECEIVE_BUF_SIZE]` (默认 2KB)。 * 更新 `recev_data_len` 和 `recev_count` 标志位。 * 用户调用 `XXX_Read` 函数从 `recev_buf` 取走数据。 2. **发送流程 (Tx)**: * 用户调用 `XXX_Write` 函数。 * 驱动申请一个新的 `pbuf`,将用户数据填入。 * 调用 LwIP 原生接口 `tcp_write` 或 `udp_send` 将数据推入发送队列。 * 对于 TCP,驱动会处理 `ERR_MEM` (内存不足) 等情况,并在 `tcp_sent` 回调中确认发送完成。 #### 3.15.5 关键配置参数 (`ethernetif.c`) * **`ETH_RX_BUFFER_SIZE`**: 单个 DMA 接收缓冲大小 (1000 Bytes)。 * **`ETH_RX_BUFFER_CNT`**: 接收缓冲数量 (12个)。 * **`ETH_DMA_TRANSMIT_TIMEOUT`**: 发送超时时间 (20ms)。 **注意**:在 STM32H7 上使用以太网时,由于 D-Cache 的存在,DMA 描述符和缓冲区必须放置在无 Cache 区域(如 SRAM1/2/3)或在操作前后执行 Cache Clean/Invalidate 操作。本驱动在 `HAL_ETH_RxLinkCallback` 中已包含 `SCB_InvalidateDCache_by_Addr` 以维护数据一致性。