面向对象编程
文件结构:
设备管理层(DEVICES)下创建一个dev_gpio.h文件(在三彩箱子加入,也需要在设置里的C/C++里面加入):
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 IODevicesRegister(void);
void IODeviceInsert(GPIODevice *ptdev);
GPIODevice *IODeviceFind(const char *name);
#endif
函数指针的用途
- 回调函数:函数指针常用于回调机制,允许将函数作为参数传递给其他函数。例如,排序函数可以接受比较函数作为参数。
- 动态函数调用:在某些情况下,程序在运行时需要决定调用哪个函数,函数指针提供了这种灵活性。
- 实现多态:在 C++ 中,函数指针可以用于实现类似于多态的行为,特别是在需要处理不同类型的函数时。
dev_gpio.c
#include "dev_gpio.h"
#include "stm32f4xx_hal.h"
#include <string.h>
#include "drv_led.h"
#include "drv_key.h"
static GPIODevice *gHeadDevice = NULL;
void IODevicesRegister(void){
LedDevicesCreate();
KeyDevicesCreate();
}
void IODeviceInsert(GPIODevice *ptdev){
if(NULL == gHeadDevice){
gHeadDevice = ptdev;
}
else{
ptdev->next = gHeadDevice;
gHeadDevice = ptdev;
}
}
GPIODevice *IODeviceFind(const char *name){
GPIODevice *ptdev = gHeadDevice;
while(ptdev !=NULL){
if(strstr(ptdev->name,name)){
return ptdev
}
ptdev = ptdev->next;
}
return NULL;
}
. strstr(a, b)
- 功能:
strstr
函数用于查找字符串b
在字符串a
中首次出现的位置。如果找到了,返回指向该位置的指针;如果没有找到,返回NULL
。 - 比较内容:它比较的是
a
中是否包含b
作为子字符串。 - 示例:
c
-
const char *a = "Hello, world!"; const char *b = "world"; if (strstr(a, b)) { // 当 b 是 a 的子字符串时,这里会被执行 printf("Found substring!\n"); }
在驱动管理层的文件moduleDrivers文件夹下面加入
drv_led.c
#include "dev_gpio.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 D1 = {
.name = "D1",
.port = "GPIOB",
.pin = "GPIO_PIN_12",
.Init = LedDrvInit,
.Write = LedDrvWrite,
.Read = LedDrvRead,
.next = NULL
};
static GPIODevice D2 = {
.name = "D2",
.port = "GPIOB",
.pin = "GPIO_PIN_13",
.Init = LedDrvInit,
.Write = LedDrvWrite,
.Read = LedDrvRead,
.next = NULL
};
static GPIODevice D3 = {
.name = "D3",
.port = "GPIOB",
.pin = "GPIO_PIN_14",
.Init = LedDrvInit,
.Write = LedDrvWrite,
.Read = LedDrvRead,
.next = NULL
};
static GPIODevice D4 = {
.name = "D4",
.port = "GPIOB",
.pin = "GPIO_PIN_15",
.Init = LedDrvInit,
.Write = LedDrvWrite,
.Read = LedDrvRead,
.next = NULL
};
void LedDevicesCreate(void){
IODeviceInsert(&D1);
IODeviceInsert(&D2);
IODeviceInsert(&D3);
IODeviceInsert(&D4);
}
static int LedDrvInit(struct GPIODev *ptdev){
if(ptdev == NULL) return -1;
return 0;
}
static int LedDrvWrite(struct GPIODev *ptdev, unsigned char status){
if(ptdev == NULL) return -1;
if(status !=0 sstatus !=1 ) return -1;
HAL_GPIO_WritePin(ptdev->port,ptdev->pin, status);
return 0;
}
static int LedDrvRead(struct GPIODev *ptdev){
if(ptdev == NULL) return -1;
int status = HAL_GPIO_ReadPin(ptdev->port, ptdev->pin);
return 0;
}
drv_led.h
#ifndef __DRV_LED_H
#define __DRV_LED_H
void LedDevicesCreate(void);
#endif
在application文件夹下面新建一个文件:
app_led.c
#include "dev_gpio.h"
#include "stm32f4xx_hal.h"
void app_led_test(void){
IODeviceRegister();
GPIODevice *pD1 = IODeviceFind("D1");
if(NULLDEV == pD1) return;
pD1->Init(pD1);
while(1){
pD1->Write(pD1,0)
HAL_Delay(100);
pD1->Write(pD1,1);
HAL_Delay(100);
}
}
建立按键的代码
drv_key.h
#ifndef __DRV_KEY_H
#define __DRV_KEY_H
void KeyDevicesCreate(void);
#endif
key_drv.c
#include "dev_gpio.h"
#include "stm32f4xx_hal.h"
static int KeyDrvInit(struct GPIODev *ptdev);
static int KeyDrvRead(struct GPIODev *ptdev);
static GPIODevice K1 = {
.name = "K1",
.port = "GPIOA",
.pin = "GPIO_PIN_0",
.Init = KeyDrvInit,
.Write = NULL,
.Read = KeyDrvRead,
.next = NULL
};
static GPIODevice K2 = {
.name = "K2",
.port = "GPIOA",
.pin = "GPIO_PIN_1",
.Init = KeyDrvInit,
.Write = NULL,
.Read = KeyDrvRead,
.next = NULL
};
static GPIODevice K3 = {
.name = "K3",
.port = "GPIOA",
.pin = "GPIO_PIN_2",
.Init = KeyDrvInit,
.Write = NULL,
.Read = KeyDrvRead,
.next = NULL
};
static GPIODevice K4 = {
.name = "K4",
.port = "GPIOA",
.pin = "GPIO_PIN_3",
.Init = KeyDrvInit,
.Write = NULL,
.Read = KeyDrvRead,
.next = NULL
};
void KeyDevicesCreate(void){
IODeviceInsert(&K1);
IODeviceInsert(&K2);
IODeviceInsert(&K3);
IODeviceInsert(&K4);
}
static int LedDrvInit(struct GPIODev *ptdev){
if(ptdev == NULL) return -1;
return 0;
}
static int LedDrvRead(struct GPIODev *ptdev){
if(ptdev == NULL) return -1;
int status = HAL_GPIO_ReadPin(ptdev->port, ptdev->pin);
return 0;
}
app_key.c
//#include "dev_gpio.h"
#include "devices.h"//对管理文件的引用,可以知道否可以用
#include "stm32f4xx_hal.h"
void app_key_test(){
IODeviceRegister();
GPIODevice *pK1 = IODeviceFind("K1");
if(NULLDEV == pK1) return;
GPIODevice *pD1 = IODeviceFind("D1");
if(NULLDEV == pD1) return;
}
错误码管理
新建一个文件夹“includes", 在里面新建一个错误码文件“error.h”,需要引用时就引入错误码文件
各层引用管理,在includes文件下新建一个文件叫“config.h”
#ifndef __CONFIG_H
#define __CONFIG_H
//管理设备层设备,目前只有引脚和串口需要加入
#define USE_GPIO_DEVICE (1)
#define USE_UART_DEVICE (0)
#endif
在device层文件夹下面设置一个管理文件叫“devices.h”
#ifndef __DEVICES_H
#define __DEVICES_H
#include "config.h"//需要知道上一层是否启用了引脚或者串口
#if USE_GPIO_DEVICE
#include "dev_gpio.h"
#define USE_GPIO_DRIVER
#if USE_UART_DEVICE
#define USE_UART_DRIVER
#endif
在驱动层加入“driver.h”
#ifndef __DRIVERS_H
#define __DRIVERS_H
#include "device.h"//知道引脚和串口是否被开启
#define NULLDEV (0)
#ifndef USE_GPIO_DRIVER
#include ""drv_led.h
#include ""drv_key.h
#endif
#ifndef USE_UART_DRIVER
#include "drv_uart.h"
#endif
#endif
也可以用一个文件夹将结构体打包成一个文件
在原来的“drv_led.c”文件下面加入
#include “./drv_config/gpio_config.h”
static GPIODevice gLedDevices[] ={
D1,D2,D3,D4
}
void LedDevicesCreat(void){
unsigned int num = sizeof(gLedDevices) / sizeof(struct GPIODev);
for(unsigned int i = 0; i < num ; i++){
IODeviceInsert(&gLedDevices[i]);
}
}
新创建一个文件“./drv_config/gpio_config.h”
#define D1{ \
.name = "D1", \
.port = GPIOB, \
.pin = GPIO_PIN_12, \
.Init = LedDrvInit, \
.Write = LedDrvWrite, \
.Read = LedDrvRead, \
.next = NULL \
}
解释
-
数组初始化:
gLedDevices
是一个GPIODevice
类型的静态数组。{ ... }
中的内容是一个结构体的初始化列表,表示数组的第一个元素。
-
结构体成员:
- 各个成员的值被正确地初始化,符合
GPIODevice
结构体的定义。
- 各个成员的值被正确地初始化,符合
注意事项
- 确保
GPIODevice
结构体的定义与这些成员匹配,否则会导致编译错误。 - 如果有多个设备,可以继续在数组中添加更多的初始化,例如:
c
static GPIODevice gLedDevices[] = {
{
.name = "D1",
.port = GPIOB,
.pin = GPIO_PIN_12,
.Init = LedDrvInit,
.Write = LedDrvWrite,
.Read = LedDrvRead,
.next = NULL
},
{
.name = "D2",
.port = GPIOC,
.pin = GPIO_PIN_13,
.Init = LedDrvInit,
.Write = LedDrvWrite,
.Read = LedDrvRead,
.next = NULL
}
};
这样可以在数组中定义多个设备。