今天給大家帶來單片機、嵌入式中比較常用的一種程序設計方法--分層設計模式,內核中就大量采用這種設計方式,一般對于某種硬件體系分為幾層,
以一個核心層來管理,它會抽象出硬件或者個體的共性操作來進行管理,很像在用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("%d\n", ret);
}
}
簡單吧,這樣的設計使我們的程序層次感更加明了,方便管理我們的項目。這里只是簡單的做了介紹,實際項目中使用的核心層管理要復雜的多,具體需要
閱讀更多的源碼來深入體會。后,提供幾個比較好的開源c源碼,有興趣可以讀一下,可以咨詢客服哦,祝大家學習愉快~