课程设计|物联网实验-温湿度实时监测系统

前言: 这是大四上学期做的物联网实验,总共4个实验,这是第4个,也是最难的一个,当然大部分程序是我的老师编写的,我只是跟着实验指导书做出来的,希望可以帮到大家。
1. 系统工作原理 温湿度感知节点(Client),实时采集温湿度数据,然后通过WiFi模块,以TCP协议
将采集数据实时无线传输给服务端(Server);服务端将接收到的温湿度数据存于数据库
中;用户终端(User)从服务端获取实时采集和历史数据,用以监测、分析、查询等应
用。
2. 系统 设计 用户应用程序界面如图所示。
课程设计|物联网实验-温湿度实时监测系统
文章图片

服务器界面:
课程设计|物联网实验-温湿度实时监测系统
文章图片

使用串口助手看数据:
如果不写服务器程序和用户应用程序,也可以使用串口助手来观察数据
操作方法如下:

  1. 打开串口调试工具SSCOM,如下图所示。
  2. 实验以开发板作为客户端(Client),以电脑作为服务器端(Server)。所以,在SSCOM中,端口号选择TCPServer,服务器IP(本地IP)、端口设置与main函数中的一致。
  3. 按下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!\r\n", 0, Single_ID_0 ); //发送湿度值到服务器 } }

服务器源码:
#define _CRT_SECURE_NO_WARNINGS#if defined(_WIN32) || defined(_WIN64)//为了支持windows平台上的编译 #include #endif#include #include #include #include #include #include "mysql.h"//该文件在…\mysql-8.0.18-winx64\include下#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_socketclient_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] = { "\0" }; //定义接受缓冲区,并赋初值Null recv_len = recv(s_accept, recv_buf, 100, 0); //接收数据长度 if (recv_len < 0) {cout << "接受失败!" << endl; break; } else {//获取温湿度数据 数据格式:温度数据 + 湿度数据 # char* p1 = NULL; char* p2 = NULL; char* p3 = NULL; //分割字符串安全函数,这个函数将剩余的字符串存储在buf变量中,而不是静态变量中,从而保证了安全性。 //char *strtok_s( char *strToken, const char *strDelimit, char **buf); string tempData = https://www.it610.com/article/strtok_s(recv_buf,"+", &p2); string humiData = https://www.it610.com/article/strtok_s(p2,"#", &p3); //获取采集时间 char str[50]; SYSTEMTIME st; //系统时间变量 GetLocalTime(&st); //获得系统时间 sprintf(str, "%u-%u-%u %u:%u:%u",st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond); string datetimeDA = str; //将采集时间转换为字符串 //拼接MYSQL查询命令字符串 string sql = "insert into acquisitiondata(tempData,humiData,datetimeDA) values ('" + tempData + "','" + humiData + "','" + datetimeDA + "')"; strcpy_s(query_str, sql.c_str()); //将采集的温湿度插入MySQL数据表acquisitiondata mysql_real_query(&mysql, query_str, strlen(query_str)); //执行由query_str指向的SQL查询 cout << "将采集的温湿度插入MySQL数据表acquisitiondata" << endl; } } //关闭服务端套接字 closesocket(s_server); closesocket(s_accept); //释放DLL资源 WSACleanup(); return 0; }void initialization() { //初始化套接字库 WORD w_req = MAKEWORD(2, 2); //版本号 WSADATA wsadata; int err; err = WSAStartup(w_req, &wsadata); if (err != 0) {cout << "初始化套接字库失败!" << endl; } else {cout << "初始化套接字库成功!" << endl; } //检测版本号 if (LOBYTE(wsadata.wVersion) != 2 || HIBYTE(wsadata.wHighVersion) != 2) {cout << "套接字库版本号不符!" << endl; WSACleanup(); } else {cout << "套接字库版本正确!" << endl; } }

【课程设计|物联网实验-温湿度实时监测系统】用户程序源码:
using System.Windows; using MySql.Data.MySqlClient; using System.Data; using System.Linq; using System.Threading; namespace UserApp {/// /// MainWindow.xaml 的交互逻辑 /// public partial class MainWindow : Window {public MainWindow() {InitializeComponent(); //窗体界面定义初始化 string connectionString = "server=localhost; port=3306; database=iotdatabase; charset=utf8; user id=root; password=123456; pooling=false; "; //MySQL数据库连接字符串 MySqlConnection conn = new MySqlConnection(connectionString); //连接MySQL数据库 conn.Open(); //打开连接 DataTable dt = new DataTable(); //定义数据表 string sqlstring = "SELECT * from acquisitiondata where numRecord = (SELECT max(numRecord)FROM acquisitiondata)"; //查询实时数据命令字符串 MySqlCommand cmd = new MySqlCommand //定义MySQLCommand对象 {Connection = conn, CommandText = sqlstring, CommandType = CommandType.Text }; SynchronizationContext _syncContext = SynchronizationContext.Current; Thread LogThread = new Thread(new ThreadStart(DoService)); //定义线程 LogThread.IsBackground = true; //设置线程为后台线程 LogThread.Start(); //开启线程void DoService() {while (true) {MySqlDataAdapter da = new MySqlDataAdapter(cmd); //获取实时数据 da.Fill(dt); //将数据填充到数据表dtDataRow dr_last = dt.AsEnumerable().Last(); _syncContext.Post(SetTextBox1, dr_last[1].ToString()); //通过线程更新txBoxTemp _syncContext.Post(SetTextBox2, dr_last[2].ToString()); //通过线程更新txBoxHumi _syncContext.Post(SetTextBox3, dr_last[3].ToString()); //通过线程更新txBoxTime Thread.Sleep(1000); } } void SetTextBox1(object text) {txBoxTemp.Text = text.ToString(); //更新txBoxTemp } void SetTextBox2(object text) {txBoxHumi.Text = text.ToString(); //更新txBoxHumi } void SetTextBox3(object text) {txBoxTime.Text = text.ToString(); //更新txBoxTime } } private void Button_Click(object sender, RoutedEventArgs e) {//查询按钮 string connectionString = "server=localhost; port=3306; database=iotdatabase; charset=utf8; user id = root; password = 123456; pooling = false; "; MySqlConnection conn = new MySqlConnection(connectionString); //连接MySQL数据库 conn.Open(); //打开连接 DataTable dt = new DataTable(); //定义数据表 string sqlstring = "SELECT * FROM acquisitiondata; "; //查询所有记录命令字符串 MySqlCommand cmd = new MySqlCommand(); //定义MySQLCommand对象 cmd.Connection = conn; cmd.CommandText = sqlstring; cmd.CommandType = CommandType.Text; MySqlDataAdapter da = new MySqlDataAdapter(cmd); da.Fill(dt); //将数据填充到数据表dt dataGridViewTH.ItemsSource = dt.DefaultView; //dataGridViewTH绑定数据表dt conn.Close(); //关闭数据库连接 } private void BtnClear_Click_1(object sender, RoutedEventArgs e) {//清空按钮 string connectionString = "server=localhost; port=3306; database=iotdatabase; charset=utf8; user id = root; password = 123456; pooling = false; "; MySqlConnection conn = new MySqlConnection(connectionString); //连接MySQL数据库 conn.Open(); //打开连接 DataTable dt = new DataTable(); //定义数据表 string sqlstring = "TRUNCATE acquisitiondata; "; //TRUNCATE TABLE 删除表中的所有行,而不记录单个行删除操作 MySqlCommand cmd = new MySqlCommand(); //定义MySQLCommand对象 cmd.Connection = conn; cmd.CommandText = sqlstring; cmd.CommandType = CommandType.Text; MySqlDataAdapter da = new MySqlDataAdapter(cmd); da.Fill(dt); //将数据填充到数据表dt dataGridViewTH.ItemsSource = dt.DefaultView; //dataGridViewTH绑定数据表dt conn.Close(); //关闭数据库连接 } private void txBoxTime_TextChanged(object sender, System.Windows.Controls.TextChangedEventArgs e) {//采集时间框 } private void TextBox_TextChanged(object sender, System.Windows.Controls.TextChangedEventArgs e) {//温度数据框 } private void txBoxHumi_TextChanged(object sender, System.Windows.Controls.TextChangedEventArgs e) {//湿度数据款框 } } }

    推荐阅读