当前位置:首页 > > 充电吧
[导读]作者:华清远见讲师 今天给大家带来单片机、嵌入式中比较常用的一种程序设计方法--分层设计模式,内核中就大量采用这种设计方式,一般对于某种硬件体系分为几层,以一个核心层来管理,它会抽象出硬件或者个体的

作者:华清远见讲师

今天给大家带来单片机、嵌入式中比较常用的一种程序设计方法--分层设计模式,内核中就大量采用这种设计方式,一般对于某种硬件体系分为几层,以一个核心层来管理,它会抽象出硬件或者个体的共性操作来进行管理,很像在用C语言实现面向对象的设计。

下面就以实际代码来简单说明。假设我们有这么一种需求,需要从某些设备读取一些数据,但是这些设备可能有51体系的,也可能有arm体系的。那么我们应该抽象一个数据结构来表示这种这些发送数据的设备。这就是核心层需要做的工作,假如我们设备有两个共性:

1.使用前需要初始化

2.能收到数据

那么我们的数据结构就应该这么抽象:

struct ReceiveOpr

{

int (*getDevData)(char data[]); //设备接收数据的函数

int (*devInit)(); //设备初始化函数

};

但是核心层管理的不仅仅是一个设备,为了方便核心层能找到某个设备,那么就需要给设备一个标示,这个标示可以有很多种,比如设备名字,产品id等等,这里我们以设备名来区分。所以上面结构体就应该继续添加名字成员,变为:

struct ReceiveOpr

{

char *name; //接收设备的名字

int (*getDevData)(char data[]); //设备接收数据的函数

int (*devInit)(); //设备初始化函数

};

那么核心层如何管理这些设备呢?比较简单也是比较常见的就是设备链表了,也就是我们普通的数据结构链表,所以还需要一个指针,来操作这个设备链表,于是,结构体应该再添加一个成员,变为:

struct ReceiveOpr

{

char *name; //接收设备的名字

int (*getDevData)(char data[]); //设备接收数据的函数

int (*devInit)(); //设备初始化函数

struct ReceiveOpr *next; //用来管理链表

};

内核中有种双向链表的数据结构 list_head,它提供了更为强大的链表管理能力,是内核最核心的数据结构之一,有兴趣也可以移植那个来用。到这里,我们的接收设备的功能抽象就基本完成了(如果在实现过程中发现还需要其他成员,可以随时添加)。

那么核心层如何具体去实现呢?贴一下代码通过注释就能明白。

receive_manager.h---输入设备核心层头文件

#ifndef _RECEIVE_MANAGER_H

#define _RECEIVE_MANAGER_H

struct ReceiveOpr

{

char *name; //接收设备的名字

int (*getDevData)(char data[]); //设备接收数据的函数

int (*devInit)(); //设备初始化函数

struct ReceiveOpr *next; //用来管理链表

};

//函数声明

int registerRecvOpr(struct ReceiveOpr *p);

int selectRecvDev(char *name);

int getDevData(char data[]);

int recvDevInit();

int recvManagerInit();

#endif /* _RECEIVE_MANAGER_H */

receive_manager.c---输入设备核心层实现文件

#include

#include

#include

static struct ReceiveOpr *listReceiveHead = NULL; //设备链表的链表头

static struct ReceiveOpr *defaultDev = NULL; //需要操作的设备指针

/**

* @brief 核心层提供给具体设备的注册函数,每个设备都要提供上面的结构体指针,然后注册到核心层

* @param p 表格行数

*/

int registerRecvOpr(struct ReceiveOpr *p)

{

struct ReceiveOpr *listTmp;

if (!listReceiveHead)

{

listReceiveHead = p;

p->next = NULL;

}

else

{

listTmp = listReceiveHead;

while (listTmp->next)

{

listTmp = listTmp->next;

}

listTmp->next = p;

p->next = NULL;

}

return 0;

}

/**

* @brief 根据name在链表中找到相应的设备,然后赋给指针 defaultDev

* @param name 设备名字

*/

int selectRecvDev(char *name)

{

struct ReceiveOpr *listTmp = listReceiveHead;

while (listTmp)

{

if (strcmp(listTmp->name, name) == 0)

{

defaultDev = listTmp;

return 0;

}

listTmp++;

}

return -1;

}

/**

* @brief 根据指定的defaultDev,取出其中的数据,存到data数组中

* @param data 数组指针

*/

int getDevData(char data[])

{

int ret;

if(defaultDev)

{

ret = defaultDev->getDevData(data);

return ret;

}

else

{

return -1;

}

}

/**

* @brief 根据指定的defaultDev,对其进行初始化

*/

int recvDevInit()

{

if(defaultDev)

{

if(defaultDev->devInit() == 0)

{

return 0;

}

else

{

return -1;

}

}

else

{

return -1;

}

}

/**

* @brief 对需要管理的设备进行注册,后边会说到

*/

int recvManagerInit()

{

registerArmRecv();

return 0;

}

核心层简单的管理工作就完成了,总结下就是:

1.提供 registerRecvOpr 接口给具体设备用,并把设备添加到设备链表

2.提供 recvDevInit、selectRecvDev、getDevData接口给上层用,来选择设备并使用设备

那么我们具体的设备要怎么做呢,就是实现核心层定义的结构体,然后注册到核心层即可,下面以一个模拟设备来说明

arm_recv.c---假设这是arm体系下一个设备,功能没有实现,只是模拟用

#include

static char buf[16];

static int fd;

static int getArmRecvDev(char data[]);

static int armRecvInit();

//这是核心层提供的设备抽象,具体设备文件就是需要去挨个实现这些成员

static struct ReceiveOpr armRecvDev = {

.name = "arm_recv",

.getDevData = getArmRecvDev,

.devInit = armRecvInit,

};

//提交数据的函数,只是模拟而已

static int getArmRecvDev(char data[])

{

int i, j=0;

int ret;

ret = read(fd, buf, 16);

if(ret > 0)

{

for(i=0; i<16; i++)

{

if(i%2 == 0)

{

data[j] = buf[i];

j++;

}

}

return (ret / 2);

}

else

{

return -1;

}

}

//设备初始化函数

static int armRecvInit()

{

fd = open("/dev/power", O_RDWR);

if (fd < 0)

{

printf("can't open arm_recv!n");

return -1;

}

else

{

printf("open arm_recv success!n");

}

return 0;

}

//注册函数,核心层初始化时候会依次调用各个设备的注册函数

int registerArmRecv(void)

{

return registerRecvOpr(&armRecvDev);

}

这里只是举了一个例子,具体的设备功能当然要复杂的多,假如还有个51体系的,或者stm32的,那么完全可以再实现两个文件:51recv.c和stm32.c来注册

到核心层。

最后,来看下上层如何通过核心层来操作具体设备

main.c---使用实例

#include "receive_manager.h"

int main(int argc, char **argv)

{

int ret;

char buf[8];

recvManagerInit(); //注册各个输入设备

selectRecvDev("arm_recv"); //选择要操作的设备

recvDevInit(); //对选择的设备进行初始化

while(1)

{

ret = getDevData(buf); //操作设备

printf("%dn", ret);

}

}

简单吧,这样的设计使我们的程序层次感更加明了,方便管理我们的项目。这里只是简单的做了介绍,实际项目中使用的核心层管理要复杂的多。

本站声明: 本文章由作者或相关机构授权发布,目的在于传递更多信息,并不代表本站赞同其观点,本站亦不保证或承诺内容真实性等。需要转载请联系该专栏作者,如若文章内容侵犯您的权益,请及时联系本站删除。
换一批
延伸阅读

LED驱动电源的输入包括高压工频交流(即市电)、低压直流、高压直流、低压高频交流(如电子变压器的输出)等。

关键字: 驱动电源

在工业自动化蓬勃发展的当下,工业电机作为核心动力设备,其驱动电源的性能直接关系到整个系统的稳定性和可靠性。其中,反电动势抑制与过流保护是驱动电源设计中至关重要的两个环节,集成化方案的设计成为提升电机驱动性能的关键。

关键字: 工业电机 驱动电源

LED 驱动电源作为 LED 照明系统的 “心脏”,其稳定性直接决定了整个照明设备的使用寿命。然而,在实际应用中,LED 驱动电源易损坏的问题却十分常见,不仅增加了维护成本,还影响了用户体验。要解决这一问题,需从设计、生...

关键字: 驱动电源 照明系统 散热

根据LED驱动电源的公式,电感内电流波动大小和电感值成反比,输出纹波和输出电容值成反比。所以加大电感值和输出电容值可以减小纹波。

关键字: LED 设计 驱动电源

电动汽车(EV)作为新能源汽车的重要代表,正逐渐成为全球汽车产业的重要发展方向。电动汽车的核心技术之一是电机驱动控制系统,而绝缘栅双极型晶体管(IGBT)作为电机驱动系统中的关键元件,其性能直接影响到电动汽车的动力性能和...

关键字: 电动汽车 新能源 驱动电源

在现代城市建设中,街道及停车场照明作为基础设施的重要组成部分,其质量和效率直接关系到城市的公共安全、居民生活质量和能源利用效率。随着科技的进步,高亮度白光发光二极管(LED)因其独特的优势逐渐取代传统光源,成为大功率区域...

关键字: 发光二极管 驱动电源 LED

LED通用照明设计工程师会遇到许多挑战,如功率密度、功率因数校正(PFC)、空间受限和可靠性等。

关键字: LED 驱动电源 功率因数校正

在LED照明技术日益普及的今天,LED驱动电源的电磁干扰(EMI)问题成为了一个不可忽视的挑战。电磁干扰不仅会影响LED灯具的正常工作,还可能对周围电子设备造成不利影响,甚至引发系统故障。因此,采取有效的硬件措施来解决L...

关键字: LED照明技术 电磁干扰 驱动电源

开关电源具有效率高的特性,而且开关电源的变压器体积比串联稳压型电源的要小得多,电源电路比较整洁,整机重量也有所下降,所以,现在的LED驱动电源

关键字: LED 驱动电源 开关电源

LED驱动电源是把电源供应转换为特定的电压电流以驱动LED发光的电压转换器,通常情况下:LED驱动电源的输入包括高压工频交流(即市电)、低压直流、高压直流、低压高频交流(如电子变压器的输出)等。

关键字: LED 隧道灯 驱动电源
关闭