Ваш браузер устарел. Рекомендуем обновить его до последней версии.





 


 



Delphi

 

 


 

 

 

 

Радиоприемник FM стерео

Радиоприемник FM стерео устроен на базе микросхемы RDA5807M. Диапазон частот 76108 МГц. Напряжение 2,73,6 В. После заливки скетча при включении установки радиомодуль найдет первую радиостанцию. При нажатии кнопки RESET отыщется следующая радиостанция.

 

Ниже два возможных скетча для этой установки. 

 

 

Первый пример_____

 

#include <Wire.h>

void setup() {
Wire.begin();
setRegister(0x02, 0xC101); // set ENABLE, DHIZ, DMUTE, SEEK
}

void loop() {
}

void setRegister(uint8_t reg, const uint16_t value) {
Wire.beginTransmission(0x11);
Wire.write(reg);
Wire.write(highByte(value));
Wire.write(lowByte(value));
Wire.endTransmission(true);
}

 

Второй пример_____

 

#include <Wire.h>

#define RDA5807M_RANDOM_ACCESS_ADDRESS 0x11
// регистры
#define RDA5807M_REG_CONFIG 0x02
#define RDA5807M_REG_TUNING 0x03
#define RDA5807M_REG_VOLUME 0x05
#define RDA5807M_REG_RSSI 0x0B
// флаги
#define RDA5807M_FLG_DHIZ 0x8000
#define RDA5807M_FLG_DMUTE 0x4000
#define RDA5807M_FLG_BASS 0x1000
#define RDA5807M_FLG_ENABLE word(0x0001)
#define RDA5807M_FLG_TUNE word(0x0010)
//маски
#define RDA5807M_CHAN_MASK 0xFFC0
#define RDA5807M_CHAN_SHIFT 6
#define RDA5807M_VOLUME_MASK word(0x000F)
#define RDA5807M_VOLUME_SHIFT 0
#define RDA5807M_RSSI_MASK 0xFE00
#define RDA5807M_RSSI_SHIFT 9

uint8_t volume = 1; // 0..15
uint16_t freq = 1073; // 107.3FM
uint16_t reg02h, reg03h, reg05h, reg0Bh;

void setup() {
Serial.begin(9600);
Wire.begin();
// Регистр 02h - включение, настройки
reg02h = RDA5807M_FLG_ENABLE | RDA5807M_FLG_DHIZ | RDA5807M_FLG_DMUTE;
setRegister(RDA5807M_REG_CONFIG, reg02h);

// А потом решили еще усилить басы:
reg02h |= RDA5807M_FLG_BASS;
setRegister(RDA5807M_REG_CONFIG, reg02h);

// Регистр 03h - выбор радиостанции
// После сброса в регистре 03h значение по умолчанию - 0
// Таким образом BAND = 00 (87..108МГц), STEP = 00 (100кГц). Оставим их как есть
reg03h = (freq - 870) << RDA5807M_CHAN_SHIFT; // chan = (freq - band) / space
setRegister(RDA5807M_REG_TUNING, reg03h | RDA5807M_FLG_TUNE);

// Регистр 05h. Установим громкость, остальные биты не изменяем
reg05h = getRegister(RDA5807M_REG_VOLUME); // Считываем текущее значение
reg05h &= ~RDA5807M_VOLUME_MASK; // Сбрасываем биты VOLUME
reg05h |= volume << RDA5807M_VOLUME_SHIFT; // Устанавливаем новую громкость
setRegister(RDA5807M_REG_VOLUME, reg05h);
}

void loop() {
// Регистр 0Bh - статус
reg0Bh = getRegister(RDA5807M_REG_RSSI);
uint8_t RSSI = (reg0Bh & RDA5807M_RSSI_MASK) >> RDA5807M_RSSI_SHIFT;
Serial.print("RSSI = ");
Serial.print(RSSI);
Serial.println(" (0-min, 127-max)");
delay(500);
}

void setRegister(uint8_t reg, const uint16_t value) {
Wire.beginTransmission(0x11);
Wire.write(reg);
Wire.write(highByte(value));
Wire.write(lowByte(value));
Wire.endTransmission(true);
}

uint16_t getRegister(uint8_t reg) {
uint16_t result;
Wire.beginTransmission(RDA5807M_RANDOM_ACCESS_ADDRESS);
Wire.write(reg);
Wire.endTransmission(false);
Wire.requestFrom(0x11, 2, true);
result = (uint16_t)Wire.read() << 8;
result |= Wire.read();
return result;
}

 

В этой установке к радиомодулю добавлены энкодер и LCD-дисплей. Энкодер служит для настройки на нужную радиоволну и для регулировки громкости. На дисплей выводится информация о частоте радиостанции. Нужна библиотека

LiquidCrystal_I2C_Menu

 

 

 

 

 

 

 

 

 

 

// https://tsibrov.blogspot.com/2019/11/rda5807m-part1.html
#define DEBUG
#include "RDA5807M.h"
#include <EEPROM.h>
#include <Wire.h>
#include <LiquidCrystal_I2C_Menu.h> // https://github.com/VladimirTsibrov/LiquidCrystal_I2C_Menu
LiquidCrystal_I2C_Menu lcd(0x27, 20, 4);

#define EEPROM_START_ADDRESS 0
#define PIN_CLK 2 // Энкодер пин A
#define PIN_DT 3 // Энкодер пин B
#define PIN_SW 4 // Кнопка

void OneBigHandler(); // Прототип обработчика меню

enum {mkBack, mkRoot, mkSeekUp, mkSeekDown, mkSetVolume, mkSetFreq, mkRotatePurpose,
mkSoundOptions, mkBassBoost, mkSoftMute, mkSoftBlend, mkSoftBlendThreshold,
mkForceMono, mkTunerOptions, mkNewDemodulation, mkSeekThreshold, mkSaveSettings};

sMenuItem menu[] = {
{mkBack, mkRoot, "Menu"},
{mkRoot, mkSeekUp, "Seek up"},
{mkRoot, mkSeekDown, "Seek down"},
{mkRoot, mkSetVolume, "Set volume", OneBigHandler},
{mkRoot, mkSetFreq, "Set frequency", OneBigHandler},
{mkRoot, mkRotatePurpose, "Encoder purpose",OneBigHandler},
{mkRoot, mkSoundOptions, "Sound options"},
{mkSoundOptions, mkBassBoost, NULL, OneBigHandler},
{mkSoundOptions, mkForceMono, NULL, OneBigHandler},
{mkSoundOptions, mkSoftMute, NULL, OneBigHandler},
{mkSoundOptions, mkSoftBlend, NULL, OneBigHandler},
{mkSoundOptions, mkSoftBlendThreshold, NULL, OneBigHandler},
{mkSoundOptions, mkBack, "Back"},
{mkRoot, mkTunerOptions, "Tuner options"},
{mkTunerOptions, mkNewDemodulation, NULL, OneBigHandler},
{mkTunerOptions, mkSeekThreshold, NULL, OneBigHandler},
{mkTunerOptions, mkBack, "Back"},
{mkRoot, mkSaveSettings, "Save settings", OneBigHandler},
{mkRoot, mkBack, "Back"}
};

uint8_t menuLen = sizeof(menu) / sizeof(sMenuItem);
bool Searching = false;
bool NeedRepaint = false;
double Freq;
enum {RotateVolume, RotateStation} EncoderPurpose = RotateStation;
unsigned long tm = 0;
char *listOffOn[] = {"OFF", "ON"};

int getItemIndexByKey(uint8_t key) {
for (uint8_t i = 0; i < menuLen; i++)
if (menu[i].key == key)
return i;
return -1;
}

void updateCaption(uint8_t key, const char format[], const char value[]) {
uint8_t index = getItemIndexByKey(key);
char* buf = (char*) malloc(40);
sprintf(buf, format, value);
menu[index].caption = (char*) realloc(menu[index].caption, strlen(buf) + 1);
strcpy(menu[index].caption, buf);
free(buf);
}

void setup() {
Wire.begin();
lcd.begin();
lcd.attachEncoder(PIN_DT, PIN_CLK, PIN_SW);

#if defined(DEBUG)
Serial.begin(57600);
lcd.attachIdleFunc(checkSerial);
#endif

// Читаем настройки из EEPROM
readEEPROM();

// Обновляем заголовки в меню
updateCaption(mkBassBoost, "Bass boost (%s)", listOffOn[(reg02h & RDA5807M_FLG_BASS) > 0]);
updateCaption(mkSoftMute, "Soft mute (%s)", listOffOn[(reg04h & RDA5807M_FLG_SOFTMUTE) > 0]);
updateCaption(mkSoftBlend, "Soft blend (%s)", listOffOn[(reg07h & RDA5807M_FLG_SOFTBLEND) > 0]);
updateCaption(mkSoftBlendThreshold, "Soft blend threshold (%s)", String((reg07h & RDA5807M_SOFTBLENDTH_MASK) >> RDA5807M_SOFTBLENDTH_SHIFT).c_str());
updateCaption(mkForceMono, "Force mono (%s)", listOffOn[(reg02h & RDA5807M_FLG_MONO) > 0]);
updateCaption(mkNewDemodulation, "New demodulation (%s)", listOffOn[(reg02h & RDA5807M_FLG_NEW) > 0]);
updateCaption(mkSeekThreshold, "Seek threshold (%s)", String((reg05h & RDA5807M_SEEKTH_MASK) >> RDA5807M_SEEKTH_SHIFT).c_str());
}

#if defined(DEBUG)
void checkSerial() {
uint8_t b;
if (Serial.available()) {
delay(1);
b = Serial.read();
if (b == 255) { // Прочитать регистр
b = Serial.read(); // Адрес регистра
Wire.beginTransmission(0x11);
Wire.write(b);
Wire.endTransmission(false);
Wire.requestFrom(0x11, 2, true);
Serial.write(b);
Serial.write(Wire.read());
Serial.write(Wire.read());
}
else { // Записать регистр
Wire.beginTransmission(0x11);
Wire.write(b);
Wire.write(Serial.read());
Wire.write(Serial.read());
Wire.endTransmission(true);
}
}
}
#endif

void loop() {
#if defined(DEBUG)
checkSerial();
#endif

// Опрос энкодера
eEncoderState encoderState = lcd.getEncoderState();
if (encoderState == eButton) { // Нажата кнопка. Покажем меню
uint8_t selectedMenuItem = lcd.showMenu(menu, menuLen, 1);
if (selectedMenuItem == mkSeekUp) { // Поиск радиостанции вверх
seekStation(1);
}
else if (selectedMenuItem == mkSeekDown) { // Поиск радиостанции вниз
seekStation(0);
}
// Остальные пункты меню в обработчике
NeedRepaint = true; // После выхода из меню нужна перерисовка дисплея
}
else if (encoderState == eLeft){ // Энкодер повернули влево
if (EncoderPurpose == RotateVolume) { // Убавить громкость
uint16_t volume = (reg05h & RDA5807M_VOLUME_MASK);
if (volume > 0) {
reg05h &= ~RDA5807M_VOLUME_MASK;
reg05h |= --volume;
setRegister(RDA5807M_REG_VOLUME, reg05h);
if (volume < 10)
lcd.printfAt(0, 1, "< %d >", volume);
else
lcd.printfAt(0, 1, "< %d >", volume);
tm = millis();
}
}
else if (EncoderPurpose == RotateStation) { // Искать вниз
seekStation(0);
NeedRepaint = true;
}
}
else if (encoderState == eRight){
if (EncoderPurpose == RotateVolume) { // Прибавить громкость
uint16_t volume = (reg05h & RDA5807M_VOLUME_MASK);
if (volume < 15) {
reg05h &= ~RDA5807M_VOLUME_MASK;
reg05h |= ++volume;
setRegister(RDA5807M_REG_VOLUME, reg05h);
if (volume < 10)
lcd.printfAt(0, 1, "< %d >", volume);
else
lcd.printfAt(0, 1, "< %d >", volume);
tm = millis();
}
}
else if (EncoderPurpose == RotateStation) { // Искать вверх
seekStation(1);
NeedRepaint = true;
}
}

if (Searching) { // Проверим найдена ли радиостанция
reg0Ah = getRegister(RDA5807M_REG_STATUS1);
if (reg0Ah & RDA5807M_FLAG_STC) {
// Найдена
Searching = false;
NeedRepaint = true;
reg03h = getRegister(RDA5807M_REG_TUNING);
Freq = 87 + double((reg03h & RDA5807M_CHAN_MASK) >> RDA5807M_CHAN_SHIFT) / 10;
}
}

if ((NeedRepaint) or (tm and (millis() - tm > 3000)))
LCDRepaint();
}

void LCDRepaint(){
// Перерисовать дисплей
lcd.clear();
if (Searching)
lcd.print("Searching...");
else {
String s(Freq, 1);
lcd.printf("%sFM", s.c_str());
}

if (EncoderPurpose == RotateVolume)
lcd.printAt(0, 1, "< Volume >");
else if (EncoderPurpose == RotateStation)
lcd.printAt(0, 1, "< Station >");

NeedRepaint = false;
tm = 0;
}

void OneBigHandler(){
// Обработчик для пунктов меню. Здесь только те пункты,
// при выборе которых не требуется выход из меню
uint8_t selectedMenuItem = lcd.getSelectedMenuItem();
if (selectedMenuItem == mkSetVolume) { // Установить громкость
uint16_t volume = (reg05h & RDA5807M_VOLUME_MASK);

/* Можно и так, но громкость будет изменяться только после выхода из inputVal
volume = lcd.inputVal<uint16_t>("Volume", 0, 15, volume);
reg05h &= ~RDA5807M_VOLUME_MASK;
reg05h |= volume;
setRegister(RDA5807M_REG_VOLUME, reg05h);
*/

lcd.clear();
lcd.print("Input volume");
lcd.printAt(0, 1, volume);
while (1) {
eEncoderState encoderState = lcd.getEncoderState();
if (encoderState == eNone) {
#if defined(DEBUG)
checkSerial();
#endif
continue;
}
else if (encoderState == eButton) break;
else if (encoderState == eLeft) {
if (volume > 0) volume--; else continue;
}
else if (encoderState == eRight) {
if (volume < 15) volume++; else continue;
}
lcd.printAt(0, 1, volume);
lcd.print(" ");
reg05h &= ~RDA5807M_VOLUME_MASK;
reg05h |= volume;
setRegister(RDA5807M_REG_VOLUME, reg05h);
}
}
else if (selectedMenuItem == mkSetFreq) { // Запросить и установить частоту
double newFreq = Freq;
if (! lcd.inputValBitwise("Input freq", newFreq, 4, 1, 0)) return; // XXX.X
while ((newFreq < 87) or (newFreq > 108)) {
lcd.printMultiline("Invalid frequency. Should be in 87..108");
if (!lcd.inputValBitwise("Input freq", newFreq, 4, 1, 0)) return;
}
Freq = newFreq;
uint16_t chan = uint8_t((newFreq - 87) * 10);
reg03h &= ~RDA5807M_CHAN_MASK;
reg03h |= chan << RDA5807M_CHAN_SHIFT;
setRegister(RDA5807M_REG_TUNING, reg03h | RDA5807M_FLG_TUNE);
}
else if (selectedMenuItem == mkRotatePurpose) { // Поведение при вращении энкодера
String listEncPurpose[] = {"Set volume", "Set station"};
EncoderPurpose = lcd.selectVal("Encoder purose", listEncPurpose, 2, (int)EncoderPurpose);
}
else if (selectedMenuItem == mkBassBoost) { // Предложим включить усиление басов
bool bassBoost = reg02h & RDA5807M_FLG_BASS;
bassBoost = lcd.selectVal("Bass boost", listOffOn, 2, bassBoost);
if (bassBoost) reg02h |= RDA5807M_FLG_BASS;
else reg02h &= ~RDA5807M_FLG_BASS;
setRegister(RDA5807M_REG_CONFIG, reg02h);
updateCaption(mkBassBoost, "Bass boost (%s)", listOffOn[bassBoost]);
}
else if (selectedMenuItem == mkForceMono) { // Предложим переключиться в моно
bool forceMono = reg02h & RDA5807M_FLG_MONO;
forceMono = lcd.selectVal("Force mono", listOffOn, 2, forceMono);
if (forceMono) reg02h |= RDA5807M_FLG_MONO;
else reg02h &= ~RDA5807M_FLG_MONO;
setRegister(RDA5807M_REG_CONFIG, reg02h);
updateCaption(mkForceMono, "Force mono (%s)", listOffOn[forceMono]);
}
else if (selectedMenuItem == mkSoftMute) { // Предложим включить softmute
bool softMute = reg04h & RDA5807M_FLG_SOFTMUTE;
softMute = lcd.selectVal("Soft mute", listOffOn, 2, softMute);
if (softMute) reg04h |= RDA5807M_FLG_SOFTMUTE;
else reg04h &= ~RDA5807M_FLG_SOFTMUTE;
setRegister(RDA5807M_REG_DEEMPH, reg04h);
updateCaption(mkSoftMute, "Soft mute (%s)", listOffOn[softMute]);
}
else if (selectedMenuItem == mkSoftBlend) { // Предложим включить softblend
bool softBlend = reg07h & RDA5807M_FLG_SOFTBLEND;
softBlend = lcd.selectVal("Soft blend", listOffOn, 2, softBlend);
if (softBlend) reg07h |= RDA5807M_FLG_SOFTBLEND;
else reg07h &= ~RDA5807M_FLG_SOFTBLEND;
setRegister(RDA5807M_REG_THRESH, reg07h);
updateCaption(mkSoftBlend, "Soft blend (%s)", listOffOn[softBlend]);
}
else if (selectedMenuItem == mkSoftBlendThreshold) { // Изменить порог softblend
uint16_t threshold = (reg07h & RDA5807M_SOFTBLENDTH_MASK) >> RDA5807M_SOFTBLENDTH_SHIFT;
threshold = lcd.inputVal<uint16_t>("Input blend theshold", 0, 31, threshold);
reg07h &= ~RDA5807M_SOFTBLENDTH_MASK;
reg07h |= (threshold << RDA5807M_SOFTBLENDTH_SHIFT);
setRegister(RDA5807M_REG_THRESH, reg07h);
updateCaption(mkSoftBlendThreshold, "Soft blend threshold (%s)", String(threshold).c_str());
}
else if (selectedMenuItem == mkNewDemodulation) { // Предложим включить новый метод демодуляции
bool newDemodulation = reg02h & RDA5807M_FLG_NEW;
newDemodulation = lcd.selectVal("New demodulation", listOffOn, 2, newDemodulation);
if (newDemodulation) reg02h |= RDA5807M_FLG_NEW;
else reg02h &= ~RDA5807M_FLG_NEW;
setRegister(RDA5807M_REG_CONFIG, reg02h);
updateCaption(mkNewDemodulation, "New demodulation (%s)", listOffOn[newDemodulation]);
}
else if (selectedMenuItem == mkSeekThreshold) { // Изменить порог для поиска
uint16_t threshold = (reg05h & RDA5807M_SEEKTH_MASK) >> RDA5807M_SEEKTH_SHIFT;
threshold = lcd.inputVal<uint16_t>("Input seek theshold", 0, 15, threshold);
reg05h &= ~RDA5807M_SEEKTH_MASK;
reg05h |= (threshold << RDA5807M_SEEKTH_SHIFT);
setRegister(RDA5807M_REG_VOLUME, reg05h);
updateCaption(mkSeekThreshold, "Seek threshold (%s)", String(threshold).c_str());
}
else if (selectedMenuItem == mkSaveSettings) { // Сохранить настройки в EEPROM
EEPROM.put(EEPROM_START_ADDRESS, reg02h);
EEPROM.put(EEPROM_START_ADDRESS + 2, reg03h);
EEPROM.put(EEPROM_START_ADDRESS + 4, reg04h);
EEPROM.put(EEPROM_START_ADDRESS + 6, reg05h);
EEPROM.put(EEPROM_START_ADDRESS + 8, reg07h);
lcd.printMultiline("Settings have been saved");
}
}

void seekStation(bool UP){
if (UP)
reg02h |= RDA5807M_FLG_SEEKUP;
else
reg02h &= ~RDA5807M_FLG_SEEKUP;
setRegister(RDA5807M_REG_CONFIG, reg02h | RDA5807M_FLG_SEEK);
Searching = true;
}

void readEEPROM(){
EEPROM.get(EEPROM_START_ADDRESS, reg02h);
if ((reg02h == 255) or !(reg02h & RDA5807M_FLG_ENABLE) or
!(reg02h & RDA5807M_FLG_DHIZ) or !(reg02h & RDA5807M_FLG_DMUTE) or
(reg02h & RDA5807M_FLG_RESET)) {
// В EEPROM что-то не то. Установим настройки по умолчанию
reg02h = 0xC001;
reg03h = 0x00;
reg04h = 0x0800;
reg05h = 0x88C1;
reg07h = 0x42C6;
}
else {
EEPROM.get(EEPROM_START_ADDRESS + 2, reg03h);
EEPROM.get(EEPROM_START_ADDRESS + 4, reg04h);
EEPROM.get(EEPROM_START_ADDRESS + 6, reg05h);
EEPROM.get(EEPROM_START_ADDRESS + 8, reg07h);
}
setRegister(RDA5807M_REG_CONFIG, reg02h);
setRegister(RDA5807M_REG_TUNING, (reg03h & RDA5807M_CHAN_MASK) ? reg03h | RDA5807M_FLG_TUNE : reg03h);

setRegister(RDA5807M_REG_DEEMPH, reg04h);
setRegister(RDA5807M_REG_VOLUME, reg05h);
setRegister(RDA5807M_REG_THRESH, reg07h);
Freq = 87 + double((reg03h & RDA5807M_CHAN_MASK) >> RDA5807M_CHAN_SHIFT) / 10;
NeedRepaint = true;
}


void setRegister(uint8_t reg, const uint16_t value) {
Wire.beginTransmission(RDA5807M_RANDOM_ACCESS_ADDRESS);
Wire.write(reg);
Wire.write(highByte(value));
Wire.write(lowByte(value));
Wire.endTransmission(true);
}

uint16_t getRegister(uint8_t reg) {
uint16_t result;
Wire.beginTransmission(RDA5807M_RANDOM_ACCESS_ADDRESS);
Wire.write(reg);
Wire.endTransmission(false);
Wire.requestFrom(RDA5807M_RANDOM_ACCESS_ADDRESS, 2, true);
result = (uint16_t)Wire.read() << 8;
result |= Wire.read();
return result;
}

 

Flag Counter
Яндекс.Метрика
200stran.ru: показано число посетителей за сегодня, онлайн, из каждой страны и за всё время
Besucherzahler russain brides
счетчик посещений

Выбери лучшее!

allbest