ESP32 - ultrazvuk - FreeRTOS - Arduino Core / ESP-IDF

Tvoříte zajímavý projekt? Pochlubte se s ním.
Pravidla fóra
Vkládejte prosím jen HOTOVÉ projekty, které chcete představit ostatním.
Odpovědět
martinius96
Příspěvky: 579
Registrován: 01 srp 2017, 19:29
Reputation: 0
Bydliště: Poprad
Kontaktovat uživatele:

ESP32 - ultrazvuk - FreeRTOS - Arduino Core / ESP-IDF

Příspěvek od martinius96 » 30 led 2022, 15:51

ESP32 je populárny WiFi IoT mikrokontróler. Dnes by som vám rád ukázal projekt senzorového uzla založeného na ESP32, ktorý vykonáva meranie výšky hladiny vody v studni ultrazvukovým senzorom vzdialenosti (HC-SR04 / JSN-SR04T / DYP-ME007). Následne prenáša dáta na vzdialené webové rozhranie, kde sú dáta archivované v MySQL databáze a vizualizované používateľovi v dashboarde. Programová implementácia bude založená na operačnom systéme reálneho času FreeRTOS, pričom bude k dispozícii aj zdrojový kód v Arduino Core, ale aj frameworku ESP-IDF, ktorý umožňuje pristupovať bližšie k fyzickej vrstve mikrokontroléra ESP32. V ESP-IDF som začiatočník a tak verím, že som mnoho vecí nepopísal, ktoré by mohli byť dôležité... Snažil som sa spomenúť moje postrehy na ktoré som narazil a poukázať na úpravy, ktoré som vytvoril.
Obrázek
FreeRTOS značne uľahčuje vývoj projektu, nakoľko je možné jednotlivé podprogramy spúšťať ako úlohy, ktoré dokážu bežať nezávisle na sebe. Blokovanie určitej úlohy, napr. funkciou delay() nezastaví iné úlohy, ktoré sa môžu ďalej vykonávať. Na FreeRTOS budú v našej ukážkovej implementácii spustené 2 tasky (úlohy), pričom jedna úloha (TASK A) bude vykonávať meranie ultrazvukovými senzormi vzdialenosti a druhá úloha (TASK B) bude realizovať HTTP / HTTPS request na webserver. Každú úlohu je možné priradiť k jadru procesora Xtensa. Najdostupnejšie mikrokontroléry ESP32 majú dvojjadrový procesor Xtensa LX6 s taktom až 240 MHz, pričom má jadro protokolu (PRO_CPU) - Core 0, ktoré obsluhuje WiFi / BT stack a jadro aplikácie (APP_CPU) - Core 1.
Obrázek
Úlohu pre HTTP / HTTPS request je tak vhodné priradiť jadru protokolu a meranie výšky hladiny vody ultrazvukovými senzormi aplikačnému jadru, kde beží (v prípade Arduino Core) aj úloha void loop(), ak nie je špecifickým nastavením (v Nástrojoch Arduino IDE) zvolené iné jadro. Každá úloha má priradenú aj prioritu. Dôležitejší task by mal mať prioritu vyššiu, kedy sa garantuje jeho skoršie obslúženie (efekt najmä vo veľkých projektoch). Nakoľko je vykonanie HTTP / HTTPS requestu podmienené meraním, využíva programová implementácia inter-task (medziúlohovú) komunikáciu cez Queue. Queue je FIFO buffer, ktorý má definovaný počet prvkov (vzorovo 20) pre určitý dátový typ, ktorý sa využíva (uint_32 v ESP-IDF, resp. INT v Arduino Core). Úloha merania vkladá do Queue hodnotu výšky hladiny vody - funkciou xQueueSend(). Príjemca Queue (Receiving task) čaká po určitý čas (maximálne po portMAX_DELAY - čo je cca 50 dní) na prijatie dát z Queue. Pokým hodnotu neobdrží, nevyužíva procesorový čas, je v blokovacom režime, nevykonáva sa telo úlohy (funkcie). Procesorový čas môže byť tak využitý inými úlohami (efektívne najmä vo väčších projektoch).

Po prijatí dát z Queue funkciou xQueueReceive() je táto hodnota z Queue automaticky odstránená (existujú aj iné funkcie pre Queue, ktoré dokážu hodnotu v Queue ponechať, alebo ju vložiť na špecifické miesto, prípadne je možné kopírovať referenciu, nie hodnotu...). Queue zároveň garantuje bezpečný prenos hodnoty medzi úlohami. V našej programovej implementácii tak HTTP / HTTPS request úloha čaká na hodnotu z Queue a následne vykoná request na server a opätovne čaká na hodnotu z Queue. Vzorovo som použil Queue pre 20 prvkov, avšak nenastane situácia, žeby v Queue bola viac ako 1 hodnota, nakoľko meranie a vloženie do Queue sa realizuje raz za 5 minút a request trvá pár milisekúnd.

Task A (producer task - tvorí dáta)
  • Vykonáva meranie ultrazvukovým senzorom vzdialenosti (10x meranie, priemer hodnôt)
  • Zapisuje hodnotu uint_32 do fronty Queue (v Arduino Core je hodnota typu INT)
  • Čaká 300 sekúnd
Task B (consumer task - používa dáta)
  • Čaká na dostupné dáta v Queue
  • Počas čakania nevyužíva procesorový čas, ktorý môže efektívne využívať iný task
  • Po prijatí dát vymaže prvok z Queue
  • Vykoná jednorázový HTTP(S) POST request s dátami na webserver
Obrázek

Implementácia pod Arduino Core
Program nevyžadoval linkovanie knižníc pre FreeRTOS, tasks a pod, realizuje to automaticky, keďže ako bolo spomenuté vyššie, aj loop úloha. Aby úloha mohla bežať neustále, musí byť napísaná v slučke, napr. while(1), inak by sa úloha po prvom vykonaní ukončila... Do FreeRTOS som kopíroval časti pôvodného zdrojového kódu, ktorý som už v minulosti napísal. Pôvodný zdrojový kód využíval rutinu vo funkcii void loop(), ktorá sa cez millis() časovala každých 5 minút, kedy sa vykonalo meranie a následný HTTP / HTTPS request na webserver, ktorý realizoval archiváciu dát do MySQL databázy cez PHP backend. Jednotlivé časti zdrojových kódov som nakopíroval do taskov, doplnil som o funkcie pre Queue a jednotlivé úlohy som priradil jadru procesora protokolu resp. aplikačnému jadru. Pre HTTP konektivitu sa využíva socket z WiFi knižnice (trieda WiFiClient). Pre HTTPS konektivitu sa využíva socket z WiFiClientSecure knižnice (trieda WiFiClientSecure), pričom je nutné do zdrojového kódu doplniť aj Root CA certifikát, ktorý vydal certifikát pre webserver (doménu), kam sa mikrokontróler pripája. Obe knižnice (WiFi, resp. WiFiClientSecure) sú vstavané do Arduino Core a nie je ich potrebné inštalovať. Obsluha ultrazvukových senzorov vzdialenosti sa realizovala cez knižnicu NewPingESP8266.
Zdrojový kód - HTTPS - FreeRTOS - Arduino Core:

Kód: Vybrat vše

/*|-----------------------------------------------------------------------------------|*/
/*|Projekt: Hladinomer - HTTPS - FreeRTOS - HC-SR04 / JSN-SR04T / HY-SRF05            |*/
/*|ESP32 (DevKit, Generic)                                                            |*/
/*|Autor: Martin Chlebovec (martinius96)                                              |*/
/*|E-mail: martinius96@gmail.com                                                      |*/
/*|Info k projektu (schéma): https://martinius96.github.io/hladinomer-studna-scripty/ |*/
/*|Testovacie webove rozhranie: https://hladinomer.000webhostapp.com/                 |*/
/*|Licencia pouzitia: MIT                                                             |*/
/*|Revízia: 3. Január 2022                                                            |*/
/*|-----------------------------------------------------------------------------------|*/

#include <WiFi.h>
#include <WiFiClientSecure.h>
#include <NewPingESP8266.h>

const char * ssid = "MY_WIFI"; //MENO WiFi SIETE
const char * password = "MY_WIFI_PASSWORD"; //HESLO WiFi SIETE
const char* host = "hladinomer.000webhostapp.com"; //adresa webservera (doména) na ktorú sa odosielajú dáta
String url = "/data.php"; //URL adresa - cesta pod domenou k cieľovemu .php súboru, ktorý realizuje zápis

#define pinTrigger    22
#define pinEcho       23
#define maxVzdialenost 450
NewPingESP8266 sonar(pinTrigger, pinEcho, maxVzdialenost);

TaskHandle_t Task1; //ULTRASONIC MEASUREMENT
TaskHandle_t Task2; //WIFI HTTP SOCKET
QueueHandle_t  q = NULL;

WiFiClientSecure client;
static void Task1code( void * parameter);
static void Task2code( void * parameter);

//Root CA cert --> CERTIFIKÁT CERTIFIKAČNEJ AUTORITY, KTORÁ VYDALA CERTIFIKÁT VÁŠ WEBSERVER v .pem formáte
//DST ROOT CA X3 EXAMPLE (https://i.imgur.com/fvw4huT.png)
const static char* test_root_ca PROGMEM = \
    "-----BEGIN CERTIFICATE-----\n" \
    "MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBh\n" \
    "MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3\n" \
    "d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD\n" \
    "QTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAwMDAwMDBaMGExCzAJBgNVBAYTAlVT\n" \
    "MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j\n" \
    "b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkqhkiG\n" \
    "9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsB\n" \
    "CSDMAZOnTjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97\n" \
    "nh6Vfe63SKMI2tavegw5BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt\n" \
    "43C/dxC//AH2hdmoRBBYMql1GNXRor5H4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7P\n" \
    "T19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y7vrTC0LUq7dBMtoM1O/4\n" \
    "gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQABo2MwYTAO\n" \
    "BgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbR\n" \
    "TLtm8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUw\n" \
    "DQYJKoZIhvcNAQEFBQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/Esr\n" \
    "hMAtudXH/vTBH1jLuG2cenTnmCmrEbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg\n" \
    "06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIttep3Sp+dWOIrWcBAI+0tKIJF\n" \
    "PnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886UAb3LujEV0ls\n" \
    "YSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk\n" \
    "CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4=\n" \
    "-----END CERTIFICATE-----\n";

void setup() {
  Serial.begin(115200);
  WiFi.begin(ssid, password); //pripoj sa na wifi siet s heslom
  while (WiFi.status() != WL_CONNECTED) {
    delay(1000);
    Serial.print(".");
  }
  Serial.println(F(""));
  Serial.println(F("Wifi connected with IP:"));
  Serial.println(WiFi.localIP());
  client.setCACert(test_root_ca);
  q = xQueueCreate(20, sizeof(int));
  if (q != NULL) {
    Serial.println(F("Queue FIFO buffer is created"));
    vTaskDelay(1000 / portTICK_PERIOD_MS); //wait for a second
    xTaskCreatePinnedToCore(
      Task1code,   /* Task function. */
      "Task1",     /* name of task. */
      10000,       /* Stack size of task */
      NULL,        /* parameter of the task */
      1,           /* priority of the task */
      &Task1,      /* Task handle to keep track of created task */
      1);          /* pin task to core 1 */
    Serial.println(F("Ultrasonic measurement task started"));
    xTaskCreatePinnedToCore(
      Task2code,   /* Task function. */
      "Task2",     /* name of task. */
      10000,       /* Stack size of task */
      NULL,        /* parameter of the task */
      1,           /* priority of the task */
      &Task2,      /* Task handle to keep track of created task */
      0);          /* pin task to core 0 */
    Serial.println(F("HTTP Socket task started"));
  } else {
    Serial.println(F("Queue creation failed"));
  }
}

void loop() {
  if (WiFi.status() != WL_CONNECTED) {
    WiFi.begin(ssid, password); //pripoj sa na wifi siet s heslom
  }
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  yield();

}

static void Task1code( void * parameter) {
  if (q == NULL) {
    Serial.println(F("Queue in Measurement task is not ready"));
    return;
  }
  while (1) {
    int distance = sonar.ping_cm();
    delay(50);
    Serial.print(F("Test measurement: "));
    Serial.print(distance);
    Serial.println(F(" cm"));
    if (distance > 0) {
      distance = 0;
      for (int i = 0; i < 10; i++) {
        distance += sonar.ping_cm();
        delay(50);
      }
      distance = distance / 10;
      Serial.print(F("Distance to water level is: "));
      Serial.print(distance);
      Serial.println(F(" cm."));
      xQueueSend(q, (void *)&distance, (TickType_t )0); //add the measurement value to Queue
      for (int countdown = 300; countdown >= 0; countdown--) {
        Serial.print(F("Next measurement in: "));
        Serial.print(countdown);
        Serial.println(F(" seconds"));
        vTaskDelay(1000 / portTICK_PERIOD_MS);
      }
    }
  }
}
static void Task2code( void * parameter) {
  int distance;
  if (q == NULL) {
    Serial.println(F("Queue in HTTP socket task is not ready"));
    return;
  }
  while (1) {
    xQueueReceive(q, &distance, portMAX_DELAY); //read measurement value from Queue and run code below, if no value, WAIT....
    String data = "hodnota=" + String(distance) + "&token=123456789";
    client.stop();
    if (client.connect(host, 443)) {
      Serial.println(F("Connected to server successfully"));
      client.println("POST " + url + " HTTP/1.0");
      client.println("Host: " + (String)host);
      client.println(F("User-Agent: ESP"));
      client.println(F("Connection: close"));
      client.println(F("Content-Type: application/x-www-form-urlencoded;"));
      client.print(F("Content-Length: "));
      client.println(data.length());
      client.println();
      client.println(data);
      Serial.println(F("Datas were sent to server successfully"));
      while (client.connected()) {
        String line = client.readStringUntil('\n');
        if (line == "\r") {
          break;
        }
      }
      String line = client.readStringUntil('\n');
    } else {
      Serial.println(F("Connection to webserver was NOT successful"));
    }
    client.stop();
  }
}
UART výstup - HTTPS - FreeRTOS - Arduino Core - DEBUG Verbose ON:
Obrázek

Implementácia pod ESP-IDF
Programová implementácia bola realizovaná pod frameworkom ESP-IDF verzie 4.3.2, mala by byť však plne kompatibilná aj pre verzie 4.0 a 4.2 (release). Podobne ako v Arduino Core, aj tu je množstvo príkladov v zložke examples a protocols. Pre HTTP konektivitu som využil príklad http_request, ktorý bol však navrhnutý pôvodne pre GET request so statickou adresou. Musel som tak existujúci request upraviť, pridať HTTP hlavičkou encodingu posielaných dát a pri každej iterácii requestu aj dosadiť aktuálne dáta o výške hladiny vody z Queue. Pre komunikáciu s ultrazvukovým senzorom vzdialenosti som použil C knižnicu ultrasonic od Ruslan V. Použitie bolo veľmi jednoduché a nakoľko bolo meranie senzorom ako samostatná úloha, nemusel som časti kódu vnoriť do existujúceho tasku pre HTTP request.

Pre HTTPS request som využil https_mbedtls príklad zo zložky protocols, bolo nutné vykonať identickú úpravu GET requestu na POST request ako v predchádzajúcom príklade. Root CA certifikát nebolo nutné vložiť do zdrojového kódu, nakoľko má ESP-IDF framework Root CA bundle, kde sú všetky certifikáty dostupných certifikačných autorít. V prípade, ak by ste používali HTTPS request na self-signed webserver napr. v LAN sieti, bolo by nutné certifikát CA doplniť napr. do Root CA bundle.
Zdrojový kód - HTTPS - FreeRTOS - ESP-IDF 4.3.2:

Kód: Vybrat vše

/*|-----------------------------------------------------------------------------------|*/
/*|Projekt: Hladinomer - HTTPS - HC-SR04 / JSN-SR04T / HY-SRF05                       |*/
/*|ESP32 (DevKit, Generic) - ESP-IDF v4.3.X                                           |*/
/*|Autor: Martin Chlebovec (martinius96)                                              |*/
/*|E-mail: martinius96@gmail.com                                                      |*/
/*|Info k projektu (schéma): https://martinius96.github.io/hladinomer-studna-scripty/ |*/
/*|Testovacie webove rozhranie HTTPS: https://hladinomer.000webhostapp.com/           |*/
/*|Revízia: 20. Január 2022                                                           |*/
/*|-----------------------------------------------------------------------------------|*/

#include <string.h>
#include <stdlib.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_wifi.h"
#include "esp_event.h"
#include "esp_log.h"
#include "esp_system.h"
#include "nvs_flash.h"
#include "protocol_examples_common.h"
#include "esp_netif.h"

#include "lwip/err.h"
#include "lwip/sockets.h"
#include "lwip/sys.h"
#include "lwip/netdb.h"
#include "lwip/dns.h"

#include "mbedtls/platform.h"
#include "mbedtls/net_sockets.h"
#include "mbedtls/esp_debug.h"
#include "mbedtls/ssl.h"
#include "mbedtls/entropy.h"
#include "mbedtls/ctr_drbg.h"
#include "mbedtls/error.h"
#include "mbedtls/certs.h"
#include "esp_crt_bundle.h"

#include "ultrasonic.h"
#include "driver/dac.h"

/* Constants that aren't configurable in menuconfig */

#define MAX_DISTANCE_CM 450 // 5m max
#define GPIO_TRIGGER	22
#define GPIO_ECHO	23
// Webserver
/* Constants that aren't configurable in menuconfig */
#define WEB_SERVER "hladinomer.000webhostapp.com"
#define WEB_PORT "443"


static const char *TAG = "https_request";
static const char *TAG2 = "ultrasonic_measurement";

QueueHandle_t  q=NULL;
static void ultrasonic(void *pvParamters)
{
	ultrasonic_sensor_t sensor = {
		.trigger_pin = GPIO_TRIGGER,
		.echo_pin = GPIO_ECHO
	};

	ultrasonic_init(&sensor);
  uint32_t distance = 0;
    if(q == NULL){
        printf("Queue is not ready \n");
        return;
    }
	while (true) {
  uint32_t avg_distance = 0;
  int index_loop = 1;
  while(index_loop<=10){
		esp_err_t res = ultrasonic_measure_cm(&sensor, MAX_DISTANCE_CM, &distance);
		if (res != ESP_OK) {
			printf("Error: ");
			switch (res) {
				case ESP_ERR_ULTRASONIC_PING:
					printf("Cannot ping (device is in invalid state)\n");
					break;
				case ESP_ERR_ULTRASONIC_PING_TIMEOUT:
					printf("Ping timeout (no device found)\n");
					break;
				case ESP_ERR_ULTRASONIC_ECHO_TIMEOUT:
					printf("Echo timeout (i.e. distance too big)\n");
					break;
				default:
					printf("%d\n", res);
			}
		} else {
			printf("Measurement %d: %d cm\n", index_loop, distance);
       avg_distance +=  distance;
      index_loop++;
		}
    }
    esp_err_t res = ultrasonic_measure_cm(&sensor, MAX_DISTANCE_CM, &distance);
    if (res == ESP_OK) {
      avg_distance = avg_distance / 10;
      distance  = avg_distance;
      xQueueSend(q,(void *)&distance,(TickType_t )0); // add the value to the queue
    }
            for(int countdown = 300; countdown >= 0; countdown--) {
            ESP_LOGI(TAG2, "%d... ", countdown);
            vTaskDelay(1000 / portTICK_PERIOD_MS);
        }
	}
}

static void https_get_task(void *pvParameters)
{
     uint32_t distance;
     if(q == NULL){
        printf("Queue is not ready \n");
        return;
    }
    char buf[512];
    int ret, flags, len;

    mbedtls_entropy_context entropy;
    mbedtls_ctr_drbg_context ctr_drbg;
    mbedtls_ssl_context ssl;
    mbedtls_x509_crt cacert;
    mbedtls_ssl_config conf;
    mbedtls_net_context server_fd;

    mbedtls_ssl_init(&ssl);
    mbedtls_x509_crt_init(&cacert);
    mbedtls_ctr_drbg_init(&ctr_drbg);
    ESP_LOGI(TAG, "Seeding the random number generator");

    mbedtls_ssl_config_init(&conf);

    mbedtls_entropy_init(&entropy);
    if((ret = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy,
                                    NULL, 0)) != 0)
    {
        ESP_LOGE(TAG, "mbedtls_ctr_drbg_seed returned %d", ret);
        abort();
    }

    ESP_LOGI(TAG, "Attaching the certificate bundle...");

    ret = esp_crt_bundle_attach(&conf);

    if(ret < 0)
    {
        ESP_LOGE(TAG, "esp_crt_bundle_attach returned -0x%x\n\n", -ret);
        abort();
    }

    ESP_LOGI(TAG, "Setting hostname for TLS session...");

     /* Hostname set here should match CN in server certificate */
    if((ret = mbedtls_ssl_set_hostname(&ssl, WEB_SERVER)) != 0)
    {
        ESP_LOGE(TAG, "mbedtls_ssl_set_hostname returned -0x%x", -ret);
        abort();
    }

    ESP_LOGI(TAG, "Setting up the SSL/TLS structure...");

    if((ret = mbedtls_ssl_config_defaults(&conf,
                                          MBEDTLS_SSL_IS_CLIENT,
                                          MBEDTLS_SSL_TRANSPORT_STREAM,
                                          MBEDTLS_SSL_PRESET_DEFAULT)) != 0)
    {
        ESP_LOGE(TAG, "mbedtls_ssl_config_defaults returned %d", ret);
        goto exit;
    }

    /* MBEDTLS_SSL_VERIFY_OPTIONAL is bad for security, in this example it will print
       a warning if CA verification fails but it will continue to connect.

       You should consider using MBEDTLS_SSL_VERIFY_REQUIRED in your own code.
    */
    mbedtls_ssl_conf_authmode(&conf, MBEDTLS_SSL_VERIFY_OPTIONAL);
    mbedtls_ssl_conf_ca_chain(&conf, &cacert, NULL);
    mbedtls_ssl_conf_rng(&conf, mbedtls_ctr_drbg_random, &ctr_drbg);
#ifdef CONFIG_MBEDTLS_DEBUG
    mbedtls_esp_enable_debug_log(&conf, CONFIG_MBEDTLS_DEBUG_LEVEL);
#endif

    if ((ret = mbedtls_ssl_setup(&ssl, &conf)) != 0)
    {
        ESP_LOGE(TAG, "mbedtls_ssl_setup returned -0x%x\n\n", -ret);
        goto exit;
    }

    while(1) {
  xQueueReceive(q,&distance,portMAX_DELAY); 
  char REQUEST [1000];
	 char values [250];
	 sprintf(values, "hodnota=%d&token=123456789", distance);
    sprintf (REQUEST, "POST /data.php HTTP/1.0\r\nHost: "WEB_SERVER"\r\nUser-Agent: ESP32\r\nConnection: close\r\nContent-Type: application/x-www-form-urlencoded;\r\nContent-Length:%d\r\n\r\n%s\r\n",strlen(values),values); 
        mbedtls_net_init(&server_fd);

        ESP_LOGI(TAG, "Connecting to %s:%s...", WEB_SERVER, WEB_PORT);

        if ((ret = mbedtls_net_connect(&server_fd, WEB_SERVER,
                                      WEB_PORT, MBEDTLS_NET_PROTO_TCP)) != 0)
        {
            ESP_LOGE(TAG, "mbedtls_net_connect returned -%x", -ret);
            goto exit;
        }

        ESP_LOGI(TAG, "Connected.");

        mbedtls_ssl_set_bio(&ssl, &server_fd, mbedtls_net_send, mbedtls_net_recv, NULL);

        ESP_LOGI(TAG, "Performing the SSL/TLS handshake...");

        while ((ret = mbedtls_ssl_handshake(&ssl)) != 0)
        {
            if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE)
            {
                ESP_LOGE(TAG, "mbedtls_ssl_handshake returned -0x%x", -ret);
                goto exit;
            }
        }

        ESP_LOGI(TAG, "Verifying peer X.509 certificate...");

        if ((flags = mbedtls_ssl_get_verify_result(&ssl)) != 0)
        {
            /* In real life, we probably want to close connection if ret != 0 */
            ESP_LOGW(TAG, "Failed to verify peer certificate!");
            bzero(buf, sizeof(buf));
            mbedtls_x509_crt_verify_info(buf, sizeof(buf), "  ! ", flags);
            ESP_LOGW(TAG, "verification info: %s", buf);
        }
        else {
            ESP_LOGI(TAG, "Certificate verified.");
        }

        ESP_LOGI(TAG, "Cipher suite is %s", mbedtls_ssl_get_ciphersuite(&ssl));

        ESP_LOGI(TAG, "Writing HTTP request...");

        size_t written_bytes = 0;
        do {
            ret = mbedtls_ssl_write(&ssl,
                                    (unsigned char *)REQUEST + written_bytes,
                                    strlen(REQUEST) - written_bytes);
            if (ret >= 0) {
                ESP_LOGI(TAG, "%d bytes written", ret);
                written_bytes += ret;
            } else if (ret != MBEDTLS_ERR_SSL_WANT_WRITE && ret != MBEDTLS_ERR_SSL_WANT_READ) {
                ESP_LOGE(TAG, "mbedtls_ssl_write returned -0x%x", -ret);
                goto exit;
            }
        } while(written_bytes < strlen(REQUEST));

        ESP_LOGI(TAG, "Reading HTTP response...");

        do
        {
            len = sizeof(buf) - 1;
            bzero(buf, sizeof(buf));
            ret = mbedtls_ssl_read(&ssl, (unsigned char *)buf, len);

            if(ret == MBEDTLS_ERR_SSL_WANT_READ || ret == MBEDTLS_ERR_SSL_WANT_WRITE)
                continue;

            if(ret == MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY) {
                ret = 0;
                break;
            }

            if(ret < 0)
            {
                ESP_LOGE(TAG, "mbedtls_ssl_read returned -0x%x", -ret);
                break;
            }

            if(ret == 0)
            {
                ESP_LOGI(TAG, "connection closed");
                break;
            }

            len = ret;
            ESP_LOGD(TAG, "%d bytes read", len);
            /* Print response directly to stdout as it is read */
            for(int i = 0; i < len; i++) {
                putchar(buf[i]);
            }
        } while(1);

        mbedtls_ssl_close_notify(&ssl);

    exit:
        mbedtls_ssl_session_reset(&ssl);
        mbedtls_net_free(&server_fd);

        if(ret != 0)
        {
            mbedtls_strerror(ret, buf, 100);
            ESP_LOGE(TAG, "Last error was: -0x%x - %s", -ret, buf);
        }

        putchar('\n'); // JSON output doesn't have a newline at end

        static int request_count;
        ESP_LOGI(TAG, "Completed %d requests", ++request_count);
        ESP_LOGI(TAG, "Starting again!");
    }
}

void app_main(void)
{
    ESP_ERROR_CHECK( nvs_flash_init() );
    ESP_ERROR_CHECK(esp_netif_init());
    ESP_ERROR_CHECK(esp_event_loop_create_default());

    /* 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());
     q=xQueueCreate(20,sizeof(unsigned long));
    if(q != NULL){
        printf("Queue is created\n");
        vTaskDelay(1000/portTICK_PERIOD_MS); //wait for a second
        xTaskCreate(&ultrasonic, "ultrasonic", 2048, NULL, 5, NULL);
        printf("Measurement task  started\n");
        xTaskCreate(&https_get_task, "https_get_task", 8192, NULL, 5, NULL);
        printf("HTTPS socket task  started\n");
    }else{
        printf("Queue creation failed");
    }  

}
UART výstup - HTTPS - FreeRTOS - ESP-IDF 4.3.2:
Obrázek

Programové implementácie pod ESP-IDF alebo Arduino Core a musím povedať, že sú zatiaľ spoľahlivé. Nestalo sa mi, aby sa mi ESP32 zaseklo, alebo by sa ukončil nejaký task napr. cez abort(), či Core Panic, ktorý by reštartoval mikrokontróler... ESP-IDF využíva pre udržanie WiFi konektivity aj tzv. event loop, kedy dokáže na udalosť výpadku WiFi konektivity s AP zareagovať a opätovne pripojiť ESP32 k AP. Event loop je inicializovaný vo funkcii app_main(), ktorá sa vykoná pri spustení programu (ekvivalent k setup() v Arduino Core). Event sa spustí a je plne nezávislý od iných úloh, funguje v podstate asynchrónne, keďže sa nikde v programe nemusí "udržiavať, ani kontrolovať stav WiFi konektivity s AP".

Pridám aj niekoľko referencií na Github, kde nájdete zdrojové kódy pre jednotlivé senzorové uzly na ESP32. HTTP senzorové uzly prenášajú dáta na http://arduino.clanweb.eu/studna_s_prekladom/, HTTPS senzorové uzly na https://hladinomer.000webhostapp.com/. V ESP-IDF projektoch je potrebné nastaviť meno a heslo na WiFi sieť, prípadne je možné použiť aj PHY Ethernet konektivitu (netestoval som, ale v nastavení adaptéra je možné vybrať). Zdrojové kódy pre Arduino Core obsahujú nastavenie SSID a hesla priamo v zdrojovom kóde. ESP-IDF projekty obsahujú aj knižnicu ultrasonic. Časovanie rutiny merania výšky hladiny vody každých 300 sekúnd je určite možné realizovať aj efektívnejšie. V mojom prípade som využil 300x volanie vTaskDelay() po dobu 1000 ms. ESP-IDF obsahuje timer (esp_timer), ktorý je ekvivalent k funkcii millis(). Časovanie rutiny by tak bolo presnejšie.
Obrázek
HTTP senzorové uzly:
https://github.com/martinius96/hladinom ... rduino.ino
https://github.com/martinius96/hladinom ... TP/ESP-IDF

HTTPS senzorové uzly:
https://github.com/martinius96/hladinom ... rduino.ino
https://github.com/martinius96/hladinom ... ps_mbedtls

Viac o projekte Hladinomer (zdrojové kódy pre ESP32 bez FreeRTOS, pre ESP8266, Arduino + Ethernet / Sigfox LPWAN, schémy zapojenia, knižnicu NewPingESP8266 a iné nájdete na): https://martinius96.github.io/hladinome ... a-scripty/

Tip na záver: Nepoužívajte prioritu tasku 0, pretože sa nezačne vôbec vykonávať. Ušetríte si tým pár desiatok minút času skúmania zdrojového kódu a šedivých vlasov :)

martinius96
Příspěvky: 579
Registrován: 01 srp 2017, 19:29
Reputation: 0
Bydliště: Poprad
Kontaktovat uživatele:

Re: ESP32 - ultrazvuk - FreeRTOS - Arduino Core / ESP-IDF

Příspěvek od martinius96 » 08 srp 2022, 12:13

Vyskúšal som aj PHY Ethernet modul LAN8720, ktorý sa s ESP32 prepája cez RMII rozhranie. V Arduino Core bola úprava jednoduchá, stačilo odstrániť všetky WiFi časti programu a nahradiť za Ethernet. Zaujímavosťou je, že MAC vrstvu robí pre PHY Ethernet ESP32 cez svoj WiFi kontróler / adaptér, keďže sa využívajú WiFi eventy pre stavy Ethernetu. PHY Ethernet dokáže fungovať na 10, alebo 100 Mbps s Full Duplex a dokáže detekovať aj odpojenie sieťového kábla. Funguje DHCP i statické nastavenie IP adresy. Pre HTTPS spojenie využíva PHY Ethernet knižnicu WiFiClientSecure rovnako ako v prípade programu s WiFi konektivitou pre HTTPS.
Obrázek
V ESP-IDF sa mi PHY Ethernet nepodarilo rozbehať. V konfigurácii sa vyžaduje RESET pin (čo v Arduino Core nevyžaduje), ktorý je v rozsahu GPIO od -1 do 33. Vyskúšal som ho nastaviť na -1, ale aj na 0, ako to bolo odporúčané v tutoriáloch, aby sa LAN8720 reštartoval pri štarte ESP32 (GPIO0 = BOOT, ktorý je po pripojení napájania v stave LOW a prechádza do HIGH, čo by malo PHY Ethernet reštartovať). Stále na UART je výpis o neúspešnom reštartovaní PHY Ethernetu a točí sa to v slučke s reštartovaním ESP32. Možno je ešte problém niekde v programe, musím testovať...

Prikladám i testované implementácie pod Arduino Core pre ESP32.

HTTP konektivita - ESP32 + LAN8720:

Kód: Vybrat vše

/*|----------------------------------------------------------------------------|*/
/*|Project: Ultrasonic water level monitor - HC-SR04 / JSN-SR04T / HY-SRF05... |*/
/*|ESP32 (DevKit, Generic) + PHY Ethernet LAN8720 / TLK110, RMII interface     |*/
/*|Author: Martin Chlebovec (martinius96)                                      |*/
/*|E-mail: martinius96@gmail.com                                               |*/
/*|Project info: https://martinius96.github.io/hladinomer-studna-scripty/en    |*/
/*|Test web interface: http://arduino.clanweb.eu/studna_s_prekladom/?lang=en   |*/
/*|Revision: 3. August 2022                                                    |*/
/*|----------------------------------------------------------------------------|*/

#include <ETH.h>
#include <NewPingESP8266.h>

const char* host = "arduino.clanweb.eu"; //webhost
String url = "/studna_s_prekladom/data.php"; //URL address to PHP file

#define pinTrigger    4
#define pinEcho       5 //CHANGED FROM D23 !!!!
#define maxVzdialenost 450
NewPingESP8266 sonar(pinTrigger, pinEcho, maxVzdialenost);

/*
     ETH_CLOCK_GPIO0_IN   - default: external clock from crystal oscillator
     ETH_CLOCK_GPIO0_OUT  - 50MHz clock from internal APLL output on GPIO0 - possibly an inverter is needed for LAN8720
     ETH_CLOCK_GPIO16_OUT - 50MHz clock from internal APLL output on GPIO16 - possibly an inverter is needed for LAN8720
     ETH_CLOCK_GPIO17_OUT - 50MHz clock from internal APLL inverted output on GPIO17 - tested with LAN8720
*/
#ifdef ETH_CLK_MODE
#undef ETH_CLK_MODE
#endif
#define ETH_CLK_MODE    ETH_CLOCK_GPIO17_OUT

// Pin# of the enable signal for the external crystal oscillator (-1 to disable for internal APLL source)
#define ETH_POWER_PIN   -1

// Type of the Ethernet PHY (LAN8720 or TLK110)
#define ETH_TYPE        ETH_PHY_LAN8720

// I²C-address of Ethernet PHY (0 or 1 for LAN8720, 31 for TLK110)
#define ETH_ADDR        1

// Pin# of the I²C clock signal for the Ethernet PHY, DONT USE THIS PIN FOR ultrasonic sensor in this sketch
#define ETH_MDC_PIN     23

// Pin# of the I²C IO signal for the Ethernet PHY
#define ETH_MDIO_PIN    18

TaskHandle_t Task1; //ULTRASONIC MEASUREMENT
TaskHandle_t Task2; //PHY ETHERNET HTTP SOCKET
QueueHandle_t  q = NULL;


WiFiClient client;
static void Task1code( void * parameter);
static void Task2code( void * parameter);
void WiFiEvent(WiFiEvent_t event);

void setup() {
  Serial.begin(115200);
  WiFi.onEvent(WiFiEvent);
  ETH.begin(ETH_ADDR, ETH_POWER_PIN, ETH_MDC_PIN, ETH_MDIO_PIN, ETH_TYPE, ETH_CLK_MODE);
  delay(5000);
  q = xQueueCreate(20, sizeof(int));
  if (q != NULL) {
    Serial.println(F("Queue FIFO buffer is created"));
    vTaskDelay(1000 / portTICK_PERIOD_MS); //wait for a second
    xTaskCreatePinnedToCore(
      Task1code,   /* Task function. */
      "Task1",     /* name of task. */
      10000,       /* Stack size of task */
      NULL,        /* parameter of the task */
      1,           /* priority of the task */
      &Task1,      /* Task handle to keep track of created task */
      1);          /* pin task to core 1 */
    Serial.println(F("Ultrasonic measurement task started"));
    xTaskCreatePinnedToCore(
      Task2code,   /* Task function. */
      "Task2",     /* name of task. */
      10000,       /* Stack size of task */
      NULL,        /* parameter of the task */
      1,           /* priority of the task */
      &Task2,      /* Task handle to keep track of created task */
      0);          /* pin task to core 0 */
    Serial.println(F("HTTP Socket task started"));
  } else {
    Serial.println(F("Queue creation failed"));
  }
}

void loop() {
  yield();
}

static void Task1code( void * parameter) {
  if (q == NULL) {
    Serial.println(F("Queue in Measurement task is not ready"));
    return;
  }
  while (1) {
    int distance = sonar.ping_cm();
    delay(50);
    Serial.print(F("Test measurement: "));
    Serial.print(distance);
    Serial.println(F(" cm"));
    if (distance > 0) {
      distance = 0;
      for (int i = 0; i < 10; i++) {
        distance += sonar.ping_cm();
        delay(50);
      }
      distance = distance / 10;
      Serial.print(F("Distance to water level is: "));
      Serial.print(distance);
      Serial.println(F(" cm."));
      xQueueSend(q, (void *)&distance, (TickType_t )0); //add the measurement value to Queue
      for (int countdown = 300; countdown >= 0; countdown--) {
        Serial.print(F("Next measurement in: "));
        Serial.print(countdown);
        Serial.println(F(" seconds"));
        vTaskDelay(1000 / portTICK_PERIOD_MS);
      }
    }
  }
}
static void Task2code( void * parameter) {
  int distance;
  if (q == NULL) {
    Serial.println(F("Queue in HTTP socket task is not ready"));
    return;
  }
  while (1) {
    xQueueReceive(q, &distance, portMAX_DELAY); //read measurement value from Queue and run code below, if no value, WAIT....
    String data = "hodnota=" + String(distance) + "&token=123456789";
    client.stop();
    if (client.connect(host, 80)) {
      Serial.println(F("Connected to server successfully"));
      client.println("POST " + url + " HTTP/1.0");
      client.println("Host: " + (String)host);
      client.println(F("User-Agent: ESP"));
      client.println(F("Connection: close"));
      client.println(F("Content-Type: application/x-www-form-urlencoded;"));
      client.print(F("Content-Length: "));
      client.println(data.length());
      client.println();
      client.println(data);
      Serial.println(F("Datas were sent to server successfully"));
      while (client.connected()) {
        String line = client.readStringUntil('\n');
        if (line == "\r") {
          break;
        }
      }
      String line = client.readStringUntil('\n');
    } else {
      Serial.println(F("Connection to webserver was NOT successful"));
    }
    client.stop();
  }
}

void WiFiEvent(WiFiEvent_t event)
{
  switch (event) {
    case ARDUINO_EVENT_ETH_START:
      Serial.println("ETH Started");
      //set eth hostname here
      ETH.setHostname("esp32-ethernet");
      break;
    case ARDUINO_EVENT_ETH_CONNECTED:
      Serial.println("ETH Connected");
      break;
    case ARDUINO_EVENT_ETH_GOT_IP:
      Serial.print("ETH MAC: ");
      Serial.print(ETH.macAddress());
      Serial.print(", IPv4: ");
      Serial.print(ETH.localIP());
      if (ETH.fullDuplex()) {
        Serial.print(", FULL_DUPLEX");
      }
      Serial.print(", ");
      Serial.print(ETH.linkSpeed());
      Serial.println("Mbps");
      break;
    case ARDUINO_EVENT_ETH_DISCONNECTED:
      Serial.println("ETH Disconnected");
      break;
    case ARDUINO_EVENT_ETH_STOP:
      Serial.println("ETH Stopped");
      break;
    default:
      break;
  }
}
HTTPS konektivita s RootCA Digicert - ESP32 + LAN8720:

Kód: Vybrat vše

/*|----------------------------------------------------------------------------|*/
/*|Project: Ultrasonic water level monitor - HC-SR04 / JSN-SR04T / HY-SRF05... |*/
/*|ESP32 (DevKit, Generic) + PHY Ethernet LAN8720 / TLK110, RMII interface     |*/
/*|Author: Martin Chlebovec (martinius96)                                      |*/
/*|E-mail: martinius96@gmail.com                                               |*/
/*|Project info: https://martinius96.github.io/hladinomer-studna-scripty/en    |*/
/*|Test web interface: https://hladinomer.000webhostapp.com/?lang=en           |*/
/*|Revision: 3. August 2022                                                    |*/
/*|----------------------------------------------------------------------------|*/

#include <WiFiClientSecure.h>
#include <ETH.h>
#include <NewPingESP8266.h>

const char* host = "hladinomer.000webhostapp.com"; //webhost
String url = "/data.php"; //URL address to PHP file

#define pinTrigger    4
#define pinEcho       5 //CHANGED FROM D23 !!!!
#define maxVzdialenost 450
NewPingESP8266 sonar(pinTrigger, pinEcho, maxVzdialenost);

/*
     ETH_CLOCK_GPIO0_IN   - default: external clock from crystal oscillator
     ETH_CLOCK_GPIO0_OUT  - 50MHz clock from internal APLL output on GPIO0 - possibly an inverter is needed for LAN8720
     ETH_CLOCK_GPIO16_OUT - 50MHz clock from internal APLL output on GPIO16 - possibly an inverter is needed for LAN8720
     ETH_CLOCK_GPIO17_OUT - 50MHz clock from internal APLL inverted output on GPIO17 - tested with LAN8720
*/
#ifdef ETH_CLK_MODE
#undef ETH_CLK_MODE
#endif
#define ETH_CLK_MODE    ETH_CLOCK_GPIO17_OUT

// Pin# of the enable signal for the external crystal oscillator (-1 to disable for internal APLL source)
#define ETH_POWER_PIN   -1

// Type of the Ethernet PHY (LAN8720 or TLK110)
#define ETH_TYPE        ETH_PHY_LAN8720

// I²C-address of Ethernet PHY (0 or 1 for LAN8720, 31 for TLK110)
#define ETH_ADDR        1

// Pin# of the I²C clock signal for the Ethernet PHY, DONT USE THIS PIN FOR ultrasonic sensor in this sketch
#define ETH_MDC_PIN     23

// Pin# of the I²C IO signal for the Ethernet PHY
#define ETH_MDIO_PIN    18

WiFiClientSecure client; //Secured client object for HTTPS connection
TaskHandle_t Task1; //ULTRASONIC MEASUREMENT
TaskHandle_t Task2; //PHY ETHERNET HTTP SOCKET
QueueHandle_t  q = NULL;

//DigiCert Global Root CA in .pem format, stored in PROGMEM flash
//DST ROOT CA X3 EXAMPLE (https://i.imgur.com/fvw4huT.png)
const static char* test_root_ca PROGMEM = \
    "-----BEGIN CERTIFICATE-----\n" \
    "MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBh\n" \
    "MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3\n" \
    "d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD\n" \
    "QTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAwMDAwMDBaMGExCzAJBgNVBAYTAlVT\n" \
    "MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j\n" \
    "b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkqhkiG\n" \
    "9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsB\n" \
    "CSDMAZOnTjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97\n" \
    "nh6Vfe63SKMI2tavegw5BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt\n" \
    "43C/dxC//AH2hdmoRBBYMql1GNXRor5H4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7P\n" \
    "T19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y7vrTC0LUq7dBMtoM1O/4\n" \
    "gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQABo2MwYTAO\n" \
    "BgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbR\n" \
    "TLtm8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUw\n" \
    "DQYJKoZIhvcNAQEFBQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/Esr\n" \
    "hMAtudXH/vTBH1jLuG2cenTnmCmrEbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg\n" \
    "06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIttep3Sp+dWOIrWcBAI+0tKIJF\n" \
    "PnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886UAb3LujEV0ls\n" \
    "YSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk\n" \
    "CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4=\n" \
    "-----END CERTIFICATE-----\n";


static void Task1code( void * parameter);
static void Task2code( void * parameter);
void WiFiEvent(WiFiEvent_t event);

void setup() {
  Serial.begin(115200);
  WiFi.onEvent(WiFiEvent);
  ETH.begin(ETH_ADDR, ETH_POWER_PIN, ETH_MDC_PIN, ETH_MDIO_PIN, ETH_TYPE, ETH_CLK_MODE);
  delay(5000);
  client.setCACert(test_root_ca);
  q = xQueueCreate(20, sizeof(int));
  if (q != NULL) {
    Serial.println(F("Queue FIFO buffer is created"));
    vTaskDelay(1000 / portTICK_PERIOD_MS); //wait for a second
    xTaskCreatePinnedToCore(
      Task1code,   /* Task function. */
      "Task1",     /* name of task. */
      10000,       /* Stack size of task */
      NULL,        /* parameter of the task */
      1,           /* priority of the task */
      &Task1,      /* Task handle to keep track of created task */
      1);          /* pin task to core 1 */
    Serial.println(F("Ultrasonic measurement task started"));
    xTaskCreatePinnedToCore(
      Task2code,   /* Task function. */
      "Task2",     /* name of task. */
      10000,       /* Stack size of task */
      NULL,        /* parameter of the task */
      1,           /* priority of the task */
      &Task2,      /* Task handle to keep track of created task */
      0);          /* pin task to core 0 */
    Serial.println(F("HTTPS Socket task started"));
  } else {
    Serial.println(F("Queue creation failed"));
  }
}

void loop() {
  yield();
}

static void Task1code( void * parameter) {
  if (q == NULL) {
    Serial.println(F("Queue in Measurement task is not ready"));
    return;
  }
  while (1) {
    int distance = sonar.ping_cm();
    delay(50);
    Serial.print(F("Test measurement: "));
    Serial.print(distance);
    Serial.println(F(" cm"));
    if (distance > 0) {
      distance = 0;
      for (int i = 0; i < 10; i++) {
        distance += sonar.ping_cm();
        delay(50);
      }
      distance = distance / 10;
      Serial.print(F("Distance to water level is: "));
      Serial.print(distance);
      Serial.println(F(" cm."));
      xQueueSend(q, (void *)&distance, (TickType_t )0); //add the measurement value to Queue
      for (int countdown = 300; countdown >= 0; countdown--) {
        Serial.print(F("Next measurement in: "));
        Serial.print(countdown);
        Serial.println(F(" seconds"));
        vTaskDelay(1000 / portTICK_PERIOD_MS);
      }
    }
  }
}
static void Task2code( void * parameter) {
  int distance;
  if (q == NULL) {
    Serial.println(F("Queue in HTTP socket task is not ready"));
    return;
  }
  while (1) {
    xQueueReceive(q, &distance, portMAX_DELAY); //read measurement value from Queue and run code below, if no value, WAIT....
    String data = "hodnota=" + String(distance) + "&token=123456789";
    client.stop();
    if (client.connect(host, 443)) {
      Serial.println(F("Connected to server successfully"));
      client.println("POST " + url + " HTTP/1.0");
      client.println("Host: " + (String)host);
      client.println(F("User-Agent: ESP"));
      client.println(F("Connection: close"));
      client.println(F("Content-Type: application/x-www-form-urlencoded;"));
      client.print(F("Content-Length: "));
      client.println(data.length());
      client.println();
      client.println(data);
      Serial.println(F("Datas were sent to server successfully"));
      while (client.connected()) {
        String line = client.readStringUntil('\n');
        if (line == "\r") {
          break;
        }
      }
      String line = client.readStringUntil('\n');
    } else {
      Serial.println(F("Connection to webserver was NOT successful"));
    }
    client.stop();
  }
}

void WiFiEvent(WiFiEvent_t event)
{
  switch (event) {
    case ARDUINO_EVENT_ETH_START:
      Serial.println("ETH Started");
      //set eth hostname here
      ETH.setHostname("esp32-ethernet");
      break;
    case ARDUINO_EVENT_ETH_CONNECTED:
      Serial.println("ETH Connected");
      break;
    case ARDUINO_EVENT_ETH_GOT_IP:
      Serial.print("ETH MAC: ");
      Serial.print(ETH.macAddress());
      Serial.print(", IPv4: ");
      Serial.print(ETH.localIP());
      if (ETH.fullDuplex()) {
        Serial.print(", FULL_DUPLEX");
      }
      Serial.print(", ");
      Serial.print(ETH.linkSpeed());
      Serial.println("Mbps");
      break;
    case ARDUINO_EVENT_ETH_DISCONNECTED:
      Serial.println("ETH Disconnected");
      break;
    case ARDUINO_EVENT_ETH_STOP:
      Serial.println("ETH Stopped");
      break;
    default:
      break;
  }
}

Zapojenie dátových vodičov PHY Ethernetu s ESP32:
Obrázek
Vyžaduje sa ešte pripojenie napájania 3V3.

Odpovědět

Kdo je online

Uživatelé prohlížející si toto fórum: Žádní registrovaní uživatelé a 11 hostů