【目标实现】
瑞萨RA8D1LVGL/LWIP开发板获取家里的环境信息,实现lvgl、网络监测。
【瑞萨RA8D1LVGL/LWIP评测】基于STCC4的环境监测系统-电子产品世界论坛
在这一篇里,我实现了lvgl的监测。这一篇在其监测的基础之上添加lwip,并添加tcp服务器。
【硬件】
1、CPKCOR-RA8D1B核心板
2、拓展板(CPKEXP-EKRA8X1)
3、STCC4二氧化碳环境监测模组
4、路由器 & 网线
【硬件连接】
核心板上的RA8D1已经集成了以太网 MAC 控制器,完整的底层硬件链路还需要以太网PHY、隔离变压器、RJ45接口。CPKEXP-EKRA8x1 扩展板提供了这部分外部硬件,我们只需要连接好相应的跳线帽即可,如图:

【网络配置】
1、我们需要导入CPKEXP-EKRA8X1的PIN的配置,可以从CPKEXP-EKRA8X1的例程中导入。
2、新建一个LWIP的freertos任务

在这个任务中添加Lwip system FreeRTOS port,一个Lwip HTTP Server。
3、打开Enable Backward Compatibility【注:这个一定要打开,要不在lwip tcpip 一直会报错】

4、把freertos 的Total Heap Size修改为81920【注:太小了会出现某些任务启动不了】

5、Tread配置如下:

6、在tcp_ip的配置中Mem size修改为40960

7、Internal memory pools配置参数如下:

8、Threading配置如下:

9、NETIF中打开LwIP netif status callback、LwIP netif link callback、LwIP netif remove callback 、LwIP num netif client data。

10、打开LwIP support custom pbuf:

11、添加网络并配置如下:

最后配置网络如下图所示:

【代码实现】
1、添加tcp_echo_server_thread.c。
#include <lwip_thread.h>
#include "common_utils.h"
#include "lwip/init.h"
#include "lwip/tcpip.h"
#include "lwip/tcp.h"
#include "lwip/timeouts.h"
#include "lwip/init.h"
#include "lwip/ip4.h"
#include <lwip/sockets.h>
#include <stdio.h> // For snprintf, sscanf
#include <string.h> // For strstr, strncmp, strlen
#define LOCAL_PORT 80 // Changed to standard HTTP port
#define RECV_BUF_SIZE (512) // Increased buffer size to accommodate the full HTML page
#define SEND_BUF_SIZE (4096) // Size for temporary buffers like headers or small responses
// --- External Global Variables for Sensor Data ---
extern uint16_t co2_concentration_raw;
extern uint8_t sensor_status_raw;
extern float hum, temp;
// --- End External Variables ---
// The HTML content from sensor_data.html embedded as a C string
const char* const HTML_PAGE =
"<!DOCTYPE html>\n"
"<html>\n"
"<head>\n"
" <title>Environmental Monitoring Station</title>\n"
" <style>\n"
" body { font-family: Arial, sans-serif; margin: 40px; background-color: #f0f0f0; }\n"
" h1 { color: #333; }\n"
" table { border-collapse: collapse; width: 50%; margin-top: 20px; }\n"
" th, td { border: 1px solid #ddd; padding: 12px; text-align: left; }\n"
" th { background-color: #4CAF50; color: white; }\n"
" tr:nth-child(even) { background-color: #f2f2f2; }\n"
" input[type=text] { padding: 10px; font-size: 16px; }\n"
" button { padding: 10px 20px; font-size: 16px; cursor: pointer; }\n"
" #statusMessage { margin-top: 20px; color: #d32f2f; font-weight: bold; }\n"
" </style>\n"
"</head>\n"
"<body>\n"
"\n"
" <h1>Environmental Monitoring Station</h1>\n"
" <label for=\"arduinoIP\">Enter Arduino IP Address:</label>\n"
" <input type=\"text\" id=\"arduinoIP\" placeholder=\"e.g., 192.168.3.12\">\n"
" <button onclick=\"connectToArduino()\">Connect</button>\n"
"\n"
" <table id='dataTable' border='1'>\n"
" <tr><th>Parameter</th><th>Value</th></tr>\n"
" <tr><td colspan=\"2\">Please enter the Arduino IP address and click Connect.</td></tr>\n"
" </table>\n"
" <div id='statusMessage'>Status: Waiting for connection...</div>\n"
"\n"
" <script>\n"
" let pollingIntervalId = null;\n"
"\n"
" function connectToArduino() {\n"
" const ip = document.getElementById(\"arduinoIP\").value.trim();\n"
" if (!ip) {\n"
" document.getElementById('statusMessage').textContent = 'Status: Please enter an IP address.';\n"
" return;\n"
" }\n"
"\n"
" document.getElementById('statusMessage').textContent = `Status: Connecting to ${ip}...`;\n"
"\n"
" // Stop any previous polling\n"
" if (pollingIntervalId) {\n"
" clearInterval(pollingIntervalId);\n"
" pollingIntervalId = null;\n"
" }\n"
"\n"
" // Attempt to fetch data once to check connection\n"
" fetchDataFromIP(ip).then(success => {\n"
" if (success) {\n"
" // If initial fetch succeeds, start polling every 5 seconds\n"
" pollingIntervalId = setInterval(() => fetchDataFromIP(ip), 5000);\n"
" }\n"
" }).catch(() => {\n"
" // Error handling already done in fetchDataFromIP\n"
" });\n"
" }\n"
"\n"
" // Modified function to fetch from the /data endpoint\n"
" function fetchDataFromIP(ip) {\n"
" return fetch(`http://${ip}/data`) // <--- Changed from / to /data\n"
" .then(response => {\n"
" if (!response.ok) {\n"
" throw new Error(`HTTP error! Status: ${response.status}`);\n"
" }\n"
" return response.json(); // Expecting JSON from /data\n"
" })\n"
" .then(data => {\n"
" updateTable(data);\n"
" document.getElementById('statusMessage').textContent = `Status: Connected to ${ip}. Data updated.`;\n"
" return true; // Indicate success\n"
" })\n"
" .catch(error => {\n"
" console.error('Error fetching data:', error);\n"
" document.getElementById('statusMessage').textContent = `Status: Error fetching data from ${ip} - ${error.message}`;\n"
" // Optionally clear data on error\n"
" const table = document.getElementById('dataTable');\n"
" table.innerHTML = '<tr><th>Parameter</th><th>Value</th></tr><tr><td colspan=\"2\">Error loading data</td></tr>';\n"
" return false; // Indicate failure\n"
" });\n"
" }\n"
"\n"
" function updateTable(data) {\n"
" const table = document.getElementById('dataTable');\n"
" table.innerHTML = '<tr><th>Parameter</th><th>Value</th></tr>'; // Clear existing rows except header\n"
" \n"
" // Add rows for each data item\n"
" for (const [key, value] of Object.entries(data)) {\n"
" const row = table.insertRow();\n"
" const cell1 = row.insertCell(0);\n"
" const cell2 = row.insertCell(1);\n"
" cell1.innerText = key.charAt(0).toUpperCase() + key.slice(1); // Capitalize first letter\n"
" cell2.innerText = value;\n"
" }\n"
" }\n"
" </script>\n"
"\n"
"</body>\n"
"</html>\n";
/**
* @brief Helper function to ensure all data is written to the socket.
* This is crucial because a single 'write' call might not send all data.
* @param sock: The socket file descriptor.
* @param buf: Pointer to the data buffer to send.
* @param count: Number of bytes to send.
* @return: Total number of bytes sent on success, -1 on error.
*/
static ssize_t write_all(int sock, const void *buf, size_t count) {
const char *ptr = (const char*)buf;
size_t sent = 0;
ssize_t res;
while (sent < count) {
res = write(sock, ptr + sent, count - sent);
if (res < 0) {
// An error occurred during write
APP_PRINT("Error writing to socket: %d\n", res);
return -1; // Propagate error
}
sent += (size_t)res; // Add the number of bytes successfully sent
}
// All data was successfully sent
return sent;
}
/**
* @brief Thread function for the TCP Server.
* Serves the HTML page on '/' and JSON data on '/data'.
* @param arg: Not used
*/
static void tcpecho_thread(void *arg) {
int sock = -1, connected = -1;
char *recv_buf;
char *send_buf; // Temporary buffer for headers and small responses
struct sockaddr_in server_addr, client_addr;
socklen_t sin_size;
size_t recv_data_len;
int flag = 1;
(void)arg;
APP_PRINT("HTTP Server starting on Local port: %d\n", LOCAL_PORT);
recv_buf = (char *)pvPortMalloc(RECV_BUF_SIZE);
send_buf = (char *)pvPortMalloc(SEND_BUF_SIZE);
if (!recv_buf || !send_buf) {
APP_PRINT("Error: Failed to allocate memory for buffers.\n");
goto __exit;
}
sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock < 0) {
APP_PRINT("Error: Socket creation failed.\n");
goto __exit;
}
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = INADDR_ANY;
server_addr.sin_port = htons(LOCAL_PORT);
memset(&(server_addr.sin_zero), 0, sizeof(server_addr.sin_zero));
if (bind(sock, (struct sockaddr *)&server_addr, sizeof(struct sockaddr)) == -1) {
APP_PRINT("Error: Unable to bind socket.\n");
goto __exit;
}
if (listen(sock, 5) == -1) {
APP_PRINT("Error: Listen failed.\n");
goto __exit;
}
APP_PRINT("Server listening for HTTP connections...\n");
while(1) {
sin_size = sizeof(struct sockaddr_in);
connected = accept(sock, (struct sockaddr *)&client_addr, &sin_size);
if (connected < 0) {
APP_PRINT("Error: Accept failed.\n");
continue;
}
APP_PRINT("New HTTP client connected from (%s, %d)\n", inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port));
setsockopt(connected, IPPROTO_TCP, TCP_NODELAY, (void *) &flag, sizeof(int));
// --- Handle Client Request ---
memset(recv_buf, 0, RECV_BUF_SIZE);
recv_data_len = recv(connected, recv_buf, RECV_BUF_SIZE - 1, 0);
if (recv_data_len > 0) {
recv_buf[recv_data_len] = '\0';
APP_PRINT("Received request:\n%s\n", recv_buf); // Print full request for debugging
// --- NEW PARSING LOGIC USING SSCANF ---
char method[8]; // GET, POST, etc.
char path[256]; // URL path like /, /data, etc.
char http_version[16]; // HTTP/1.0, HTTP/1.1, etc.
// Parse the request line: "METHOD PATH HTTP_VERSION"
// %s reads up to the first whitespace character.
int parsed_items = sscanf(recv_buf, "%7s %255s %15s", method, path, http_version);
if (parsed_items == 3) {
APP_PRINT("Parsed Method: %s, Path: %s, Version: %s\n", method, path, http_version);
if (strncmp(method, "GET", 3) == 0) {
if (strcmp(path, "/") == 0) { // Serve the main HTML page
APP_PRINT("Serving main HTML page.\n");
// Calculate Content-Length for the HTML body
size_t html_len = strlen(HTML_PAGE);
// Prepare the response header
int header_len = snprintf(send_buf, SEND_BUF_SIZE,
"HTTP/1.1 200 OK\r\n"
"Content-Type: text/html\r\n"
"Access-Control-Allow-Origin: *\r\n"
"Access-Control-Allow-Methods: GET\r\n"
"Access-Control-Allow-Headers: Content-Type\r\n"
"Content-Length: %zu\r\n"
"Connection: close\r\n"
"\r\n", // Header ends with an extra \r\n
html_len);
// Send the header first
if (write_all(connected, send_buf, header_len) < 0) {
APP_PRINT("Error sending response header.\n");
goto cleanup_and_continue;
}
// Send the HTML page content using the helper function
if (write_all(connected, HTML_PAGE, html_len) < 0) {
APP_PRINT("Error sending HTML page content.\n");
// The connection will be closed below anyway
} else {
APP_PRINT("Sent HTML response (%zu bytes body) to client.\n", html_len);
}
// Done sending HTML page, go to cleanup
goto cleanup_and_continue;
} else if (strcmp(path, "/data") == 0) { // Serve the JSON data - CORRECTED LOGIC
APP_PRINT("Serving JSON data.\n");
// Step 1: Calculate the length of the JSON body
int json_body_len = snprintf(NULL, 0, // Calculate length only
"{ \"co2\": %u, \"temperature\": %.1f, \"humidity\": %.1f, \"status\": \"0x%02X\" }",
co2_concentration_raw, (double)temp, (double)hum, sensor_status_raw);
if (json_body_len <= 0) {
APP_PRINT("Error: Failed to calculate JSON body length.\n");
snprintf(send_buf, SEND_BUF_SIZE, "HTTP/1.1 500 Internal Server Error\r\nConnection: close\r\n\r\n");
} else {
// Step 2: Format the response header
int header_len = snprintf(send_buf, SEND_BUF_SIZE,
"HTTP/1.1 200 OK\r\n"
"Content-Type: application/json\r\n"
"Access-Control-Allow-Origin: *\r\n"
"Access-Control-Allow-Methods: GET\r\n"
"Access-Control-Allow-Headers: Content-Type\r\n"
"Content-Length: %d\r\n"
"Connection: close\r\n"
"\r\n", // Header ends with an extra \r\n
json_body_len);
// Step 3: Send the header first
if (write_all(connected, send_buf, header_len) < 0) {
APP_PRINT("Error sending JSON response header.\n");
goto cleanup_and_continue;
}
// Step 4: Send the JSON body
int body_len = snprintf(send_buf, SEND_BUF_SIZE, // Use send_buf to hold the JSON body
"{ \"co2\": %u, \"temperature\": %.1f, \"humidity\": %.1f, \"status\": \"0x%02X\" }",
co2_concentration_raw, (double)temp, (double)hum, sensor_status_raw);
if (body_len < 0 || body_len != json_body_len) {
APP_PRINT("Error: Formatting JSON body failed or mismatched length.\n");
// Connection will be closed below
goto cleanup_and_continue;
}
if (write_all(connected, send_buf, body_len) < 0) {
APP_PRINT("Error sending JSON response body.\n");
} else {
APP_PRINT("Sent JSON response (%d bytes body) to client.\n", body_len);
}
// Done sending JSON data, go to cleanup
goto cleanup_and_continue;
}
} else { // 404 for other paths
APP_PRINT("Path '%s' not found, sending 404.\n", path);
snprintf(send_buf, SEND_BUF_SIZE,
"HTTP/1.1 404 Not Found\r\n"
"Content-Type: text/plain\r\n"
"Access-Control-Allow-Origin: *\r\n"
"Access-Control-Allow-Methods: GET\r\n"
"Access-Control-Allow-Headers: Content-Type\r\n"
"Content-Length: 9\r\n"
"Connection: close\r\n"
"\r\n"
"Not Found");
}
} else { // Only handle GET requests
APP_PRINT("Unsupported method '%s', sending 405.\n", method);
snprintf(send_buf, SEND_BUF_SIZE,
"HTTP/1.1 405 Method Not Allowed\r\n"
"Content-Type: text/plain\r\n"
"Access-Control-Allow-Origin: *\r\n"
"Access-Control-Allow-Methods: GET\r\n"
"Access-Control-Allow-Headers: Content-Type\r\n"
"Content-Length: 15\r\n"
"Connection: close\r\n"
"\r\n"
"Method Not Allowed");
}
} else { // Malformed request line
APP_PRINT("Malformed request line (parsed %d items), sending 400.\n", parsed_items);
snprintf(send_buf, SEND_BUF_SIZE,
"HTTP/1.1 400 Bad Request\r\n"
"Content-Type: text/plain\r\n"
"Access-Control-Allow-Origin: *\r\n"
"Access-Control-Allow-Methods: GET\r\n"
"Access-Control-Allow-Headers: Content-Type\r\n"
"Content-Length: 11\r\n"
"Connection: close\r\n"
"\r\n"
"Bad Request");
}
// --- END OF NEW PARSING LOGIC ---
// Send the response stored in send_buf (for 404, 405, 500, or malformed requests)
int send_result = write_all(connected, send_buf, strlen(send_buf));
if (send_result < 0) {
APP_PRINT("Error sending data to client.\n");
} else {
APP_PRINT("Sent HTTP response (%d bytes) to client.\n", send_result);
}
} else {
APP_PRINT("No data received from client.\n");
}
cleanup_and_continue:
if (connected >= 0) {
closesocket(connected);
APP_PRINT("Client connection closed.\n");
}
connected = -1;
}
__exit:
if (sock >= 0) closesocket(sock);
if (recv_buf) vPortFree(recv_buf); // Use FreeRTOS functions if applicable
if (send_buf) vPortFree(send_buf);
APP_PRINT("HTTP Server thread exiting.\n");
}
/*-----------------------------------------------------------------------------------*/
void tcp_echo_server_init(void) {
sys_thread_new("tcpecho_thread", tcpecho_thread, NULL, 2048, 4);
}代码的思路是创建tcp_server并监听,当有tcpclient进来时,向其发送请求的数据。
2、在lwip_tread_entry.c中添加lwip初始化以启动tcp_server,代码如下:
#include <lwip_thread.h>
#include "common_utils.h"
#include "usr_app.h"
#include "lwip/init.h"
#include "lwip/tcpip.h"
#include "lwip/tcp.h"
#include "lwip/timeouts.h"
#include "lwip/init.h"
#include "lwip/ip4.h"
#include "lwip/dhcp.h"
#include <lwip/sockets.h>
struct netif gnetif;
ip4_addr_t ipaddr;
ip4_addr_t netmask;
ip4_addr_t gw;
void tcpecho_init(void);
extern void tcp_echo_server_init(void);
/*---------------------------------------------------------------------------*/
/* 1) Define your callback functions */
/*---------------------------------------------------------------------------*/
void ethernet_link_status_updated(struct netif *netif)
{
if (netif_is_link_up(netif)) {
APP_PRINT("LINK UP\n\n");
} else {
APP_PRINT("LINK DOWN\n\n");
}
}
void LwIP_Init(void)
{
LWIP_DEBUGF(TCP_DEBUG, ("RTT Debug Enabled\n"));
/* Initialize the LwIP stack with RTOS */
tcpip_init(NULL, NULL);
// ipaddr.addr = 0;
// netmask.addr = 0;
// gw.addr = 0;
IP4_ADDR(&ipaddr, 192, 168, 3, 12);
IP4_ADDR(&gw, 192, 168, 3, 1);
IP4_ADDR(&netmask, 255, 255, 255, 0);
/* add the network interface (IPv4/IPv6) with RTOS */
netif_add(&gnetif, &ipaddr, &netmask, &gw, &g_lwip_ether0_instance, &rm_lwip_ether_init, &tcpip_input);
/* Registers the default network interface */
netif_set_default(&gnetif);
/* When the netif is fully configured this function must be called */
netif_set_up(&gnetif);
netif_set_link_up(&gnetif);
/* Set the link callback function, this function is called on change of link status*/
netif_set_link_callback(&gnetif, ethernet_link_status_updated);
APP_PRINT("Local IP :%d.%d.%d.%d\n\n", \
((gnetif.ip_addr.addr)&0x000000ff), \
(((gnetif.ip_addr.addr)&0x0000ff00)>>8), \
(((gnetif.ip_addr.addr)&0x00ff0000)>>16), \
((gnetif.ip_addr.addr)&0xff000000)>>24);
APP_PRINT("Local Netmask :%d.%d.%d.%d\n\n", \
((gnetif.netmask.addr)&0x000000ff), \
(((gnetif.netmask.addr)&0x0000ff00)>>8), \
(((gnetif.netmask.addr)&0x00ff0000)>>16), \
((gnetif.netmask.addr)&0xff000000)>>24);
APP_PRINT("Local GW :%d.%d.%d.%d\n\n", \
((gnetif.gw.addr)&0x000000ff), \
(((gnetif.gw.addr)&0x0000ff00)>>8), \
(((gnetif.gw.addr)&0x00ff0000)>>16), \
((gnetif.gw.addr)&0xff000000)>>24);
ip_addr_set(&ipaddr,&(gnetif.ip_addr));
ip_addr_set(&netmask,&(gnetif.netmask));
ip_addr_set(&gw,&(gnetif.gw));
}
/*******************************************************************************************************************//**
* @brief This is the User Thread for the EP.
* @param[in] Thread specific parameters
* @retval None
**********************************************************************************************************************/
void lwip_thread_entry(void *pvParameters)
{
fsp_pack_version_t version = {RESET_VALUE};
FSP_PARAMETER_NOT_USED(pvParameters);
/* version get API for FLEX pack information */
R_FSP_VersionGet (&version);
/* Example Project information printed on the RTT */
APP_PRINT (BANNER_INFO, EP_VERSION, version.version_id_b.major, version.version_id_b.minor, version.version_id_b.patch);
LwIP_Init();
tcp_echo_server_init();
/* If this thread is done, you can delete it */
vTaskDelete(NULL);
}在这个工程中,我们配置开发板的ip与有我们的所在的网络的网段一致。
【测试】
编译下载后,我们ping一下开发板:

顺利的连上了网络。
编写测试网页:
<!DOCTYPE html>
<html>
<head>
<title>RA8D1 环境监测站</title>
<style>
body {
font-family: Arial, sans-serif;
margin: 40px;
background-color: #f0f0f0;
}
h1 {
color: #333;
}
table {
border-collapse: collapse;
width: 50%;
margin-top: 20px;
}
th,
td {
border: 1px solid #ddd;
padding: 12px;
text-align: left;
}
th {
background-color: #4CAF50;
color: white;
}
tr:nth-child(even) {
background-color: #f2f2f2;
}
input[type=text] {
padding: 10px;
font-size: 16px;
}
button {
padding: 10px 20px;
font-size: 16px;
cursor: pointer;
}
#statusMessage {
margin-top: 20px;
color: #d32f2f;
font-weight: bold;
}
</style>
</head>
<body>
<h1>RA8D1 环境监测站</h1>
<label for="arduinoIP">请输入 RA8D1 开发板的 IP 地址:</label>
<input type="text" id="arduinoIP" placeholder="例如: 192.168.3.12">
<button onclick="connectToArduino()">连接</button>
<table id='dataTable' border='1'>
<tr>
<th>参数</th>
<th>数值</th>
</tr>
<tr>
<td colspan="2">请输入 RA8D1 开发板的 IP 地址并点击连接。</td>
</tr>
</table>
<div id='statusMessage'>状态: 等待连接...</div>
<script>
let pollingIntervalId = null;
function connectToArduino() {
const ip = document.getElementById("arduinoIP").value.trim();
if (!ip) {
document.getElementById('statusMessage').textContent = '状态: 请输入一个 IP 地址.';
return;
}
document.getElementById('statusMessage').textContent = `状态: 正在连接到 ${ip}...`;
// 停止任何先前的轮询
if (pollingIntervalId) {
clearInterval(pollingIntervalId);
pollingIntervalId = null;
}
// 尝试获取一次数据以检查连接
fetchDataFromIP(ip).then(success => {
if (success) {
// 如果初始获取成功,则每 5 秒轮询一次
pollingIntervalId = setInterval(() => fetchDataFromIP(ip), 5000);
}
}).catch(() => {
// 错误处理已在 fetchDataFromIP 中完成
});
}
// 修改后的函数,从 /data 端点获取数据
function fetchDataFromIP(ip) {
return fetch(`http://${ip}/data`) // <--- Changed from / to /data
.then(response => {
if (!response.ok) {
throw new Error(`HTTP 错误! 状态: ${response.status}`);
}
return response.json(); // 期望从 /data 获取 JSON
})
.then(data => {
updateTable(data);
document.getElementById('statusMessage').textContent = `状态: 已连接到 ${ip}。数据已更新.`;
return true; // 表示成功
})
.catch(error => {
console.error('获取数据时出错:', error);
document.getElementById('statusMessage').textContent = `状态: 从 ${ip} 获取数据时出错 - ${error.message}`;
// 可选择在出错时清除数据
const table = document.getElementById('dataTable');
table.innerHTML = '<tr><th>参数</th><th>数值</th></tr><tr><td colspan="2">加载数据出错</td></tr>';
return false; // 表示失败
});
}
function updateTable(data) {
const table = document.getElementById('dataTable');
table.innerHTML = '<tr><th>参数</th><th>数值</th></tr>'; // 清除现有行,保留表头
// 为每个数据项添加行
for (const [key, value] of Object.entries(data)) {
const row = table.insertRow();
const cell1 = row.insertCell(0);
const cell2 = row.insertCell(1);
// 将英文参数名转换为常见的中文名称 (可选)
let chineseKey = key.charAt(0).toUpperCase() + key.slice(1); // 默认首字母大写
if (key.toLowerCase() === 'co2') chineseKey = '二氧化碳浓度 (ppm)';
if (key.toLowerCase() === 'temperature') chineseKey = '温度 (°C)';
if (key.toLowerCase() === 'humidity') chineseKey = '湿度 (%)';
if (key.toLowerCase() === 'status') chineseKey = '传感器状态';
cell1.innerText = chineseKey;
cell2.innerText = value;
}
}
</script>
</body>
</html>打开网页,输入IP地址后,在网页上就可以实现的监测到环境数据了。


【总结】
瑞萨的RASC图形化的配置工具网络非常方便工程的配置。提供的pin的配置,我们不需要自己去编写复杂的管脚配置,可以快速的实现lwip。同时RA8D1性能非常强大,在运行lvgl下面,也可以高效的处理网络请求。
【感谢】
非常感谢@枫雪天 大佬的指导,此次工程是学习他的freertos+lwip_tcp工程的基础上创建出来的。
我要赚赏金
