2020-06-16 UDP验证OK。贴上软件代码。

udp.c

/* Esptouch example

   This example code is in the Public Domain (or CC0 licensed, at your option.)

   Unless required by applicable law or agreed to in writing, this
   software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
   CONDITIONS OF ANY KIND, either express or implied.
*/

#include <string.h>
#include <stdlib.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/event_groups.h"
#include "esp_wifi.h"
#include "esp_wpa2.h"
#include "esp_event_loop.h"
#include "esp_log.h"
#include "esp_err.h"
#include "esp_system.h"
#include "nvs_flash.h"
#include "tcpip_adapter.h"
#include "esp_smartconfig.h"
#include <sys/socket.h>
#include "udp_bsp.h"


#define LED_IO 22

#define KEY_REC_IO      36
#define KEY_MODE_IO     39

uint8_t  key_value = 0;
uint16_t timer_ms_cnt = 0;
uint16_t timer_1s_cnt = 0;
uint8_t  led_flag = 0;
//定时器句柄
esp_timer_handle_t fw_timer_handle = 0;


void read_key(void);
void fw_timer_cb(void *arg);





/* The event group allows multiple bits for each event,
   but we only care about one event - are we connected
   to the AP with an IP? */
static const int CONNECTED_BIT = BIT0;
static const int ESPTOUCH_DONE_BIT = BIT1;

static void user_app(void *pvParameters);
static void udp_connect(void *pvParameters);





void app_main()
{
	printf("app_main!\n");

   //选择 IO
   gpio_pad_select_gpio(LED_IO);
   gpio_pad_select_gpio(KEY_REC_IO);
   gpio_pad_select_gpio(KEY_MODE_IO);

   //设置 IO 为输出
   gpio_set_direction(LED_IO, GPIO_MODE_OUTPUT);
   gpio_set_level(LED_IO, 1);//不亮

   //设置按键 IO 输入
   gpio_set_direction(KEY_REC_IO, GPIO_MODE_INPUT);
   gpio_set_direction(KEY_MODE_IO, GPIO_MODE_INPUT);


   //定时器结构体初始化
   esp_timer_create_args_t fw_timer =
   {
      .callback = &fw_timer_cb, //回调函数
      .arg = NULL, //参数
      .name = "fw_timer" //定时器名称
   };

   //定时器创建、启动
   esp_err_t err = esp_timer_create(&fw_timer, &fw_timer_handle);
   err = esp_timer_start_periodic(fw_timer_handle, 1 * 1000);//1ms回调
   if(err == ESP_OK)
   {
      printf("fw timer cteate and start ok!\r\n");
   }



    //初始化flash
    esp_err_t ret = nvs_flash_init();
    if (ret == ESP_ERR_NVS_NO_FREE_PAGES)
    {
        ESP_ERROR_CHECK(nvs_flash_erase());
        ret = nvs_flash_init();
    }
    ESP_ERROR_CHECK(ret);

#if UDP_SERVER_CLIENT_OPTION
    //server,建立ap
    wifi_init_softap();
#else
    //client,建立sta
    wifi_init_sta();
#endif
    //新建一个udp连接任务
    xTaskCreate(&udp_connect, "udp_connect", 4096, NULL, 5, NULL);


    //新建一个app任务
    xTaskCreate(&user_app,       //任务函数名
                "user_app",      //任务名
                4096,               //栈大小,单位为字,即4个字节,设置太小堆栈会溢出
                NULL,               //任务形参
                8,                  //优先级,数值越大,优先级越高
                NULL                //句柄
                );

}




void read_key(void)
{
   static uint8_t cnt1 = 50;
   static uint8_t cnt2 = 50;

   if(gpio_get_level(KEY_REC_IO)==0)//按键按下
      cnt1++;
   else
      cnt1--;
   
   if(gpio_get_level(KEY_MODE_IO)==0)//按键按下
      cnt2++;
   else
      cnt2--;

   if(cnt1 > 52)
   {
      cnt1 = 50;
      key_value |= 0x01;
   }
   else if(cnt1 < 48)
   {
      cnt1 = 50;
      key_value &= ~0x01;
   }

   if(cnt2 > 52)
   {
      cnt2 = 50;
      key_value |= 0x02;
   }
   else if(cnt2 < 48)
   {
      cnt2 = 50;
      key_value &= ~0x02;
   }
}



void fw_timer_cb(void *arg)
{
   timer_ms_cnt++;
   timer_1s_cnt++;
}



/*
* 任务:建立UDP连接并从UDP接收数据
* @param[in]   void  		       :无
* @retval      void                :无
* @note        修改日志 
*               Ver0.0.1:
                    hx-zsj, 2018/08/10, 初始化版本\n 
*/
static void udp_connect(void *pvParameters)
{
    //等待WIFI连接成功事件,死等
    xEventGroupWaitBits(udp_event_group, WIFI_CONNECTED_BIT, false, true, portMAX_DELAY);
    ESP_LOGI(TAG, "start udp connected");

    //延时3S准备建立clien
    vTaskDelay(3000 / portTICK_RATE_MS);
    ESP_LOGI(TAG, "create udp Client");
    //建立client
    int socket_ret = create_udp_client();
    if (socket_ret == ESP_FAIL)
    {
        //建立失败
        ESP_LOGI(TAG, "create udp socket error,stop...");
        vTaskDelete(NULL);
    }
    else
    {
        //建立成功
        ESP_LOGI(TAG, "create udp socket succeed...");            
        //建立tcp接收数据任务
        if (pdPASS != xTaskCreate(&recv_data, "recv_data", 4096, NULL, 4, NULL))
        {
            //建立失败
            ESP_LOGI(TAG, "Recv task create fail!");
            vTaskDelete(NULL);
        }
        else
        {
            //建立成功
            ESP_LOGI(TAG, "Recv task create succeed!");
        }

    }
    vTaskDelete(NULL);
}






static void user_app(void *pvParameters)
{
    static uint8_t key_value_tmp = 0;

    while(1)
    {
        if(timer_ms_cnt > 10)   //10ms
        {
            timer_ms_cnt -= 10;
            read_key();
        }

        if(key_value_tmp != key_value)
        {
            key_value_tmp = key_value;
            printf("\r\nkey_value = 0x%.2x \n",key_value);
        }

        if(timer_1s_cnt >= 1000)   //1s
        {
            timer_1s_cnt -= 1000;   

            if(led_flag)
            {
                led_flag = 0;
                gpio_set_level(LED_IO, 1);    //led亮
            }
            else
            {
                led_flag = 1;
                gpio_set_level(LED_IO, 0);    //led灭
            }      


//            tcp_send_task();

        }

        vTaskDelay(10/ portTICK_RATE_MS);
    }
}

udp_bsp.c

/*
* @file         udp_bsp.c 
* @brief        wifi连接事件处理和socket收发数据处理
* @details      在官方源码的基础是适当修改调整,并增加注释
* @author       hx-zsj 
* @par Copyright (c):  

* @par History:          
*               Ver0.0.1:
                     hx-zsj, 2018/08/10, 初始化版本\n 
*/

/* 
=============
头文件包含
=============
*/
#include <string.h>
#include <sys/socket.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/event_groups.h"
#include "esp_wifi.h"
#include "esp_event_loop.h"
#include "esp_log.h"
#include "udp_bsp.h"

/*
===========================
全局变量定义
=========================== 
*/
EventGroupHandle_t udp_event_group;                     //wifi建立成功信号量

struct sockaddr_in client_addr;                  //client地址
static unsigned int socklen = sizeof(client_addr);      //地址长度
int connect_socket=0;                          //连接socket
/*
===========================
函数声明
=========================== 
*/

/*
* wifi 事件
* @param[in]   void  		       :无
* @retval      void                :无
* @note        修改日志 
*               Ver0.0.1:
                    hx-zsj, 2018/08/06, 初始化版本\n 
*/
static esp_err_t event_handler(void *ctx, system_event_t *event)
{
    switch (event->event_id)
    {
    case SYSTEM_EVENT_STA_START:        //STA模式-开始连接
        esp_wifi_connect();
        break;
    case SYSTEM_EVENT_STA_DISCONNECTED: //STA模式-断线
        esp_wifi_connect();
        xEventGroupClearBits(udp_event_group, WIFI_CONNECTED_BIT);
        break;
    case SYSTEM_EVENT_STA_CONNECTED:    //STA模式-连接成功
        xEventGroupSetBits(udp_event_group, WIFI_CONNECTED_BIT);
        break;
    case SYSTEM_EVENT_STA_GOT_IP:       //STA模式-获取IP
        ESP_LOGI(TAG, "got ip:%s\n",
                 ip4addr_ntoa(&event->event_info.got_ip.ip_info.ip));
        xEventGroupSetBits(udp_event_group, WIFI_CONNECTED_BIT);
        break;
    default:
        break;
    }
    return ESP_OK;
}



/*
* 接收数据任务
* @param[in]   void  		       :无
* @retval      void                :无
* @note        修改日志 
*               Ver0.0.1:
                    hx-zsj, 2018/08/06, 初始化版本\n 
*/
void recv_data(void *pvParameters)
{
    int len = 0;            //长度
    char databuff[1024];    //缓存
    while (1)
    {
        //清空缓存
        memset(databuff, 0x00, sizeof(databuff));

        //读取接收数据
		len = recvfrom(connect_socket, databuff, sizeof(databuff), 0,
				(struct sockaddr *) &client_addr, &socklen);
        if (len > 0)
        {
            //打印接收到的数组
            ESP_LOGI(TAG, "UDP Client recvData: %s", databuff);
            //接收数据回发
            sendto(connect_socket, databuff, strlen(databuff), 0,
			            (struct sockaddr *) &client_addr, sizeof(client_addr));
        }
        else
        {
            //打印错误信息
            show_socket_error_reason("UDP Client recv_data", connect_socket);
            break;
        }
    }
    close_socket();

    vTaskDelete(NULL);
}
/*
* 建立udp client
* @param[in]   void  		       :无
* @retval      void                :无
* @note        修改日志 
*               Ver0.0.1:
                    hx-zsj, 2018/08/06, 初始化版本\n 
*               Ver0.0.12:
                    hx-zsj, 2018/08/09, 增加close socket\n 
*/
esp_err_t create_udp_client()
{

    ESP_LOGI(TAG, "will connect gateway ssid : %s port:%d",
             UDP_ADRESS, UDP_PORT);
    //新建socket
    connect_socket = socket(AF_INET, SOCK_DGRAM, 0);                         /*参数和TCP不同*/
    if (connect_socket < 0)
    {
        //打印报错信息
        show_socket_error_reason("create client", connect_socket);
        //新建失败后,关闭新建的socket,等待下次新建
        close(connect_socket);
        return ESP_FAIL;
    }
    //配置连接服务器信息
    client_addr.sin_family = AF_INET;
    client_addr.sin_port = htons(UDP_PORT);
    client_addr.sin_addr.s_addr = inet_addr(UDP_ADRESS);
    

    int len = 0;            //长度
    char databuff[1024] = "Hello Server,Please ack!!";    //缓存
    //测试udp server,返回发送成功的长度
	len = sendto(connect_socket, databuff, 1024, 0, (struct sockaddr *) &client_addr,
			sizeof(client_addr));
	if (len > 0) {
		ESP_LOGI(TAG, "Transfer data to %s:%u,ssucceed\n",
				inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port));
	} else {
        show_socket_error_reason("recv_data", connect_socket);
		close(connect_socket);
		return ESP_FAIL;
	}
    return ESP_OK;
}


/*
* WIFI作为STA的初始化
* @param[in]   void  		       :无
* @retval      void                :无
* @note        修改日志 
*               Ver0.0.1:
                    hx-zsj, 2018/08/06, 初始化版本\n 
*/
void wifi_init_sta()
{
    udp_event_group = xEventGroupCreate();
    tcpip_adapter_init();
    ESP_ERROR_CHECK(esp_event_loop_init(event_handler, NULL));
    wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
    ESP_ERROR_CHECK(esp_wifi_init(&cfg));
    wifi_config_t wifi_config = {
        .sta = {
            .ssid = GATEWAY_SSID,           //STA账号
            .password = GATEWAY_PAS},       //STA密码
    };
    ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));
    ESP_ERROR_CHECK(esp_wifi_set_config(ESP_IF_WIFI_STA, &wifi_config));
    ESP_ERROR_CHECK(esp_wifi_start());

    ESP_LOGI(TAG, "wifi_init_sta finished.");
    ESP_LOGI(TAG, "connect to ap SSID:%s password:%s \n",
             GATEWAY_SSID, GATEWAY_PAS);
}

/*
* 获取socket错误代码
* @param[in]   socket  		       :socket编号
* @retval      void                :无
* @note        修改日志 
*               Ver0.0.1:
                    hx-zsj, 2018/08/06, 初始化版本\n 
*/
int get_socket_error_code(int socket)
{
    int result;
    u32_t optlen = sizeof(int);
    int err = getsockopt(socket, SOL_SOCKET, SO_ERROR, &result, &optlen);
    if (err == -1)
    {
        //WSAGetLastError();
        ESP_LOGE(TAG, "socket error code:%d", err);
        // ESP_LOGE(TAG, "socket error code:%s", strerror(err));
        return -1;
    }
    return result;
}

/*
* 获取socket错误原因
* @param[in]   socket  		       :socket编号
* @retval      void                :无
* @note        修改日志 
*               Ver0.0.1:
                    hx-zsj, 2018/08/06, 初始化版本\n 
*/
int show_socket_error_reason(const char *str, int socket)
{
    int err = get_socket_error_code(socket);

    if (err != 0)
    {
        ESP_LOGW(TAG, "%s socket error reason %d %s", str, err, strerror(err));
    }

    return err;
}
/*
* 检查socket
* @param[in]   socket  		       :socket编号
* @retval      void                :无
* @note        修改日志 
*               Ver0.0.1:
                    hx-zsj, 2018/08/06, 初始化版本\n 
*/
int check_working_socket()
{
    int ret;

    ESP_LOGD(TAG, "check connect_socket");
    ret = get_socket_error_code(connect_socket);
    if (ret != 0)
    {
        ESP_LOGW(TAG, "connect socket error %d %s", ret, strerror(ret));
    }
    if (ret != 0)
    {
        return ret;
    }
    return ret;
}
/*
* 关闭socket
* @param[in]   socket  		       :socket编号
* @retval      void                :无
* @note        修改日志 
*               Ver0.0.1:
                    hx-zsj, 2018/08/06, 初始化版本\n 
*/
void close_socket()
{
    close(connect_socket);
}

udp_bsp.h

#ifndef __UDP_BSP_H__
#define __UDP_BSP_H__



#ifdef __cplusplus
extern "C" {
#endif


#ifndef FALSE
#define FALSE 0
#endif

#ifndef TRUE
#define TRUE (!FALSE)
#endif

#define UDP_SERVER_CLIENT_OPTION FALSE              //esp32作为client
#define TAG                     "\r\nCLZY-UDP"            //打印的tag

//client
//STA模式配置信息,即要连上的路由器的账号密码
#define GATEWAY_SSID            "M"         //账号
#define GATEWAY_PAS             "123456"       //密码
// #define GATEWAY_SSID            "stop"               //账号
// #define GATEWAY_PAS             "11111111111"       //密码
#define UDP_ADRESS              "255.255.255.255"   //作为client,要连接UDP服务器的地址
                                                    //如果为255.255.255.255:UDP广播
                                                    //如果为192.168.169.205:UDP单播:根据自己的server写

#define UDP_PORT                12345               //统一的端口号,包括UDP客户端或者服务端


// FreeRTOS event group to signal when we are connected to wifi
#define WIFI_CONNECTED_BIT BIT0
extern EventGroupHandle_t udp_event_group;

//wifi作为sta
void wifi_init_sta();

//创建USP client
esp_err_t create_udp_client();

//收发数据
void recv_data(void *pvParameters);

//close all socket
void close_socket();

//get socket error code. return: error code
int get_socket_error_code(int socket);

//show socket error code. return: error code
int show_socket_error_reason(const char* str, int socket);

//check working socket
int check_working_socket();


#ifdef __cplusplus
}
#endif


#endif /*#ifndef __UDP_BSP_H__*/