2023服创 A10 智能家居远程控制系统

一、项目要求

        本文的智能家居系统基于 WiFi 无线通信技术和手机Android 客户端,可实现对家用电器的控制和对家庭环境中温湿度、光照强度、可燃气体浓度的检测等基础功能,以及情绪识别和智能安防等创新功能。本项目设计的智能家居控制系统的设计目标如下所述:

  • 智能控制系统:可以实现智能设备的单个或批量的接入、断开、管理;联动控制多种智能家电;创建家庭群组并授予亲属用户对于智能家电设备的控制权限;
  • 智能安防系统:实时监测、存储、分析家居环境信息,当监测指标超过安全范围则将发送报警信息,防范灾害发生;通过多组态交叉识别的生物信息提取,提高屋门解锁的准确性;远程控制门锁的开关,警示可疑人员;
  • 智能照明系统:通过APP要求实现房屋内灯光一键全开,全关。对房间,客餐厅,主卧,次卧等区域灯光实行分区控制,对于一个区域有多种灯源要独立设立控制开关,系统展示房间内灯源打开数量以及打开区域,方便用户进入系统操作开关,查看资源消耗情况;
  • 智能暖通系统:通过APP要求实现房屋内空调一键全开,全关。实现对房间客厅,主卧,次卧空调分别控制开关,模式控制(制冷,制热,通风),温度设定,风速(低风,中风,高风),查看资源消耗情况;
  • 情景模式:根据节日或者识别到的人的情绪,联动相关智能设备,开启特定模式;单独或批量设置模式中联动设备的状态;
  • APP操作简单方便、界面简洁美观;

二、项目内容

本项目基于 Android,设计开发出一款智能家居远程控制 APP,实现远程控制房间的智能家居设备,首先,在进入房间时使用多组态交叉识别的智能安防系统来实现远程开锁,提高屋门解锁的准确性并且警示可疑人员,同时使用多模块融合的情绪识别模型来识别主人情绪,进行屋内多情绪模式的切换,实现改善情绪的联动响应;其次,对房屋的设备进行实时监测、存储、分析家居环境信息,实现智能设备的单个或批量的接入、断开、管理并且联动控制多种智能家电,查看并控制照明设备,更改设备状态、模式,查看资源消耗情况;最后,设置安全报警系统和预警提醒系统,获取温度湿度和烟雾等信息,并对其进行预测提醒主人出行安全,对房间的异常设备进行警报,检查如果出现火灾,煤气泄漏等严重情况进行报警处理,以确保房主的安全。本文主要描述加粗字体功能的硬件实现和通信硬件部分通信代码。

图2-1 整体项目设计

三-、硬件部分代码和连接图 

1、硬件部分的总体构成

        硬件整体通过esp8266进行远程通信,实现题中的智能控制中心并且减少接线复杂程度,同时系统可扩展性大大增强。

图3-1 总通信模块示意图

2、各个部分的构成

(1)硬件部分的连接

        本项目的智能家居系统总共有三个通信模块和三个MCU,实现对家居各个房间的单独控制。厕所和次卧的灯光连接在主卧的MCU上,用更简单的方式模拟。

门厅硬件连接图如下:

图3-2 门厅硬件连接图

图中人脸识别模块,指纹模块都通过串口和MCU通信,若识别到指纹库中的指纹或者人脸库中的人脸,模块给MCU发送成功指令,MCU控制舵机开门90°。RFID通过SPI2和MCU通信,若卡片正确也会给MCU发送成功指令,然后开门。温湿度传感器会通过ADC外设将检测到的温湿度数据传给MCU,MCU通过串口3将数据上传到服务器。烟雾传感器会在有害气体浓度过高时发出警报,指示灯恒亮。离线语音模块可以根据录入的指令直接给不同IO口高电平,此时可以在MCU内设置各个指令的最后效果。

客厅硬件连接图如下:

图3-3 客厅硬件连接图

图中电机1模拟空调在通风模式下的转速,利用TIM1_CH4输出不同占空比的PWM波控制电机不同的转速。DS0模拟制热模式下设定温度的变化,温度越高,红色灯光越亮;DS1模拟制冷模式下设定温度的变化,温度越低,绿色灯光越亮;灯1代表灯光系统中客厅的主灯,通过给IO口赋高低电平来控制。灯5代表餐厅主灯,同理控制。电机3用来模拟客厅窗帘的开关,通过给电机驱动不同的正负信号控制电机正反转,实现窗帘的开关。WIFI模块用来和门厅的网关模块相连,实现通信功能。

卧室硬件连接图如下:

图3-4 卧室硬件连接图

图中电机2模拟空调在通风模式下的转速,利用TIM1_CH4输出不同占空比的PWM波控制电机不同的转速。DS0模拟制热模式下设定温度的变化,温度越高,红色灯光越亮;DS1模拟制冷模式下设定温度的变化,温度越低,绿色灯光越亮;灯2代表灯光系统中卧室的主灯,通过给IO口赋高低电平来控制。灯4代表次卧主灯,同理控制。灯3代表厕所灯,通过感应人体发出高低电平控制灯的亮灭。WIFI模块用来和门厅的网关模块相连,实现通信功能。

(2)硬件程序设计
门厅部分

门厅部分作为智能控制中心,包含整个系统的网关,以及门厅及其周边的控制。主要连接了通信,指纹,人脸识别,门以及温湿度传感器模块。

图3-5 门厅部分软件程序流程图

   模块初始化函数

指纹

指纹模块使用ATK-AS608 指纹识别模块,是一款高性能的光学指纹识别模块。芯片内置 DSP 运算单元,集成了指纹识别算法,能高效快速采集图像并识别指纹特征。模块通过串口与mcu进行沟通。该模块主要包含录入,验证,删除指纹等功能。代码内容包括模块与mcu的信息交流,通过发送指令使指纹模块实现图像写入,图像储存,图像检索等功能。

void PS_StaGPIO_Init(void);//初始化PA6读状态引脚
	
u8 PS_GetImage(void); //录入图像 
 
u8 PS_GenChar(u8 BufferID);//生成特征 

u8 PS_Match(void);//精确比对两枚指纹特征 

u8 PS_Search(u8 BufferID,u16 StartPage,u16 PageNum,SearchResult *p);//搜索指纹 
 
u8 PS_RegModel(void);//合并特征(生成模板) 
 
u8 PS_StoreChar(u8 BufferID,u16 PageID);//储存模板 

u8 PS_DeletChar(u16 PageID,u16 N);//删除模板 

u8 PS_Empty(void);//清空指纹库 

u8 PS_WriteReg(u8 RegNum,u8 DATA);//写系统寄存器 
 
u8 PS_ReadSysPara(SysPara *p); //读系统基本参数 

u8 PS_SetAddr(u32 addr);  //设置模块地址 

u8 PS_WriteNotepad(u8 NotePageNum,u8 *content);//写记事本 

u8 PS_ReadNotepad(u8 NotePageNum,u8 *note);//读记事 

u8 PS_HighSpeedSearch(u8 BufferID,u16 StartPage,u16 PageNum,SearchResult *p);//高速搜索 
  
u8 PS_ValidTempleteNum(u16 *ValidN);//读有效模板个数 

u8 PS_HandShake(u32 *PS_Addr); //与AS608模块握手

const char *EnsureMessage(u8 ensure);//确认码错误信息解析

void Add_FR(void);

void press_FR(void);

void Del_FR(void);

下面是录入,验证,删除的代码

//录指纹
void Add_FR(void)
{
  u8 i, ensure, processnum = 0;
  
  while(1)
  {
    switch (processnum)
    {
    case 0:
      i++;
      printf("    请按手指    \r\n");
      ensure = PS_GetImage();
      if(ensure == 0x00)
      {
        ensure = PS_GenChar(CharBuffer1); //生成特征
        if(ensure == 0x00)
        {
          printf("    指纹正常    ");
          printf("                ");
          i = 0;
          processnum = 1; //跳到第二步
        }
        else ShowErrMessage(ensure);
      }
      else ShowErrMessage(ensure);
      break;

    case 1:
      i++;
      printf("   请再按一次   ");
      printf("                ");
      ensure = PS_GetImage();
      if(ensure == 0x00)
      {
        ensure = PS_GenChar(CharBuffer2); //生成特征
        if(ensure == 0x00)
        {
          printf("    指纹正常    ");
          printf("                ");
          i = 0;
          processnum = 2; //跳到第三步
        }
        else ShowErrMessage(ensure);
      }
      else ShowErrMessage(ensure);
      break;

    case 2:
      printf("  对比两次指纹  ");
      printf("                ");
      ensure = PS_Match();
      if(ensure == 0x00)
      {
        printf("    对比成功    ");
        printf("                ");
        processnum = 3; //跳到第四步
      }
      else
      {
        printf("    对比失败    ");
        printf("                ");
        ShowErrMessage(ensure);
        i = 0;
        processnum = 0; //跳回第一步
      }
      delay_ms(500);
      break;

    case 3:
      printf("  生成指纹模板  ");
      printf("                ");
      delay_ms(500);
      ensure = PS_RegModel();
      if(ensure == 0x00)
      {
        printf("生成指纹模板成功");
        printf("                ");
        processnum = 4; //跳到第五步
      }
      else
      {
        processnum = 0;
        ShowErrMessage(ensure);
      }
      delay_ms(1000);
      break;

    case 4:
			++ID_NUM;
			printf("ID=");
			printf("%d",ID_NUM);
      ensure = PS_StoreChar(CharBuffer2, ID_NUM); //储存模板
      if(ensure == 0x00)
      {
        //OLED_Clear();
        printf("  录入指纹成功  ");
        printf("                ");
        delay_ms(1500);
        //OLED_Clear();
        printf("指纹模块测试程序");
        printf("K1键添加指纹");
        printf("K3键删除指纹");
        printf("K5键验证指纹");
        return ;
      }
      else
      {
        //OLED_Clear();
        processnum = 0;
        ShowErrMessage(ensure);
      }
      break;
    }
    delay_ms(400);
    if(i == 10) //超过5次没有按手指则退出
      break;
  }
}

SysPara AS608Para;//指纹模块AS608参数
//刷指纹
extern KEY_Configure_TypeDef Key1Cfg;
void press_FR(void)
{
  SearchResult seach;
  u8 ensure;
  char str[20];
  while(Key1Cfg.KEY_Event != KEY_Event_SingleClick)
  {
    //key_num = KEY_Scan(0);
    ensure = PS_GetImage();
    if(ensure == 0x00) //获取图像成功
    {
      ensure = PS_GenChar(CharBuffer1);
      if(ensure == 0x00) //生成特征成功
      {
        ensure = PS_HighSpeedSearch(CharBuffer1, 0, 99, &seach);
        if(ensure == 0x00) //搜索成功
        {
          printf("  指纹验证成功  ");
					doorstate=1;
          sprintf(str, " ID:%d 得分:%d ", seach.pageID, seach.mathscore);
          printf((u8*)str);
         break;
        }
        else
        {
          printf("验证失败");
          delay_ms(1500);
        }
      }
      else
      //OLED_Clear();
      printf("请按手指");
    }
  }
  //OLED_Clear();
  printf("指纹模块测试程序");
  printf("K1键添加指纹");
  printf("K3键删除指纹");
  printf("K5键验证指纹");
}

//删除指纹
void Del_FR(void)
{
  u8  ensure;
	printf("1234");
	ensure = PS_Empty(); //清空指纹库
	if(ensure == 0)
	{
		//OLED_Clear();
		printf(" 清空指纹库成功 ");
		ID_NUM = 0;
	}
	else
		ShowErrMessage(ensure);
}
舵机

开门动作需要舵机逆时针旋转90°,关门动作需要舵机顺时针旋转90°,可以通过控制舵机转动的时间控制旋转的方向。通过定时器2的比较函数可以直接控制旋转度数。旋转5度表示关门,旋转90°表示开门。servo_angle()中参数是代表旋转角度,servo_init()表示开机状态时关门。

void servo_init(void)
{
	TIM2_Init(SERVO_TIM_ARR,SERVO_TIM_PSC);
	servo_angle(90);
}
 
//0.5ms--0°  2.5ms--180°
void servo_angle(uint16_t angle)
{
  uint16_t pulse;
  
  //针对舵机可转角度限辐
  if(angle <= 5)
    angle = 5;
  if(angle >= 175)
    angle = 175;
  //将角度值转换为脉冲值  
  pulse = (uint16_t)(50 + angle * 100/90.0);  //此转换公式需根据pwm的arr及psc配置来做相应变化
  TIM_SetCompare2(TIM2, pulse);
}
按键

按键初始化属于是对gpio口的初始化。需要配置分频数,引脚位置,引脚模式。通过按下按键引发中断,改变标志位状态,进而控制实现相应的功能。

void KEY_Init(void) //IO初始化
{ 
 	GPIO_InitTypeDef GPIO_InitStructure;
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOC,ENABLE);//使能PORTA,PORTC时钟
	GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE);//关闭jtag,使能SWD,可以用SWD模式调试
 
		//初始化 key0-->GPIOC5  
	GPIO_InitStructure.GPIO_Pin  = GPIO_Pin_5;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //设置成上拉输入
	GPIO_Init(GPIOC, &GPIO_InitStructure);//初始化GPIOA.0
	
		//初始化 key1-->GPIOA15	  
	GPIO_InitStructure.GPIO_Pin  = GPIO_Pin_15;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //设置成上拉输入
	GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.0

}

由于本开发板按键数量有限,可以通过长按,短按不同设置来增加可控功能数。采用有限状态机的程序模式可以加快运行速率。

// 长按时长的宏定义
#define KEY_LONG_PRESS_TIME    50  // 20ms*50 = 1s
#define KEY_PRESSED_LEVEL      1   // wake_up按键被按下时的电平
#define KEY_PRESSED_LEVEL1      0   // key0,key1按键被按下时的电平

KEY_Configure_TypeDef Key0Cfg={
		
		0,						// 按键长按时长计数
		KEY_Action_Release,		// 按键动作,按下或释放 
		KEY_Status_Idle,        // 按键状态
		KEY_Event_Null,         // 按键事件
		KEY0_ReadPin             // 读引脚电平函数
};

static KEY_PinLevel_TypeDef  KEY0_ReadPin(void); //按键读取函数

static void KEY0_GetAction(void);// 获取按键动作,按下或释放,保存到结构体

//读取key0引脚的电平Pc5
static KEY_PinLevel_TypeDef  KEY0_ReadPin(void) 
{
  return (KEY_PinLevel_TypeDef)GPIO_ReadInputDataBit(GPIOC,GPIO_Pin_5);
}
static void KEY0_GetAction(void) // 获取按键动作,按下或释放,保存到结构体
{
	if(Key0Cfg.KEY_ReadPin_Fcn() == KEY_PRESSED_LEVEL1)
	{
		Key0Cfg.KEY_Action = KEY_Action_Press;
	}
	else
	{
		Key0Cfg.KEY_Action =  KEY_Action_Release;
	}
 
}

void KEY0_ReadStateMachine(void)
{
    KEY0_GetAction();
	switch(Key0Cfg.KEY_Status)
	{
		//状态:没有按键按下
		case KEY_Status_Idle:
			if(Key0Cfg.KEY_Action == KEY_Action_Press)
			{
				Key0Cfg.KEY_Status = KEY_Status_Debounce;
				Key0Cfg.KEY_Event = KEY_Event_Null;
			}
			else
			{
				Key0Cfg.KEY_Status = KEY_Status_Idle;
				Key0Cfg.KEY_Event = KEY_Event_Null;
			}
			break;
			
		//状态:消抖
		case KEY_Status_Debounce:
			if(Key0Cfg.KEY_Action == KEY_Action_Press)
			{
				Key0Cfg.KEY_Status = KEY_Status_ConfirmPress;
				Key0Cfg.KEY_Event = KEY_Event_Null;
			}
			else
			{
				Key0Cfg.KEY_Status = KEY_Status_Idle;
				Key0Cfg.KEY_Event = KEY_Event_Null;
			}
			break;	
			
		//状态:确认按下
		case KEY_Status_ConfirmPress:
			if( (Key0Cfg.KEY_Action == KEY_Action_Press) && ( Key0Cfg.KEY_Count >= KEY_LONG_PRESS_TIME))
			{
				printf("0000KEY_Status_ConfirmPressLong\r\n");
				Key0Cfg.KEY_Count = 0;
				Key0Cfg.KEY_Status = KEY_Status_ConfirmPressLong;
				Key0Cfg.KEY_Event = KEY_Event_Null;
				
			}
			else if( (Key0Cfg.KEY_Action == KEY_Action_Press) && (Key0Cfg.KEY_Count < KEY_LONG_PRESS_TIME))
			{
				printf("0000继续按下 %d\r\n",Key0Cfg.KEY_Count);
				Key0Cfg.KEY_Count++;
				Key0Cfg.KEY_Status = KEY_Status_ConfirmPress;
				Key0Cfg.KEY_Event = KEY_Event_Null;
			}
			else
			{
				printf("0000突然gg,按短了,未达到长按时间,为短按 %d\r\n",Key0Cfg.KEY_Count);
				Key0Cfg.KEY_Count = 0;
				Key0Cfg.KEY_Status = KEY_Status_Idle;
				Key0Cfg.KEY_Event = KEY_Event_SingleClick;
			}
			break;				
		//状态:确认长按
		case KEY_Status_ConfirmPressLong:
			printf("0000KEY_Status_ConfirmPressLong\r\n");
			if(Key0Cfg.KEY_Action == KEY_Action_Press) 
			{   // 一直等待其放开
				printf("0000一直按着 KEY_Status_ConfirmPressLong\r\n");
				//LED0=0;
				Key0Cfg.KEY_Status = KEY_Status_ConfirmPressLong;
				Key0Cfg.KEY_Event = KEY_Event_Null;
				Key0Cfg.KEY_Count = 0;
			}
			else
			{
				//LED0=1;
				Key0Cfg.KEY_Status = KEY_Status_Idle;
				Key0Cfg.KEY_Event = KEY_Event_LongPress;
				Key0Cfg.KEY_Count = 0;
			}
			break;	
		default:
			break;
	}

}
esp8266

首先写好通过窗口给该模发送指令的函数,该模块的初始化需要依照功能需求选择特定的模式,通过发送指令函数发送AT指令实现功能。与服务器建立tcp连接。

发送指令函数



//向ESP8266发送命令
//cmd:发送的命令字符串;ack:期待的应答结果,如果为空,则表示不需要等待应答;waittime:等待时间(单位:10ms)
//返回值:0,发送成功(得到了期待的应答结果);1,发送失败
u8 esp8266_send_cmd(u8 *cmd,u8 *ack,u16 waittime)
{
	u8 res=0; 
	USART3_RX_STA=0;
	u3_printf("%s\r\n",cmd);	//发送命令
	if(ack&&waittime)		//需要等待应答
	{
		while(--waittime)	//等待倒计时
		{
			delay_ms(10);
			if(USART3_RX_STA&0X8000)//接收到期待的应答结果
			{
				if(esp8266_check_cmd(ack))
				{
					printf("ack:%s\r\n",(u8*)ack);
					break;//得到有效数据 
				}
					USART3_RX_STA=0;
			} 
		}
		if(waittime==0)res=1; 
	}
	return res;
} 


//ESP8266发送命令后,检测接收到的应答
//str:期待的应答结果
//返回值:0,没有得到期待的应答结果;其他,期待应答结果的位置(str的位置)
u8* esp8266_check_cmd(u8 *str)
{
	char *strx=0;
	if(USART3_RX_STA&0X8000)		//接收到一次数据了
	{ 
		USART3_RX_BUF[USART3_RX_STA&0X7FFF]=0;//添加结束符
		strx=strstr((const char*)USART3_RX_BUF,(const char*)str);
	} 
	return (u8*)strx;
}


//向ESP8266发送数据
//cmd:发送的命令字符串;waittime:等待时间(单位:10ms)
//返回值:发送数据后,服务器的返回验证码
u8* esp8266_send_data(u8 *cmd,u16 waittime)
{
	char temp[5];
	char *ack=temp;
	USART3_RX_STA=0;
	u3_printf("%s\r\n",cmd);	//发送命令
	if(waittime)		//需要等待应答
	{
		while(--waittime)	//等待倒计时
		{
			delay_ms(10);
			if(USART3_RX_STA&0X8000)//接收到期待的应答结果
			{
				USART3_RX_BUF[USART3_RX_STA&0X7FFF]=0;//添加结束符
				ack=(char*)USART3_RX_BUF;
				printf("ack:%s\r\n",(u8*)ack);
				USART3_RX_STA=0;
				break;//得到有效数据 
			} 
		}
	}
	return ack;
}
	
	u8* esp8266_send_num(u8 cmd,u16 waittime)
{
	char temp[5];
	char *ack=temp;
	USART3_RX_STA=0;
	u3_printf("%d\r\n",cmd);	//发送命令
	if(waittime)		//需要等待应答
	{
		while(--waittime)	//等待倒计时
		{
			delay_ms(10);
			if(USART3_RX_STA&0X8000)//接收到期待的应答结果
			{
				USART3_RX_BUF[USART3_RX_STA&0X7FFF]=0;//添加结束符
				ack=(char*)USART3_RX_BUF;
				printf("ack:%s\r\n",(u8*)ack);
				USART3_RX_STA=0;
				break;//得到有效数据 
			} 
		}
	}
	return (u8*)ack;
} 
u8* esp8266_send_float(float cmd,u16 waittime)
{
	char temp[5];
	char *ack=temp;
	USART3_RX_STA=0;
	u3_printf("%f\r\n",cmd);	//发送命令
	if(waittime)		//需要等待应答
	{
		while(--waittime)	//等待倒计时
		{
			delay_ms(10);
			if(USART3_RX_STA&0X8000)//接收到期待的应答结果
			{
				USART3_RX_BUF[USART3_RX_STA&0X7FFF]=0;//添加结束符
				ack=(char*)USART3_RX_BUF;
				printf("ack:%s\r\n",(u8*)ack);
				USART3_RX_STA=0;
				break;//得到有效数据 
			} 
		}
	}
	return (u8*)ack;
} 

利用AT指令初始化模块

const char* host = "***"; //需要访问的域名
 const int httpsPort = ***;  // 需要访问的端口
 const char* url = "***";   // 需要访问的地址
extern char p[50];
	
//ESP8266模块和PC进入透传模式
void esp8266_start(void)
{
	while(esp8266_send_cmd("AT","OK",20))//检查WIFI模块是否在线
	{
		esp8266_quit_trans();//退出透传
		esp8266_send_cmd("AT+CIPMODE=0","OK",200);  //关闭透传模式
		delay_ms(800);
	}
	
	//设置工作模式 1:station模式   2:AP模式  3:兼容 AP+station模式
	esp8266_send_cmd("AT+CWMODE=3","OK",50);
	
	//让Wifi模块重启的命令
	while(esp8266_send_cmd("AT+RST","OK",20));
	printf("%s",USART3_RX_BUF);
	
	delay_ms(1000);         //延时3S等待重启成功
	delay_ms(1000);
	delay_ms(1000);
	delay_ms(1000);
	printf("未连接");
	//让模块连接上自己的路由
	while(esp8266_send_cmd("AT+CWSAP=\"E1\",\"12345678\",1,4","OK",600));
	while(esp8266_send_cmd("AT+CWJAP=\"mm\",\"12345678\"","WIFI GOT IP",600));
	printf("已连接");
	 while(esp8266_send_cmd("AT+CIFSR","APIP",20));
	//=0:单路连接模式     =1:多路连接模式0
	printf("%s",USART3_RX_BUF);
	esp8266_send_cmd("AT+CIPMUX=1","OK",20);
	delay_ms(500);
	esp8266_send_cmd("AT+CIPSERVER=1,8086","OK",20); ///改
		delay_ms(500);
  esp8266_send_cmd("AT+CIPSTO=1200","OK",20);

	  
	//建立TCP连接  这四项分别代表了 要连接的ID号0~4   连接类型  远程服务器IP地址   远程服务器端口号
	while(esp8266_send_cmd("AT+CIPSTART=0,\"TCP\",\"106.55.182.93\",1234","CONNECT",200));/改
	printf("IP连接");
	sprintf(p,"*8509b7ae-ab4b-4949-94d2-0f0501b55154");
	esp8266_send_data("AT+CIPSEND=0,37",300);
	esp8266_send_data(p,50);
	
	printf("序列号已发送");
}

//ESP8266退出透传模式   返回值:0,退出成功;1,退出失败
//配置wifi模块,通过想wifi模块连续发送3个+(每个+号之间 超过10ms,这样认为是连续三次发送+)
u8 esp8266_quit_trans(void)
{
	u8 result=1;
	u3_printf("+++");
	delay_ms(1000);					//等待500ms太少 要1000ms才可以退出
	result=esp8266_send_cmd("AT","OK",20);//退出透传判断.
	if(result)
		printf("quit_trans failed!");
	else
		printf("quit_trans success!");
	return result;
}





温湿度传感器

温湿度传感器通过stm32集成的adc转换通道将温湿度的模拟电信号转化成数字信号。最后将数字信号信息通过公式转化成温度信息发送给app(烟雾传感器的原理和这个类似),从而实现对屋内环境状况的检测。

u8 DHT11_Init(void)
{	 
 	GPIO_InitTypeDef  GPIO_InitStructure;
 	
 	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOG, ENABLE);	 //使能PG端口时钟
	
 	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;				 //PG11端口配置
 	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; 		 //推挽输出
 	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
 	GPIO_Init(GPIOG, &GPIO_InitStructure);				 //初始化IO口
 	GPIO_SetBits(GPIOG,GPIO_Pin_11);						 //PG11 输出高
			    
	DHT11_Rst();  //复位DHT11
	return DHT11_Check();//等待DHT11的回应
} 
void dht11_task(void *pvParameters)	//任务函数
{
	while(1)
	{
		printf("dht11\n");
		DHT11_Read_Data(&temperature,&humidity);	//读取温湿度值
		printf("当前室内的温度:%d\t湿度:%d\r\n",(int)temperature,humidity);
//		sprintf(p,"{\"t\":%s, \"h\":%s,\"d\":%s}",(int)temperature,humidity,doorstate);
//		esp8266_send_data("AT+CIPSEND=0,100",300);
//		esp8266_send_data(p,100);
		vTaskDelay(500);
	}
}

rfid 

RFID或射频识别系统由两个主要组件组成,一个是附加到要识别的对象上的应答器/标签,另一个是也称为询问器/阅读器的收发器。阅读器由射频模块和产生高频电磁场的天线组成。它包含一个用于存储和处理信息的微芯片,以及一个用于接收和发送信号的天线。要读取标签上编码的信息,将其放置在阅读器的附近(不需要在阅读器的直接视线范围内)。读取器产生电磁场,该电磁场使电子移动通过标签的天线,然后为芯片供电。主要读取该模块信息与正确信息比对,信息正确则开门。RFID使用spi通信。

客厅部分

客厅部分包含了客厅的空调,窗帘以及灯光模块。

图3-6 客厅部分软件程序流程图

卧室部分

卧室部分包括空调,控制基本和客厅模块一样,还包括主卧灯,次卧灯和厕所灯光。当服务发来多控指令时,应该解析成多个全局控制变量的变化。各模块代码书写思路一致,只有8266设置模式不同。

void esp8266_start(void)
{while(esp8266_send_cmd("AT","OK",20))//检查WIFI模块是否在线
	{
		esp8266_quit_trans();//退出透传
		esp8266_send_cmd("AT+CIPMODE=0","OK",200);  //关闭透传模式
		delay_ms(800);
	}
	
	//设置工作模式 1:station模式   2:AP模式  3:兼容 AP+station模式
	esp8266_send_cmd("AT+CWMODE=1","OK",50);
	
	//让Wifi模块重启的命令
	while(esp8266_send_cmd("AT+RST","OK",20));
	

	printf("未连接");
	//让模块连接上自己的路由
	//while(esp8266_send_cmd("AT+CWSAP=\"E1\",\"12345678\",1,4","OK",600));
	while(esp8266_send_cmd("AT+CWJAP=\"E1\",\"12345678\"","WIFI GOT IP",600));
	//while(esp8266_send_cmd("AT+CWJAP=\"Xiaomi_9B4B\",\"88888888\"","WIFI GOT IP",600));
	printf("已连接");
	 while(esp8266_send_cmd("AT+CIFSR","OK",20));
	//=0:单路连接模式     =1:多路连接模式
	printf("%s",USART3_RX_BUF);
	esp8266_send_cmd("AT+CIPMUX=0","OK",20);
	delay_ms(500);

	printf("IP连接");
	

}

图3-7 卧室部分软件程序流程图

        使用全局状态变量控制比直接控制相应端口更加简洁易懂,可移植性更好。

四、问题和解决方案

1、通讯的连接以及连接速度问题

        (1)ESP8266使用ap+ata模式实现接受指令和发送指令

        以前的项目只使用过一个esp8266模块与远程服务器连接,由于创新增加了一些功能模块并且题目要求使用智能控制中心,需要完成模块1与服务器之间的通讯,也需要完成模块1与模块2、模块1与模块3之间的通讯,实现一对多和一个模块同时实现接收和发送功能。两个功能可以分开调试,最后再合到一起。

        (2)传输速率底下

        在没有加入free rtos系统之前,整个系统是单线程运作,两个模块节点会抢和网关的连接,导致运行缓慢并且传输不稳定。改进之后,使用多线程既可以提高程序运行速度又可以保证网关命令准确的发送到每一个节点。

2、通讯的传输格式问题

        (1)主机和从机的数据传输

尽量设计简单的能够顾名思义的传输内容,写好通信协议,包括包头包尾。

        (2)摄像头的数据传输

摄像头的内置代码运行,以至于发送内容的格式不好确定,也不好接收,最后通过串口调试助手,逐个内容比对得出。

3、端口的分配问题

stm32芯片的很多引脚都有复用功能,所以要按照功能合理分配,确保用尽量少的芯片和简单的接线方式完成项目。

五、参赛感想

1、关于项目内容

        对内容的创意来自以前项目的积累,也来自于对日常生活的观察,蕴藏在每一个希望生活变好的瞬间。我们在思考创新内容时,最开始的时候不要放弃任何疯狂的想法,在实现阶段,尽量找到简单经济的方法,对于实现有困难的可以寻找实现路径,在以后的学习和其他项目中进一步发展。

2、关于如何获奖

        比赛是对我们学习成果的检查,是自身提高的需要,若是与此同时能够获奖,将是对我们学习过程一个很好的正反馈。首先,审题要清楚,这是一个创新创业的题目,必须要有足够的创新想法并且要能够投入生产,易于实现。其次,这是一个软件题,所以硬件部分是为了展示软件的功能和效果,要搞对重心,不用过于在意硬件具体功能的实现。再次,我们如果只求比赛获奖,最后只需要视频演示,文档和ppt,那么只要演示出创新的结果,功能分步实现,分开拍摄也是没有问题的,不必一镜到底。对于比赛,完成比完美更加重要,在做出完美结果前,需要一个可以上交的plan B。在得知晋级的前几天,我没有专注于ppt,反而想要提高连接速度有更好的展示效果,导致答辩的失误。总的来说,就是要抓住主要矛盾的主要方面。

3、关于答辩遇到的问题

答辩过程老师问的主要是和实际应用,实际生活相关的,基本不会问道技术问题,所以答辩之前的最后几天最好队员们一起模拟一下答辩过程,不要纠结于技术实现。答辩过程中有一个令我印象深刻的文体,关于情绪识别的部分(项目最初的想法是为孤独的成年人提供情绪支持,给予一定的安慰,没考虑到小孩)。老师问到:“如果小孩哭闹,识别机制一直做出反应该怎么办?”我们当时回答:“我们的系统有用户等级机制,可以设置对小孩的哭闹不做出反应。”事后复盘猜想到可以直接启动安抚小孩的音乐和灯光功能的。还问道如何接入空调设备,我就回答硬件部分空调是如何做的。老师知道我没懂问题,又说了格力,美的这种牌子的如何直接加到智能化系统中,其实重点在软件和软件的市场推广。

4、关于自学

        自学不仅依靠自身努力,有效的信息,高效的方法也非常重要。所以搜索能力也就变得极其重要。

        实践是自学的最快方式。学会之后马上进入实践,会使我对知识的理解更加深刻。做完项目再回过去看芯片手册,以前不明白的很多东西都明白了。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值