绪论

硬件工具:STC89C52RC芯片、51单片机开发板、ESP8266通信模块、TTL转USB、各类传感器

软件工具:Keil开发环境,STC-ISP烧录工具,IDEA专业版,Postman,WebStorm,vx小程序开发工具,sscom串口助手,Socket-Tools,Tomcat8,JDK1.8,Navicat,Android Studio

开发环境:Java8、SpringBoot+MyBatis、MySQL、C51、阿里云、JavaScript、JQuery、Ajax、Windows操作系统、Chrome浏览器,Android操作系统

开发描述:基于ESP8266通信模块,通过51单片机采集环境传感数据并实现自动控制,通过AT指令将采集数据打包json格式发送目标服务器,云端部署jar包并建立数据库,将接收的数据解析并保存到设备数据表中,基于Ajax与Restful接口实现前后端分离,实现用户登录注册、设备管理、数据查询功能,并支持在Android和vx小程序上访问设备信息。

项目整体框架

一、硬件开发

本案例通过检测MQ-5可燃气体传感器、DHT数字温湿度传感器、火焰传感器这三个传感器感知的环境数据,进而通过逻辑判断通过I/O口输出到继电器、蜂鸣器和LED报警灯。通过ESP8266-01s模块通过WIFI接入云服务器,将采集的数据实时发送到指定端口,且51单片机根据传感器采集的各种火灾安全参数进行判断,如果出现异常情况则单片机启动接入的控制元器件进行自动控制,控制报警灯、蜂鸣器和风扇进行工作,硬件整体框架如下

ESP8266调试

我们使用sscom调试助手进行调试。首先需要一个TTL转USB工具插上ESP8266模块连接PCcom口,打开调试助手检测到设备,然后可以向8266发送指令,指令集如下:

AT+RST :初始化
AT+CWMODE=3 :设置兼容模式,可以访问其他WiFi
AT+UART=<波特率>,8,1,0,0 :设置波特率
AT+CWJAP="<SSID>","<PWD>" :设置连接的WiFi名称和密码
AT+CIPSTART="TCP","<IP地址>",<端口号>
AT+CIPSEND=5 : 用于测试字符长度
<下面输入要发送的字符串>

C51单片机程序开发

使用Keil编写,打开工具,引入STC系列的MCU

//引入库与宏定义
#include <reg52.h>
#include <intrins.h>
#include <assert.h>
#include <stdlib.h>#define uchar unsigned char
#define uint unsigned inttypedef unsigned char u8;
typedef unsigned int u16;
unsigned char strlen(unsigned char *str);
unsigned char flag;sbit Data=P0^6;
sbit Gas_DOUT = P0^4;
sbit Fire_DOUT = P0^3;
sbit beep=P0^2;
sbit LED = P0^1;
sbit relay = P0^5;bit uart_busy = 0;
uchar temp_dat[9];
uchar tempture[2];
uchar string_data1[80];
uchar string_data2[10];
char gas;
char fire;
//设置发送数据
uchar string_send[12];
uint i;
uint count;
void relay_fun();
uchar len_a;
uchar len_b;
uchar len_c;
uchar len_sum;void LED_Alarm()
{u8 i;for(i=10;i>0;i--){LED=0;beep=0;delay_u16(10);LED=1;beep=1;delay_u16(10);}
}
//设置频率
void delay_u16(u16 i)
{while(i--);
}
//控制继电器风扇函数
void relay_fun(){relay = ~relay;LED_Alarm();relay = ~relay;
}void beep_led_alarm(){beep = 0; for(i=0;i<5000;i++){beep=~beep;delay_u16(100);}
}void DHT11_delay_us(uchar n)
{while(--n);
}void DHT11_delay_ms(uint z)
{uint i,j;for(i=z;i>0;i--)for(j=110;j>0;j--);
}void DHT11_start()
{Data=1;DHT11_delay_us(2);Data=0;DHT11_delay_ms(20);   Data=1;DHT11_delay_us(30);
}uchar DHT11_rec_byte()
{uchar i,dat=0;for(i=0;i<8;i++)   {          while(!Data);   DHT11_delay_us(8);     dat<<=1;           if(Data==1)   dat+=1;while(Data);   }  return dat;
}
//DHT11AD转换函数
void DHT11_receive()
{uchar R_H,R_L,T_H,T_L,RH,RL,TH,TL,revise; DHT11_start();if(Data==0){while(Data==0);     DHT11_delay_us(40);  R_H=DHT11_rec_byte();    R_L=DHT11_rec_byte();    T_H=DHT11_rec_byte();     T_L=DHT11_rec_byte();    revise=DHT11_rec_byte(); DHT11_delay_us(25);    if((R_H+R_L+T_H+T_L)==revise)      {RH=R_H;RL=R_L;TH=T_H;TL=T_L;} if(TH > 24){LED_Alarm();LED = 0;beep=0;}temp_dat[0]='0'+(TH/10);temp_dat[1]='0'+(TH%10);}
}void delay5ms(){unsigned char a,b;for(b=201;b>0;b--)for(a=247;a>0;a--);
}void Init_uart(void) {  TMOD = TMOD | 0x20;    SCON = SCON | 0x50;    TH1 = 0xFd;        TL1 = TH1;  TR1 = 1;              EA =1;                ES =1;
}void Uart_SendByteData(unsigned char msg){while(uart_busy); SBUF=msg;        uart_busy = 1;
}void Uart_SendStrData(unsigned char *msg){while(*msg){Uart_SendByteData(*msg++);}
}//取字符串长度
unsigned char strlen(unsigned char *str)
{unsigned char len=0;while(1){                             if(*str=='\0')break;//拷贝完成了.len++;str++;}return len;
}void main(){count = 0;beep=1;LED=1;Init_uart();len_a=0;len_b=0;len_sum=0;while(1){count++;DHT11_receive();delay5ms();delay5ms();for(i=0;i<2;i++){tempture[i]=temp_dat[i];}if(Gas_DOUT == 0){gas='1';LED_Alarm();LED = 0;beep=0;}else{gas='0';}if(Fire_DOUT == 0){fire='1';LED_Alarm();LED = 0;beep=0;}else{fire='0';}for(i=0;i<2;i++){string_send[i]=tempture[i];}string_send[2]='t';string_send[3]=fire;string_send[4]='g';string_send[5]=gas;string_send[6]='f';string_data1[]="{\"type\":\"02\",\"deviceCode\":\"Device\",\"deviceData\":\"";string_data2[]="\"}";len_a=strlen(string_data1);leb_b=strlen(string_data2);len_c=strlen(string_send);len_sum=len_a+len_b+len_c;Uart_SendStrData("AT+CIPSTART=\"TCP\",\"<ip>\",<port>\r\n");   delay5ms();Uart_SendStrData("AT+CIPSEND=");Uart_SendStrData(len_sum);Uart_SendStrData("\r\n");delay5ms();      Uart_SendStrData(string_data1);Uart_SendStrData(string_send);Uart_SendStrData(string_data2);delay1_relay(2);}
}void UART_Interrupt(void) interrupt 4 {unsigned char temp;if(RI){temp = SBUF;RI = 0;if(temp == 1){flag = 1;}}if(TI){TI = 0;uart_busy = 0;}
}

调试通信

ESP8266上的TX和RX一定要和单片机上的RX与TX交叉连接,                                                        8266-TX连接51-RX,8266-RX连接51-TX

以下为单片机串口调试图:

使用Socket-Tools,在云服务器上创建TCPServer指定端口号,开启单片机连接WiFi

下图为端口通信调试图:

二、服务器软件开发

TCP接收服务开发

创建socket通信端口以多线程方式等待监听端口

package com.bl.demo;import javax.annotation.PostConstruct;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;import static com.bl.utli.SocketParam.*;public class TCPServer extends Thread {ServerSocket serverSocket = null;public static TCPServer tcpServer;@PostConstructpublic void init(){tcpServer = this;tcpServer.start();}public String socketSendData(String deviceCode,String sendData){//不为空时subSocketClient temp = DeviceCode2SocketMap.get(deviceCode);if(null!=temp){return temp.sendSocketData(sendData,deviceCode);}else{return SendError;}}@Overridepublic void run() {try {serverSocket = new ServerSocket(PortNum);System.out.println("PortNum: "+PortNum);} catch (IOException e) {System.out.println("the port cannot open.");}while(true){try {System.out.println("wait. .. ...");//使用accept()是阻塞方法Socket socketTemp = serverSocket.accept();new subSocketClient(this.serverSocket,socketTemp).start();//为每个连接都创建一个线程客户端} catch (IOException e) {System.out.println("happening");}}}
}

使用JDBC对MySQL进行操作, 在run()方法中解析数据并存储到数据库中

package com.bl.demo;import com.alibaba.fastjson.JSONObject;
import com.bl.Data.Data;
import com.bl.Data.DataMapper;
import com.bl.Data.DataService;
import com.bl.utli.SocketParam;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.text.SimpleDateFormat;
import java.util.Calendar;import static com.bl.utli.SocketParam.*;public class subSocketClient extends Thread {private ServerSocket serverSocket;private Socket socket;@Autowired@Resourceprivate DataMapper tempMapper_udp_save;public static subSocketClient subSocketClient;public subSocketClient(ServerSocket serverSocket, Socket socket) {this.serverSocket = serverSocket;this.socket = socket;}//初始化通信程序@PostConstructpublic void init(){subSocketClient = this;subSocketClient.tempMapper_udp_save = this.tempMapper_udp_save;}private static final String DRIVER = "com.mysql.cj.jdbc.Driver";public void addTemp(String temp, String fire, String gas, String time) {String url = "jdbc:mysql://localhost:3306/fire?serverTimezone=UTC&allowMultiQueries=true";// 数据库用户名String user = "root";// 数据库密码String password = "123456";// 建立数据库连接,获得连接对象conntry {Connection conn = DriverManager.getConnection(url, user, password);Class.forName("com.mysql.jdbc.Driver");String sql = "insert into data_info_t (temp,fire,gas,time) values(?,?,?,?)";PreparedStatement ps = conn.prepareStatement(sql);ps.setString(1, temp);ps.setString(2, fire);ps.setString(3, gas);ps.setString(4, time);// 执行sql语句ps.executeUpdate();System.out.println("SQL插入完毕!");// 关闭数据库连接对象conn.close();} catch (Exception e) {e.printStackTrace();}}String temp = "";String fire = "";String gas = "";String time = "";String str1 = "";String str2 = "";String str3 = "";public String sendSocketData(String sendData, String deviceCode) {try {BufferedReader br = null;PrintWriter pw = null;br = new BufferedReader(new InputStreamReader(System.in));pw = new PrintWriter(socket.getOutputStream(), true);//查看socket是否存在if (!socket.isClosed()) {pw.println(sendData);pw.flush();return SendSuccess;} else {//不存在则移除该socketDeviceCode2SocketMap.remove(deviceCode);return SendError;}} catch (IOException e) {e.printStackTrace();}return SendError;}@Overridepublic void run() {try {//获取输入流InputStream inputStream = socket.getInputStream();BufferedReader br = new BufferedReader(new InputStreamReader(inputStream));byte[] buf = new byte[1024];//接收数据int line = 0;while ((line = inputStream.read(buf)) != -1) {String param = new String(buf, 0, line);//转成json格式JSONObject jsonObject = JSONObject.parseObject(param);//获取type类型,如果是02则自动注册设备String type = jsonObject.getString("type");if (type.equals(TypeUpdateData)) {//获取设备编号String deviceCode = jsonObject.getString("deviceCode");System.out.println(deviceCode);//获取传感数据String deviceData = jsonObject.getString("deviceData");System.out.println(deviceData);//字符串解析str1 = deviceData;String[] strArr1 = StringUtils.split(str1, "t");for (int i = 0; i < strArr1.length; i++) {temp = strArr1[0];str2 = strArr1[1];}String[] strArr2 = StringUtils.split(str2, "f");for (int i = 0; i < strArr2.length; i++) {fire = strArr2[0];str3 = strArr2[1];}String[] strArr3 = StringUtils.split(str3, "g");for (int i = 0; i < strArr3.length; i++) {gas = strArr3[0];}Calendar calendar = Calendar.getInstance();SimpleDateFormat sd = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");time = sd.format(calendar.getTime());System.out.println("温度: " + temp);System.out.println("湿度: " + fire);System.out.println("燃气: " + gas);System.out.println("时间: " + time);addTemp(temp, fire, gas, time);}}Thread.sleep(10);} catch (Exception e) {e.printStackTrace();}}
}

工具类:

package com.bl.utli;import com.bl.demo.subSocketClient;import java.net.Socket;
import java.util.HashMap;public class SocketParam {public static HashMap<String, subSocketClient> DeviceCode2SocketMap = new HashMap<>();public static int PortNum = 7880;public static String TypeRegister = "01";public static String TypeUpdateData = "02";public static String SendSuccess = "OK";public static String SendError = "ERROR";
}

创建restful端口,调用获取设备数据方法将设备传感数据返回,访问方法为POST

    @RequestMapping(value = "/getData", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)@CrossOriginpublic List<Data> getData() {List<Data> temps = dataService.getTemps();return temps;}

创建数据服务接口,用于获取和添加传感器数据

package com.bl.Data;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;
import java.util.Map;@Mapper
public interface DataMapper {int addTemp(Map<String,Object> param);List<Data> getTemps();}
package com.bl.Data;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.List;
import java.util.Map;
@Service
public class DataService {@AutowiredDataMapper dataMapper;public int addTemp(Map<String, Object> param){return dataMapper.addTemp(param);}public List<com.bl.Data.Data> getTemps(){return dataMapper.getTemps();}
}

编写xml文件,设备数据插入与查询,查询排序按时间递减

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.bl.Data.DataMapper"><insert id="addTemp" parameterType="map">insert into data_info_t(temp,humi,beam,time) values (#{temp},#{humi},#{beam},#{time})</insert><select id="getTemps" resultType="com.bl.Data.Data">select * from data_info_t ORDER BY time DESC LIMIT 100</select>
</mapper>

postman通信测试图

三、前端页面数据展示

页面实现

<!DOCTYPE html>
<html><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge,Chrome=1"><meta name="renderer" content="webkit"><meta name="viewport" content="width=device-width, initial-scale=1"><title>后台管理系统</title><link rel="shortcut icon" href="images/favicon.ico"/><link rel="bookmark" href="images/favicon.ico"/><link rel="stylesheet" type="text/css" href="css/base.css"><link rel="stylesheet" type="text/css" href="fonts/iconfont.css"><script type="text/javascript" src="framework/jquery-1.11.3.min.js" ></script><script type="text/javascript" src="js/base.js"></script><link rel="stylesheet" type="text/css" href="layui/css/layui.css"><script type="text/javascript" src="layui/layui.js"></script><script src="framework/cframe.js"></script><link rel="stylesheet" type="text/css" href="css/frameStyle.css"><script type="text/javascript" src="framework/frame.js" ></script></head><body><div class="frameMenu"><div class="logo"><img src="data:images/logo.png"/><div class="logoText"><h1>室内火灾监控平台</h1></div></div><div class="menu"><div class="hoverBox"></div><ul><li><a class="menuFA" href="javascript:void(0)"><i class="iconfont icon-liuliangyunpingtaitubiao03 left" onmouseenter="getLeftTips(this, '用户管理')" onmouseleave="layer.closeAll('tips')"></i><font>用户管理</font><i class="iconfont icon-dajiantouyou right"></i></a><dl><dt><a href="javascript:void(0)" onclick="menuCAClick('tgls/user/user_add.html',this, 'page10022')">添加用户</a></dt><dt><a href="javascript:void(0)" onclick="menuCAClick('tgls/user/user_list.html',this, 'page10023')">用户列表</a></dt><dt><a href="javascript:void(0)" onclick="menuCAClick('tgls/user/modify.html',this, 'page10024')">修改信息</a></dt></dl></li><li><a class="menuFA" href="javascript:void(0)"><i class="iconfont icon-yunying left" onmouseenter="getLeftTips(this, '设备信息')" onmouseleave="layer.closeAll('tips')"></i><font>设备信息</font><i class="iconfont icon-dajiantouyou right"></i></a><dl><dt><a href="javascript:void(0)" onclick="menuCAClick('tgls/view/view_add.html',this, 'page10027')">添加设备</a></dt><dt><a href="javascript:void(0)" onclick="menuCAClick('tgls/view/view_list.html',this, 'page10028')">设备数据</a></dt></dl></li></ul></div></div><div class="main"><div class="frameTop"><div class="shrinkBut"><div class="hoverBox"></div><ul><li><a href="javascript:void(0)" onclick="menuShrink(this)" onmouseenter="getTips(this, '收缩菜单')" onmouseleave="layer.closeAll('tips')"><i class="iconfont icon-caidan-shousuo"></i></a></li><li><a href="javascript:void(0)" onclick="frameRefresh()" onmouseenter="getTips(this, '刷新')" onmouseleave="layer.closeAll('tips')"><i class="iconfont icon-htmal5icon23"></i></a></li></ul></div><div class="topMenu"><div class="hoverBox"></div><ul><li><a href="login1.html" onmouseenter="getTips(this, '退出系统')" onmouseleave="layer.closeAll('tips')"><i class="iconfont icon-084tuichu"></i></a></li></ul></div></div><div class="frameMain"><div class="title" id="frameMainTitle"><i class="iconfont icon-shuangzuojiantou- leftbut" onclick="pageShow('l')"></i><div class="mainPageBox"><div class="mainPage"><span class="active" onclick="pageSwitch(this)"><div class="hoverBox"></div><i class="iconfont icon-shouye"></i></span></div></div><i class="iconfont icon-shuangyoujiantou- rightbut" onclick="pageShow('r')"></i></div><div class="con"><div class="mainPageCon"><iframe class="mainIframe" src="tgls/user/user_list.html" scrolling="yes"></iframe></div></div></div></div></body></html>
    $("#search").click(function () {var name=$("#input").val();$.ajax({async:true,type: "POST",url: "http://47.102.42.105:8456/Device/getData",dataType: "json",data: JSON.stringify({"name":name}),contentType: "application/json",success: function (res) {console.log(res);for(var i=0; i<res.msg.length; i++){console.log(res.msg[i]);tr = '<td id="temp">'+res.resultList[i].temp+'</td>'+'<td id="fire">' +res.resultList[i].fire+'</td>'+'<td id="gas">'+res.resultList[i].gas+'</td>'+'<td id="time">'+res.resultList[i].time+'</td>';$("#table").append('<tr id="current" style="height: 30px; align-content: center">' + tr + '</tr>');}}})})
})

51单片机物联网开发相关推荐

  1. 《51单片机应用开发从入门到精通》——2.2 跑马灯实例

    本节书摘来自异步社区<51单片机应用开发从入门到精通>一书中的第2章,第2.2节,作者 张华杰,更多章节内容可以访问云栖社区"异步社区"公众号查看. 2.2 跑马灯实例 ...

  2. 《51单片机应用开发从入门到精通》——2.6 中断控制功能的作用

    本节书摘来自异步社区<51单片机应用开发从入门到精通>一书中的第2章,第2.6节,作者 张华杰,更多章节内容可以访问云栖社区"异步社区"公众号查看. 2.6 中断控制功 ...

  3. 《51单片机应用开发范例大全(第3版)》——第1章 单片机C语言开发基础

    本节书摘来异步社区<51单片机应用开发范例大全(第3版)>一书中的第1章,作者:张杰 , 宋戈 , 黄鹤松 , 员玉良,更多章节内容可以访问云栖社区"异步社区"公众号查 ...

  4. Mac版下实现51单片机进行开发的环境搭建

    目录 前言 简单介绍一下51单片机吧 一.安装homebrew 二.内核编译器 sdcc 安装 三.安装CH341驱动 四.烧录程序stcgal的安装 1.python3下载安装并配置环境 2.验证是 ...

  5. 51单片机程序开发入门知识

    51单片机在我的理解上来说,就是遵循51指令集工作的芯片.他就像一台超微型的电脑,里面有内存.硬盘.CPU等基本配备. 而他所谓的CPU使用的就是51指令集,他的硬盘就是内置的Flash,他的内存也是 ...

  6. c51汇编语言典型例子详解,51单片机典型开发实例大全.pdf

    51单片机典型开发实例大全 提供电子技术最新最实用设计方案 --单片机 C51 编程规范 typedef unsigned char INT8U; // 无符号 8 位整型变量 // typedef ...

  7. 《51单片机应用开发从入门到精通》——1.1 单片机开发流程

    本节书摘来异步社区<51单片机应用开发从入门到精通>一书中的第1章,第1.1节,作者:张华杰 ,更多章节内容可以访问云栖社区"异步社区"公众号查看 1.1 单片机开发流 ...

  8. 51单片机应用开发25例—基于Proteus仿真(电路图+程序)

    51单片机应用开发25例-基于Proteus仿真(电路图+程序) 分享的51单片机应用开发25例-基于Proteus仿真非常全面,里面仿真工程文件和源程序都有. 目录: 应用实例1  呼吸灯\ 应用实 ...

  9. 51单片机仿真开发环境构建实验

    51单片机仿真开发环境构建实验目录 实验目的 一.实验步骤 Step1:之前Debug,USE里面没有Proteus VSM Monitor Driver Step2:把VDM51.dll复制到Pro ...

最新文章

  1. mysql 数据索引使用_mysql数据库正确建立索引及使用
  2. HDFS文件详情查看案例
  3. [BJDCTF2020]EzPHP 1
  4. 推荐php 8新特性比较好的两个网站
  5. SGU 160.Magic Multiplying Machine
  6. css之hover改变子元素和其他元素样式
  7. 云漫圈 | 腾讯面试,我竟然输给了final关键字
  8. 【网络流】 HDU 4309 Seikimatsu Occult Tonneru 状压枚举边
  9. JavaScript选择器
  10. UVALive5910 UVA1641 POJ4022 ASCII Area【水题+输入输出】
  11. 贡献一个新浪的幻灯片(javascript)
  12. mongodb执行sql脚本文件
  13. OpenCV 头像训练与识别
  14. C语言判断第几天(最简版)
  15. 关于AI输电线路在线监测多目4G摄像头低功耗解决方案
  16. keilC51编译常见错误和警告说明
  17. 散点图的相关性与显著性---MATLAB
  18. CAP与ACID原则
  19. 记录一个被自己蠢到的事——解决Potplay等播放器播放视频异常打不开故障
  20. 详解Discuz插件开发之自定义页面嵌入点

热门文章

  1. Ubuntu 18.04 Mellanox ConnectX 网络适配器驱动安装
  2. 数据挖掘的十大经典算法
  3. WPF学习之X名称空间详解
  4. 海量微博数据舆情热点挖掘项目难点总结
  5. 蓝色经典钢琴-Cinesamples Piano In Blue v2.3b Kontakt
  6. Git之拉取指定tag版本/切换指定tag代码
  7. 苹果 谷歌 微软 三国混战 附地图详解
  8. i5 9400f参数 i5 9400f性能怎么样
  9. 使用expression design制作silverlight LOGO那种烟雾效果教程(翻译)
  10. android 仿支付宝动画,自定义view之仿支付宝动画