软件分层模块化设计–抽象与硬件分离
以点亮led为例子代码实现
led.h
#ifndef _LED_H_
#define _LED_H_
#include <stdint.h>
#define LED1 0
#define LED2 1
#define LED3 2
/**
***********************************************************
* @brief LED硬件初始化
* @param
* @return
***********************************************************
*/
void LedDrvInit(void);
/**
***********************************************************
* @brief 点亮LED
* @param ledNo,LED标号,0~2
* @return
***********************************************************
*/
void TurnOnLed(uint8_t ledNo);
/**
***********************************************************
* @brief 熄灭LED
* @param ledNo,LED标号,0~2
* @return
***********************************************************
*/
void TurnOffLed(uint8_t ledNo);
#endif
led.c
#include <stdint.h>
#include "gd32f30x.h"
typedef struct
{
rcu_periph_enum rcu;
uint32_t gpio;
uint32_t pin;
} Led_GPIO_t;
static Led_GPIO_t g_gpioList[] =
{
{RCU_GPIOA, GPIOA, GPIO_PIN_8},
{RCU_GPIOE, GPIOE, GPIO_PIN_6},
{RCU_GPIOF, GPIOF, GPIO_PIN_6}
};
#define LED_NUM_MAX (sizeof(g_gpioList) / sizeof(g_gpioList[0]))
/**
***********************************************************
* @brief LED硬件初始化
* @param
* @return
***********************************************************
*/
void LedDrvInit(void)
{
for (uint8_t i = 0; i < LED_NUM_MAX; i++)
{
rcu_periph_clock_enable(g_gpioList[i].rcu);
gpio_init(g_gpioList[i].gpio, GPIO_MODE_OUT_PP, GPIO_OSPEED_2MHZ, g_gpioList[i].pin);
gpio_bit_reset(g_gpioList[i].gpio, g_gpioList[i].pin);
}
}
/**
***********************************************************
* @brief 点亮LED
* @param ledNo,LED标号,0~2
* @return
***********************************************************
*/
void TurnOnLed(uint8_t ledNo)
{
if (ledNo >= LED_NUM_MAX)
{
return;
}
gpio_bit_set(g_gpioList[ledNo].gpio, g_gpioList[ledNo].pin);
}
/**
***********************************************************
* @brief 熄灭LED
* @param ledNo,LED标号,0~2
* @return
***********************************************************
*/
void TurnOffLed(uint8_t ledNo)
{
if (ledNo >= LED_NUM_MAX)
{
return;
}
gpio_bit_reset(g_gpioList[ledNo].gpio, g_gpioList[ledNo].pin);
}
代码分析
这段代码实现了LED驱动的模块化设计,通过分层的方式将硬件相关的初始化和控制与应用逻辑分离开来,增强了代码的可维护性和可移植性。
让我们逐步分析代码的各个部分:
1.头文件包含:
- #include <stdint.h>:引入标准整数类型,如uint8_t等。
- #include “gd32f30x.h”:引入芯片相关的头文件,其中可能包含了对芯片特定寄存器的定义和操作函数。
2.结构体定义: - Led_GPIO_t:定义了一个结构体类型,包含LED的相关信息,包括RCU外设、GPIO端口和引脚号。
3.LED GPIO列表: - static Led_GPIO_t g_gpioList[]:定义了一个静态数组,存储了多个LED的GPIO信息,每个元素包含了LED的RCU外设、GPIO端口和引脚号。
4.LED数量宏定义: - #define LED_NUM_MAX (sizeof(g_gpioList) / sizeof(g_gpioList[0])):定义了LED的最大数量,通过计算g_gpioList数组的元素个数来确定LED的数量。
5.LED硬件初始化函数: - void LedDrvInit(void):初始化LED硬件,依次启用每个LED对应的RCU外设,配置相应的GPIO为推挽输出模式,并将LED初始状态设置为熄灭。
6.点亮LED函数: - void TurnOnLed(uint8_t ledNo):点亮指定编号的LED,首先检查编号是否合法,然后将对应GPIO的相应引脚置位。
7.熄灭LED函数: - void TurnOffLed(uint8_t ledNo):熄灭指定编号的LED,首先检查编号是否合法,然后将对应GPIO的相应引脚复位。
通过这样的设计,可以在应用层面方便地调用TurnOnLed和TurnOffLed函数来控制LED的状态,而不需要关心具体的硬件细节。同时,若要新增或修改LED的引脚配置,只需修改g_gpioList数组即可,无需修改其他代码,提高了代码的灵活性和可维护性。
总结
这段代码展示了LED驱动模块的设计,体现了软件分层模块化设计的几个方面:
结构体封装:
使用结构体 Led_GPIO_t 封装了LED的相关信息,包括使用的 RCC 外设、GPIO 端口和引脚号,使得 LED 相关的信息更具可读性和可维护性。
模块化函数设计:
将 LED 相关的功能函数(初始化、点亮、熄灭)封装成了独立的函数,分别是 LedDrvInit()、TurnOnLed() 和 TurnOffLed(),这样设计使得 LED 功能模块化,易于扩展和维护。
抽象接口:
通过函数的参数传入 LED 的编号,实现了对 LED 控制的抽象,使得调用者不需要了解 LED 具体的引脚编号,只需传入 LED 编号即可控制相应的 LED,提高了代码的可重用性和可移植性。
代码可读性:
使用了宏定义 LED_NUM_MAX 来表示 LED 的数量,增强了代码的可读性和可维护性,若要增加或减少 LED 的数量,只需修改 LED 相关信息的数量,而不需要修改其他代码。
这样的设计使得 LED 驱动模块具有良好的模块化、可扩展性和可维护性,同时提高了代码的可读性和可重用性,使得 LED 控制的实现更加简洁和灵活。