【ESP8266】AP热点模式+服务器模式 实现手机显示串口信息(绘图)

最近在准备电赛,训练的时候做到了2021年的A题。

这个题目硬件部分要求相对简单,但其中有一项要求让我头疼了很久。

就是在手机上显示测量装置测得并显示的输入信号THD值、一个周期波形、基波与谐波的归一化幅值。

在网上搜索了很久,也看了过去的获奖队伍,都没有提到相关的技术。

开始打算通过一些物联网应用实现,但在使用的过程中发现他们大多没有提供相关功能或者需要收费。其次,有些接口并不能实现实时接收数据。

最重要的是,需要联网。这在电赛是不允许的。

于是想到自己不久前的一个帖子。使用ESP8266+舵机,实现宿舍无线开关

这里同理,可以使用esp8266做网络客户端, 通过手机浏览器查看。

首先是HTML代码部分。(比较长,所以单独列出来)

<!DOCTYPE html>
<html>
<head>
	<title>测试使用</title>
	<meta http-equiv="refresh" content="1" charset="utf-8">
    <!--为了保证数据更新,此页面每一秒刷新一次--->
	<style type="text/css">
		body
		{
			display: inline-flex;
		}	
		.label1{
			width: 210px;
			text-align:center;
			margin-top: 70px;
			margin-left: 30px;
		}
		.label3{
			font-size: 24px;
			line-height: 60px;
			text-align:left;
		}
	</style>
	
</head>
<body style="height:100% ;">
	<div class="label1">
		<div class="label3"><span>THD: &nbsp;</span><text id="THD"></text></div>
		<div class="label3"><span>一次谐波: &nbsp;</span><text id="one"></text></div>
		<div class="label3"><span>二次谐波: &nbsp;</span><text id="two"></text></div>
		<div class="label3"><span>三次谐波: &nbsp;</span><text id="three"></text></div>
		<div class="label3"><span>四次谐波: &nbsp;</span><text id="four"></text></div>
		<div class="label3"><span>五次谐波: &nbsp;</span><text id="five"></text></div>
	</div>

	<div>
	<h2 style="text-align:center;">折线图</h2>
	<canvas id="mc" width="700" height="400" style="border:3px solid rgb(0, 0, 0)"></canvas>
	<script type="text/javascript">
		var canvas=document.getElementById('mc');
		var ctx=canvas.getContext('2d');
		ctx.lineWidth = 3;
		ctx.beginPath();
		
		var THD,one,two,three,four,five,x,y;

        x= [30,40.32,50.65,60.97,71.29,81.61,91.94,102.26,112.58,122.9,
			133.23,143.55,153.87,164.19,174.52,184.84,195.16,205.48,215.81,226.13,
			236.45,246.77,257.1,267.42,277.74,288.06,298.39,308.71,319.03,329.35,339.68,
			350,360.32,370.65,380.97,391.29,401.61,411.94,422.26,432.58,442.9,453.23,463.55,
			473.87,484.19,494.52,504.84,515.16,525.48,535.81,546.13,556.45,566.77,577.1,587.42,
			597.74,608.06,618.39,628.71,639.03,649.35,659.68,670]; 
		y = [200,182.03,164.24,146.80,129.90,113.70,98.36,84.03,70.87,58.99,48.52,
			39.57,32.22,26.55,22.61,20.44,20.06,21.49,24.69,29.65,36.31,44.61,54.46,65.76,
			78.41,92.27,107.2,123.07,139.7,156.93,174.6,192.51,210.51,228.4,246,263.15,279.66,
			295.38,310.14,323.81,336.23,347.3,356.9,364.92,371.3,375.97,378.88,380 ,379.32,
			376.86,372.62,366.66,359.03,349.82,339.11,327.01,313.64,299.13,283.63,267.3,250.3,
			232.79,214.96];
		THD = 1;
        one = 0;
		two = 0;
		three = 0;
	    four = 0;
		five = 0;// 默认数据是0,画sin图像
        
		document.getElementById("THD").innerHTML=THD;   //id指向对应数据,实现数据修改
		document.getElementById("one").innerHTML=one;
		document.getElementById("two").innerHTML=two;
		document.getElementById("three").innerHTML=three;
		document.getElementById("four").innerHTML=four;
		document.getElementById("five").innerHTML=five;

		ctx.moveTo(x[0],y[0]);
		for(var i=2;i<x.length;i++)
		{
			ctx.lineTo(x[i],y[i]);
		}
		ctx.stroke();
	</script>
	</div>

</body>
</html>
		

这个代码是可以直接运行的,默认画sin图像

虽然比较简陋,但要求的功能都有。

接下来便是ESP8266代码部分了。

上一次的作品尽管不需要网络,但仍然依赖于路由器 ,有些麻烦。由于上次是物联网项目,连接路由器无可厚非,但对于比赛,我觉得还是有些冗余了。

所以,这次使用ESP8266的AP热点模式,既可以做热点也可以做网络服务器。手机只需连接ESP8266建立的热点,并在浏览器中输入地址即可。

#include<stdio.h>
#include <ESP8266WiFi.h>        // 本程序使用 ESP8266WiFi库
#include <ESP8266WiFiMulti.h>   //  ESP8266WiFiMulti库
#include <ESP8266WebServer.h>   //  ESP8266WebServer库
 
ESP8266WiFiMulti wifiMulti;     // 建立ESP8266WiFiMulti对象,对象名称是 'wifiMulti'
ESP8266WebServer esp8266_server(80);// 建立网络服务器对象,该对象用于响应HTTP请求。监听端口(80)

String html_code1 = " <!DOCTYPE html><html><head><meta http-equiv=\"refresh\" content=\"1\"></head>   <style type=\"text/css\"> body{display: inline-flex;} .label1{width: 210px; text-align:center; margin-top: 70px; margin-left: 22px;} .label3{font-size: 24px; line-height: 60px; text-align:left;} </style> <body style=\"height:100% ;\">   <div class=\"label1\"> <div class=\"label3\"><span>THD: &nbsp;</span><text id=\"THD\"></text></div> <div class=\"label3\"><span>一次谐波: &nbsp;</span><text id=\"one\"></text></div> <div class=\"label3\"><span>二次谐波: &nbsp;</span><text id=\"two\"></text></div> <div class=\"label3\"><span>三次谐波: &nbsp;</span><text id=\"three\"></text></div> <div class=\"label3\"><span>四次谐波: &nbsp;</span><text id=\"four\"></text></div> <div class=\"label3\"><span>五次谐波: &nbsp;</span><text id=\"five\"></text></div> </div> <div><h2 style=\"text-align:center;\">波形图</h2>  <canvas id=\"mc\" width=\"700\" height=\"400\" style=\"border:2px solid black\"></canvas><script type=\"text/javascript\"> var canvas=document.getElementById(\'mc\'); var ctx=canvas.getContext(\'2d\');ctx.beginPath();ctx.lineWidth = 3; var THD = 0;var one,two,three,four,five,x,y;";
String html_code3 = " document.getElementById(\"THD\").innerHTML=THD; document.getElementById(\"one\").innerHTML=one; document.getElementById(\"two\").innerHTML=two; document.getElementById(\"three\").innerHTML=three; document.getElementById(\"four\").innerHTML=four; document.getElementById(\"five\").innerHTML=five; ctx.moveTo(x[0],y[0]); for(var i=1;i<x.length;i++){ctx.lineTo(x[i],y[i]);}ctx.stroke();</script></div></body></html> ";
//默认图像,正弦函数

String html_code2 = \
    " x = [30,40.32,50.65,60.97,71.29,81.61,91.94,102.26,112.58,122.9,\
    133.23,143.55,153.87,164.19,174.52,184.84,195.16,205.48,215.81,226.13,\
    236.45,246.77,257.1,267.42,277.74,288.06,298.39,308.71,319.03,329.35,339.68,\
    350,360.32,370.65,380.97,391.29,401.61,411.94,422.26,432.58,442.9,453.23,463.55,\
    473.87,484.19,494.52,504.84,515.16,525.48,535.81,546.13,556.45,566.77,577.1,587.42,\
    597.74,608.06,618.39,628.71,639.03,649.35,659.68,670]; \
      y = [200,182.03,164.24,146.80,129.90,113.70,98.36,84.03,70.87,58.99,48.52,\
    39.57,32.22,26.55,22.61,20.44,20.06,21.49,24.69,29.65,36.31,44.61,54.46,65.76,\
    78.41,92.27,107.2,123.07,139.7,156.93,174.6,192.51,210.51,228.4,246,263.15,279.66,\
    295.38,310.14,323.81,336.23,347.3,356.9,364.92,371.3,375.97,378.88,380 ,379.32,\
    376.86,372.62,366.66,359.03,349.82,339.11,327.01,313.64,299.13,283.63,267.3,250.3,\
    232.79,214.96];\       
      THD = 0;\
      one = 1;\ 
      two = 0;\
      three = 0;\
      four = 0;\
      five = 0; ";   //正弦坐标值;
    

void setup() {
  Serial.begin(9600);
  WiFi.mode(WIFI_AP);  //设置Wi-Fi为AP模式
  IPAddress softLocal(192,168,1,1);   //设置内网WIFI IP地址
  IPAddress softGateway(192,168,1,1);  //设置网关
  IPAddress softSubnet(255,255,255,0);
  WiFi.softAPConfig(softLocal, softGateway, softSubnet);
  String apName = ((String)ESP.getChipId());  
  const char *softAPName = apName.c_str();
  
  String WiFi_name = "your_wifi_name";
  String pasword = "your_pasword";
  WiFi.softAP(WiFi_name, pasword);      // 创建wifi  名称 +密码 adminadmin
 
  IPAddress myIP = WiFi.softAPIP();  // 输出创建的WIFI IP地址
  Serial.println("");
  Serial.println("AP热点模式 ");
  Serial.print("网关IP: ");     
  Serial.println(myIP);
  Serial.print("WiFi 名称: ");  
  Serial.println(WiFi_name);
  Serial.print("WiFi 密码: ");  
  Serial.println(pasword);  


  esp8266_server.begin();                           // 启动网站服务
  esp8266_server.on("/", HTTP_GET, handleRoot);     // 设置服务器根目录即'/'的函数'handleRoot'
  esp8266_server.onNotFound(handleNotFound);        // 设置处理404情况的函数'handleNotFound'
 
  Serial.println("HTTP esp8266_server started");//  告知用户ESP8266网络服务功能已经启动
}
 
void loop() {
  
  if(Serial.available()>0)
  {
      InformationGet();    
  }

  // put your main code here, to run repeatedly:
  esp8266_server.handleClient();  
  
}

/*串口数据接收*/
void InformationGet(){
  html_code2 = "";
  while (Serial.available())//时刻读取硬件串口数据
  {
    html_code2 = Serial.readStringUntil('\n');//从串口缓存区读取字符到一个字符串型变量,直至读完或遇到某终止字符。
    Serial.println("information recieved!");
  }
  while (Serial.read() >= 0){}//清除串口缓存
}
 
void handleRoot() {      
  String html_code = html_code1 + html_code2 + html_code3;
  
  esp8266_server.send(200, "text/html;charset=utf-8", html_code);
}


// 设置处理404情况的函数'handleNotFound'
void handleNotFound()
{
    esp8266_server.send(404, "text/plain", "404: Not found"); // 发送 HTTP 状态 404 (未找到页面) 并向浏览器发送文字 "404: Not found"
}

这个实现的本质就是通过ESP8266获取串口信息对HTML代码修改。

串口信息需要以特定格式输入,如下

x = [30,40.32,50.65];    //x坐标
y = [200,182.03,164.24];   //y坐标   两坐标数量要相等。否则绘图失败
THD = 0.3456; 
one = 1;  
two = 0.12;
three = 0.45; 
four = 0.44; 
five = 0.89;     //其他参数   分号不可忽略

//   数据输入顺序无要求。未输入的保持默认值0(x,y除外)

坐标适应性变换

mid = (max(y)+min(y))/2;
temp = mid-y;
y = temp/max(temp)*180;
y = y + 200;
temp = x - min(x);
x = temp/max(temp)*640+30;

坐标适应性变换是因为浏览器窗口不会跟随图像变化。题目要求显示一个周期。

此外,数组在js里是弱类型,操作起来十分不方便。

所以直接让队友在单片机里处理好再传输了。

不知道有没有大神有更好的方法?

  • 1
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
以下是一个简单的 ESP8266 IDF 使用 AP STA 模式的代码示例: ``` #include <stdio.h> #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "esp_wifi.h" #include "esp_event_loop.h" #include "esp_log.h" #define WIFI_SSID "my_wifi_ssid" #define WIFI_PASS "my_wifi_password" static const char *TAG = "wifi station"; static void wifi_event_handler(void* arg, esp_event_base_t event_base, int32_t event_id, void* event_data) { if (event_id == WIFI_EVENT_STA_START) { esp_wifi_connect(); } else if (event_id == WIFI_EVENT_STA_DISCONNECTED) { esp_wifi_connect(); ESP_LOGI(TAG, "retry to connect to the AP"); } } void wifi_init_sta(void) { wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT(); esp_wifi_init(&cfg); esp_event_handler_instance_t instance_any_id; esp_event_handler_instance_t instance_got_ip; esp_event_handler_instance_register(WIFI_EVENT, ESP_EVENT_ANY_ID, &wifi_event_handler, NULL, &instance_any_id); esp_event_handler_instance_register(IP_EVENT, IP_EVENT_STA_GOT_IP, &wifi_event_handler, NULL, &instance_got_ip); wifi_config_t wifi_config = { .sta = { .ssid = WIFI_SSID, .password = WIFI_PASS, }, }; esp_wifi_set_mode(WIFI_MODE_STA); esp_wifi_set_config(ESP_IF_WIFI_STA, &wifi_config); esp_wifi_start(); ESP_LOGI(TAG, "wifi_init_sta finished."); ESP_LOGI(TAG, "connect to ap SSID:%s password:%s", WIFI_SSID, WIFI_PASS); } void wifi_init_softap(void) { wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT(); esp_wifi_init(&cfg); wifi_config_t wifi_config = { .ap = { .ssid = "my_ap_ssid", .ssid_len = 0, .password = "my_ap_password", .max_connection = 4, .authmode = WIFI_AUTH_WPA_WPA2_PSK, }, }; esp_wifi_set_mode(WIFI_MODE_AP); esp_wifi_set_config(ESP_IF_WIFI_AP, &wifi_config); esp_wifi_start(); ESP_LOGI(TAG, "wifi_init_softap finished."); ESP_LOGI(TAG, "ssid:%s password:%s", "my_ap_ssid", "my_ap_password"); } void app_main() { ESP_ERROR_CHECK(esp_netif_init()); ESP_ERROR_CHECK(esp_event_loop_create_default()); wifi_init_softap(); wifi_init_sta(); } ``` 这个示例代码中,我们使用了 ESP8266 IDF 的 Wi-Fi 库来实现 AP STA 模式。在这个模式下,ESP8266 既可以作为一个 Wi-Fi 接入点(AP),也可以作为一个 Wi-Fi 客户端(STA)连接到其他 Wi-Fi 接入点。在这个示例中,我们首先初始化了一个 Wi-Fi 接入点,然后初始化了一个 Wi-Fi 客户端,连接到了一个指定的 Wi-Fi 接入点。在连接过程中,我们还注册了一些 Wi-Fi 事件处理程序,以便在连接状态发生变化时进行处理。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值