概述
前言:
这是大四上学期做的物联网实验,总共4个实验,这是第4个,也是最难的一个,当然大部分程序是我的老师编写的,我只是跟着实验指导书做出来的,希望可以帮到大家。
1. 系统工作原理
温湿度感知节点(Client),实时采集温湿度数据,然后通过WiFi模块,以TCP协议
将采集数据实时无线传输给服务端(Server);服务端将接收到的温湿度数据存于数据库
中;用户终端(User)从服务端获取实时采集和历史数据,用以监测、分析、查询等应
用。
2. 系统 设计
用户应用程序界面如图所示。
服务器界面:
使用串口助手看数据:
如果不写服务器程序和用户应用程序,也可以使用串口助手来观察数据
操作方法如下:
- 打开串口调试工具SSCOM,如下图所示。
- 实验以开发板作为客户端(Client),以电脑作为服务器端(Server)。所以,在SSCOM中,端口号选择TCPServer,服务器IP(本地IP)、端口设置与main函数中的一致。
- 按下SSCOM“侦听”按钮,若系统显示“已连接”,表明开发板已经建立了与服务器端的TCP连接,则可以看到温湿度的实时监测数据,。
终端设备:
主要用到的元器件有:
STM32F103C8T6、ESP8266、DHT11、DS18B20、ST-LINK下载器、方口数据线
3. 程序编写
STM32部分源码:
这部分代码太多了,只给出主函数的代码。
#include "filelib.h"
int main(void)
{
char *sendtxt = (char*)malloc(48);
strcpy(P_data.wifi_ssid,"XIAOCHUN"); //设置连接WiFi名称
strcpy(P_data.wifi_psd,"3118003167"); //设置连接WiFi密码
strcpy(P_data.wifi_ip,"192.168.43.217"); //设置连接服务器IP
strcpy(P_data.wifi_port,"12345"); //设置连接服务器端口
ESP8266_Init (); //初始化ESP8266
DHT11_GPIO_Config();
DS18B20_Init();
macESP8266_CH_ENABLE(); //使能ESP8266
ESP8266_AT_Test(); //检测ESP8266的AT是否启动(若10次测试失败,则结束程序运行)
ESP8266_Net_Mode_Choose(STA); //设置wifi模块为STA模式
//连接wifi
while (!ESP8266_JoinAP(P_data.wifi_ssid, P_data.wifi_psd))
{
//连接wifi失败,重连
}
ESP8266_Enable_MultipleId(DISABLE); //关闭WiFi多连接
//连接到远程服务器
while (!ESP8266_Link_Server(enumTCP, P_data.wifi_ip, P_data.wifi_port, Single_ID_0))
{
//连接服务器失败,重连
}
while (!ESP8266_UnvarnishSend()) ; //开启穿透模式
while(1)
{
Delay_ms(1500); //每隔1500ms获取一次温湿度
//Dev_data.temp = readtemp(); //获取温度
Dev_data.temp =DS18B20_GetTemperture();
sprintf(sendtxt,"%s%.2f%s","温度:",Dev_data.temp,"℃");
ESP8266_SendString ( ENABLE,sendtxt,0, Single_ID_0 ); //发送温度值到服务器
Dev_data.humi = Get_Humi_Value(); //获取湿度
sprintf(sendtxt,"%s%u%s","湿度:",Dev_data.humi,"%RH");
ESP8266_SendString ( ENABLE,sendtxt,0, Single_ID_0 ); //发送温度值到服务器
// ESP8266_SendString ( ENABLE, "Welcome!rn", 0, Single_ID_0 ); //发送湿度值到服务器
}
}
服务器源码:
#define _CRT_SECURE_NO_WARNINGS
#if defined(_WIN32) || defined(_WIN64) //为了支持windows平台上的编译
#include <windows.h>
#endif
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<iostream>
#include<winsock.h>
#include "mysql.h" //该文件在…mysql-8.0.18-winx64include下
#pragma comment(lib,"ws2_32.lib")
using namespace std;
void initialization();
int main() {
//以下是MySQL数据库操作程序
MYSQL mysql, * sock; //声明MySQL的句柄
const char* host = "localhost"; //数据库服务器IP
const char* user = "root"; //连接MySQL的用户名
const char* passwd = "123456"; //连接MySQL的用户密码
const char* db = "iotdatabase"; //连接数据库的名字
unsigned int port = 3306; //这是MySQL的服务器的端口,如果没有修改过的话就是3306
const char* unix_socket = NULL; //unix_socket这是unix下的,在Windows下把它设置为NULL
unsigned long client_flag = 0; //这个参数一般为0
char query_str[200]; //MySQL命令字符串
mysql_init(&mysql); //连接数据库之前必须使用初始化函数进行初始化
//连接MySQL
if ((sock = mysql_real_connect(&mysql, host, user, passwd, db, port, NULL,0 )) == NULL) //unix_socket client_flag
{
cout << "连接mysql失败" << endl;
exit(1); //exit(0);正常的关闭所有程序; exit(1):有错误的关闭所有程序
}
//以下是Socket通信服务端程序
int recv_len = 0; //定义长度变量
int len = 0;
//定义服务端套接字,接受请求套接字
SOCKET s_server;
SOCKET s_accept;
//服务端地址客户端地址
SOCKADDR_IN server_addr;
SOCKADDR_IN accept_addr;
//initialization();
//填充服务端信息
server_addr.sin_family = AF_INET; //协议簇类型:TCP/IP–IPv4
server_addr.sin_addr.S_un.S_addr = inet_addr("192.168.43.217"); //服务器IP 192.168.43.217
server_addr.sin_port = htons(12345); //服务器端口
//初始化套接字
WORD w_req = MAKEWORD(2, 2); //版本号
WSADATA wsadata;
int err;
err = WSAStartup(w_req, &wsadata); //初始化套接字
if (err != 0) {
WSACleanup(); //中止套接字
}
//创建套接字
s_server = socket(AF_INET, SOCK_STREAM, 0); //SOCK_STREAM—TCP流
//SOCK_DGRAM—UDP数据报;SOCK_RAW—原始套接字
if (bind(s_server, (SOCKADDR*)&server_addr, sizeof(SOCKADDR)) == SOCKET_ERROR) {
WSACleanup();
cout << "失败" << endl;
}
else {
cout << "套接字绑定成功!" << endl;
cout << "IP:192.168.43.217" << endl;
cout << "端口:12345" << endl;
}
//设置套接字为监听状态
if (listen(s_server, SOMAXCONN) < 0) {
cout << "设置监听状态失败!" << endl;
WSACleanup();
}
else {
cout << "设置监听状态成功!" << endl;
}
cout << "服务端正在监听连接,请稍候...." << endl;
//接受连接请求
len = sizeof(SOCKADDR);
s_accept = accept(s_server, (SOCKADDR*)&accept_addr, &len);
if (s_accept == SOCKET_ERROR) {
cout << "连接失败!" << endl;
WSACleanup(); //释放DLL资源
return 0;
}
cout << "连接建立,准备接受数据" << endl;
//接收数据
while (1) {
char recv_buf[100] = { "