Un programma per leggere i messaggi HID da un volante Logitech con Esp32S3 Otg Host
Un programma per leggere i messaggi HID da un volante Logitech con Esp32S3 Otg Host
SmartConfig e' un metodo per configurare il WiFi di una Esp32 utilizzando una app su smartphone scaricabile dagli store o personalizzabile tramite sorgenti (EspTouch, Github )
Esistono due versioni. In V1 vengono configurati inviando le credenziali di rete a tutti i dispositivi in ascolto
| V1 |
| V2 |
idf.py erase-flash
// Change from:
ESP_ERROR_CHECK( esp_smartconfig_set_type(SC_TYPE_ESPTOUCH) );
// To:
ESP_ERROR_CHECK( esp_smartconfig_set_type(SC_TYPE_ESPTOUCH_V2) );
Ho provato Espnow, un protocollo per inviare brevi messaggi tra Esp32 e simili senza l'appoggio di un accesspoint
ho usato Idf 5.3.1 ed il programma di esempio
idf.py create-project-from-example "espressif/esp-now:get-started"
idf.py menuconfig
Example configuration
CONFIG_ESPNOW_CHANNEL → e.g. 1
CONFIG_ESPNOW_SEND_LEN → e.g. 200
CONFIG_ESPNOW_SEND_COUNT → e.g. 100
CONFIG_ESPNOW_SEND_DELAY → e.g. 1000 (ms)
se non si vuole un progetto di esempio si aggiunge il componente
idf.py add-dependency "espressif/esp-now"
l'esempio si puo' usare in assenza di wifi e si carica lo stesso firmware di esempio su entrambi i dispositivi. A seconda di send_param->magic=esp_random() viene scelto quale tra i due dispositivi e' il sender e quale e' il receiver
se si vuole forzare il ruolo si
#define FORCE_SENDER 1 // 1 = always sender, 0 = always receiver
sender.c (a seconda delle impostazione di peer mac la comunicazione puo' essere broadcast, specificando come Mac Address FF:FF:FF:FF:FF:FF od indirizzata specificatamente ad un dispositivo)
====================================
#include "esp_wifi.h"
#include "esp_now.h"
#include "esp_log.h"
#include "nvs_flash.h"
#include "string.h"
static const char *TAG = "ESPNOW_SENDER";
// 👉 Replace this with your receiver’s MAC address (check via `esp_read_mac`)
uint8_t peer_mac[] = {0x24, 0x6F, 0x28, 0xAA, 0xBB, 0xCC};
static void send_cb(const uint8_t *mac_addr, esp_now_send_status_t status) {
ESP_LOGI(TAG, "Send to %02X:%02X:%02X:%02X:%02X:%02X status: %s",
mac_addr[0], mac_addr[1], mac_addr[2],
mac_addr[3], mac_addr[4], mac_addr[5],
status == ESP_NOW_SEND_SUCCESS ? "OK" : "FAIL");
}
void app_main(void) {
ESP_ERROR_CHECK(nvs_flash_init());
ESP_ERROR_CHECK(esp_netif_init());
ESP_ERROR_CHECK(esp_event_loop_create_default());
ESP_ERROR_CHECK(esp_wifi_init(&(wifi_init_config_t)WIFI_INIT_CONFIG_DEFAULT()));
ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));
ESP_ERROR_CHECK(esp_wifi_start());
ESP_ERROR_CHECK(esp_wifi_set_channel(1, WIFI_SECOND_CHAN_NONE));
ESP_ERROR_CHECK(esp_now_init());
ESP_ERROR_CHECK(esp_now_register_send_cb(send_cb));
esp_now_peer_info_t peer = {0};
memcpy(peer.peer_addr, peer_mac, 6);
peer.channel = 1;
peer.encrypt = false;
ESP_ERROR_CHECK(esp_now_add_peer(&peer));
const char *msg = "Hello ESPNOW";
while (1) {
esp_err_t res = esp_now_send(peer_mac, (uint8_t *)msg, strlen(msg));
if (res == ESP_OK) ESP_LOGI(TAG, "Message sent: %s", msg);
else ESP_LOGE(TAG, "Send error: %s", esp_err_to_name(res));
vTaskDelay(pdMS_TO_TICKS(1000));
}
}
================================
receiver.c
=============================
#include "esp_wifi.h"
#include "esp_now.h"
#include "esp_log.h"
#include "nvs_flash.h"
static const char *TAG = "ESPNOW_RECEIVER";
static void recv_cb(const esp_now_recv_info_t *info, const uint8_t *data, int len) {
ESP_LOGI(TAG, "From %02X:%02X:%02X:%02X:%02X:%02X | Len: %d | Data: %.*s",
info->src_addr[0], info->src_addr[1], info->src_addr[2],
info->src_addr[3], info->src_addr[4], info->src_addr[5],
len, len, data);
}
void app_main(void) {
ESP_ERROR_CHECK(nvs_flash_init());
ESP_ERROR_CHECK(esp_netif_init());
ESP_ERROR_CHECK(esp_event_loop_create_default());
ESP_ERROR_CHECK(esp_wifi_init(&(wifi_init_config_t)WIFI_INIT_CONFIG_DEFAULT()));
ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));
ESP_ERROR_CHECK(esp_wifi_start());
ESP_ERROR_CHECK(esp_wifi_set_channel(1, WIFI_SECOND_CHAN_NONE));
ESP_ERROR_CHECK(esp_now_init());
ESP_ERROR_CHECK(esp_now_register_recv_cb(recv_cb));
ESP_LOGI(TAG, "Receiver ready");
}
=================================
se si vuole mandare variabili di tipo differente nel pacchetto queste devono essere incluse in una struttura. La lunghezza dei pacchetti e' 250 bytes
=================================
#include "esp_wifi.h"
#include "esp_now.h"
#include "esp_log.h"
#include "nvs_flash.h"
#include <string.h>
static const char *TAG = "ESPNOW_SENDER";
uint8_t peer_mac[] = {0x24, 0x6F, 0x28, 0xAA, 0xBB, 0xCC};
// Define your custom data structure
typedef struct {
uint32_t id;
float temperature;
float humidity;
int status;
char label[16];
} sensor_packet_t;
static void send_cb(const uint8_t *mac_addr, esp_now_send_status_t status) {
ESP_LOGI(TAG, "Send to %02X:%02X:%02X:%02X:%02X:%02X status: %s",
mac_addr[0], mac_addr[1], mac_addr[2],
mac_addr[3], mac_addr[4], mac_addr[5],
status == ESP_NOW_SEND_SUCCESS ? "OK" : "FAIL");
}
void app_main(void) {
ESP_ERROR_CHECK(nvs_flash_init());
ESP_ERROR_CHECK(esp_netif_init());
ESP_ERROR_CHECK(esp_event_loop_create_default());
ESP_ERROR_CHECK(esp_wifi_init(&(wifi_init_config_t)WIFI_INIT_CONFIG_DEFAULT()));
ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));
ESP_ERROR_CHECK(esp_wifi_start());
ESP_ERROR_CHECK(esp_wifi_set_channel(1, WIFI_SECOND_CHAN_NONE));
ESP_ERROR_CHECK(esp_now_init());
ESP_ERROR_CHECK(esp_now_register_send_cb(send_cb));
esp_now_peer_info_t peer = {0};
memcpy(peer.peer_addr, peer_mac, 6);
peer.channel = 1;
peer.encrypt = false;
ESP_ERROR_CHECK(esp_now_add_peer(&peer));
sensor_packet_t pkt = {0};
pkt.id = 1;
while (1) {
pkt.temperature = 22.5 + (esp_random() % 100) / 10.0;
pkt.humidity = 60.0 + (esp_random() % 100) / 10.0;
pkt.status = esp_random() % 2;
strcpy(pkt.label, "Node_A");
esp_err_t res = esp_now_send(peer_mac, (uint8_t *)&pkt, sizeof(pkt));
if (res == ESP_OK)
ESP_LOGI(TAG, "Sent packet: id=%lu T=%.1f H=%.1f status=%d",
pkt.id, pkt.temperature, pkt.humidity, pkt.status);
else
ESP_LOGE(TAG, "Send error: %s", esp_err_to_name(res));
pkt.id++;
vTaskDelay(pdMS_TO_TICKS(1000));
}
}
====================
#include "esp_wifi.h"
#include "esp_now.h"
#include "esp_log.h"
#include "nvs_flash.h"
#include <string.h>
static const char *TAG = "ESPNOW_RECEIVER";
typedef struct {
uint32_t id;
float temperature;
float humidity;
int status;
char label[16];
} sensor_packet_t;
static void recv_cb(const esp_now_recv_info_t *info, const uint8_t *data, int len) {
if (len != sizeof(sensor_packet_t)) {
ESP_LOGW(TAG, "Invalid packet size: %d", len);
return;
}
sensor_packet_t pkt;
memcpy(&pkt, data, sizeof(pkt));
ESP_LOGI(TAG, "From %02X:%02X:%02X:%02X:%02X:%02X | id=%lu | T=%.1f | H=%.1f | status=%d | label=%s",
info->src_addr[0], info->src_addr[1], info->src_addr[2],
info->src_addr[3], info->src_addr[4], info->src_addr[5],
pkt.id, pkt.temperature, pkt.humidity, pkt.status, pkt.label);
}
void app_main(void) {
ESP_ERROR_CHECK(nvs_flash_init());
ESP_ERROR_CHECK(esp_netif_init());
ESP_ERROR_CHECK(esp_event_loop_create_default());
ESP_ERROR_CHECK(esp_wifi_init(&(wifi_init_config_t)WIFI_INIT_CONFIG_DEFAULT()));
ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));
ESP_ERROR_CHECK(esp_wifi_start());
ESP_ERROR_CHECK(esp_wifi_set_channel(1, WIFI_SECOND_CHAN_NONE));
ESP_ERROR_CHECK(esp_now_init());
ESP_ERROR_CHECK(esp_now_register_recv_cb(recv_cb));
ESP_LOGI(TAG, "Receiver ready");
}
Nell'SDK IDF ' contenuto un emulatore ESP32 QEmu
Non si possono simulare sensori e protocolli di trasmissione ma per cose semplici come REPL sulla seriale funziona piu' che bene
Non sono riuscito a fare partire l'emulatore con la finestra grafica
Mi sono comprato una scheda per pilotare un NEMA 17 dalla Cina ed e' arrivata senza istruzioni. Per fortuna dopo un po' di ricerca ho trovato lo schema di connessione che peraltro abbastanza semplice
I motori stepper si dividono in closed loop e open loop: nel primo caso nel motore c'e' un encoder ottico che verifica il corretto posizionamento del motore anche in presenza di carichi che limitino il motore non perdendo passi
Il modulo A4988 non arriva montato ...deve essere inserito facendo coincidere il pin VIN (ultimo in basso fila di sinistra del connettore rosso centrale)
![]() |
| https://docs.google.com/document/d/e/2PACX-1vTyiIMFXQ1cY5TMhOh_0EjdznmC3Nw6CplW7Xx8F61ogOaUpHVyuaXsqrWhIiuE8SjpbON_VzB-rk3R/pub |
Nello sketch che segue viene eseguita anche una accelerazione e decelerazione in partenza ed arrivo (valore di ramp), usando il delayMin viene gestita la velocita' (in pratica l'intervallo tra gli impulsi)
/*
* Stepper motor control with A4988 driver
* Includes acceleration/deceleration ramp
* Speed controlled by potentiometer on A0
*/
#define enablePin 6 // Enable (LOW = ON)
#define dirPin 4 // Direction
#define stepPin 5 // Step
#define potPin A0 // Potentiometer input
const int stepsPerRevolution = 200; // 1.8° per step motor
// Motion control variables
int delayMin; // Minimum delay between steps (fastest speed)
int delayMax = 2000; // Maximum delay (slowest speed)
int rampSteps = 50; // Number of steps to accelerate/decelerate
void setup() {
pinMode(enablePin, OUTPUT);
pinMode(stepPin, OUTPUT);
pinMode(dirPin, OUTPUT);
pinMode(potPin, INPUT);
digitalWrite(enablePin, LOW); // Enable driver
digitalWrite(dirPin, HIGH); // Initial direction
}
void loop() {
// Read potentiometer to set minimum delay (speed)
int potValue = analogRead(potPin);
delayMin = map(potValue, 0, 1023, 2000, 200); // slower -> faster
// Rotate forward
digitalWrite(dirPin, HIGH);
moveStepper(stepsPerRevolution, delayMin);
delay(500); // pause
// Rotate backward
digitalWrite(dirPin, LOW);
moveStepper(stepsPerRevolution, delayMin);
delay(500);
}
//--------------------------------------------
// Function to move stepper with accel/decel
//--------------------------------------------
void moveStepper(int steps, int delayMin) {
for (int i = 0; i < steps; i++) {
int currentDelay;
// Acceleration phase
if (i < rampSteps)
currentDelay = map(i, 0, rampSteps, delayMax, delayMin);
// Deceleration phase
else if (i > steps - rampSteps)
currentDelay = map(i, steps - rampSteps, steps, delayMin, delayMax);
// Constant speed
else
currentDelay = delayMin;
// Step pulse
digitalWrite(stepPin, HIGH);
delayMicroseconds(currentDelay);
digitalWrite(stepPin, LOW);
delayMicroseconds(currentDelay);
}
}
Durante la tesi di dottorato avevo provato a determinare il contenuto di CaCO3 in suoli naturali basandomi solo sul picco di assorbimento ca...