Funktionsgenerator mit dem ESP32 - [Teil1] - AZ-Delivery
In diesem Beitrag wollen wir mit einem ESP32 einen Funktionsgenerator bauen, der sich zu 100 Prozent der Hardware des ESP32 bedient. Die Software dient lediglich zur Bedienung. Da die Erzeugung der Wellenformen durch eingebaute Hardware des ESP32 erfolgt, gibt es keine Störungen durch den Programmablauf.

Der Funktionsgenerator liefert Sinus und Rechtecksignale mit einer Frequenz von 20Hz bis 200kHz, sowie Dreiecksignale mit einer Frequenz von 40Hz bis 20kHz. Für Rechteck und Dreieck kann das Tastverhältnis zwischen 0 und 100 % eingestellt werden. Die Ausgangsspannung ist nur positiv zwischen 0 und 3.3 V. Das Signal kann an GPIO26 des ESP32 abgenommen werden. Die Bedienung erfolgt über die serielle Schnittstelle.

Im zweiten Teil erhält der Funktionsgenerator ein Display und eine Bedienung über Joystick und selbstverständlich ein Gehäuse aus dem 3D-Drucker.

Benötigte Hardware

Anzahl Bauteil Anmerkung
1 ESP32 DevKit CV4


Der Sinusgenerator

Der ESP32 besitzt einen eingebauten Sinusgenerator, der sein Signal an den beiden Digital zu Analog Wandler Ausgängen (GPIO25 und GPIO26) ausgeben kann. Eine Periode kann in bis zu 65536 Schritte unterteilt werden.  Als Takt wird der interne 8MHz Takt genutzt. Das heißt, für einen Schritt pro Takt müsste die Frequenz 8.000.000 / 65536 = 122 Hz betragen. Versuche haben allerdings gezeigt, dass die Frequenz bei dieser Einstellung 127 Hz beträgt. Somit ist der interne Takt höher als 8MHz.

Zur Einstellung der Frequenz kann die Schrittweite pro Takt eingestellt werden. Das bedeutet, die Frequenz = 127 * Schrittweite. Somit kann die Frequenz in 127 Hz Schritten eingestellt werden. Da dies für niedrige Frequenzen zu ungenau ist, gibt es noch eine zweite Einstellmöglichkeit. Der Takt kann durch 1 bis 8 geteilt werden. Damit ist die niedrigste Frequenz 127/8 = 15,9 Hz. Die gesamte Frequenzformel lautet also Frequenz = 127 / Vorteiler * Schrittweite. Für kleine Frequenzen sieht das dann so aus.

Schrittweite→
Vorteiler↓
1 2 3 4 5 6 7 8
8 15,9 31,8 47,6 63,5 79,4 95,3 111,1 127,0
7 18,1 36,3 54,4 72,6 90,7 108,9 127,0 145,1
6 21,2 42,3 63,5 84,7 105,8 127,0 148,2 169,3
5 25,4 50,8 76,2 101,6 127,0 152,4 177,8 203,2
4 31,8 63,5 95,3 127,0 158,8 190,5 222,3 254,0
3 42,3 84,7 127,0 169,3 211,7 254,0 296,3 338,7
2 63,5 127,0 190,5 254,0 317,5 381,0 444,5 508,0
1 127,0 254,0 381,0 508,0 635,0 762,0 889,0 1016,0


Man sieht, um eine gewünschte Frequenz möglichst gut anzunähern, muss man eine der beiden Variablen, Schrittweite oder Vorteiler, durchprobieren. Da die Schrittweite 65536 Möglichkeiten, der Vorteiler aber nur acht Möglichkeiten hat, ist es naheliegend, den Vorteiler durchzuprobieren. 

Zur Frequenzeinstellung berechnen wir die Schrittweite für jede der möglichen Vorteiler-Einstellungen und verwenden jene, bei der die geringste Frequenzabweichung auftritt. Damit eine schöne Sinusform erreicht wird, sollte die Schrittweite nicht größer als 1024 gewählt werden. Damit wird eine Sinuswelle aus 64 Schritten zusammengesetzt.

Da es für den Sinusgenerator keine fertige Bibliothek gibt, müssen die entsprechenden Bits in Steuerregistern des ESP32 eingestellt werden. Wer sich im Detail dafür interessiert, wie das funktioniert, der erhält die nötigen Informationen von

ESP32 Technical Reference Manual

und zur Ansteuerung der Register aus der Arduino IDE

https://github.com/espressif/arduino-esp32/blob/master/tools/sdk/include/soc/soc/soc.h


Der Rechteckgenerator

Der ESP32 besitzt interne Timer, mit denen an einem beliebigen GPIO-Pin Rechtecksignale mit einstellbarem Tastverhältnis erzeugt werden können. Diese Signale sind in erster Linie zur Erzeugung von Pulsbreiten-Modulation gedacht, können aber auch als Rechteckgenerator mit variablem Tastverhältnis genutzt werden.

Mit der Funktion ledcAttachPin(26,1) wird GPIO26 als Signalausgang für Timer 1 definiert. Die Funktion ledcSetup(1,frequency,7) setzt die Frequenz für Timer1 und die Auflösung für das Tastverhältnis auf 7 Bit. Die Funktion ledcWrite(1,127.0*ratio/100) setzt das Tastverhältnis von Timer1. 127 ist die maximale Anzahl von Schritten bei 7 Bit. Die Variable ratio enthält das Tastverhältnis in Prozent. Mit ledcDetachPin(26) wird der Anschluss GPIO26 wieder freigegeben.


Der Dreieckgenerator

Für den Dreieck-Generator wurde die eingebaute I2S Schnittstelle zweckentfremdet. Eine Betriebsart der I2S Schnittstelle ermöglicht es, Audiodaten zum Beispiel aus einer WAV-Datei an die beiden Analogausgänge GPIO25 und GPIO26 auszugeben.

Die Ausgabe erfolgt als Stereo-Signal und zwar der rechte Kanal auf GPIO25 und der linke auf GPO26. Jeder Abtastwert hat 32 Bit. Die höherwertigen 16 Bit enthalten den rechten, und die niederwertigen den linken Kanal. Andere Einstellungen für 1-Kanal Ausgabe und 8Bit sind zwar möglich, funktionieren aber nicht. Zur Ausgabe wird ein FiFo (First in, First out) Buffer verwendet.

Nun der Trick, den wir benutzen, um damit einen Dreieck-Generator zu realisieren. Wenn der gesamte FiFo-Buffer genau mit einer Periode des Dreiecksignals befüllt wird, und danach kein weiterer Schreibvorgang erfolgt, gibt die I2S Schnittstelle den Inhalt des FiFo-Buffers immer wieder mit der eingestellten Abtastrate aus.

Experimente haben ergeben, dass die Abtastrate zwischen 5,2 kHz und 650kHz sein darf. Wenn wir für eine Periode 128 Abtastwerte nutzen, ergibt das einen Frequenzbereich von 5200/128 = 40,6 Hz bis 5,1 kHz. Für höhere Frequenzen muss die Anzahl der Abtastwerte pro Periode verringert werden. Mit 64 Abtastwerten erhält man 10kHz mit 32 Abtastwerten 20kHz und mit 16 Abtastwerten 40kHz. Allerdings wird die Kurvenform mit abnehmender Zahl an Abtastwerten immer schlechter Siehe zweites Bild mit 16 Schritten je Periode.

 


Das Tastverhältnis kann herangezogen werden, um anstatt eines Dreiecksignals einen Sägezahn zu erstellen. Je nach Tastverhältnis werden die Abtastwerte pro Periode aufgeteilt. Bei einem Tastverhältnis von 20% werden 0.2*128 = 26 Schritte für den Anstieg und 102Schritte für die abfallende Flanke genutzt.

Die Software

/*
 *  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%
 *  Ausgangsspannung 3.3V Signale nur positiv!
*/

//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"

#define SINFAKT 127.0 //gemessen für Schrittweite = 1 und kein Vorteiler (8.3MHz)

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

//Einstellwerte für Kurvenform, Frequenz und Tastverhältnis
char mode = 'S'; //S=Sinus, R=Rechteck, T=Dreieck
float frequency = 1000; //20 bis 200000 Hz
uint8_t ratio = 50; //Tastverhältnis 0 bis 100%

//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(26); 
    i2s_driver_uninstall((i2s_port_t)0); 
    dac_output_disable(DAC_CHANNEL_2);
    dac_i2s_disable();
    initDone=false;
}

//Kurvenform Rechteck starten
//Pin 26 als Ausgang zuweisen
void startRectangle(){
    ledcAttachPin(26,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 Pin26 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 'S' :
    case 's': if (!initDone) startSinus();
        frequency = sinusSetFrequency(frequency);
        break;
    case 'T' :
    case 't' : if (!initDone) startTriangle();
        frequency = triangleSetFrequency(frequency,ratio);
        break;
    case 'R' :
    case 'r' : if (!initDone) startRectangle();
        rectangleSetFrequency(frequency,ratio);
        break;
  }
}

//Serielle Schnittstelle aktivieren und 
//Defaulteinstellungen 1kHz Sinus setzen
void setup()
{
    Serial.begin(115200);
    controlGenerator();
    Serial.print("Kommando M,F,R : ");
}


void loop(){
  //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
      if (newMode != mode) { //Nur wenn eine Änderung vorliegt, mus was getan werden
        stopAll(); 
        mode=newMode;
        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 'R' :
        case 'r' :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
    String ba;
    switch (mode) {
      case 'S':
      case 's': ba="Sinus"; break;
      case 'T':
      case 't': ba="Dreieck"; break;
      case 'R':
      case 'r': ba="Rechteck"; break;
    }
    Serial.println("**************** Eingestellte Werte *************************");
    Serial.print("Betriebsart    = "); Serial.println(ba);
    Serial.print("Frequenz       = "); Serial.print(frequency); Serial.println("Hz");
    Serial.print("Tastverhältnis = "); Serial.print(ratio); Serial.println("%");
    Serial.println();
    Serial.print("Kommando M,F,R : ");
  }
}

Bedienung

Die Bedienung erfolgt über die serielle Schnittstelle. Oben im Seriellen-Monitor ist eine Zeile, in die die Befehle eingegeben werden können. Mit dem Button „Senden“, wird der Text an die serielle Schnittstelle gesendet.

Folgende Befehle sind möglich:

MS         Sinus
MR         Rechteck
MT         Dreieck
F####   Frequenz in Herz
R##        Tastverhältnis in Prozent

Es können auch Kleinbuchstaben verwendet werden. # steht für Zahleneingabe.

Hier der ganze Beitrag zum Download.

Esp-32Projekte für anfänger

27 commentaires

Herbert

Herbert

Guten Tag,

ich möchte Sie darauf hinweisen, dass das Unternehmen ESPRESSIF seine
SW- API “LEDC” geändert hat.
Dadurch kommt es zu Compiler- Fehlern bei bestehenden Programmen.
Dies betrifft auch Ihr o.a. Projekt. (Compilation error: ‘ledcDetachPin’
…)

mit freundlichem Gruß

Andreas Wolter

Andreas Wolter

@Blaubart: Es hängt noch davon ab, wie Sie den Code kopiert haben. Wenn ich den Code vollständig übernehme, ist Zeile 199 eine geschweifte Klammer zu am Ende der Funktion sinusSetFrequency()

Viel aus dem Code ist veraltet. Eventuell liegt es auch daran. Der Link zur soc.h z.B. funktioniert nicht mehr.

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

Blaubart

Blaubart

Ich habe den Code hier von der Webseite Copy-Paste genommen. Zeile 199 in der Funktion “double sinusSetFrequency(double frequency) {”

Andreas Wolter

Andreas Wolter

@Blaubart: diese Zeile kann ich in dem Code nicht finden.
Eine Zeile, die ähnlich aussieht, ist 186: delta = abs(f-frequency);
Wird Ihnen angezeigt, in welcher Datei der Aufruf stattfindet?

Grüße,
Andreas Wolter
AZ-Delivery Blog

Blaubart

Blaubart

Ich erhalte den Fehler
delta = froms(f – frequency);
^~~~~
exit status 1
‘froms’ was not declared in this scope

Fehlt mir eine Bibliothek? Finde im Netz auch nichts zu der Funktion froms().

Andreas Wolter

Andreas Wolter

@k-str: die Datei müsste sich im Projektordner befinden:
https://docs.platformio.org/en/latest/projectconf/index.html

Dieses Projekt ist für die Arduino-IDE geschrieben, denke ich.

Grüße,
Andreas Wolter
AZ-Delivery Blog

k-str

k-str

Hallo,
das ist ein sehr schönes Programm und es funktioniert fast auf Anhieb.
Aber ich habe das gleiche Problem wie @Didier Bonnel.
Leider kann ich die Datei platformio.ini nicht finden. Wo steckt sie?

Didier Bonnel

Didier Bonnel

HI, I sent a comment yesterday telling the triangle and retangle wawes don’t work.
I modify the platformio.ini with
platform = espressif32@3.2
And it’s ok now

Didier Bonnel

Didier Bonnel

Hello,
I compile some time ago and all was OK, but now, I get this warning
warning: ‘I2S_COMM_FORMAT_I2S_MSB’ is deprecated [-Wdeprecated-declarations]
.communication_format = (i2s_comm_format_t) I2S_COMM_FORMAT_I2S_MSB,
and the triangle and the rectangle wawes are not generated!
Do you have any idea?
Thanks
Didier

Wolf

Wolf

Für alle, die den Fehler ‘i2s_write_bytes’ was not declared in this scope bekommen:

Die Funktion i2s_write_bytes ist deprecated und wurde mittlerweile gelöscht. Die korrektur ist:

Ersetzen der Zeile:
i2s_write_bytes((i2s_port_t)0, (const char )&buf, size8, 100);
durch:
size_t i2s_bytes_written;
i2s_write((i2s_port_t)0, (const char*)&buf, size*8, &i2s_bytes_written, 100);

Grüße
Wolf

Tobias

Tobias

i2s_write_Byte —> i2s_write_byte see https://docs.espressif.com/projects/esp-idf/en/release-v3.3/api-reference/peripherals/i2s.html
Die Funktion i2s_write_byte ist deprecated und soll durch i2s_write ersetzt werden, mit Boardverwalter esp32 Version 1.06 läuft der Compiler aber mit der oben genannten Modifikation durch.

Andreas Wolter

Andreas Wolter

im dritten Teil wird statt des Dev Kits ein D1 R32 verwendet. Der darf in Deutschland momentan so nicht verwendet werden, da die Sendeleistung des Funkmoduls nicht den deutschen Normen entspricht. Daher mussten die dazugehörigen Beiträge vorerst offline genommen werden.

Lars

Lars

Ja wir haben im Raspberry Forum auch schon darüber geschrieben und ich musste auf Version 1.0.5 downgraden.

danke

oh wo ist den
https://www.az-delivery.de/blogs/azdelivery-blog-fur-arduino-und-raspberry-pi/funktionsgenerator-mit-dem-esp32-display-und-gehaeuse-teil-3
die Seite hin?

danke

Andreas Wolter

Andreas Wolter

@Lars: es sieht so aus, als wäre eine Bibliothek nicht installiert, oder eine andere Version. Das ist auch möglich.

Lars

Lars

Hallo,

ich bin nun leider in der Situation das ich einen Signalgenerator benötige.
Also fand ich das Script aber ich bekomme da ein Fehler.

i2s_write_bytes((i2s_port_t)0, (const char )&buf, size8, 100); ^~~~~~~~~~~~~~~ i2s_write_expand

exit status 1

‘i2s_write_bytes’ was not declared in this scope

Was muss ich nun machen? danke

Gerald Lechner

Gerald Lechner

Hi Mike, you could use a potentiometer to adjust the output voltage or better a signal amplifier as we describe in the part two of this blog post.

Mike

Mike

How would you reduce or limit the amplitude to 1V?

Nejib Nasr

Nejib Nasr

herr wolfgang, ich bin sehr daran interessiert, ein oled-display hinzuzufügen, aber ich finde immer noch ein problem, dass i2s und i2c gleichzeitig funktionieren, wie Sie dieses Problem überschrieben haben
vielen Dank im Voraus

mike

mike

Klasse, läuft auf Anhieb. Danke
Schön um ein anderes Hobby Equipment zu testen
DSO150, ein kleines ‘Oszilloskop’ mit dem sich die Signale sehr schön visualisieren lassen.

Wolfgang Menzel

Wolfgang Menzel

Hallo, ich nochmal.
Zusätzlich zu OLED-Display, bei dem eine 2. I2C-Schnittstelle werwendet wird, habe ich jetzt noch eine WLan-Funktionalität eingefügt. Kommandos können sowohl über die serielle Schnittstelle als auch über WLan eingegeben werden. Ich verwende für WiFi die App “WiFiControl” aus dem iOS-AppStore.
Ich habe noch einen Fehler gefunden, an der Stelle, wo die Grenzwerte überprüft werden:
//Grenzwerte werden überprüft
if (ratio > 100) ratio = 100;
if (frequency < 20) frequency = 20;
if (frequency > 20000) frequency = 20000 <—- hier war eine 0 zuviel.
Gruß

Wolfgang

Wolfgang

Hallo,
sehr cooles Projekt, hat auch auf Anhieb funktioniert.
Ich habe allerdings noch ein OLED-Display dazugefügt, auf dem die Daten Angezeigt werden.
Leider kann ich hier kein Bild posten, aber falls jemand Interesse hat …
Gruß

Bernd Albrecht

Bernd Albrecht

@ Julius zu der Frage nach anderen Micro Controllern:
Nein, nur der ESP32 hat den Digital zu Analog Wandler.

Julius

Julius

Kann man auch einen wemos d1 mini verwenden?
Besten Dank für eine Rückmeldung!

Wolfhard Jording

Wolfhard Jording

Jetzt funktioniert alles!!! Hatte beim Serial-Monitor falsche Baud-Rate eingestellt.
Vielen Dank für das tolle Projekt.

Wolfhard Jording

Wolfhard Jording

Hallo,
muss es unbedingt ein ESP32 DEVKIT CV4 sein? Ich habe das Programm mal auf ein ESP WROOM-32 gespielt und bekomme auch an GPIO26 ein Sinussignal mit 1,06 kHz. Aber ich kann das Signal nicht ändern. Ich habe mich aber auch noch nicht näher mit dem Programm beschäftigt – sorry!!!

Wolfgang R.

Wolfgang R.

Vielen Dank, Herr Lechner. Das wirkt sehr durchdacht, ich probiere es bestimmt demnächst aus.

Translation and suggestions for Jules Vere:
Many thanks, Mr. Lechner. This seems very well thought out, I will certainly try it out soon.

As to have a translation in English, you could try https://translate.google.com/?hl=de#view=home&op=translate&sl=de&tl=en or https://www.deepl.com/en/translator#de/en/ for the summery in the first paragraph. If this post meets your interest, you could further use the translation software to translate more sections or even comments in the source text.
Surely, further questions here in the comments area would likely be answered in English if asked politely.

Jules Vere

Jules Vere

In english please !

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