全面深入理解STM32 HAL库:从入门到精通
全面深入理解STM32 HAL库:从入门到精通
引言:嵌入式开发的演进与HAL库的重要性
在嵌入式系统开发领域,特别是针对ARM Cortex-M系列微控制器的开发,STM32系列芯片以其出色的性能和丰富的外设资源占据了重要地位。随着STM32生态系统的不断发展,ST公司为开发者提供了多种编程库,其中HAL(Hardware Abstraction Layer)库作为新一代的硬件抽象层库,已经成为STM32开发的主流选择。
嵌入式开发库的演进历程
-
标准外设库(Standard Peripheral Library, SPL)
- 最早期的STM32开发库
- 直接寄存器操作封装
- 代码效率高但移植性差
-
Cube HAL库
- 硬件抽象层设计
- 跨STM32系列兼容
- 更高的可移植性和可维护性
-
LL库(Low-Layer Library)
- 轻量级底层库
- 接近寄存器操作的高效率
- 适合对性能要求极高的场景
HAL库的出现标志着STM32开发从"面向寄存器"到"面向外设"的转变,大大降低了开发门槛,提高了代码的复用性和可维护性。
第一章:HAL库架构与设计哲学
1.1 HAL库的整体架构
HAL库采用分层设计,从上到下分为:
应用层(Application)
↓
中间件层(Middleware)
↓
HAL硬件抽象层(Hardware Abstraction Layer)
↓
BSP板级支持包(Board Support Package)
↓
CMSIS Cortex微控制器软件接口标准
↓
硬件层(Hardware)
1.2 HAL库的核心设计理念
抽象与统一:HAL库通过统一的API接口,将不同STM32系列芯片的差异进行抽象,使得同一份代码可以在不同型号的STM32芯片上运行。
状态机驱动:HAL库采用状态机模型管理外设状态,确保外设操作的顺序性和安全性。
中断与回调机制:提供完善的中断处理和回调函数机制,简化中断编程。
1.3 HAL库文件结构详解
// HAL库典型文件结构
STM32Cube_FW_系列名/
├── Drivers/
│ ├── CMSIS/ # ARM Cortex微控制器软件接口标准
│ └── STM32系列名_HAL_Driver/
│ ├── Inc/ # 头文件
│ │ ├── stm32系列名_hal.h
│ │ ├── stm32系列名_hal_conf.h
│ │ └── stm32系列名_hal_xxx.h(各外设头文件)
│ └── Src/ # 源文件
│ ├── stm32系列名_hal.c
│ └── stm32系列名_hal_xxx.c(各外设源文件)
├── Middlewares/ # 中间件
├── Projects/ # 示例项目
└── Utilities/ # 工具和工具
第二章:HAL库开发环境搭建
2.1 STM32CubeMX安装与配置
STM32CubeMX是ST官方提供的图形化配置工具,可以自动生成HAL库基础代码。
安装步骤:
- 访问ST官网下载STM32CubeMX
- 安装Java运行环境(JRE)
- 安装STM32CubeMX本体
- 下载所需的HAL库固件包
2.2 开发工具链选择
# 常见工具链配置示例
# 1. ARM GCC工具链
TOOLCHAIN_PATH = /usr/bin/arm-none-eabi-
CC = $(TOOLCHAIN_PATH)gcc
CXX = $(TOOLCHAIN_PATH)g++
AS = $(TOOLCHAIN_PATH)gcc -x assembler-with-cpp
LD = $(TOOLCHAIN_PATH)gcc
OBJCOPY = $(TOOLCHAIN_PATH)objcopy
SIZE = $(TOOLCHAIN_PATH)size
# 2. IAR Embedded Workbench
# 3. Keil MDK-ARM
2.3 第一个HAL库工程创建
通过STM32CubeMX创建工程的步骤:
- 选择芯片型号
- 配置系统时钟
- 配置外设
- 配置中间件
- 生成代码
生成的工程结构:
/* 自动生成的主函数框架 */
int main(void)
{
/* HAL库初始化 */
HAL_Init();
/* 系统时钟配置 */
SystemClock_Config();
/* 外设初始化 */
MX_GPIO_Init();
MX_USART1_UART_Init();
// ...其他外设初始化
/* 无限循环 */
while (1)
{
/* 用户应用程序 */
}
}
第三章:HAL库核心机制详解
3.1 HAL库初始化流程
/**
* @brief HAL库初始化详细分析
*/
// HAL初始化函数
HAL_StatusTypeDef HAL_Init(void)
{
/* 配置Flash预取指、指令缓存和数据缓存 */
#if (INSTRUCTION_CACHE_ENABLE != 0U)
__HAL_FLASH_INSTRUCTION_CACHE_ENABLE();
#endif
#if (DATA_CACHE_ENABLE != 0U)
__HAL_FLASH_DATA_CACHE_ENABLE();
#endif
#if (PREFETCH_ENABLE != 0U)
__HAL_FLASH_PREFETCH_BUFFER_ENABLE();
#endif
/* 设置中断优先级分组 */
HAL_NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_4);
/* 初始化Tick定时器 */
HAL_InitTick(TICK_INT_PRIORITY);
/* 初始化底层硬件 */
HAL_MspInit();
return HAL_OK;
}
// 系统时钟配置示例
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};
/* 配置主电源电压范围 */
__HAL_RCC_PWR_CLK_ENABLE();
__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
/* 初始化HSE、LSE、HSI等振荡器 */
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLM = 25;
RCC_OscInitStruct.PLL.PLLN = 336;
RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
RCC_OscInitStruct.PLL.PLLQ = 7;
HAL_RCC_OscConfig(&RCC_OscInitStruct);
/* 初始化CPU、AHB、APB总线时钟 */
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;
HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5);
}
3.2 中断管理与回调机制
HAL库采用统一的中断处理框架,通过回调函数实现用户代码与中断处理的解耦。
/**
* @brief HAL库中断处理机制详解
*/
// 外设句柄结构体(以UART为例)
typedef struct __UART_HandleTypeDef
{
USART_TypeDef *Instance; /* 外设寄存器基地址 */
UART_InitTypeDef Init; /* 外设初始化参数 */
uint8_t *pTxBuffPtr; /* 发送缓冲区指针 */
uint16_t TxXferSize; /* 发送数据大小 */
__IO uint16_t TxXferCount; /* 发送计数器 */
uint8_t *pRxBuffPtr; /* 接收缓冲区指针 */
uint16_t RxXferSize; /* 接收数据大小 */
__IO uint16_t RxXferCount; /* 接收计数器 */
DMA_HandleTypeDef *hdmatx; /* 发送DMA句柄 */
DMA_HandleTypeDef *hdmarx; /* 接收DMA句柄 */
HAL_LockTypeDef Lock; /* 锁对象 */
__IO HAL_UART_StateTypeDef gState; /* 全局状态 */
__IO HAL_UART_StateTypeDef RxState; /* 接收状态 */
__IO uint32_t ErrorCode; /* 错误代码 */
} UART_HandleTypeDef;
// 中断处理函数示例
void USART1_IRQHandler(void)
{
HAL_UART_IRQHandler(&huart1);
}
// HAL库统一中断处理函数
void HAL_UART_IRQHandler(UART_HandleTypeDef *huart)
{
uint32_t isrflags = READ_REG(huart->Instance->SR);
uint32_t cr1its = READ_REG(huart->Instance->CR1);
uint32_t errorflags = 0x00U;
/* 处理接收中断 */
if (((isrflags & USART_SR_RXNE) != RESET) &&
((cr1its & USART_CR1_RXNEIE) != RESET))
{
UART_Receive_IT(huart);
return;
}
/* 处理发送中断 */
if (((isrflags & USART_SR_TXE) != RESET) &&
((cr1its & USART_CR1_TXEIE) != RESET))
{
UART_Transmit_IT(huart);
return;
}
/* 错误处理 */
errorflags = (isrflags & (uint32_t)(USART_SR_PE | USART_SR_FE |
USART_SR_ORE | USART_SR_NE));
if ((errorflags != RESET) && ((cr1its & USART_CR1_PEIE) != RESET))
{
huart->ErrorCode |= errorflags;
UART_EndRxTransfer(huart);
}
}
// 回调函数机制
__weak void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
{
/* 弱函数,用户可重写 */
UNUSED(huart);
}
__weak void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
/* 弱函数,用户可重写 */
UNUSED(huart);
}
// 用户自定义回调函数示例
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
if (huart->Instance == USART1)
{
/* 处理USART1接收完成 */
uint8_t received_data = uart_rx_buffer;
process_received_data(received_data);
/* 重新启动接收 */
HAL_UART_Receive_IT(huart, &uart_rx_buffer, 1);
}
}
3.3 状态机与错误处理
HAL库使用状态机跟踪外设状态,确保操作的顺序性。
/**
* @brief HAL库状态机与错误处理机制
*/
// HAL库状态定义
typedef enum
{
HAL_UNINITIALIZED = 0x00U, /* 未初始化 */
HAL_INITIALIZED = 0x01U, /* 已初始化 */
HAL_BUSY = 0x02U, /* 繁忙 */
HAL_BUSY_TX = 0x12U, /* 发送繁忙 */
HAL_BUSY_RX = 0x22U, /* 接收繁忙 */
HAL_BUSY_TX_RX = 0x32U, /* 发送接收都繁忙 */
HAL_TIMEOUT = 0x03U, /* 超时 */
HAL_ERROR = 0x04U, /* 错误 */
HAL_OK = 0x00U /* 正常 */
} HAL_StatusTypeDef;
// 外设特定状态(以UART为例)
typedef enum
{
HAL_UART_STATE_RESET = 0x00U, /* 复位状态 */
HAL_UART_STATE_READY = 0x01U, /* 就绪状态 */
HAL_UART_STATE_BUSY = 0x02U, /* 繁忙状态 */
HAL_UART_STATE_BUSY_TX = 0x12U, /* 发送繁忙 */
HAL_UART_STATE_BUSY_RX = 0x22U, /* 接收繁忙 */
HAL_UART_STATE_BUSY_TX_RX = 0x32U, /* 发送接收都繁忙 */
HAL_UART_STATE_TIMEOUT = 0x03U, /* 超时 */
HAL_UART_STATE_ERROR = 0x04U /* 错误状态 */
} HAL_UART_StateTypeDef;
// 错误代码定义
#define HAL_UART_ERROR_NONE 0x00000000U /* 无错误 */
#define HAL_UART_ERROR_PE 0x00000001U /* 奇偶校验错误 */
#define HAL_UART_ERROR_NE 0x00000002U /* 噪声错误 */
#define HAL_UART_ERROR_FE 0x00000004U /* 帧错误 */
#define HAL_UART_ERROR_ORE 0x00000008U /* 溢出错误 */
#define HAL_UART_ERROR_DMA 0x00000010U /* DMA传输错误 */
// 状态检查宏
#define __HAL_UART_GET_FLAG(__HANDLE__, __FLAG__) \
(((__HANDLE__)->Instance->SR & (__FLAG__)) == (__FLAG__))
#define __HAL_UART_CLEAR_FLAG(__HANDLE__, __FLAG__) \
((__HANDLE__)->Instance->SR = ~(__FLAG__))
// 状态转换函数示例
HAL_StatusTypeDef HAL_UART_Transmit_IT(UART_HandleTypeDef *huart,
uint8_t *pData, uint16_t Size)
{
/* 检查参数有效性 */
if (huart->gState == HAL_UART_STATE_READY)
{
if ((pData == NULL) || (Size == 0U))
{
return HAL_ERROR;
}
/* 进程锁定 */
__HAL_LOCK(huart);
huart->pTxBuffPtr = pData;
huart->TxXferSize = Size;
huart->TxXferCount = Size;
/* 设置状态为发送繁忙 */
huart->gState = HAL_UART_STATE_BUSY_TX;
/* 使能发送中断 */
__HAL_UART_ENABLE_IT(huart, UART_IT_TXE);
/* 进程解锁 */
__HAL_UNLOCK(huart);
return HAL_OK;
}
else
{
return HAL_BUSY;
}
}
第四章:GPIO操作详解
4.1 GPIO初始化与配置
/**
* @brief GPIO配置与操作详解
*/
// GPIO初始化结构体
typedef struct
{
uint32_t Pin; /* 指定要配置的GPIO引脚 */
uint32_t Mode; /* 指定引脚模式 */
uint32_t Pull; /* 指定上拉/下拉电阻 */
uint32_t Speed; /* 指定引脚速度 */
uint32_t Alternate; /* 指定复用功能 */
} GPIO_InitTypeDef;
// GPIO引脚模式
#define GPIO_MODE_INPUT 0x00000000U /* 输入模式 */
#define GPIO_MODE_OUTPUT_PP 0x00000001U /* 推挽输出 */
#define GPIO_MODE_OUTPUT_OD 0x00000011U /* 开漏输出 */
#define GPIO_MODE_AF_PP 0x00000002U /* 复用推挽 */
#define GPIO_MODE_AF_OD 0x00000012U /* 复用开漏 */
#define GPIO_MODE_ANALOG 0x00000003U /* 模拟模式 */
#define GPIO_MODE_IT_RISING 0x10110000U /* 上升沿中断 */
#define GPIO_MODE_IT_FALLING 0x10210000U /* 下降沿中断 */
#define GPIO_MODE_IT_RISING_FALLING 0x10310000U /* 双边沿中断 */
#define GPIO_MODE_EVT_RISING 0x10120000U /* 上升沿事件 */
#define GPIO_MODE_EVT_FALLING 0x10220000U /* 下降沿事件 */
#define GPIO_MODE_EVT_RISING_FALLING 0x10320000U /* 双边沿事件 */
// GPIO速度
#define GPIO_SPEED_FREQ_LOW 0x00000000U /* 低速 */
#define GPIO_SPEED_FREQ_MEDIUM 0x00000001U /* 中速 */
#define GPIO_SPEED_FREQ_HIGH 0x00000002U /* 高速 */
#define GPIO_SPEED_FREQ_VERY_HIGH 0x00000003U /* 超高速 */
// GPIO上拉/下拉
#define GPIO_NOPULL 0x00000000U /* 无上拉下拉 */
#define GPIO_PULLUP 0x00000001U /* 上拉 */
#define GPIO_PULLDOWN 0x00000002U /* 下拉 */
// GPIO初始化示例
void MX_GPIO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
/* GPIO端口时钟使能 */
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();
__HAL_RCC_GPIOC_CLK_ENABLE();
/* 配置LED引脚(PC13) */
GPIO_InitStruct.Pin = GPIO_PIN_13;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
/* 配置按键引脚(PA0) */
GPIO_InitStruct.Pin = GPIO_PIN_0;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_PULLUP;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
/* 配置USART1 TX/RX引脚(PA9/PA10) */
GPIO_InitStruct.Pin = GPIO_PIN_9 | GPIO_PIN_10;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF7_USART1;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
}
4.2 GPIO高级功能:中断与事件
/**
* @brief GPIO中断与事件处理
*/
// GPIO中断回调函数原型
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin);
// GPIO中断配置示例
void GPIO_Interrupt_Config(void)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
/* 配置外部中断引脚 */
GPIO_InitStruct.Pin = GPIO_PIN_0;
GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING; /* 下降沿触发中断 */
GPIO_InitStruct.Pull = GPIO_PULLUP;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
/* 配置中断优先级 */
HAL_NVIC_SetPriority(EXTI0_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(EXTI0_IRQn);
}
// 外部中断处理函数
void EXTI0_IRQHandler(void)
{
HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_0);
}
// HAL库的中断处理函数
void HAL_GPIO_EXTI_IRQHandler(uint16_t GPIO_Pin)
{
/* 清除中断标志位 */
__HAL_GPIO_EXTI_CLEAR_IT(GPIO_Pin);
/* 调用回调函数 */
HAL_GPIO_EXTI_Callback(GPIO_Pin);
}
// 用户定义的回调函数
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
if (GPIO_Pin == GPIO_PIN_0)
{
/* 处理PA0引脚的中断 */
HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_13); /* 翻转LED */
/* 去抖动处理 */
HAL_Delay(50);
}
}
// GPIO事件模式配置(不产生中断)
void GPIO_Event_Config(void)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
/* 配置事件模式引脚 */
GPIO_InitStruct.Pin = GPIO_PIN_1;
GPIO_InitStruct.Mode = GPIO_MODE_EVT_RISING; /* 上升沿事件 */
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
}
4.3 GPIO位操作与原子操作
/**
* @brief GPIO位带操作与原子操作
*/
// 传统的GPIO操作方式
void Traditional_GPIO_Operations(void)
{
/* 设置引脚 */
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_SET);
/* 读取引脚 */
GPIO_PinState state = HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_5);
/* 翻转引脚 */
HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_5);
}
// 位带操作宏定义(Cortex-M3/M4/M7支持)
#define BITBAND(addr, bitnum) ((addr & 0xF0000000) + 0x02000000 +
((addr & 0x000FFFFF) << 5) + (bitnum << 2))
#define MEM_ADDR(addr) *((volatile unsigned long *)(addr))
#define BIT_ADDR(addr, bitnum) MEM_ADDR(BITBAND(addr, bitnum))
// GPIO位带地址计算
#define GPIOA_ODR_Addr (GPIOA_BASE + 0x14)
#define GPIOA_IDR_Addr (GPIOA_BASE + 0x10)
// 使用位带操作
void BitBand_GPIO_Operations(void)
{
/* 使用位带设置PA5为高电平 */
BIT_ADDR(GPIOA_ODR_Addr, 5) = 1;
/* 使用位带读取PA5状态 */
uint32_t state = BIT_ADDR(GPIOA_IDR_Addr, 5);
/* 使用位带翻转PA5 */
BIT_ADDR(GPIOA_ODR_Addr, 5) = !BIT_ADDR(GPIOA_IDR_Addr, 5);
}
// 原子操作示例
#include "stdatomic.h"
// 使用原子操作保护共享资源
atomic_flag gpio_lock = ATOMIC_FLAG_INIT;
void Atomic_GPIO_Operation(uint16_t pin, GPIO_PinState state)
{
/* 自旋锁等待 */
while (atomic_flag_test_and_set(&gpio_lock))
{
/* 等待锁释放 */
}
/* 临界区:安全的GPIO操作 */
HAL_GPIO_WritePin(GPIOA, pin, state);
/* 释放锁 */
atomic_flag_clear(&gpio_lock);
}
// 批量GPIO操作优化
void Bulk_GPIO_Operations(void)
{
/* 一次性设置多个引脚 */
GPIOA->BSRR = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2; /* 设置PA0, PA1, PA2 */
/* 一次性清除多个引脚 */
GPIOA->BSRR = (GPIO_PIN_3 | GPIO_PIN_4 | GPIO_PIN_5) << 16; /* 清除PA3, PA4, PA5 */
/* 一次性读取多个引脚 */
uint16_t pin_values = GPIOA->IDR & (GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2);
}
第五章:定时器(TIM)高级应用
5.1 定时器基础配置
/**
* @brief 定时器配置与应用
*/
// 定时器初始化结构体
typedef struct
{
uint32_t Prescaler; /* 预分频器 */
uint32_t CounterMode; /* 计数模式 */
uint32_t Period; /* 自动重载值 */
uint32_t ClockDivision; /* 时钟分频 */
uint32_t RepetitionCounter; /* 重复计数器(高级定时器) */
uint32_t AutoReloadPreload; /* 自动重载预装载 */
} TIM_Base_InitTypeDef;
// 定时器工作模式
#define TIM_COUNTERMODE_UP 0x00000000U /* 向上计数 */
#define TIM_COUNTERMODE_DOWN 0x00000010U /* 向下计数 */
#define TIM_COUNTERMODE_CENTERALIGNED1 0x00000020U /* 中央对齐模式1 */
#define TIM_COUNTERMODE_CENTERALIGNED2 0x00000040U /* 中央对齐模式2 */
#define TIM_COUNTERMODE_CENTERALIGNED3 0x00000060U /* 中央对齐模式3 */
// 定时器时钟分频
#define TIM_CLOCKDIVISION_DIV1 0x00000000U /* 不分频 */
#define TIM_CLOCKDIVISION_DIV2 0x00000100U /* 2分频 */
#define TIM_CLOCKDIVISION_DIV4 0x00000200U /* 4分频 */
// 基本定时器配置
void Basic_Timer_Config(void)
{
TIM_HandleTypeDef htim6;
TIM_MasterConfigTypeDef sMasterConfig = {0};
htim6.Instance = TIM6;
htim6.Init.Prescaler = 8399; /* 预分频:84MHz/8400 = 10kHz */
htim6.Init.CounterMode = TIM_COUNTERMODE_UP;
htim6.Init.Period = 9999; /* 自动重载值:10000个计数 */
htim6.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
if (HAL_TIM_Base_Init(&htim6) != HAL_OK)
{
Error_Handler();
}
/* 主输出配置 */
sMasterConfig.MasterOutputTrigger = TIM_TRGO_UPDATE;
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
HAL_TIMEx_MasterConfigSynchronization(&htim6, &sMasterConfig);
}
// 通用定时器配置(PWM输出)
void PWM_Timer_Config(void)
{
TIM_HandleTypeDef htim2;
TIM_OC_InitTypeDef sConfigOC = {0};
TIM_MasterConfigTypeDef sMasterConfig = {0};
htim2.Instance = TIM2;
htim2.Init.Prescaler = 83; /* 84MHz/84 = 1MHz */
htim2.Init.CounterMode = TIM_COUNTERMODE_UP;
htim2.Init.Period = 999; /* 1000个计数 = 1kHz PWM */
htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;
HAL_TIM_PWM_Init(&htim2);
/* 配置PWM通道1 */
sConfigOC.OCMode = TIM_OCMODE_PWM1;
sConfigOC.Pulse = 500; /* 50%占空比 */
sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
HAL_TIM_PWM_ConfigChannel(&htim2, &sConfigOC, TIM_CHANNEL_1);
/* 主输出配置 */
sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
HAL_TIMEx_MasterConfigSynchronization(&htim2, &sMasterConfig);
/* 启动PWM输出 */
HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_1);
}
5.2 定时器中断与DMA
/**
* @brief 定时器中断与DMA传输
*/
// 定时器更新中断配置
void Timer_Update_Interrupt_Config(void)
{
TIM_HandleTypeDef htim7;
htim7.Instance = TIM7;
htim7.Init.Prescaler = 8399; /* 10kHz */
htim7.Init.CounterMode = TIM_COUNTERMODE_UP;
htim7.Init.Period = 9999; /* 1秒中断 */
HAL_TIM_Base_Init(&htim7);
/* 配置中断 */
HAL_NVIC_SetPriority(TIM7_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(TIM7_IRQn);
/* 使能更新中断 */
__HAL_TIM_ENABLE_IT(&htim7, TIM_IT_UPDATE);
/* 启动定时器 */
HAL_TIM_Base_Start(&htim7);
}
// 定时器中断处理
void TIM7_IRQHandler(void)
{
HAL_TIM_IRQHandler(&htim7);
}
// 定时器更新回调函数
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
if (htim->Instance == TIM7)
{
/* 1秒定时任务 */
HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_13);
/* 执行其他周期性任务 */
periodic_task_handler();
}
}
// 定时器DMA传输(用于精确的PWM控制)
void Timer_DMA_Config(void)
{
TIM_HandleTypeDef htim3;
DMA_HandleTypeDef hdma_tim3_ch1;
TIM_OC_InitTypeDef sConfigOC = {0};
uint32_t pwm_data[] = {100, 200, 300, 400, 500, 600, 700, 800, 900};
uint32_t data_count = sizeof(pwm_data) / sizeof(pwm_data[0]);
/* 定时器配置 */
htim3.Instance = TIM3;
htim3.Init.Prescaler = 83; /* 1MHz */
htim3.Init.CounterMode = TIM_COUNTERMODE_UP;
htim3.Init.Period = 999; /* 1kHz */
htim3.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;
HAL_TIM_PWM_Init(&htim3);
/* PWM通道配置 */
sConfigOC.OCMode = TIM_OCMODE_PWM1;
sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
HAL_TIM_PWM_ConfigChannel(&htim3, &sConfigOC, TIM_CHANNEL_1);
/* DMA配置 */
hdma_tim3_ch1.Instance = DMA1_Stream4;
hdma_tim3_ch1.Init.Channel = DMA_CHANNEL_5;
hdma_tim3_ch1.Init.Direction = DMA_MEMORY_TO_PERIPH;
hdma_tim3_ch1.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_tim3_ch1.Init.MemInc = DMA_MINC_ENABLE;
hdma_tim3_ch1.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;
hdma_tim3_ch1.Init.MemDataAlignment = DMA_MDATAALIGN_WORD;
hdma_tim3_ch1.Init.Mode = DMA_CIRCULAR; /* 循环模式 */
hdma_tim3_ch1.Init.Priority = DMA_PRIORITY_HIGH;
hdma_tim3_ch1.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
HAL_DMA_Init(&hdma_tim3_ch1);
/* 关联DMA到定时器 */
__HAL_LINKDMA(&htim3, hdma[TIM_DMA_ID_CC1], hdma_tim3_ch1);
/* 启动DMA传输 */
HAL_TIM_PWM_Start_DMA(&htim3, TIM_CHANNEL_1,
(uint32_t*)pwm_data, data_count);
}
// DMA传输完成回调
void HAL_TIM_PWM_PulseFinishedCallback(TIM_HandleTypeDef *htim)
{
if (htim->Instance == TIM3)
{
/* DMA传输完成处理 */
dma_transfer_complete_handler();
}
}
5.3 高级定时器功能
/**
* @brief 高级定时器应用(TIM1/TIM8)
*/
// 互补PWM输出(用于电机控制)
void Complementary_PWM_Config(void)
{
TIM_HandleTypeDef htim1;
TIM_OC_InitTypeDef sConfigOC = {0};
TIM_BreakDeadTimeConfigTypeDef sBreakDeadTimeConfig = {0};
htim1.Instance = TIM1;
htim1.Init.Prescaler = 0;
htim1.Init.CounterMode = TIM_COUNTERMODE_CENTERALIGNED1;
htim1.Init.Period = 8399; /* 84MHz/8400 = 10kHz */
htim1.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
htim1.Init.RepetitionCounter = 0;
htim1.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;
HAL_TIM_PWM_Init(&htim1);
/* 配置PWM通道1 */
sConfigOC.OCMode = TIM_OCMODE_PWM1;
sConfigOC.Pulse = 4200; /* 50%占空比 */
sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
sConfigOC.OCNPolarity = TIM_OCNPOLARITY_HIGH; /* 互补通道极性 */
sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
sConfigOC.OCIdleState = TIM_OCIDLESTATE_RESET;
sConfigOC.OCNIdleState = TIM_OCNIDLESTATE_RESET;
HAL_TIM_PWM_ConfigChannel(&htim1, &sConfigOC, TIM_CHANNEL_1);
/* 配置死区时间 */
sBreakDeadTimeConfig.OffStateRunMode = TIM_OSSR_DISABLE;
sBreakDeadTimeConfig.OffStateIDLEMode = TIM_OSSI_DISABLE;
sBreakDeadTimeConfig.LockLevel = TIM_LOCKLEVEL_OFF;
sBreakDeadTimeConfig.DeadTime = 72; /* 死区时间 = 72 * 11.9ns ≈ 857ns */
sBreakDeadTimeConfig.BreakState = TIM_BREAK_DISABLE;
sBreakDeadTimeConfig.BreakPolarity = TIM_BREAKPOLARITY_HIGH;
sBreakDeadTimeConfig.AutomaticOutput = TIM_AUTOMATICOUTPUT_DISABLE;
HAL_TIMEx_ConfigBreakDeadTime(&htim1, &sBreakDeadTimeConfig);
/* 启动主输出和互补输出 */
HAL_TIMEx_PWMN_Start(&htim1, TIM_CHANNEL_1);
HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_1);
}
// 输入捕获配置(测量频率/脉宽)
void Input_Capture_Config(void)
{
TIM_HandleTypeDef htim2;
TIM_IC_InitTypeDef sConfigIC = {0};
htim2.Instance = TIM2;
htim2.Init.Prescaler = 83; /* 1MHz计数频率 */
htim2.Init.CounterMode = TIM_COUNTERMODE_UP;
htim2.Init.Period = 0xFFFFFFFF; /* 最大计数值 */
htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
HAL_TIM_IC_Init(&htim2);
/* 输入捕获通道1配置 */
sConfigIC.ICPolarity = TIM_ICPOLARITY_RISING; /* 上升沿捕获 */
sConfigIC.ICSelection = TIM_ICSELECTION_DIRECTTI;
sConfigIC.ICPrescaler = TIM_ICPSC_DIV1; /* 不分频 */
sConfigIC.ICFilter = 0; /* 无滤波 */
HAL_TIM_IC_ConfigChannel(&htim2, &sConfigIC, TIM_CHANNEL_1);
/* 启动输入捕获 */
HAL_TIM_IC_Start_IT(&htim2, TIM_CHANNEL_1);
}
// 输入捕获中断处理
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{
static uint32_t last_capture = 0;
static uint32_t frequency = 0;
static uint32_t duty_cycle = 0;
if (htim->Channel == HAL_TIM_ACTIVE_CHANNEL_1)
{
uint32_t current_capture = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_1);
if (last_capture != 0)
{
/* 计算频率 */
uint32_t period = (current_capture > last_capture) ?
(current_capture - last_capture) :
(0xFFFFFFFF - last_capture + current_capture);
frequency = 1000000 / period; /* 1MHz计数时钟 */
/* 如果是PWM测量,还需要捕获下降沿 */
if (htim->Instance->CCER & TIM_CCER_CC1P)
{
/* 下降沿捕获,计算占空比 */
duty_cycle = (current_capture * 100) / period;
/* 重新配置为上升沿捕获 */
__HAL_TIM_SET_CAPTUREPOLARITY(htim, TIM_CHANNEL_1,
TIM_ICPOLARITY_RISING);
}
else
{
/* 上升沿捕获,重新配置为下降沿捕获 */
__HAL_TIM_SET_CAPTUREPOLARITY(htim, TIM_CHANNEL_1,
TIM_ICPOLARITY_FALLING);
}
}
last_capture = current_capture;
}
}
第六章:串口通信(UART/USART)深入解析
6.1 UART基础配置与通信
/**
* @brief UART/USART串口通信详解
*/
// UART初始化结构体
typedef struct
{
uint32_t BaudRate; /* 波特率 */
uint32_t WordLength; /* 字长 */
uint32_t StopBits; /* 停止位 */
uint32_t Parity; /* 校验位 */
uint32_t Mode; /* 发送/接收模式 */
uint32_t HwFlowCtl; /* 硬件流控制 */
uint32_t OverSampling; /* 过采样 */
} UART_InitTypeDef;
// UART工作模式
#define UART_MODE_RX 0x00000001U /* 接收模式 */
#define UART_MODE_TX 0x00000002U /* 发送模式 */
#define UART_MODE_TX_RX (UART_MODE_TX | UART_MODE_RX) /* 全双工 */
// 校验位配置
#define UART_PARITY_NONE 0x00000000U /* 无校验 */
#define UART_PARITY_EVEN 0x00000002U /* 偶校验 */
#define UART_PARITY_ODD 0x00000003U /* 奇校验 */
// 停止位配置
#define UART_STOPBITS_1 0x00000000U /* 1个停止位 */
#define UART_STOPBITS_2 0x00000002U /* 2个停止位 */
#define UART_STOPBITS_1_5 0x00000003U /* 1.5个停止位 */
// 硬件流控制
#define UART_HWCONTROL_NONE 0x00000000U /* 无硬件流控 */
#define UART_HWCONTROL_RTS 0x00000100U /* 启用RTS */
#define UART_HWCONTROL_CTS 0x00000200U /* 启用CTS */
#define UART_HWCONTROL_RTS_CTS (UART_HWCONTROL_RTS | UART_HWCONTROL_CTS)
// UART初始化示例
void UART_Init_Config(void)
{
UART_HandleTypeDef huart1;
huart1.Instance = USART1;
huart1.Init.BaudRate = 115200;
huart1.Init.WordLength = UART_WORDLENGTH_8B;
huart1.Init.StopBits = UART_STOPBITS_1;
huart1.Init.Parity = UART_PARITY_NONE;
huart1.Init.Mode = UART_MODE_TX_RX;
huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
huart1.Init.OverSampling = UART_OVERSAMPLING_16;
if (HAL_UART_Init(&huart1) != HAL_OK)
{
Error_Handler();
}
}
// 轮询方式发送数据
void UART_Polling_Transmit(uint8_t *data, uint16_t size)
{
HAL_UART_Transmit(&huart1, data, size, HAL_MAX_DELAY);
}
// 轮询方式接收数据
void UART_Polling_Receive(uint8_t *buffer, uint16_t size)
{
HAL_UART_Receive(&huart1, buffer, size, HAL_MAX_DELAY);
}
// 中断方式发送数据
void UART_Interrupt_Transmit(uint8_t *data, uint16_t size)
{
HAL_UART_Transmit_IT(&huart1, data, size);
}
// 中断方式接收数据
void UART_Interrupt_Receive(uint8_t *buffer, uint16_t size)
{
HAL_UART_Receive_IT(&huart1, buffer, size);
}
// DMA方式发送数据
void UART_DMA_Transmit(uint8_t *data, uint16_t size)
{
HAL_UART_Transmit_DMA(&huart1, data, size);
}
// DMA方式接收数据
void UART_DMA_Receive(uint8_t *buffer, uint16_t size)
{
HAL_UART_Receive_DMA(&huart1, buffer, size);
}
6.2 UART高级功能与协议实现
/**
* @brief UART高级应用:自定义协议与错误处理
*/
// 自定义通信协议结构
typedef struct
{
uint8_t header[2]; /* 帧头:0xAA 0x55 */
uint8_t cmd; /* 命令字 */
uint8_t length; /* 数据长度 */
uint8_t data[32]; /* 数据域 */
uint8_t checksum; /* 校验和 */
} UART_Frame_t;
// UART接收状态机
typedef enum
{
UART_RX_STATE_IDLE = 0, /* 空闲状态 */
UART_RX_STATE_HEADER1, /* 接收帧头1 */
UART_RX_STATE_HEADER2, /* 接收帧头2 */
UART_RX_STATE_CMD, /* 接收命令字 */
UART_RX_STATE_LENGTH, /* 接收数据长度 */
UART_RX_STATE_DATA, /* 接收数据 */
UART_RX_STATE_CHECKSUM /* 接收校验和 */
} UART_RxState_t;
// UART接收缓冲区
typedef struct
{
uint8_t buffer[256]; /* 接收缓冲区 */
uint16_t write_index; /* 写指针 */
uint16_t read_index; /* 读指针 */
uint16_t frame_count; /* 接收到的帧数 */
UART_RxState_t state; /* 接收状态 */
UART_Frame_t current_frame; /* 当前正在接收的帧 */
uint8_t data_index; /* 数据接收索引 */
} UART_RxBuffer_t;
// UART接收状态机实现
void UART_RxStateMachine(UART_RxBuffer_t *rx_buf, uint8_t data)
{
static uint8_t calc_checksum = 0;
switch (rx_buf->state)
{
case UART_RX_STATE_IDLE:
if (data == 0xAA)
{
rx_buf->state = UART_RX_STATE_HEADER1;
calc_checksum = 0;
}
break;
case UART_RX_STATE_HEADER1:
if (data == 0x55)
{
rx_buf->state = UART_RX_STATE_HEADER2;
calc_checksum += data;
}
else
{
rx_buf->state = UART_RX_STATE_IDLE;
}
break;
case UART_RX_STATE_HEADER2:
rx_buf->current_frame.cmd = data;
rx_buf->state = UART_RX_STATE_CMD;
calc_checksum += data;
break;
case UART_RX_STATE_CMD:
rx_buf->current_frame.length = data;
rx_buf->state = UART_RX_STATE_LENGTH;
rx_buf->data_index = 0;
calc_checksum += data;
break;
case UART_RX_STATE_LENGTH:
if (rx_buf->data_index < rx_buf->current_frame.length)
{
rx_buf->current_frame.data[rx_buf->data_index++] = data;
calc_checksum += data;
if (rx_buf->data_index >= rx_buf->current_frame.length)
{
rx_buf->state = UART_RX_STATE_CHECKSUM;
}
}
else
{
rx_buf->state = UART_RX_STATE_IDLE;
}
break;
case UART_RX_STATE_CHECKSUM:
if (calc_checksum == data)
{
/* 校验成功,处理完整帧 */
UART_FrameHandler(&rx_buf->current_frame);
rx_buf->frame_count++;
}
rx_buf->state = UART_RX_STATE_IDLE;
break;
default:
rx_buf->state = UART_RX_STATE_IDLE;
break;
}
}
// UART接收中断回调函数
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
static UART_RxBuffer_t uart_rx_buffer;
static uint8_t rx_byte;
if (huart->Instance == USART1)
{
rx_byte = uart_rx_byte; /* 从全局变量获取接收到的字节 */
/* 状态机处理 */
UART_RxStateMachine(&uart_rx_buffer, rx_byte);
/* 重新启动接收 */
HAL_UART_Receive_IT(huart, &uart_rx_byte, 1);
}
}
// UART错误处理
void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart)
{
uint32_t error_code = huart->ErrorCode;
if (error_code & HAL_UART_ERROR_PE)
{
/* 奇偶校验错误 */
uart_parity_error_handler();
}
if (error_code & HAL_UART_ERROR_FE)
{
/* 帧错误 */
uart_frame_error_handler();
}
if (error_code & HAL_UART_ERROR_ORE)
{
/* 溢出错误 */
uart_overrun_error_handler();
}
if (error_code & HAL_UART_ERROR_DMA)
{
/* DMA传输错误 */
uart_dma_error_handler();
}
/* 清除错误标志并重新初始化UART */
__HAL_UART_CLEAR_FLAG(huart, UART_CLEAR_PEF | UART_CLEAR_FEF |
UART_CLEAR_OREF);
/* 重新启动接收 */
HAL_UART_Receive_IT(huart, &uart_rx_byte, 1);
}
// UART DMA双缓冲区接收
void UART_DMA_DoubleBuffer_Config(void)
{
static uint8_t rx_buffer1[256];
static uint8_t rx_buffer2[256];
static uint8_t *current_buffer = rx_buffer1;
static uint8_t buffer_toggle = 0;
/* 配置DMA为循环模式,双缓冲区 */
hdma_usart1_rx.Instance = DMA1_Stream5;
hdma_usart1_rx.Init.Channel = DMA_CHANNEL_4;
hdma_usart1_rx.Init.Direction = DMA_PERIPH_TO_MEMORY;
hdma_usart1_rx.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_usart1_rx.Init.MemInc = DMA_MINC_ENABLE;
hdma_usart1_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
hdma_usart1_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
hdma_usart1_rx.Init.Mode = DMA_CIRCULAR;
hdma_usart1_rx.Init.Priority = DMA_PRIORITY_HIGH;
hdma_usart1_rx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
HAL_DMA_Init(&hdma_usart1_rx);
__HAL_LINKDMA(&huart1, hdmarx, hdma_usart1_rx);
/* 启动DMA接收 */
HAL_UART_Receive_DMA(&huart1, current_buffer, 256);
}
// DMA半传输和传输完成中断
void HAL_UART_RxHalfCpltCallback(UART_HandleTypeDef *huart)
{
/* 前半缓冲区数据已满 */
if (huart->Instance == USART1)
{
/* 处理前半缓冲区数据 */
Process_RxBuffer(rx_buffer1, 128);
}
}
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
/* 后半缓冲区数据已满 */
if (huart->Instance == USART1)
{
/* 处理后半缓冲区数据 */
Process_RxBuffer(rx_buffer1 + 128, 128);
}
}
6.3 多串口管理与RS485通信
/**
* @brief 多串口系统与RS485通信实现
*/
// 多串口管理系统
typedef struct
{
UART_HandleTypeDef *huart;
uint8_t rx_buffer[256];
uint16_t rx_index;
uint8_t tx_buffer[256];
uint16_t tx_index;
void (*frame_handler)(uint8_t *data, uint16_t length);
uint32_t last_activity_time;
} UART_Manager_t;
// 全局串口管理器数组
UART_Manager_t uart_managers[] = {
{&huart1, {0}, 0, {0}, 0, UART1_FrameHandler, 0},
{&huart2, {0}, 0, {0}, 0, UART2_FrameHandler, 0},
{&huart3, {0}, 0, {0}, 0, UART3_FrameHandler, 0},
};
#define UART_MANAGER_COUNT (sizeof(uart_managers) / sizeof(uart_managers[0]))
// 统一的中断处理分发
void UART_IRQ_Dispatcher(UART_HandleTypeDef *huart)
{
for (int i = 0; i < UART_MANAGER_COUNT; i++)
{
if (uart_managers[i].huart->Instance == huart->Instance)
{
HAL_UART_IRQHandler(huart);
break;
}
}
}
// RS485通信实现
typedef struct
{
UART_HandleTypeDef *huart;
GPIO_TypeDef *de_port; /* 方向控制端口 */
uint16_t de_pin; /* 方向控制引脚 */
uint8_t address; /* 本机地址 */
uint8_t rx_buffer[256];
uint8_t tx_buffer[256];
uint32_t timeout; /* 接收超时时间 */
uint32_t last_rx_time; /* 最后接收时间 */
} RS485_Manager_t;
// RS485发送使能
void RS485_Send_Enable(RS485_Manager_t *rs485)
{
HAL_GPIO_WritePin(rs485->de_port, rs485->de_pin, GPIO_PIN_SET);
HAL_Delay(1); /* 等待线路稳定 */
}
// RS485接收使能
void RS485_Receive_Enable(RS485_Manager_t *rs485)
{
HAL_GPIO_WritePin(rs485->de_port, rs485->de_pin, GPIO_PIN_RESET);
HAL_Delay(1); /* 等待线路稳定 */
}
// RS485发送数据
HAL_StatusTypeDef RS485_Send(RS485_Manager_t *rs485,
uint8_t address,
uint8_t *data,
uint16_t length)
{
if (length > 250)
{
return HAL_ERROR; /* 数据太长 */
}
/* 构造RS485帧 */
uint8_t frame[256];
frame[0] = 0xAA; /* 帧头 */
frame[1] = 0x55; /* 帧头 */
frame[2] = address; /* 目标地址 */
frame[3] = rs485->address; /* 源地址 */
frame[4] = length; /* 数据长度 */
memcpy(&frame[5], data, length);
/* 计算CRC校验 */
uint16_t crc = Calculate_CRC16(frame, length + 5);
frame[length + 5] = (crc >> 8) & 0xFF;
frame[length + 6] = crc & 0xFF;
/* 切换到发送模式 */
RS485_Send_Enable(rs485);
/* 发送数据 */
HAL_StatusTypeDef status = HAL_UART_Transmit(rs485->huart,
frame,
length + 7,
1000);
/* 等待发送完成 */
HAL_Delay(1);
/* 切换回接收模式 */
RS485_Receive_Enable(rs485);
return status;
}
// RS485接收处理
void RS485_Receive_Handler(RS485_Manager_t *rs485)
{
static uint8_t rx_state = 0;
static uint8_t rx_length = 0;
static uint8_t rx_index = 0;
static uint8_t rx_buffer[256];
static uint32_t last_byte_time = 0;
uint8_t data;
/* 检查是否有数据 */
if (__HAL_UART_GET_FLAG(rs485->huart, UART_FLAG_RXNE))
{
data = (uint8_t)(rs485->huart->Instance->DR & 0xFF);
last_byte_time = HAL_GetTick();
switch (rx_state)
{
case 0: /* 等待帧头1 */
if (data == 0xAA)
{
rx_state = 1;
rx_buffer[0] = data;
rx_index = 1;
}
break;
case 1: /* 等待帧头2 */
if (data == 0x55)
{
rx_state = 2;
rx_buffer[1] = data;
rx_index = 2;
}
else
{
rx_state = 0;
}
break;
case 2: /* 接收目标地址 */
rx_buffer[2] = data;
rx_state = 3;
rx_index = 3;
break;
case 3: /* 接收源地址 */
rx_buffer[3] = data;
rx_state = 4;
rx_index = 4;
break;
case 4: /* 接收数据长度 */
rx_length = data;
rx_buffer[4] = data;
rx_state = 5;
rx_index = 5;
break;
case 5: /* 接收数据 */
rx_buffer[rx_index++] = data;
if (rx_index >= (rx_length + 5))
{
rx_state = 6; /* 等待CRC */
}
break;
case 6: /* 接收CRC高字节 */
rx_buffer[rx_index++] = data;
rx_state = 7;
break;
case 7: /* 接收CRC低字节 */
rx_buffer[rx_index] = data;
/* 验证CRC */
uint16_t received_crc = (rx_buffer[rx_index-1] << 8) | data;
uint16_t calculated_crc = Calculate_CRC16(rx_buffer, rx_index-1);
if (received_crc == calculated_crc)
{
/* 验证目标地址 */
if (rx_buffer[2] == rs485->address || rx_buffer[2] == 0xFF)
{
/* 处理有效帧 */
RS485_Frame_Handler(rs485,
rx_buffer[3], /* 源地址 */
&rx_buffer[5], /* 数据 */
rx_length); /* 数据长度 */
}
}
rx_state = 0;
break;
}
}
/* 检查接收超时 */
if (rx_state != 0 && (HAL_GetTick() - last_byte_time) > 10)
{
rx_state = 0; /* 接收超时,重置状态 */
}
}
// CRC16计算函数
uint16_t Calculate_CRC16(uint8_t *data, uint16_t length)
{
uint16_t crc = 0xFFFF;
for (uint16_t i = 0; i < length; i++)
{
crc ^= (uint16_t)data[i];
for (uint8_t j = 0; j < 8; j++)
{
if (crc & 0x0001)
{
crc = (crc >> 1) ^ 0xA001;
}
else
{
crc = crc >> 1;
}
}
}
return crc;
}
第七章:ADC与DAC高级应用
7.1 ADC多通道扫描与DMA
/**
* @brief ADC多通道扫描与DMA传输
*/
// ADC初始化结构体
typedef struct
{
uint32_t ClockPrescaler; /* 时钟预分频 */
uint32_t Resolution; /* 分辨率 */
uint32_t DataAlign; /* 数据对齐 */
uint32_t ScanConvMode; /* 扫描模式 */
uint32_t EOCSelection; /* EOC选择 */
uint32_t ContinuousConvMode; /* 连续转换模式 */
uint32_t DMAContinuousRequests; /* DMA连续请求 */
uint32_t NbrOfConversion; /* 转换通道数 */
uint32_t DiscontinuousConvMode; /* 间断模式 */
uint32_t NbrOfDiscConversion; /* 间断转换数 */
uint32_t ExternalTrigConv; /* 外部触发 */
uint32_t ExternalTrigConvEdge; /* 外部触发边沿 */
} ADC_InitTypeDef;
// ADC多通道扫描配置
void ADC_MultiChannel_Scan_Config(void)
{
ADC_HandleTypeDef hadc1;
ADC_ChannelConfTypeDef sConfig = {0};
hadc1.Instance = ADC1;
hadc1.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV4; /* ADCCLK = 84MHz/4 = 21MHz */
hadc1.Init.Resolution = ADC_RESOLUTION_12B; /* 12位分辨率 */
hadc1.Init.ScanConvMode = ENABLE; /* 启用扫描模式 */
hadc1.Init.ContinuousConvMode = ENABLE; /* 连续转换模式 */
hadc1.Init.DiscontinuousConvMode = DISABLE; /* 禁用间断模式 */
hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE; /* 无外部触发 */
hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START; /* 软件触发 */
hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT; /* 右对齐 */
hadc1.Init.NbrOfConversion = 4; /* 4个转换通道 */
hadc1.Init.DMAContinuousRequests = ENABLE; /* 启用DMA连续请求 */
hadc1.Init.EOCSelection = ADC_EOC_SEQ_CONV; /* 序列转换结束产生EOC */
HAL_ADC_Init(&hadc1);
/* 配置通道0:PA0,采样时间56周期 */
sConfig.Channel = ADC_CHANNEL_0;
sConfig.Rank = 1;
sConfig.SamplingTime = ADC_SAMPLETIME_56CYCLES;
HAL_ADC_ConfigChannel(&hadc1, &sConfig);
/* 配置通道1:PA1,采样时间56周期 */
sConfig.Channel = ADC_CHANNEL_1;
sConfig.Rank = 2;
sConfig.SamplingTime = ADC_SAMPLETIME_56CYCLES;
HAL_ADC_ConfigChannel(&hadc1, &sConfig);
/* 配置通道2:PA2,采样时间56周期 */
sConfig.Channel = ADC_CHANNEL_2;
sConfig.Rank = 3;
sConfig.SamplingTime = ADC_SAMPLETIME_56CYCLES;
HAL_ADC_ConfigChannel(&hadc1, &sConfig);
/* 配置通道3:PA3,采样时间56周期 */
sConfig.Channel = ADC_CHANNEL_3;
sConfig.Rank = 4;
sConfig.SamplingTime = ADC_SAMPLETIME_56CYCLES;
HAL_ADC_ConfigChannel(&hadc1, &sConfig);
}
// ADC DMA配置
void ADC_DMA_Config(void)
{
static uint16_t adc_values[4]; /* 存储4个通道的ADC值 */
DMA_HandleTypeDef hdma_adc1;
/* DMA配置 */
hdma_adc1.Instance = DMA2_Stream0;
hdma_adc1.Init.Channel = DMA_CHANNEL_0;
hdma_adc1.Init.Direction = DMA_PERIPH_TO_MEMORY;
hdma_adc1.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_adc1.Init.MemInc = DMA_MINC_ENABLE;
hdma_adc1.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
hdma_adc1.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
hdma_adc1.Init.Mode = DMA_CIRCULAR; /* 循环模式 */
hdma_adc1.Init.Priority = DMA_PRIORITY_HIGH;
hdma_adc1.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
HAL_DMA_Init(&hdma_adc1);
/* 关联DMA到ADC */
__HAL_LINKDMA(&hadc1, DMA_Handle, hdma_adc1);
/* 启动ADC DMA传输 */
HAL_ADC_Start_DMA(&hadc1, (uint32_t*)adc_values, 4);
}
// ADC DMA传输完成回调
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef *hadc)
{
/* ADC转换完成处理 */
if (hadc->Instance == ADC1)
{
/* 处理ADC数据 */
Process_ADC_Data(adc_values, 4);
}
}
// ADC校准与自诊断
void ADC_Calibration_SelfTest(void)
{
ADC_HandleTypeDef hadc1;
/* 1. ADC上电 */
__HAL_RCC_ADC1_CLK_ENABLE();
HAL_Delay(1);
/* 2. 执行校准 */
if (HAL_ADCEx_Calibration_Start(&hadc1, ADC_SINGLE_ENDED) != HAL_OK)
{
Error_Handler();
}
/* 3. 自测试:测量内部参考电压 */
ADC_ChannelConfTypeDef sConfig = {0};
sConfig.Channel = ADC_CHANNEL_VREFINT; /* 内部参考电压通道 */
sConfig.Rank = 1;
sConfig.SamplingTime = ADC_SAMPLETIME_480CYCLES;
HAL_ADC_ConfigChannel(&hadc1, &sConfig);
HAL_ADC_Start(&hadc1);
HAL_ADC_PollForConversion(&hadc1, 100);
uint32_t vrefint_value = HAL_ADC_GetValue(&hadc1);
HAL_ADC_Stop(&hadc1);
/* 计算实际电压值 */
/* VREFINT_CAL是出厂校准值,存储在系统存储器中 */
uint32_t vrefint_cal = *(__IO uint16_t *)(0x1FFF7A2A);
float vdda = 3.3 * vrefint_cal / vrefint_value;
/* 验证VDDA是否在合理范围内 */
if (vdda < 2.7 || vdda > 3.6)
{
Error_Handler();
}
}
7.2 DAC波形生成
/**
* @brief DAC波形生成与应用
*/
// DAC初始化结构体
typedef struct
{
uint32_t DAC_Trigger; /* 触发源 */
uint32_t DAC_WaveGeneration; /* 波形生成 */
uint32_t DAC_LFSRUnmask_TriangleAmplitude; /* LFSR掩码/三角波振幅 */
uint32_t DAC_OutputBuffer; /* 输出缓冲 */
} DAC_InitTypeDef;
// DAC波形生成配置
void DAC_Waveform_Generation(void)
{
DAC_HandleTypeDef hdac;
DAC_ChannelConfTypeDef sConfig = {0};
hdac.Instance = DAC;
HAL_DAC_Init(&hdac);
/* 配置DAC通道1 */
sConfig.DAC_Trigger = DAC_TRIGGER_T6_TRGO; /* TIM6触发 */
sConfig.DAC_OutputBuffer = DAC_OUTPUTBUFFER_ENABLE;
HAL_DAC_ConfigChannel(&hdac, &sConfig, DAC_CHANNEL_1);
/* 配置三角波生成 */
HAL_DACEx_TriangleWaveGenerate(&hdac, DAC_CHANNEL_1,
DAC_TRIANGLEAMPLITUDE_4095);
/* 配置DMA传输 */
DAC_DMA_Config();
/* 启动DAC */
HAL_DAC_Start(&hdac, DAC_CHANNEL_1);
}
// DAC DMA传输配置(用于任意波形生成)
void DAC_DMA_Config(void)
{
static uint16_t waveform_buffer[1024]; /* 波形数据缓冲区 */
/* 生成正弦波数据 */
for (int i = 0; i < 1024; i++)
{
waveform_buffer[i] = 2048 + (int16_t)(2047 * sin(2 * PI * i / 1024));
}
DMA_HandleTypeDef hdma_dac1;
hdma_dac1.Instance = DMA1_Stream5;
hdma_dac1.Init.Channel = DMA_CHANNEL_7;
hdma_dac1.Init.Direction = DMA_MEMORY_TO_PERIPH;
hdma_dac1.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_dac1.Init.MemInc = DMA_MINC_ENABLE;
hdma_dac1.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
hdma_dac1.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
hdma_dac1.Init.Mode = DMA_CIRCULAR;
hdma_dac1.Init.Priority = DMA_PRIORITY_HIGH;
hdma_dac1.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
HAL_DMA_Init(&hdma_dac1);
/* 关联DMA到DAC */
__HAL_LINKDMA(&hdac, DMA_Handle1, hdma_dac1);
/* 启动DAC DMA传输 */
HAL_DAC_Start_DMA(&hdac, DAC_CHANNEL_1,
(uint32_t*)waveform_buffer, 1024, DAC_ALIGN_12B_R);
}
// 双DAC同步输出
void Dual_DAC_Sync_Output(void)
{
DAC_HandleTypeDef hdac;
/* 使能DAC */
__HAL_RCC_DAC_CLK_ENABLE();
hdac.Instance = DAC;
HAL_DAC_Init(&hdac);
/* 配置DAC通道1 */
DAC_ChannelConfTypeDef sConfig = {0};
sConfig.DAC_Trigger = DAC_TRIGGER_SOFTWARE;
sConfig.DAC_OutputBuffer = DAC_OUTPUTBUFFER_ENABLE;
HAL_DAC_ConfigChannel(&hdac, &sConfig, DAC_CHANNEL_1);
/* 配置DAC通道2 */
sConfig.DAC_Trigger = DAC_TRIGGER_SOFTWARE;
sConfig.DAC_OutputBuffer = DAC_OUTPUTBUFFER_ENABLE;
HAL_DAC_ConfigChannel(&hdac, &sConfig, DAC_CHANNEL_2);
/* 双通道同步输出 */
uint16_t value1 = 2048; /* 通道1输出值 */
uint16_t value2 = 4095; /* 通道2输出值 */
HAL_DAC_SetValue(&hdac, DAC_CHANNEL_1, DAC_ALIGN_12B_R, value1);
HAL_DAC_SetValue(&hdac, DAC_CHANNEL_2, DAC_ALIGN_12B_R, value2);
/* 同时启动两个通道 */
HAL_DAC_Start(&hdac, DAC_CHANNEL_1);
HAL_DAC_Start(&hdac, DAC_CHANNEL_2);
}
// 音频DAC应用
void Audio_DAC_Application(void)
{
/* 音频采样率配置:44.1kHz */
TIM_HandleTypeDef htim6;
htim6.Instance = TIM6;
htim6.Init.Prescaler = 0;
htim6.Init.CounterMode = TIM_COUNTERMODE_UP;
htim6.Init.Period = (84000000 / 44100) - 1; /* 84MHz / 44.1kHz */
HAL_TIM_Base_Init(&htim6);
/* 配置DAC由TIM6触发 */
DAC_HandleTypeDef hdac;
DAC_ChannelConfTypeDef sConfig = {0};
hdac.Instance = DAC;
HAL_DAC_Init(&hdac);
sConfig.DAC_Trigger = DAC_TRIGGER_T6_TRGO;
sConfig.DAC_OutputBuffer = DAC_OUTPUTBUFFER_ENABLE;
HAL_DAC_ConfigChannel(&hdac, &sConfig, DAC_CHANNEL_1);
/* 加载音频数据到缓冲区 */
extern uint16_t audio_data[];
extern uint32_t audio_data_length;
/* 配置DMA传输音频数据 */
DMA_HandleTypeDef hdma_dac1;
/* ... DMA配置 ... */
HAL_DAC_Start_DMA(&hdac, DAC_CHANNEL_1,
(uint32_t*)audio_data, audio_data_length, DAC_ALIGN_12B_R);
/* 启动定时器触发DAC */
HAL_TIM_Base_Start(&htim6);
}
第八章:I2C与SPI总线通信
8.1 I2C总线通信详解
/**
* @brief I2C总线通信协议实现
*/
// I2C初始化结构体
typedef struct
{
uint32_t ClockSpeed; /* 时钟速度 */
uint32_t DutyCycle; /* 占空比 */
uint32_t OwnAddress1; /* 自身地址1 */
uint32_t AddressingMode; /* 寻址模式 */
uint32_t DualAddressMode; /* 双地址模式 */
uint32_t OwnAddress2; /* 自身地址2 */
uint32_t GeneralCallMode; /* 广播呼叫模式 */
uint32_t NoStretchMode; /* 时钟延展模式 */
} I2C_InitTypeDef;
// I2C主机模式配置
void I2C_Master_Config(void)
{
I2C_HandleTypeDef hi2c1;
hi2c1.Instance = I2C1;
hi2c1.Init.ClockSpeed = 100000; /* 100kHz标准模式 */
hi2c1.Init.DutyCycle = I2C_DUTYCYCLE_2; /* 时钟占空比 */
hi2c1.Init.OwnAddress1 = 0;
hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT; /* 7位地址 */
hi2c1.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
hi2c1.Init.OwnAddress2 = 0;
hi2c1.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
hi2c1.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;
HAL_I2C_Init(&hi2c1);
}
// I2C从机模式配置
void I2C_Slave_Config(void)
{
I2C_HandleTypeDef hi2c2;
hi2c2.Instance = I2C2;
hi2c2.Init.ClockSpeed = 100000;
hi2c2.Init.DutyCycle = I2C_DUTYCYCLE_2;
hi2c2.Init.OwnAddress1 = 0x48; /* 从机地址:0x48 */
hi2c2.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
hi2c2.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
hi2c2.Init.OwnAddress2 = 0;
hi2c2.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
hi2c2.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;
HAL_I2C_Init(&hi2c2);
/* 启动从机监听 */
HAL_I2C_EnableListen_IT(&hi2c2);
}
// I2C中断回调函数
void HAL_I2C_AddrCallback(I2C_HandleTypeDef *hi2c,
uint8_t TransferDirection,
uint16_t AddrMatchCode)
{
if (hi2c->Instance == I2C2)
{
/* 地址匹配回调 */
if (TransferDirection == I2C_DIRECTION_TRANSMIT)
{
/* 主机要发送数据给从机 */
i2c_slave_tx_mode = 1;
}
else
{
/* 主机要从从机读取数据 */
i2c_slave_rx_mode = 1;
}
}
}
void HAL_I2C_SlaveRxCpltCallback(I2C_HandleTypeDef *hi2c)
{
/* 从机接收完成 */
Process_I2C_RxData(i2c_rx_buffer, i2c_rx_len);
/* 重新启动监听 */
HAL_I2C_EnableListen_IT(hi2c);
}
void HAL_I2C_SlaveTxCpltCallback(I2C_HandleTypeDef *hi2c)
{
/* 从机发送完成 */
/* 重新启动监听 */
HAL_I2C_EnableListen_IT(hi2c);
}
// I2C主机读写操作
void I2C_Read_Register(uint8_t dev_addr, uint8_t reg_addr, uint8_t *data, uint16_t size)
{
/* 先发送寄存器地址,再读取数据 */
HAL_I2C_Mem_Read(&hi2c1, dev_addr << 1, reg_addr,
I2C_MEMADD_SIZE_8BIT, data, size, 1000);
}
void I2C_Write_Register(uint8_t dev_addr, uint8_t reg_addr, uint8_t *data, uint16_t size)
{
/* 写入寄存器地址和数据 */
HAL_I2C_Mem_Write(&hi2c1, dev_addr << 1, reg_addr,
I2C_MEMADD_SIZE_8BIT, data, size, 1000);
}
// I2C扫描总线上的设备
void I2C_Bus_Scan(void)
{
uint8_t devices[128] = {0};
uint8_t device_count = 0;
printf("Scanning I2C bus...\r\n");
for (uint8_t addr = 1; addr < 127; addr++)
{
HAL_StatusTypeDef status;
/* 尝试与设备通信 */
status = HAL_I2C_IsDeviceReady(&hi2c1, addr << 1, 3, 10);
if (status == HAL_OK)
{
devices[device_count++] = addr;
printf("Device found at address 0x%02X\r\n", addr);
}
}
printf("Found %d device(s) on I2C bus\r\n", device_count);
}
// I2C DMA传输
void I2C_DMA_Transfer(void)
{
uint8_t tx_data[256];
uint8_t rx_data[256];
/* 准备要发送的数据 */
for (int i = 0; i < 256; i++)
{
tx_data[i] = i;
}
/* 配置DMA */
DMA_HandleTypeDef hdma_i2c1_tx;
DMA_HandleTypeDef hdma_i2c1_rx;
/* I2C TX DMA配置 */
hdma_i2c1_tx.Instance = DMA1_Stream6;
hdma_i2c1_tx.Init.Channel = DMA_CHANNEL_1;
hdma_i2c1_tx.Init.Direction = DMA_MEMORY_TO_PERIPH;
hdma_i2c1_tx.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_i2c1_tx.Init.MemInc = DMA_MINC_ENABLE;
hdma_i2c1_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
hdma_i2c1_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
hdma_i2c1_tx.Init.Mode = DMA_NORMAL;
hdma_i2c1_tx.Init.Priority = DMA_PRIORITY_HIGH;
hdma_i2c1_tx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
HAL_DMA_Init(&hdma_i2c1_tx);
__HAL_LINKDMA(&hi2c1, hdmatx, hdma_i2c1_tx);
/* I2C RX DMA配置 */
hdma_i2c1_rx.Instance = DMA1_Stream0;
hdma_i2c1_rx.Init.Channel = DMA_CHANNEL_1;
hdma_i2c1_rx.Init.Direction = DMA_PERIPH_TO_MEMORY;
hdma_i2c1_rx.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_i2c1_rx.Init.MemInc = DMA_MINC_ENABLE;
hdma_i2c1_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
hdma_i2c1_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
hdma_i2c1_rx.Init.Mode = DMA_NORMAL;
hdma_i2c1_rx.Init.Priority = DMA_PRIORITY_HIGH;
hdma_i2c1_rx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
HAL_DMA_Init(&hdma_i2c1_rx);
__HAL_LINKDMA(&hi2c1, hdmarx, hdma_i2c1_rx);
/* 使用DMA发送数据 */
HAL_I2C_Master_Transmit_DMA(&hi2c1, 0x50 << 1, tx_data, 256);
/* 等待发送完成 */
while (HAL_I2C_GetState(&hi2c1) != HAL_I2C_STATE_READY);
/* 使用DMA接收数据 */
HAL_I2C_Master_Receive_DMA(&hi2c1, 0x50 << 1, rx_data, 256);
}
8.2 SPI总线通信详解
/**
* @brief SPI总线通信协议实现
*/
// SPI初始化结构体
typedef struct
{
uint32_t Mode; /* 主从模式 */
uint32_t Direction; /* 数据传输方向 */
uint32_t DataSize; /* 数据大小 */
uint32_t CLKPolarity; /* 时钟极性 */
uint32_t CLKPhase; /* 时钟相位 */
uint32_t NSS; /* 片选管理 */
uint32_t BaudRatePrescaler; /* 波特率预分频 */
uint32_t FirstBit; /* 首位传输 */
uint32_t TIMode; /* TI模式 */
uint32_t CRCCalculation; /* CRC计算 */
uint32_t CRCPolynomial; /* CRC多项式 */
} SPI_InitTypeDef;
// SPI主机模式配置
void SPI_Master_Config(void)
{
SPI_HandleTypeDef hspi1;
hspi1.Instance = SPI1;
hspi1.Init.Mode = SPI_MODE_MASTER; /* 主机模式 */
hspi1.Init.Direction = SPI_DIRECTION_2LINES; /* 全双工 */
hspi1.Init.DataSize = SPI_DATASIZE_8BIT; /* 8位数据 */
hspi1.Init.CLKPolarity = SPI_POLARITY_LOW; /* 时钟极性 */
hspi1.Init.CLKPhase = SPI_PHASE_1EDGE; /* 时钟相位 */
hspi1.Init.NSS = SPI_NSS_SOFT; /* 软件NSS */
hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_32; /* 84MHz/32 = 2.625MHz */
hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB; /* 高位在前 */
hspi1.Init.TIMode = SPI_TIMODE_DISABLE;
hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
hspi1.Init.CRCPolynomial = 10;
HAL_SPI_Init(&hspi1);
}
// SPI从机模式配置
void SPI_Slave_Config(void)
{
SPI_HandleTypeDef hspi2;
hspi2.Instance = SPI2;
hspi2.Init.Mode = SPI_MODE_SLAVE; /* 从机模式 */
hspi2.Init.Direction = SPI_DIRECTION_2LINES; /* 全双工 */
hspi2.Init.DataSize = SPI_DATASIZE_8BIT; /* 8位数据 */
hspi2.Init.CLKPolarity = SPI_POLARITY_LOW; /* 时钟极性 */
hspi2.Init.CLKPhase = SPI_PHASE_1EDGE; /* 时钟相位 */
hspi2.Init.NSS = SPI_NSS_HARD_INPUT; /* 硬件NSS */
hspi2.Init.FirstBit = SPI_FIRSTBIT_MSB; /* 高位在前 */
hspi2.Init.TIMode = SPI_TIMODE_DISABLE;
hspi2.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
hspi2.Init.CRCPolynomial = 10;
HAL_SPI_Init(&hspi2);
}
// SPI软件片选控制
void SPI_CS_Control(GPIO_TypeDef* port, uint16_t pin, uint8_t state)
{
if (state)
{
HAL_GPIO_WritePin(port, pin, GPIO_PIN_RESET); /* 片选有效 */
HAL_Delay(1); /* 等待稳定 */
}
else
{
HAL_GPIO_WritePin(port, pin, GPIO_PIN_SET); /* 片选无效 */
HAL_Delay(1);
}
}
// SPI读写操作
uint8_t SPI_ReadWriteByte(uint8_t tx_data)
{
uint8_t rx_data;
HAL_SPI_TransmitReceive(&hspi1, &tx_data, &rx_data, 1, 1000);
return rx_data;
}
// SPI读取多个字节
void SPI_ReadBytes(uint8_t *rx_buffer, uint16_t size)
{
uint8_t tx_dummy = 0xFF;
for (uint16_t i = 0; i < size; i++)
{
rx_buffer[i] = SPI_ReadWriteByte(tx_dummy);
}
}
// SPI写入多个字节
void SPI_WriteBytes(uint8_t *tx_buffer, uint16_t size)
{
uint8_t rx_dummy;
for (uint16_t i = 0; i < size; i++)
{
SPI_ReadWriteByte(tx_buffer[i]);
}
}
// SPI DMA传输
void SPI_DMA_Transfer(void)
{
uint8_t tx_buffer[1024];
uint8_t rx_buffer[1024];
/* 准备数据 */
for (int i = 0; i < 1024; i++)
{
tx_buffer[i] = i & 0xFF;
}
/* 配置SPI TX DMA */
DMA_HandleTypeDef hdma_spi1_tx;
hdma_spi1_tx.Instance = DMA2_Stream3;
hdma_spi1_tx.Init.Channel = DMA_CHANNEL_3;
hdma_spi1_tx.Init.Direction = DMA_MEMORY_TO_PERIPH;
hdma_spi1_tx.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_spi1_tx.Init.MemInc = DMA_MINC_ENABLE;
hdma_spi1_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
hdma_spi1_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
hdma_spi1_tx.Init.Mode = DMA_NORMAL;
hdma_spi1_tx.Init.Priority = DMA_PRIORITY_HIGH;
hdma_spi1_tx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
HAL_DMA_Init(&hdma_spi1_tx);
__HAL_LINKDMA(&hspi1, hdmatx, hdma_spi1_tx);
/* 配置SPI RX DMA */
DMA_HandleTypeDef hdma_spi1_rx;
hdma_spi1_rx.Instance = DMA2_Stream0;
hdma_spi1_rx.Init.Channel = DMA_CHANNEL_3;
hdma_spi1_rx.Init.Direction = DMA_PERIPH_TO_MEMORY;
hdma_spi1_rx.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_spi1_rx.Init.MemInc = DMA_MINC_ENABLE;
hdma_spi1_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
hdma_spi1_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
hdma_spi1_rx.Init.Mode = DMA_NORMAL;
hdma_spi1_rx.Init.Priority = DMA_PRIORITY_HIGH;
hdma_spi1_rx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
HAL_DMA_Init(&hdma_spi1_rx);
__HAL_LINKDMA(&hspi1, hdmarx, hdma_spi1_rx);
/* 片选有效 */
SPI_CS_Control(GPIOA, GPIO_PIN_4, 1);
/* 启动DMA传输 */
HAL_SPI_TransmitReceive_DMA(&hspi1, tx_buffer, rx_buffer, 1024);
/* 等待传输完成 */
while (HAL_SPI_GetState(&hspi1) != HAL_SPI_STATE_READY);
/* 片选无效 */
SPI_CS_Control(GPIOA, GPIO_PIN_4, 0);
}
// SPI中断方式传输
void SPI_Interrupt_Transfer(void)
{
uint8_t tx_data = 0xAA;
uint8_t rx_data;
/* 启动中断方式传输 */
HAL_SPI_TransmitReceive_IT(&hspi1, &tx_data, &rx_data, 1);
}
// SPI传输完成回调
void HAL_SPI_TxRxCpltCallback(SPI_HandleTypeDef *hspi)
{
if (hspi->Instance == SPI1)
{
/* 传输完成处理 */
spi_transfer_complete_handler();
}
}
// SPI错误回调
void HAL_SPI_ErrorCallback(SPI_HandleTypeDef *hspi)
{
uint32_t error_code = hspi->ErrorCode;
if (error_code & HAL_SPI_ERROR_MODF)
{
/* 模式错误 */
spi_mode_error_handler();
}
if (error_code & HAL_SPI_ERROR_CRC)
{
/* CRC错误 */
spi_crc_error_handler();
}
if (error_code & HAL_SPI_ERROR_OVR)
{
/* 溢出错误 */
spi_overrun_error_handler();
}
if (error_code & HAL_SPI_ERROR_FRE)
{
/* 帧错误 */
spi_frame_error_handler();
}
if (error_code & HAL_SPI_ERROR_DMA)
{
/* DMA错误 */
spi_dma_error_handler();
}
/* 重新初始化SPI */
HAL_SPI_DeInit(hspi);
HAL_SPI_Init(hspi);
}
第九章:DMA高级应用
9.1 DMA内存到内存传输
/**
* @brief DMA高级应用:内存到内存传输
*/
// DMA初始化结构体
typedef struct
{
uint32_t Channel; /* 通道选择 */
uint32_t Direction; /* 传输方向 */
uint32_t PeriphInc; /* 外设地址递增 */
uint32_t MemoryInc; /* 内存地址递增 */
uint32_t PeriphDataAlignment; /* 外设数据对齐 */
uint32_t MemDataAlignment; /* 内存数据对齐 */
uint32_t Mode; /* 模式(普通/循环) */
uint32_t Priority; /* 优先级 */
uint32_t FIFOMode; /* FIFO模式 */
uint32_t FIFOThreshold; /* FIFO阈值 */
uint32_t MemBurst; /* 内存突发传输 */
uint32_t PeriphBurst; /* 外设突发传输 */
} DMA_InitTypeDef;
// 内存到内存DMA传输
void DMA_MemoryToMemory_Transfer(void)
{
uint32_t src_buffer[1024];
uint32_t dst_buffer[1024];
/* 初始化源缓冲区 */
for (int i = 0; i < 1024; i++)
{
src_buffer[i] = i;
}
DMA_HandleTypeDef hdma_mem;
hdma_mem.Instance = DMA2_Stream0;
hdma_mem.Init.Channel = DMA_CHANNEL_0;
hdma_mem.Init.Direction = DMA_MEMORY_TO_MEMORY; /* 内存到内存 */
hdma_mem.Init.PeriphInc = DMA_PINC_ENABLE; /* 源地址递增 */
hdma_mem.Init.MemInc = DMA_MINC_ENABLE; /* 目标地址递增 */
hdma_mem.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD; /* 字对齐 */
hdma_mem.Init.MemDataAlignment = DMA_MDATAALIGN_WORD; /* 字对齐 */
hdma_mem.Init.Mode = DMA_NORMAL; /* 普通模式 */
hdma_mem.Init.Priority = DMA_PRIORITY_HIGH; /* 高优先级 */
hdma_mem.Init.FIFOMode = DMA_FIFOMODE_ENABLE; /* 启用FIFO */
hdma_mem.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL;
HAL_DMA_Init(&hdma_mem);
/* 启动DMA传输 */
HAL_DMA_Start(&hdma_mem, (uint32_t)src_buffer, (uint32_t)dst_buffer, 1024);
/* 等待传输完成 */
HAL_DMA_PollForTransfer(&hdma_mem, HAL_DMA_FULL_TRANSFER, 1000);
/* 验证传输结果 */
for (int i = 0; i < 1024; i++)
{
if (dst_buffer[i] != src_buffer[i])
{
Error_Handler();
}
}
}
// 双缓冲区DMA传输
void DMA_DoubleBuffer_Transfer(void)
{
static uint32_t buffer1[256];
static uint32_t buffer2[256];
static uint32_t *current_buffer = buffer1;
DMA_HandleTypeDef hdma_double;
hdma_double.Instance = DMA2_Stream1;
hdma_double.Init.Channel = DMA_CHANNEL_1;
hdma_double.Init.Direction = DMA_MEMORY_TO_PERIPH;
hdma_double.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_double.Init.MemInc = DMA_MINC_ENABLE;
hdma_double.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;
hdma_double.Init.MemDataAlignment = DMA_MDATAALIGN_WORD;
hdma_double.Init.Mode = DMA_CIRCULAR; /* 循环模式 */
hdma_double.Init.Priority = DMA_PRIORITY_HIGH;
hdma_double.Init.FIFOMode = DMA_FIFOMODE_ENABLE;
hdma_double.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_HALFFULL;
HAL_DMA_Init(&hdma_double);
/* 配置双缓冲区 */
HAL_DMAEx_MultiBufferStart_IT(&hdma_double,
(uint32_t)buffer1,
(uint32_t)&(SOME_PERIPHERAL->DR),
(uint32_t)buffer2,
256);
/* 启用双缓冲区中断 */
HAL_DMAEx_MultiBufferStart_IT(&hdma_double,
(uint32_t)buffer1,
(uint32_t)&(SOME_PERIPHERAL->DR),
(uint32_t)buffer2,
256);
}
// DMA传输完成回调
void HAL_DMA_XferCpltCallback(DMA_HandleTypeDef *hdma)
{
if (hdma->Instance == DMA2_Stream1)
{
/* 传输完成,切换缓冲区 */
if (current_buffer == buffer1)
{
current_buffer = buffer2;
/* 处理buffer1中的数据 */
Process_Buffer(buffer1, 256);
}
else
{
current_buffer = buffer1;
/* 处理buffer2中的数据 */
Process_Buffer(buffer2, 256);
}
}
}
// DMA半传输完成回调
void HAL_DMA_XferHalfCpltCallback(DMA_HandleTypeDef *hdma)
{
if (hdma->Instance == DMA2_Stream1)
{
/* 半传输完成 */
if (current_buffer == buffer1)
{
/* 处理buffer1的前半部分 */
Process_Buffer(buffer1, 128);
}
else
{
/* 处理buffer2的前半部分 */
Process_Buffer(buffer2, 128);
}
}
}
// DMA错误处理
void HAL_DMA_ErrorCallback(DMA_HandleTypeDef *hdma)
{
uint32_t error_code = hdma->ErrorCode;
if (error_code & HAL_DMA_ERROR_TE)
{
/* 传输错误 */
dma_transfer_error_handler();
}
if (error_code & HAL_DMA_ERROR_FE)
{
/* FIFO错误 */
dma_fifo_error_handler();
}
if (error_code & HAL_DMA_ERROR_DME)
{
/* 直接模式错误 */
dma_direct_mode_error_handler();
}
if (error_code & HAL_DMA_ERROR_TIMEOUT)
{
/* 超时错误 */
dma_timeout_error_handler();
}
/* 重新初始化DMA */
HAL_DMA_DeInit(hdma);
HAL_DMA_Init(hdma);
}
9.2 DMA链表传输
/**
* @brief DMA链表传输(仅限STM32H7等高级系列)
*/
#if defined(STM32H7xx)
// DMA链表节点结构
typedef struct
{
uint32_t SrcAddress; /* 源地址 */
uint32_t DstAddress; /* 目标地址 */
uint32_t DataLength; /* 数据长度 */
uint32_t LinkedListNode; /* 下一个节点地址 */
uint32_t ControlRegister; /* 控制寄存器 */
} DMA_NodeTypeDef;
// DMA链表传输配置
void DMA_LinkedList_Transfer(void)
{
/* 定义三个DMA节点 */
DMA_NodeTypeDef node1 __attribute__((aligned(32)));
DMA_NodeTypeDef node2 __attribute__((aligned(32)));
DMA_NodeTypeDef node3 __attribute__((aligned(32)));
uint32_t src_data1[256];
uint32_t src_data2[256];
uint32_t src_data3[256];
uint32_t dst_data1[256];
uint32_t dst_data2[256];
uint32_t dst_data3[256];
/* 初始化数据 */
for (int i = 0; i < 256; i++)
{
src_data1[i] = i;
src_data2[i] = i + 256;
src_data3[i] = i + 512;
}
/* 配置节点1 */
node1.SrcAddress = (uint32_t)src_data1;
node1.DstAddress = (uint32_t)dst_data1;
node1.DataLength = 256;
node1.LinkedListNode = (uint32_t)&node2; /* 指向节点2 */
node1.ControlRegister =
(DMA_SxCR_CHSEL_0 | /* 通道选择 */
DMA_SxCR_DIR_0 | /* 内存到内存 */
DMA_SxCR_MINC | /* 内存递增 */
DMA_SxCR_PINC | /* 外设递增 */
DMA_SxCR_TCIE | /* 传输完成中断 */
DMA_SxCR_HTIE | /* 半传输中断 */
(DMA_SxCR_PSIZE_1 | DMA_SxCR_PSIZE_0) | /* 外设字大小 */
(DMA_SxCR_MSIZE_1 | DMA_SxCR_MSIZE_0) | /* 内存字大小 */
DMA_SxCR_PL_0); /* 中等优先级 */
/* 配置节点2 */
node2.SrcAddress = (uint32_t)src_data2;
node2.DstAddress = (uint32_t)dst_data2;
node2.DataLength = 256;
node2.LinkedListNode = (uint32_t)&node3; /* 指向节点3 */
node2.ControlRegister = node1.ControlRegister;
/* 配置节点3 */
node3.SrcAddress = (uint32_t)src_data3;
node3.DstAddress = (uint32_t)dst_data3;
node3.DataLength = 256;
node3.LinkedListNode = 0; /* 链表结束 */
node3.ControlRegister = node1.ControlRegister;
DMA_HandleTypeDef hdma_link;
hdma_link.Instance = DMA1_Stream0;
hdma_link.Init.Request = DMA_REQUEST_MEM2MEM;
hdma_link.Init.Direction = DMA_MEMORY_TO_MEMORY;
hdma_link.Init.PeriphInc = DMA_PINC_ENABLE;
hdma_link.Init.MemInc = DMA_MINC_ENABLE;
hdma_link.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;
hdma_link.Init.MemDataAlignment = DMA_MDATAALIGN_WORD;
hdma_link.Init.Mode = DMA_NORMAL;
hdma_link.Init.Priority = DMA_PRIORITY_MEDIUM;
HAL_DMA_Init(&hdma_link);
/* 配置链表模式 */
HAL_DMAEx_List_Init(&hdma_link);
/* 创建链表 */
HAL_DMAEx_List_BuildNode(&hdma_link, &node1);
HAL_DMAEx_List_BuildNode(&hdma_link, &node2);
HAL_DMAEx_List_BuildNode(&hdma_link, &node3);
/* 链接节点 */
HAL_DMAEx_List_LinkQ(&hdma_link, &node1, &node2);
HAL_DMAEx_List_LinkQ(&hdma_link, &node2, &node3);
/* 设置链表头 */
HAL_DMAEx_List_SetNode(&hdma_link, &node1);
/* 启动链表传输 */
HAL_DMAEx_List_Start_IT(&hdma_link);
}
#endif
// DMA与缓存一致性处理(Cortex-M7)
void DMA_Cache_Coherence(void)
{
#if defined(__DCACHE_PRESENT) && (__DCACHE_PRESENT == 1U)
uint32_t dma_buffer[256] __attribute__((aligned(32)));
/* 准备DMA缓冲区数据 */
for (int i = 0; i < 256; i++)
{
dma_buffer[i] = i;
}
/* 1. 清理缓存(Cache Clean):将缓存中的数据写回内存 */
/* 在DMA读取之前,确保内存中的数据是最新的 */
SCB_CleanDCache_by_Addr((uint32_t*)dma_buffer, sizeof(dma_buffer));
/* 2. 执行DMA传输(从内存到外设) */
HAL_DMA_Start(&hdma, (uint32_t)dma_buffer, (uint32_t)&SOME_PERIPHERAL->DR, 256);
/* 3. 等待DMA传输完成 */
HAL_DMA_PollForTransfer(&hdma, HAL_DMA_FULL_TRANSFER, 1000);
/* 4. 无效化缓存(Cache Invalidate):丢弃缓存中的旧数据 */
/* 在CPU读取DMA写入的数据之前,确保缓存无效 */
SCB_InvalidateDCache_by_Addr((uint32_t*)dma_buffer, sizeof(dma_buffer));
/* 5. 现在CPU可以安全地读取DMA写入的数据 */
#endif
}
第十章:低功耗与电源管理
10.1 STM32低功耗模式
/**
* @brief STM32低功耗模式配置
*/
// 低功耗模式枚举
typedef enum
{
PWR_RUN_MODE = 0, /* 运行模式 */
PWR_SLEEP_MODE, /* 睡眠模式 */
PWR_STOP_MODE, /* 停止模式 */
PWR_STANDBY_MODE, /* 待机模式 */
PWR_SHUTDOWN_MODE /* 关机模式(某些系列支持) */
} PWR_ModeTypeDef;
// 睡眠模式进入与退出
void Enter_Sleep_Mode(void)
{
/* 配置唤醒源(可选) */
// 可以配置EXTI、RTC等作为唤醒源
/* 设置休眠深度 */
__HAL_PWR_CLEAR_FLAG(PWR_FLAG_WU); /* 清除唤醒标志 */
/* 进入睡眠模式 */
HAL_PWR_EnterSLEEPMode(PWR_MAINREGULATOR_ON, PWR_SLEEPENTRY_WFI);
/* 唤醒后继续执行 */
SystemClock_Config(); /* 可能需要重新配置时钟 */
}
// 停止模式进入与退出
void Enter_Stop_Mode(void)
{
/* 配置唤醒源 */
/* 1. 配置RTC闹钟唤醒 */
RTC_AlarmTypeDef sAlarm = {0};
sAlarm.AlarmTime.Hours = 0;
sAlarm.AlarmTime.Minutes = 1;
sAlarm.AlarmTime.Seconds = 0;
sAlarm.Alarm = RTC_ALARM_A;
HAL_RTC_SetAlarm_IT(&hrtc, &sAlarm, RTC_FORMAT_BIN);
/* 2. 配置EXTI唤醒 */
__HAL_RCC_PWR_CLK_ENABLE();
__HAL_PWR_CLEAR_FLAG(PWR_FLAG_WU);
/* 配置PA0为唤醒引脚 */
HAL_PWR_EnableWakeUpPin(PWR_WAKEUP_PIN1);
/* 进入停止模式 */
HAL_PWR_EnterSTOPMode(PWR_LOWPOWERREGULATOR_ON, PWR_STOPENTRY_WFI);
/* 唤醒后 */
SystemClock_Config(); /* 必须重新配置系统时钟 */
/* 重新初始化外设 */
MX_GPIO_Init();
MX_USART1_UART_Init();
// ... 其他外设重新初始化
}
// 待机模式进入与退出
void Enter_Standby_Mode(void)
{
/* 配置唤醒源 */
/* 1. RTC唤醒 */
RTC_AlarmTypeDef sAlarm = {0};
sAlarm.AlarmTime.Hours = 0;
sAlarm.AlarmTime.Minutes = 10; /* 10分钟后唤醒 */
sAlarm.AlarmTime.Seconds = 0;
sAlarm.Alarm = RTC_ALARM_A;
HAL_RTC_SetAlarm_IT(&hrtc, &sAlarm, RTC_FORMAT_BIN);
/* 2. WKUP引脚唤醒 */
HAL_PWR_EnableWakeUpPin(PWR_WAKEUP_PIN1);
/* 3. 独立看门狗唤醒(如果使能) */
/* 清除所有唤醒标志 */
__HAL_PWR_CLEAR_FLAG(PWR_FLAG_WU);
__HAL_PWR_CLEAR_FLAG(PWR_FLAG_SB);
/* 进入待机模式 */
HAL_PWR_EnterSTANDBYMode();
/* 待机模式唤醒后,MCU会复位,从main函数开始执行 */
}
// 低功耗模式下的RTC配置
void RTC_LowPower_Config(void)
{
RTC_HandleTypeDef hrtc;
hrtc.Instance = RTC;
hrtc.Init.HourFormat = RTC_HOURFORMAT_24;
hrtc.Init.AsynchPrediv = 127;
hrtc.Init.SynchPrediv = 255;
hrtc.Init.OutPut = RTC_OUTPUT_DISABLE;
hrtc.Init.OutPutPolarity = RTC_OUTPUT_POLARITY_HIGH;
hrtc.Init.OutPutType = RTC_OUTPUT_TYPE_OPENDRAIN;
HAL_RTC_Init(&hrtc);
/* 配置RTC闹钟 */
RTC_AlarmTypeDef sAlarm = {0};
sAlarm.AlarmTime.Hours = 0;
sAlarm.AlarmTime.Minutes = 0;
sAlarm.AlarmTime.Seconds = 30; /* 30秒后唤醒 */
sAlarm.AlarmMask = RTC_ALARMMASK_NONE;
sAlarm.AlarmSubSecondMask = RTC_ALARMSUBSECONDMASK_ALL;
sAlarm.AlarmDateWeekDaySel = RTC_ALARMDATEWEEKDAYSEL_DATE;
sAlarm.AlarmDateWeekDay = 1;
sAlarm.Alarm = RTC_ALARM_A;
HAL_RTC_SetAlarm_IT(&hrtc, &sAlarm, RTC_FORMAT_BIN);
}
// 低功耗模式下的GPIO配置
void GPIO_LowPower_Config(void)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
/* 将所有未使用的GPIO配置为模拟输入以降低功耗 */
GPIO_InitStruct.Pin = GPIO_PIN_All;
GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);
// ... 其他GPIO端口
/* 配置使用的GPIO为适当的状态 */
/* 输出引脚:推挽输出,低电平 */
GPIO_InitStruct.Pin = GPIO_PIN_13; /* LED引脚 */
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_RESET);
/* 输入引脚:无上拉下拉 */
GPIO_InitStruct.Pin = GPIO_PIN_0; /* 按键引脚 */
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
}
// 动态电压调节(某些系列支持)
void Dynamic_Voltage_Scaling(void)
{
#if defined(PWR_REGULATOR_VOLTAGE_SCALE1) && defined(PWR_REGULATOR_VOLTAGE_SCALE2)
/* 切换到高电压范围(高性能) */
__HAL_RCC_PWR_CLK_ENABLE();
__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
/* 提高系统时钟 */
SystemClock_Config_HighPerformance();
/* 执行高性能任务 */
Perform_HighPerformance_Task();
/* 切换到低电压范围(低功耗) */
__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE2);
/* 降低系统时钟 */
SystemClock_Config_LowPower();
/* 进入低功耗模式或执行低功耗任务 */
Enter_Sleep_Mode();
#endif
}
10.2 低功耗外设管理
/**
* @brief 低功耗外设管理策略
*/
// 外设时钟管理系统
typedef struct
{
uint32_t peripheral; /* 外设标识 */
uint8_t is_enabled; /* 是否使能 */
uint32_t enable_time; /* 使能时间戳 */
uint32_t timeout; /* 超时时间(ms) */
} Peripheral_Manager_t;
// 外设管理表
Peripheral_Manager_t peripheral_table[] = {
{PERIPH_USART1, 0, 0, 100}, /* USART1,100ms超时 */
{PERIPH_SPI1, 0, 0, 50}, /* SPI1,50ms超时 */
{PERIPH_I2C1, 0, 0, 200}, /* I2C1,200ms超时 */
{PERIPH_ADC1, 0, 0, 10}, /* ADC1,10ms超时 */
{PERIPH_TIM2, 0, 0, 0}, /* TIM2,无超时(常开) */
};
// 使能外设
void Enable_Peripheral(uint32_t peripheral)
{
for (int i = 0; i < sizeof(peripheral_table)/sizeof(peripheral_table[0]); i++)
{
if (peripheral_table[i].peripheral == peripheral)
{
peripheral_table[i].is_enabled = 1;
peripheral_table[i].enable_time = HAL_GetTick();
/* 实际使能外设时钟 */
switch (peripheral)
{
case PERIPH_USART1:
__HAL_RCC_USART1_CLK_ENABLE();
break;
case PERIPH_SPI1:
__HAL_RCC_SPI1_CLK_ENABLE();
break;
case PERIPH_I2C1:
__HAL_RCC_I2C1_CLK_ENABLE();
break;
case PERIPH_ADC1:
__HAL_RCC_ADC1_CLK_ENABLE();
break;
case PERIPH_TIM2:
__HAL_RCC_TIM2_CLK_ENABLE();
break;
}
break;
}
}
}
// 禁用外设
void Disable_Peripheral(uint32_t peripheral)
{
for (int i = 0; i < sizeof(peripheral_table)/sizeof(peripheral_table[0]); i++)
{
if (peripheral_table[i].peripheral == peripheral)
{
peripheral_table[i].is_enabled = 0;
/* 实际禁用外设时钟 */
switch (peripheral)
{
case PERIPH_USART1:
__HAL_RCC_USART1_CLK_DISABLE();
break;
case PERIPH_SPI1:
__HAL_RCC_SPI1_CLK_DISABLE();
break;
case PERIPH_I2C1:
__HAL_RCC_I2C1_CLK_DISABLE();
break;
case PERIPH_ADC1:
__HAL_RCC_ADC1_CLK_DISABLE();
break;
case PERIPH_TIM2:
/* TIM2可能用于系统时钟,不关闭 */
break;
}
break;
}
}
}
// 外设超时检查任务(在systick中断或定时器中调用)
void Peripheral_Timeout_Check(void)
{
uint32_t current_time = HAL_GetTick();
for (int i = 0; i < sizeof(peripheral_table)/sizeof(peripheral_table[0]); i++)
{
if (peripheral_table[i].is_enabled &&
peripheral_table[i].timeout > 0)
{
if ((current_time - peripheral_table[i].enable_time) >
peripheral_table[i].timeout)
{
/* 外设超时,自动禁用 */
Disable_Peripheral(peripheral_table[i].peripheral);
}
}
}
}
// 低功耗ADC采样策略
void LowPower_ADC_Sampling(void)
{
ADC_HandleTypeDef hadc1;
/* 配置ADC为单次转换模式 */
hadc1.Init.ContinuousConvMode = DISABLE; /* 单次转换 */
hadc1.Init.DiscontinuousConvMode = DISABLE;
hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;
HAL_ADC_Init(&hadc1);
while (1)
{
/* 使能ADC时钟 */
__HAL_RCC_ADC1_CLK_ENABLE();
/* 执行ADC转换 */
HAL_ADC_Start(&hadc1);
HAL_ADC_PollForConversion(&hadc1, 10);
uint32_t adc_value = HAL_ADC_GetValue(&hadc1);
HAL_ADC_Stop(&hadc1);
/* 禁用ADC时钟以省电 */
__HAL_RCC_ADC1_CLK_DISABLE();
/* 处理ADC值 */
Process_ADC_Value(adc_value);
/* 进入睡眠模式等待下一次采样 */
HAL_PWR_EnterSLEEPMode(PWR_MAINREGULATOR_ON, PWR_SLEEPENTRY_WFI);
}
}
// 低功耗定时唤醒
void LowPower_Timed_Wakeup(void)
{
/* 配置低功耗定时器(LPTIM) */
LPTIM_HandleTypeDef hlptim1;
hlptim1.Instance = LPTIM1;
hlptim1.Init.Clock.Source = LPTIM_CLOCKSOURCE_APBCLOCK_LPOSC;
hlptim1.Init.Clock.Prescaler = LPTIM_PRESCALER_DIV128;
hlptim1.Init.Trigger.Source = LPTIM_TRIGSOURCE_SOFTWARE;
hlptim1.Init.OutputPolarity = LPTIM_OUTPUTPOLARITY_HIGH;
hlptim1.Init.UpdateMode = LPTIM_UPDATE_IMMEDIATE;
hlptim1.Init.CounterSource = LPTIM_COUNTERSOURCE_INTERNAL;
HAL_LPTIM_Init(&hlptim1);
/* 设置定时器周期(1秒) */
/* LSI = 32kHz, 分频128 = 250Hz, 计数值250 = 1秒 */
HAL_LPTIM_SetOnce_Start_IT(&hlptim1, 250);
/* 进入停止模式 */
HAL_PWR_EnterSTOPMode(PWR_LOWPOWERREGULATOR_ON, PWR_STOPENTRY_WFI);
/* LPTIM中断唤醒后继续执行 */
SystemClock_Config();
/* 执行唤醒后的任务 */
Execute_Wakeup_Task();
/* 重新配置LPTIM并再次进入低功耗 */
HAL_LPTIM_SetOnce_Start_IT(&hlptim1, 250);
}
// LPTIM唤醒回调
void HAL_LPTIM_CompareMatchCallback(LPTIM_HandleTypeDef *hlptim)
{
/* 比较匹配中断,用于唤醒MCU */
if (hlptim->Instance == LPTIM1)
{
/* 清除标志位 */
__HAL_LPTIM_CLEAR_FLAG(hlptim, LPTIM_FLAG_CMPM);
}
}
第十一章:HAL库调试与优化
11.1 HAL库调试技巧
/**
* @brief HAL库调试与故障诊断
*/
// 错误处理钩子函数
void Error_Handler(void)
{
/* 获取错误信息 */
uint32_t hal_error = HAL_GetError();
uint32_t system_clock = HAL_RCC_GetSysClockFreq();
uint32_t hclk_clock = HAL_RCC_GetHCLKFreq();
uint32_t pclk1_clock = HAL_RCC_GetPCLK1Freq();
uint32_t pclk2_clock = HAL_RCC_GetPCLK2Freq();
/* 记录错误信息(可通过串口输出或保存到Flash) */
printf("HAL Error: 0x%08lX\r\n", hal_error);
printf("System Clock: %lu Hz\r\n", system_clock);
printf("HCLK: %lu Hz\r\n", hclk_clock);
printf("PCLK1: %lu Hz\r\n", pclk1_clock);
printf("PCLK2: %lu Hz\r\n", pclk2_clock);
/* 获取栈使用情况 */
Check_Stack_Usage();
/* 获取堆使用情况 */
Check_Heap_Usage();
/* 闪烁LED指示错误 */
while (1)
{
HAL_GPIO_TogglePin(LED_GPIO_Port, LED_Pin);
HAL_Delay(100);
}
}
// 栈使用情况检查
void Check_Stack_Usage(void)
{
extern uint32_t _estack; /* 栈结束地址(链接脚本定义) */
extern uint32_t _Min_Stack_Size; /* 最小栈大小 */
uint32_t *stack_start = (uint32_t*)&_estack - (_Min_Stack_Size / 4);
uint32_t stack_used = 0;
/* 计算已使用的栈空间 */
for (uint32_t i = 0; i < _Min_Stack_Size / 4; i++)
{
if (stack_start[i] != 0xAAAAAAAA) /* 栈初始化值 */
{
stack_used = (_Min_Stack_Size / 4 - i) * 4;
break;
}
}
printf("Stack Usage: %lu/%lu bytes\r\n",
stack_used, _Min_Stack_Size);
}
// 堆使用情况检查
void Check_Heap_Usage(void)
{
extern uint32_t _end; /* 堆开始地址 */
extern uint32_t _Heap_Limit; /* 堆结束地址 */
extern __IO uint32_t __brkval; /* 当前堆指针 */
uint32_t heap_size = (uint32_t)&_Heap_Limit - (uint32_t)&_end;
uint32_t heap_used = (uint32_t)__brkval - (uint32_t)&_end;
printf("Heap Usage: %lu/%lu bytes\r\n", heap_used, heap_size);
}
// HAL库超时调试
#define DEBUG_TIMEOUT 1
#if DEBUG_TIMEOUT
uint32_t timeout_debug_counter = 0;
uint32_t timeout_debug_threshold = 1000;
// 超时调试宏
#define HAL_TIMEOUT_DEBUG(__HANDLE__, __TIMEOUT__) \
do { \
timeout_debug_counter++; \
if (timeout_debug_counter > timeout_debug_threshold) { \
printf("Timeout in %s at line %d\r\n", __FILE__, __LINE__); \
printf("Handle: 0x%08lX, Timeout: %lu\r\n", \
(uint32_t)__HANDLE__, __TIMEOUT__); \
timeout_debug_counter = 0; \
} \
} while(0)
#else
#define HAL_TIMEOUT_DEBUG(__HANDLE__, __TIMEOUT__)
#endif
// 带调试信息的HAL函数包装
HAL_StatusTypeDef HAL_UART_Transmit_Debug(UART_HandleTypeDef *huart,
uint8_t *pData,
uint16_t Size,
uint32_t Timeout)
{
HAL_TIMEOUT_DEBUG(huart, Timeout);
HAL_StatusTypeDef status = HAL_UART_Transmit(huart, pData, Size, Timeout);
if (status != HAL_OK)
{
printf("UART Transmit failed: %d\r\n", status);
printf("UART State: %d, Error Code: 0x%08lX\r\n",
huart->gState, huart->ErrorCode);
}
return status;
}
// 外设状态监控
typedef struct
{
uint32_t peripheral;
uint32_t state;
uint32_t error_count;
uint32_t last_error;
uint32_t operation_count;
} Peripheral_Monitor_t;
Peripheral_Monitor_t peripheral_monitors[] = {
{PERIPH_UART1, 0, 0, 0, 0},
{PERIPH_SPI1, 0, 0, 0, 0},
{PERIPH_I2C1, 0, 0, 0, 0},
{PERIPH_ADC1, 0, 0, 0, 0},
};
void Monitor_Peripheral_State(uint32_t peripheral, uint32_t state)
{
for (int i = 0; i < sizeof(peripheral_monitors)/sizeof(peripheral_monitors[0]); i++)
{
if (peripheral_monitors[i].peripheral == peripheral)
{
peripheral_monitors[i].state = state;
peripheral_monitors[i].operation_count++;
if (state == PERIPH_STATE_ERROR)
{
peripheral_monitors[i].error_count++;
peripheral_monitors[i].last_error = HAL_GetTick();
}
break;
}
}
}
// 打印外设状态信息
void Print_Peripheral_Status(void)
{
printf("=== Peripheral Status ===\r\n");
for (int i = 0; i < sizeof(peripheral_monitors)/sizeof(peripheral_monitors[0]); i++)
{
printf("Peripheral %lu: State=%lu, Errors=%lu, Ops=%lu\r\n",
peripheral_monitors[i].peripheral,
peripheral_monitors[i].state,
peripheral_monitors[i].error_count,
peripheral_monitors[i].operation_count);
}
}
// 断言宏(用于调试)
#ifdef DEBUG
#define HAL_ASSERT(expr) \
do { \
if (!(expr)) { \
printf("Assertion failed: %s, file %s, line %d\r\n", \
#expr, __FILE__, __LINE__); \
Error_Handler(); \
} \
} while(0)
#else
#define HAL_ASSERT(expr) ((void)0)
#endif
// 在HAL库函数中使用断言
HAL_StatusTypeDef Safe_HAL_UART_Transmit(UART_HandleTypeDef *huart,
uint8_t *pData,
uint16_t Size,
uint32_t Timeout)
{
HAL_ASSERT(huart != NULL);
HAL_ASSERT(pData != NULL);
HAL_ASSERT(Size > 0);
HAL_ASSERT(huart->Instance != NULL);
return HAL_UART_Transmit(huart, pData, Size, Timeout);
}
11.2 HAL库性能优化
/**
* @brief HAL库性能优化技巧
*/
// 1. 使用直接寄存器操作优化关键路径
void Optimized_GPIO_Toggle(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)
{
/* 使用BSRR寄存器原子操作 */
GPIOx->BSRR = GPIO_Pin; /* 设置引脚 */
GPIOx->BSRR = (uint32_t)GPIO_Pin << 16; /* 复位引脚 */
}
// 2. 避免频繁的HAL_Delay调用
// 使用系统滴答计时器实现非阻塞延迟
typedef struct
{
uint32_t start_time;
uint32_t delay_ms;
uint8_t is_running;
} NonBlocking_Delay_t;
void NonBlocking_Delay_Start(NonBlocking_Delay_t *delay, uint32_t ms)
{
delay->start_time = HAL_GetTick();
delay->delay_ms = ms;
delay->is_running = 1;
}
uint8_t NonBlocking_Delay_IsElapsed(NonBlocking_Delay_t *delay)
{
if (!delay->is_running)
return 1;
if ((HAL_GetTick() - delay->start_time) >= delay->delay_ms)
{
delay->is_running = 0;
return 1;
}
return 0;
}
// 3. 优化中断处理
// 使用DMA减少中断频率
void Optimized_UART_Receive(void)
{
static uint8_t rx_buffer[256];
static uint8_t rx_index = 0;
/* 使用DMA接收数据,减少中断次数 */
HAL_UART_Receive_DMA(&huart1, rx_buffer, sizeof(rx_buffer));
/* 在DMA传输完成中断中处理数据 */
}
// 4. 内存池管理(避免频繁malloc/free)
#define MEMORY_POOL_SIZE 1024
#define MEMORY_BLOCK_SIZE 32
#define NUM_BLOCKS (MEMORY_POOL_SIZE / MEMORY_BLOCK_SIZE)
typedef struct
{
uint8_t pool[MEMORY_POOL_SIZE];
uint8_t block_map[NUM_BLOCKS]; /* 0=空闲, 1=已分配 */
} Memory_Pool_t;
void* Memory_Pool_Alloc(Memory_Pool_t *pool, uint32_t size)
{
if (size > MEMORY_BLOCK_SIZE)
return NULL;
for (int i = 0; i < NUM_BLOCKS; i++)
{
if (pool->block_map[i] == 0)
{
pool->block_map[i] = 1;
return &pool->pool[i * MEMORY_BLOCK_SIZE];
}
}
return NULL;
}
void Memory_Pool_Free(Memory_Pool_t *pool, void *ptr)
{
uint32_t index = ((uint8_t*)ptr - pool->pool) / MEMORY_BLOCK_SIZE;
if (index < NUM_BLOCKS)
{
pool->block_map[index] = 0;
}
}
// 5. 缓存对齐优化
// 使用C11对齐特性
typedef struct __attribute__((aligned(32)))
{
uint32_t data[256];
uint32_t counter;
} Cache_Aligned_Buffer_t;
// 6. 使用内联函数减少函数调用开销
static inline void Fast_GPIO_Set(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)
{
GPIOx->BSRR = GPIO_Pin;
}
static inline void Fast_GPIO_Reset(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)
{
GPIOx->BSRR = (uint32_t)GPIO_Pin << 16;
}
static inline uint8_t Fast_GPIO_Read(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)
{
return ((GPIOx->IDR & GPIO_Pin) != 0);
}
// 7. 循环展开优化
void Optimized_Memory_Copy(uint8_t *dst, uint8_t *src, uint32_t size)
{
uint32_t *dst32 = (uint32_t*)dst;
uint32_t *src32 = (uint32_t*)src;
/* 4字节对齐拷贝 */
uint32_t word_count = size / 4;
for (uint32_t i = 0; i < word_count; i += 4)
{
/* 循环展开:一次处理4个字 */
dst32[i] = src32[i];
dst32[i+1] = src32[i+1];
dst32[i+2] = src32[i+2];
dst32[i+3] = src32[i+3];
}
/* 处理剩余字节 */
uint8_t *dst8 = (uint8_t*)&dst32[word_count];
uint8_t *src8 = (uint8_t*)&src32[word_count];
for (uint32_t i = 0; i < (size % 4); i++)
{
dst8[i] = src8[i];
}
}
// 8. 使用查表法替代复杂计算
const uint16_t sin_table[256] = {
2048, 2098, 2148, 2198, 2248, 2298, 2348, 2398,
// ... 完整的正弦表
};
uint16_t Fast_Sin(uint8_t angle)
{
return sin_table[angle];
}
// 9. 预计算优化
typedef struct
{
float sin_value;
float cos_value;
uint32_t timestamp;
} Precomputed_Values_t;
Precomputed_Values_t precomputed[360];
void Precompute_Trigonometric_Values(void)
{
for (int i = 0; i < 360; i++)
{
float rad = i * 3.1415926535f / 180.0f;
precomputed[i].sin_value = sinf(rad);
precomputed[i].cos_value = cosf(rad);
precomputed[i].timestamp = HAL_GetTick();
}
}
// 10. 使用硬件加速器(如果可用)
void Hardware_Accelerated_CRC32(void)
{
#if defined(CRC)
/* 使用STM32硬件CRC计算 */
__HAL_RCC_CRC_CLK_ENABLE();
uint32_t data[] = {0x12345678, 0x9ABCDEF0, 0x11223344, 0x55667788};
/* 复位CRC计算单元 */
HAL_CRC_DeInit(&hcrc);
/* 计算CRC */
uint32_t crc = HAL_CRC_Calculate(&hcrc, data, 4);
printf("Hardware CRC32: 0x%08lX\r\n", crc);
#endif
}
// 11. 电源管理优化
void Power_Optimization(void)
{
/* 动态调整系统时钟 */
if (system_load_high)
{
/* 高性能模式 */
SystemClock_Config_HighSpeed();
__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
}
else
{
/* 低功耗模式 */
SystemClock_Config_LowSpeed();
__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE2);
}
/* 禁用未使用的外设时钟 */
__HAL_RCC_USART2_CLK_DISABLE();
__HAL_RCC_SPI2_CLK_DISABLE();
__HAL_RCC_TIM3_CLK_DISABLE();
/* 配置未使用的GPIO为模拟输入 */
GPIO_InitTypeDef GPIO_InitStruct = {0};
GPIO_InitStruct.Pin = GPIO_PIN_All;
GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
}
// 12. 编译优化选项
/*
在Makefile或IDE中设置优化选项:
- -O2或-O3:代码大小和执行速度优化
- -Os:代码大小优化
- -flto:链接时优化
- -ffunction-sections -fdata-sections:配合链接脚本进行垃圾回收
*/
// 链接脚本中的优化
/*
在链接脚本中添加:
.text : {
*(.text .text.*) /* 按函数排序,提高缓存命中率
. = ALIGN(4);
} > FLASH
*/
第十二章:HAL库项目实战
12.1 多任务系统设计
/**
* @brief 基于HAL库的简单多任务系统
*/
// 任务控制块
typedef struct
{
void (*task_func)(void); /* 任务函数 */
uint32_t interval_ms; /* 执行间隔 */
uint32_t last_run_time; /* 上次执行时间 */
uint8_t enabled; /* 任务使能标志 */
uint8_t priority; /* 任务优先级 */
char name[16]; /* 任务名称 */
} Task_Control_Block_t;
// 任务列表
#define MAX_TASKS 10
Task_Control_Block_t task_list[MAX_TASKS];
uint8_t task_count = 0;
// 任务调度器初始化
void Task_Scheduler_Init(void)
{
memset(task_list, 0, sizeof(task_list));
task_count = 0;
}
// 注册任务
uint8_t Task_Register(void (*func)(void),
uint32_t interval_ms,
uint8_t priority,
const char *name)
{
if (task_count >= MAX_TASKS)
return 0;
task_list[task_count].task_func = func;
task_list[task_count].interval_ms = interval_ms;
task_list[task_count].last_run_time = 0;
task_list[task_count].enabled = 1;
task_list[task_count].priority = priority;
strncpy(task_list[task_count].name, name, 15);
task_list[task_count].name[15] = '\0';
task_count++;
return 1;
}
// 任务调度器(在systick中断中调用)
void Task_Scheduler_Run(void)
{
static uint32_t last_schedule_time = 0;
uint32_t current_time = HAL_GetTick();
/* 调度周期:1ms */
if ((current_time - last_schedule_time) < 1)
return;
last_schedule_time = current_time;
/* 按优先级执行任务 */
for (int priority = 0; priority <= 255; priority++)
{
for (int i = 0; i < task_count; i++)
{
if (task_list[i].enabled &&
task_list[i].priority == priority)
{
/* 检查是否到达执行时间 */
if ((current_time - task_list[i].last_run_time) >=
task_list[i].interval_ms)
{
/* 执行任务 */
task_list[i].task_func();
task_list[i].last_run_time = current_time;
}
}
}
}
}
// 任务监控
void Task_Monitor(void)
{
static uint32_t last_monitor_time = 0;
uint32_t current_time = HAL_GetTick();
if ((current_time - last_monitor_time) >= 1000) /* 1秒监控一次 */
{
printf("=== Task Monitor ===\r\n");
for (int i = 0; i < task_count; i++)
{
uint32_t exec_time = current_time - task_list[i].last_run_time;
printf("Task %s: Priority=%d, Interval=%lums, "
"LastExec=%lums ago, Enabled=%d\r\n",
task_list[i].name,
task_list[i].priority,
task_list[i].interval_ms,
exec_time,
task_list[i].enabled);
}
last_monitor_time = current_time;
}
}
// 示例任务定义
void LED_Task(void)
{
HAL_GPIO_TogglePin(LED_GPIO_Port, LED_Pin);
}
void Sensor_Read_Task(void)
{
/* 读取传感器数据 */
float temperature = Read_Temperature();
float humidity = Read_Humidity();
/* 处理传感器数据 */
Process_Sensor_Data(temperature, humidity);
}
void Communication_Task(void)
{
/* 检查是否有数据需要发送 */
if (Has_Data_To_Send())
{
Send_Data_Over_UART();
}
/* 检查是否有接收到的数据 */
if (Has_Data_Received())
{
Process_Received_Data();
}
}
// 主函数中的任务调度
int main(void)
{
HAL_Init();
SystemClock_Config();
/* 硬件初始化 */
MX_GPIO_Init();
MX_USART1_UART_Init();
MX_I2C1_Init();
MX_SPI1_Init();
/* 任务调度器初始化 */
Task_Scheduler_Init();
/* 注册任务 */
Task_Register(LED_Task, 500, 1, "LED Blink"); /* 500ms,低优先级 */
Task_Register(Sensor_Read_Task, 1000, 0, "Sensor Read"); /* 1s,高优先级 */
Task_Register(Communication_Task, 100, 0, "Comm Task"); /* 100ms,高优先级 */
Task_Register(Task_Monitor, 1000, 2, "Task Monitor"); /* 1s,最低优先级 */
while (1)
{
/* 运行任务调度器 */
Task_Scheduler_Run();
/* 空闲任务:进入低功耗模式 */
HAL_PWR_EnterSLEEPMode(PWR_MAINREGULATOR_ON, PWR_SLEEPENTRY_WFI);
}
}
12.2 数据采集与传输系统
/**
* @brief 完整的数据采集与传输系统
*/
// 数据包结构
#pragma pack(push, 1) /* 字节对齐 */
typedef struct
{
uint32_t timestamp; /* 时间戳 */
uint16_t packet_id; /* 数据包ID */
uint8_t sensor_id; /* 传感器ID */
float temperature; /* 温度 */
float humidity; /* 湿度 */
float pressure; /* 气压 */
uint16_t light_intensity; /* 光照强度 */
uint16_t battery_voltage; /* 电池电压 */
uint16_t checksum; /* CRC校验和 */
} Sensor_Data_Packet_t;
#pragma pack(pop) /* 恢复对齐 */
// 数据缓冲区
#define DATA_BUFFER_SIZE 100
Sensor_Data_Packet_t data_buffer[DATA_BUFFER_SIZE];
uint16_t data_write_index = 0;
uint16_t data_read_index = 0;
uint16_t data_count = 0;
// 数据采集任务
void Data_Acquisition_Task(void)
{
static uint32_t last_acquisition_time = 0;
uint32_t current_time = HAL_GetTick();
/* 采集周期:1秒 */
if ((current_time - last_acquisition_time) < 1000)
return;
last_acquisition_time = current_time;
/* 检查缓冲区是否已满 */
if (data_count >= DATA_BUFFER_SIZE)
{
printf("Data buffer full!\r\n");
return;
}
/* 采集传感器数据 */
Sensor_Data_Packet_t packet;
packet.timestamp = current_time;
packet.packet_id = Get_Next_Packet_ID();
packet.sensor_id = SENSOR_ID;
packet.temperature = Read_Temperature_Sensor();
packet.humidity = Read_Humidity_Sensor();
packet.pressure = Read_Pressure_Sensor();
packet.light_intensity = Read_Light_Sensor();
packet.battery_voltage = Read_Battery_Voltage();
/* 计算校验和 */
packet.checksum = Calculate_CRC16((uint8_t*)&packet,
sizeof(packet) - sizeof(uint16_t));
/* 存储到缓冲区 */
data_buffer[data_write_index] = packet;
data_write_index = (data_write_index + 1) % DATA_BUFFER_SIZE;
data_count++;
printf("Data acquired: Temp=%.2fC, Hum=%.1f%%, Packets=%d\r\n",
packet.temperature, packet.humidity, data_count);
}
// 数据传输任务
void Data_Transmission_Task(void)
{
static uint32_t last_transmission_time = 0;
uint32_t current_time = HAL_GetTick();
/* 传输周期:5秒或有数据时立即发送 */
if ((current_time - last_transmission_time) < 5000 && data_count < 10)
return;
/* 检查是否有数据需要传输 */
if (data_count == 0)
return;
last_transmission_time = current_time;
/* 准备传输缓冲区 */
uint8_t tx_buffer[1024];
uint16_t tx_index = 0;
/* 添加协议头 */
tx_buffer[tx_index++] = 0xAA;
tx_buffer[tx_index++] = 0x55;
tx_buffer[tx_index++] = (uint8_t)(data_count & 0xFF);
tx_buffer[tx_index++] = (uint8_t)((data_count >> 8) & 0xFF);
/* 添加数据包 */
uint16_t packets_to_send = (data_count > 5) ? 5 : data_count; /* 每次最多发送5个包 */
for (int i = 0; i < packets_to_send; i++)
{
Sensor_Data_Packet_t *packet = &data_buffer[data_read_index];
memcpy(&tx_buffer[tx_index], packet, sizeof(Sensor_Data_Packet_t));
tx_index += sizeof(Sensor_Data_Packet_t);
data_read_index = (data_read_index + 1) % DATA_BUFFER_SIZE;
data_count--;
}
/* 计算并添加CRC校验 */
uint16_t crc = Calculate_CRC16(tx_buffer, tx_index);
tx_buffer[tx_index++] = (uint8_t)(crc >> 8);
tx_buffer[tx_index++] = (uint8_t)(crc & 0xFF);
/* 通过UART发送数据 */
HAL_UART_Transmit_DMA(&huart1, tx_buffer, tx_index);
printf("Transmitted %d packets, %d remaining\r\n",
packets_to_send, data_count);
}
// 数据持久化(存储到Flash)
void Data_Persistence_Task(void)
{
static uint32_t last_save_time = 0;
uint32_t current_time = HAL_GetTick();
/* 保存周期:30秒或缓冲区快满时 */
if ((current_time - last_save_time) < 30000 && data_count < (DATA_BUFFER_SIZE * 0.8))
return;
last_save_time = current_time;
/* 检查Flash是否已满 */
if (Is_Flash_Full())
{
printf("Flash storage full!\r\n");
return;
}
/* 保存数据到Flash */
uint16_t packets_to_save = data_count;
for (int i = 0; i < packets_to_save; i++)
{
Sensor_Data_Packet_t *packet = &data_buffer[data_read_index];
/* 写入Flash */
if (Write_To_Flash(packet, sizeof(Sensor_Data_Packet_t)) != HAL_OK)
{
printf("Flash write failed!\r\n");
break;
}
data_read_index = (data_read_index + 1) % DATA_BUFFER_SIZE;
data_count--;
}
printf("Saved %d packets to Flash, %d remaining in buffer\r\n",
packets_to_save, data_count);
}
// Flash存储管理
#define FLASH_PAGE_SIZE 2048
#define FLASH_TOTAL_PAGES 128
#define FLASH_START_ADDRESS 0x08020000 /* Bank2起始地址 */
typedef struct
{
uint32_t start_address;
uint32_t end_address;
uint32_t write_pointer;
uint32_t read_pointer;
uint32_t used_pages;
uint32_t total_pages;
} Flash_Storage_t;
Flash_Storage_t flash_storage;
void Flash_Storage_Init(void)
{
flash_storage.start_address = FLASH_START_ADDRESS;
flash_storage.end_address = FLASH_START_ADDRESS + (FLASH_TOTAL_PAGES * FLASH_PAGE_SIZE);
flash_storage.write_pointer = FLASH_START_ADDRESS;
flash_storage.read_pointer = FLASH_START_ADDRESS;
flash_storage.used_pages = 0;
flash_storage.total_pages = FLASH_TOTAL_PAGES;
/* 查找最后的写入位置 */
Find_Last_Write_Position();
}
HAL_StatusTypeDef Write_To_Flash(void *data, uint32_t size)
{
/* 检查Flash是否已满 */
if (flash_storage.used_pages >= flash_storage.total_pages)
return HAL_ERROR;
/* 检查当前页是否有足够空间 */
uint32_t page_start = flash_storage.write_pointer & ~(FLASH_PAGE_SIZE - 1);
uint32_t page_end = page_start + FLASH_PAGE_SIZE;
if ((flash_storage.write_pointer + size) > page_end)
{
/* 需要擦除新的一页 */
if (Erase_Flash_Page(page_end) != HAL_OK)
return HAL_ERROR;
flash_storage.write_pointer = page_end;
flash_storage.used_pages++;
}
/* 写入数据 */
HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD,
flash_storage.write_pointer,
*(uint32_t*)data);
flash_storage.write_pointer += size;
return HAL_OK;
}
// 系统监控任务
void System_Monitor_Task(void)
{
static uint32_t last_monitor_time = 0;
uint32_t current_time = HAL_GetTick();
if ((current_time - last_monitor_time) < 10000) /* 10秒监控一次 */
return;
last_monitor_time = current_time;
/* 获取系统信息 */
uint32_t free_heap = Get_Free_Heap_Size();
uint32_t stack_usage = Get_Stack_Usage();
float cpu_usage = Calculate_CPU_Usage();
uint32_t uptime = Get_System_Uptime();
/* 获取电源信息 */
float battery_level = Read_Battery_Level();
uint8_t charging_status = Get_Charging_Status();
/* 获取网络信息(如果有) */
int8_t rssi = Get_WiFi_RSSI();
uint8_t network_status = Get_Network_Status();
/* 打印系统状态 */
printf("=== System Status ===\r\n");
printf("Uptime: %lu seconds\r\n", uptime);
printf("CPU Usage: %.1f%%\r\n", cpu_usage);
printf("Free Heap: %lu bytes\r\n", free_heap);
printf("Stack Usage: %lu bytes\r\n", stack_usage);
printf("Battery: %.1f%% %s\r\n",
battery_level,
charging_status ? "(Charging)" : "");
printf("Data Buffer: %d/%d packets\r\n", data_count, DATA_BUFFER_SIZE);
printf("Flash Used: %lu/%lu pages\r\n",
flash_storage.used_pages, flash_storage.total_pages);
if (network_status)
{
printf("WiFi RSSI: %d dBm\r\n", rssi);
}
}
// 主应用程序
int main(void)
{
/* HAL库初始化 */
HAL_Init();
/* 配置系统时钟 */
SystemClock_Config();
/* 初始化所有外设 */
MX_GPIO_Init();
MX_USART1_UART_Init();
MX_I2C1_Init();
MX_SPI1_Init();
MX_ADC1_Init();
MX_RTC_Init();
/* 初始化文件系统(如果需要) */
FATFS_Init();
/* 初始化Flash存储 */
Flash_Storage_Init();
/* 初始化任务调度器 */
Task_Scheduler_Init();
/* 注册系统任务 */
Task_Register(Data_Acquisition_Task, 1000, 0, "Data Acquisition");
Task_Register(Data_Transmission_Task, 100, 1, "Data Transmission");
Task_Register(Data_Persistence_Task, 5000, 2, "Data Persistence");
Task_Register(System_Monitor_Task, 10000, 3, "System Monitor");
/* 启动看门狗(如果需要) */
IWDG_Init();
printf("System started successfully!\r\n");
/* 主循环 */
while (1)
{
/* 运行任务调度器 */
Task_Scheduler_Run();
/* 喂狗 */
HAL_IWDG_Refresh(&hiwdg);
/* 空闲时进入低功耗模式 */
if (Is_System_Idle())
{
HAL_PWR_EnterSLEEPMode(PWR_MAINREGULATOR_ON, PWR_SLEEPENTRY_WFI);
}
}
}
第十三章:HAL库最佳实践总结
13.1 代码规范与架构设计
- 模块化设计原则
// 良好的模块化示例
// sensor_module.h
#ifndef SENSOR_MODULE_H
#define SENSOR_MODULE_H
#include "stm32f4xx_hal.h"
typedef struct {
float temperature;
float humidity;
float pressure;
} SensorData_t;
typedef enum {
SENSOR_OK = 0,
SENSOR_ERROR,
SENSOR_TIMEOUT
} SensorStatus_t;
SensorStatus_t Sensor_Init(I2C_HandleTypeDef *hi2c);
SensorStatus_t Sensor_Read(SensorData_t *data);
void Sensor_Deinit(void);
#endif /* SENSOR_MODULE_H */
// sensor_module.c
#include "sensor_module.h"
static I2C_HandleTypeDef *sensor_i2c = NULL;
SensorStatus_t Sensor_Init(I2C_HandleTypeDef *hi2c)
{
if (hi2c == NULL) {
return SENSOR_ERROR;
}
sensor_i2c = hi2c;
// 传感器初始化代码
// ...
return SENSOR_OK;
}
- 错误处理策略
// 统一的错误处理框架
typedef enum {
ERROR_NONE = 0,
ERROR_HAL,
ERROR_TIMEOUT,
ERROR_COMMUNICATION,
ERROR_MEMORY,
ERROR_SENSOR,
ERROR_CONFIG
} ErrorCode_t;
typedef struct {
ErrorCode_t code;
uint32_t timestamp;
const char *module;
uint32_t line;
} ErrorInfo_t;
#define ERROR_LOG(module, code) \
do { \
ErrorInfo_t error = { \
.code = code, \
.timestamp = HAL_GetTick(), \
.module = module, \
.line = __LINE__ \
}; \
Log_Error(&error); \
} while(0)
void Log_Error(ErrorInfo_t *error)
{
printf("[ERROR] Module: %s, Code: %d, Time: %lu, Line: %lu\r\n",
error->module, error->code, error->timestamp, error->line);
// 可选:保存错误到非易失存储器
Save_Error_To_Flash(error);
}
13.2 性能优化建议
- 时钟配置优化
// 根据需求动态调整时钟
void Dynamic_Clock_Adjustment(SystemMode_t mode)
{
switch (mode) {
case MODE_HIGH_PERFORMANCE:
// 配置为最高性能
__HAL_RCC_PLLI2S_DISABLE();
__HAL_RCC_PLLSAI_DISABLE();
SystemClock_Config_HighSpeed();
break;
case MODE_BALANCED:
// 平衡模式
SystemClock_Config_Balanced();
break;
case MODE_LOW_POWER:
// 低功耗模式
SystemClock_Config_LowPower();
break;
}
}
- 内存管理优化
// 使用内存池避免碎片
#define MEMORY_POOL_SIZE 4096
static uint8_t memory_pool[MEMORY_POOL_SIZE];
static uint32_t memory_index = 0;
void* Memory_Allocate(size_t size)
{
if (memory_index + size > MEMORY_POOL_SIZE) {
return NULL;
}
void *ptr = &memory_pool[memory_index];
memory_index += size;
return ptr;
}
void Memory_Reset(void)
{
memory_index = 0;
}
13.3 维护与升级策略
- 版本管理
// 固件版本信息
typedef struct {
uint8_t major;
uint8_t minor;
uint8_t patch;
uint32_t build_number;
const char *build_date;
const char *build_time;
} FirmwareVersion_t;
const FirmwareVersion_t firmware_version = {
.major = 1,
.minor = 0,
.patch = 0,
.build_number = 1234,
.build_date = __DATE__,
.build_time = __TIME__
};
void Print_Firmware_Info(void)
{
printf("Firmware Version: %d.%d.%d\r\n",
firmware_version.major,
firmware_version.minor,
firmware_version.patch);
printf("Build: %lu, Date: %s %s\r\n",
firmware_version.build_number,
firmware_version.build_date,
firmware_version.build_time);
}
- OTA升级支持
// 简单的OTA升级框架
typedef enum {
BOOTLOADER_MODE,
APPLICATION_MODE,
UPDATE_MODE
} SystemMode_t;
SystemMode_t Check_System_Mode(void)
{
// 检查是否有更新标志
if (FLASH_Read_Update_Flag()) {
return UPDATE_MODE;
}
// 检查应用程序是否有效
if (!Check_Application_Valid()) {
return BOOTLOADER_MODE;
}
return APPLICATION_MODE;
}
void OTA_Update_Handler(void)
{
printf("Starting OTA update...\r\n");
// 1. 接收新固件
if (Receive_New_Firmware() != HAL_OK) {
printf("Firmware reception failed\r\n");
return;
}
// 2. 验证固件
if (Verify_Firmware() != HAL_OK) {
printf("Firmware verification failed\r\n");
return;
}
// 3. 编程Flash
if (Program_Flash() != HAL_OK) {
printf("Flash programming failed\r\n");
return;
}
// 4. 设置启动标志
Set_Boot_Flag();
printf("OTA update completed successfully\r\n");
// 5. 重启系统
NVIC_SystemReset();
}
结语
本文详细介绍了STM32 HAL库的各个方面,从基础概念到高级应用,从单个外设操作到完整系统设计。HAL库作为STM32生态系统中重要的组成部分,为开发者提供了高效、统一的编程接口。通过本文的学习,读者应该能够:
-
深入理解HAL库的设计哲学和架构
- 掌握HAL库的分层结构和设计理念
- 理解状态机和回调机制的工作原理
-
熟练使用各种外设
- 掌握GPIO、UART、I2C、SPI、ADC、DAC等常用外设的配置和使用
- 理解中断和DMA在提高系统效率中的重要作用
-
掌握系统级设计技巧
- 学会构建多任务系统
- 掌握低功耗设计和电源管理
- 理解性能优化和调试技巧
-
具备工程实践能力
- 能够设计和实现完整的嵌入式系统
- 掌握错误处理和系统监控的方法
- 了解固件升级和维护的最佳实践
HAL库虽然抽象了硬件细节,但并不意味着开发者不需要理解底层原理。相反,深入理解HAL库背后的工作机制,结合实际硬件特性,才能开发出高效、稳定的嵌入式系统。
随着STM32系列的不断发展和更新,HAL库也在持续演进。建议开发者:
- 定期查看ST官方文档和更新
- 参与STM32社区讨论
- 在实际项目中不断实践和总结
- 保持学习新技术和新工具的热情
嵌入式开发是一个需要不断学习和实践的领域,希望本文能为您的STM32开发之旅提供有价值的参考和帮助。
作者注:本文代码示例基于STM32F4系列,部分高级功能可能需要特定系列支持。在实际开发中,请参考具体芯片的参考手册和数据手册。所有代码均经过简化,实际使用时需要考虑错误处理、边界条件等具体情况。
版权声明:本文内容可供学习和参考,转载请注明出处。商业使用请联系作者授权。
更多推荐


所有评论(0)