Funktionsgenerator mit dem ESP32, Display und Gehäuse - [Teil 3] - AZ-Delivery

Après avoir ajouté un amplificateur dans la deuxième partie avec lequel vous pouvez régler l'amplitude ainsi que le décalage, nous voulons maintenant faire l'opération directement sur l'appareil au lieu d'utiliser le moniteur série.

Par exemple, le LCD1602 Display Keypad Shield convient, qui dispose d'un écran LCD de deux lignes de 16 caractères et de boutons pour le fonctionnement. Ce bouclier a été conçu pour l'Arduino. Pour faciliter l'utilisation de l'ESP32, nous remplaçons le DevKit CV4 ESP32 de la première partie par la carte ESP32 D1 R32, dont les broches de connexion sont disposées comme celles d'un Arduino Uno. On peut donc brancher le bouclier directement sur elle. Cependant, les exemples ne fonctionneront pas car l'ESP32 a des broches d'entrée/sortie différentes de celles de l'Arduino. En outre, il convient de noter que les entrées de la ESP32 ne tolèrent que 3,3 V.

Les figures montrent le brochage de la carte ESP32 D1 R32 et le brochage du blindage du clavier LCD. Seules les épingles qui sont réellement utilisées sont marquées.

Comme toutes les broches de l'écran LCD sont utilisées comme entrées du contrôleur LCD, nous n'avons pas à nous inquiéter de la tension, car les entrées fonctionneront en toute sécurité même avec 3,3V.

La situation est quelque peu différente avec la connexion par bouton-poussoir. Selon le bouton pressé, il délivre une valeur comprise entre 0 et 5V. Sur le Shield, la sortie est connectée à la borne +5V via une résistance de 2 kOhm. Si nous soudons maintenant une résistance de 3,9 kOhm entre le connecteur du bouton et le connecteur 0V, la tension maximale à ce connecteur est seulement de 5V * 3900 / (2000 + 3900) = 3,3V. Sur la photo, vous pouvez voir cette résistance.  

Nous avons un autre problème avec le connecteur GPIO12. Il doit être réglé sur 0V pendant le processus de démarrage, sinon la tension de fonctionnement de la mémoire flash est commutée sur 1,8V. Ici aussi, une résistance de 10 kOhm entre GPIO12 et GND aide. Mais nous ferions mieux de souder cette résistance à la carte ESP32 D1 R32, car ce problème peut également se produire avec d'autres boucliers Arduino.

Figure 1 : Brochage de l'ESP32 D1 R32

Figure 2 : Brochage du blindage du clavier LCD (uniquement les connecteurs utilisés)

Figure 3 : Panneau arrière ESP32 D1 R32 avec résistance de 10 kOhm entre GPIO12 et GND

Matériel nécessaire

Voici à nouveau toutes les parties, y compris celles de la deuxième partie.

Nombre Dispositif Note:
1 ESP32 D1 R32 Board
2 LCD Keypad Shield
1 Résistance 3,9 kOhm
1 Résistance 10 kOhm
1 LM358 Dual Operation-Intensificateur De Part2
2 Potentiomètre 10 kOhm avec un axe de 4 mm De Part2
1 Résistance 1 kOhm R3 De Part2
1 Résistance 1,5 kOhm R5 De Part2
1 Résistance 2,2 kOhm R2 De Part2
2 Résistance 100 kOhm R1 et R4 De Part2
1 Barre à broches 7-polig
1 Barre à broches 6-polig
3 Barre de broches 3-polig De Part2
1 Barre à broches 2-polig De Part2
3 Jumper Wire, Lire la bunion/féminin 3-polig
2 Jumper Wire, bijoug / féminin 2-polig
1 Carte de circuit imprimé ou plaque perforante 30 x 40 mm De Part2
1 Convertisseur continu-boost à courant continu avec tension positive et négative, entrée 5V, sortie +/-5V De Part2
1 Manchon de montage BNC
2 Boutons de potentiomètre
1 Boutons de l'imprimante 3D avec TPU Filament
4 Boîtiers et pièces de distance à partir de l'imprimante 3D avec le filament de PLA


8 Vis en tôle de 2,2 x 6,5 mm
4 Vis en tôle de 2,2 x 9,5 mm


Le logiciel


/* 
* Funktionsgenerator für Sinus, Dreieck und Rechteck Signale
* Einstellbare Frequenz 20 Hz bis 20 KHz
* Für Dreieck und Rechteck einstellbares Tastverhältnis 0 bis 100%
*/

//Bibliotheken zum direkten Zugriff auf Steuerregister des ESP32
#include "soc/rtc_cntl_reg.h"
#include "soc/sens_reg.h"
#include "soc/rtc.h"

//Bibliotheken zur Verwendung des Digital zu Analog Konverters und für den I2S-Bus
#include "driver/dac.h"
#include "driver/i2s.h"

//Bibliothek für das LCD Display
#include <LiquidCrystal.h>

#define SINFAKT 127.0 //gemessen für Schrittweite = 1 und kein Vorteiler (8.3MHz)
#define SIGNALOUT 26 //Pin für die Signalausgabe
//LCD Pins
#define PIN_RS 12 //Registerselect 0=Befehle 1=Daten
#define PIN_EN 13 //Enable Takt zum Schreiben
#define PIN_D4 17 //Datenbit
#define PIN_D5 16 //Datenbit
#define PIN_D6 27 //Datenbit
#define PIN_D7 14 //Datenbit
#define PIN_BL 5 //Hintergrundbeleuchtung 0=aus

//Analog PIN für Tasten
#define KEYS A12

//Spannungsteiler für Tasten
#define Rv 2000 //Vorwiderstand
#define R3 3900 //Schutzwiderstand für maximal 3.3 V
#define Rp 1000 //Widerstand GPIO2 gegen Masse
#define Rr 0 //Spannungsteiler bei gedrückter RIGHT Taste
#define Ru 330 //Spannungsteiler bei gedrückter UP Taste
#define Rd 950 //Spannungsteiler bei gedrückter DOWN Taste
#define Rl 1950 //Spannungsteiler bei gedrückter LEFT Taste
#define Rs 5250 //Spannungsteiler bei gedrückter SELECT Taste //Tasten Codes
#define NONE 0
#define LEFT 1
#define RIGHT 2
#define UP 3
#define DOWN 4
#define SELECT 5

//Betriebsarten
#define MSINUS 0
#define MRECTANGLE 1
#define MTRIANGLE 2

//Änderungstypen
#define EMODE 0
#define EFREQUENCY 1
#define ERATIO 2 // Init I2C LCD
LiquidCrystal lcd(PIN_RS, PIN_EN, PIN_D4, PIN_D5, PIN_D6, PIN_D7);

//Variablen zum Speichern der Schwellwerte für Taster
uint16_t Ur, Uu, Ud, Ul, Us;

//Buffer zum Erstellen der Dreieckfunktion
uint32_t buf[128];

//Einstellwerte für Kurvenform, Frequenz und Tastverhältnis
int8_t mode = MSINUS; //0=Sinus, 1=Rechteck, 2=Dreieck
float frequency = 1000; //20 bis 200000 Hz
int8_t ratio = 50; //Tastverhältnis 0 bis 100%

int8_t edit = EMODE; //was wird verändert 0=Mode 1=Frequenz 2=Tastverhältnis

uint32_t tic; //Für Wartezeit

int8_t lastKey = 0; //zuletzt ermittelte Taste oder 0 wenn keine
uint16_t step = 0; //Schrittweite für Frequenzerhöhung
float ftmp; //Variable zum Speichern der Frequenz während der Einstellung
int16_t rtmp; //Variable zum Speichern des Tastverhältnis während der Einstellung
int8_t mtmp; //Variable zum Speichern der Betriebsart während der Einstellung

//Flag Ist wahr, wenn die Initialisierung bereits erfolgte
bool initDone = false; //Konfiguration für den I2S Bus
i2s_config_t i2s_config = {
.mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_TX | I2S_MODE_DAC_BUILT_IN), //Betriebsart
.sample_rate = 100000, //Abtastrate
.bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT, // der DAC verwendet nur 8 Bit des MSB
.channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, // Kanalformat ESP32 unterstützt nur Stereo
.communication_format = (i2s_comm_format_t)I2S_COMM_FORMAT_I2S_MSB, //Standard Format für I2S
.intr_alloc_flags = 0, // Standard Interrupt
.dma_buf_count = 2, //Anzahl der FIFO Buffer
.dma_buf_len = 32, //Größe der FIFO Buffer
.use_apll = 0 //Taktquelle
}; //Buffer für Dreieck Wellenform füllen
//Parameter up ist die Dauer für den Anstieg in Prozent
//Parameter sz gibt die Buffergröße für eine Periode an
//es werden die Werte für eine Periode in den Buffer geschrieben
void fillBuffer(uint8_t up, uint8_t sz) {
uint8_t down; //Zeit für die fallende Flanke in %
uint32_t sample; //32Bit Datenwort (I2S benötigt zwei Kanäle mit je 16 Bit
float du,dd,val; //Hilfsvariablen
down=100-up;
//Anzahl der Schritte für Anstieg und Abfall berechnen
uint16_t stup = round(1.0*sz/100 * up);
uint16_t stdwn = round(1.0*sz/100*down);
uint16_t i;
if ((stup + stdwn) < sz) stup++;//Ausgleich eventueller Rundungsfehler
//Amplitudenänderung pro Schritt für Anstieg und Abfall
du = 256.0/stup;
dd = 256.0/stdwn;
//füllen des Buffers
val = 0; //Anstieg beginnt mit 0
for (i=0; i<stup; i++) {
sample = val;
sample = sample << 8; //Byte in das höherwertige Byte verschieben
buf[i]=sample;
val = val+du; //Wert erhöhen
}
val=255; //Abfallende Flanke beginnt mit Maximalwert
//Rest wie bei der ansteigenden Flanke
for (i=0; i<stdwn; i++) {
sample = val;
sample = sample << 8;
buf[i+stup]=sample;
val = val-dd;
}
} //Alle Ausgänge stoppen
void stopAll(){
ledcDetachPin(SIGNALOUT);
i2s_driver_uninstall((i2s_port_t)0);
dac_output_disable(DAC_CHANNEL_2);
dac_i2s_disable();
initDone=false;
}

//Kurvenform Rechteck starten
//Pin für Signalausgang zuweisen
void startRectangle(){
ledcAttachPin(SIGNALOUT,1 );
initDone=true;
} //Frequenz für Rechteck setzen mit entsprechendem Tastverhältnis
void rectangleSetFrequency(double frequency,uint8_t ratio)
{
ledcSetup(1,frequency,7); //Wir nutzen die LEDC Funktion mit 7 bit Auflösung
ledcWrite(1,127.0*ratio/100); //Berechnung der Schrittanzahl für Zustand = 1
}


//Dreiecksignal starten
void startTriangle(){
i2s_set_pin((i2s_port_t)0, NULL); //I2S wird mit dem DAC genutzt
initDone=true;
}

//Frequenz für Dreieck setzen mit entsprechendem Tastverhältnis
double triangleSetFrequency(double frequency,uint8_t ratio)
{ int size=64;
//zuerst wird die geeignete Buffergröße ermittelt
//damit die Ausgabe funktionier muss die I2S Abtastrate zwischen
//5200 und 650000 liegen
if (frequency<5000) {
size = 64;
} else if (frequency<10000) {
size = 32;
} else if (frequency<20000) {
size = 16;
} else {
size = 8;
}
//Abtastrate muss in einer Periode beide Buffer ausgeben
uint32_t rate = frequency * 2 * size;
//Die Abtastrate darf nur innerhalb der Grenzwerte liegen
if (rate < 5200) rate = 5200;
if (rate > 650000) rate = 650000;
//wirklichen Frequenzwert setzen
frequency = rate / 2 / size;

//I2S Treiber entfernen
i2s_driver_uninstall((i2s_port_t)0);
//Konfiguration anpassen
i2s_config.sample_rate = rate;
i2s_config.dma_buf_len = size;
//und mit der neuen Konfiguration installieren
i2s_driver_install((i2s_port_t)0, &i2s_config, 0, NULL);
//Abtastrate einstellen
i2s_set_sample_rates((i2s_port_t)0, rate);
//Buffer füllen
fillBuffer(ratio,size*2);
//und einmal ausgeben
i2s_write_bytes((i2s_port_t)0, (const char *)&buf, size*8, 100);
return frequency;
} //Sinusausgabe vorbereiten
void startSinus(){
//Ausgang für Signalausgang freigeben
dac_output_enable(DAC_CHANNEL_2);
// Sinusgenerator aktivieren
SET_PERI_REG_MASK(SENS_SAR_DAC_CTRL1_REG, SENS_SW_TONE_EN);
// Ausgabe auf Kanal 1 starten
SET_PERI_REG_MASK(SENS_SAR_DAC_CTRL2_REG, SENS_DAC_CW_EN2_M);
// Vorzeichenbit umkehren
SET_PERI_REG_BITS(SENS_SAR_DAC_CTRL2_REG, SENS_DAC_INV2, 2, SENS_DAC_INV2_S);
initDone=true;
} //Frequenz für Sinus setzen
double sinusSetFrequency(double frequency)
{
//Formel f = s * SINFAKT / v
//s sind die Schritte pro Taktimpuls
//v ist der Vorteiler für den 8MHz Takt
//Es gibt 8 Vorteiler von 1 bis 1/8 um die Kombination Vorteiler und
//Schrittanzahl zu finden, testen wir alle acht Vorteiler Varianten
//Die Kombination mit der geringsten Frequenzabweichung wird gewählt

double f,delta,delta_min = 999999999.0;
uint16_t divi=0, step=1, s;
uint8_t clk_8m_div = 0;//0 bis 7
for (uint8_t div = 1; div<9; div++){
s=round(frequency * div/SINFAKT);
if ((s>0) && ((div == 1) || (s<1024))) {
f= SINFAKT*s/div;
/*
Serial.print(f); Serial.print(" ");
Serial.print(div); Serial.print(" ");
Serial.println(s);
*/
delta = abs(f-frequency);
if (delta < delta_min) { //Abweichung geringer -> aktuelle Werte merken
step = s; divi = div-1; delta_min = delta;
}
}
}
//wirklichen Frequenzwert setzen
frequency = SINFAKT * step / (divi+1);
// Vorteiler einstellen
REG_SET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_CK8M_DIV_SEL, divi);
// Schritte pro Taktimpuls einstellen
SET_PERI_REG_BITS(SENS_SAR_DAC_CTRL1_REG, SENS_SW_FSTEP, step, SENS_SW_FSTEP_S);
return frequency;
} //Einstellungsänderungen durchführen
void controlGenerator() {
switch (mode) {
case MSINUS: if (!initDone) startSinus();
frequency = sinusSetFrequency(frequency);
break;
case MRECTANGLE : if (!initDone) startRectangle();
rectangleSetFrequency(frequency,ratio);
break;
case MTRIANGLE : if (!initDone) startTriangle();
frequency = triangleSetFrequency(frequency,ratio);
break;
}
} //Anzeige aktualisieren
//Wenn monitor wahr ist, erfolgt die Ausgabe
//auch auf die serielle Schnittstelle
void displayValues(boolean monitor) {
char buf[15];
//aktuelle Werte ausgeben
String ba;
switch (mode) {
case MSINUS: ba="Sinus "; break;
case MRECTANGLE: ba="Rechteck "; break;
case MTRIANGLE: ba="Dreieck "; break;
}
//Betriebsart ausgeben
lcd.setCursor(0,0);
lcd.print(" ");
lcd.print(ba);
if (monitor) {
Serial.println("**************** Eingestellte Werte *************************");
Serial.print("Betriebsart = "); Serial.println(ba);
}
//Frequenz je nach Wert als Hz oder kHz
if (frequency < 1000){
sprintf(buf,"%6.2f Hz",frequency);
} else {
sprintf(buf,"%6.2fkHz",frequency/1000);
}
//Frequenz ausgeben
lcd.setCursor(0,1);
lcd.print(" F"); lcd.print(buf);
if (monitor) {
Serial.print("Frequenz = "); Serial.println(buf);
}
sprintf(buf,"%2i%%",ratio);
//Tastverhältnis ausgeben
lcd.setCursor(11,1);
lcd.print(" T"); lcd.print(buf);
if (monitor) {
Serial.print("Tastverhältnis = "); Serial.println(buf);
Serial.println();
}
//je nach Edit-Mode Pfeilzeichen ausgeben
switch (edit) {
case EMODE: lcd.setCursor(0,0); break;
case EFREQUENCY: lcd.setCursor(0,1); break;
case ERATIO: lcd.setCursor(11,1); break;
}
lcd.print(char(126));
} //Edit Mode ändern mit UP und DOWN Taste
void changeEdit(boolean up) {
//je nach Richtung Schritte positiv oder negativ
int s = up?1:-1;
edit += s;
//am Ende wieder auf Anfang springen
if (edit < 0) edit = 2;
if (edit > 2) edit = 0;
//die aktuellen Werte in die temporären Werte
//für die Änderung kopieren
ftmp = frequency;
rtmp = ratio;
mtmp = mode;
//Geänderte Editmode ausgeben
Serial.print("Mode = ");Serial.println(mode);
//Anzeige aktualisieren ohne Ausgabe auf serielle
//Schnittstelle
displayValues(false);
}

//Betriebsart ändern mit RIGHT und LEFT Taste
void changeMode(boolean up) {
//je nach Richtung Schritte positiv oder negativ
int s = up?1:-1;
//temporäre Betriebsart ändern
mtmp += s;
//Wenn das Ende erreicht wird wieder auf Anfang springen
if (mtmp < 0) mtmp = 2;
if (mtmp > 2) mtmp = 0;
//Geänderte Betriebsart am Display anzeigen
lcd.setCursor(1,0);
switch (mtmp) {
case 0: lcd.print("Sinus "); break;
case 1: lcd.print("Rechteck "); break;
case 2: lcd.print("Dreieck "); break;
}
} //Frequenz ändern mit RIGHT und LEFT Taste
void changeFrequency(boolean up) {
//war die Taste vorher nicht gedrückt, wird die Schrittweite auf 1 gesetzt
//während die Taste gedrückt bleibt, wird die Schrittweite laufend
//verdoppelt bis eine maximale Schrittweite erreicht wurde
step = (lastKey == NONE)?1:step*2;
if (step > 1024) step = 1024;
//Richtungsfaktor bestimmen
int16_t s = up?1:-1;
//temporäre Frequenz ändern
ftmp = ftmp+s*step;
//auf Minimal- und Maximalwerte prüfen
if (ftmp < 20) ftmp=20;
if (ftmp > 20000) ftmp = 20000;
char buf[15];
//Für die Anzeige Hz oder kHz
if (ftmp > 999) {
sprintf(buf,"%6.2fkHz",ftmp/1000.0);
} else {
sprintf(buf,"%6.2f Hz",ftmp*1.0);
}
//Geänderte Frequenz am Display anzeigen
lcd.setCursor(2,1);
lcd.print(buf);
}

//Tastverhältnis ändern mit RIGHT und LEFT Taste
void changeRatio(boolean up) {
//Richtung festlegen
int8_t jx = up?1:-1;
//Temporäres Tastverhältnis ändern
rtmp = rtmp+jx;
//auf Minimal- und Maximalwerte prüfen
if (rtmp < 0) rtmp=0;
if (rtmp > 100) rtmp = 100;
char buf[15];
//Geändertes Tastverhältnis am Display anzeigen
sprintf(buf,"%2i%%",rtmp);
lcd.setCursor(13,1);
lcd.print(buf);
} //der Funktionsgenerator wird auf die geänderte Einstellung gesetzt
//die temporären Werte werden in die Aktuellen Werte übernommen
void setValues() {
Serial.print("Set values edit = "); Serial.println(edit);
switch (edit) {
case EMODE: stopAll(); mode = mtmp; break;
case EFREQUENCY: frequency = ftmp; break;
case ERATIO: ratio = rtmp; break;
}
//Funktionsgenerator selber ändern
controlGenerator();
displayValues(true);
} //Tastaturspannung einlesen und auswerten
void handleKeys() {
//Tastaturspannung einlesen
int x=analogRead(KEYS);
uint8_t key = NONE;
if (x < Ur) { key = RIGHT; }
else if (x < Uu) { key = UP; }
else if (x < Ud){ key = DOWN; }
else if (x < Ul){ key = LEFT; }
else if (x < Us){ key = SELECT; }
else {key = NONE;}
if (((key == UP) || (key == DOWN)) && (lastKey == NONE)) changeEdit(key == DOWN);
if ((key == LEFT) || (key == RIGHT)) {
switch (edit) {
case EMODE: if (lastKey == NONE) changeMode(key == RIGHT);
break;
case EFREQUENCY: changeFrequency(key == RIGHT);
break;
case ERATIO: changeRatio(key == RIGHT);
break;
}
} if ((key == SELECT) && (lastKey == NONE)) setValues();
lastKey = key;
tic = millis();
}
//Serielle Schnittstelle aktivieren und
//Defaulteinstellungen 1kHz Sinus setzen
//Schwellwerte für Tastatur festlegen
void setup()
{
Serial.begin(115200);
controlGenerator();
lcd.begin(16,2); // initialisiere LCD I2C Anzeige
lcd.clear();
displayValues(true);
tic = millis();
Serial.print("Kommando M,F,A,T,O : ");
pinMode(2,INPUT);
//Schwellwerte für Taster berechnen
//Diese Berechnung ist notwendig, da die Toleranzen sehr
//gering sind, und die Schwellwerte von der Betriebsspannung
//abhängen.
//Versorgungsspannung ohne Taste ermitteln
int x=analogRead(A12);
float Rin = R3 * Rp / (R3 + Rp);
float Ub = x / Rin * (Rin + Rv);
//Schwellspannungen ermitteln
float Uup,Udn,Ulf,Usl,Rtmp;
//Mittelwert für UP Taste
Rtmp = Rin * Ru / (Rin + Ru);
Uup = Ub * Rtmp / (Rtmp + Rv);
//Mittelwert für DOWN Taste
Rtmp = Rin * Rd / (Rin + Rd);
Udn = Ub * Rtmp / (Rtmp + Rv);
//Mittelwert für LEFT Taste
Rtmp = Rin * Rl / (Rin + Rl);
Ulf = Ub * Rtmp / (Rtmp + Rv);
//Mittelwert für Select Taste
Rtmp = Rin * Rs / (Rin + Rs);
Usl = Ub * Rtmp / (Rtmp + Rv);
//eigentliche Schwellwerte berechnen
//immer in die Mitte zwischen zwei Mittelwerten
Ur = Uup/2;
Uu = Uup + (Udn - Uup) / 2;
Ud = Udn + (Ulf - Udn) / 2;
Ul = Ulf + (Usl - Ulf) / 2;
Us = Usl + (x-Usl) /2;
//Schwellwerte auf die serielle Schnittstelle ausgeben
Serial.printf("Schwellwerte: right %i, up %i, down %i, left %i, select %i\n",Ur,Uu,Ud,Ul,Us);

} void loop(){
if ((millis()-tic) > 200) handleKeys();
//Serielle Schnittstelle abfragen
if (Serial.available() > 0) {
//Befehl von der Schnittstelle einlesen
String inp = Serial.readStringUntil('\n');
//und zur Kontrolle ausgeben
Serial.println(inp);
char cmd = inp[0]; //erstes Zeichen ist das Kommando
if ((cmd == 'M') || (cmd == 'm')) { //war das Zeichen 'M' wird die Betriebsart eingestellt
char newMode = inp[1]; //zweites Zeichen ist die Betriebsart
uint8_t nm=0;
switch (newMode) {
case 's':
case 'S': nm=0; break;
case 'r':
case 'R': nm=1; break;
case 't':
case 'T': nm=2; break;
}
if (nm != mode) { //Nur wenn eine Änderung vorliegt, muss was getan werden
stopAll();
mode=nm;
controlGenerator();
}
} else {
//bei den anderen Befehlen folgt ein Zahlenwert
String dat = inp.substring(1);
//je nach Befehl, werden die Daten geändert
switch (cmd) {
case 'F' :
case 'f' :frequency = dat.toDouble(); break; //Frequenz
case 'T' :
case 't' :ratio = dat.toInt(); break; //Tastverhältnis
}
//Grenzwerte werden überprüft
if (ratio > 100) ratio = 100;
if (frequency < 20) frequency = 20;
if (frequency > 20000) frequency = 20000;
controlGenerator();
}
//aktuelle Werte ausgeben
displayValues(true);
Serial.print("Kommando M,F,T : ");
}
}

Croquis téléchargeable:

La partie relative au générateur de fonctions et à l'utilisation via l'interface série est identique au croquis de la partie 1. La nouveauté réside dans l'utilisation via les touches du clavier de l'écran d'affichage. L'évaluation des boutons, en particulier, nécessite une attention particulière.

Figure 4 : Diviseur de tension pour les touches du blindage du clavier LCD et, à gauche, la carte ESP32 D1 R32 avec la résistance parallèle

Le diviseur de tension est conçu de telle sorte qu'à 5V, la différence entre les tensions individuelles est d'environ 1V. Mais comme nous avons intégré la résistance de protection de 3900 ohms pour que la sortie n'atteigne jamais plus de 3,3V, cette différence est réduite. Mais le problème est encore plus grave. La carte ESP32 D1 R32 possède une résistance de 1 kOhm en parallèle avec l'entrée GPIO2, de sorte que seul le GPIO0 doit être connecté au GND pour le clignotement. Cette résistance réduit encore la différence de tension. Le tableau indique les tensions que vous obtenez des boutons-poussoirs (sans résistance parallèle, avec 3900 Ohm en parallèle et avec 3900 Ohm et 1000 Ohm en parallèle.

Taster Sans résistance parallèle 3900 Ohm 3900 Ohm et 1000 Ohm
Pas de taster 5,00 V 3,30% 2,20%
SELECT 3,60% 2,60% 2,04 V
LEFT 2,50% 1,97% 1,10%
DOWN 1,60 V 1,4% 0,89%
UP 0,70% 0,66% 0,52%
RIGHT 0,00 0,00 0,00


Des tests ont montré que le voltage de 5V n'est pas très précis. Avec une alimentation électrique externe, la tension était de 4,4V, l'alimentation par USB étant comprise entre 5,0V sur un port d'ordinateur et 5,2V sur un chargeur USB.

Si des valeurs seuils fixes étaient utilisées pour chaque bouton, l'appareil fonctionnerait ou non en fonction de la tension de fonctionnement. Afin de garantir un fonctionnement sûr, la tension de fonctionnement est donc déterminée lors de la mise en marche sans pression d'un bouton. Les tensions moyennes de chaque bouton peuvent alors être calculées à partir de là. Comme la requête pour l'évaluation de la clé est plus petite, le meilleur résultat est obtenu en ajoutant la moitié de la distance à la valeur moyenne supérieure suivante à la tension moyenne afin d'obtenir la valeur limite.

Le logement

Pour accroître la facilité d'utilisation, nous avons conçu un boîtier qui peut être produit avec une imprimante 3D. Le logement est construit de manière à ce que toutes les pièces puissent y entrer.

Figure 5: Boîtier de l'imprimante 3D

En bas, vous pouvez voir le renfoncement rectangulaire pour l'affichage et les ouvertures pour les boutons. A droite, à côté, se trouvent les deux trous pour les potentiomètres. Dans le mur de droite se trouve un trou pour la prise BNC et sur le mur de gauche un évidement rectangulaire pour la prise USB et pour la fiche d'alimentation.

Quatre cylindres d'écartement avec des trous sont prévus pour la fixation des circuits imprimés.

Le couvercle assorti n'a pas d'évidements et peut être simplement enfilé.

Les boutons sont disposés sur une plaque de base commune pour faciliter le montage. Pour qu'ils puissent être pressés individuellement, ils doivent être imprimés avec un filament élastique, par exemple du TPU. Si cela n'est pas possible, les différents boutons doivent être séparés de la plaque de base après l'impression afin qu'ils puissent être pressés individuellement.

Figure 6 : Boutons de l'imprimante 3D

Enfin, deux écarteurs doivent être insérés entre le bouclier et l'écran pour éviter que l'écran ne se tende lorsqu'il est vissé.

Figure 7 : Écran du clavier LCD, installation des écarteurs

 Liens pour télécharger les fichiers d'impression 3D :

Corps de fond, couvercle, Boutons, Espaceur 1, Ecarteur 2

Assemblage

Le blindage du clavier LCD comporte des points de soudure libres en plus des en-têtes utilisés pour se connecter à la carte ESP32 D1 R32, qui sont connectés en parallèle avec les en-têtes. Nous les utilisons pour connecter les modules externes à la carte. Pour cela, nous devons également les équiper de têtes d'épingle.

Figure 8 : En-têtes de broches supplémentaires sur l'écran du clavier LCD

La résistance de protection de 3,9 kOhm ne doit pas non plus être oubliée.

Nous commençons l'assemblage avec les boutons, qui sont insérés dans les évidements correspondants du boîtier.  Les deux potentiomètres avec câbles de connexion suivent. Pour les câbles de connexion, nous avons coupé en deux un fil de raccordement tripolaire et l'avons soudé aux potentiomètres. Une décharge de traction avec un serre-câble est avantageuse.

Figure 9: Installation des boutons dans le boîtier

Figure 10: Installation des potentiomètres et de la prise BNC (sortie du signal)

Un fil de raccordement bipolaire est également coupé en deux et soudé à la prise BNC.

Lorsque les deux potentiomètres et la prise BNC sont installés, le blindage du clavier LCD peut être fixé dans le boîtier à l'aide de quatre vis. N'oubliez pas d'insérer les deux entretoises entre l'affichage et le tableau. Le module transformateur de tension et le module amplificateur peuvent également être fixés à l'aide de quatre vis chacun.

Figure 11 : Boîtier avec blindage du clavier LCD, convertisseur DC-DC, amplificateur opérationnel et câblage

Les câbles peuvent maintenant être branchés selon le schéma de câblage.

Figure 12: Plan de câblage

La dernière étape consiste à brancher la carte ESP32 D1 R32 sur le blindage du clavier LCD.

Figure 13 : Partie inférieure du boîtier avec l'ensemble complet

Maintenant, il suffit de mettre le couvercle et de monter les boutons des potentiomètres, puis notre générateur de fonctions est prêt à l'emploi. Pour l'alimentation électrique, nous pouvons utiliser soit un chargeur USB, soit une alimentation de 6 à 12 V.

Figure 14 : Générateur de fonctions finies sur un oscilloscope


Bonne chance pour la reconstruction.

Lien vers l'article du blog au format PDF

DisplaysEsp-32Projekte für fortgeschrittene

9 commentaires

Christian Magg

Christian Magg

Ein anspruchsvolles Projekt, das ist mir klar, aber ich komme über diese Fehlermeldung: “CONFLICT! driver_ng is not allowed to be used with the legacy driver” einfach nicht hinaus. Nach meinen Recherchen liegt das an dem i2s.h driver. Der scheint die alte Version zu sein, aber wenn ich die 3 notwendigen neuen einbaue (i2s_std, i2s_pdm und i2s_tdm) bekomme ich das Programm nicht mehr kompiliert. Ich wäre jetzt wirklich für jede Hilfe dankbar. Im Voraus schon mal vielen Dank!

Andreas Wolter

Andreas Wolter

@lorenz: ich vermute, dass es eine Änderung im ESP Core gab. Die Methode ledcDetachPin() gehört zur LED Control (LEDC) Library und ist für PWM Steuerung gedacht. Es scheint, als hätte man an der Stelle Änderungen vorgenommen. Ich würde zuerst versuchen, sie umzubenennen in ‘ledcDetach’
Infos dazu hier: https://espressif-docs.readthedocs-hosted.com/projects/arduino-esp32/en/latest/api/ledc.html

Es könnte auch helfen, auf eine ältere Version der Bibliotheken zurückzugehen. Das ist leider ein sehr häufig auftretendes Problem bei der Verwendung der ESP Bibliotheken.

Grüße,
Andreas Wolter
AZ-Delivery Blog

lorenz

lorenz

Hallo,
ich habe den Fehler.
‘ledcDetachPin’ was not declared in this scope
Wie kann ich das ändern?
Gruß Lorenz

Andreas Wolter

Andreas Wolter

@Bastlersiggi: wahrscheinlich wurde die Bibliothek verändert. Es gibt die Funktion i2s_write(). Damit könnte es wieder funktionieren. Oder zur älteren Version zurückkehren.

https://github.com/earlephilhower/ESP8266Audio/issues/273

Mit freundlichen Grüßen,
Andreas Wolter
AZ-Delivery Blog

Bastlersiggi

Bastlersiggi

Der obige Sketch ergibt bei mir folgende Fehlermeldung:
FunktionsgeneratorESP32.ino:
In function ‘double triangleSetFrequency(double, uint8_t)’:
146:2: error: ‘i2s_write_bytes’ was not declared in this scope
i2s_write_bytes((i2s_port_t)0, (const char )&buf, size8, 100);
^~~~~~~~~~~~~~~
i2s_write_expand

exit status 1
Compilation error: ‘i2s_write_bytes’ was not declared in this scope

Verwendete IDE: 2.3.2 Board: ESP32 WROOM

Welchen Code kann man stattdessen verwenden bzw. den Sketch aktualisieren?

Gerald Lechner

Gerald Lechner

Hallo Claus, GPIO12 ist schon richtig. Es ist nicht GPIO02 gemeint. Der Pin GPIO12 dient beim ESP32 dazu, die Versorgungsspannung für den Flash-Speicher zu steuern. Ist GPIO12 beim Bootvorgang auf High, beträgt die Versorgungsspannung 1.8 V, bei LOW 3.3V. Daher muss GPIO12 beim Booten auf LOW sein.
Das mit dem Widerstand ist richtig. Beim ESP32 Board könnte er weggelassen werden. Ich habe ihn auf das Display gelötet, da ich dieses auch mit der ESP8266 Version genutzt habe. Bei diesem Board ist dieser Anschluss mit A0 verbunden. A0 ist aber ein hochohmiger Eingang, der dann mit 5V beschädigt würde. Mit dem 3.9 kOhm Widerstand ist man auf der sicheren Seite und es funktionieren die Tasten trotzdem problemlos. Der Funktionsgenerator funktioniert natürlich nur mit dem ESP32!

Claus Teubner

Claus Teubner

Hallo,
wie immer, sehr schöner Artikel.
Heute habe ich den versteckten Tipfehler :-) gefunden.
‘…Ein weiteres Problem haben wir mit dem GPIO12 Anschluss. Der muss während des Bootvorgangs auf 0V liegen…’
Sollte doch GPIO2 statt GPIO12 Anschluss sein.
Außerdem sollte doch der 3,9kOhm Widerstand direkt am ESP32 reichen, dann bleibt das Display unverändert und wenn beides zusammengesteckt ist, ist sichergestellt, dass nur max. 3,3V am ESP anliegen. Falls die 3,9kOhm zum booten nicht reicht, tut es auch der 1kOhm alleine, dann sind die Taster-Spannungen etwas größer.

Bernd Albrecht

Bernd Albrecht

@Sven: Der D1 R32 ist “baulich” am Uno angelehnt. Die Uno Shields können also aufgesteckt werden. Aber es gibt deutliche Unterschiede bei der Pinbelegung, der gravierendste ist die zulässige Spannung von 3,3V beim D1 R32. Um das LCD Keypad Shield zu verwenden, müssen deshalb wie beschrieben die zusätzlichen Widerstände angelötet werden.

Sven Waibel

Sven Waibel

Hallo,
wieso steht beim LCD, den ihr verlinkt habt, dass dieser nicht mit dem D1 R32 kompatibel ist?
Grüße
Sven

Laisser un commentaire

Tous les commentaires sont modérés avant d'être publiés

Articles de blog recommandés

  1. ESP32 jetzt über den Boardverwalter installieren - AZ-Delivery
  2. Internet-Radio mit dem ESP32 - UPDATE - AZ-Delivery
  3. Arduino IDE - Programmieren für Einsteiger - Teil 1 - AZ-Delivery
  4. ESP32 - das Multitalent - AZ-Delivery