WikiElectronique

Wiki sur l'électronique et l'informatique

Outils pour utilisateurs

Outils du site


esp_idf

Ceci est une ancienne révision du document !


ESP IDF

Installation

Installer Visual Code
Aller dans le menu “Extension”
Installer l'extension “ESP-IDF”
Vérifier que vous avez bien la dernière version d'ESP-IDF

Créer un 1er projet

Carte de développement : ESP32 C6 Zero

Dans Visual Studio, sélectionner le menu ESP-IDF

Cliquer sur “New project”
Brancher votre ESP32
Sélectionner la référence du micro avec une programmation “via builtin USB-JTAG”
Sélectionner le port COM de l'ESP32

Cliquer sur “Choose template”
Sélectionner “ESP-IDF” puis le template “hello_world”

VC vous propose d'ouvrir le nouveau projet, répondez “oui”.

Dans le répertoire “main” se trouve votre code source

Vérifier que vous en mode “UART” pour la programmation du soft
Compiler et flasher votre code (Icone flamme)

Free RTOS

Free RTOS permet d’exécuter plusieurs tâches en “parallèle”
Vous souhaitez faire clignoter une LED toutes les x secondes, attendre la réception d'une trame sur une liaison série, lire des valeurs ADC etc … de nombreuses petites tâches qui vont transformer votre code en usine à gaz avec des délais parfois même bloquant.

Free RTOS va vous permettre de créer des tâches indépendantes à exécuter à intervalle régulier.

Si vous souhaitez faire clignoter une LED à 1Hz, vous avez la possibilité de faire :

while(1)
{
  digitalWrite(LED, HIGH);
  delay(500); // bloqué ici pendant 500ms
  digitalWrite(LED, LOW); 
  delay(500); // bloqué ici pendant 500ms
}

delay() est bien souvent une fonction bloquante qui va demander à votre micro de tourner en boucle et ne fera rien d'autre jusqu'à que sa boucle soit terminée. (Cette méthode c'est le mal !)

Arduino propose aussi une méthode millis() qui renvoie le nombre de millisecondes écoulées depuis le démarrage du micro. Il s'agit d'un compteur qui est incrémenté par un timer.
Il est possible de comparer “l'heure” du début de notre tache (previousTime) à la valeur de millis() (currentTime) et si la différence est supérieur à X ms, alors X ms se sont écoulées. Le code n'est plus bloquant mais cela implique de créer un nombre important de variables et transformer votre code en usine à gaz si vous avez plusieurs taches à exécuter.

unsigned long currentTime=0;
unsigned long previousTime=0;
bool ledState=LOW;
 
while(1)
{
  currentTime=millis();
  if((currentTime-previousTime)>500){
    previousTime=currentTime;
    ledState=!ledState;
    digitalWrite(LED,ledState);
  }
 
  //Ici on peut faire d'autres choses sans être bloqué
}

La 3ème solution utilisée dans tous les programmes un peu complexe c'est : l'OS temps réel comme Free RTOS.

while(1)
{
  xTaskCreate(LedBlink,"Toggle LED",4096,NULL,1,NULL); //Création d'une tâche
  xTaskCreate(FaireTruc2,"FaireTruc2",4096,NULL,1,NULL); //d'une 2ème
  xTaskCreate(FaireTruc3,"FaireTruc3",4096,NULL,1,NULL); //d'une 3ème 
  xTaskCreate(FaireTruc3,"FaireTruc3",4096,NULL,1,NULL); //d'une 4ème
}

Contenu de la tâche :

void LedBlink(void * parameter)
{
    while(1)
    {
        digitalWrite(LED, !digitalRead(LED));
        vTaskDelay(500/ portTICK_PERIOD_MS); //On redonne la main à Free RTOS pour qu'il execute d'autres tâches pendant 500ms
    }
}

Juste pour faire clignoter une LED, c'est peut être un peu lourd mais dès que vous aurez plusieurs tâches à exécuter ça vous simplifiera grandement les choses et vous évitera de vous soucier du séquencement de vos tâches.

Console

Pour écrire quelque chose sur la liaison série, la methode printf() est utilisée:

Une chaîne de caractères

  printf("Hello world!\r\n");

Résultat: Hello world!

Un nombre entier

  int8_t val = 12;
  printf("Un entier %d\r\n",val);

Résultat: Un entier 12

Un nombre entier sur 3 digits

  int8_t val = 12;
  printf("Un entier %03d\r\n",val);

Résultat: Un entier 012

Un nombre entier négatif

    int8_t val_neg = -10;
    printf("Un entier négatif %d\r\n",val_neg);

Résultat: Un entier négatif -10

Un nombre décimal

    float fval = 3.141592;
    printf("Un nombre decimal %f\r\n",fval);

Résultat: Un nombre decimal 3.141592

Un nombre décimal avec deux chiffres après la virgule

    float fval2 = 3.141592;
    printf("Un nombre decimal avec 2 chiffres apres la virgule %.2f\r\n",fval2);

Résultat: Un nombre decimal avec 2 chiffres apres la virgule 3.14

Une valeur hexadécimale

    uint8_t hex = 128;
    printf("Une valeur hexadecimale 0x%X\r\n",hex);

Résultat: Une valeur hexadecimale 0x80

Plusieurs valeurs en même temps

  printf("La valeur N°%d vaut %X en hexa et pi=%.2f\r\n",val,hex,fval);

Résultat: La valeur N°12 vaut 80 en hexa et pi=3.14

String

On a souvent besoin de manipuler des chaînes de caractères. Arduino apporte une solution assez simple et de haut niveau avec son type String donc on peut être tenté de chercher à retrouver la même chose sur ESP-IDF mais ce n'est pas forcément une méthode bien adaptée dans le cadre de la programmation sur microcontrôleur. L'exemple ci-dessous illustre une méthode qui permet de concaténer des éléments pour créer une chaine de caractère avant de l'envoyer sur la liaison série. Cette méthode a l'avantage de maîtriser la taille mémoire allouée.

char buffer[32]; //Création d'un buffer de la taille de la trame qu'on souhaite envoyer
int8_t pt;       //Pointeur d'écriture dans ce tableau
void app_main(void)
{
    pt=sprintf(trame,"%s","ESP32-C6,");
    pt+=sprintf(trame+pt,"VALI:%d,",val);
    pt+=sprintf(trame+pt,"VALF:%.2f;",fval);
 
    printf("Trame: %s dont la taille est %d\r\n",trame,pt);
}

Résultat : Trame: ESP32-C6,VALI:12,VALF:3.14; dont la taille est 27

Il est évidement possible d'écrire ceci en un seul sprintf().

ESP-NOW

L'ESP-NOW est une méthode simple de transmission de données par radio en 2.4Ghz entre plusieurs ESP.

Avantages :

  • Simple à mettre en œuvre
  • Pas de temps d'appairage et peu de latence lors des transmissions
  • Pas de réseau (Pas de réseau ESP-NOW à créer, pas de réseau Wifi à rejoindre, pas de gateway, c'est du vrai point à point)
  • Possibilité de crypter les trames
  • Pas besoin de déclarer l'adresse de l’émetteur sur l'ESP récepteur. (Ca peut se faire en live au moment de la réception de la trame)
  • Portée plus importante que du Wifi classique
  • Consommation réduite

Inconvénients :

  • Limité à 20 devices (On a néanmoins la possibilité de broadcaster une trame à tout le monde et donc d'avoir plus de 20 devices max)
  • Pas de gestion des collisions

Exemple de code pour un récepteur:

#include <stdlib.h>
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/queue.h"
#include "nvs_flash.h"
#include "esp_event.h"
#include "esp_netif.h"
#include "esp_wifi.h"
#include "esp_log.h"
#include "esp_system.h"
#include "esp_now.h"
 
void onReceiveData(const esp_now_recv_info_t *esp_now_info, const uint8_t *data, int len) {
    printf("** Data Received **\n");
    printf("Source: %02x:%02x:%02x:%02x:%02x:%02x\n", esp_now_info->src_addr[0], esp_now_info->src_addr[1], esp_now_info->src_addr[2], esp_now_info->src_addr[3], esp_now_info->src_addr[4], esp_now_info->src_addr[5]);
    printf("Destination: %02x:%02x:%02x:%02x:%02x:%02x\n", esp_now_info->des_addr[0], esp_now_info->des_addr[1], esp_now_info->des_addr[2], esp_now_info->des_addr[3], esp_now_info->des_addr[4], esp_now_info->des_addr[5]);
    printf("Length: %d byte(s)\n", len);
    printf("Data: %d\n\n", data[0]);
}
 
static void init_espnow(void)
{
    if (esp_now_init() != ESP_OK) {
        printf("Error initializing ESP-NOW\n");
        return;
    }
    else
        printf("ESP-NOW ready !\n");
 
    esp_now_register_recv_cb(onReceiveData);
}
 
static void init_wifi(void)
{
    const wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
    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_ERROR_CHECK( esp_netif_init());
    ESP_ERROR_CHECK( esp_event_loop_create_default() );
    ESP_ERROR_CHECK( esp_wifi_init(&cfg) );
    ESP_ERROR_CHECK( esp_wifi_set_storage(WIFI_STORAGE_RAM) );
    ESP_ERROR_CHECK( esp_wifi_set_mode(WIFI_MODE_STA) );
    ESP_ERROR_CHECK( esp_wifi_start() );
}
 
void app_main(void)
{    
    init_wifi();
    init_espnow();
 
    while (1) {
        vTaskDelay(100/ portTICK_PERIOD_MS);
    }
}
** Data Received **
Source: 40:4c:ca:5c:c9:6c
Destination: 40:4c:ca:5b:e9:50
Length: 4 byte(s)
Data: 65

Exemple de code pour un émetteur:

#include <stdlib.h>
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/queue.h"
#include "nvs_flash.h"
#include "esp_event.h"
#include "esp_netif.h"
#include "esp_wifi.h"
#include "esp_log.h"
#include "esp_system.h"
#include "esp_now.h"
 
uint8_t broadcastAddress[] = {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF}; //A remplacer par l'adresse mac du destinataire
esp_now_peer_info_t peerInfo;
int x = 65;
 
void onReceiveData(const esp_now_recv_info_t *esp_now_info, const uint8_t *data, int len) {
    printf("** Data Received **\n");
    printf("Source: %02x:%02x:%02x:%02x:%02x:%02x\n", esp_now_info->src_addr[0], esp_now_info->src_addr[1], esp_now_info->src_addr[2], esp_now_info->src_addr[3], esp_now_info->src_addr[4], esp_now_info->src_addr[5]);
    printf("Destination: %02x:%02x:%02x:%02x:%02x:%02x\n", esp_now_info->des_addr[0], esp_now_info->des_addr[1], esp_now_info->des_addr[2], esp_now_info->des_addr[3], esp_now_info->des_addr[4], esp_now_info->des_addr[5]);
    printf("Length: %d byte(s)\n", len);
    printf("Data: %d\n\n", data[0]);
}
 
static void init_espnow(void)
{
    if (esp_now_init() != ESP_OK) {
        printf("Error initializing ESP-NOW\n");
        return;
    }
    else
    {
        printf("ESP-NOW ready !\n");
        SetColorWhite();
    }
    memcpy(peerInfo.peer_addr, broadcastAddress, 6);
    peerInfo.channel = 0;  
    peerInfo.encrypt = false;
    if (esp_now_add_peer(&peerInfo) != ESP_OK){
        printf("Failed to add peer\n");
        return;
    }
    esp_now_register_recv_cb(onReceiveData);
}
 
static void init_wifi(void)
{
    const wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
    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_ERROR_CHECK( esp_netif_init());
    ESP_ERROR_CHECK( esp_event_loop_create_default() );
    ESP_ERROR_CHECK( esp_wifi_init(&cfg) );
    ESP_ERROR_CHECK( esp_wifi_set_storage(WIFI_STORAGE_RAM) );
    ESP_ERROR_CHECK( esp_wifi_set_mode(WIFI_MODE_STA) );
    ESP_ERROR_CHECK( esp_wifi_start() );
}
 
void app_main(void)
{    
    init_wifi();
    init_espnow();
 
    while (1) {
 
        esp_err_t result = esp_now_send(broadcastAddress, (uint8_t *) &x, sizeof(int));
        if (result == ESP_OK) {
            printf("Data sent successfully\n");
        }
        else {
            printf("Error sending the data\n");
        }
         vTaskDelay(10000 / portTICK_PERIOD_MS);
    }
}

On peut évidement combiner les codes pour faire un émetteur/récepteur.

esp_idf.1719127653.txt.gz · Dernière modification : 2024/06/23 09:27 de jp

Donate Powered by PHP Valid HTML5 Valid CSS Driven by DokuWiki