侧边栏壁纸
  • 累计撰写 10 篇文章
  • 累计创建 1 个标签
  • 累计收到 1 条评论

目 录CONTENT

文章目录

ESP32 和 CH32V307 UDP通信

Z_Tam
2022-07-18 / 0 评论 / 0 点赞 / 639 阅读 / 12573 字

简述:使用ESP32实现在同一局域网内通过UDP进行通信及控制。
功能:ESP32通过电容屏控制及显示CH32V307开发板LED的状态。
详细资料:请关注公众号《跳跃的影子》并发送“ ESP32 和 CH32V307 UDP通信 ”获取。

CH32V307

硬件说明

  • 系统框图
    • 网口不需要phy芯片,支持10M通信。
  • 开发板正面
    • 左侧
      • type-c供电口下载口串口
      • 开关:只有通过左侧type-c供电时才受控制。
      • 按键:复位按键、用户按键。
    • 右侧
      • type-c
      • 网口。
    • LED
      • 两按键间的两个LED灯只连接到了排针上,未连接芯片,需要跳线。
  • 开发板背面。

软件说明

  • 开发环境使用RT-Thread Studio(2.2.4)。
    • RT-Thread_Source_Code:4.1.0
    • CH32V307V-R1:1.0.8
    • RISC-V-GCC-WCH:8.2.0
  • 使能ETH
  • 使能网络接口设备TCP/IP
void udpserv(void)
{
    int sock;
    int bytes_read;
    char *recv_data;
    rt_uint32_t addr_len;
    struct sockaddr_in server_addr, client_addr;

    /* 分配接收用的数据缓冲 */
    recv_data = rt_malloc(1024);
    if (recv_data == RT_NULL)
    {
        /* 分配内存失败,返回 */
        rt_kprintf("No memory\n");
        return;
    }

    /* 创建一个socket,类型是SOCK_DGRAM,UDP类型 */
    if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
    {
        rt_kprintf("Socket error\n");

        /* 释放接收用的数据缓冲 */
        rt_free(recv_data);
        return;
    }

    /* 初始化服务端地址 */
    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(5000);             /* _端口_ */
    server_addr.sin_addr.s_addr = INADDR_ANY;
    rt_memset(&(server_addr.sin_zero), 0, sizeof(server_addr.sin_zero));

    /* 绑定socket到服务端地址 */
    if (bind(sock, (struct sockaddr *) &server_addr, sizeof(struct sockaddr))
            == -1)
    {
        /* 绑定地址失败 */
        rt_kprintf("Bind error\n");

        /* 释放接收用的数据缓冲 */
        rt_free(recv_data);
        return;
    }

    addr_len = sizeof(struct sockaddr);
    rt_kprintf("\nUDPServer Waiting for client on port 5000...\n");

    while (1)
    {
        /* 从sock中收取最大1024字节数据 (堵塞接收) */
        bytes_read = recvfrom(sock, recv_data, 1024, 0,(struct sockaddr *) &client_addr, &addr_len);
        /* UDP不同于TCP,它基本不会出现收取的数据失败的情况,除非设置了超时等待 */

        recv_data[bytes_read] = '\0'; /* 把末端清零 */

        /* 返回led状态 */
        if(strcmp(recv_data, "led0_check") == 0){
            rt_kprintf("led0_check \n");
            if(GPIO_ReadOutputDataBit(GPIOA, GPIO_Pin_0) == 1){
                sendto(sock, "led0_ack0", 9, 0,
                      (struct sockaddr *) &client_addr, sizeof(struct sockaddr));
                rt_kprintf("led0_ack0 \n");
            }else if(GPIO_ReadOutputDataBit(GPIOA, GPIO_Pin_0) == 0){
                sendto(sock, "led0_ack1", 9, 0,
                      (struct sockaddr *) &client_addr, sizeof(struct sockaddr));
                rt_kprintf("led0_ack1 \n");
            }
        }
        /* led0 */
        else if (strcmp(recv_data, "led0_off") == 0)
        {
            GPIO_SetBits(GPIOA,GPIO_Pin_0);
            sendto(sock, "led0_ack0", 9, 0,
                  (struct sockaddr *) &client_addr, sizeof(struct sockaddr));
            rt_kprintf("led0 off success \n");
        }
        else if (strcmp(recv_data, "led0_on") == 0)
        {
            GPIO_ResetBits(GPIOA,GPIO_Pin_0);
            sendto(sock, "led0_ack1", 9, 0,
                              (struct sockaddr *) &client_addr, sizeof(struct sockaddr));
            rt_kprintf("led0 on success \n");
        }
        /* pwm */
        else if (strncmp(recv_data, "led1:", 5) == 0)
        {
            //rt_kprintf("%s \n", recv_data+5);

            TIM1->CH1CVR=atoi(recv_data+5);
        }
        /* 退出 */
        else if (strcmp(recv_data, "exit") == 0) /* 如果接收数据是exit,退出 */
        {
            lwip_close(sock);

            /* 释放接收用的数据缓冲 */
            rt_free(recv_data);
            break;
        }
        /* 其他数据直接返回 */
        else
        {
            /* 输出接收的数据 */
            rt_kprintf("\n(%s, %d) said : ", inet_ntoa(client_addr.sin_addr), ntohs(server_addr.sin_port));
            rt_kprintf("%s", recv_data);
            /* 回发 */
            sendto(sock, recv_data, bytes_read, 0,
                  (struct sockaddr *) &client_addr, sizeof(struct sockaddr));
        }


    }

    return;
}
MSH_CMD_EXPORT(udpserv,  udpserv sample);
  • 下载选项
    • Chip Mem:连接上芯片后,选择192K ROM + 128K RAM后点击Set
    • 文件选择.hex

ESP32

硬件说明

  • 裸板正面。
    • 2.0寸(240*320)电容触摸屏。
    • 右上角:sht30温湿度传感器、电源指示灯。
    • 右下角:MPU6050、按键。
  • 裸板背面。
    • 左侧:ESP32。
    • 右侧:供电口下载口调试口
  • 3D打印外壳正面。
  • 通电LCD显示效果。

软件说明

  • VS Code

    • ESP-IDF:4.3
    • FreeRTOS
    • LIWP
    • LVGL:7.9.0
    • GUI-Guider1.3.0-GA
  • 使用Kconfig文件给配置菜单添加相关配置项。

  • 打开配置菜单。
menu "IP Configuration"

    choice EXAMPLE_IP_MODE
        prompt "IP Version"
        depends on EXAMPLE_SOCKET_IP_INPUT_STRING
        help
            Example can use either IPV4 or IPV6.

        config EXAMPLE_IPV4
            bool "IPV4"

        config EXAMPLE_IPV6
            bool "IPV6"
            select EXAMPLE_CONNECT_IPV6

    endchoice

    config EXAMPLE_IPV4_ADDR
        string "IPV4 Address"
        default "192.168.0.165"
        depends on EXAMPLE_IPV4
        help
            IPV4 address to which the client example will send data.

    config EXAMPLE_IPV6_ADDR
        string "IPV6 Address"
        default "FE80::30AD:E57B:C212:68AD"
        depends on EXAMPLE_IPV6
        help
            IPV6 address to which the client example will send data.

    config EXAMPLE_PORT
        int "Port"
        range 0 65535
        default 3333
        help
            The remote port to which the client example will send data.

    choice EXAMPLE_SOCKET_IP_INPUT
        prompt "Socket example source"
        default EXAMPLE_SOCKET_IP_INPUT_STRING
        help
            Selects the input source of the IP used in the example.

        config EXAMPLE_SOCKET_IP_INPUT_STRING
            bool "From string"

        config EXAMPLE_SOCKET_IP_INPUT_STDIN
            bool "From stdin"
    endchoice

endmenu
  • UDP主要逻辑代码。
static void udp_client_task(void *pvParameters)
{
    char rx_buffer[128];
    char host_ip[] = HOST_IP_ADDR;
    int addr_family = 0;
    int ip_protocol = 0;
    ESP_LOGI(TAG, "udp start!");
    while (1) {
        
        dest_addr.sin_addr.s_addr = inet_addr(HOST_IP_ADDR);
        dest_addr.sin_family = AF_INET;
        dest_addr.sin_port = htons(PORT);
        addr_family = AF_INET;
        ip_protocol = IPPROTO_IP;
        socklen_t socklen = sizeof(dest_addr);

        sock = socket(addr_family, SOCK_DGRAM, ip_protocol);
        if (sock < 0) {
            ESP_LOGE(TAG, "Unable to create socket: errno %d", errno);
            break;
        }
        ESP_LOGI(TAG, "Socket created, sending to %s:%d", HOST_IP_ADDR, PORT);

        sendto(sock, "led0_check", 10, 0, (struct sockaddr *)&dest_addr, sizeof(dest_addr));      /* 查询状态 */
        vTaskDelay(1000 / portTICK_PERIOD_MS);

        while (1) {
            /* 接收函数 */
            int len = recvfrom(sock, rx_buffer, sizeof(rx_buffer) - 1, 0, (struct sockaddr *)&dest_addr, &socklen);
     
            rx_buffer[len] = 0;                                             /* 接收最后一字节为结束符 */
            /* 处理函数 */
            /* led0 */
            if (strcmp(rx_buffer, "led0_ack0") == 0)
            {
                lv_led_off(guider_ui.screen_led_1);
                ESP_LOGI(TAG, "led0_off");
            }
            else if(strcmp(rx_buffer, "led0_ack1") == 0)
            {
                lv_led_on(guider_ui.screen_led_1);
                ESP_LOGI(TAG, "led0_on");
            }
            else
            {
                ESP_LOGI(TAG, "Received %d  from %s:", len, inet_ntoa(dest_addr.sin_addr));      /* 接收长度,接收IP */
                ESP_LOGI(TAG, "%s", rx_buffer);
            }

            /* 退出循环 */
            if (strncmp(rx_buffer, "OK: ", 4) == 0) {
                ESP_LOGI(TAG, "Received expected message, reconnecting");
                break;
            }

            /* 延时 */
            vTaskDelay(500 / portTICK_PERIOD_MS);
        }

        if (sock != -1) {
            ESP_LOGE(TAG, "Shutting down socket and restarting...");
            shutdown(sock, 0);
            close(sock);
        }
    }
    vTaskDelete(NULL);
}

  • events_init.c中添加lvgl相关的事件驱动。
/*
 * Copyright 2022 NXP
 * SPDX-License-Identifier: MIT
 */

#include "events_init.h"
#include <stdio.h>
#include "lvgl/lvgl.h"
#if !LV_USE_GUIDER_SIMULATOR
#include "lwip/sockets.h"
static unsigned int counter = 0;
extern struct sockaddr_in dest_addr;
extern int sock;
#endif



void events_init(lv_ui *ui)
{
}

static void screen_led0_onevent_handler(lv_obj_t * obj, lv_event_t event)
{
	switch (event)
	{
	case LV_EVENT_PRESSED:
	{
		#if !LV_USE_GUIDER_SIMULATOR
		sendto(sock, "led0_on", 7, 0, (struct sockaddr *)&dest_addr, sizeof(dest_addr));
		#endif
	}
		break;
	default:
		break;
	}
}

static void screen_led0_offevent_handler(lv_obj_t * obj, lv_event_t event)
{
	switch (event)
	{
	case LV_EVENT_PRESSED:
	{
		#if !LV_USE_GUIDER_SIMULATOR
		sendto(sock, "led0_off", 8, 0, (struct sockaddr *)&dest_addr, sizeof(dest_addr));
		#endif
	}
		break;
	default:
		break;
	}
}

static void screen_slider_1event_handler(lv_obj_t * obj, lv_event_t event)
{
	switch (event)
	{
	case LV_EVENT_VALUE_CHANGED:
	{
		#if !LV_USE_GUIDER_SIMULATOR
		static char buf[20]={0};
		sprintf(buf, "led1:%03d", lv_slider_get_value(guider_ui.screen_slider_1));
		sendto(sock, buf, 8, 0, (struct sockaddr *)&dest_addr, sizeof(dest_addr));
		#endif
	}
		break;
	default:
		break;
	}
}

void events_init_screen(lv_ui *ui)
{
	lv_obj_set_event_cb(ui->screen_led0_on, screen_led0_onevent_handler);
	lv_obj_set_event_cb(ui->screen_led0_off, screen_led0_offevent_handler);
	lv_obj_set_event_cb(ui->screen_slider_1, screen_slider_1event_handler);
}

视频

0

评论区