Ich hab das mal auf einen Controller spielen lassen.
Auf einem UNO oder einem MEGA muss das funktionieren.
Zudem muss eine LED auf dem Controller blinken.
#include <Wire.h>
#include <TEA5767.h>
#include <LiquidCrystal.h>
#define DEBUG // Wenn aktiviert, werden Zwischenwerte ausgegeben
#ifdef DEBUG
#define DBG_PRINTLN(...) Serial.println(__VA_ARGS__)
#define DBG_PRINT(...) Serial.print(__VA_ARGS__)
#else
#define DBG_PRINTLN(...
#define DBG_PRINT(...)
#endif
LiquidCrystal lcd( 8, 9, 4, 5, 6, 7);
TEA5767 radio = TEA5767(); // Der kann hier auch Parameter übergeben werden....
// Display
constexpr uint8_t spalten {16};
constexpr uint8_t zeilen {2};
// Keypad
constexpr uint8_t btnPin {A0};
enum class BTNSTATE : uint8_t {NO, UP, DOWN, LEFT, RIGHT, SELECT};
// Suchrichtung
constexpr bool forward {true};
constexpr bool backward {!forward};
bool direction = forward;
// Radio
constexpr float minFreq {87.5};
constexpr float maxFreq {108.0};
float frequency = minFreq;
constexpr float stepFreq {0.2};
// - Signalstärke für Wiedergabe
constexpr uint8_t minLevel {6};
// - Mute während des Suchlaufs
constexpr bool seekMute {true};
// Spielzeit
constexpr uint32_t minWait {100};
constexpr uint32_t maxWait {1000};
constexpr uint32_t waitStep {100};
uint32_t wait = minWait;
uint32_t lastScanTime;
bool stopped = true;
uint8_t count = 0;
void setup()
{
Serial.begin(115200);
Serial.println(F("Start..."));
delay(1000);
pinMode(btnPin, INPUT);
pinMode(LED_BUILTIN, OUTPUT);
Wire.begin();
lcd.begin(spalten, zeilen);
splashScreen();
delay(1500);
}
void loop()
{
if (getButton() == BTNSTATE::SELECT)
{ stopped = !stopped; }
if (stopped == true)
{ deviceSetup(); }
else
{ searchNext(); }
heartBeat(500);
}
void deviceSetup()
{
// clang-format off
//*INDENT-OFF*
BTNSTATE btn = getButton(); // holt Tastenzusatand
switch (btn)
{
case BTNSTATE::RIGHT: radio.setMuted(!radio.isMuted()); break;
case BTNSTATE::LEFT: direction = !direction; break;
case BTNSTATE::UP: setWait(maxWait); break;
case BTNSTATE::DOWN: setWait(minWait); break;
default: break;
}
if (btn != BTNSTATE::NO) // eine Taste wurde gedrückt
{
displaySetup(); // aktuallisiere Display
}
//*INDENT-ON*
// clang-format on
}
void displaySetup()
{
char buf[spalten + 1] = {'\0'};
lcd.clear();
snprintf(buf, spalten, "Mute: %s # Dir: %s", radio.isMuted() == true ? "Y" : "N", direction == forward ? ">" : "<");
lcd.print(buf);
Serial.println(buf);
snprintf(buf, spalten, "Wait: %li ms", wait);
lcd.setCursor(0, 1);
lcd.print(buf);
Serial.println(buf);
}
void setWait(const uint32_t end)
{
if (end == minWait)
{
if ((wait - waitStep) >= minWait)
{ wait -= waitStep; }
}
else
{
if ((wait + waitStep) <= maxWait)
{ wait += waitStep; }
}
}
BTNSTATE getButton()
{
uint16_t btnValue = analogRead(btnPin);
static BTNSTATE lastState = BTNSTATE::NO;
static bool isRelease = false;
BTNSTATE newState = BTNSTATE::NO;
static uint32_t releaseTime = 0;
const uint32_t debounceTime = 100;
// clang-format off
//*INDENT-OFF*
switch (btnValue)
{
case 0 ... 59: newState = BTNSTATE::RIGHT; break;
case 60 ... 199: newState = BTNSTATE::UP; break;
case 200 ... 399: newState = BTNSTATE::DOWN; break;
case 400 ... 599: newState = BTNSTATE::LEFT; break;
case 600 ... 799: newState = BTNSTATE::SELECT; break;
default: newState = BTNSTATE::NO; break;
}
//*INDENT-ON*
// clang-format on
if (lastState != newState) // geänderte Auswahl?
{
DBG_PRINT(F("Neuer BTN-Value: "));
DBG_PRINTLN(btnValue);
if (lastState == BTNSTATE::NO) // Vorher: keine Taste aktiv
{
DBG_PRINTLN(F("neue Taste!"));
lastState = newState; // Neue ausgewählte Taste merken
return newState; // Taste zurückgeben
}
else // Vorher: Taste aktiv
{
if (newState == BTNSTATE::NO) // Jetzt: Taste inaktiv
{
DBG_PRINTLN(F("keine Taste"));
if (isRelease == false) // vorher nicht losgelassen
{
DBG_PRINTLN(F("erstes release"));
releaseTime = millis(); // Zeit merken
isRelease = true; // losgelassen merken
}
else // war vorher losgelassen
{
if (millis() - releaseTime > debounceTime) // Zeit abgelaufen
{
DBG_PRINTLN(F("Button gelöscht"));
isRelease = false; // Merker löschen
lastState = newState; // Status merken
}
}
}
}
}
return BTNSTATE::NO; // - Keine Wiederholung! - ungedrückte Taste!
}
void splashScreen()
{
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(F("Spiritmaster"));
lcd.setCursor(0, 1);
lcd.print(F("by Masterdetektor"));
}
void checkFreq()
{
if (direction == forward)
{
if (frequency > maxFreq)
{
frequency = minFreq;
count = 0;
}
}
else
{
if (frequency < minFreq)
{
frequency = maxFreq;
count = 0;
}
}
}
float nextFreq()
{
if (direction == forward)
{ frequency += stepFreq; }
else
{ frequency -= stepFreq; }
checkFreq();
return frequency;
}
void searchNext()
{
if (millis() - lastScanTime > wait)
{
char buf[spalten + 1] = {'\0'}; // Buffer für eine Zeile LCD anlegen
lcd.clear();
snprintf(buf, spalten, "Scanning... %s", direction == forward ? "->->" : "<-<-"); // baut 1.te Zeile für LCD
lcd.print(buf); // Ausgabe :-)
Serial.println(buf);
if (seekMute) // wenn Mute während Sendersuchlauf
{ radio.setMuted(true); }
uint8_t oldCount = count; // Merker für Vergleich
while (count == oldCount) // Wiederhole, bis Sender gefunden
{
radio.setFrequency(nextFreq());
delay(50); // Hier kann versucht werden, mit dem Wert noch weiter runter zu gehen
if (minLevel < radio.getSignalLevel()) // Wenn Sender gefunden
{ count++; }
char fbuf[7] = {'\0'};
dtostrf(radio.getFrequency(), 4, 1, fbuf); // float zu *char
snprintf(buf, spalten, "F: %s # c: %i", fbuf, count); // baut 2.te Zeile für LCD
lcd.setCursor(0, 1);
lcd.print(buf);
}
radio.setMuted(false); // garantiert, dass nach Senderfund Ton an ist
Serial.println(buf); // gibt den letzten Inhalt nach dem neuen Senderfund aus
Serial.println(F("*************\r\n"));
lastScanTime = millis(); // Merker, wann der Sender gefunden wurde
}
}
void heartBeat(const uint32_t beat)
{
static uint32_t lastBeat = 0;
if (millis() - lastBeat > beat)
{
digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN));
lastBeat = millis();
}
}




