51单片机物联网开发

绪论

硬件工具: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小程序上访问设备信息。

项目整体框架

51单片机物联网开发

一、硬件开发

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

51单片机物联网开发

ESP8266调试

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

AT+RST :初始化
AT+CWMODE=3 :设置兼容模式,可以访问其他WiFi
AT+UART=,8,1,0,0 :设置波特率
AT+CWJAP="","" :设置连接的WiFi名称和密码
AT+CIPSTART="TCP","",
AT+CIPSEND=5 : 用于测试字符长度

C51单片机程序开发

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

//引入库与宏定义
#include 
#include 
#include 
#include 

#define uchar unsigned char
#define uint unsigned int

typedef 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;i0;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 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==' ')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",rn");   
		delay5ms();
		Uart_SendStrData("AT+CIPSEND=");
        Uart_SendStrData(len_sum);
        Uart_SendStrData("rn");
		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

51单片机物联网开发

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

51单片机物联网开发

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

下图为端口通信调试图:

51单片机物联网开发

二、服务器软件开发 

 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;

    @PostConstruct
    public 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;
        }
    }

    @Override
    public 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
    @Resource
    private DataMapper tempMapper_udp_save;
    public static subSocketClient subSocketClient;

    public subSocketClient(ServerSocket serverSocket, Socket socket) {
        this.serverSocket = serverSocket;
        this.socket = socket;
    }

    //初始化通信程序
    @PostConstruct
    public 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";
        // 建立数据库连接,获得连接对象conn
        try {
            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 {
                //不存在则移除该socket
                DeviceCode2SocketMap.remove(deviceCode);
                return SendError;
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return SendError;

    }

    @Override
    public 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 

工具类:

package com.bl.utli;

import com.bl.demo.subSocketClient;

import java.net.Socket;
import java.util.HashMap;

public class SocketParam {
    public static HashMap 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)
    @CrossOrigin
    public List getData() {
        List 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 param);

    List 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 {
    @Autowired
    DataMapper dataMapper;

    public int addTemp(Map param){
        return dataMapper.addTemp(param);
    }

    public List getTemps()
    {
        return dataMapper.getTemps();
    }
}

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




    
        insert into data_info_t(temp,humi,beam,time) values (#{temp},#{humi},#{beam},#{time})
    

    

postman通信测试图
51单片机物联网开发

三、前端页面数据展示

51单片机物联网开发

 51单片机物联网开发

51单片机物联网开发

 51单片机物联网开发

 页面实现




	
		
		
		
		
		后台管理系统
		
		
		
		
		
		
		
		
		
		
		
		
	
	
	
	
		
    $("#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.resultList[i].fire+''
						+''+res.resultList[i].gas+''
						+''+res.resultList[i].time+'';
					$("#table").append('' + tr + '');
				}
			}
		})
	})
})

本文章来源于互联网,如有侵权,请联系删除!原文地址:51单片机物联网开发

相关推荐: 工业物联网未来发展的六大趋势

许多新技术新产品的发展正在塑造 2022 年的工业物联网,从软件和硬件方面的创新到增强人类感官能力的智能穿戴设备,所有这些都有可能通过改进的数据驱动智能影响生产系统和流程。工业物联网正在将传统的线性制造转变为动态的、互联的系统,帮助工厂释放潜力,更高效、更高产…