ESP32 AP+TCP通信实现ADC采集数据传输

sui整个工程可以分为三大部分:WIFI_AP模式的实现,TCP协议的创建与开启ADC单次采集与传输

一、WIFI_AP的实现

        ESP32支持AP、STA、AP&STA模式,这里我们通过PC连接ESP32_AP方式。

        ESP32-IDF提供了各个模块部分的搭建:WIFI_AP参考于wifi目录下的sofAP

        代码如下:

#ifndef WiFIAP_H_
#define WifiAP_H_

#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_mac.h"
#include "esp_wifi.h"
#include "esp_event.h"
#include "esp_log.h"
#include "nvs_flash.h"

#include "lwip/err.h"
#include "lwip/sys.h"
#include "sdkconfig.h"

#define EXAMPLE_ESP_WIFI_SSID      "XHL"
#define EXAMPLE_ESP_WIFI_PASS      "12345678"
#define EXAMPLE_ESP_WIFI_CHANNEL   1
#define EXAMPLE_MAX_STA_CONN       4


// static void wifi_event_handler(void* arg, esp_event_base_t event_base,
//                                     int32_t event_id, void* event_data);
void wifi_init_softap(void);

#endif
#include "WiFiAP.h"

static const char *TAG = "AP";

static void wifi_event_handler(void *arg, esp_event_base_t event_base,
                               int32_t event_id, void *event_data)
{
    if (event_id == WIFI_EVENT_AP_STACONNECTED)
    {
        wifi_event_ap_staconnected_t *event = (wifi_event_ap_staconnected_t *)event_data;
        ESP_LOGI(TAG, "station " MACSTR " join, AID=%d",
                 MAC2STR(event->mac), event->aid);
    }
    else if (event_id == WIFI_EVENT_AP_STADISCONNECTED)
    {
        wifi_event_ap_stadisconnected_t *event = (wifi_event_ap_stadisconnected_t *)event_data;
        ESP_LOGI(TAG, "station " MACSTR " leave, AID=%d",
                 MAC2STR(event->mac), event->aid);
    }
}

void wifi_init_softap(void)
{
    // ESP_ERROR_CHECK(esp_netif_init());    //初始化底层TCP/IP协议栈,底层创建任务task
    // ESP_ERROR_CHECK(esp_event_loop_create_default());   //创建event_task
    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());
        ret = nvs_flash_init();
    }
    ESP_ERROR_CHECK(ret);

    ESP_LOGI(TAG, "ESP_WIFI_MODE_AP");
    ESP_ERROR_CHECK(esp_netif_init()); // 建立lwip协议栈
    ESP_ERROR_CHECK(esp_event_loop_create_default());
    esp_netif_create_default_wifi_ap();

    wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
    ESP_ERROR_CHECK(esp_wifi_init(&cfg)); // 初始化WIFI Driver

    ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT,
                                                        ESP_EVENT_ANY_ID,
                                                        &wifi_event_handler,
                                                        NULL,
                                                        NULL)); // 注册WIFI事件处理函数,将事件注册到loop循环中

    wifi_config_t wifi_config = {
        // 配置WIFI Driver
        .ap = {
            .ssid = EXAMPLE_ESP_WIFI_SSID,
            .ssid_len = strlen(EXAMPLE_ESP_WIFI_SSID),
            .channel = EXAMPLE_ESP_WIFI_CHANNEL,
            .password = EXAMPLE_ESP_WIFI_PASS,
            .max_connection = EXAMPLE_MAX_STA_CONN,
#ifdef CONFIG_ESP_WIFI_SOFTAP_SAE_SUPPORT
            .authmode = WIFI_AUTH_WPA3_PSK,
            .sae_pwe_h2e = WPA3_SAE_PWE_BOTH,
#else /* CONFIG_ESP_WIFI_SOFTAP_SAE_SUPPORT */
            .authmode = WIFI_AUTH_WPA2_PSK,
#endif
            .pmf_cfg = {
                .required = true,
            },
        },
    };
    if (strlen(EXAMPLE_ESP_WIFI_PASS) == 0)
    {
        wifi_config.ap.authmode = WIFI_AUTH_OPEN;
    }

    ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_AP));
    ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_AP, &wifi_config)); // 设置配置
    ESP_ERROR_CHECK(esp_wifi_start());                              // 启动WIFI_Driver

    ESP_LOGI(TAG, "wifi_init_softap finished. SSID:%s password:%s channel:%d",
             EXAMPLE_ESP_WIFI_SSID, EXAMPLE_ESP_WIFI_PASS, EXAMPLE_ESP_WIFI_CHANNEL);
}

在B站发现一个UP主讲得很好,将AP模式的流程基本理清,这里粘贴出来

大致流程是先通过    ESP_ERROR_CHECK(esp_netif_init()); 建立lwip协议栈然后esp_wifi_init()初始化WIFI_AP,随便建立回调处理的相关函数,其实基于ESP-IDF也可以理清AP模式的初始化流程

二、TCP协议的传输

        参考于TCP_server,并对于官方的代码进行一定修改,主要是修改do_transmit函数,避免其因为do while而一直循环,

        

#ifndef WiFITCP_H_
#define WiFiTCP_H_

#include "lwip/err.h"
#include "lwip/sockets.h"
#include "lwip/sys.h"
#include <lwip/netdb.h>
#include <string.h>
#include <sys/param.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_netif.h"
#include "WiFiAP.h"

#define PORT                        CONFIG_EXAMPLE_PORT
#define KEEPALIVE_IDLE              CONFIG_EXAMPLE_KEEPALIVE_IDLE
#define KEEPALIVE_INTERVAL          CONFIG_EXAMPLE_KEEPALIVE_INTERVAL
#define KEEPALIVE_COUNT             CONFIG_EXAMPLE_KEEPALIVE_COUNT
void TCP_TASK();
// static esp_err_t creat_listen_socket();
esp_err_t send_message(char* buf, int _size);
esp_err_t send_message_test(int buf, int _size);
#endif
#include "WiFiTCP.h"

static const char *TAG = "TCP";
static int sock = 0;
static int listen_sock;

int do_retransmit(int sock)
{
    int len;
    char rx_buffer[128];
    int temp_sock = 0;
    temp_sock = sock;

    len = recv(sock, rx_buffer, sizeof(rx_buffer) - 1, 0);
    if (len < 0)
    {
        ESP_LOGE(TAG, "Error occurred during receiving: errno %d", errno);
        temp_sock = 0;
        return temp_sock;
    }
    else if (len == 0)
    {
        ESP_LOGW(TAG, "Connection closed");
        temp_sock = 0;
        return temp_sock;
    }
    else
    {
        rx_buffer[len] = 0; // Null-terminate whatever is received and treat it like a string
        ESP_LOGI(TAG, "Received %d bytes: %s", len, rx_buffer);

        // send() can return less bytes than supplied length.
        // Walk-around for robust implementation.
        int to_write = len;
        while (to_write > 0)
        {
            int written = send(sock, rx_buffer + (len - to_write), to_write, 0);
            if (written < 0)
            {
                ESP_LOGE(TAG, "Error occurred during sending: errno %d", errno);
                // Failed to retransmit, giving up
            }
            to_write -= written;
        }
    }
    return temp_sock;
}

static esp_err_t creat_listen_socket()
{
    int addr_family = AF_INET;
    int ip_protocol = 0;
    struct sockaddr_storage dest_addr;

    struct sockaddr_in *dest_addr_ip4 = (struct sockaddr_in *)&dest_addr;
    dest_addr_ip4->sin_addr.s_addr = htonl(INADDR_ANY);
    dest_addr_ip4->sin_family = AF_INET;
    dest_addr_ip4->sin_port = htons(PORT);
    ip_protocol = IPPROTO_IP;

    listen_sock = socket(addr_family, SOCK_STREAM, ip_protocol); // 创建监听
    if (listen_sock < 0)
    {
        ESP_LOGE(TAG, "Unable to create socket: errno %d", errno);
        vTaskDelete(NULL);
        goto CLEAN_UP;
    }
    ESP_LOGI(TAG, "listen_sock created");

    int opt = 1;
    setsockopt(listen_sock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
    setsockopt(listen_sock, IPPROTO_IPV6, IPV6_V6ONLY, &opt, sizeof(opt));
    ESP_LOGI(TAG, "Socket created");

    int err = bind(listen_sock, (struct sockaddr *)&dest_addr, sizeof(dest_addr)); // 绑定监听sock到端口
    if (err != 0)
    {
        ESP_LOGE(TAG, "Socket unable to bind: errno %d", errno);
        ESP_LOGE(TAG, "IPPROTO: %d", addr_family);
        goto CLEAN_UP;
    }
    ESP_LOGI(TAG, "Socket bound, port %d", PORT);

    err = listen(listen_sock, 1); // 启动监听
    if (err != 0)
    {
        ESP_LOGE(TAG, "Error occurred during listen: errno %d", errno);
        goto CLEAN_UP;
    }
    ESP_LOGI(TAG, "Listen loop....");
    return ESP_OK;

CLEAN_UP:
    close(listen_sock);
    vTaskDelete(NULL);
    return -1;
}

static void tcp_server_task(void *pvParameters)
{
    char addr_str[128];
    // int addr_family = (int)pvParameters;
    // int ip_protocol = 0;
    int keepAlive = 1;
    int keepIdle = KEEPALIVE_IDLE;
    int keepInterval = KEEPALIVE_INTERVAL;
    int keepCount = KEEPALIVE_COUNT;
    // struct sockaddr_storage dest_addr;
    creat_listen_socket(); // 创建listen并启动
    // #ifdef CONFIG_EXAMPLE_IPV4
    //     if (addr_family == AF_INET)
    //     {
    //         struct sockaddr_in *dest_addr_ip4 = (struct sockaddr_in *)&dest_addr;
    //         dest_addr_ip4->sin_addr.s_addr = htonl(INADDR_ANY);
    //         dest_addr_ip4->sin_family = AF_INET;
    //         dest_addr_ip4->sin_port = htons(PORT);
    //         ip_protocol = IPPROTO_IP;
    //     }
    // #endif

    // int listen_sock = socket(addr_family, SOCK_STREAM, ip_protocol); // 创建监听
    // if (listen_sock < 0)
    // {
    //     ESP_LOGE(TAG, "Unable to create socket: errno %d", errno);
    //     vTaskDelete(NULL);
    //     return;
    // }
    //     int opt = 1;
    //     setsockopt(listen_sock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
    // #if defined(CONFIG_EXAMPLE_IPV4) && defined(CONFIG_EXAMPLE_IPV6)
    //     // Note that by default IPV6 binds to both protocols, it is must be disabled
    //     // if both protocols used at the same time (used in CI)
    //     setsockopt(listen_sock, IPPROTO_IPV6, IPV6_V6ONLY, &opt, sizeof(opt));
    // #endif

    // int err = bind(listen_sock, (struct sockaddr *)&dest_addr, sizeof(dest_addr)); // 绑定监听sock到端口
    // if (err != 0)
    // {
    //     ESP_LOGE(TAG, "Socket unable to bind: errno %d", errno);
    //     ESP_LOGE(TAG, "IPPROTO: %d", addr_family);
    //     goto CLEAN_UP;
    // }
    // ESP_LOGI(TAG, "Socket bound, port %d", PORT);

    // err = listen(listen_sock, 1); // 检测端口是否发生连接
    // if (err != 0)
    // {
    //     ESP_LOGE(TAG, "Error occurred during listen: errno %d", errno);
    //     goto CLEAN_UP;
    // }
    while (1)
    {
        if (sock == 0)
        {
            ESP_LOGI(TAG, "Socket listening");

            struct sockaddr_storage source_addr; // Large enough for both IPv4 or IPv6
            socklen_t addr_len = sizeof(source_addr);
            sock = accept(listen_sock, (struct sockaddr *)&source_addr, &addr_len); // 接受当前的连接
            if (sock < 0)
            {
                ESP_LOGE(TAG, "Unable to accept connection: errno %d", errno);
                break;
            }

            // Set tcp keepalive option                                 //对接受的连接进行设置
            setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, &keepAlive, sizeof(int));
            setsockopt(sock, IPPROTO_TCP, TCP_KEEPIDLE, &keepIdle, sizeof(int));
            setsockopt(sock, IPPROTO_TCP, TCP_KEEPINTVL, &keepInterval, sizeof(int));
            setsockopt(sock, IPPROTO_TCP, TCP_KEEPCNT, &keepCount, sizeof(int));

            // Convert ip address to string
#ifdef CONFIG_EXAMPLE_IPV4
            if (source_addr.ss_family == PF_INET)
            {
                inet_ntoa_r(((struct sockaddr_in *)&source_addr)->sin_addr, addr_str, sizeof(addr_str) - 1);
            }
#endif
            ESP_LOGI(TAG, "Socket accepted ip address: %s", addr_str);
        }
        else if (sock > 0)
        {
            sock = do_retransmit(sock);
        }

        // do_retransmit(sock); // 在此处进行数据的接受和发送
        // send(sock,"ho",sizeof("ho"),0);
    }
    shutdown(sock, 0);
    close(sock);
}

void TCP_TASK()
{
    ESP_LOGI(TAG, "TCP_TASK_Creating");
    xTaskCreate(tcp_server_task, "tcp_server", 4096, (void *)AF_INET, 5, NULL);
}

esp_err_t send_message(char* buf, int _size)
{
     ESP_LOGE(TAG, "Tring");
    if (sock <= 0)
    {
         ESP_LOGI(TAG,"ERROR");
        return -1;
       
    }
    int ret = send(sock, buf, _size, 0);
    if (ret < 0)
    {
        ESP_LOGE(TAG, "ERROR occurred during sneding : errmo %d", errno);
        return -1;
    }
    
    return ESP_OK;
}

esp_err_t send_message_test(int buf, int _size)
{
     ESP_LOGE(TAG, "Tring");
    if (sock <= 0)
    {
         ESP_LOGI(TAG,"ERROR");
        return -1;
       
    }
    int ret = send(sock, buf, _size, 0);
    if (ret < 0)
    {
        ESP_LOGE(TAG, "ERROR occurred during sneding : errmo %d", errno);
        return -1;
    }
    
    return ESP_OK;
}

对于TCP_server其实其初始化也是有固定流程,对应上面的初始化和官方的demo可以很快理清,

 只看服务端就是先socket()、blind()、listen()、accept() 然后就是数据传输了

除了与官方demo一样接受上位机rev然后write之外,也单独将发送函数写出来方便ADC采样后可以上传数据,所用到的是send()函数,也即是lwip_sned(sock,const void *data,size);

buf是一个数组,将ADC采样和需要的数据通过sprintf函数合并然后放进去,当然不论什么数据类型都可以这里只是为了VOFA上位机的数据特殊格式而已;

三、ADC

        ADC我用的是单次采样,连续采样我只是单独实现过感觉有点麻烦单次足够了,下面是对应代码:

#ifndef ADC_TCP_H_
#define ADC_TCP_H_

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "soc/soc_caps.h"
#include "esp_log.h"
#include "esp_adc/adc_oneshot.h"
#include "esp_adc/adc_cali.h"
#include "esp_adc/adc_cali_scheme.h"
#include "WiFiTCP.h"


void ADC_START();

#endif
#include "ADC_TCP.h"

static const char *TAG = "ADC";

#define EXAMPLE_ADC1_CHAN ADC_CHANNEL_1
#define EXAMPLE_ADC_ATTEN ADC_ATTEN_DB_11

static int adc_raw = 0;
static int voltage = 0;
static bool example_adc_calibration_init(adc_unit_t unit, adc_channel_t channel, adc_atten_t atten, adc_cali_handle_t *out_handle);
static void example_adc_calibration_deinit(adc_cali_handle_t handle);

void ADC_task(void)
{
    //-------------ADC1 Init---------------//
    adc_oneshot_unit_handle_t adc1_handle;
    adc_oneshot_unit_init_cfg_t init_config1 = {
        .unit_id = ADC_UNIT_1,
    };
    ESP_ERROR_CHECK(adc_oneshot_new_unit(&init_config1, &adc1_handle));

    //-------------ADC1 Config---------------//
    adc_oneshot_chan_cfg_t config = {
        .bitwidth = ADC_BITWIDTH_DEFAULT,
        .atten = EXAMPLE_ADC_ATTEN,
    };
    ESP_ERROR_CHECK(adc_oneshot_config_channel(adc1_handle, EXAMPLE_ADC1_CHAN, &config));

    adc_cali_handle_t adc1_cali_chan_handle = NULL;
    bool do_calibration1_chan = example_adc_calibration_init(ADC_UNIT_1, EXAMPLE_ADC1_CHAN, EXAMPLE_ADC_ATTEN, &adc1_cali_chan_handle);

    char buff[20]={0};
    while (1)
    {
        ESP_ERROR_CHECK(adc_oneshot_read(adc1_handle, EXAMPLE_ADC1_CHAN, &adc_raw));
        ESP_LOGI(TAG, "ADC%d Channel[%d] Raw Data: %d", ADC_UNIT_1 + 1, EXAMPLE_ADC1_CHAN, adc_raw);
        if (do_calibration1_chan)
        {
            ESP_ERROR_CHECK(adc_cali_raw_to_voltage(adc1_cali_chan_handle, adc_raw, &voltage));
            ESP_LOGI(TAG, "ADC%d Channel[%d] Cali Voltage: %d mV", ADC_UNIT_1 + 1, EXAMPLE_ADC1_CHAN, voltage);
            sprintf(buff,"%d%s",voltage,"\n");
            send_message(buff, strlen(buff));
            ESP_LOGI(TAG,"Buff:%s",buff);

        }
        vTaskDelay(pdMS_TO_TICKS(1));
    }
    ESP_ERROR_CHECK(adc_oneshot_del_unit(adc1_handle));
    if (do_calibration1_chan)
    {
        example_adc_calibration_deinit(adc1_cali_chan_handle);
    }
}

void ADC_START()
{
    ESP_LOGI(TAG, "ADC_TASK_Creating...");
    xTaskCreate((void *)ADC_task, "ADC TASK", 4096, NULL, 5, NULL);
}

static bool example_adc_calibration_init(adc_unit_t unit, adc_channel_t channel, adc_atten_t atten, adc_cali_handle_t *out_handle)
{
    adc_cali_handle_t handle = NULL;
    esp_err_t ret = ESP_FAIL;
    bool calibrated = false;

    if (!calibrated)
    {
        ESP_LOGI(TAG, "calibration scheme version is %s", "Curve Fitting");
        adc_cali_curve_fitting_config_t cali_config = {
            .unit_id = unit,
            .chan = channel,
            .atten = atten,
            .bitwidth = ADC_BITWIDTH_DEFAULT,
        };
        ret = adc_cali_create_scheme_curve_fitting(&cali_config, &handle);
        if (ret == ESP_OK)
        {
            calibrated = true;
        }
    }
    *out_handle = handle;
    if (ret == ESP_OK)
    {
        ESP_LOGI(TAG, "Calibration Success");
    }
    else if (ret == ESP_ERR_NOT_SUPPORTED || !calibrated)
    {
        ESP_LOGW(TAG, "eFuse not burnt, skip software calibration");
    }
    else
    {
        ESP_LOGE(TAG, "Invalid arg or no memory");
    }

    return calibrated;
}

static void example_adc_calibration_deinit(adc_cali_handle_t handle)
{
    ESP_LOGI(TAG, "deregister %s calibration scheme", "Curve Fitting");
    ESP_ERROR_CHECK(adc_cali_delete_scheme_curve_fitting(handle));
}

 

最后我们在app_main里面初始化这些任务

void app_main(void)
{
  //
    ESP_LOGI(TAG,"main_task begin");
    /* This helper function configures Wi-Fi or Ethernet, as selected in menuconfig.
     * Read "Establishing Wi-Fi or Ethernet Connection" section in
     * examples/protocols/README.md for more information about this function.
     */
    // ESP_ERROR_CHECK(example_connect());
    
    wifi_init_softap();
    TCP_TASK();
    ADC_START();


// #ifdef CONFIG_EXAMPLE_IPV4
   
// #endif
// #ifdef CONFIG_EXAMPLE_IPV6
//     xTaskCreate(tcp_server_task, "tcp_server", 4096, (void*)AF_INET6, 5, NULL);
// #endif
}

app_main后面也可以加个任务删除函数将app_main这个任务删除掉

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值