1.前言
模块化的编程思想虽然可以很好的管理项目和具有比较好的移植性,但是为了更好的管理项目,使项目更具有移植性和更便于管理,我们引入面向对象编程思想。块化设计思想本质上是面向过程的思想,面向对象的设计思想更符合人类的思考习惯,面向对象编程就是将事物抽象为“对象” ,针对“对象”持有的数据和与之相关的行为进行编程。
2.面向对象的三大特征
封装:将不需要外部看到的数据和对应的方法放到类中,只需要暴露外部需要看到的数据和方法 ,根据事物特征进行分类封装,是从“代码手段/方法层面”将相关的数据和对应的方法集中一 起,让程序聚合成类和对象的基本单元。
继承:依据相关类的共有特征进行层级分类:GPIO->LED,GPIO->按键,UART->WiFi 。子类继承父类的特征,还可以有自己的独立特征,从“核心行为层面”给与了类聚合相关特征、灵活分类的能力。
多态:相同的特征在不同情况下有不同的表现,从“应用结果和表现层面”,描述了基于分类带来的益处,也就是可拓展性和可复用性。
3.分层设计
为了便于面向对象的管理和理解,提出分层设计。最底层是硬件抽象层HAL层,分层结构的中心点其实是设备管理层,设备管理层写出对应的抽象类,然后设备驱动层对设备管理层进行继承,应用层直接调用设备管理层进行设备的操作,几乎能实现代码的完全移植。
4.GPIO设备对象的封装和管理
4.1 devices层
首先 ,分析GPIO的数据特征:引脚号、端口号,GPIO行为特征:初始化、输出电平、读取电平,然后通过链表进行管理,所以得出以下GPIO对象。
typedef struct GPIODev{
char *name;
void *port;
unsigned char pin;
int (*Init)(struct GPIODev *ptdev);
int (*Write)(struct GPIODev *ptdev, unsigned char status);
int (*Read)(struct GPIODev *ptdev);
struct GPIODev *next;
}GPIODevice;
接着我们要对GPIO对象进行管理。所以我们在devices层分别编写代码如下,分别为dev_gpio.c和dev_gpio.h。
/*dev_gpio.c*/
#include "dev_gpio.h"
#include "mytype.h"
#include "string.h"
#include "drivers.h"
static GPIODevice *gHeadDevice = NULLDEV;
void IODeviceRegister(void)
{
GPIODeviceCreate();
}
void IODeviceInsert(GPIODevice *ptdev)
{
if(NULLDEV == ptdev)
{
gHeadDevice = ptdev;
}
else
{
ptdev->next = gHeadDevice;
gHeadDevice = ptdev;
}
}
GPIODevice *IODeviceFind(const char *name)
{
GPIODevice *ptdev = gHeadDevice;
while(NULLDEV != ptdev)
{
if(strstr(name,ptdev->name))
{
return ptdev;
}
ptdev = ptdev->next;
}
return NULLDEV;
}
/*dev_gpio.h*/
#ifndef __DEV_GPIO_H
#define __DEV_GPIO_H
typedef struct GPIODev{
char *name;
void *port;
unsigned int pin;
int (*Init)(struct GPIODev *ptdev);
int (*Write)(struct GPIODev *ptdev,unsigned char status);
int (*Read)(struct GPIODev *ptdev);
struct GPIODev *next;
}GPIODevice;
void IODeviceRegister(void);
void IODeviceInsert(GPIODevice *ptdev);
GPIODevice *IODeviceFind(const char *name);
#endif /* __DEV_GPIO_H*/
4.2 drivers层
驱动层继承设备层,此层创建一个单独的gpio_config.h和drv_led.c和drv_led.h,代码分别如下。
/*gpio_config.h*/
#ifndef __GPIO_CONFIG_H
#define __GPIO_CONFIG_H
#define D1 \
{ \
.name = "D1", \
.port = GPIOB, \
.pin = GPIO_PIN_12, \
.Init = GPIODrvInit, \
.Write = GPIODrvWrite, \
.Read = GPIODrvRead, \
.next = NULL \
}
#define D2 \
{ \
.name = "D2", \
.port = GPIOB, \
.pin = GPIO_PIN_13, \
.Init = GPIODrvInit, \
.Write = GPIODrvWrite, \
.Read = GPIODrvRead, \
.next = NULL \
}
#define D3 \
{ \
.name = "D3", \
.port = GPIOB, \
.pin = GPIO_PIN_14, \
.Init = GPIODrvInit, \
.Write = GPIODrvWrite, \
.Read = GPIODrvRead, \
.next = NULL \
}
#define D4 \
{ \
.name = "D4", \
.port = GPIOB, \
.pin = GPIO_PIN_15, \
.Init = GPIODrvInit, \
.Write = GPIODrvWrite, \
.Read = GPIODrvRead, \
.next = NULL \
}
#endif
/*drv_led.h*/
#ifndef __DRV_LED_H
#define __DRV_LED_H
void LedDeviceCreate(void);
#endif /* __DRV_LED_H*/
/*drv_led.c*/
#include "dev_gpio.h"
#include "errno.h"
#include "./drv_config/gpio_config.h"
#include "stm32f4xx_hal.h"
static int LedDrvInit(struct GPIODev *ptdev);
static int LedDrvWrite(struct GPIODev *ptdev,unsigned char status);
static int LedDrvRead(struct GPIODev *ptdev);
static GPIODevice gLedDevices[] = {
D1,D2,D3,D4
};
void LedDeviceCreate(void)
{
unsigned int num = sizeof(gLedDevices)/sizeof(struct GPIODev);
for(unsigned int i = 0;i<num;i++)
IODeviceInsert(&gLedDevices[i]);
}
static int LedDrvInit(struct GPIODev *ptdev)
{
if(NULL == ptdev) return -EINVAL;
return ESUCCESS;
}
static int LedDrvWrite(struct GPIODev *ptdev,unsigned char status)
{
if(NULL == ptdev) return -EINVAL;
if(status != 0 && status != 1) return -EINVAL;
HAL_GPIO_WritePin(ptdev->port,ptdev->pin,status);
return ESUCCESS;
}
static int LedDrvRead(struct GPIODev *ptdev)
{
if(NULL == ptdev) return -EINVAL;
int status = HAL_GPIO_ReadPin(ptdev->port,ptdev->pin);
return status;
}
4.3 applications
app_led.c
#include "dev_gpio.h"
#include "mytype.h"
#include "stm32f4xx_hal.h"
void app_led_test(void)
{
IODeviceRegister();
GPIODevice *pD1 = IODeviceFind("D1");
if(NULLDEV == pD1) return;
GPIODevice *pD2 = IODeviceFind("D2");
if(NULLDEV == pD2) return;
GPIODevice *pD3 = IODeviceFind("D3");
if(NULLDEV == pD3) return;
GPIODevice *pD4 = IODeviceFind("D4");
if(NULLDEV == pD4) return;
pD1->Init(pD1);
pD1->Init(pD2);
pD1->Init(pD3);
pD1->Init(pD4);
while(1)
{
pD1->Write(pD1,0);
HAL_Delay(200);
pD1->Write(pD1,1);
HAL_Delay(200);
}
}