Metto quà all'inizio il file zippato contenente lo sketh per ESP32, il file .aia per Mit inventor i files LTSpice (se volete realizzare il circuito LC) e l'app .apk compilata
ZipFiles.zip (5.5 MB)
ZipFiles2_temperature.zip (6.9 MB)
Ciao a tutti
Ho deciso di sviluppare questo software per evitare di utiizzare un touch screen dedicato per ogni progetto utilizzato su ESP32 o Arduino
Soprattutto su Arduino l'utilizzo di un touch screen và ad occupare un numero notevole di pin che sono già meno rispetto a un ESP32 e ne rimangono liberi ben pochi.
Il programma l'ho testato sia con ESP32 Wroom che con ESP32-D Wroom, le diffrenze che ho riscontrato tra i due sono che ESP32 deve essere bindato al telefono, mentre su ESP32-D non è necessaria la bindatura, inoltre, quando si carica un nuovo sketch su ESP32-D, non serve premere il tasto di reset ogni volta (veramente noioso), e il monitor seriale parte direttamente.
Cosa serve:
- ESP32 o Arduino con BLE
- Telefono con BLE
- Arduino Ide + MIT App Inventor 2 per Android ( Windows per il login MIT App Inventor) come browser consigliano di utilizzare Chrome o Firefox, io, che ho usato la connessione USB mi son trovato meglio con Chrome, anche se ogni tanto perdono la connessione e bisogna ristabilirla (consiglio di chiudere l'app sul telefono, poi dare il comando di reset connessione nel menu di Mit e poi ristabilire una nuova connessione).
Se volete utilizzare il progetto così com'è, avrete bisogno di un circuito CL tank collegato a ESP32 (pin 16 e 17) e il generatore di forme d'onda AD9833 che utilizza i pin SCLK = 18, MISO = 19, MOSI = 23, SELECT = 5 e un pin a scelta (io ho utilizzato il pin 4) per l'uscita di LedC che può variare il Duty cycle e quindi cambiare l'illuminazione di un led o la velocità di un motore.
Il circuito CL permette di misurare l'induttanza di un induttore collegato, oltre alla frequenza di risonanza (utile ad esempio per un metal detector per ottenere il massimo dal campo magnetico generato) e la lunghezza del ciclo (utile per determinare lo spazio minimo tra un segnale di ON e il successivo).
Purtroppo AD9833, che è ottimo per generare una sinusoidale pulita sino a 12500 Hz, non ha a disposizione comandi per variare il Duty cycle, per cui per il tipo di onda quadra con Duty variabile sono ricorso alla funzione LedC di ESP32 high speed (sino a 19000 Hz con risoluzione 12 bit) che viene utilizzata nel mio sketch se selezionate 3 come tipo di onda.
Perchè Mit inventor e non Android studio o altro?
Perchè tutto fila via meglio e spedito ed è + alla portata di tutti..l'unica cosa che gli rimprovero è il salvataggio in automatico che non si può disabilitare, e questo costringe a salvare spesso il lavoro, così se si sbaglia qualcosa si carica la versione precedente.
Android Studio è sempre in evoluzione e quando carichi un programma fatto un anno prima (sempre con Android Studio) ti genera una marea di errori e ci devi perdere delle ore per risolverli, se poi cerchi di importare pezzi di codice trovati online la cosa si complica maggiormente anche perchè magari quell' istruzione non è + supportata dalle nuove versioni Android, oppure perchè quelle impostazioni sulla privacy (ridicole) continuano a cambiare....rendendo la programmazione su quel tool veramente uno stress e una perdita di tempo enorme.
Chiusa questa parentesi passiamo ad esaminare prima il lato Android con questa immagine che visualizza la prima pagina delle 3 che ho impostato nel programma (selezionabili col tasto B1-B2-B3 sul telefono), ogni pagina ha 6 slot disponibili (potete aumentare sia i bottoni che gli slot e quindi riesaminare tutto il codice sia lato Android che ESP32 per adattarlo alle vostre esigenze) e qua sotto includo uno screenshot della prima pagina
Potete utilizzare queste pagine sia per ricevere dati da Arduino (ad esempio la pagina B1 nel mio esempio riceve i dati dal circuito CL collegato ad ESP32, mentre la pagina B2 l'ho utilizzata per inviare dati ad ESP32, per cui posso selezionare il tipo di onda di AD9833, frequenza ecc. (oppure se seleziono tipo di onda 3 ESP32 eseguirà la routine software high speed che si basa sull'istruzione ledc di Espressif, che genera un'onda quadra con duty cycle modificabile), e il Duty selezionabile nell'indice 10 funzionerà solo sul tipo di onda 3 perchè AD9833 non permette di impostare questo campo.
Quà sotto metto due immagini, la prima visualizza la pagina 2 (B2) e la seconda è presa dall'oscilloscopio ( e poi visualizzate in un mio programma sviluppato in .net) che mostra le 2 forme d'onda attivate dal programma, nel canale 1 una sinusoidale generata da AD9833 e nel canale 2 l'onda quadra generata da ESP32 con duty cycle 25%
I files che impostano i 3 campi di ogni riga, sono letti all'avvio dell' app (caricati dalla sezione MEDIA di MIT) e sono List1Field.csv List2Field.csv e List3Field.csv.
In MIT, se cliccate con il mouse sopra ad esempio in MEDIA List1Field.csv potete scaricare sul PC questo file e modificarlo con un editor di testo e poi ricaricarlo dopo le modifiche in MIT con lo stesso nome e si sostituirà al precedete.
Il primo file (List1Field.csv) è un elenco indice (prima colonna), il secondo file è il nome che apparirà sul bottone (seconda colonna) e il terzo campo è il dato modificable per l'invio verso ESP32 (terza colonna con sfondo bianco) oppure per visualizzare i dati in arrivo da ESP32.
Il terzo campo può essere utile per impostare una variabile di partenza di quel dato campo(se è un campo di spedizione dati e non di ricezione), ma facciamo un esempio: se ad esempio, nella pagina 2 (B2) nella prima riga (scelta della forma d'onda) c'è impostato 1, cliccando sul bottone WaveForm 1-2-3-4, nel campo testo da inviare apparirà automaticamente 1 per cui basta premere su SEND che il comando di cambio di forma d'onda invierà 1 ad ESP32, ovvero selezione onda sinusoidale; se invece nel campo testo inserite 2 verrà salvato sino al riavvio dell'app.
Per attivare l'uscita della forma d'onda bisogna premere sulla scelta della forma d'onda, altrimenti resterà in modo OFF, e poi potrete scegliere la frequenza ecc..
Purtroppo negli ASSETS possiamo solo leggere i files e non salvarli da programma (ad esempio all'uscita dell'app, per cui ce li saremmo trovati uguali al prossimo utilizzo dell'APP) e andare a salvarli in altri FileScope (App,Cache,Legacy,Private e Shared) ci si và a scontrare con le varie versioni Android e con le impostazioni di Privacy, per cui ho preferito utilizzare Assets e non altre directory sparse su SD, memoria interna ecc. almeno tutto rimane interno all'app per una più semplice portabilità su altri telefoni.
Sotto alle 6 righe c'è un tasto di start/stop, questo serve per comunicare a ESP32 di cominciare ad inviare i dati tramite la routine1 che si trova nel loop principale, questa routine funziona solo se stiamo visualizzando la pagina B1 (la posizione della pagina viene controllata da ESP32 che utilizza la routine1 solo se sul telefono viene visualizzata la pagina B1), ma volendo si può anche disabilitare questo controllo, tanto, tramite l'indice del messaggio inviato da ESP32, i dati arriveranno solo alla riga del relativo indice.
Sotto a questo tasto di start/stop c'è una label che visualizza l'indice a cui invieremo i dati nella casella di testo a fianco (cliccando su questa casella di testo viene visualizzata una tastiera con soli dati numerici che possiamo inviare a ESP32 premendo sul tasto SEND ).
Anche in questo caso c'è un controllo se effettivamente siamo nella pagina giusta, ovvero, potremo inviare dati a AD9833 solo se ci troviamo nella pagina 2 (B2).
Il campo testo può inviare un massimo di 10 cifre non superiore a 2147483647.
Lo sketch per ESP32 l'ho già documentato abbastanza nei rem, diciamo che nelle routines iniziali troviamo quella che interpreta la stringa di dati in arrivo dal telefono che sono praticamente 2, ovvero un INDICE (i primi 2 caratteri) e un Valore che sono i numeri provenienti dalla terza colonna del telefono (text box).
Se il secondo valore è nullo, è una stringa di comando, ad esempio per comunicare ad ESP32 che ho cambiato pagina sul telefono (B1-B2-B3).
Se invece è presente il secondo valore, allora viene processato con switch (Identity) {
case...
class MyCallbacks : public BLECharacteristicCallbacks {
void onWrite(BLECharacteristic* pCharacteristic) {
String stringReceived = pCharacteristic->getValue();
if (stringReceived.length() > 0) {
incomingNumbers = "";
for (int i = 0; i < stringReceived.length(); i++) {
incomingNumbers += stringReceived[i];
}
String StringIncoming = incomingNumbers.substring(0, 2); // the first 2 characters are the recipient's identifier (1-18)
int Identity = StringIncoming.toInt();
StringIncoming = incomingNumbers.substring(2); // and then the second value in the string from 2 to the end of the string MAX 10 chars
Valore = StringIncoming.toFloat();
Serial.println((String)Valore);
if (Valore == 0) { // if not are numbers in second field of incoming string then....
// if want reset calibration of metal detection or if you change inductor, just press off sending messages on phone
if (Identity == 30) { // 30 is the identifier of the start/stop send button
Altre subroutines sono per la connessione/disconnessione BLE e dopo il SETUP arriviamo al LOOP dove viene gestito l'invio di dati da ESP32 al telefono, che nel mio progetto interessano solo la prima pagina del programma di cui riporto uno screenshot quà sotto:
void loop() {
if (deviceConnected) {
static uint32_t updateTime;
if (millis() - updateTime >= 1000 && start1 == 1) { // update time is set any 1 second
updateTime = millis();
switch (routine) { // we update only data choose by B1-B2-B3 button on phone
case 1:
routine1(); // is a OUTPUT routine for CL tank circuit (for measure freq,period and inductance of inserted inductor)
break;
case 2:
//is a INPUT routine already done in class MyCallbacks
break;
case 3:
// routine3(); free to use INPUT (in class MyCallbacks) OR OUTPUT same of routine 1
break;
Il Loop guarda innanzitutto se siamo connessi al BLE e poi ogni secondo, a secondo della variabile ROUTINE salta ad una delle 3 possibili routine.
Nel mio esempio è solo la routine 1 che invia dati verso la prima pagina del telefono e riporto qua il codice:
void routine1() { // routine 1 that send 3 parameters to phone, so Freq/Period/inductance of CL circuit
numPulses = 0;
digitalWrite(16, HIGH);
Delay(10); // carico il condensatore
digitalWrite(16, LOW);
delayMicroseconds(30); // <<<<<<< lasso di tempo tra fine segnale ESP32 e inizio oscillazione circuito CL tank
readTime();
inductance = (float)(pow(1.0 / (6.283185307 * freq), 2)) / capacitance;
inductance *= 100000L; // uF
if (numPulses > 0) {
stringVal = String(freq);
T_buff[(stringVal.length() + 1)]; // string + null terminated char
dtostrf(freq, 1, 2, T_buff); // 1 is mininum width, 2 is number ofdecimals
stringVal = String(T_buff);
stringSend = "01" + stringVal;
// Serial.print(freq);
// Serial.print(" >>> ");
// Serial.println(stringSend); //display send string
pCharacteristic->setValue(stringSend);
pCharacteristic->notify();
Delay(10);
stringVal = String(Periodo);
T_buff[(stringVal.length() + 1)];
dtostrf(Periodo, 1, 0, T_buff); //1 is mininum width, 2 is precision
stringVal = String(T_buff);
stringSend = "02" + stringVal;
// Serial.print(Periodo);
// Serial.print(" >>> ");
// Serial.println(stringSend); //display send string
pCharacteristic->setValue(stringSend);
pCharacteristic->notify();
Delay(10);
stringVal = String(inductance);
T_buff[(stringVal.length() + 1)];
dtostrf(inductance, 1, 2, T_buff); //1 is mininum width, 2 is precision
stringVal = String(T_buff);
stringSend = "03" + stringVal;
// Serial.print(inductance);
// Serial.print(" >>> ");
// Serial.println(stringSend); //display send string
pCharacteristic->setValue(stringSend);
pCharacteristic->notify();
Delay(10);
if (counterPeriod < 10) {
counterPeriod++;
calibratedPeriod += Periodo;
if (counterPeriod == 10) {
calibratedPeriod /= 10;
stringVal = String(calibratedPeriod);
T_buff[(stringVal.length() + 1)];
dtostrf(calibratedPeriod, 1, 0, T_buff); //1 is mininum width, 2 is precision
stringVal = String(T_buff);
stringSend = "06" + stringVal; // send calibratedPeriod to index 06
pCharacteristic->setValue(stringSend);
pCharacteristic->notify();
Delay(10);
}
}
// this condition work as metal detector, if the Periodo variable change it is because a proximity of metals is revealed
// if period is decreased is because are a non ferrous material near so alluminium, ore ecc..if increase are a ferrous material near
// but distance of detection is very low (5 cm aprox in air) because 3.3 volt of ESP32 generate a very low magnetic field
if (counterPeriod == 10) { // when calibration is done can see if are variation from calibrated period and new period
if (Periodo > calibratedPeriod + 1 || Periodo < calibratedPeriod - 1) {
tempVariation = Periodo - calibratedPeriod;
} else {
tempVariation = 0;
}
stringVal = String(tempVariation);
T_buff[(stringVal.length() + 1)];
dtostrf(tempVariation, 1, 0, T_buff); //1 is mininum width, 2 is precision
stringVal = String(T_buff);
stringSend = "04" + stringVal; // send calibratedPeriod to index 06
pCharacteristic->setValue(stringSend);
pCharacteristic->notify();
Delay(10);
}
} else {
Serial.println("insert an inductor");
}
}
La prima parte invia un segnale di start al circuito CL ( digitalWrite(16, HIGH) ) e poi interroga la routine readTime()
void IRAM_ATTR isr() {
unsigned long now = micros();
if (numPulses == 0) {
Time1 = now;
} else {
Time2 = now;
detachInterrupt(17); // disable interrupt after second signal from CL wave
}
++numPulses;
}
void readTime() {
// Opzioni: DISABLED RISING FALLING CHANGE ONLOW ONHIGH ONLOW_WE ONHIGH_WE (wake up the ESP32 from light sleep)
attachInterrupt(17, isr, CHANGE);
Delay(5);
//formula frequenza = 1 / Periodo
Periodo = (float)(Time2 - Time1) * 2.0;
freq = 1.0 / Periodo;
freq *= 1000000.0; // Hz
}
che attiva un interrupt ed esamina i cambiamenti (CHANGE) sul pin 17, e al secondo segnale si interrompe l'interrupt e si valuta la lunghezza e quindi la frequenza e l'induzione.
E in seguito si inviano questi dati, una stringa alla volta perchè il BLE di default (ma si possono aumentare) ha un massimo di 20 bytes di spedizione (3bytes di intestazione e 20 di dati) e, importante, ci vuole un ritardo (20 millisecondi) tra un invio e il successivo per non sovraccaricare il BLE che non è molto veloce nell'invio.
Nel mio esempio, ogni 10 letture, calcolo anche la durata media del Periodo che mi serve per determinare la Calibrazione, perchè il circuito funziona anche come metal detector (5-6 cm di distanza in quanto il segnale di start proveniente da ESP32 è di soli 3.3 Volt e quindi il campo magnetico generato dall'induttore è veramente basso) e nel campo Metal Detection sul telefono mi appariranno numeri negativi se avvicino metalli non ferrosi all'induttore e numeri positivi se avvicino metalli ferrosi.
Penso di aver elencato le cose essenziali di questo progetto, poi stà a voi adattare la parte MIT e la parte ESP32 al vostro progetto, ma di base avrete una connessione BLE funzionante utilizzando 2 soli UUID, e un display touch di tutto rispetto anche utilizzando un vecchio telefono e un notevole risparmio di energia su ESP32 senza display, e tanti GPIO liberi.
Con calma stò eseguendo un video e prossimamente metterò il link qua sotto.
Ciaooo a tutti e buon divertimento











