这个项目是受到B站一个视频启发而做的。Up主他其实是有开源了整套方案的,但是作为一个整天摸鱼的大学生,这种东西肯定还是自己重新实现一遍有意思啦。
参考视频地址:https://www.bilibili.com/video/BV1jL4y1x7gx?share_source=copy_web
既然决定要自己动手做,第一步那得首先确定要用什么硬件。我本身最熟悉的单片机应该是STM32的,使用STM32配合STM32CubeMX程序实现起来也简单。原先我的计划是,pc端的上位机直接通过串口将数据发送到单片机显示。但是现在芯片的价格实在太高了,以前几块钱就能买到的最小系统板都涨了不少,那我也没必要为了那么简单的功能使用显然会资源过剩的单片机了。
最终我选用了esp8266作为控制芯片。当然,既然都选了esp8266了,那数据交换只用串口不用网络就说不过去了。起码也得使用http get或者post。有可能的话最好还要使用mqtt进行通信。
目前项目PC端代码可以在我的Gitee上找到。
获取内存占用代码:
/*内存使用率*/
//windows 内存 使用率
DWORD getWin_MemUsage(void)
{
MEMORYSTATUSEX ms;
ms.dwLength = sizeof(ms);
GlobalMemoryStatusEx(&ms);
//cout << left << setw(17) << "内存占用率:" << setw(3) << ms.dwMemoryLoad << "%" << endl;
return ms.dwMemoryLoad;
}
获取CPU占用率代码:
FILETIME preidleTime;
FILETIME prekernelTime;
FILETIME preuserTime;
FILETIME idleTime;
FILETIME kernelTime;
FILETIME userTime;
int get_CPU_usage_init(void)
{
res = GetSystemTimes(&idleTime, &kernelTime, &userTime);
preidleTime = idleTime;
prekernelTime = kernelTime;
preuserTime = userTime;
return 0;
}
int get_CPU_usage(void)
{
res = GetSystemTimes(&idleTime, &kernelTime, &userTime);
__int64 idle = CompareFileTime(preidleTime, idleTime);
__int64 kernel = CompareFileTime(prekernelTime, kernelTime);
__int64 user = CompareFileTime(preuserTime, userTime);
int cpu = (kernel + user - idle) * 100 / (kernel + user);
//cout << kernel << " " << user << " " << idle << endl;
preidleTime = idleTime;
prekernelTime = kernelTime;
preuserTime = userTime;
return cpu;
}
上位机与单片机通信可选http get或者是mqtt进行。目前已实现通过get来获取。这部分代码参考了网上的资料。但是网上找到的资料有些在我的环境下get失败。另外还有无响应时卡住、长时间运行卡住等小问题。所以进行了一点点的修改优化。
通信代码:
#define IPSTR "192.168.1.112" //服务器IP地址;
#define PORT 80 //服务器端口;
#define BUFSIZE 1024
class httpClient {
std::string host;
std::string path;
std::string post_content;
public:
std::string httpSend(std::string httpHeader);
std::string httpGet(std::string host, std::string path);
std::string httpPost(std::string host, std::string path, std::string post_content);
};
std::string httpClient::httpSend(std::string httpHeader) {
//POST请求方式
std::string ret = ""; // 返回Http Response
// 开始进行socket初始化
WSADATA wData;
::WSAStartup(MAKEWORD(2, 2), &wData);
SOCKET clientSocket = socket(AF_INET, 1, 0);
struct sockaddr_in ServerAddr = { 0 };
ServerAddr.sin_addr.s_addr = inet_addr(IPSTR);
ServerAddr.sin_port = htons(PORT);
ServerAddr.sin_family = AF_INET;
int errNo = connect(clientSocket, (sockaddr*)&ServerAddr, sizeof(ServerAddr));
if (errNo == 0) {
errNo = send(clientSocket, httpHeader.c_str(), httpHeader.length(), 0);//发送头文件
if (errNo > 0) {
std::cout << "发送成功" << std::endl;
}
else {
std::cout << "errNo:" << errNo << std::endl;
// socket环境清理
::WSACleanup();
return ret;
}
// 接收
char bufRecv[3069] = { 0 };
errNo = recv(clientSocket, bufRecv, 3069, 0);
if (errNo > 0) {
ret = bufRecv;// 如果接收成功,则返回接收的数据内容
char* p;
char* delims = { "\n" };
p = strtok(bufRecv, "\n");
int i = 0;
while (p != NULL) {
if (i == 13) {
ret = p;
}
i++;
p = strtok(NULL, delims);
}
// socket环境清理
::WSACleanup();
return ret;
}
else {
std::cout << "errNo:" << errNo << std::endl;
// socket环境清理
::WSACleanup();
return ret;
}
}
else {
errNo = WSAGetLastError();
std::cout << "errNo:" << errNo << std::endl;
// socket环境清理
::WSACleanup();
return ret;
}
}
/** Get 请求 */
std::string httpClient::httpGet(std::string host, std::string path) {
std::string httpHeader;
httpHeader =
"GET " + path + " HTTP/1.1\r\n"
"Host: " + host + "\r\n"
"User-Agent: IE or Chrome\r\n"
"Accept-Type: */*\r\n"
"Connection: Close\r\n\r\n";
return httpSend(httpHeader);
}
/** Post 请求 */
std::string httpClient::httpPost(std::string host, std::string path, std::string post_content) {
std::string httpHeader;
char lenChar[16]; //这个长度根据需要吧
sprintf(lenChar, "%d", (int)post_content.length());
std::string len(lenChar);
httpHeader =
"POST " + path + " HTTP/1.1\r\n"
"Accept-Encoding: gzip, deflate"
"Host: " + host + "\r\n"
"Connection: keep-alive\r\n"
"Content-Type: application/x-www-form-urlencoded\r\n"
"Content-Length: " + len + "\r\n\r\n"
+ post_content;
return httpSend(httpHeader);
}
esp8266是在arduino的平台上开发的,参考代码:
#include <ESP8266WiFi.h>
#include <WiFiClient.h>
#include <ESP8266WebServer.h>
#include <ESP8266mDNS.h>
#include "Ticker.h"
#ifndef STASSID
#define STASSID "wifi_ssid"
#define STAPSK "wifi_密码"
#endif
const char* ssid = STASSID;
const char* password = STAPSK;
int cpu_usage = 0;
int mem_usage = 0;
int cpu_usage_display = 0;
int mem_usage_display = 0;
Ticker displayTicker; //建立一个需要定时调度的对象
ESP8266WebServer server(80);
const int led = LED_BUILTIN;
const String postForms = "<html>\
<head>\
<title>ESP8266 Web Server POST handling</title>\
<style>\
body { background-color: #cccccc; font-family: Arial, Helvetica, Sans-Serif; Color: #000088; }\
</style>\
</head>\
<body>\
<h1>POST plain text to /postplain/</h1><br>\
<form method=\"post\" enctype=\"text/plain\" action=\"/postplain/\">\
<input type=\"text\" name=\'{\"hello\": \"world\", \"trash\": \"\' value=\'\"}\'><br>\
<input type=\"submit\" value=\"Submit\">\
</form>\
<h1>POST form data to /postform/</h1><br>\
<form method=\"post\" enctype=\"application/x-www-form-urlencoded\" action=\"/postform/\">\
<input type=\"text\" name=\"hello\" value=\"world\"><br>\
<input type=\"text\" name=\"sweet\" value=\"summer\"><br>\
<input type=\"text\" name=\"cpu_usage\" value=\"50\"><br>\
<input type=\"text\" name=\"mem_usage\" value=\"60\"><br>\
<input type=\"submit\" value=\"Submit\">\
</form>\
<h1>update device data</h1><br>\
<form method=\"post\" enctype=\"application/x-www-form-urlencoded\" action=\"/device/\">\
<input type=\"text\" name=\"cpu_usage\" value=\"50\"><br>\
<input type=\"text\" name=\"mem_usage\" value=\"60\"><br>\
<input type=\"submit\" value=\"Submit\">\
</form>\
</body>\
</html>";
void tickerHandle() //到时间时需要执行的任务
{
if((cpu_usage*10+cpu_usage_display*9)/10 == cpu_usage_display && cpu_usage_display > (cpu_usage*10))
{
cpu_usage_display--;
}
else if((cpu_usage*10+cpu_usage_display*9)/10 == cpu_usage_display && cpu_usage_display < (cpu_usage*10))
{
cpu_usage_display++;
}
else
{
cpu_usage_display = (cpu_usage*10+cpu_usage_display*9)/10;
}
analogWrite(15, cpu_usage_display*105/100); // D8
}
void handleRoot() {
digitalWrite(led, 1);
server.send(200, "text/html", postForms);
digitalWrite(led, 0);
}
void handlePlain() {
if (server.method() != HTTP_POST) {
digitalWrite(led, 1);
server.send(405, "text/plain", "Method Not Allowed");
digitalWrite(led, 0);
} else {
digitalWrite(led, 1);
server.send(200, "text/plain", "POST body was:\n" + server.arg("plain"));
digitalWrite(led, 0);
}
}
void handleForm() {
if (server.method() != HTTP_POST) {
digitalWrite(led, 1);
server.send(405, "text/plain", "Method Not Allowed");
digitalWrite(led, 0);
} else {
digitalWrite(led, 1);
String message = "POST form was:\n";
for (uint8_t i = 0; i < server.args(); i++) {
message += " " + server.argName(i) + ": " + server.arg(i) + "\n";
}
server.send(200, "text/plain", message);
digitalWrite(led, 0);
}
}
void handleDevice() {
if (server.method() != HTTP_POST) {
digitalWrite(led, 1);
server.send(405, "text/plain", "Method Not Allowed");
digitalWrite(led, 0);
} else {
digitalWrite(led, 1);
String message = "POST form was:\n";
for (uint8_t i = 0; i < server.args(); i++) {
message += " " + server.argName(i) + ": " + server.arg(i) + "\n";
if(server.argName(i) == "cpu_usage")
{
cpu_usage = server.arg(i).toInt();
Serial.print("cpu usage:");
Serial.println(cpu_usage);
}
else if(server.argName(i) == "mem_usage")
{
mem_usage = server.arg(i).toInt();
Serial.print("mem usage:");
Serial.println(mem_usage);
}
}
server.send(200, "text/plain", message);
Serial.println("=====================================================");
digitalWrite(led, 0);
}
}
void handleNotFound() {
digitalWrite(led, 1);
String message = "File Not Found\n\n";
message += "URI: ";
message += server.uri();
message += "\nMethod: ";
message += (server.method() == HTTP_GET) ? "GET" : "POST";
message += "\nArguments: ";
message += server.args();
message += "\n";
for (uint8_t i = 0; i < server.args(); i++) {
message += " " + server.argName(i) + ": " + server.arg(i) + "\n";
}
server.send(404, "text/plain", message);
digitalWrite(led, 0);
}
void setup(void) {
pinMode(led, OUTPUT);
digitalWrite(led, 0);
analogWriteFreq(1000);
analogWriteRange(1100);
pinMode(15, OUTPUT);
analogWrite(15, 0); // D8
Serial.begin(115200);
WiFi.begin(ssid, password);
Serial.println("");
// Wait for connection
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.print("Connected to ");
Serial.println(ssid);
Serial.print("IP address: ");
Serial.println(WiFi.localIP());
if (MDNS.begin("sweet")) {
Serial.println("MDNS responder started");
}
server.on("/", handleRoot);
server.on("/postplain/", handlePlain);
server.on("/postform/", handleForm);
server.on("/device/",handleDevice);
server.onNotFound(handleNotFound);
server.begin();
Serial.println("HTTP server started");
displayTicker.attach(0.1,tickerHandle);
}
void loop(void) {
server.handleClient();
MDNS.update();
}
目前测试正常。
待续。。。