- 一、智能家居功能细节拆分
- 控制区:
- 外设区:
- 面向对象类和对象的该概念
- 结构体新玩法
- 二、工厂模式
- 1. 工厂模式的概念
- 2. 工厂模式的实现
- 3. 工厂模式使用及功能验证
- 三、智能家居项目框架设计
- 1. 智能家居架构代码文件工程建立
- 2. 主流程设计和浴室灯框架编写
- 3. 浴室灯代码实现和测试
语音识别模块,socket客户端
外设区:继电器组控制灯,远程终端子系统控制灯,窗帘等,火灾报警,摄像头。
面向对象类和对象的该概念类:是一种用户定义的引用的数据类型,也称类类型,(结构体)
对象:类的一种具象
struct Animal {
char name[128];
int age;
int sex; //成员属性
void *peat();
void *pbeat(); //成员方法
};
对象是类的一种具象,如 struct Animal dog ;struct Animal cat;struct Animal person; dog 就是类的具体的对象,dog是Animal类的对象。
C语言面向对象的代码
#include结构体新玩法//类:抽象的 struct Animal { char name[128]; int age; int sex; //成员属性 void (*peat)(); void (*pbeat)(); //成员方法 }; void dogEat() { printf("狗吃骨头n"); } void catEat() { printf("猫吃鱼n"); } void personEat() { printf("人吃饭n"); } void dongBeat() { printf("咬人n"); } void dogBeat() { printf("咬人n"); } void catBeat() { printf("抓人n"); } void personBeat() { printf("打人n"); } int main() { struct Animal dog; struct Animal cat; struct Animal person; //对象,事物的具象 dog.peat = dogEat; cat.peat = catEat; person.peat = personEat; dog.pbeat = dogBeat; cat.pbeat= catBeat; person.pbeat= personBeat; dog.peat(); cat.peat(); person.peat(); dog.pbeat(); cat.pbeat(); person.pbeat(); return 0; }
内核的方式给结构体赋值:
struct Animal dog2 = {
.name = "阿黄",
.peat = dogEat,
.pbeat = dogBeat
};
新玩法代码
#include二、工厂模式 1. 工厂模式的概念//类:抽象的 struct Animal { char name[128]; int age; int sex; //成员属性 void (*peat)(); void (*pbeat)(); //成员方法 }; void dogEat() { printf("狗吃骨头n"); } void dongBeat() { printf("咬人n"); } int main() { //以前我们写结构体赋值时,是这样按顺序怼进去 struct Animal dog1 = {"阿黄",1,1,dogEat,dogBeat}; //有时候我们只是想给单个赋值,我们怎么写呢? struct Animal dog2 = { .name = "阿黄", .peat = dogEat, .pbeat = dogBeat }; dog.peat(); dog.pbeat(); return 0; }
工厂模式(Factory Pattern)是最常用的设计模式之一,这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。
在工厂模式中,我们在创建对象时不会对客户端暴露创建逻辑,并且是通过使用一个共同的接口(API)来指向新创建的对象。
2. 工厂模式的实现创建对象时不会对客户端暴露创建逻辑,并且是通过使用一个共同的接口(API)来指向新创建的对象。
暴漏逻辑代码例如:
#include//类:抽象的 struct Animal { char name[128]; int age; int sex; //成员属性 void (*peat)(); void (*pbeat)(); //成员方法 }; void dogEat() { printf("狗吃骨头n"); } void dongBeat() { printf("咬人n"); } int main() { struct Animal dog= { .name = "阿黄", .peat = dogEat, .pbeat = dogBeat }; dog.peat(); dog.pbeat(); return 0; }
暴漏了逻辑
void dogEat()
{
printf("狗吃骨头n");
}
void dongBeat()
{
printf("咬人n");
}
struct Animal dog2 = {
.name = "阿黄",
.peat = dogEat,
.pbeat = dogBeat
};
设计思路图
-
首先在选定位置新建一个文件夹,然后在文件夹里面新建dog.c、animal.h、cat.c和mainPro.c 然后再新建一个文件夹存放sourceInsight的工程文件(有关sourceInsight的用法),如下图所示:
-
先写下4个分文件,animal.h 、cat.c 、dog.c 、person.c(一个功能一个文件) 然后将对应的代码写入对应的文件,比如:dog.c这个文件就是存放dog这个对象的相关行为,并且提供让主程序调用的函数API将dog这个对象添加到链表中去(这个就像是以后的智能家居为实现整个控制系统,需要添加的各个功能模块,一个供能模块就是一个文件),putdogInLink 是将dog对象插入进链表的API接口,这里采用头插法进行插入,即:先插入的在后边。
-
mainPro.c 主程序要调用这三个文件组成链表。 最后就是编写mainpro.c主函数,下面函数还编写了一个可供用户输入的然后查找响应节点的函数,用户输入要查找的节点名称,找到后返回指向该节点的指针,通过指针就可以对该节点进行操作,就把它当做链表的一个节点即可。
#include"animal.h" #include//功能链表的遍历 struct Animal *findUtilByName(char *str,struct Animal *phead) { struct Animal *tmp = phead; if(phead == NULL){ return NULL; } else{ while(tmp != NULL){ if(strcmp(tmp->name,str)==0){ //若s1、s2字符串相等,则返回零 return tmp; } tmp = tmp->next; } return NULL; } } int main() { char buf[128]={' '}; struct Animal *phead = NULL; struct Animal *ptmp; //把文件都连接起来(链表) phead = putCatInLink(phead); phead = putDogInLink(phead); phead = putPersonInLink(phead); //业务代码 while(1){ puts("please input Tom ,pipi,CONG"); scanf("%s",buf); ptmp = findUtilByName(buf,phead); if(ptmp != NULL){ ptmp->pbeat(); ptmp->peat(); } memset(buf,' ',sizeof(buf)); } return 0; }
他们之间的关联就是链表一样,一个文件加入链表,要加功能(就是加文件)就把文件当成元素插入链表中。
3. 工厂模式使用及功能验证
把文件中的cat ,dog, person 换成 卧室灯,餐厅灯,客厅灯,不就是功能性文件嘛, 要在来个卫生间灯,就在加一个文件。
- 添加XXX功能文件:
在目录下添加文件XXX.c ,再在animal.h 中把struct Animal * putXXXInLink(struct Animal *phead);(接口)暴露出来,暴露出来目的是给mainPro添加,加入功能链表中。
- 根据以上简单工厂模式,智能家居设计的时候,就可以设计为指令工厂、main函数、控制工厂,指令工厂面就存放指令(比如:语音指令、客户端指令等,将这些指令串为一个链表),控制工厂就是控制一些家庭设备(比如:各个房间的灯,门锁、串口等,创建一个链表,然后根据指令,去查找对应的控制结点),main函数里面首先创建两个链表(指令工厂、控制工厂),然后接下来创建两个线程(一个是语音的、一个是客户端的),在每个线程里面在接受到指令后去控制工厂里面去查找对应的控制设备然后进行一系列操作。
- 根据上面的叙述,我们可以创建以下架构的代码文件工程,指令工场和控制工场的头文件就是以下图片中的两个头文件。然后将这些文件导入到sourceInsight里面进行代码的编写。
以上是智能家居开发的软件框架构建准备工作,接下来开始代码的编写。
2. 主流程设计和浴室灯框架编写主流程设计框架
指令工厂框架
设备控制工厂框架
浴室灯控制框架设计
#include"contrlDevice.h"
int bathroomLightOPen()
{
}
int bathroomLightClose()
{
}
int bathroomLightInit()
{
}
int bathroomLightStatus(int status)
{
}
struct Devices bathroomLight = {
.name = "bathroomLight",
.open = bathroomLightOPen,
.close = bathroomLightClose,
.deviceInit = bathroomLightInit,
.changStatus = bathroomLightStatus
};
struct Devices * addBathroomLightToDeviceLink(struct Devices *phead)
{
if(phead == NULL){
return &bathroomLight;
}
else{
bathroomLight.next = phead;
phead = &bathroomLight;
}
}
根据上面内容的代码框架开始编写代码:
首先编写controlDevices.h这个头文件里面的代码,这个是设备工厂每一个结点的结构体类型,而且还要在这个头文件里面进行函数的声明,也就是创建的那些设备.c文件里面的函数(为了将设备添加至设备链表的函数),其中这个头文件里面的结构体内容根据功能提前设定。同样然后再编写inputCommand.h这个头文件里面的内容,这个是指令工厂里面的头文件,也是指令链表里面的每一个结点的类型。编写完这两个头文件,然后再进行设备工厂设备文件、指令工厂指令文件和main.c文件的编写。
3. 浴室灯代码实现和测试先写一些硬件测试代码,如继电器组的代码,来测试接线问题。
- controlDevices.h是指令工厂头文件代码,结点结构体的声明,这里面的东西不一定够用,可以先写上,等不够的时候在进行添加。
#include//包含wiringPi库 #include #include struct Devices { int status; //表示开关的状态 int pinNum; char devicesName[128]; //存放设备的名称 int (*open)(int pinNum); int (*close)(int pinNum); int (*deviceInit)(int pinNum); int (*readStatus)(int pinNum); int (*changStatus)(int status); struct Devices*next; }; //以下几行将设备添加至设备链表的函数声明,便于以后的查找引用 struct Devices* addBathroomLightToDeviceLink(struct Devices* phead);
- inputCommand.h是设备工厂头文件代码,里面有设备链表每一个结点的结构体类型的声明,和指令工厂头文件类似。
struct InputCommander
{
char commandName[128];
char command[32];
int (*Init)(char *name , char *ipAdress, char *port);
int (*getCommand)(char *cmd);
char log[1024];
struct InputCommander *next;
}
- 首先编写设备工厂的设备文件bathroomLight.c
#include"contrlDevices.h" //包含头文件
int bathroomLightOPen(int pinNum)
{
digitalWrite(pinNum, HIGH); //将引脚电平拉高,点亮浴室灯
}
int bathroomLightClose(int pinNum)
{
digitalWrite(pinNum, LOW); //将引脚电平拉低,熄灭浴室灯
}
int bathroomLightInit(int pinNum)
{
pinMode(pinNum , OUTPUT); //初始化引脚功能
digitalWrite(pinNum, HIGH);
}
struct Devices bathroomLight = {
.deviceName = "bathroomLight", //通过这个设备名进行浴室灯结点的查找,然后再进行结构体函数的调用
.pinNum = 22, //浴室灯继电器控制IO口引脚 gpio 22
.open = bathroomLightOPen,
.close = bathroomLightClose,
.deviceInit = bathroomLightInit,
};
//将浴室灯结点插入到设备工厂链表里面,采用头插法
struct Devices * addBathroomLightToDeviceLink(struct Devices *phead)
{
if(phead == NULL){
return &bathroomLight;
}
else{
bathroomLight.next = phead;
phead = &bathroomLight;
}
}
- 最后mainPro.c主程序控制代码编写,main函数里面涉及到设备工厂、指令工厂头结点的插入和设备文件、指令文件分别插入到设备链表和指令链表。同时还要有结点查找函数:包括设备结点查找函数、指令结点查找函数,查找后返回结点指针然后对特定结点进行操作即可。
#include#include"contrlDevices.h" #include struct Devices * findDeviceByName(char *name, struct Devices* phead){ struct Devices *tmp = phead; if(phead == NULL){ return NULL; } else{ while(tmp != NULL){ if(strcmp(tmp->deviceName,name) ==0 ){ return tmp; } tmp = tmp->next; } return NULL; } } int main(){ if(-1 == wiringPiSetup()){ return -1; } char *name ="bathroomLight"; struct Devices *pdeviceHead = NULL; pdeviceHead = addBathroomLightToDeviceLink(pdeviceHead); struct Devices *tmp = findDeviceByName(name,pdeviceHead); if(tmp != NULL){ tmp->deviceInit(tmp->pinNum); tmp->open(tmp->pinNum); } return 0; }
代码编写完成后通过ftp工具传输到树莓派编译(我这里用的是FileIlla)
- 使用指令:gcc *.c -o test -lwiringPi进行编译。
浴室灯调试



