一、作品背景:
近年来,高校宿舍安全事故频发,给同学们造成了不必要的人身伤害和财产损失,故宿舍安全问题是学生安全生活的基本保障。宿舍的安全问题主要在于学生是否使用了违规电器,那么对用电设备的监测是重要的一环,所以本设计应运而生。
本设计用STM32单片机做主控芯片,对宿舍用电情况进行了智能监测,对火灾信号进行检测,利用OneNet物联网云平台对用电参数进行实时监测;同时拥有人脸识别功能,实现人走断电,对寝室智能的通断电进行控制;拥有指纹识别功能,实现宿舍门的开关;还设计了终端系统,可以看到各宿舍用电情况,包括是否着火、是否使用大功率设备,当有异常情况时,系统可以自动进行断电操作。
本设计自己认为很有实际意义,因为自己家旁边的学校就因为学生违规使用电器导致宿舍着火。
作品照片
使用到的元器件主要有:
宿舍终端:2块STM32F1RCT6核心板、2个ZigBee模块、2个指纹模块、2个蜂鸣器、2个IM1281B电参数采集模块、2个WIFI模块、2个开关电源、2个断路器、2个继电器、电源模块以及其他元件杜邦线若干。
宿舍管理员控制终端:1块STM32F7508—DK开发板、1个ZigBee模块、1块Linux开发板、摄像头、电源模块、串口屏等元件。
因为这些元件自己都有,所以也就顺便用上了,希望做一个简易的DEMO出来。
二、系统结构
2.1 系统框图
学生侧框图
学生侧端使用STM32核心板、WIFI、ZigBee、继电器以及传感器等其他元件组成,STM32核心板用来采集宿舍内的用电情况以及烟雾,火焰等信息。信号采集完以后使用STM32驱动WIFI模块把信号发送给中国移动OneNet物联网云平台,后在平台显示出各个宿舍用电,烟雾,火焰等信息,同时STM32还驱动ZigBee模块把宿舍信号发给控制终端,以便进行监控。
终端使用STM32F7508-DK开发板、ZigBee、串口屏、摄像头、Linux开发板等组成。因为嫌STM32F7508-DK开发板上自带的屏幕太小,所以手头有的串口屏也使用到本项目中。
STM32F7508-DK开发板作为ZigBee信号协调器的控制器,接收各个宿舍传来的各个信息,以便驱动串口屏显示。由于STM32F7508-DK开发板做人脸识别的时候速度比较慢,所以使用Linux开发板进行人脸识别,人脸识别完以后,STM32F7508-DK通过ZigBee信号协调器向宿舍发送命令,以便可以学生在离开宿舍的时候可以自行进行断电。
注:由于学生侧驱动代码比较完善,在学生侧设备的代码使用标准库编写,由于STM32F7508-DK有板载外设,且STM32CubeIDE中有对应配套的BSP,所以管理员终端侧设备使用HAL库开发。
2.2 系统硬件结构
三、各部分功能说明
3.1学生侧
学生侧设备的主要功能是:1、采集宿舍的用电信息;2、使用WIFI模块将电参数传到中国移动OneNet物联网云平台上;3、宿舍终端设备与宿舍管理员控制终端设备采用ZigBee进行数据交互,宿舍终端ZigBee作为终端节点向宿舍管理员控制终端发送宿舍的电参数,火焰、烟雾等信号,宿舍管理员控制终端的ZigBee作为协调器接收宿舍传来的信号;4、有指纹模块,可以实现指纹开门。
其中硬件接口如下:
电参数采集代码
void read_data(void)
{
union crcdata
{
unsigned int word16;
unsigned char byte[2];
}crcnow;
if(read_enable==1) // 到时间抄读模块,抄读间隔 1 秒钟(或其他)
{
read_enable=0;
Tx_Buffer1[0]=Read_ID; //模块的 ID 号,默认 ID 为 0x01
Tx_Buffer1[1]=0x03;
Tx_Buffer1[2]=0x00;
Tx_Buffer1[3]=0x48;
Tx_Buffer1[4]=0x00;
Tx_Buffer1[5]=0x08;
crcnow.word16=chkcrc(Tx_Buffer1,6);
Tx_Buffer1[6]=crcnow.byte[1]; //CRC 效验低字节在前
Tx_Buffer1[7]=crcnow.byte[0];
}
for(j=0;j<i;j++) //循环发送数据01 03 00 48 00 08 C4 1A
{
while(USART_GetFlagStatus(UART5,USART_FLAG_TC)==RESET); //串口三 循环发送,直到发送完毕
USART_SendData(UART5,Tx_Buffer1[j]);
// while(USART_GetFlagStatus(USART1,USART_FLAG_TC)==RESET); //循环发送,直到发送完毕
// USART_SendData(USART1,Tx_Buffer1[j]); //用 串口一 来检测是否发送的一样
}
Anysis_data_bit = 1;
// UsartPrintf(USART1,"read data_IM1281B\r\n");
}
当电参数数据采集完毕以后,需要进行解包,因为电参数模块使用的是ModBus协议,需要解包供系统使用。其中数据解包的代码如下
void Analysis_data(void)
{
union crcdata
{
unsigned int word16;
unsigned char byte[2];
}crcnow;
if(receive_finished==1) //接收完成
{
reveive_numbe=USART3_RX_STA;
receive_finished=0;
if((Rx_Buffer1[0]==0x01)||(Rx_Buffer1[0]==0x00)) //确认 ID 正确
{
crcnow.word16=chkcrc(Rx_Buffer1,reveive_numbe-2); //reveive_numbe 是接收数据总长度
if((crcnow.byte[0]==Rx_Buffer1[reveive_numbe-1])&&(crcnow.byte[1]==Rx_Buffer1[reveive_numbe-2]))//确认 CRC 校验正确
{
/////*********电压
// UsartPrintf(USART1,"%X,%X,%X,%X",Rx_Buffer1[3],Rx_Buffer1[4],Rx_Buffer1[5],Rx_Buffer1[6]);
Electric.Voltage_data=(((unsigned long)(Rx_Buffer1[3]))<<24)|(((unsigned long)(Rx_Buffer1[4]))<<16)|(((unsigned long)(Rx_Buffer1[5]))<<8)|Rx_Buffer1[6];
Electric.Voltage_data1 = (float)(Electric.Voltage_data*0.0001); //得到小数值
UsartPrintf(USART1,"\r\n电压值:%fV\r\n",Electric.Voltage_data1);//串口一来打印电压值
/////*********电流
Electric.Current_data=(((unsigned long)(Rx_Buffer1[7]))<<24)|(((unsigned long)(Rx_Buffer1[8]))<<16)|(((unsigned long)(Rx_Buffer1[9]))<<8)|Rx_Buffer1[10];
Electric.Current_data1 = (float)(Electric.Current_data*0.0001);
UsartPrintf(USART1,"电流:%fA\r\n",Electric.Current_data1);//串口一来打印电流
/////*********功率
Electric.Power_data=(((unsigned long)(Rx_Buffer1[11]))<<24)|(((unsigned long)(Rx_Buffer1[12]))<<16)|(((unsigned long)(Rx_Buffer1[13]))<<8)|Rx_Buffer1[14];
Electric.Power_data1 = (float)(Electric.Power_data*0.0001);
UsartPrintf(USART1,"功率:%fW\r\n",Electric.Power_data1);//串口一来打印功率
/////*********电能
Electric.Energy_data=(((unsigned long)(Rx_Buffer1[15]))<<24)|(((unsigned long)(Rx_Buffer1[16]))<<16)|(((unsigned long)(Rx_Buffer1[17]))<<8)|Rx_Buffer1[18];
Electric.Energy_data1 = (float)(Electric.Energy_data*0.0001);
// UsartPrintf(USART1,"电能:%f\r\n",Electric.Energy_data1);//串口一来打印电能
//
/////*********功率因数
Electric.Pf_data=(((unsigned long)(Rx_Buffer1[19]))<<24)|(((unsigned long)(Rx_Buffer1[20]))<<16)|(((unsigned long)(Rx_Buffer1[21]))<<8)|Rx_Buffer1[22];
Electric.Pf_data1=(float)(Electric.Pf_data*0.001);
// UsartPrintf(USART1,"功率因数:%.3lf\r\n",Electric.Pf_data1); //串口一来打印接受功率因数
//////*********CO2浓度
Electric.CO2_data=(((unsigned long)(Rx_Buffer1[23]))<<24)|(((unsigned long)(Rx_Buffer1[24]))<<16)|(((unsigned long)(Rx_Buffer1[25]))<<8)|Rx_Buffer1[26];
Electric.CO2_data1 = (float)(Electric.CO2_data*0.0001);
// UsartPrintf(USART1,"二氧化碳:%f\r\n",Electric.CO2_data1);//串口一来打印接受二氧化碳
///*************频率
Electric.HZ=(((unsigned long)(Rx_Buffer1[31]))<<24)|(((unsigned long)(Rx_Buffer1[32]))<<16)|(((unsigned long)(Rx_Buffer1[33]))<<8)|Rx_Buffer1[34];
Electric.HZ1= Electric.HZ*0.01;
// UsartPrintf(USART1,"赫兹:%.2lfHZ\r\n",Electric.HZ1);//串口一来打印接受单相交流电的赫兹
USART3_RX_STA=0;
Malignant_load_identfiy(); ///负载识别
}
// else UsartPrintf(USART1,"// CRC 校验错误\r\n");//串口一来打印接受电压值
}
ZigBee_UP_Date(); //更新完数据就开始ZigBee 数据传输。
wifi_null();
}
// else UsartPrintf(USART1,"\r\nreceive_finished标志位为0\r\n");
}
数据解析完毕以后,得到解析后的电参量结构体。
电参量采集的流程图如下所示
为了简单起见,设定功率达到一定值时继电器断开给宿舍进行断电,这里并没有对负载是阻性、容性还是感性类型进行识别。继电器控制框图如下图所示。
解包完以后数据变成浮点型,此时单片机系统可以控制WIFI模块向中国移动OneNet物联网云平台上传数据。
其WIFI模块硬件接口如下:
学生侧数据上传OneNet使用的是MQTT方式,具体可以从OneNet官网下载SDK使用。
下载完SDK以后,更改自己的WIFI热点以及密码。并在平台上创建设备信息,具体信息可以见OneNet文档
https://open.iot.10086.cn/doc/v5/develop/detail/easy-manual
建立的产品界面如下,可以看到产品和宿舍信息
完事以后,更改自己的产品ID、设备ID等参数。
#define ESP8266_WIFI_INFO "AT+CWJAP=\"ONENET\",\"IOT@Chinamobile123\"\r\n"
#define PROID "77247"
#define AUTH_INFO "test"
#define DEVID "5616839"
这一部分以及数据上传到平台以后如何进行数据流显示可以从OneNet官网入门资料入手。
数据打包上传
unsigned char OneNet_FillBuf(char *buf)
{
char text[512];
memset(text, 0, sizeof(text));
strcpy(buf, "{");
///****电压
memset(text, 0, sizeof(text));
sprintf(text, "\"Voltage\":%lf,", Electric.Voltage_data1);
strcat(buf, text);
///*****电流
memset(text, 0, sizeof(text));
sprintf(text, "\"Current\":%lf,", Electric.Current_data1);
strcat(buf, text);
////*****宿舍ID
memset(text, 0, sizeof(text));
sprintf(text, "\"DEV_ID\":%d,", DEVID1);
strcat(buf, text);
////*****有功功率
memset(text, 0, sizeof(text));
sprintf(text, "\"PWOER\":%lf,", Electric.Power_data1);
strcat(buf, text);
//////*******功率因数
memset(text, 0, sizeof(text));
sprintf(text, "\"PF\":%lf,", Electric.Pf_data1);
strcat(buf, text);
/////*****电能
memset(text, 0, sizeof(text));
sprintf(text, "\"Energy\":%lf", Electric.Energy_data1);
strcat(buf, text);
memset(text, 0, sizeof(text));
strcat(buf, "}");
// UsartPrintf(USART_DEBUG,"\r\n");
return strlen(buf);
}
中国移动OneNet物联网云平台上显示的界面如下所示。
1. void ZigBee_UP_Date(void)
2. {
3. int i = 0,j = 0;
4. unsigned char send_date[100];
5. unsigned char send_temp1[100];///电能数据
6. memset(send_date,0,sizeof(send_date)); //清0
7. memset(send_temp1,0,sizeof(send_temp1));
8. send_temp1[0]= DEVID1; //设备ID
9. send_temp1[1]= 0x03;
10. /////******拷贝电压数据
11. for(j = 0;j < 20;j++) //20位电参数
12. {
13. send_temp1[j+2]= Rx_Buffer1[j+3];
14. }
15. ///////
16. send_date[0] = 0xFC;
17. send_date[1] = 0x21; //数据长度 不包括 0XFC 和长度位 一定要对!!!!
18. send_date[2] = 0x03;send_date[3] = 0x01; //zigbee功能码 0x03 0x01 透传
19. send_date[4] = 0x00;send_date[5] = 0x00; // 协调器短地址
20. for(j = 0;j < 22;j++) //22位zigbee模块参数放到 帧头后面
21. {
22. send_date[j+6]= send_temp1[j];
23. }
24. send_date[28] = renti[0];send_date[29] = dagonglv[0];send_date[30] =yanwu[0];
25. send_date[31] = duandian[0];send_date[32] = huoyan[0];
26. send_date[33] = ShortAdress1[0];send_date[34] = ShortAdress1[1]; //设备自己短地址
27. for(i = 0;i < 35;i++)
28. {
29. while(USART_GetFlagStatus(M6312_USART, USART_FLAG_TC) == RESET); //等待发送完成
30. USART_SendData(M6312_USART,send_date);
31. UsartPrintf(USART1,"%X",send_date);
32. }
33. UsartPrintf(USART1,"\r\n");
34. UsartPrintf(USART1,"ZigBee_buf_Len send successful!\r\n");
35. }
宿舍管理员控制终端的ZigBee当做协调器,对宿舍传来的数据进行解析。其中解包代码如下。
36. void ZigBee_data(void)
37. {
38.
39. if(M6312_WaitRecive()==REV_OK) //说明串口接受完成
40. {
41. if(((m6312[0] == 0x01)&&(m6312[1] == 0x03))==1) //说明是需要的数据
42. {
43. DEV_ID = m6312[0]; //设备ID
44. ////
45. voltage = (unsigned long)(m6312[2]<<24)|(unsigned long)(m6312[3]<<16)|(unsigned long)(m6312[4]<<8)|m6312[5]; //电压数据
46. voltage1 = (float)(voltage*0.0001);
47. ////
48. Current = (unsigned long)(m6312[6]<<24)|(unsigned long)(m6312[7]<<16)|(unsigned long)(m6312[8]<<8)|m6312[9];
49. Current1 = (float)(Current*0.0001);
50. /////
51. POWER = (unsigned long)(m6312[10]<<24)|(unsigned long)(m6312[11]<<16)|(unsigned long)(m6312[12]<<8)|m6312[13];
52. POWER1 = (float)(POWER*0.0001);
53. ////
54. Enery = (unsigned long)(m6312[14]<<24)|(unsigned long)(m6312[15]<<16)|(unsigned long)(m6312[16]<<8)|m6312[17];
55. Enery1 = (float)(Enery*0.0001);
56. ////
57. PF = (unsigned long)(m6312[18]<<24)|(unsigned long)(m6312[19]<<16)|(unsigned long)(m6312[20]<<8)|m6312[21];
58. PF1 = (float)(PF*0.001);
59. ////
60. renti[0] = m6312[22];dagonglv[0] = m6312[23];yanwu[0] = m6312[24];duandian[0] = m6312[25];huoyan[0] = m6312[26];
61.
62. ///设备短地址
63. Short_Adress1[0] = m6312[27];Short_Adress1[1] = m6312[28];
64. }
65. if(((m6312[0] == 0x02)&&(m6312[1] == 0x03))==1) //说明是需要的数据
66. {
67. DEV_ID = m6312[0];
68. ////
69. voltage = (unsigned long)(m6312[2]<<24)|(unsigned long)(m6312[3]<<16)|(unsigned long)(m6312[4]<<8)|m6312[5]; //电压数据
70. voltage2 = (float)(voltage*0.0001);
71. ////
72. Current = (unsigned long)(m6312[6]<<24)|(unsigned long)(m6312[7]<<16)|(unsigned long)(m6312[8]<<8)|m6312[9];
73. Current2 = (float)(Current*0.0001);
74. /////
75. POWER = (unsigned long)(m6312[10]<<24)|(unsigned long)(m6312[11]<<16)|(unsigned long)(m6312[12]<<8)|m6312[13];
76. POWER2 = (float)(POWER*0.0001);
77. ////
78. Enery = (unsigned long)(m6312[14]<<24)|(unsigned long)(m6312[15]<<16)|(unsigned long)(m6312[16]<<8)|m6312[17];
79. Enery2 = (float)(Enery*0.0001);
80. ////
81. PF = (unsigned long)(m6312[18]<<24)|(unsigned long)(m6312[19]<<16)|(unsigned long)(m6312[20]<<8)|m6312[21];
82. PF2 = (float)(PF*0.001);
83. ///////
84. renti1[0] = m6312[22];dagonglv1[0] = m6312[23];yanwu1[0] = m6312[24];duandian1[0] = m6312[25];huoyan1[0] = m6312[26];
85.
86. ///设备短地址
87. Short_Adress2[0] = m6312[27];Short_Adress2[1] = m6312[28];
88. }
89. M6312_Clear();
90. }
91. }
ZigBee工作在终端节点模式和协调器下的主要工作流程图如下图所示
以上就是宿舍终端侧的三大主要模块。但是宿舍终端设备还集成了指纹锁,可以通过按键或者刷指纹的方式对宿舍门进行开关。详解如下。
其指纹接口的硬件接口如下
92. void Compare_FR(void)
93. {
94. uint16_t ID=0; /*初始化ID值*/
95. uint16_t sure;
96.
97. // AS608_INFO("******命令:对比指纹,请按手指******\r\n");
98. OLED_Clear();
99. OLED_ShowString(0,16,"Contrast finger:",16,1);
100. OLED_ShowString(0,32,"Press finger:",8,1);
101. OLED_Refresh();
102. sure=PS_GetImage();
103. if(sure == 0x00)
104. {
105. sure=PS_GenChar(CHAR_BUFFER1); /*生成特征1*/
106. if(sure==0x00)
107. {
108. /*高速搜索指纹库*/
109. sure=PS_HighSpeedSearch(CHAR_BUFFER1,0,PS_MAXNUM,&ID);
110. if(sure==0x00)
111. {
112. // AS608_INFO ("对比指纹成功,指纹ID:%d!!!\r\n\r\n",ID);
113. UsartPrintf(DEBUG_USARTx,"对比指纹成功,指纹ID:%d!!!\r\n\r\n",ID);
114. AS608_Com_Fig_Num = ID;
115. AS608_Com_Error_bit = 0; //检测正确
116. AS608_success_bit = 2;
117.
118. }
119. else
120. {
121. AS608_Com_Error_bit = 1; //检测错误
122. ShowErrMessage(sure);
123. }
124. }
125. else
126. {
127. ShowErrMessage(sure);
128. }
129. }
130. else
131. {
132. ShowErrMessage(sure);
133. }
134.
135. }
当对比指纹成功以后,开门标志置1,此时Stm32驱动电机旋转,门开启。其模块比如蜂鸣器、火焰、烟雾等传感器直接使用单片机驱动或者采集响应的ADC信号,然后根据采集的信号进行报警或者其他操作,由于逻辑比较简单,所以代码不再贴出,只给出程序设计的流程图。
到此,学生宿舍端设备各个功能已经讲解完毕。下面是宿舍管理员控制终端的功能介绍。
3.2 宿舍管理员控制终端
宿舍管理员控制终端的功能主要是:ZigBee数据接收、命令下发、人脸识别。
其中,1、ZigBee数据接收是ZigBee工作在协调器模式,接收宿舍传来的数据,供显示设备显示,这点已经在上一部分ZigBee工作流程中讲到了。2、命令下发是指管理员通过串口屏(带触摸触摸以后可以自定义数据输出)来对宿舍的电源进行开关,以及当摄像头检测到人员离开或者进入宿舍时对宿舍进行断、来电。3、人脸识别后的结果发送给宿舍管理员控制终端,然后宿舍管理员控制终端下发命令。
其中ZigBee数据下发的代码片段如下。
136. void ZigBee_DOWN_Date(void)
137. {
138. int i = 0;
139. unsigned char send_date[100];
140. if(cmd_down_bit == 1)
141. // if(usart1_WaitRecive() == REV_OK)
142. {
143. buf_len = 0;
144. cmd_down_bit = 0;
145. DEV_ID1 = usart1Buf[1]; //设备ID
146. DEV_ID_Cmd = usart1Buf[2]; //命令
147. buf[0] = usart1Buf[0];buf[1] = usart1Buf[1];buf[2] = usart1Buf[2];buf[3] = usart1Buf[3];
148. usart1Buf_Clear();
149. memset(send_date,0,sizeof(send_date)); //清0
150. if(buf[1] == 0x01)
151. {
152. send_date[4] = Short_Adress1[0];send_date[5] = Short_Adress1[1]; // 终端短地址
153. }
154. if(buf[1] == 0x02)
155. {
156. send_date[4] = Short_Adress2[0];send_date[5] = Short_Adress2[1]; // 终端短地址
157. }
158. send_date[0] = 0xFC;
159. send_date[1] = 0x06; //数据长度 不包括 0XFC
160. send_date[2] = 0x03;send_date[3] = 0x01; //zigbee功能码 0x03 0x01
161. send_date[6] = DEV_ID1; //设备ID 1号对应0x01 2号对应0x02
162. send_date[7] = DEV_ID_Cmd; // 命令 0x01开灯 0x02 关灯
163. }
164. }
串口屏使用的是迪文串口屏,带触摸,触摸时候可以自定义数据输出,所以可以在屏幕上点击对宿舍进行来电和通电。其中串口屏数据更新程序如下所示。
165. void Reflash_UI(void)
166. {
167. char Enery_temp[300];
168. memset(Enery_temp,0,sizeof(Enery_temp));
169. if(DEV_ID == 0x01)
170. {
171. SetTextValue(0,16,"已连接"); ///显示电压
172. SetTextValue(0,48,"1"); ///显示电压
173. sprintf(Enery_temp,"%.2f",voltage1);
174. SetTextValue(0,8,Enery_temp); ///显示电压
175. memset(Enery_temp,0,sizeof(Enery_temp));
176. ///
177. sprintf(Enery_temp,"%.4f",Current1);
178. SetTextValue(0,9,Enery_temp); ///显示电压
179. memset(Enery_temp,0,sizeof(Enery_temp));
180. /////
181. sprintf(Enery_temp,"%.3f",POWER1);
182. SetTextValue(0,10,Enery_temp); ///显示电压
183. memset(Enery_temp,0,sizeof(Enery_temp));
184. //////
185. sprintf(Enery_temp,"%.3f",Enery1);
186. SetTextValue(0,11,Enery_temp); ///显示电压
187. memset(Enery_temp,0,sizeof(Enery_temp));
188. ////////
189. sprintf(Enery_temp,"%f",PF1);
190. SetTextValue(0,44,Enery_temp); ///显示电压
191. memset(Enery_temp,0,sizeof(Enery_temp));
192. ////**
193. if(renti[0] == 0x00)
194. {
195. SetTextValue(0,31,"无");
196. }else SetTextValue(0,31,"有");
197. ////**
198. if(dagonglv[0] == 0x00)
199. {
200. SetTextValue(0,40,"无");
201. }else SetTextValue(0,40,"有");
202. ////**
203. if(duandian[0] == 0x00)
204. {
205. SetTextValue(0,36,"无");
206. }else SetTextValue(0,36,"有");
207. ////**
208. if(huoyan[0] == 0x00)
209. {
210. SetTextValue(0,53,"无");
211. }else SetTextValue(0,53,"有");
212. /////****
213. if(yanwu[0] == 0x00)
214. {
215. SetTextValue(0,51,"无");
216. }else SetTextValue(0,51,"有");
217.
218.
219. }
220. if(DEV_ID == 0x02)
221. {
222. SetTextValue(0,64,"已连接"); ///显示电压
223. SetTextValue(0,49,"2"); ///显示电压
224. sprintf(Enery_temp,"%.2f",voltage2);
225. SetTextValue(0,22,Enery_temp); ///显示电压
226. memset(Enery_temp,0,sizeof(Enery_temp));
227. ///
228. sprintf(Enery_temp,"%.4f",Current2);
229. SetTextValue(0,23,Enery_temp); ///显示电压
230. memset(Enery_temp,0,sizeof(Enery_temp));
231. /////
232. sprintf(Enery_temp,"%.3f",POWER2);
233. SetTextValue(0,24,Enery_temp); ///显示电压
234. memset(Enery_temp,0,sizeof(Enery_temp));
235. //////
236. sprintf(Enery_temp,"%.3f",Enery2);
237. SetTextValue(0,25,Enery_temp); ///显示电压
238. memset(Enery_temp,0,sizeof(Enery_temp));
239. ////////
240. sprintf(Enery_temp,"%f",PF2);
241. SetTextValue(0,46,Enery_temp); ///显示电压
242. memset(Enery_temp,0,sizeof(Enery_temp));
243. ////**
244. if(renti1[0] == 0x00)
245. {
246. SetTextValue(0,37,"无");
247. }else SetTextValue(0,37,"有");
248. ////**
249. if(dagonglv1[0] == 0x00)
250. {
251. SetTextValue(0,42,"无");
252. }else SetTextValue(0,42,"有");
253. ////**
254. if(duandian1[0] == 0x00)
255. {
256. SetTextValue(0,38,"无");
257. }else SetTextValue(0,38,"有");
258. ////**
259. if(huoyan1[0] == 0x00)
260. {
261. SetTextValue(0,57,"无");
262. }else SetTextValue(0,57,"有");
263. ///////******
264. if(yanwu1[0] == 0x00)
265. {
266. SetTextValue(0,55,"无");
267. }else SetTextValue(0,55,"有");
268. }
269. DEV_ID = 0;
270. }
串口屏参数显示UI界面如下:
人脸识别使用的是百度云识别方案,因为比较省事,不用在Linux板子上移植机器视觉算法。首先从百度云上下载SDK,下载Python-SDK版本。见地址
https://ai.baidu.com/ai-doc/FACE/ek37c1qiz
把SDK在Linux解包以后就得到目录
272. ├── README.md
273. ├── aip //SDK目录
274. │ ├── __init__.py //导出类
275. │ ├── base.py //aip基类
276. │ ├── http.py //http请求
277. │ └── face.py //人脸识别
278. └── setup.py //setuptools安装
运行以下命令进行安装
279. python setup.py install
SDK安装好以后,就可以编写代码了。其中一些API参数可以参考百度云脸识别文档,见地址
280. https://ai.baidu.com/ai-doc/FACE/ek37c1qiz
281. https://ai.baidu.com/ai-doc/FACE/yk37c1u4t
然后进行在百度云建立一个人脸识别的应用
然后点击应用列表,添加一个应用,我这里已经添加过了,然后点击可视化人脸库新建一个组,点击新建的组。
然后新建组以后,会看到新建用户,这里的用户就是需要对比的照片,一个照片算一张用户,这里的用户名注意不能写成英文,写成数字,英文均可。
新建应用以后就可以在应用列表中看到一个应用,见下图
人脸识别流程部分代码如下,此代码使用Linux开发板进行跑的,使用的是Python语言。如果使用下面提供的代码的话,需要在代码中更改APP_ID、API_KEY、SECRET_KEY这3个参数。
1. import os
2. import sys
3. import re
4. from aip import AipFace
5. import urllib.request
6. import base64
7. import time
8. import serial
9. #百度人脸识别API账号信息
10. APP_ID = '245554564'
11. API_KEY = 'ZM6c6lrOo4554544PYMkK6rGNT'
12. SECRET_KEY ='GtqNyc5lepqI2y44545Y454dtFg6oasokSO0U'
13. client = AipFace(APP_ID, API_KEY, SECRET_KEY)#创建一个客户端用以访问百度云
14. #图像编码方式
15. IMAGE_TYPE='BASE64'
16. #用户组
17. GROUP = '2'
18. ##串口通信
19. ser = serial.Serial('/dev/ttyUSB1',115200)
20. def Send_Message():
21. # ser = serial.Serial('/dev/ttyUSB1',115200)
22. ser.write('Face_discern_successful'.encode())
23.
24.
25. def Send_Message1():
26. # ser = serial.Serial('/dev/ttyUSB1',115200)
27. ser.write('Face_discern_succeassfu'.encode())
28.
29. #照相函数
30. def getimage():
31. os.system("fswebcam -d /dev/video0 -S 30 image1.jpg")
32. time.sleep(5)
33.
34.
35. #对图片的格式进行转换
36. def transimage():
37. f = open('image1.jpg','rb')
38. img = base64.b64encode(f.read())
39. # img = (f.read())
40. return img
41. #上传到百度api进行人脸检测
42. def go_api(image1):
43. result = client.search(str(image1, 'utf-8'), IMAGE_TYPE, GROUP);#在百度云人脸库中寻找有没有匹配的人脸
44. # name = result['result']['user_list'][0]['user_id']#获取名字
45. # score = result['result']['user_list'][0]['score']#获取相似度
46. # print("欢迎%s 相似度%d!" % name %score)
47. if result['error_msg'] != 'SUCCESS':
48. result11 = result['error_msg']
49. print("%s" %result11)
50. if result['error_msg'] == 'SUCCESS':#如果成功了
51. name = result['result']['user_list'][0]['user_id']#获取名字
52. score = result['result']['user_list'][0]['score']#获取相似度
53. if score > 60:#如果相似度大于80
54. if name == '1_Zhang':
55. print("欢迎%s,相似度为:%s !" %(name,score))
56. time.sleep(3)
57. if name == '1_Zhang':
58. print("欢迎%s !" % name)
59. time.sleep(3)
60. if name == "_01quhao":
61. print("欢迎%s !" % name)
62. else:
63. print("对不起,我不认识你!")
64. name = 'Unknow'
65. return 0
66. curren_time = time.asctime(time.localtime(time.time()))#获取当前时间
67.
68. #将人员出入的记录保存到Log.txt中
69. f = open('Log.txt','a')
70. f.write("Person: " + name + " " + "Time:" + str(curren_time)+'\n')
71. f.close()
72. return 1
73. if result['error_msg'] == 'pic not has face':
74. print('检测不到人脸')
75. time.sleep(2)
76. return 0
77. else:
78. #print(name+str(score))
79. return 0
80. #主函数
81. if __name__ == '__main__':
82. while True:
83. print('准备')
84. if True:
85. getimage()#拍照
86. img = transimage()#转换照片格式
87. res = go_api(img)#将转换了格式的图片上传到百度云
88.
89. if(res == 1):#是人脸库中的人
90. print("开门")
91. Send_Message()
92. else:
93. print("关门")
94. Send_Message1()
95. print('稍等三秒进入下一个')
96. time.sleep(2)
人脸识别的程序设计流程如下图所示。人脸结果识别完以后,Linux板子通过串口将识别结果发送给宿舍管理员控制终端控制器,即STM32F7508—DK开发板,然后开发板根据识别结果驱动ZigBee协调器向对应宿舍发送指令。
四、作品源码
由于作品源码上传以后两天了,看还是没审核,所以把视频展示与代码放到一块,整理成百度云连接上传。代码也会当做附件放在帖子下面,由于视频比较大,就不放了。
五、作品功能演示视频
点击查看 >> 演示视频
六、项目总结
经过这次项目学习我学会了如何用简单的方法实现人脸识别,以及使用ZigBee做一个小项目,将物联网与当前社会热点问题结合,使我明白了物联网给生活带来的方便,同时对物联网的发展有一定的思考。目前物联网的发展已经不是当初简单的终端设备+平台,目前IoT和AI技术紧密结合,能干的事越来越多,生活也越来越智能化。由于平时学习和工作忙没有时间发帖,作品是国庆假期期间憋出来的,发帖这方面和论坛其他坛友相比自己工作量有所不足,但是最终的作品来说,自己认为还是很有工作量的。由于时间原因,最终作品并不完美,大多数线都是用杜邦线连的,后续估计有时间会优化一些。这次申请的STM32F7508—DK性能很强大,资料也不少,后面有时间自己也会慢慢用这块板子做一些其他的事情。