当前位置: 首页 > article >正文

网络高级项目( 基于webserver的工业数据采集和控制项目)

目录

一、项目要求:

二、演示效果:

设备端:

Modbus用户控制端:

服务器端:

网页端:

三、 项目代码:

Modbus用户控制端代码:

服务器端代码:

网页端代码:

四、B站讲解视频:


一、项目要求:

设备端:有温湿度传感器采集温度和湿度以及LED灯,和BEEP蜂鸣器(使用Modbus slave来模拟);

虚拟机端:通过modbus采集和控制信息的用户控制端和采集数据保存历史纪录的服务器端,利用进程间通信实现连接;

网页端:利用html5写一个网页,显示采集的温湿度信息和能够控制LED灯和BEEP蜂鸣器的开关,通过http协议与服务器连接。


二、演示效果:

设备端:

显示采集的温湿度和led,蜂鸣器的状态(0为关闭,1为开启)

Modbus用户控制端:

每隔两秒采集一次数据并将数据打印至终端

服务器端:

显示通过网页传递过来的指令和用户控制端进行联系,并且存入历史记录中

网页端:

按下温湿度采集按钮,显示采集到的温度和湿度,能够控制LED灯和蜂鸣器的开关,按下历史记录查询按钮可以显示历史记录


三、 项目代码:

Modbus用户控制端代码:

#include <stdio.h>
#include "modbus-tcp.h"
#include "modbus.h"
#include <pthread.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <errno.h>
#include <sys/shm.h>
#include <stdio.h>

union val
{
    int i_val;
    float f_val;
};

typedef struct dev
{
    long op;
    char dev_name[32]; // 设备名称
    union val v;       // 存放具体数据
} DEV;

struct data
{
    char buf[32];
};

struct data *p = NULL;
key_t key, key1;
int msgid;
int shmid;

void *kongzhi(void *arg)
{
    modbus_t *ctx = (modbus_t *)arg;
    DEV dev;
    while (1)
    {
        msgrcv(msgid, &dev, sizeof(dev) - sizeof(dev.op), 100, 0);
        printf("%s %d\n", dev.dev_name, dev.v.i_val);
        if (strcmp(dev.dev_name, "led") == 0)
        {
            modbus_write_bit(ctx, 0, dev.v.i_val);
            printf("led灯%s\n", dev.v.i_val ? "开启" : "关闭");
        }
        else if (strcmp(dev.dev_name, "beep") == 0)
        {
            modbus_write_bit(ctx, 1, dev.v.i_val);
            printf("蜂鸣器%s\n", dev.v.i_val ? "开启" : "关闭");
        }
    }
}

int main(int argc, char const *argv[])
{
    if (argc != 2)
    {
        printf("用法 <ip>\n");
        return -1;
    }
    modbus_t *ctx;
    ctx = modbus_new_tcp(argv[1], 502);
    if (ctx == NULL)
    {
        perror("modbus new tcp失败");
        return -1;
    }

    // 设置从机ID
    modbus_set_slave(ctx, 1);

    // 建立连接
    if (modbus_connect(ctx) < 0)
    {
        printf("modbus connect失败\n");
        modbus_free(ctx);
        return -1;
    }
    printf("connect ok\n");
    key = ftok("./test", 'a');
    if (key < 0)
    {
        perror("创建key值失败");
        return -1;
    }

    shmid = shmget(key, 128, IPC_CREAT | IPC_EXCL | 0666);
    if (shmid < 0)
    {
        if (errno == EEXIST)
        {
            shmid = shmget(key, 128, 0666);
        }
        else
        {
            perror("创建共享内存失败");
            return -1;
        }
    }

    p = (struct data *)shmat(shmid, NULL, 0);
    if (p == (struct data *)-1)
    {
        perror("映射共享内存失败");
        return -1;
    }

    key1 = ftok("./test1", 'a');
    if (key1 < 0)
    {
        perror("创建key值失败");
        return -1;
    }
    msgid = msgget(key1, IPC_CREAT | IPC_EXCL | 0666);
    if (msgid <= 0)
    {
        if (errno == EEXIST)
        {
            msgid = msgget(key1, 0666);
        }
        else
        {
            perror("创建消息队列失败");
            return -1;
        }
    }

    pthread_t kongzhitid;
    // 创建线程
    if (pthread_create(&kongzhitid, NULL, kongzhi, ctx) != 0)
    {
        perror("创建控制线程失败");
        modbus_free(ctx);
        modbus_close(ctx);
        return -1;
    }
    uint16_t dest[4];
    DEV tem, hum;

    while (1)
    {
        int mrr = modbus_read_registers(ctx, 0, 4, dest);
        if (mrr <= 0)
        {
            perror("读保持寄存器的值失败");
            exit(0);
        }
        else
        {
            strcpy(tem.dev_name, "温度");
            tem.v.f_val = modbus_get_float_dcba(dest);
            strcpy(hum.dev_name, "温度");
            hum.v.f_val = modbus_get_float_dcba(dest + 2);
            sprintf(p->buf, "温度:%.2f℃ 湿度:%.2f\%\n", tem.v.f_val, hum.v.f_val);
            printf("%s",p->buf);
        }
        sleep(2); // 每2秒采集一次
    }
    modbus_free(ctx);
    modbus_close(ctx);
    return 0;
}

服务器端代码:

#include <sys/types.h>
#include <sys/socket.h>
#include "custom_handle.h"

struct data *p = NULL;
DEV dev;
extern int len;
sqlite3 *db;

#define KB 1024
#define HTML_SIZE (64 * KB)

// 普通的文本回复需要增加html头部
#define HTML_HEAD "Content-Type: text/html\r\n" \
                  "Connection: close\r\n"
/**
 * @brief 处理自定义请求,在这里添加进程通信
 * @param input
 * @return
 */
int parse_and_process(int sock, const char *query_string, const char *input)
{
    // 打开数据库
    if (sqlite3_open("./history.db", &db) < 0)
    {
        printf("打开数据库失败: %s\n", sqlite3_errmsg(db));
        return -1;
    }

    key_t key, key1;
    int shmid, msgid;
    key = ftok("./test", 'a');
    if (key < 0)
    {
        perror("创建key值失败");
        return -1;
    }
    shmid = shmget(key, 128, IPC_CREAT | IPC_EXCL | 0666);
    if (shmid < 0)
    {
        if (errno == EEXIST)
        {
            shmid = shmget(key, 128, 0666);
        }
        else
        {
            perror("创建共享内存失败");
            return -1;
        }
    }
    p = (struct data *)shmat(shmid, NULL, 0);
    if (p == (struct data *)-1)
    {
        perror("映射共享内存失败");
        return -1;
    }

    key1 = ftok("./test1", 'a');
    if (key1 < 0)
    {
        perror("创建key值失败");
        return -1;
    }
    msgid = msgget(key1, IPC_CREAT | IPC_EXCL | 0666);
    if (msgid <= 0)
    {
        if (errno == EEXIST)
        {
            msgid = msgget(key1, 0666);
        }
        else
        {
            perror("创建消息队列失败");
            return -1;
        }
    }
    char sql[1024];
    char *errmsg = NULL;
    char **result = NULL;
    int rows, columns;
    time_t t;
    struct tm *timeinfo;
    char date[100];
    time(&t);
    timeinfo = localtime(&t);
    snprintf(date, sizeof(date), "%d-%d-%d %d:%d:%d", timeinfo->tm_year + 1900, timeinfo->tm_mon + 1, timeinfo->tm_mday, timeinfo->tm_hour, timeinfo->tm_min, timeinfo->tm_sec);

    if (strstr(input, "get"))
    {
        send(sock, p->buf, strlen(p->buf), 0);
        snprintf(sql, sizeof(sql), "insert into history values ('%s','%s');", date, p->buf);
        if (sqlite3_exec(db, sql, NULL, NULL, &errmsg) != 0)
        {
            printf("放入历史记录失败: %s", errmsg);
            return -1;
        }
        memset(sql, 0, sizeof(sql));
        memset(p->buf, 0, sizeof(p->buf));
    }
    else if (strstr(input, "history"))
    {
        memset(p->buf, 0, sizeof(p->buf));
        snprintf(sql, sizeof(sql), "select * from history;");
        int rc = sqlite3_get_table(db, sql, &result, &rows, &columns, &errmsg);
        if (rc != 0)
        {
            printf("查询历史记录失败: %s", errmsg);
        }
        else
        {
            if (rows > 0)
            {
                for (int i = 1; i <= rows; ++i)
                {
                    for (int j = 0; j < columns; ++j)
                    {
                        strcat(p->buf, result[i * columns + j]);
                        strcat(p->buf, " ");
                    }
                    strcat(p->buf, "\n");
                }
            }
        }
        send(sock, p->buf, strlen(p->buf), 0);
        memset(sql, 0, sizeof(sql));
        memset(p->buf, 0, sizeof(p->buf));
    }
    else
    {
        memset(dev.dev_name, 0, sizeof(dev.dev_name));
        // for (int i = 0; i < len - 2; i++)
        // {
        //     dev.dev_name[i] = input[i];
        // }
        // char i = input[len - 1];
        // dev.v.i_val = i - '0';
        // printf("%s %d\n", dev.dev_name, dev.v.i_val);
        char i;
        sscanf(input, "%s %s", dev.dev_name, &i);
        dev.v.i_val = i - '0';
        printf("%s %d\n", dev.dev_name, dev.v.i_val);
        dev.op = 100;
        msgsnd(msgid, &dev, sizeof(dev) - sizeof(dev.op), 0);
        if (strcmp(dev.dev_name, "led") == 0)
        {
            sprintf(p->buf, "led灯%s\n", dev.v.i_val ? "开启" : "关闭");
            // send(sock, p->buf, strlen(p->buf), 0);
            snprintf(sql, sizeof(sql), "insert into history values ('%s','%s');", date, p->buf);
            if (sqlite3_exec(db, sql, NULL, NULL, &errmsg) != 0)
            {
                printf("放入历史记录失败: %s", errmsg);
                return -1;
            }
            printf("%s\n", sql);
            memset(sql, 0, sizeof(sql));
        }
        else if (strcmp(dev.dev_name, "beep") == 0)
        {
            sprintf(p->buf, "蜂鸣器%s\n", dev.v.i_val ? "开启" : "关闭");
            // send(sock, p->buf, strlen(p->buf), 0);
            snprintf(sql, sizeof(sql), "insert into history values ('%s','%s');", date, p->buf);
            if (sqlite3_exec(db, sql, NULL, NULL, &errmsg) != 0)
            {
                printf("放入历史记录失败: %s", errmsg);
                return -1;
            }
            printf("%s\n", sql);
            memset(sql, 0, sizeof(sql));
        }
        else
        {
            sprintf(p->buf, "输入错误,请重新输入\n");
            // send(sock, p->buf, strlen(p->buf), 0);
        }
    }

    return 0;
}

网页端代码:

<!DOCTYPE html>
<html lang="en">

<head>
	<meta charset="UTF-8">
	<meta name="viewport" content="width=device-width, initial-scale=1.0">
	<title>工业信息采集系统</title>
	<style>
		body {
			font-family: Arial, sans-serif;
			margin: 20px;
		}

		.container {
			max-width: 800px;
			margin: 0 auto;
		}

		.section {
			margin-bottom: 20px;
		}

		.button {
			padding: 10px 20px;
			font-size: 16px;
			cursor: pointer;
			background-color: #007bff;
			color: white;
			border: none;
			border-radius: 5px;
		}

		.button:disabled {
			background-color: #6c757d;
			cursor: not-allowed;
		}

		.status {
			margin-top: 10px;
			padding: 10px;
			background-color: #f8f9fa;
			border: 1px solid #ced4da;
			border-radius: 5px;
		}
	</style>
	<script>
		//     //设置定时器,定时5秒调用一次函数refreshPage
		//     setInterval(refreshPage, 5000);
		//     function refreshPage() {
		//         //TODO
		//     }
		function sendledon() {
			var buf = "led 1";
			var xhr = new XMLHttpRequest();
			var url = "";
			xhr.open("post", url, true);
			xhr.send(buf);
		}
		function sendledoff() {
			var buf = "led 0";
			var xhr = new XMLHttpRequest();
			var url = "";
			xhr.open("post", url, true);
			xhr.send(buf);
		}
		function sendbeepon() {
			var buf1 = "beep 1";
			var xhr = new XMLHttpRequest();
			var url = "";
			xhr.open("post", url, true);
			xhr.send(buf1);
		}
		function sendbeepoff() {
			var buf1 = "beep 0";
			var xhr = new XMLHttpRequest();
			var url = "";
			xhr.open("post", url, true);
			xhr.send(buf1);
		}
		function sendcaiji() {
			var buf = "get";
			var xhr = new XMLHttpRequest();
			var url = "";
			xhr.open("post", url, true);
			xhr.send(buf);
			xhr.onreadystatechange = function () {
				var response = xhr.responseText;
				document.getElementById('temhum').innerText = response;
			};
		}
		function sendhistory() {
			var buf = "history";
			var xhr = new XMLHttpRequest();
			var url = "";
			xhr.open("post", url, true);
			xhr.send(buf);
			xhr.onreadystatechange = function () {
				var response = xhr.responseText;
				document.getElementById('lishi').innerText = response;
			};
		}
	</script>


</head>

<body>
	<div class="container">
		<h1>工业信息采集系统</h1>

		<!-- 温湿度采集 -->
		<div class="section">
			<input class="button" type="button" name="caiji" value="温湿度采集" onclick="sendcaiji()" />
			<div class="status" id="wenshidu">
				<p><span id="temhum"></p>
			</div>
		</div>

		<!-- LED灯控制 -->
		<div class="section">
			<h2>LED灯控制</h2>
			<label for="ledon">
				开<input type="radio" name="led" id="ledon" value="led 1" onclick="sendledon()" />
			</label>
			<label for="ledoff">
				关<input type="radio" name="led" id="ledoff" checked="checked" value="led 0"
					onclick="sendledoff()" /><br />
			</label>
		</div>

		<!-- 蜂鸣器控制 -->
		<div class="section">
			<h2>蜂鸣器控制</h2>
			<label for="ledon">
				开<input type="radio" name="beep" id="beepon" value="beep 1" onclick="sendbeepon()" />
			</label>
			<label for="ledoff">
				关<input type="radio" name="beep" id="beepoff" checked="checked" value="beep 0"
					onclick="sendbeepoff()" /><br />
			</label>
		</div>

		<!-- 历史记录查询 -->
		<div class="section">
			<input type="button" class="button" name="history" value="历史记录查询" onclick="sendhistory()" />
			<div class="status" id="history-records">
				<p><strong>历史记录:</strong></p>
				<ul id="lishi"></ul>
			</div>
		</div>
	</div>
</body>

</html>

四、B站讲解视频:


http://www.kler.cn/a/307734.html

相关文章:

  • Dubbo 3.2 源码导读
  • Flask和Python实现在线课堂学生疲劳检测系统设计与实现
  • 【postman】怎么通过curl看请求报什么错
  • 《鸿蒙生态:开发者的机遇与挑战》
  • Java 包装类
  • 机器学习、深度学习面试知识点汇总
  • Https AK--(ssl 安全感满满)
  • 【LIO】FAST-LIO论文详解
  • 如何在C++中使用mupdf操作pdf文件(一)
  • 微信小程序页面制作——婚礼邀请函(含代码)
  • 深入探讨ES6高级特性与实际应用
  • 注册登录案列
  • 加密
  • 空间解析几何 1 :空间中直线、圆、椭圆的方程表示
  • 感知器神经网络
  • 【Qt】Qt C++ Widget中嵌入qml
  • Python酷库之旅-第三方库Pandas(120)
  • type和interface区别
  • redis 十大应用场景
  • 《Effective Debugging:软件和系统调试的66个有效方法》读书笔记-Part2
  • 828华为云征文|华为Flexus云服务器搭建Cloudreve私人网盘
  • 优化Web性能:Varnish中精准识别并缓存移动与桌面请求
  • html+css网页设计 旅游网站首页1个页面
  • WPF入门教学一 WPF简介
  • 【C++前后缀分解 动态规划】2100. 适合野炊的日子|1702
  • ROS笔记3.路径规划1