#include "udp2uart.h"
#include "board.h"
#include "settings.h"
#include <esp_log.h>
#include <driver/gpio.h>
#include <driver/uart.h>
#include "system_info.h"
#include <cstring>
#include <vector>
#include <sstream>
#include <algorithm>
#include <string>
using namespace std;
#define TAG "Udp2Uart"
char udpbuf[MAX_UDP_BUF];
int udpbuflen;
#define MAX_LINES 20
std::vector<string> LCD_Line; // LCD行显示缓冲区
uint8_t LCD_Line_Flag[MAX_LINES]={0}; // 标记需要更新的行
uint8_t LCD_Line_Cnt=0; // 当前行数
bool is_LCD_Update=false; // 新增:LCD更新标志
Udp2Uart::Udp2Uart()
{
udpbuflen=0;
LCD_Line.resize(MAX_LINES);
is_LCD_Update=false;
}
Udp2Uart::~Udp2Uart()
{
}
// 清空屏幕
void Udp2Uart::ClearScreen()
{
std::string strUart;
for (int i=0; i<MAX_LINES; i++) {
LCD_Line[i]="";
LCD_Line_Flag[i]=0;
}
LCD_Line_Cnt=0;
// 发送清屏命令
strUart = "JUMP(3)\r\n";
uart_write_bytes(UART_NUM, strUart.c_str(), strUart.size());
vTaskDelay(pdMS_TO_TICKS(100));
strUart = "JUMP(2)\r\n";
uart_write_bytes(UART_NUM, strUart.c_str(), strUart.size());
}
// 处理中文字符显示
void Udp2Uart::togbk(std::string utf8_str, uint8_t dir)
{
// 转换UTF-8到GBK(实现可能在别处)
std::string strGB=GB.get(utf8_str);
if (strGB.empty()) return;
// 添加方向标记
if(dir==1){
strGB = "<" + strGB;
}else if(dir==2){
strGB = ">" + strGB;
}
// 分行处理(每行最多32个字符)
uint16_t lenGB=strGB.size();
vector<string> lines;
if(lenGB < 32){
lines.push_back(strGB);
}else{
size_t start_pos = 0;
size_t current_len = 0;
size_t i = 0;
while (i < lenGB) {
bool is_chinese = (static_cast<unsigned char>(strGB[i]) & 0x80) != 0;
size_t char_len = is_chinese ? 2 : 1;
if (current_len + char_len > 32) {
lines.push_back(strGB.substr(start_pos, i - start_pos));
if(lines.size() >= MAX_LINES) break;
start_pos = i;
current_len = 0;
}
current_len += char_len;
i += char_len;
}
if (i > start_pos && lines.size() < MAX_LINES) {
lines.push_back(strGB.substr(start_pos, i - start_pos));
}
}
// 确定显示位置
int StartLine=0;
int AddLines=lines.size();
if(AddLines >= MAX_LINES){
AddLines=MAX_LINES;
StartLine=0;
LCD_Line_Cnt=0;
}else{
if(LCD_Line_Cnt + AddLines < MAX_LINES){
StartLine=LCD_Line_Cnt;
if(AddLines>1) LCD_Line_Cnt += AddLines-1;
}else if(LCD_Line_Cnt + AddLines == MAX_LINES){
StartLine=LCD_Line_Cnt;
if(AddLines>1) LCD_Line_Cnt += AddLines-1;
}else{
StartLine=MAX_LINES-AddLines;
LCD_Line_Cnt=MAX_LINES-1;
}
}
// 更新显示缓冲区
for(int i=StartLine; i<StartLine+AddLines; i++){
LCD_Line[i]=lines[i-StartLine];
LCD_Line_Flag[i]=1;
}
is_LCD_Update=true;
LCD_Line_Cnt++;
if(LCD_Line_Cnt >= MAX_LINES) LCD_Line_Cnt=0;
lines.clear();
}
// 启动服务
void Udp2Uart::Start()
{
TARGET_IP="172.16.0.29"; // 默认目标IP,可通过命令修改
// 配置串口参数
uart_config_t uart_config = {
.baud_rate = 115200,
.data_bits = UART_DATA_8_BITS,
.parity = UART_PARITY_DISABLE,
.stop_bits = UART_STOP_BITS_1,
.flow_ctrl = UART_HW_FLOWCTRL_DISABLE
};
uart_param_config(UART_NUM_2, &uart_config);
uart_set_pin(UART_NUM_2, 12, 11, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE);
uart_driver_install(UART_NUM_2, BUF_SIZE, 0, 0, NULL, 0);
// 创建UDP接收和串口转发任务
xTaskCreate([](void *arg){
Udp2Uart* app = (Udp2Uart*)arg;
app->udp_to_serial_task();
vTaskDelete(NULL);
}, "udp_to_serial", 4096, this, 10, nullptr);
xTaskCreate([](void *arg){
Udp2Uart* app = (Udp2Uart*)arg;
app->serial_to_udp_task();
vTaskDelete(NULL);
}, "serial_to_udp", 4096, this, 5, nullptr);
}
// 串口到UDP转发
void Udp2Uart::serial_to_udp_task()
{
int sockfd_tx;
struct sockaddr_in target_addr;
uint8_t *rx_buffer = (uint8_t *) malloc(RD_BUF_SIZE);
// 创建UDP socket
if ((sockfd_tx = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
ESP_LOGE(TAG, "Failed to create socket");
vTaskDelete(NULL);
}
// 配置目标地址
memset(&target_addr, 0, sizeof(target_addr));
target_addr.sin_family = AF_INET;
target_addr.sin_port = htons(TARGET_PORT);
inet_pton(AF_INET, TARGET_IP.c_str(), &target_addr.sin_addr);
while (1) {
// 读取串口数据并转发到UDP
int len = uart_read_bytes(UART_NUM_2, rx_buffer, RD_BUF_SIZE, pdMS_TO_TICKS(100));
if (len > 0) {
sendto(sockfd_tx, rx_buffer, len, 0, (struct sockaddr *)&target_addr, sizeof(target_addr));
ESP_LOGI(TAG, "Forwarded %d bytes from Serial to UDP", len);
}
}
free(rx_buffer);
close(sockfd_tx);
vTaskDelete(NULL);
}
// UDP到串口转发及命令处理
void Udp2Uart::udp_to_serial_task()
{
int sockfd_rx;
struct sockaddr_in serv_addr, client_addr;
socklen_t addr_len = sizeof(client_addr);
char rx_buffer[BUF_SIZE];
// 创建UDP socket
if ((sockfd_rx = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
ESP_LOGE(TAG, "Failed to create socket");
vTaskDelete(NULL);
}
// 设置非阻塞模式
int flags = fcntl(sockfd_rx, F_GETFL, 0);
fcntl(sockfd_rx, F_SETFL, flags | O_NONBLOCK);
// 设置地址重用
int opt = 1;
setsockopt(sockfd_rx, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
// 绑定本地端口
memset(&serv_addr, 0, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(UDP_PORT);
serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
if (bind(sockfd_rx, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) {
ESP_LOGE(TAG, "Bind failed");
close(sockfd_rx);
vTaskDelete(NULL);
}
ESP_LOGI(TAG, "UDP server started on port %d", UDP_PORT);
while (1) {
// 接收UDP数据
int len = recvfrom(sockfd_rx, rx_buffer, BUF_SIZE, 0,
(struct sockaddr *)&client_addr, &addr_len);
if (len > 0) {
rx_buffer[len] = '\0';
std::string cmd(rx_buffer);
// 处理人体检测命令
if (cmd == "HUMAN_DETECTED") {
// 清空屏幕并显示"有人经过"
ClearScreen();
togbk("有人经过", 1);
ESP_LOGI(TAG, "Human detected - updating display");
} else if (cmd == "NO_ONE") {
// 清空屏幕并显示"无人"
ClearScreen();
togbk("无人", 1);
ESP_LOGI(TAG, "No one detected - updating display");
} else if (strncmp(rx_buffer, "sysinfo", 7) == 0) {
// 系统信息命令
SystemInfo::PrintRealTimeStats(0xFFFF);
} else {
// 其他命令或数据转发到串口
uart_write_bytes(UART_NUM_2, rx_buffer, len);
ESP_LOGI(TAG, "Forwarded %d bytes from UDP to Serial", len);
}
}
// 更新LCD显示
if(is_LCD_Update){
std::string strOut="";
std::string strUart;
for (int i=0; i<LCD_Line.size(); i++) {
if (LCD_Line_Flag[i]) {
strUart = "SET_TXT(" + std::to_string(i) + ",\'" + LCD_Line[i] + "\')\r\n";
uart_write_bytes(UART_NUM_2, strUart.c_str(), strUart.size());
vTaskDelay(pdMS_TO_TICKS(220));
strOut += strUart;
LCD_Line_Flag[i]=0;
}
}
// 发送响应到客户端
if (!strOut.empty()) {
sendto(sockfd_rx, strOut.c_str(), strOut.size(), 0,
(struct sockaddr *)&client_addr, sizeof(client_addr));
}
is_LCD_Update=false;
}
// 有UDP数据需要返回
if(udpbuflen > 0){
sendto(sockfd_rx, udpbuf, udpbuflen, 0,
(struct sockaddr *)&client_addr, sizeof(client_addr));
udpbuflen=0;
}
vTaskDelay(1);
}
close(sockfd_rx);
vTaskDelete(NULL);
}#include <esp_log.h>
#include <esp_err.h>
#include <nvs.h>
#include <nvs_flash.h>
#include <driver/gpio.h>
#include <esp_event.h>
#include "application.h"
#include "system_info.h"
#define TAG "main"
extern "C" void app_main(void)
{
// Initialize the default event loop
ESP_ERROR_CHECK(esp_event_loop_create_default());
// Initialize NVS flash for WiFi configuration
esp_err_t ret = nvs_flash_init();
if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
ESP_LOGW(TAG, "Erasing NVS flash to fix corruption");
ESP_ERROR_CHECK(nvs_flash_erase());
ret = nvs_flash_init();
}
ESP_ERROR_CHECK(ret);
// Launch the application
Application::GetInstance().Start();
// The main thread will exit and release the stack memory
}
import network
import socket
import neopixel
import machine
from machine import Pin
# 硬件配置
LED_PIN = 9 # WS2812数据输入端口
LED_NUM = 16*16 # 总像素数
BRIGHTNESS = 0.2 # 亮度
# Wi-Fi 配置
WIFI_SSID = "310"
WIFI_PASS = "310310310"
UDP_PORT = 8888 # 监听端口(需与雷达代码的UDP_PORT_LIGHT一致)
# 初始化LED
np = neopixel.NeoPixel(Pin(LED_PIN), LED_NUM)
np.fill((0, 0, 0))
np.write()
# Wi-Fi连接
def wifi_connect():
sta_if = network.WLAN(network.STA_IF)
if not sta_if.isconnected():
sta_if.active(True)
sta_if.connect(WIFI_SSID, WIFI_PASS)
while not sta_if.isconnected():
time.sleep(0.5)
print("灯带控制器已连接:", sta_if.ifconfig()[0])
# UDP服务:处理亮灭指令
def udp_server():
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.bind(('0.0.0.0', UDP_PORT))
print(f"灯带控制器监听端口{UDP_PORT}")
while True:
data, addr = sock.recvfrom(1024)
cmd = data.decode().strip()
if cmd == "LIGHT:ON":
np.fill((255, 0, 0)) # 红色常亮
np.write()
elif cmd == "LIGHT:OFF":
np.fill((0, 0, 0)) # 熄灭
np.write()
if __name__ == "__main__":
print("===== 灯带控制器 =====")
wifi_connect()
udp_server()
import machine
import time
import network
import socket
# 网络配置(三者需在同一局域网,IP需手动设置)
WIFI_SSID = "310"
WIFI_PASSWORD = "310310310"
# 硬件配置
SENSOR_PIN = 2 # LD1030传感器OUT引脚
LOCAL_LED_PIN = 13 # 本地状态指示灯(可选)
UDP_PORT_S3 = 5005 # ESP32-S3接收端口(对应vscodeesp32s3udp2uart.cc的UDP_PORT)
UDP_PORT_LIGHT = 8888 # 灯带控制器端口(对应thonny灯带代码的UDP_PORT)
UDP_TARGET_IP_S3 = "192.168.43.91" # ESP32-S3的IP
UDP_TARGET_IP_LIGHT = "192.168.43.100" # 灯带控制器的IP
# 初始化硬件
sensor = machine.Pin(SENSOR_PIN, machine.Pin.IN)
local_led = machine.Pin(LOCAL_LED_PIN, machine.Pin.OUT) if LOCAL_LED_PIN else None
# 连接WiFi
def connect_wifi():
wlan = network.WLAN(network.STA_IF)
wlan.active(True)
if not wlan.isconnected():
print(f"正在连接到WiFi: {WIFI_SSID}")
wlan.connect(WIFI_SSID, WIFI_PASSWORD)
while not wlan.isconnected():
time.sleep(1)
print(f"WiFi已连接,IP地址: {wlan.ifconfig()[0]}")
return wlan.ifconfig()[0]
# 初始化UDP套接字
def init_udp_socket():
try:
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
print("UDP套接字创建成功")
return sock
except Exception as e:
print(f"创建UDP套接字失败: {e}")
return None
# 主函数
def main():
try:
connect_wifi()
udp_sock = init_udp_socket()
if not udp_sock:
raise RuntimeError("UDP初始化失败")
print(f"目标S3: {UDP_TARGET_IP_S3}:{UDP_PORT_S3} | 目标灯带: {UDP_TARGET_IP_LIGHT}:{UDP_PORT_LIGHT}")
while True:
sensor_state = sensor.value() # 高电平=有人
# 控制本地状态灯
if local_led:
local_led.value(sensor_state)
# 发送屏幕显示指令
message_s3 = "HUMAN_DETECTED" if sensor_state else "NO_ONE"
udp_sock.sendto(message_s3.encode(), (UDP_TARGET_IP_S3, UDP_PORT_S3))
# 发送灯带控制指令(自定义协议,如"LIGHT:ON")
message_light = "LIGHT:ON" if sensor_state else "LIGHT:OFF"
udp_sock.sendto(message_light.encode(), (UDP_TARGET_IP_LIGHT, UDP_PORT_LIGHT))
print(f"传感器状态: {'有人' if sensor_state else '无人'}")
time.sleep(0.2)
except KeyboardInterrupt:
print("\n程序终止")
finally:
if udp_sock:
udp_sock.close()
if __name__ == "__main__":
main()
根据这四个代码帮我修改实现,就是有人经过时雷达传感器控制灯带使灯带亮起来,然后小智esp32s3串口屏上显示有人,其中这三个东西是独立的串口。小智esp32s3不控制灯带,雷达传感器控制灯带