嵌入式DAY5

面向对象编程

文件结构:

设备管理层(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 \
}

解释

  1. 数组初始化

    • gLedDevices 是一个 GPIODevice 类型的静态数组。
    • { ... } 中的内容是一个结构体的初始化列表,表示数组的第一个元素。
  2. 结构体成员

    • 各个成员的值被正确地初始化,符合 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 
    }
};

这样可以在数组中定义多个设备。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值