前言
国产的芯片的,性价比 真是高,ESP32-3C 经典版 12.9 SRAM 400K flash 4M ,主频160MHZ,
这跟STM32 比,吓死人, 自带蓝牙与WIFI,连模块钱省了,不过,
看下各自占用的资源对比吧 需要联网 不是太苛刻的环境下,首选择ESP32,还有GD32(主频高点),这个也是基于ARM,对比STM32 也不便宜,国产替补品,STM32好多也是国产芯片
STM32 智能小车 RAM 20K flash 64k ARM指令 8-10元
ESP32 -3C HTTP client RAM 400k flash 4M 基于RISC-V指令 11-13元
1:环境
ESP32 3C 经典版 TYPEC 可以下载也可以当UART0 使用 (GPIO 8,9)
VSCODE+IDF5.4.1 安装可能需要科学上网
2:直接上代码
main.c
#include <stdio.h>
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_system.h"
#include "esp_wifi.h"
#include "esp_event.h"
#include "esp_log.h"
#include "nvs_flash.h"
#include "esp_http_client.h"
#include "esp_netif.h" // 替代 tcpip_adapter 的新网络接口组件
// WiFi 配置(替换为实际的 WiFi 名称和密码)
#define WIFI_SSID "自己的SSID"
#define WIFI_PASSWORD "自己的密码"
// 日志标签
static const char *TAG = "WIFI_HTTP_EXAMPLE";
#define REQUEST_URL "http://192.168.1.3:8080/hello"
// 事件组:用于等待 WiFi 连接成功
static EventGroupHandle_t s_wifi_event_group;
const int WIFI_CONNECTED_BIT = BIT0;
// WiFi 事件处理函数
static void event_handler(void* arg, esp_event_base_t event_base,
int32_t event_id, void* event_data)
{
if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) {
// WiFi 启动后开始连接
esp_wifi_connect();
} else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) {
// 连接断开后重试
esp_wifi_connect();
xEventGroupClearBits(s_wifi_event_group, WIFI_CONNECTED_BIT);
ESP_LOGW(TAG, "WiFi disconnect,try again...");
} else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) {
// 获取 IP 地址后标记连接成功
ip_event_got_ip_t* event = (ip_event_got_ip_t*) event_data;
ESP_LOGI(TAG, "get IP address: " IPSTR, IP2STR(&event->ip_info.ip));
xEventGroupSetBits(s_wifi_event_group, WIFI_CONNECTED_BIT);
}
}
// 初始化 WiFi 为 Station 模式
void wifi_init_sta(void)
{
// 1. 初始化事件组(用于同步 WiFi 连接状态)
s_wifi_event_group = xEventGroupCreate();
// 2. 初始化 esp-netif(替代旧的 tcpip_adapter_init())
ESP_ERROR_CHECK(esp_netif_init());
// 3. 创建默认事件循环(处理 WiFi 和 IP 事件)
ESP_ERROR_CHECK(esp_event_loop_create_default());
// 4. 创建默认的 WiFi Station 网络接口
esp_netif_create_default_wifi_sta();
// 5. 初始化 WiFi 驱动
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
ESP_ERROR_CHECK(esp_wifi_init(&cfg));
// 6. 注册事件处理函数(监听 WiFi 和 IP 事件)
ESP_ERROR_CHECK(esp_event_handler_register(WIFI_EVENT, ESP_EVENT_ANY_ID, &event_handler, NULL));
ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, IP_EVENT_STA_GOT_IP, &event_handler, NULL));
// 7. 配置 WiFi 连接参数(SSID 和密码)
wifi_config_t wifi_config = {
.sta = {
.ssid = WIFI_SSID,
.password = WIFI_PASSWORD,
},
};
ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA)); // 设置为 Station 模式
ESP_ERROR_CHECK(esp_wifi_set_config(ESP_IF_WIFI_STA, &wifi_config)); // 应用配置
ESP_ERROR_CHECK(esp_wifi_start()); // 启动 WiFi
ESP_LOGI(TAG, "WiFi init finish,connect %s...", WIFI_SSID);
}
// HTTP 事件回调函数(处理服务器响应数据)
// HTTP 请求的处理函数
esp_err_t _http_event_handler(esp_http_client_event_t *evt)
{
// 缓存http响应的buffer
// static char *output_buffer;
// 已经读取的字节数
static int output_len;
switch(evt->event_id) {
case HTTP_EVENT_ERROR:
ESP_LOGD(TAG, "HTTP_EVENT_ERROR");
break;
case HTTP_EVENT_ON_CONNECTED:
ESP_LOGD(TAG, "HTTP_EVENT_ON_CONNECTED");
break;
case HTTP_EVENT_HEADER_SENT:
ESP_LOGD(TAG, "HTTP_EVENT_HEADER_SENT");
break;
case HTTP_EVENT_ON_HEADER:
ESP_LOGD(TAG, "HTTP_EVENT_ON_HEADER, key=%s, value=%s", evt->header_key, evt->header_value);
break;
case HTTP_EVENT_ON_DATA:
ESP_LOGD(TAG, "HTTP_EVENT_ON_DATA, len=%d", evt->data_len);
if (!esp_http_client_is_chunked_response(evt->client)) {
// 如果配置了user_data buffer,则把响应复制到该buffer中
if (evt->user_data) {
memcpy(evt->user_data + output_len, evt->data, evt->data_len);
} else {
// if (output_buffer == NULL) {
// output_buffer = (char *) malloc(esp_http_client_get_content_length(evt->client));
// output_len = 0;
// if (output_buffer == NULL) {
// ESP_LOGE(TAG, "Failed to allocate memory for output buffer");
// return ESP_FAIL;
// }
// }
// memcpy(output_buffer + output_len, evt->data, evt->data_len);
ESP_LOGD(TAG,"%.*s", evt->data_len, (char*)evt->data);
}
output_len += evt->data_len;
}
break;
case HTTP_EVENT_ON_FINISH:
ESP_LOGD(TAG, "HTTP_EVENT_ON_FINISH");
// if (output_buffer != NULL) {
// // Response is accumulated in output_buffer. Uncomment the below line to print the accumulated response
// // ESP_LOG_BUFFER_HEX(TAG, output_buffer, output_len);
// free(output_buffer);
// output_buffer = NULL;
// }
output_len = 0;
break;
case HTTP_EVENT_DISCONNECTED:
ESP_LOGI(TAG, "HTTP_EVENT_DISCONNECTED");
// if (output_buffer != NULL) {
// free(output_buffer);
// output_buffer = NULL;
// }
output_len = 0;
break;
default:
ESP_LOGI(TAG, "HTTP_EVENT_OTHER");
}
return ESP_OK;
}
char *str_to_hex_str(const char *input,int inputlen,char* output) {
if (input == NULL) return NULL;
size_t len = inputlen;//strlen(input);
// 每个字符转十六进制占 2 个字符,再加上可能的分隔符、字符串结束符 '\0'
// 这里示例没加分隔符,直接连续存,所以总长度是 len * 2 + 1
// char *hex_buf = (char *)malloc(len * 2 + 1);
// if (hex_buf == NULL) return NULL;
char *p = output;//hex_buf;
for (size_t i = 0; i < len; i++) {
// 逐个字符格式化到 hex_buf
p += sprintf(p, "%02x", (unsigned char)input[i]);
}
return output;
}
// 发送 HTTP GET 请求
void http_get_request(const char *url)
{
// 响应结果放在这里
char local_response_buffer[2048] = {0};
// 创建一个 HTTP 客户端配置
esp_http_client_config_t config = {
.method = HTTP_METHOD_GET,
.url = url,
.event_handler = _http_event_handler,
.user_data = local_response_buffer,
.disable_auto_redirect = true,
};
// 创建一个 HTTP 客户端并执行 GET 请求
// 创建一个 HTTP 客户端并执行 GET 请求
esp_http_client_handle_t client = esp_http_client_init(&config);
esp_err_t err = esp_http_client_perform(client);
// 检查请求是否成功
if (err == ESP_OK) {
int len = esp_http_client_get_content_length(client);
ESP_LOGI(TAG, "Status = %d, content_length = %d",
esp_http_client_get_status_code(client),//状态码
len);//数据长度
if(len>0){
local_response_buffer[len]=0;
ESP_LOGI(TAG, "recv[%s]\n",local_response_buffer);
// for(int i=0;i<len;i++){
// // ESP_LOGI(TAG, "recv server respon[%x]", sztemphex[i]);
// ESP_LOGI(TAG,"%02x",(unsigned char)(local_response_buffer[i]));
// }
// char sztemphex[2048]={0,};
// memset(sztemphex,0,sizeof(sztemphex));
// str_to_hex_str(local_response_buffer,len,sztemphex);
// ESP_LOGI(TAG, "recv server respon[%s]", sztemphex);
}
} else {
printf("HTTP GET request failed: %s\n", esp_err_to_name(err));
}
//printf("Response: %.*s\n", strlen(local_response_buffer), local_response_buffer);
// ESP_LOGI(TAG, "recv server respon[%d]:%s",strlen(local_response_buffer), local_response_buffer);
//断开并释放资源
esp_http_client_cleanup(client);
}
void http_get_request_bak(const char *url)
{
// 配置 HTTP 客户端
// esp_http_client_config_t config = {
// .url = url, // 目标网址
// .event_handler = _http_event_handler, // 响应处理回调
// .timeout_ms = 10000, // 超时时间(10秒)
// };
esp_http_client_config_t config = {
.url = REQUEST_URL,
.event_handler = _http_event_handler,
.timeout_ms = 10000,
// 关键:显式指定 HTTP 版本为 1.1(避免自动降级)
.transport_type = HTTP_TRANSPORT_OVER_TCP,
};
// 初始化客户端并发送请求
esp_http_client_handle_t client = esp_http_client_init(&config);
esp_http_client_set_header(client, "User-Agent", "ESP32-HTTP-Example/1.0");
esp_err_t err = esp_http_client_perform(client);
if (err == ESP_OK) {
ESP_LOGI(TAG, "HTTP state code: %d", esp_http_client_get_status_code(client));
// 读取并打印响应内容
//char response_buf[1024] = {0}; // 缓冲区,根据实际响应大小调整
// int read_len = esp_http_client_read(client, response_buf, sizeof(response_buf) - 1);
int total_len = 0;
char buffer[1024] = {0};
while (1) {
int read_len = esp_http_client_read(client, buffer + total_len, sizeof(buffer) - total_len - 1);
if (read_len <= 0) break; // 读取完毕或出错
total_len += read_len;
// 防止缓冲区溢出(可选,根据需求调整)
if (total_len >= sizeof(buffer) - 1) break;
}
buffer[total_len] = '\0'; // 确保字符串结尾
ESP_LOGI(TAG, "recv server respon[%d]:%s",total_len,buffer);
// if (read_len > 0) {
// ESP_LOGI(TAG, "recv server respon:%s",response_buf);
// // printf("%s\n", response_buf); // 直接打印原始响应
// } else if (read_len == 0) {
// ESP_LOGI(TAG, "server respon NULL");
// } else {
// ESP_LOGE(TAG, "server respon fail");
// }
} else {
ESP_LOGE(TAG, "HTTP request fail: %s", esp_err_to_name(err));
}
// 清理资源
esp_http_client_cleanup(client);
}
void app_main(void)
{
// 1. 初始化 NVS(存储 WiFi 配置等信息)
esp_err_t ret = nvs_flash_init();
if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
ESP_ERROR_CHECK(nvs_flash_erase()); // 若 NVS 满或版本不兼容,先擦除
ret = nvs_flash_init();
}
ESP_ERROR_CHECK(ret);
// 2. 初始化 WiFi 并连接
wifi_init_sta();
// 3. 等待 WiFi 连接成功(阻塞直到获取 IP)
xEventGroupWaitBits(s_wifi_event_group, WIFI_CONNECTED_BIT,
pdFALSE, pdTRUE, portMAX_DELAY);
ESP_LOGI(TAG, "WiFi connect success,start send HTTP request...");
// 4. 访问目标网址(http://www.ip.cn/ 会重定向到 https://myip.xyz/zh/)
// const char *url = "http://www.ip.cn/";
ESP_LOGI(TAG, "vist url: %s", REQUEST_URL);
http_get_request(REQUEST_URL);
// 5. 程序保持运行(可添加循环请求逻辑)
while (1) {
vTaskDelay(pdMS_TO_TICKS(8000)); // 每 8 秒循环一次
http_get_request(REQUEST_URL); // 取消注释可实现定时重复请求
}
}
golang server代码
package main
import (
"context" // 添加缺失的context包
"fmt"
"log"
"net/http"
"os"
"os/signal"
"syscall"
"time"
)
func main() {
// 创建一个带有超时设置的服务器实例
server := &http.Server{
Addr: ":8080",
Handler: setupRouter(),
ReadTimeout: 10 * time.Second,
WriteTimeout: 10 * time.Second,
IdleTimeout: 30 * time.Second,
}
// 启动服务器的goroutine
go func() {
log.Printf("服务器启动,监听端口: %s\n", server.Addr)
if err := server.ListenAndServe(); err != nil && err != http.ErrServerClosed {
log.Fatalf("服务器启动失败: %v\n", err)
}
}()
// 优雅关闭服务器
waitForShutdown(server)
}
// 设置路由和中间件
func setupRouter() http.Handler {
mux := http.NewServeMux()
// 注册路由
mux.HandleFunc("/", homeHandler)
mux.HandleFunc("/hello", helloHandler)
// 使用中间件包装路由
return loggingMiddleware(mux)
}
// 首页处理器
func homeHandler(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("欢迎来到Go HTTP服务器!\n"))
}
// 问候处理器
func helloHandler(w http.ResponseWriter, r *http.Request) {
curtime := time.Now().Unix()
log.Printf("Received request from %s, Method: %s, Headers: %v",
r.RemoteAddr, r.Method, r.Header)
rep := fmt.Sprintf("hello_time=%v", curtime)
w.Write([]byte(rep))
//w.Write([]byte("hello,world!\n"))
log.Println(fmt.Sprintf("recv request from %v time=%v len(rep)=%v_%v", r.RemoteAddr, curtime, len(rep), rep))
}
// 等待关闭信号并优雅地关闭服务器
func waitForShutdown(server *http.Server) {
interruptChan := make(chan os.Signal, 1)
signal.Notify(interruptChan, os.Interrupt, syscall.SIGINT, syscall.SIGTERM)
// 等待中断信号
<-interruptChan
log.Println("接收到关闭信号,开始优雅关闭服务器...")
// 创建一个5秒的超时时间来关闭服务器
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
// 优雅关闭服务器,等待现有请求完成
if err := server.Shutdown(ctx); err != nil {
log.Printf("服务器关闭错误: %v\n", err)
} else {
log.Println("服务器已优雅关闭")
}
}
3:测试结果 如果对你又帮助,麻烦点个赞,加个关注