目录
一、核心原则:
(一)、高内聚低耦合:每个函数只做一件事,减少依赖。
(二)、接口清晰:隐藏实现细节。
(三)、可配置性:通过宏、结构体或回调支持灵活扩展。
(四)、可移植性:抽象硬件差异,降低移植成本。
一、模块化设计
五、宏定义配置参数
二、在头文件中宏定义函数
三、使用结构体封装硬件配置
四、回调函数机制
六、错误处理与返回值封装
七、硬件抽象层( HAL)
八、静态函数限制作用域
九、版本兼容性设计
十、使用const优化
十一、状态机封装
十二、封装签名
核心思想:将功能相关函数代码封装到独立的 .c/.h 文件中,形成模块。并添加注释、签名
以LED模块作为示例
#ifndef __LED_H
#define __LED_H
#include "sys.h"
#include "delay.h"
/* LED_0时钟端口、引脚定义 */
#define LED_0_PIN GPIO_Pin_5
#define LED_0_PORT GPIOE
#define LED_0_CLK RCC_APB2Periph_GPIOE
/* LED_1时钟端口、引脚定义 */
#define LED_1_PIN GPIO_Pin_5
#define LED_1_PORT GPIOB
#define LED_1_CLK RCC_APB2Periph_GPIOB
#define LED0 PEout(5)
#define LED1 PBout(5)
void LED_INIT(void);//初始化
void LED_CYCLEBLINK( u32 times, u32 frequency);
#endif
#include "LED.h"
/*******************************************************************************
* 函 数 名 : LED_INIT
* 函数功能 : LED初始化
* 输 入 : 无
* 输 出 : 无
*******************************************************************************/
void LED_INIT(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd( LED_0_CLK| LED_1_CLK, ENABLE); //使能PB,PE端口时钟
GPIO_InitStructure.GPIO_Pin = LED_0_PIN; //LED0-->PB.5 端口配置
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //IO口速度为50MHz
GPIO_Init( LED_0_PORT, &GPIO_InitStructure); //根据设定参数初始化GPIOB.5
GPIO_SetBits( LED_0_PORT, LED_0_PIN); //LED0 输出高
GPIO_InitStructure.GPIO_Pin = LED_1_PIN; //LED1-->PE.5 端口配置, 推挽输出
GPIO_Init( LED_1_PORT, &GPIO_InitStructure); //推挽输出 ,IO口速度为50MHz
GPIO_SetBits( LED_1_PORT, LED_1_PIN); //LED1 输出高
}
优点:便于移植;代码独立,便于复用和调试。
/* 亮输出低电平;灭输出高电平 */
#define ON 1
#define OFF 0
#define LED_0(a) if(a)GPIO_ResetBits( LED_0_PORT, LED_0_PIN);else GPIO_SetBits( LED_0_PORT, LED_0_PIN);
#define LED_1(a) if(a)GPIO_ResetBits( LED_1_PORT, LED_1_PIN);else GPIO_SetBits( LED_1_PORT, LED_1_PIN);
核心思想:通过结构体统一管理硬件参数(如GPIO、UART配置)
//.h
tybedef struct{
GPIO_TybeDef *Port;//端口
uint16_t Pin;//引脚号
uint8_t Mode;//模式
} GPIO_Config;
void GPIO_INIT( const GPIO_CONFIG *cfg){
GPIO_InitTybe init = {0};
init.Pin = cfg -> Pin;
init.Mode = cfg -> Mode;
HAL_GPIO_Init( cfg -> Port, &init);
}
优点:配置参数集中管理,修改灵活。
核心思想:通过函数指针实现事件驱动的回调(如中断、定时器触发)。
/*定义回调函数类型*/
typedef void( *TimeCallback)( void);
/*定时器模块封装*/
void Timer_SetCallback( TimerCallback cb){
/*在中断服务函数中调用cb()*/
}
/*用户自定义回调*/
void MyTimerHandler(){
LED_Toggle();
}
int main(){
Timer_SetCallback( MyTimerHandler);
while(1);
}
优点:解耦硬件事件与业务逻辑。
核心思想:统一错误码和返回值处理机制。
typedef enum{
DRV_OK = 0;
DRV_ERROR,
DRV_TIMEOUT
}DrvStatus;
DrvStatus UART_SendData( uint8_t *data, uint16_t len){
if( HAL_UART_Transmit( &huart1, data, len, 1000) != HAL_OK){
return GRV_TIMEOUT;
}
return DRV_OK;
}
核心思想:将底层硬件操作抽象为统一接口,适配不同硬件。
//hal_adc.h
typedef void ( *ADC_ReadCallback)( uint16_t value);
void HAL_ADC_Init( ADC_ReadCallback cb);
void HAL_ADC_StartConversion( void);
/*不同平台实现*/
#ifdef STM32
void HAL_ADC_Init(...){ /* STM32 专用代码 */}
#elif defined( ESP32)
void HAL_ADC_Init(...){ /* ESP32 专用代码 */}
#endif
优点:跨平台代码复用,减少移植工作量。
核心思想:用static限制函数作用域,避免模块内部函数被外部误调用。(static作静态变量有记忆功能)
//adc.c
static void ADC_Calibrate(){
/* 仅限本文件内使用 */
}
/* 读取数据 */
void ADC_Read(){
ADC_Calibrate();/* 内部调用 */
}
优点:隐藏实现细节,提高模块安全性。
核心思想:通过宏定义或函数重命名保持向后兼容。
//旧版本函数(标记为废弃)
#define ADC_Start() ADC_StartConversion() //兼容旧代码
//新版本函数
void ADC_StartConversion( void){ ... }
优点:平滑升级,减少代码迁移成本。
核心思想:通过const修饰符保护常量数据(如配置表,映射关系)。
//只读LED映射表
const GPIO_Config LED_MAP[] = {
{ GPIOA, GPIO_PIN_5, GPIO_MODE_OUTPUT_PP},
{ GPIOB, GPIO_PIN_#, GPIO_MODE_OUTPUT_PP}
}
优点:防止数据被意外修改,节省RAM。
核心思想:将复杂逻辑封装为状态机函数,提高可读性。
typedef enum{
STATE_IDLE,
STATE_RUNNING,
STATE_ERROR
}SystemState;
void System_UpdateState(){
Static SystemState state = STATE_IDLE;
switch( state){
case STATE_IDLE:
if( trigger)state = STATE_RUNNING;
break;
case STATE_RUNNING:
/* 执行操作 */
break;
}
}
核心思想:运用模块化注释方便阅读调用
/*
* @brief //作用
* @param //参数
* @retval //返回值
* @note:补充说明或注意事项
* @warning:警告信息(如潜在风险)
* @return:类似@retval,但更常用于简单返回值
* @see:关联其他函数或文档
*/
优点:提高代码可读性;通过工具自动生成HTML/PDF等格式的API文档;现代IDE(Keil、VSCode)支持会根据注释提供智能提示。