2. Advent: Neues Internetradio mit ESP32 und MAX 98357A

Nachdem der Blog-Beitrag Internet-Radio mit dem ESP32 ein großes Echo hervorrief, stellen wir hier jetzt eine zweite Variante vor, die zahlreiche Verbesserungen und Erweiterungen erhielt. Wesentlichste Änderung ist die Verwendung des I2S Digital Verstärkers MAX98357A an Stelle des Analogverstärkers. Das Display wurde auf 4 Zeilen mit 20 Zeichen vergrößert. Neben dem gerade gespielten Sender werden Datum und Uhrzeit, sowie die aktuelle Lautstärke angezeigt. In den beiden unteren Zeilen werden Informationen zum laufenden Programm angezeigt, die mit dem Audiostream mitgeschickt werden. Die Lautstärkeregelung erfolgt ebenso, wie die Senderwahl über einen Rotary-Encoder. Die Konfiguration kann, wie bei der verbesserten Version von Herrn Schröder (siehe Update im alten Beitrag), über einen Browser erfolgen. Über diesen Weg kann auch die Senderliste verändert und erweitert werden. Da manche URLs nicht abspielbar sind, kann eine URL über die Browserkonfiguration jetzt getestet werden, ehe sie gespeichert wird. Die Versorgung über Akku wurde weggelassen, da der Stromverbrauch zu hoch war. Zusätzlich kann ein Firmwareupdate über WLAN (Over The Air = OTA) erfolgen.

 

Benötigte Hardware

Anzahl Bauteil Anmerkung

1

ESP32 Development Board

 

2

I2S Digitalverstärker mit MAX98357A

 

1

Lautsprecher 2er Set

 

1

Widerstand 470 kOhm

 

1

Widerstand 10 kOhm

 

1

Elko 1000uF / 10V

 

1

DC-Einbaubuchse

 

2

Drehgeber Encoder

 

1

Lochrasterplatte 50x70

 

2

Federleisten 19-polig

 

2

Federleisten 7-polig

 

1

Stiftleiste 3-polig

 

1

Stiftleiste 4-polig

 

2

Stiftleiste 5-polig

 

2

Drehknöpfe für 6mm Achse

 

Mehrere

Jumperkabel weiblich zu weiblich

 

1

Bultgehäuse aus dem 3D-Drucker

 

1

Gehäuseboden aus dem 3D-Drucker

 

 

Schaltung

 

Die folgende Tabelle zeigt die Verwendung der Pins des ESP32

Gerät

Bezeichnung

ESP32

Verstärker links

LRC

25

BCLK

26

DIN

27

 

GAIN

GND

 

SD

+5V

 

GND

GND

VIN

+5V

Verstärker rechts

LRC

25

BCLK

26

 

DIN

27

 

GAIN

GND

 

SD

+5V über 470kΩ

 

GND

GND

 

VIN

+5V

LCD-Display

GND

GND

 

VCC

+5V

 

SDA

21

 

SCL

22

Encoder Lautstärke

CLK

14

 

DT

13

 

SW

 

 

+

+3.3V

 

GND

GND

Encoder Senderwahl

CLK

33

 

DT

32

 

SW

35 3.3V über10kΩ

 

+

+3.3V

 

GND

GND

Versorgung

+5V

VIN

 

GND

GND

 

Der ESP32 wird mit den Widerständen und Stiftleisten für die Peripherie auf einer 50x70 mm großen Lochrasterplatte aufgebaut. Für die beiden Verstärker-Module werden 7-polige Federleisten verwendet.


Die Abbildung zeigt die Bestückung und die Verdrahtung auf der Unterseite


Die Abbildung zeigt die Realisierung auf einer Lochrasterplatine 50 x 70 mm

Die Verdrahtung könnte auch über eine einseitig gedruckte Schaltung erfolgen. Lediglich die rot eingezeichnete Verbindung muss über eine freie Verbindung realisiert werden. Für den I2S Bus werden drei Drahtbrücken verwendet.
In die beiden 7-poligen Federleisten werden die zwei Verstärkermodule eingesteckt. Die beiden Rotary-Encoder und das Display werden mit Jumper Wire Kabel F2F mit den entsprechenden Stiftleisten auf der Lochrasterplatte verbunden. Die Lautsprecher werden an den Schraubklemmen der Verstärkermodule angeschlossen.


 

Software

Der Sketch wurde aus Gründen der Übersichtlichkeit in mehrere Teile zerlegt. Dazu wird eine Funktion genutzt, die die Arduino IDE zur Verfügung stellt. Gibt es neben dem Hauptsketch, der denselben Namen wie der Ordner hat, noch weitere „.ino“ oder „.h“ Dateien im selben Ordner, so werden diese vom Compiler in alphabetischer Reihenfolge an den Hauptsketch angehängt.
Da der gesamte Code sehr umfangreich geworden ist, gibt es diesen nur zum Herunterladen.

Sketch zum Herunterladen

Die ZIP-Datei enthält den Ordner mit allen zugehörigen Dateien. Sie muss in das Arbeitsverzeichnis der Arduino IDE (meist Dokumente\Arduino\) entpackt werden. Im Folgenden werden die einzelnen Teile kurz beschrieben. Eine detaillierte Beschreibung finden Sie als Kommentare im Code.

  • Webradio_MAX.ino: Das ist der Hauptsketch. Es werden globale Variablen und Datenstrukturen definiert.
    • setup() nach dem Initialisieren der seriellen Schnittstelle werden die Konfigurationsdaten aus den Präferenzen gelesen. Dann werden die Setupfunktionen der einzelnen Programmteile, mit Ausnahme von Webservers und OTA aufgerufen. Es folgt der Verbindungsaufbau zum lokalen WLAN. War die Verbindung nicht erfolgreich, werden auf dem Display Informationen zur Konfiguration angezeigt. Bei erfolgreicher Verbindung wird die Echtzeituhr initialisiert und die Wiedergabe der zuletzt gehörten Station gestartet. Nun kann auch das Setup für Webserver und OTA aufgerufen werden.
    • loop() prüft zuerst, ob OTA-Anfragen vorliegen und dann, ob es Anfragen für den Webserver gibt. Es wird überprüft, ob die Verbindung zum WLAN noch besteht. Wenn die Verbindung besteht, werden der Audiostream und die beiden Encoder auf Ereignisse geprüft. Einmal pro Minute wird die Anzeige der Uhrzeit aktualisiert. War die Verbindung mehr als 5 Minuten unterbrochen, wird der ESP32 neu gestartet.
  • audio.ino: In diesem Teil werden alle Funktionen im Zusammenhang mit den Audiostreams implementiert.
    • setup_audio() bereitet das System vor. Buffer und Stream-Ausgang werden initialisiert.
    • audio_loop() überprüft den Status des Audio-Streams.
    • MDCallback(void *cbData, const char *type, bool isUnicode, const char *string)
      wird immer dann aufgerufen, wenn im empfangenen Stream neue Metadaten verfügbar sind. Metadaten vom Typ „Title“ werden auf dem Display angezeigt.
    • stopPlaying() beendet das Abspielen des Streams und gibt die zugehörigen Ressourcen frei.
    • bool startUrl(String url) Startet das Abspielen eines Streams von einer gegebenen URL. Ist der Start nicht erfolgreich, wird false zurückgegeben.
    • setGain() setzt die Lautstärke auf den Wert der globalen Variablen currentGain.
  • display.ino: Enthält Funktionen zum Ansteuern des Displays und die Definition von Sonderzeichen wie Lautsprecher und deutsche Umlaute.
    • setup_display() initialisiert das Display und erzeugt die Sonderzeichen im Display-RAM.
    • String extraChar(String text) ersetzt im übergebenen UTF8-Text die deutschen Umlaute durch den entsprechenden Sonderzeichen-Code.
    • showStation() zeigt den Namen der aktuellen Radiostation in der zweiten Zeile des Displays an. Die Anzeige beginnt an der Position 2 und wird auf 18 Zeichen beschnitten. Ist die aktuelle Station auch die aktive Station so wird auf Position 0 das Lautsprechersymbol angezeigt.
    • displayMessage2(uint8_t line, String msg) der übergebene String wird ab der angegebenen Zeile in zwei Zeilen angezeigt. Beide Zeilen werden vorher gelöscht. Hat der String mehr als 20 Zeichen, erfolgt ein Zeilenumbruch. Die zweite Zeile wird nach 20 Zeichen abgeschnitten.
    • displayDateTime() In der ersten Zeile wird Datum und Uhrzeit angezeigt. In der äußerst rechten Position wird die aktuelle Lautstärke in Prozent angezeigt.
    • displayMessage(uint8_t line, String msg) der übergebene String wird in der angegebenen Zeile angezeigt. Die Zeile wird vorher gelöscht. Der String wird auf maximal 20 Zeichen beschnitten.
    • displayClear() löscht alle vier Zeilen.
    • clearLine(uint8_t line) löscht die angegebene Zeile
  • gain.ino: Steuert die Lautstärkeregelung mit einem Rotary-Encoder
    • gain_loop() prüft ob sich der Wert des Rotary-Encoders geändert hat. Ist das der Fall, wird der neue Lautstärkewert gespeichert und eingestellt.
    • IRAM_ATTR readGainISR() Interrupt-Behandlung für den Encoder
    • setup_gain() startet den Encoder, registriert die Interrupt-Routine, setzt die Grenzwerte und den aktuellen Wert als Voreinstellung.
  • index.h: Enthält die HTML-Seiten für den Webserver. Mit der Befehlsfolge
    const char MAIN_page[] PROGMEM = R"=====(
    beliebiger Text………
    )=====";

    kann ein beliebiger Text direkt als Konstante in den Programmspeicher eingebaut werden. Das ist für HTML-Seiten sehr praktisch, da diese dann außerhalb der IDE entworfen und getestet werden können. Die vorliegenden Seiten nutzen jQuery, Ajax und JavaScript. Der Vorteil von Ajax für interaktive Seiten liegt darin, dass bei Änderungen nur der veränderte Teil der Seite aktualisiert wird.  Es werden drei HTML-Konstanten definiert.
    • OPTION_entry ein Template für Einträge in der Auswahlliste für die Radiostationen
    • MAIN_page die Hauptseite mit Konfiguration und Wartung der Senderliste
    • CONFIG_page Seite zur Eingabe der Zugangsdaten, wenn der ESP32 zur Erstkonfiguration im Accesspoint Modus ist.
  • ota.ino: Hier sind die Funktionen zum Update der Firmware über WLAN zu finden.
    • setup_ota() es wird der Hostname und das Passwort festgelegt. Anschließend werden Callback-Funktionen registriert.
    • ota_onStart() wird beim Start eines OTA-Uploads aufgerufen. Das Display wird gelöscht und in der ersten Zeile eine entsprechende Meldung angezeigt
    • ota_onEnd() wird nach dem Beenden des Uploads aufgerufen. Eine entsprechende Meldung wird in der dritten Zeile angezeigt.
    • ota_onProgress(unsigned int progress, unsigned int total) wird während des Uploads in regelmäßigen Abständen aufgerufen und liefert Informationen über den Fortgang. In der zweiten Zeile des Displays wird der Fortgang in Prozent angezeigt.
    • ota_onError(ota_error_t error) wird aufgerufen wenn ein Fehler auftritt. Die Fehlermeldung wird dann in der vierten Zeile angezeigt.
  • rotary.ino steuert die Senderwahl mit einem Rotary-Encoder
    • rotary_loop() prüft, ob sich der Wert des Rotary-Encoders geändert hat. Ist das der Fall, wird die nächste Station aus der Senderliste angezeigt. Wird innerhalb von 10 Sekunden der Knopf am Encoder gedrückt, so wird auf die neue Station umgeschaltet. Wird der Knopf nicht gedrückt, erfolgt kein Wechsel und die aktuelle Station wird wieder angezeigt.
    • IRAM_ATTR readRotaryISR() Interrupt-Behandlung für den Encoder
    • setup_rotary() startet den Encoder, registriert die Interrupt-Routine, setzt die Grenzwerte und den aktuellen Wert als Voreinstellung.
  • stations.ino: definiert eine Programmspeicherkonstante mit der Default-Senderliste.
    • setup_senderliste() füllt die Senderliste im RAM mit der Senderliste aus den Preferences. Gibt es dort keine Senderliste, so wird die Default-Senderliste verwendet.
  • webserver.ino: Enthält das Setup und die Funktionen, um auf http-Anfragen zu reagieren.
    • setup_webserver(): Es werden die einzelnen Funktionen zum Behandeln der http-Anfragen registriert und der Server auf Port 80 gestartet.
    • webserver_loop() es wird geprüft, ob neue Anfragen vorliegen.
    • handleRoot() bearbeitet eine Anfrage für die Hauptseite. Liegt eine Verbindung ins lokale WLAN vor, wird die Hauptseite an den Client gesendet. Ist der ESP32 für die Grundkonfiguration im Accesspoint Modus, wird die Konfigurationsseite übertragen. Zusätzlich müssen in diesem Fall noch eventuell vorhandene Parameter verarbeitet werden, um die Zugangsdaten zu speichern, oder einen Neustart auszulösen.
    • sendStations() reagiert auf das Ajax-Kommando mit der URL /cmd/stations. Sendet die Liste der Stationen als HTML-Optionlist. Diese Liste wird dann über Javascript im Client in das Dropdownelement eingebaut.
    • setAccessData() reagiert auf das Ajax-Kommando mit der URL /cmd/setaccess. Die Konfigurationsdaten SSID, PKEY und NTP-Server werden in den Präferenzen gespeichert.
    • getAccessData() reagiert auf das Ajax-Kommando mit der URL /cmd/getaccess. Die Konfigurationsdaten SSID, PKEY und NTP-Server werden als Antwort gesendet. Als Trennzeichen wird das Zeilenende verwendet.
    • getStationData() reagiert auf das Ajax-Kommando mit der URL /cmd/getstation. Die ID der gewünschten Station wird als Argument erwartet. Es wird der Name, die URL und das Enable-Flag der angegebenen Station als Antwort gesendet. Als Trennzeichen wird das Zeilenende verwendet.
    • setStationData() reagiert auf das Ajax-Kommando mit der URL /cmd/setstation. Die ID der gewünschten Station wird als Argument erwartet. Ist die ID gültig, werden die als Argument übergebenen Daten für den Namen, die URL und das Enable-Flag in der Senderliste gespeichert.
    • testStation() reagiert auf das Ajax-Kommando mit der URL /cmd/teststation. Die URL, die getestet werden soll, wird als Argument erwartet. Es wird versucht, die Wiedergabe der angegebenen URL zu starten. Ist der Versuch nicht erfolgreich, so wird wieder auf die aktuelle Station zurückgeschaltet und mit „ERROR“ geantwortet.
    • endTest() reagiert auf das Ajax-Kommando mit der URL /cmd/endtest. Der Test wird beendet, indem die Wiedergabe der aktuellen Station gestartet wird.
    • restart() reagiert auf das Ajax-Kommando mit der URL /cmd/restart. Der ESP32 wird neu gestartet.
  • wlan.ino: Enthält die Funktion zum Herstellen einer Verbindung mit dem lokalen WLAN oder zur Bereitstellung eines Accesspoints, wenn eine Verbindung nicht möglich ist.
    • boolean initWiFi(String ssid, String pkey) versucht mit den angegebenen Zugangsdaten eine Verbindung zum lokalen WLAN herzustellen. Wenn keine SSID angegeben wurde, oder der Verbindungsversuch nicht gelingt, wird ein Accesspoint gestartet. Über diesen Accesspunkt kann dann von einem Browser unter der Adresse 192.168.4.1 die Konfigurationsseite aufgerufen werden.

Damit der Sketch kompiliert werden kann, muss die Arduino IDE entsprechend vorbereitet werden. Die Arduino IDE unterstützt standardmäßig eine große Anzahl von Boards mit unterschiedlichen Mikrocontrollern, nicht aber den ESP32. Damit man Programme für diese Controller erstellen und hochladen kann, muss daher ein Softwarepaket für die Unterstützung installiert werden.

Zuerst müssen Sie der Arduino IDE mitteilen, wo sie die zusätzlich benötigten Daten findet. Dazu öffnen Sie im Menü Datei den Punkt Voreinstellungen. Im Voreinstellungs-Fenster gibt es das Eingabefeld mit der Bezeichnung „Zusätzliche Boardverwalter URLs“. Wenn Sie auf das Icon rechts neben dem Eingabefeld klicken, öffnet sich ein Fenster, in dem Sie die URL https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_index.json eingeben können.

Nun wählen Sie in der Arduino IDE unter Werkzeug → Board die Boardverwaltung.

Es öffnet sich ein Fenster, in dem alle zur Verfügung stehenden Pakete aufgelistet werden. Um die Liste einzugrenzen, gibt man im Suchfeld „esp32“ ein. Dann erhält man nur noch einen Eintrag in der Liste. Installieren Sie das Paket „esp32“. Falls das Paket schon installiert war, prüfen Sie bitte, ob Sie die neueste Version haben.

 

Für das Display benötigen Sie eine Bibliothek, die über die Arduino Bibliotheksverwaltung installiert werden kann. Das ist die Bibliothek „LiquidCrystal I2C“ von Marco Schwartz in der Version 1.1.2.

 

Eine weitere Bibliothek wird für den Rotary-Encoder benötigt. Ihr Name ist „AiEsp32RotaryEncoder“ von Igor Antolic in der Version 1.4.0.

Kernstück dieses Projekts ist aber die Bibliothek „ESP8266Audio“ von Earle F. Philhower in der Version 1.9.7.

Diese Bibliothek ermöglicht es, verschiedene digitale Audiostreams zu lesen, zu dekodieren und über verschiedene Ausgangskanäle wiederzugeben. Als Eingang, kann der Programmspeicher, der interne RAM´, ein Filesystem, eine SD-Karte, ein HTTP-Stream, oder ein ICY-Stream genutzt werden. Der ICY-Stream wird typisch von Internet-Radios genutzt.
Dekodiert werden können WAV, MOD, MIDI, FLAC, AAC und MP3 Dateien. Für das Webradio wird MP3 benötigt. Die Ausgabe kann schließlich in Speicher, Files oder I2S erfolgen.

Wenn alle Bibliotheken installiert sind, kann der Sketch kompiliert und auf die Hardware hochgeladen werden.

Achtung! Da sich der Sketch aus zahlreichen Teilen zusammensetzt, kann das Kompilieren, insbesondere beim ersten Mal, lange dauern. In den Voreinstellungen sollte „Compiler Warnungen“ auf „keine“ gestellt werden, da die LCD-Bibliothek fälschlicherweise eine Warnung ausgibt

Inbetriebnahme

Bei der ersten Inbetriebnahme sind noch keine Präferenzen vorhanden. Es kann daher keine Verbindung zum lokalen WLAN hergestellt werden. Ein Accesspunkt mit der SSID „webradioconf“ ohne Passwort wird gestartet. Mit z.B. einem Smartphone kann nun eine Verbindung zu diesem Accesspoint hergestellt werden. Danach kann in einem Browser über die Adresse 192.168.4.1 die Konfigurationsseite aufgerufen werden.

Nach dem Neustart sollte die Verbindung zum lokalen WLAN erfolgreich hergestellt werden können. Die Wiedergabe der Station 0 aus der Default Liste (NDR2) sollte mit einer Lautstärke von 50% starten. Mit dem Encoder für die Lautstärke kann die Verstärkung eingestellt werden. Änderungen werden in den Präferenzen gespeichert, sodass beim nächsten Einschalten dieselbe Lautstärke eingestellt wird. Mit dem anderen Encoder kann ein Sender aus der Liste gewählt werden. Beim Drehen des Encoders wird in der zweiten Zeile des Displays der Name der Station angezeigt. Durch Drücken des Kopfes am Encoder wird die gerade angezeigte Station zur aktuellen Station und die Wiedergabe wird gestartet. Auch dieser Wert wird in den Präferenzen gespeichert. Beim nächsten Start wird automatisch die zuletzt gewählte Station wiedergegeben. Wird der Knopf am Encoder innerhalb von 10 Sekunden nicht gedrückt, springt die Anzeige auf die aktuelle Station zurück.

Konfiguration und Bearbeitung der Senderliste

Über die URL http://webradio/ sollte die Konfigurationsseite abrufbar sein. Im oberen Teil können die Zugangsdaten und der NTP-Server geändert werden. Die Änderungen werden erst dann wirksam, wenn der Knopf „Speichern“ geklickt wurde.
Mit dem Knopf „Neustart“ kann ein Neustart ausgelöst werden.

Die Dropdown-Liste enthält alle Sender der Senderliste. Auswählbare Sender haben vor dem Namen einen schwarzen Punkt. Im Formular darunter werden die Daten zur ausgewählten Station angezeigt und können geändert werden. Ist das Häkchen bei „Verwenden“ nicht gesetzt, kann die Station im Gerät nicht ausgewählt werden. Da manche URLs nicht funktionieren, sollte eine neue URL mit dem Knopf „Testen“ getestet werden. Ein Klicken auf diesen Knopf startet die Wiedergabe der URL am Gerät. Sollte die Wiedergabe nicht funktionieren, wird sofort wieder auf den aktuellen Sender zurückgeschaltet und eine Meldung angezeigt. Ist die Wiedergabe möglich, wird eine Box mit einem Knopf angezeigt. Klicken auf diesen Knopf schließt die Box und beendet den Test. Es wird wieder die aktuelle Station wiedergegeben.  Mit dem Knopf „Ändern“ können die Änderungen für die ausgewählte Station dauerhaft geändert werden.

Firmware Update über OTA

Um das Programm zu aktualisieren ist es nicht notwendig, das Gerät zu öffnen und eine USB-Verbindung herzustellen. In der Arduino IDE sollten Sie bei den Ports den folgenden Eintrag sehen.

Über diesen Port können Sie nun einen Sketch hochladen. Zum Schutz muss nach Aufforderung das Passwort „radioupdate“ eingegeben werden. Da die Serielle Schnittstelle nicht genutzt werden kann, werden Meldungen am Display angezeigt.

Hinweise

Der ESP32 hat eine CPU mit zwei Kernen. Beim Internet Radio muss der Web-Datenstrom vom Internet über das http-Protokoll gelesen werden. Das geschieht im System-Thread, der auf dem Kern 0 läuft. Die Anwendung muss den empfangenen Stream dekodieren und in den Buffer schreiben, aus dem dann die Daten über DMA ohne Zutun der CPU ausgegeben werden. Das Dekodieren erfolgt im Anwendungs-Thread, der auf Kern 1 läuft. Wenn nun zusätzlich CPU-Zeit für Display und Encoder verwendet werden, kommt es zu kurzen Unterbrechungen, die beim Drehen der Encoder akustisch zu hören sind.

Eine Stromversorgung über den USB-Bus des ESP32 Moduls ist möglich. Die Versorgung über den externen Eingang ist nur eine Empfehlung.

Das 3D-Objekt zum Pultgehäuse ist so angeordnet, dass ein 3D-Druck ohne Stützstrukturen möglich ist. Den Link zu den Druckdateien finden Sie in der Bauteileliste am Anfang des Beitrages.

Viel Spaß mit dem Radio!

Beitrag als PDF

UPDATE

Herr Andreas Kühn hat das vierzeilige Display durch ein farbiges TFT-Display ersetzt. Er hat uns dankenswerter Weise erlaubt, seine Version hier zu veröffentlichen.

Die Funktionen für das Display mussten natürlich ersetzt werden. Auch zwei zusätzliche Bibliotheken sind erforderlich.
"U8g2" von Oliver in der Version 2.27.6 und
"GFX Library for Arduino" von Moon On Our Nation in Version 1.3.1

Die folgende Tabelle zeigt die Verdrahtung zwischen dem Display und dem ESP32

DISPLAY ESP32
VCC +5V
GND GND
CS GPIO 05
RESET EN
A0 GPIO 17
SDA GPIO 23
SCK GPIO 18
LED 3.3V

 

Sketch zum Herunterladen

DisplaysEsp-32Specials

76 comentarios

Konrad

Konrad

@Horst Mayer:
1. Das mit dem 2 zeiligen Display mit Laufschrift würde mich sehr interessieren. Bitte gerne hier posten. Vielen Dank.
2. Versorgung mit „Battery Expansion Shield 18650“: Auch das würde mich brennend interessieren. Das Produkt habe ich mir auch zugelegt; – bin aber als selbst definierter Anfänger nicht so richtig klar gekommen damit. Auf Nachfrage an AZ, mehr Daten / Hintergrundinfo dazu zu erhalten habe nicht so viel erhalten. Auch hier gerne mal eine Verdrahtung, gerne mit Erläuterung. Großes Danke auch hier.

@Hr. Lechner: In wieweit macht es nicht schon Sinn, den Flash nun mit zu verwenden? Testweise habe ich es schon mit Erfolg gemacht. ( Siehe auch fipsok.de). Das Hochladenden des Programmes dauert inzwischen bei mir ca. 15 Minuten (im Wiederholungsfall – also nicht beim ersten Mal; – da ist es ja noch länger)! Bei nur kleineren Änderungen im Programm macht das jetzt schon keine Freude

Einfach ein Supertolles Projekt. Und wenn das Ganze dann mit SD-Card (mp3 -Player), Wecker und Touchscreen final gemacht wird…… Woh!!

Wenn jemand dazu dann noch die slt Datei für einen 3D Druck zur Verfügung stellt, würde dich schon von Schwarmintelligenzprojekt reden.

Grüße

Konrad

Thommy

Thommy

@ Achim Agster: Vielleicht hat dein Display eine andere I2C Adresse? Standard bei “display.ino” ist 0×27 diesen Wert kannst du ändern.
Mein Display hatte z.B. die Adresse 0×3f.
Du kannst aber auch testen welche Adresse dein Display hat. Dazu bitte folgendes Script auf deinen ESP32 flashen und dann im Serialmonitor nachschauen. Die Adresse notieren, dann in der display.ino eintragen und den Radiocode flashen:

// -—————————————————-
// i2c_scanner
//
// Version 1
// This program (or code that looks like it)
// can be found in many places.
// For example on the Arduino.cc forum.
// The original author is not know.
// Version 2, Juni 2012, Using Arduino 1.0.1
// Adapted to be as simple as possible by Arduino.cc user Krodal
// Version 3, Feb 26 2013
// V3 by louarnold
// Version 4, March 3, 2013, Using Arduino 1.0.3
// by Arduino.cc user Krodal.
// Changes by louarnold removed.
// Scanning addresses changed from 0…127 to 1…119,
// according to the i2c scanner by Nick Gammon
// https://www.gammon.com.au/forum/?id=10896
// Version 5, March 28, 2013
// As version 4, but address scans now to 127.
// A sensor seems to use address 120.
// Version 6, November 27, 2015.
// Added waiting for the Leonardo serial communication.
//
//
// This sketch tests the standard 7-bit addresses
// Devices with higher bit address might not be seen properly.
//

#include

void setup()
{
Wire.begin();

Serial.begin(9600); while (!Serial); // Leonardo: wait for serial monitor Serial.println(“\nI2C Scanner”);

}

void loop()
{
byte error, address;
int nDevices;

Serial.println(“Scanning…”); nDevices = 0; for(address = 1; address < 127; address++ ) { // The i2c_scanner uses the return value of // the Write.endTransmisstion to see if // a device did acknowledge to the address. Wire.beginTransmission(address); error = Wire.endTransmission(); if (error == 0) { Serial.print(“I2C device found at address 0x”); if (address<16) Serial.print(“0”); Serial.print(address,HEX); Serial.println(" !"); nDevices++; } else if (error==4) { Serial.print(“Unknown error at address 0x”); if (address<16) Serial.print(“0”); Serial.println(address,HEX); } } if (nDevices == 0) Serial.println(“No I2C devices found\n”); else Serial.println(“done\n”); delay(5000); // wait 5 seconds for next scan

}

Gerald Lechner

Gerald Lechner

@Achim Agster: Nachdem es beim Kompilieren keinen Fehler gab, nehme ich an, die LCD-Library ist die richtige. Ich habe vielmehr die Vermutung, dass der Kontrast nicht richtig eingestellt ist. Drehen Sie mal am blauen Potentiometer auf der I2C Adapter Platine.

Siegfried

Siegfried

@ Achim Agster: in der Bibliotheksverwaltung gibt es von Marco Schwartz die Version 1.1.2 „LiquidCristal I2C“ , die hatte ich genutzt

Gruß Siegfried

Achim Agster

Achim Agster

Hallo Herr Lechner,

danke für das geniale Projekt. Ich suche schon länger ein minimalistisches Internetradio – dieses hier finde ich klasse.

Ich hab das Radio schrittweise aufgebaut. Momentan ist alles angeschlossen bis auf die beiden Encoder.
Es steigt schon mal kein Rauch auf ;-)
Es kommt sogar Musik und die Webseite meldet sich wie gewünscht.
Ich hab’ nur ein Problem: Das Display zeigt nichts an.
Lötfehler habe ich ausgeschlossen.

Ich verwende ide Library LiquidCrystal I2C von Frank de Brabander Version 1.1.2 (So die Anzeige im Library Manager)
Installiert habe ich die Library manuell nach Download von Github.
Die hat es mir angezeigt als ich nach der von Marco Schwartz gesucht habe. Das repository ist allerdings umgezogen zu John Rickman.
Verwende ich die richtige Library ?

Woran kann es noch liegen ?

Horst Mayer

Horst Mayer

Zunächst ein herzlicher Dank an Herrn Gerald Lechner für dieses tolle Projekt. Vom Sound her ist das mit dem externen I2S Verstärker ja ein ganz gewaltiger Fortschritt gegenüber den internen 8 Bit DACs in der ersten Ausführung.
Aber da es immer noch etwas zu verbessern und weiter zu entwickeln gibt, die folgenden Anmerkungen:
1. „Die Versorgung über Akku wurde weggelassen, da der Stromverbrauch zu hoch war.“ kann ich nicht nachvollziehen. Statt den beiden Modulen „Laderegler und DC/DC Step Up Converter“ habe ich zur Versorgung ein „Battery Expansion Shield 18650“ (gibt es auch bei AZ-Delivery) verwendet. Das vereint beide Funktionen und das Radio spielt damit Stundenlang ohne aufladen.
2. Entgegen dem bzw. zusätzlich zu dem Verdrahtungsplan habe ich den ungenutzten Push Button (SW) des Lautstärke Encoders an den naheliegenden P12 für eine spätere Verwendung angeschlossen. Später habe ich sogar fest gestellt, dass dies in der SW in gain.ino gar auch schon mit „#define ROTARY_ENCODER_BUTTON_PIN 12“ vorgesehen ist. Mit dem high Pegel des nicht gedrückten Push Buttons bootet der ESP32 aber nicht. P12 ist dafür also nicht geeignet und kann zu einer langen Fehlersuche führen.
3. Der externe PullUp nach 3V3 ist bei meinen Rotary Encodern schon auf der Trägerplatine vorhanden. Der externe PullUp ist dann entbehrlich. Doppelt schadet hier aber nicht.
4. Mit der Frage nach dem Pegel-Übergang vom ESP32 mit 3,3 V nach dem Display mit 5 V hat Herr Klaas nicht ganz Unrecht. Für reine Digitalsignale mit TTL-Pegel von 3,3 V nach 5 V ist das unkritisch, wie Herr Lechner in seiner Antwort direkt danach ausgeführt hat. Hier ist der Pegelübergang aber am I2C-Bus. Da wird der I2C Port-Expander am Display mit 5 V und der ESP mit 3,3 V betrieben und die die SDA-Leitung am I2C ist bidirektional. Genau genommen gehört da ein I2C Level Shifter rein. Ich bin das Problem dadurch umgangen, dass ich ein 3,3 V Display verwende und daher alles an 3,3 V betreibe.
5. Die Lautstärkeanzeige mit
lcd.print(" “);
lcd.setCursor(18,0);
lcd.print(g);
zeigt die ein oder zweistellige Lautstärke unschön linksbündig an.
Schöner geht es wie folgt:
if (g < 10) lcd.print(”0");
lcd.print(g);
Also bei Werten von 0 bis 9 ein führende Null oder, wer will, kann auch ein Leerzeichen nehmen, und dann einstellig die Lautstärke und 2 Stellige Werte 1:1 auf die beiden Stellen.
6. Die Drehrichtung des Sender Rotary Encoders ist falsch herum. Eine Rechtsdrehung führt zu niedrigeren statt (wie zu erwarten) höheren Stationsplätzen. Ändern kann man dies durch Vertauschen der Leitungen an den Pins 32 und 33 am ESP32 oder durch entsprechende Anpassung der defines für ROTARY_ENCODER_A und ROTARY_ENCODER_B in rotary.ino (hier ebenfalls 32 und 33 untereinander tauschen)
7. Vermutlich durch Rundungsfehler erzeugt die Lautstärke 1 genauso wie Lautstärke 0 absolute Stille im Lautsprecher. Abhilfe: „float v = curGain / 100.0;“ –> „float v = (curGain + 1) / 100.0;“ in audio.ino.
8. Der String „char title64; //character array to hold meta data message“ im Hauptprogramm ist zu vergrößern, z.B. zu verdoppeln, da die ausgestrahlten Meldungen teilweise länger als 64 Zeichen sind. Bei BR24 habe ich schon über 100 gesehen.
9. Die im Programmlauf asynchrone Ausgabe von Datum und Uhrzeit alle 60 s ist unglücklich ausgeführt und kann dazu führen, dass die angezeigte Zeit um fast eine Minute nachgehen kann. Wird die Zeitanzeige gerade in der 59. Sekunde aktualisiert, bleibt diese falsche Zeit über die Folgeminute falsch stehen. Hier wäre eine Synchronisation auf den Wechsel der „echten“ Zeit angebracht, also die Ausgabe immer dann, wenn ein Wechsel der Minute erkannt wird. Das führt auch nur zu einer Ausgabe pro Minute, aber eben zum richtigen Zeitpunkt.
10. Da 2 Zeilen zu je 20 Zeichen, insgesamt also 40 Zeichen nicht reichen und der Zeilenumbruch beim nächst gelegenen Leerzeichen auch kritisch ist, habe ich die Textausgabe als Laufschrift in einer Zeile realisiert. (dies u.a. weil ich ein 2 zeiliges Display verwendet habe). In der oberen Zeile: Lautstärke, Lautsprechersymbol und dann die Station im Wechsel mit der Zeit. Und in der zweiten Zeile die Textmeldung, bis 20 Zeichen statisch bis zum nächsten Wechsel, bei mehr als 20 Zeichen als Laufschrift. Die Codeänderungen dazu sind etwas zu umfangreich für diese Aufzählung. Auf Wunsch kann ich sie aber in einem separaten Posting nachreichen.
Unabhängig von dieser Aufzählung habe ich kein Gehäuse gedruckt, sondern nach alter Väter Sitte (Bohrer, Fräser etc.) das Radio in eine alte 5 ¼ Diskettenbox aus Kunststoff eingebaut und damit einen Look ähnlich einem alten Autoradio erreicht. (rechts und links ein Drehknopf auf der schmalen Seite und dazwischen das Display) Ein Bild davon kann ich hier wohl nicht posten, aber gerne zur Veröffentlichung am Ende des Beitrags zur Verfügung stellen.
Gruß Horst Mayer

Siegfried

Siegfried

Hallo an Alle,

ich habe das Radio mit dem Display nach Andreas Kühn aufgebaut. Jetzt möchte ich mit einen größeren Display probieren und dazu müssen die Einstellungen in der Display.ino geändert werden. Hat dieses schon mal jemand gemacht und kann Unterstützung geben, an welchen Stellen und welche Werte.

Vielen Dank an Gerald und Herrn Kühn.

Siegfried

Achim Kleine

Achim Kleine

@ Andreas

Habe das nun auch mit dem PCM5102 umgesetzt, funktioniert bei mir, wenn auf der Bestückungsseite die Brücke SCK gesetzt wird.
Gab dazu im Netz eine Beschreibung, da auf der Platine noch mehr Brücken auf der Rückseite sind hab ich das mal hier kopiert.

https://raspberrypi.stackexchange.com/questions/76188/how-to-make-pcm5102-dac-work-on-raspberry-pi-zerow

“On the front (component side) there is one pair of pads which may be bridged to tie the SCK (system clock) low.
This will force the PCM510x to generate the system clock using its internal PLL.
You may bridge these pads to remove the need for an external SCK or connect the SCK pin to ground (0V).
The Raspberry Pi does not supply a system clock so this will be required to connect to the Raspberry Pi.

On the back (non-component side) there are 4 sets of 3 pads for the 4 functions:

FLT – Filter select : Normal latency (Low) / Low latency (High) DEMP – De-emphasis control for 44.1kHz sampling rate: Off (Low) / On (High) XSMT – Soft mute control(1): Soft mute (Low) / soft un-mute (High) FMT – Audio format selection : I2S (Low) / Left justified (High)

The centre pad is connected to the corresponding pin. Each of these function pads may be bridged with solder either high or low (or the pins connected to +3.3V / 0V).
(My board is supplied with 1, 2 & 4 bridged low and 3 bridged high, i.e. normal latency filter, 44.1kHz de-emphasis disabled, soft-mute not asserted, I2S audio format.)

The normal filter is an FIR with good response, delaying the signal by approx. 500us (at 44.1 kHz) which should be fine. The fast filter is an IIR with slightly poorer response and delays the signal approx. 80us. Very few (if any) audio sources have pre-emphasis applied so DEMP should be low. The XSMT pin would allow muting of the output via a GPI (if the solder bridge was removed).
Raspberry Pi supports I2S bitstream so FMT should be low."

Bei meinem Board waren alle Rückseitigen Brücken korrekt gesetzt, einzig SCK auf der Vorderseite musste gelötet werden.

Gerald Lechner

Gerald Lechner

@Andreas: Es sollte mit dem PCM5102 auch funktionieren. Nachdem Sie die Definition der Pins geändert haben, nehme ich an, dass Sie die den PCM5102 dann auch entsprechend angeklemmt haben. Datenleitung an Pin 25 rechts/links Umschaltung an Pin 26 und den Bittakt an Pin 27.
Bezüglich Titel/Interpret.
Im File audio.ino gibt es die Funktion MDCallback, die Metadaten im Stream findet und falls es ein Titel ist die Nachricht in die globale Variable title speichert. Außerdem muss das Flag newTitle auf true gesetzt werden. In der Hauptschleife im File webradio_MAX.ino wird dieses Flag abgefragt. Falls es gesetzt ist, wird die Funktion displayMessage2(2,title) aufgerufen, die den Titel ab der dritten Zeile anzeigt. Diese Funktion befindest sich im File display.ino. Es könnte auch sein, dass die Station, die Sie edmpfangen keine Metadaten mitsendet. Aber ich nehme an, dass Sie verschiedene Stastionen versucht haben.

Andreas

Andreas

Hi Gerald,
super Nummer mit der neuen Soft.
Leider macht der PCM5102 den ich nutze, nur geschtotter.
So angeklemmt: #define DOUT 25, #define LRCLK 26, #define BCLK 27.
Leider kein Titel und Interpret im Display.

Gruß
Andreas

Konrad S.

Konrad S.

Hallo Herr Lechner,

absolut tolles Projekt. Speziell mit der überarbeiteten Codevariante. Die kurzen “Abhacker” sind nun weg! Toll.
Auch dass man die Senderliste umnummerieren kann; – Klasse!

Gestern habe ich von meinem Schwager dann den 3D Druck bekommen. Alles passt jetzt. Wahnsinn. Ich bin total begeistert.
Es gibt somit von meiner Seite fast nichts mehr zu verbessern (eigentlich Schade).

Kleiner Hinweis: OTA habe ich mal ausprobiert. So richtig hat es nicht geklappt. Auch wenn ich das Passwort “radioupdate” eingegeben habe; – nach einer gefühlten halben Stunde mit Warten habe ich abgebrochen und habe das Radio aufgeschraubt und über die übliche USB und serielle Schittstelle hochgeladen; ohne Probleme. Hätte ich noch länger warten sollen?

Weitere Frage: Gibt es zum TFT Display auch eine 3D Druck Datei? Würde mich auch interessieren.

Bezüglich der Platine habe ich schon eine email an Sie geschrieben.

Danke aus dem Süden der Republik

Konrad

Riemi

Riemi

Hat noch jemand eine alternative für die Lautsprecher um noch bessere Qualität zu haben?

Siegfried

Siegfried

Hallo in die Runde,

gibt es hier einen „Mitbauer“, der das Design auf eine Platine zaubern wird und diese evtl. auch produzieren lässt. Ich hab die Variante mit dem 1,8“ Display und würde mich da finanziell beteiligen.

Rutscht gut ins Jahr 23

Vielen Dank an Gerald und das AZ Team

Ulrich Klaas

Ulrich Klaas

Hallo,
mich haben noch ein paar Sachen beim Tuning gestört und deshalb habe ich rotary_loop() etwas geändert.
1) Wenn ein Sender läuft und man sucht durch wählt den Sender dann aber nicht an springt die Anzeige ja wieder auf den aktiven Sender.
Das ist schön. Nur wenn man wieder tunen will geht es diesmal nicht von dem eingestellten Sender weiter sonder von da wo man beim
letzten mal aufgehört hat.
2) Hat man mehrere deaktivierte Sender oder halt am Ende der Liste viele noch nicht definierte so wird der nächste aktivierte angezeigt nur man
muss halt n-mal weiter drehen (also über alle deaktivierten) bis sich die Anzeige wieder ändert.
3) Da ist auch ein Bug drin : Will man rückwärts über einen deaktivierten Sender drehen hängt die Anzeige ! Man kann nur noch vorwärts drehen.
So sieht meine modifizierte rotary_loop() aus :

//handle events from rotary encoder
//called from main loop

uint8_t changedByCode = false;

void rotary_loop()
{
int16_t v;
uint8_t disabledStations;
int16_t richtung;

disabledStations = false; if (changedByCode) { // Value changed by my changes (uk) do not retrigger and clean event rotaryEncoder.encoderChanged(); changedByCode = false; } else { //don’t do anything unless value changed if (richtung = rotaryEncoder.encoderChanged()) { Serial.print(“Encode changed. Richtung:”);Serial.println(richtung); uint8_t cnt = 0; //overflow counter, prevents endless loop if no station is enabled v = rotaryEncoder.readEncoder(); while ((!stationlist[v].enabled) && (cnt < 2)){ disabledStations = true; if ((richtung > 0) && (richtung != STATIONS)) // STATIONS means from 0 to 45 backwards ! { v++; if (v >= STATIONS){ v=0; cnt++; } } else { v—; if (v < 0) { v = STATIONS – 1; cnt++; } } } //set new currtent station and show its name if (v < STATIONS) { curStation = v; showStation(); if (disabledStations) { // found di//no event to handle. rotaryEncoder.encoderChanged() triggers on thissabled stations → correct rotary to jump over rotaryEncoder.setEncoderValue(curStation); //set encoder to the found station changedByCode = true; //no event to handle. rotaryEncoder.encoderChanged() triggers on this } lastchange = millis(); } } //if no change happened within 10s set active station as current station if ((lastchange > 0) && ((millis()-lastchange) > 10000)){ curStation = actStation; lastchange = 0; showStation(); rotaryEncoder.setEncoderValue(actStation); //start tuning from here again changedByCode = true; //no event to handle. rotaryEncoder.encoderChanged() triggers on this } //react on rotary encoder switch if (rotaryEncoder.isEncoderButtonClicked()) { //set current station as active station and start streaming actStation = curStation; pref.putUShort(“station”,curStation); if (!startUrl(String(stationlist[actStation].url))) { //if start fails we switch back to station 0 actStation = 0; startUrl(String(stationlist[actStation].url)); } //call show station to display the speaker symbol showStation(); } }

}

klaus Treutler

klaus Treutler

@Gerald Lechner Danke für die Erläuterung der Funktion zu Metadaten. Ja, ich habe verschiedene Stationen durchprobiert; nirgendwo melden sich Titel o.ä. in Zeile 3 und 4 des Displays oder im Terminal

Gerald Lechner

Gerald Lechner

@Ulrich Klaas: Bei der Verbindung von 3.3V und 5V Logik ist die Übertragungsrichtung wichtig. Ausgang 3.3 V → Eingang 5V kein Problem. Die 5V Logik erkennt ein High Signal ab etwa 2V. Ausgang 5V → Eingang 3.3V erfordert einen Levelshifter, da die 5V vom Ausgang den 3.3V Eingang schädigen würden. Beim Display werden nur Daten vom Mikrocontroller zum Diplay übertragen, daher keine Levelshifter erforderlich.
@klaus Treutler: Die Warnmeldung hat nichts damit zu tun, sie resultiert aus einem Fehler im Properties File der Bibliothek. Um Ihrem Problem auf die Spur zu kommen, müssen Sie die betroffenen Funktionen überprüfen. Im File audio.ino gibt es die Funktion MDCallback, die Metdaten im Stream findet und falls es ein Titel ist die Nachricht in die globale Variable title speichert. Außerdem muss das Flag newTitle auf true gesetzt werden.
In der Hauptschleife im File webradio_MAX.ino wird dieses Flag abgefragt. Falls es gesetzt ist, wird die Funktion displayMessage2(2,title) aufgerufen, die den Titel ab der dritten Zeile anzeigt. Diese Funktion befindest sich im File display.ino.
Es könnte auch sein, dass die Station, die Sie edmpfangen keine Metadaten mitsendet. Aber ich nehme an, dass Sie verschiedene Stastionen versucht haben.

Ulrich Klaas

Ulrich Klaas

Hallo,
in der Schaltung wird ein 5V Display verwendet. Der ESP arbeitet aber mir 3.3V Logik.
Normalerweise schalte ich da einen Levelshifter zwischen. Sehen Sie da kein Problem ?

Ulrich Klaas

klaus Treutler

klaus Treutler

@Gerald Lechner Danke für die schnelle Antwort und die Erläuterungen. Den Tipp zur Korrektur bzgl der Pins 35/36 hatte ich schon erledigt (ich verwende einen analogen Verstärker), ebenfalls die output-Parameter eingesetzt. Bei meinen Displays bleiben die Zeilen 3 und 4 unbespielt; habe zwei LCD´s ausprobiert mit dem gleichen Verhalten. Kann es an dieser Meldung liegen, die ich beim Kompilieren bekomme. WARNUNG: Bibliothek LiquidCrystal_I2C behauptet auf avr Architektur(en) ausgeführt werden zu können und ist möglicherweise inkompatibel mit Ihrem derzeitigen Board, welches auf esp32 Architektur(en) ausgeführt wird.
Die Zeileln 1 und 2 zeigen korrekt Datum, Zeit und auch das Lautsprechersymbol nebst Stationsname.
Danke schonmal und viele Grüße

Gerald Lechner

Gerald Lechner

@Rainer: Die Fehlermeldung bezieht sich auf den WiFi Secure Client, der im Sketch nicht verwendet wird. Es wurde also der Sketch vor dem Kompilieren verändert. Der Secure Client wird benötigt wenn statt http https verwendet werden soll, was in diesem Projekt nicht vorgesehen ist. Laut Fehlermeldung wurde das für SSL notwendige Zertifikat nicht richtig konfiguriert.

Rainer

Rainer

@Gerald Lechner

Vielen Dank für die schnelle Antwort. Ich bin allerdings erst heute dazu gekommen, Ihre Hinweise zu überprüfen.

1. Den Sketch habe ich erneut heruntergeladen und entpackt.
2. Ich verwende das ESP32 Package mit der Version 2.0.5
3. Als Board habe ich ESP32 Dev Module ausgewählt.

Nach erneutem Compilieren mit dem neu heruntergeladenem Skatch erhalte ich jetzt folgende Fehlermeldung:

c:\Users\Rainer\Documents\Arduino\libraries\WiFiClientSecure\src\ssl_client.cpp:23:4: error: #error “Please configure IDF framework to include mbedTLS → Enable pre-shared-key ciphersuites and activate at least one cipher”
exit status 1

Compilation error: exit status 1

Ich bin mit meiner Kunst am Ende.
Ich bitte um Hilfe.

Viele Grüße
Rainer

Ralf Naumann

Ralf Naumann

Ich will ja nicht meckern, aber es ist schon merkwürdig, das die Verlinkung mit den Bauteilen zum Beispiel einen anderen ESP 32 Baustein zum Kauf anbietet als in der Strucktur der Platine und in der Schaltung dann verbaut wurde. Da ich den in der Schaltung verbauten Baustein jetzt erst nachkaufen muss, kann ich mich noch nicht über die Schwierigkeiten beim Laden der Sketche aus der zip Datei aufgetreten sind, auslassen und auf Hilfe hoffen. Wenn ich über diese Tatsachen schlecht denken würde, könnte man in gewisser Weise , an Abzocke denken. Ich bin für Verbesserungen offen. Es sollte dann aber konsequent alles überarbeitet werden. Dann sollte so etwas nicht passieren.
Vielen Dank

Siegfried

Siegfried

@Gerald: ich hatte gedacht, ich kann über Webradio auch den gerade laufenden Sender durch einen in der Sendeliste ändern und den dann hören

Das Neueintragen von Sendern in die Webradioliste funktioniert.

Gruß

Gerald Lechner

Gerald Lechner

@Siegfried: Um einen neuen Sender einzugeben gehen Sie wie folgt vor. Zuerst in der Dropdown-Liste den Sendeplatz auswählen auf dem der neue Sender gespeichert werden soll. Dann die URL mit der des neuen Senders überschreiben und die URL testen. Zum Schluss den Namen nach Wunsch ändern und den Button “Ändern” klicken.

Siegfried

Siegfried

Hallo Herr Lechner,

aufgebaut und es läuft. Allerdings kann ich im „Webradio“ die Sender zwar testen, aber wenn ich den getesteten Sender nutzen möchte, öffnet sich ein Fenster mit „ok“ und „schließen“ . Aber ok ist nicht hinterlegt ( bei mir) .
Ich nutze ein IPad.

Mit freundlichen Grüßen

Siegfried

Rainer Hoffmann

Rainer Hoffmann

@Gerald Lechner
Danke für die schnelle Antwort und die Reproduktion meines Problems. Ihre Analyse (zu hohe Bitrate des streams) ist plausibel.
Frohe Weihnachten.
MfG
Rainer

Gerald Lechner

Gerald Lechner

@Rainer: Soweit ich das dem Protokoll entnehmen kann, wurde nicht der originale Sketch vom Download kompiliert, da dieser nicht das File AudioFileSourceSD.h inkludiert. Zweitens benutzen Sie nicht wwie im Beitrag angegeben das ESP32 Package mit Version2.0.5 sondern die Version 1.0.6. Es könnte außerdem noch sein, dass sie ein falsches Board ausgewählt haben. Es muss ESP32 Dev Module sein.

Rainer

Rainer

Hallo,
mit großer Freude habe ich die Neuauflage des Radio-Projekts gelesen.
das 1. Radioprojekt habe ich mehrfach problemlos gebaut.

Nachdem ich dann alle Bauteile auf meinem Basteltisch liegen hatte, habe ich mit dem Bau begonnen.
So weit, so gut.
Als ich dann den ESP32 programmieren wollte, begannen die Probleme.
Egal ob ich mit der Arduino IDE 1.8.18 oder 2.0.3 programmiert habe, es kamen immer Fehlermeldungen.
Auch auf verschiedenen Rechnern habe ich es versucht.
Immer wieder die nachfolgende Fehlermeldungen:

WARNUNG: Bibliothek LiquidCrystal I2C behauptet auf avr Architektur(en) ausgeführt werden zu können und ist möglicherweise inkompatibel mit Ihrer derzeitigen Platine, welche auf esp32 Architektur(en) ausgeführt wird.
In file included from c:\Users\Rainer\Documents\Arduino\libraries\SD\src/utility/Sd2Card.h:26:0,
from c:\Users\Rainer\Documents\Arduino\libraries\SD\src/utility/SdFat.h:29,
from c:\Users\Rainer\Documents\Arduino\libraries\SD\src/SD.h:20,
from c:\Users\Rainer\Documents\Arduino\libraries\ESP8266Audio\src\AudioFileSourceSD.h:25,
from c:\Users\Rainer\Documents\Arduino\libraries\ESP8266Audio\src\AudioFileSourceSD.cpp:21:
c:\Users\Rainer\Documents\Arduino\libraries\SD\src/utility/Sd2PinMap.h:524:2: error: #error Architecture or board not supported.
#error Architecture or board not supported.
^
Mehrere Bibliotheken wurden für “Preferences.h” gefunden
Benutzt: C:\Users\Rainer\AppData\Local\Arduino15\packages\esp32\hardware\esp32\1.0.6\libraries\Preferences
Nicht benutzt: C:\Users\Rainer\Documents\Arduino\libraries\Preferences
Mehrere Bibliotheken wurden für “HTTPClient.h” gefunden
Benutzt: C:\Users\Rainer\AppData\Local\Arduino15\packages\esp32\hardware\esp32\1.0.6\libraries\HTTPClient
Nicht benutzt: C:\Users\Rainer\Documents\Arduino\libraries\HttpClient
Mehrere Bibliotheken wurden für “FS.h” gefunden
Benutzt: C:\Users\Rainer\Documents\Arduino\libraries\FS
Nicht benutzt: C:\Users\Rainer\AppData\Local\Arduino15\packages\esp32\hardware\esp32\1.0.6\libraries\FS
Mehrere Bibliotheken wurden für “SD.h” gefunden
Benutzt: C:\Users\Rainer\Documents\Arduino\libraries\SD
Nicht benutzt: C:\Users\Rainer\AppData\Local\Arduino15\packages\esp32\hardware\esp32\1.0.6\libraries\SD
Mehrere Bibliotheken wurden für “SPIFFS.h” gefunden
Benutzt: C:\Users\Rainer\Documents\Arduino\libraries\SPIFFS
Nicht benutzt: C:\Users\Rainer\AppData\Local\Arduino15\packages\esp32\hardware\esp32\1.0.6\libraries\SPIFFS
Mehrere Bibliotheken wurden für “Update.h” gefunden
Benutzt: C:\Users\Rainer\Documents\Arduino\libraries\Update
Nicht benutzt: C:\Users\Rainer\AppData\Local\Arduino15\packages\esp32\hardware\esp32\1.0.6\libraries\Update
Mehrere Bibliotheken wurden für “WiFiClientSecure.h” gefunden
Benutzt: C:\Users\Rainer\Documents\Arduino\libraries\WiFiClientSecure
Nicht benutzt: C:\Users\Rainer\Documents\Arduino\libraries\ESP8266WiFi
Nicht benutzt: C:\Users\Rainer\AppData\Local\Arduino15\packages\esp32\hardware\esp32\1.0.6\libraries\WiFiClientSecure
Mehrere Bibliotheken wurden für “WebServer.h” gefunden
Benutzt: C:\Users\Rainer\Documents\Arduino\libraries\WebServer
Nicht benutzt: C:\Users\Rainer\AppData\Local\Arduino15\packages\esp32\hardware\esp32\1.0.6\libraries\WebServer
Mehrere Bibliotheken wurden für “ESPmDNS.h” gefunden
Benutzt: C:\Users\Rainer\Documents\Arduino\libraries\ESPmDNS
Nicht benutzt: C:\Users\Rainer\AppData\Local\Arduino15\packages\esp32\hardware\esp32\1.0.6\libraries\ESPmDNS
exit status 1

Compilation error: exit status 1

Ich weiß nicht mehr weiter.
Vielleicht kann mir hier jemand helfen.

Schon jetzt Danke.
Rainer

Gerald Lechner

Gerald Lechner

@Rainer Hoffmann: Es sollte mit jedem ESP32 Modul funktionieren. Ihr Problem hat nichts mit dem ESP32 zu tun. Ich habe die von Ihnen angegebene URL probiert und das selbe Problem festgestellt. Ich vermute, dass bei diesem Stream die Bitrate für den ESP32 zu hoch ist. Aber das ist nur eine Vermutung.

Rainer Hoffmann

Rainer Hoffmann

Ein sehr schönes Projekt Herr Lechner, Danke dafür.
In Abweichung zum angegebenen ESP32-Modul habe ich allerdings das aus dem alten Internetradio-Projekt genommen. Welche Nachteile sich dadurch ergeben könnten weiß ich nicht. Fakt ist aber, dass ich den stream
“http://stream.kontrafunk.radio/listen/kontrafunk/radio.mp3”
zwar einfügen und abrufen kann, jedoch stottert die Ausgabe extrem. Wenn Sie, Herr Lechner, oder aber einer der Mitleser einen Tip für die Lösung dieses Problems haben wäre ich dafür sehr dankbar.
MfG Rainer

Edgar Bauer

Edgar Bauer

Hallo
habe den Fehler gefunden, hatte das falsche Board ausgewählt, ja manchmal ist man blind.
Grüße Edgar Bauer

Edgar Bauer

Edgar Bauer

Guten Abend,
ich habe nochmal alles installiert, hänge aber beim WebServer,welchen soll ich nehmen?
Gruß Edgar Bauer

Edgar Bauer

Edgar Bauer

Guten Tag,
ich bin gerade dabei das Projekt nachzubauen und scheitere schon beim testen des Sketches.
Mir fehlen immer irgendwelche Dateien, einiges habe ich schon gefixt oder auch nicht im Momenthänge ich jetzt am Webserver
Welche Grund Bibliotkeken brauch ich denn? Anbei meine aktuelle Fehlermeldung.

Mehrere Bibliotheken wurden für “WiFi.h” gefunden

webserver:1:10: fatal error: WebServer.h: No such file or directory
Benutzt: C:\Users\edgar\Downloads\arduino-1.8.19-windows\arduino-1.8.19\libraries\WiFi
1 | #include
Nicht benutzt: C:\Users\edgar\OneDrive\Dokumente\Arduino\libraries\WiFiEspAT
| ^~~~~~~~~~~~~
compilation terminated.
exit status 1
WebServer.h: No such file or directory
Kann mir jemand helfen?
Liebe Grüße
Edgar

Ulrich Klaas

Ulrich Klaas

Weil es einfach eleganter ist habe ich meinen Code :
if (inMainLoop)
{
audio_loop();
}
durch Ihren Code :
if (decoder && (decoder→isRunning())) decoder→loop();

ersetzt.
Dann habe ich aber wieder leichte Störgeräusche.
Eventuell habe ich ja was übersehen.

Übrigens der Austausch von Stations.ino,Webserver.ino und index.h in meinem Sketch hat gereicht und
das neue Webinterface zu etablieren. Prima. Genau das hat gefehlt.
Ich bin jetzt angefixt ;-) Ein schönes mehrzeiliges Grafikdisplay würde mir auch noch gefallen. Mal sehen wann ich Zeit habe.

Ulrich Klaas

Ulrich Klaas

Einen hab ich noch ;-) !
Die DisplayUpdate2 hat einen Fehler. Wenn die Infozeile >20 Zeichen ist und in den ersten 20 Zeichen kein Blank ist geht das schief und
schreibt in die zweite Zeile mit rein und ruiniert die Senderanzeige.
Heute gehabt auf WDR 2 : Argentinen-Frankreich 3:3 Das erste Leerzeichen kommt erst nach mehr als 20 Zeichen.
Ich habe es für mich so gelöst das ich gar nicht nach dem Blank scanne weil mir das doch bei manchen Anzeigen zu viel Platz in den mageren 40 Zeichen
der zwei Zeilen weg nimmt.

Und mal eine Frage : Reicht es für die Änderungen am Webinterface die Datei “webserver.ino” auszutauschen ? Ich habe nämlich schon so einige Änderungen gemacht und bin jetzt zu faul das nachzuziehen. (Also Änderungen im Sinne von “personalisiern” ;-) !

Gerald Lechner

Gerald Lechner

Angeregt durch die Verbesserungen von Herrn Klaas, habe ich eine neue Version der ZIP-Datei auf den Download-Link gelegt. Die neue Version verhindert die Störgeräusche durch die Anzeige wie von Herrn Klaas vorgeschlagen.
Weiters gibt es Erweiterungen zum Web-Interface. Mit dem Button “Senderliste zurücksetzen” kann man wieder die Defaultliste zurückholen. Außerdem ist es nun möglich die Sender umzusortieren. Dazu gibt es jetzt ein neues Eingabefeld mit dem Label “Position”. Dies zeigt die aktuelle Position in der Liste an. Um einen Sender umzureihen, muss einfach die gewünschte neue Position in der Liste in das Eingabefeld eingegeben und dann der Button “Ändern” geklickt werden. Die Nummerierung der Positionen beginnt mit 1.

Ulrich Klaas

Ulrich Klaas

Schade das man seine Post nicht nachträglich ändern kann.
Eins noch : in der Rotary.ino sind in den das Displayupdatenden Routinen Serial.print(s) o.Ä.
Diese bitte auch entfernen. Ich glaube auch in Display.ino waren welche. Bitte raus nehmen denn auch die stehlen dem Audiostream Zeit.

Ich habe jetzt einen einfachen Stereowandler ohne Verstärker dran. Das klappt über die große Stereoanlage super und völlig ohne Störungen.
Die Version mit den eingebauten 8-Bit DA-Wandlern klang dagegen besc….en.

Bin ja beim Musikhörern eher der “Analogie” :-) Aber als Berieselungsmaschine mit Vielfalt ist das Dingen klasse !!

Ulrich Klaas

Ulrich Klaas

SO ! Jetzt bin ich auch die Störungen für den Titelupdate los. War gar nicht so schwer.
Das musste nur aus dem Callback raus da ich aus dem Callback heraus nicht “audioUpdate” aufrufen konnte. Das hätte eine unschöne
und sofort den Stack ruinierende Rekursion gegeben.

Erst mal nehmen wir die Funktion clearLineForeground(uint8_t line) wieder raus und ersetzten sie auch an den Aufrufstellen wieder
durch clearLine();
clearLine sieht jetzt so aus :

//clear one line
void clearLine(uint8_t line) {
lcd.setCursor(0,line);
for (uint8_t i = 0; i<20; i++)
{
if (inMainLoop)
{
audio_loop();
}
lcd.print(" ");
}
}

Ansonsten alles wie gestern beschrieben.
In der displayMessage (ohne2) müssen wir nichts ändern da die nur aus Setup aufgerufen wird.
Das inMainLoop brauchen wir weil sonst in den Ausgaberoutinen “updateAudio” aufgerufen würde ohne das die Librarie initialisiert ist → Absturz.

Um jetzt auch das Update der Indozeile störungsfrei zu bekommen deklarieren wir im Hauptmodul webradio_MAX folgende Variable ganz oben
global (am besten hinter inMainLoop) :
boolean connected;
boolean inMainLoop=false;
boolean Message2Flag = false;

Unten in loop() kommt jetzt hinter dem Uhrenupdate :

//timed event updatetime display every minute if ((millis() – tick) > 30000) { // before 60000 if (connected) displayDateTime(1); tick = millis(); } if (Message2Flag) { displayMessage2(2,title); Message2Flag = false; }

Da die Variable char title[] netterweise schon global war müssen wir in Audio.ino nur noch den Callback ändern :

//callback function will be called if meta data were found in input stream
void MDCallback(void *cbData, const char *type, bool isUnicode, const char *string)
{
if (strstr_P(type, PSTR)) {
strncpy(title, string, sizeof(title));
title[sizeof(title)-1] = 0;
} else {
// Who knows what to do? Not me!
};
//show the message on the display
Message2Flag = true;
//displayMessage2(2,title);
}

Damit haben wir im Callback nur noch einen Trigger und die Ausgabe erfolgt in der Hauptscheife in der wir dann
wieder nach jedem Zeichen das ans Display geht vorsichtshalber audioUpdate aufrufen dürfen damit uns der Puffer nicht leer läuft.

Was habe ich jetzt eigentlich gemacht. Ich habe die ESP8266 nicht voll analysiert aber ich denke sie wird einen Audiopuffer füllen der dann in
einem Interrupt abgearbeitet wird. D.h. nach audioUpdate läuft die Lib eine Weile (ein paar ms) autark im Hintergrund. Nur irgendwann
braucht sie Datennachschub was updateAudio aus dem Stream erledigt. Wenn wir jetzt mehre 20 Byte lange Strings auf dem Display ausgeben
(erst die Zeile löschen dann der neue Inhalt) dann dauert das über den nicht all zu schnellen I2C Bus zum Display zu lange. Der Audiopuffer wird leer
und es gibt Störgeräusche bis er wieder neu gefüllt ist. Ich sorge jetzt einfach nur dafür das bis auf wenige Ausnahmen nur ein Zeichen zum Display
geschickt wird und dazwischen immer wieder updateAudio aufgerufen wird (also audio_loop) und schon sind die Störungen weg. Die Ausgabe auf
dem Display wird dadurch (für mich) nicht sichtbar langsamer. Man muss auf embedded System immer genau schauen wie man mit Zeiten umgeht ;-)

Ich hoffe die Änderung wird übernommen und macht Spaß !

Frohe Weihnachten und guten Rutsch.

Ulli

Ulrich Klaas

Ulrich Klaas

Hallo,
ich habe mal angefangen was zur Störgeräuschminimierung einzubauen. Beim Tunen und änder der Lautstärke hat mich das kaum gestört aber ich habe
das Displayupdate auf eine halbe Minute gesetzt (weil ich da was geändert habe) und immer bei diesem Update stockte der Ton auch.
Auch wenn die Infozeilen ein update bekommen aber das ist ja seltener.
Folgende fixe Lösung habe ich gefunden.
Zuerst muss im Modul webradio_MAX die Variable “boolean inMainLoop=0 declariert werden”. Am Ende von Setup wird die auf 1 gesetzt !
Dann kommen in Display.ino folgende Funktionen :

void MyLcdPrint(char output)
{
while (
output)
{
lcd.print(*output);
if (inMainLoop)
{
audio_loop();
}
output++;
}
}

void clearLineForeground(uint8_t line) {
lcd.setCursor(0,line);
for (uint8_t i = 0; i<20; i++)
{
if (inMainLoop)
{
audio_loop();
}
lcd.print(" ");
}
}

Die Stringausgabe wird also auf ein Zeichen reduziert bevor wieder die Audioloop gerufen wird.
Die ClearLineForground ist notwendig weil auch Stringroutinen aus der Audioloop aufgerufen werden und das eine unschöne Rekursion gibt.

In ShowStation() und displayDateTime() nutze ich jetzt nur noch clearLineForeground und MyLcdPrint.
Und siehe (und höre vor Allem) → Keine Störgeräusche mehr beim Drehen an den Reglern und kein Aussetzer mehr wenn das Display geupdatet wird.

Dabei reicht schon eine von beiden Maßnahmen also entweder das ClearLineForground oder das MyLcdPrint (geht nur bei char *).

Für die Infozeilen aus der Audioloop muss ich mir noch was einfallen lassen. Da wird für die Zeichenweise Ausgabe, zumindest für das Löschen der Zeilen, nur eine Statemaschine helfen. Wenn Interesse besteht mache ich hier gerne Updates.

Werner

Werner

Dank an Herrn Lechner
Als interessierter Bastler der aber keine Ahnung von programmieren und auch keine Englischkenntnisse hat,hatte ich mich vergeblich an dem webradio MAX versucht. Immer war irgendein Fehler beim kompilieren da. Aber dank der Hilfe von Herrn Lechner via E-Mail läuft das Radio jetzt hervorragend. Danke nochmal an Herr Lechner und das AZ-Delivery Team. Allen Bastlern ein schönes Weihnachtsfest und viel Gesundheit
Werner Herzig

Ulrich Klaas

Ulrich Klaas

Ich muss mich entschuldigen.
Ich hatte nur mal so zum Spaß um Warnings los zu werden die etwas gewagten Zuweisungen in “SendStations”
a la “char *sel” und sel = ""; ersetzt mit Puffern und strcpy’s. Das habe ich dann doch wieder ausgebaut um dem
Originalzustand zu erhalten. Dabei hatte ich ein strcpy auf einen Nullpointer vergessen :-( . Pardon ! Mein Fehler.

Ulli

Gerald Lechner

Gerald Lechner

@Ulrich Klaas: Ich kann mir nicht erklären wie das zustande kam. Ich habe schon einige Sender geändert oder neu gespeichert immer ohne Probleme. Ich werde den Webserver um eine Funktion erweitern mit der man die Präferenzen wieder auf Default setzen kann. Mit der Funktion sender.clear() sollte es möglich sein alle Einträge zu löschen und damit wieder auf die Defaultwerte zurückzuschalten. Das habe ich aber noch nicht probiert!

Ulrich Klaas

Ulrich Klaas

Erst mal danke für die schnelle Antwort.
Jetzt habe ich ein echtes Problem. So läuft erst mal alles nur auf der Website ist das Dropdownmenü für die Stationen immer lehr.
Wenn ich eine neue Eingebe ist nachher die Stationsliste auf dem Gerät hin. Alles über 24 ist gleich und der Eintrag auf 0 ist überschrieben (mit meinem neuen Sender)

Gerald Lechner

Gerald Lechner

@Joachim: Display abschalten könnte man machen, bringt aber nicht viel Ersparnis, da die WLAN Funktionen des ESP32 und ie Verstärker den Hauptteil des Stroms verbrauchen. Ein Sortieren der Senderliste müsste über das Webinterface geschehen. Ich werde mir mal überlegen, wie man das machen könnte.
@Ulrich Klaas: Ja es ist richtig, dass die Funktion setGain() Werte bis 4.0 zulässt. Der Wert wird intern in eine binäre 8-Bit Festkommazahl umgewandelt. Das bedeutet 2 Bit für den Exponenten und 6 Bit für die Mantisse. Damit ist die höchste mögliche Zahl 3.984375 deshalb die Begrenzung auf 4.0. Diese Festkommazahl wird dann mit den Amplitudenwerten der Kanäle multipliziert um die Amplitude zu ermitteln, die an das I2S Interface gesendet wird. Das bedeutet 1.0 liefert genau die Amplitude, die im MP3 Stream empfangen wurde. Ich habe zuerst auch gedacht 4 wäre der Höchstwert, aber bei Werte über 1 funktioniert die Ausgabe nicht mehr richtig.

Ulrich Klaas

Ulrich Klaas

Hallo,

Erst mal : Prima Projekt.

Aber ich habe mal eine Frage zu der Funktion “setGain()”. Hier wird currentGain / 100.0 gerechnet und an out.SetGain() übergeben.
Da currentGain nur Werte zwischen 0 und 100 annehmen kann ist also auch der Maximalwert 1 !
Aber SetGain hat als Maximalwert 4.0. Ist das Absicht ? Meiner Meinung arbeitet so der DA-Wandler nicht optimal (zumindest wenn man
einen mit Verstärkeranschluss benutzt). Bei 1.0 werden ja dann nicht alle 16 Bit des Wandlers benutzt !

Joachim

Joachim

Danke für den Hinweis, in der Sender-URL https durch http zu ersetzen – so simpel kann’s sein!
Ich habe noch zwei Anregungen:
- Schön wäre, wenn sich das Display “schlafen legt” um Strom zu sparen. Hoher Programmieraufwand?
- Senderliste sortieren – geht nur im Sketch, oder?

Gerald Lechner

Gerald Lechner

@Joachim: https:// kann nicht empfangen werden. Aber meist gibt es den selben Stream auch über http:// so auch in Ihrem Fall.
http://st02.sslstream.dlf.de/dlf/02/128/mp3/stream.mp3
funktioniert.

Joachim

Joachim

https://st02.sslstream.dlf.de/dlf/02/128/mp3/stream.mp3

Dies ist die URL von Deutschlandradio Kultur. Der Test unter http://webradio/ schlägt fehl. Was mache ich falsch? Der Sender müsste doch zu empfangen sein – genau wie der Deutschlandfunk, welcher in Ihrer Liste enthalten ist.

Gerald Lechner

Gerald Lechner

ACHTUNG!!!!
In der Schaltung wurden die Anschlüsse des Rotary-Encoders für die Senderwahl vertauscht. Die Zeichnung ist jetzt korrigiert. Die Verbindungsliste unterhalb der Schaltung war immer richtig!

Gerald Lechner

Gerald Lechner

@Eddy: Man könnte Audiobuchsen parallel oder anstelle der Lautsprecher anbringen. Die Spannung dürfte bei ca. 3V liegen ist aber von der eingestellten Lauststärke abhängig.
@Sven Hesse: Freut mich, dass alles funktioniert. Das mit begin() stat init() stimmt für die im Beitrag angegebene Bibliothek nicht. init() startet den I2C Treiber Wire setzt Flags für das Display und ruft dann begin() auf.

Sven Hesse

Sven Hesse

Hallo,

vielen Dank für die Bereitstellung dieser “Webradioerweiterung”.
Bis auf einen kleinen Fehler im Abschnitt “display.ino” ( anstelle von lcd.init(); muss hier stehen lcd.begin();) gab es nix auffälliges.

Da ich kein ESP32 Development Board mehr hatte, habe ich dieses Projekt mit dem ESP32 D1 Mini umgesetzt.
Hierbei musste ich lediglich PIN13 (gain.ino) irgendwie ersetzen. Habe mich dann letztlich für PIN17 entschieden.
Läuft :-).

Deja un comentario

Todos los comentarios son moderados antes de ser publicados

Publicaciones de blog recomendadas

  1. Wir bauen eine Smart Home Zentrale mit ArduiTouch
  2. Schrittmotor Steuerung für Antennen Rotor
  3. Arbeiten mit dem Cayenne Dashboard - einfacher Sensor (Teil 1)
  4. Mit dem ESP8266 8 Lampen steuern