树莓派智能家居项目整合(包含语音、socket、火灾、摄像头线程)

5 篇文章 1 订阅
1 篇文章 0 订阅


坎坎坷坷,墨墨迹迹了这么久也算是完成了四个线程的同时运行。记录下代码,也分享下学习过程中的问题。

1.百度网盘下载代码链接

点我下载代码
提取码: jtzn
在这里插入图片描述
在这里插入图片描述

2.main.c

这里放下main函数,其他的在百度网盘连接里可下载

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <wiringSerial.h>

#include "contrlDevices.h"
#include "InputCommand.h"

#define SWITCH1 21		//四盏灯对应的引脚
#define SWITCH2 22
#define SWITCH3 23
#define SWITCH4 24
#define SWITCH5 25		//火焰传感器对应的引脚

struct InputCommander *pCommandHead = NULL;		//指令控制工厂链表节点头
struct Devices		  *pdeviceHead = NULL;		//设备工厂链表头节点
struct InputCommander *socketHandler = NULL;	//网络控制线程执行的函数使用到的全局变量,在read_thread线程和socket_thread都使用到了

int c_fd;


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;
	}
}

struct InputCommander* findCommandByName(char *name,struct InputCommander *phead)		//根据名字寻找指令控制工厂链表链节函数,并返回链节
{
	struct InputCommander *tmp = phead;
	if(phead == NULL){
		return NULL;
	}else{
		while(tmp != NULL){
			if(strcmp(tmp->commandName,name) == 0){
				return tmp;
			}
			tmp = tmp->next;
		}
		return NULL;
	}
}

void *fireAlarmThread(void *data)				//“火灾报警器线程”执行的函数
{
	int status;
	struct Devices *firetmp = NULL;
	struct Devices *buztmp = NULL;

	firetmp = findDeviceByName("fireIfOrNot",pdeviceHead);		//寻找“火焰传感器”链表节点,返回给firetmp
	buztmp = findDeviceByName("beep",pdeviceHead);				//寻找“蜂鸣器”链表节点,返回给buztmp

	while(1){
		status = firetmp->readStatus(firetmp->pinNum);			//读取“火焰传感器”状态
	
		if(status == 0){						//检测到火焰或强光源
			buztmp->open(buztmp->pinNum);		//打开蜂鸣器
			delay(1000);						//延时1000毫秒=1秒
		}

		if(status == 1){						//未检测到火焰、强光源或解除警报
			buztmp->close(buztmp->pinNum);		//关闭蜂鸣器
		}
	}
}

void * voice_thread(void* datas)		//语音线程
{
	struct InputCommander *voiceHandler;	
	struct Devices        *tmp = NULL;

	int nread;
	voiceHandler = findCommandByName("voice",pCommandHead);		//找到语音节点

	if(voiceHandler == NULL){		//防止段错误
		printf("find voiceHandler error\n");
		pthread_exit(NULL);	//线程里不用return

	}else{
		if(voiceHandler->Init(voiceHandler,NULL,NULL)<0){	//判断voice的fd是否正确
			printf("voice init error\n");
			pthread_exit(NULL);
		}else{
			printf("%s init success\n",voiceHandler->commandName);
		}
		while(1){
			nread = voiceHandler->getCommand(voiceHandler);	//指令读在voiceHandler->command里面
			if(nread==0){
				printf("waiting....\n");
			}else{
				printf("do divece contrl:%s\n",voiceHandler->command);
				if(strstr(voiceHandler->command,"WZ") != NULL){		//一级指令,

					printf("shoudaoXP\n");	
				}else if(strstr(voiceHandler->command,"KYS") != NULL){		//对串口收到的指令进行分析,并执行对应的操作
					digitalWrite(SWITCH1,LOW);
				}else if(strstr(voiceHandler->command,"GYS") != NULL){
					digitalWrite(SWITCH1,HIGH);
				}else if(strstr(voiceHandler->command,"KCT") != NULL){
					digitalWrite(SWITCH2,LOW);
				}else if(strstr(voiceHandler->command,"GCT") != NULL){
					digitalWrite(SWITCH2,HIGH);
				}else if(strstr(voiceHandler->command,"KEL") != NULL){
					digitalWrite(SWITCH3,LOW);
				}else if(strstr(voiceHandler->command,"GEL") != NULL){
					digitalWrite(SWITCH3,HIGH);
				}else if(strstr(voiceHandler->command,"KWS") != NULL){
					digitalWrite(SWITCH4,LOW);
				}else if(strstr(voiceHandler->command,"GWS") != NULL){
					digitalWrite(SWITCH4,HIGH);
				}
			}
			memset(voiceHandler->command,'\0',sizeof(voiceHandler->command));
		}
	}

}

void *cameraThread_func(void* data)//起线程的函数有格式要求
{
	struct Devices *cameraTemp;

	cameraTemp = findDeviceByName("camera", pdeviceHead); 	//设备都要从工厂里面取出来

	if(cameraTemp == NULL){  //防止段错误的必需判断,当给指针赋值是,一定要考虑NULL的情况,否则后续操作都是空谈
		printf("find camera error\n");
		pthread_exit(NULL); //在线程中不用return
	}

	cameraTemp->justDoOnce(); //调用postUrl函数
}


void * read_thread(void* datas)
{
	int n_read;
	while(1){
		memset(socketHandler->command,'\0', sizeof(socketHandler->command));
		n_read = read(c_fd,socketHandler->command,sizeof(socketHandler->command));	//从套接字中读取指令放在socketHandler->command中
		if(n_read == -1){
			perror("read");
		}else if(n_read>0){
			printf("\nget: %d,%s\n",n_read,socketHandler->command);	//打印出指令字节数和指令
			if(strstr(socketHandler->command,"KYS") != NULL){		//对socket收到的指令进行分析,并执行对应的操作
				digitalWrite(SWITCH1,LOW);
			}
			if(strstr(socketHandler->command,"GYS") != NULL){
				digitalWrite(SWITCH1,HIGH);
			}
			if(strstr(socketHandler->command,"KCT") != NULL){
				digitalWrite(SWITCH2,LOW);
			}
			if(strstr(socketHandler->command,"GCT") != NULL){
				digitalWrite(SWITCH2,HIGH);
			}
			if(strstr(socketHandler->command,"KEL") != NULL){
				digitalWrite(SWITCH3,LOW);
			}
			if(strstr(socketHandler->command,"GEL") != NULL){
				digitalWrite(SWITCH3,HIGH);
			}
			if(strstr(socketHandler->command,"KWS") != NULL){
				digitalWrite(SWITCH4,LOW);
			}
			if(strstr(socketHandler->command,"GWS") != NULL){
				digitalWrite(SWITCH4,HIGH);
			}
			if(0 == strcmp(socketHandler->command,"OPCA")){		//当指令是OPCA时创建摄像头线程,完成拍照,人脸识别
				pthread_t cameraThread;
				pthread_create(&cameraThread,NULL,cameraThread_func,NULL);
				//pthread_join(cameraThread, NULL);
			}
		}
	}
}

void * socket_thread(void* datas)
{
	int n_read = 0;
	pthread_t readThread;
	struct sockaddr_in c_addr;
	memset(&c_addr, 0, sizeof(struct sockaddr_in));
	int clen = sizeof(struct sockaddr_in);

	socketHandler = findCommandByName("sockerServer",pCommandHead);

	if(socketHandler == NULL){	//防止段错误
		printf("find socketHandler error\n");
		pthread_exit(NULL);		//在线程中不用return
	}else{
		printf("%s init success\n",socketHandler->commandName);
	}
	socketHandler->Init(socketHandler,NULL,NULL);		//找到之后执行socketInit函数

	while(1){
		c_fd = accept(socketHandler->sfd, (struct sockaddr *)&c_addr, &clen);	//不断连接connect,连接到后创建readThread线程
		pthread_create(&readThread,NULL,read_thread,NULL);
	}
}

int main()
{
	char name[128];
	struct Devices *tmp = NULL;
	pthread_t voiceThread;
	pthread_t socketThread;
	pthread_t fireAlarm_thread;

	if(wiringPiSetup() == -1){
		return -1;
	}

	//1.指令工厂初始化
	pCommandHead = addvoiceContrlToInputCommandLink(pCommandHead);
	pCommandHead = addSocketContrlToInputCommandLink(pCommandHead);

	//2.设备控制工厂初始化
	pdeviceHead = addBathroomLightToDeviceLink(pdeviceHead);
	pdeviceHead = addUpstairLightToDeviceLink(pdeviceHead);
	pdeviceHead = addRestaurantLightToDeviceLink(pdeviceHead);
	pdeviceHead = addLivingroomLightToDeviceLink(pdeviceHead);
	pdeviceHead = addcameraToDeviceLink(pdeviceHead);
	pdeviceHead = addFireToDeviceLink(pdeviceHead);
	pdeviceHead = addBeepToDeviceLink(pdeviceHead);

	struct Devices *tmpDeviceshead = pdeviceHead;
	while(tmpDeviceshead != NULL){						//设备工厂所有设备初始化
		tmpDeviceshead->deviceInit(tmpDeviceshead->pinNum);
		tmpDeviceshead = tmpDeviceshead->next;
	}
	
	
	//3.线程池建立
	//int pthread_create(pthread_t *restrict tidp, const pthread_attr_t *restrict attr, void *(*start_rtn)(void *), void *restrict arg);
	//3.1语音线程
	pthread_create(&voiceThread,NULL,voice_thread,NULL);

	//3.2socket线程
	pthread_create(&socketThread,NULL,socket_thread,NULL);

	//3.3摄像头线程

	//3.4火灾线程
	pthread_create(&fireAlarm_thread,NULL,fireAlarmThread,NULL);
	printf("camera init success\n");

	pthread_join(voiceThread,NULL);		//等待语音线程调用pthread_exit函数
	pthread_join(socketThread,NULL);	//等待socket线程调用pthread_exit函数
	pthread_join(fireAlarm_thread, NULL);	//等待火灾线程调用pthread_exit函数


	return 0;
}


3.段错误

在添加摄像头线程时,改了半天错误之后,可运行了,但是给我提示 segment fault,哈哈哈,心态崩了。当时我就关了树莓派打起了LOL,这一打就是一下午。晚上接着处理段错误,无果,第二天,无果。第二天晚上在图书馆发呆想到了找段错误的一种方法:printf调试法,晚上回到宿舍用了printf调试法十分钟就找到了错误,然后改正,运行成功,人脸识别成功。

4.C语言的函数声明

有的书上是这么说的,如果函数定义放在main函数前面,可以不用写声明。如果函数放在main函数后面,就规定要写函数声明。这么说没毛病。
不过有的地方又说:如果在函数定义在这个函数调用之前,就不需要写声明。否则就要写声明。
大家稍微注意下就行。为了防止报错的话,只要是函数都给声明就行了。

4.1没声明的报错内容

warning: implicit declaration of function ‘test’ [-Wimplicit-function-declaration]在这里插入图片描述

5.关于报错,调试程序

编译报错,你要正确认识报错,为什么要报错。编译报错是编译器在帮助你。不要有报错就放弃,慢慢调试,成功永远在拐角之后,否则你永远不知道你离它有多远。加油。

  • 7
    点赞
  • 43
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值