Микросхема RDA5807M - это FM радиоприемник нового поколения с поддержкой RDS/RBDS и цифровым управлением по I2C. Микросхема выполнена по CMOS технологии, что определяет ее минимальное энергопотребление. RDA5807M уже содержит все необходимые узлы и требует лишь небольшого числа внешних компонентов. А мощный аудиопроцессор обеспечивает оптимальное качество звука при различных условиях приема. Все это делает RDA5807M удачным выбором для носимых, портативных устройств.
В интернет магазинах распространен модуль RRD-102v2, на котором распаяны RDA5807M, кварцевый резонатор и пара компонентов обвязки. В данной статье я опишу как подключить этот модуль к Ардуино и что нужно знать для создания радиоприемника на его основе.
Характеристики RDA5807M
Сразу даю ссылку на даташит: RDA5807M_datasheet_v1.1, наиболее полную информацию о характеристиках RDA5807M вы можете найти в нем. Я перечислю некоторые из них:- Напряжение питания 2.7 - 3.3В
- Потребляемый ток (при напряжении питания 3В):
- в рабочем режиме - не более 20мА
- в режиме сна - не более 15мкА
- Диапазон принимаемых частот 50 - 115МГц
- Выбираемый шаг изменения частоты: 200кГц, 100кГц, 50кГц, 25кГц
- Выбираемый источник тактового сигнала: внешний или внутренний генератор (для внутреннего генератора требуется резонатор 32.768кГц)
- Поддержка RDS/RBDS
- Управление по шине I2C
- Возможность прямого подключения нагрузки от 32Ом
Диапазон напряжения питания не самый удобный, например, от лития без стабилизации запитать не получится. Зато наушники можно подключать прямо к выводам микросхемы, дополнительное усиление не требуется. Также можно отметить небольшой потребляемый ток микросхемы, что позволяет запитывать ее от цифрового вывода микроконтроллера (по крайней мере AVR) в тех случаях, когда требуется отключение питания радио в целях энергосбережения.
Распиновка и подключение к Ардуино
Распиновка RRD-102v2 |
Подключение RRD-102v2 (RDA5807M) к Ардуино |
Выводы SDA и SCL модуля подключаются к одноименным выводам Ардуино. Для платы Uno это пины A4 и A5 соответственно. Их уровни превышают напряжение питания RDA5807M, но это не критично, микросхема отлично работает без преобразователя уровней. Питание берем с вывода 3v3.
Интерфейс управления
Здесь я хочу обратить внимание на имеющуюся в технической документации неточность (даташит на эту микросхему вообще очень мутный): в ней говорится, что I2C адрес микросхемы 0x10h, что внутренние адреса ее регистров не видны и что чтение и запись выполняются последовательно, начиная с фиксированного стартового адреса (0x0Ah для чтения, 0x02h для записи). После каждой операции чтения/записи происходит инкремент внутреннего счетчика и очередная операция будет выполняться уже для следующего регистра. Так до тех пор, пока внутренний счетчик не дойдет до верхней границы 0x3Ah, после этого он вернется к своему начальному значению.На самом деле RDA5807M отзывается на три I2C адреса, в чем легко убедиться, воспользовавшись I2C сканером:
I2C адреса RDA5807M |
Адрес 0x10h используется для последовательного обращения к регистрам, как было описано выше.
Адрес 0x11h позволяет обращаться к произвольным регистрам.
Адрес 0x60h позволяет работать с RDA5807M в режиме совместимости с TEA5767.
Упоминание адреса 0x11h можно найти в документе RDA5807P_ProgManual_1.0. Хоть он и предназначен для другой микросхемы, но практически всё применимо и для RDA5807M. Ниже приведен фрагмент из данного документа, описывающий формат I2C обмена при использовании адреса 0x11h:
Формат обмена с RDA5807M по I2C адресу 0x11h |
Как можно видеть, при записи в режиме произвольного доступа первым передается адрес интересующего регистра (REGISTER ADDRESS), затем старший и младший байты данных. Для чтения содержимого регистра из RDA5807M микроконтроллер сначала передает его адрес, затем считывает старший и младший байты. Чуть позже я приведу пример чтения/записи регистров, а пока разберемся с их назначением.
Регистры RDA5807M
Управление работой RDA5807M заключается в обращении к его регистрам: изменяя одни регистры, мы производим необходимые нам настройки; из других можно читать различную информацию (флаги, данные RDS и т.д.). Регистры 16-разрядные, их адреса и назначение приведены в даташите. Описание весьма скудное, поэтому я решил сам "пощупать" каждый регистр, чтобы понять какой бит за что отвечает. Для этого была написана следующая программа:Управление работой RDA5807M с компьютера |
Данная программа читает значения регистров RDA5807M, отображает в удобном виде и позволяет изменять их, щелкая мышью по элементам управления. Ардуино при этом выступает в роли посредника между программой на компьютере и RDA5807M, для этого в нее должен быть загружен соответствующий скетч (вы найдёте его в программе по кнопке "Скетч для Ардуино"). Очень рекомендую попробовать данную программу, чтобы разобраться с назначением регистров. Скачать ее можно здесь. И, чтобы совсем не осталось вопросов по управлению RDA5807M, привожу описание регистров на понятном языке.
Регистр | Биты | Имя | Назначение | Значение по умолчанию |
00h | 15:0 | CHIP_ID | Chip ID - Идентификатор микросхемы. Есть у меня основания полагать, что значение ChipID состоит именно из двух байт, а не одного, как это указано в даташите. | 0x5804 |
02h | 15 | DHIZ | Audio Output High-Z Disable. Управляет состоянием аудио выводов: 0 - выводы находятся в высокоимпедансном состоянии; 1 - переводит выводы в рабочий режим. | 0 |
14 | DMUTE | Mute Disable - отключение режима mute, который по умолчанию включен (значение 0). Для отключения mute в этот бит следует записать 1. | 0 | |
13 | MONO | Принудительное моно, включается записью в данный бит значения 1 | 0 | |
12 | BASS | Bass Boost - усиление басов. Для включения данной опции необходимо записать 1 | 0 | |
11 | RCLK_NON_ CALIBRATE_ MODE |
Если я правильно понял, этот бит отключает температурную компенсацию тактового генератора, в результате чего RDA5807M не сможет работать в заявленном температурном диапазоне (-20..70C) и сможет поддерживать колебания температуры только на +/- 20C от точки настройки. | 0 | |
10 | RCLK_DIRECT_ INPUT_MODE |
Бит RCLK Direct Input Mode следует установить в 1, если используется внешний тактовый сигнал | 0 | |
9 | SEEKUP | Seek Up - направление поиска радиостанций: 0 - к нижней границе диапазона; 1 - вверх. | 0 | |
8 | SEEK | Запись 1 в этот бит запускает процесс поиска радиостанции. Поиск ведется в направлении, заданном битом SEEKUP, до нахождения радиостанции или до прохождения всего диапазона частот, после чего данный бит сбрасывается и устанавливается бит STC. | 0 | |
7 | SKMODE | Seek Mode. Определяет поведение при достижении границы диапазона во время поиска радиостанций: 0 - продолжить поиск с другой границы; 1 - прекратить поиск | 0 | |
6:4 | CLK_MODE | Позволяет выбрать частоту внешнего тактового сигнала. Возможны следующие значения: 000 = 32.768кГц 001 = 12МГц 101 = 24МГц 010 = 13МГц 110 = 26МГц 011 = 19.2МГц 111 = 38.4МГц При указании неверного значения ничего страшного не произойдет, просто FM приемник не сможет настраиваться на частоту и выполнять поиск радиостанций. |
000 | |
3 | RDS_EN | RDS/RBDS Enable. Запись 1 в этот бит включает прием RDS/RBDS сообщений. | 0 | |
2 | NEW_METHOD | New Demodulation Method Enable - установка этого бита задействует новый метод демодуляции, способный улучшить чувствительность приемника | 0 | |
1 | SOFT_RESET | Программный сброс RDA5807M. Установка бита в 1 приведет к сбросу всех внутренних регистров к значениям по умолчанию. Сброс выполняется автоматически при включении питания микросхемы, нет необходимости сбрасывать устройство дополнительно. | 0 | |
0 | ENABLE | Power Up Enable - разрешение работы. Установка в 1 переводит приемник в рабочий режим; 0 - спящий режим - отключает питание внутренних узлов, состояние регистров при этом сохраняется, после возвращения в рабочий режим необходимо выполнить TUNE для настройки на радиостанцию. | 0 | |
03h | 15:6 | CHAN | Channel Select - выбор канала. Частота радиостанции устанавливается не явно, а путем изменения значения CHAN, которое при умножении на SPACE и прибавления нижней границы диапазона дает итоговую частоту. Для записи CHAN необходимо также установить бит TUNE, в противном случае CHAN не изменится. | 0x00 |
5 | DIRECT_MODE | Режим прямого управления, который используется только при тестировании - это описание из даташита, не уверен, что данный бит имеет отношение к RDA5807M. | 0 | |
4 | TUNE | Запись в этот бит значения 1 запускает процесс настройки. По окончании настройки устанавливается бит STC, бит TUNE при этом сбрасывается. | 0 | |
3:2 | BAND | Выбор полосы. Возможно одно из четырех значений: 00 - 87..108МГц 01 - 76..91МГц 10 - 76..108МГц 11 - 65..76МГц или 50..65МГц (определяется битом 65M_50M MODE регистра 07h) |
00 | |
1-0 | SPACE | Задает шаг изменения частоты. Возможны следующие значения: 00 - 100кГц 01 - 200кГц 10 - 50кГц 11 - 25кГц В большинстве стран частоты радиостанций разнесены на 200кГц или 100кГц. Поэтому, скорее всего, вам не придется менять значение по умолчанию. Установив шаг 50кГц или 25кГц, вы лишь замедлите процесс поиска радиостанций. |
00 | |
04h | 15:12 | RSVD | Биты зарезервированы | 0000 |
11 | DE | De-emphases. Определяет значение постоянной времени для частотных предыскажений: 0 - 75мкс 1 - 50мкс Предыскажения подразумевают усиление высоких частот сигнала при передаче (pre-emphasis) с целью уменьшения воздействия на них помех и последующее восстановление исходного сигнала в приемнике (ослабление высоких частот - de-emphases). В большинстве стран (в т.ч. в Европе и РФ) используется значение 50. В Северной и Южной Америке, в Южной Корее - 75. |
0 | |
10 | RSVD | Зарезервирован | 1 | |
9 | SOFTMUTE_EN | Soft Mute Enable - приглушение звука, может быть использовано для минимизации шумов в условиях слабого приема. Функция включается установкой бита в 1. | 0 | |
8 | AFCD | Automatic Frequency Control Disable - отключение автоматической подстройки частоты. 0 - AFC работает 1 - AFC выключено. |
0 | |
05h | 15 | INT_MODE | Режим генерации прерывания при завершении поиска/настройки. Данный бит определен в даташите, но не имеет отношения к RDA5807M. Актуален для микросхем с дополнительными выводами GPIO, например, RDA5807P. | 1 |
14:12 | RSVD | Биты зарезервированы | 000 | |
11:8 | SEEKTH | Seek Threshold. Данные биты задают порог отношения сигнал/шум при выполнении поиска радиостанций. | 1000 | |
7:6 | LNA_PORT_SEL | Low Noise Amplifier Port Selection - эти биты пропущены в даташите RDA5807M. При этом они весьма важны, поскольку определяют источник сигнала для приемника (смотрите блок LNA на функциональной схеме приемника в даташите): 00 - нет входа 01 - LNAN (земля) 10 - LNAP (вход FMIN) 11 - оба источника |
10 | |
5:4 | RSVD | Биты зарезервированы | 00 | |
3:0 | VOLUME | Регулировка громкости | 1011 | |
06h | 15 | RSVD | Зарезервирован | 0 |
14:13 | OPEN_MODE | Данные биты указаны в даташите, но они неактуальны для RDA5807M. В других микросхемах серии установка этих битов в 11 разрешает изменение остальных битов регистра, отвечающих за настройку I2S (Audio Data Interface). | 00 | |
07h | 15 | RSVD | Зарезервирован | 0 |
14:10 | TH_SOFTBLEND | Soft Blend Thershold - настройка уровня шумоподавления. | 10000 | |
9 | 65M_50M MODE | Данный бит определяет используемый диапазон частот, когда биты BAND содержат значение 11: 0 - 50..76МГц 1 - 65..76МГц |
1 | |
8 | RSVD | Зарезервирован | 0 | |
7:2 | SEEK_TH_OLD | Seek Threshold Old - по аналогии с SEEKTH данные биты определяют порог при поиске радиостанций, но актуальны только при SEEK_MODE (биты 14:12 регистра 0x20h) = 001 - "старый" метод поиска. | 000000 | |
1 | SOFTBLEND_EN | Soft Blend Enable. Данный бит разрешает шумоподавление, уровень которого задан битами TH_SOFTBLEND. Помогает здорово очистить сигнал от помех. | 1 | |
0 | FREQ_MODE | Режим задания частоты. Когда данный бит сброшен в 0, результирующая частота определяется как BAND + CHAN * STEP. При FREQ_MODE = 1 частота определяется как BAND + содержимое регистра 08h. | 0 | |
08h | 15:0 | FREQ_DIRECT | Определяет частоту при FREQ_MODE = 1. Результирующая частота является суммой значения данного регистра (в килогерцах) и нижней границы диапазона. Например, при BAND = 00 (87..108МГц) и FREQ_DIRECT = 20300 итоговая частота будет 107,3МГц. Описание регистра FREQ_DIRECTотсутствует в даташите, вероятно, потому, что такой способ изменения частоты не является штатным. |
0x0h |
0Ah | 15 | RDSR | RDS Ready - флаг готовности данных RDS/RBDS (1 - данные готовы) | 0 |
14 | STC | Seek/Tune Complete - флаг завершения поиска/настройки на заданную частоту (1 - операция завершена). | 0 | |
13 | SF | Seek Fail - флаг, сигнализирующий о неуспешном выполнении поиска, когда не удалось найти сигнал с RSSI большим порога SEEKTH | 0 | |
12 | RDSS | RDS Synchronization - индикатор синхронизации RDS. 0 - RDS декодер не синхронизирован; 1 - RDS декодер синхронизирован. В даташите указано, что данный флаг обновляется только в verbose (подробном) режиме работы RDS (в противопоставление стандартному, менее информативному режиму), однако не уточняется, какой бит отвечает за выбор режима. Судя по тому, что данный флаг обновляется, как и биты BLERA .. BLERD, RDA5807M по умолчанию работает в подробном режиме RDS. |
0 | |
11 | BLK_E | Данный флаг сообщает о получении E блока. | 0 | |
10 | ST | Stereo Indicator. 0 - моно; 1 - стерео. |
1 | |
9:0 | READCHAN | Read Channel. Эти биты содержат значение CHAN, доступны только для чтения. В режиме последовательного доступа к регистрам RDA5807M стартовый адрес для чтения - 0Ah, таким образом нет возможности прочитать значение CHAN регистра 03h. Этим и обусловлено наличие битов READCHAN. | 0x0h | |
0Bh | 15:9 | RSSI | Received Signal Strength Indicator - показатель уровня принимаемого сигнала. | 0 |
8 | FM_TRUE | Данный флаг сигнализирует о наличии передачи на текущей частоте. То есть приемник настроен на радиостанцию. | 0 | |
7 | FM_READY | Насколько я могу судить, данный флаг идентичен флагу STC | 0 | |
6:5 | RSVD | Биты зарезервированы | 00 | |
4 | ABCD_E | Действующий в США стандарт RBDS помимо блоков A, B, C и D, предусмотренных стандартом RDS, предполагает использование еще одного блока - E. Бит ABCD_E помогает идентифицировать содержимое регистров 0Ch..0Fh как ABCD или E: 0 - A, B, C, D 1 - E |
0 | |
3:2 | BLERA | Block Errors Level Of A - уровень ошибок в блоке A (RDS) или E (RBDS, когда ABCD_E флаг установлен в 1): 00 - нет ошибок; 01 - 1..2 ошибки требуют коррекции; 10 - 3..5 ошибок требуют коррекции; 11 - более 6 ошибок - блок некорректный и не должен использоваться. |
||
1:0 | BLERB | Block Errors Level Of B - уровень ошибок в блоке B (RDS) или E (RBDS, когда ABCD_E флаг установлен в 1). Значения битов аналогичны BLERA. | ||
0Ch | 15:0 | RDSA | Блок A (в режиме RDS) или E (в режиме RBDS при ABCD_E = 1). | 0x5803h |
0Dh | 15:0 | RDSB | Блок B (в режиме RDS) или E (в режиме RBDS при ABCD_E = 1). | 0x5804h |
0Eh | 15:0 | RDSC | Блок C (в режиме RDS) или E (в режиме RBDS при ABCD_E = 1). | 0x5808h |
0Fh | 15:0 | RDSD | Блок D (в режиме RDS) или E (в режиме RBDS при ABCD_E = 1). | 0x5804h |
10h | 15:14 | BLERC | Block Errors Level Of C - уровень ошибок в блоке C (RDS) или E (RBDS, когда ABCD_E флаг установлен в 1). Значения битов аналогичны BLERA. | |
13:12 | BLERD | Block Errors Level Of D - уровень ошибок в блоке D (RDS) или E (RBDS, когда ABCD_E флаг установлен в 1). Значения битов аналогичны BLERA. |
Это не все регистры RDA5807M, по старшим адресам доступны другие. Возможно, среди них есть еще что-то интересное. И если вам о них известно, пишите, добавлю их в список.
Программирование RDA5807M
Давайте начнем с простенького скетча. Если вы попробуете управлять RDA5807M из моей программы, то обнаружите, что для того чтобы заставить его работать достаточно установить несколько битов: ENABLE, DHIZ, DMUTE, SEEK. Установка последнего запустит поиск радиостанции. Эти же действия можно выполнить программно при помощи следующего скетча:#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);
}
Подключите RDA5807M к Ардуино по приведенной ранее схеме и залейте в нее скетч. Приемник выполнит поиск и настроится на первую найденную радиостанцию. Бит Tune при этом сбрасывается. Нажатие кнопки Reset на Ардуино и повторное выполнение функции setup будут снова устанавливать этот бит, инициируя поиск следующей станции. Работает? Двигаемся дальше.
В примере скетча выше мы записали в регистр 02h заранее определенное значение. На деле такое требуется редко, разве что для инициализации некоторых регистров. В основном же значения регистров формируются в процессе работы программы при изменении отдельных битов. В таких случаях удобно использовать константы, содержащие номера этих битов или маски для их установки. Ниже приведен пример такого скетча. Он позволяет настроиться на конкретную радиостанцию, установить громкость и получить RSSI.
#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;
}
В этом примере значения регистров получаются установкой отдельных разрядов. Для этого используются определенные в начале скетча флаги и маски. Я описал несколько из них для примера, остальные добавляются по аналогии.
Чтобы настроить RDA5807M на интересующую частоту необходимо установить значения BAND и SPACE и затем изменять только значение CHAN. Итоговая частота определяется по формуле:
F = BAND + CHAN * SPACE.
В скетче используются определенные по умолчанию BAND и SPACE (87..108МГц и 100кГц соответственно). По ним можно определить значение, которое должно быть записано в биты CHAN для получения интересующей частоты. Не забывайте при записи CHAN устанавливать также бит TUNE.
Для изменения громкости значение регистра 05h считывается из RDA5807M в переменную. Затем осуществляется сброс битов VOLUME. И уже после этого можно устанавливать новое значение громкости и записывать результат в регистр.
Для получения RSSI выполняются обратные действия: в считанном из регистра 0Bh значении сбрасываются все биты, кроме содержащих RSSI. Затем результат сдвигается вправо, чтобы младший бит RSSI оказался в младшем разряде переменной. Так мы получим нужное нам значение.
Теперь, когда описаны основные приемы управления RDA5807M, можно приступить к программированию. Нужно лишь определиться с функционалом и интерфейсом.
Добавим LCD дисплей и энкодер
Да, я люблю использовать в своих проектах LCD2004 с I2C интерфейсом и энкодер вращения. Это уже привычные для меня элементы создания пользовательского интерфейса. Используя их, я могу сосредоточиться на текущей задаче, а не заморачиваться с изобретением велосипеда. Поэтому сейчас я добавил их в схему:Схема радио с дисплеем и энкодером |
Макет радио с дисплеем и энкодером |
Итак, моя текущая задача - это создание радио с базовым функционалом и индикацией. О законченном проекте речь пока не идет. Для меня это скорее знакомство с данным модулем. Поэтому в предлагаемом ниже скетче нет фишек вроде сохранения списка радиостанций в EEPROM. Нет и работы с RDS - использованию этой технологии в RDA5807M я посвящу следующую публикацию. В последствии я планирую сделать радио в оригинальном корпусе с OLED дисплеем. А пока можете оценить результат данного этапа, скетч доступен по ссылке. Для работы требуется библиотека LiquidCrystal_I2C_Menu, скачайте и установите ее.
В скетче реализовано:
- Поиск радиостанции вверх/вниз и отображение частоты
- Регулировка громкости
- Ввод значения частоты энкодером
- Выбор поведения при повороте энкодера: регулировка громкости или поиск радиостанции
- Установка ряда параметров, отвечающих за звук и шумоподавление
- Сохранение настроек в EEPROM и чтение их при включении радио
Вход в меню осуществляется при нажатии на кнопку энкодера. Кстати, в скетче присутствует код для управления RDA5807M с компьютера из упомянутой ранее программы. Это удобно для отслеживания содержимого регистров в процессе работы радио. Чтобы отключить эту возможность достаточно закомментировать первую строку скетча.
На этом пока всё. Продолжение будет в следующей публикации с обзором RDS.
Браво! Ждем продолжения.
ОтветитьУдалитьСлучайно зашел, великолепно. Пожалуй прочитаю все что есть ) Спасибо автору!
ОтветитьУдалитьСпасибо за положительный отзыв!
УдалитьСпасибо большое, все доступно и понятно.
ОтветитьУдалитьЗаходите еще, будет продолжение про RDS
УдалитьЗаинтересовало, надо поэксперементировать. Спасибо Владимир.
ОтветитьУдалитьСпасибо очень интересно, занимаюсь созданием своего радио, данная публикация очень помогла.
ОтветитьУдалитьХотелось-бы узнать о автоматической настройке и записи найденных радиостанций в каналы, чтобы потом переключать только каналы. Я так понимаю нужно использовать регистр SEEK? Как правильно его использовать?
Верно, SEEK. Только это не регистр, а бит регистра 02H. Если вам нужна процедура нахождения всех радиостанций, то ее алгоритм может быть следующий:
Удалить1. Устанавливаете CHAN = 0, SEEKUP = 1 (поиск вверх), SKMODE = 1 (прекратить поиск при достижении границы).
2. В цикле пока SF != 1 (т.е. пока не дошли до верхней границы) устанавливаете бит SEEK для поиска очередной станции и периодически читаете регистр 0AH в ожидании STC = 1.
3. Когда бит STC изменится с 0 на 1 (при условии что SF = 0), сохраняете текущее значение CHAN. В массиве или в EEPROM - как вам удобнее. И возвращаетесь к пункту 2 для поиска следующей станции.
4. При прохождении всего диапазона частот будут установлены флаги STC и SF. Последний является условием для выхода из предложенного цикла.
По окончании процедуры получите массив значений CHAN и их количество.
Спасибо, буду пробовать.
ОтветитьУдалить..спасибо, что в регистрах навели порядок, собирался тожсамое, а тут бац! и ваша статья попалась, и отдельная благодарность за скан чипа на доп.отклики, мнеб ивголову непришло, карочи, like-like �� very-very
ОтветитьУдалитьБлагодарю за положительный отзыв о публикации. Сегодня выложил продолжение про RDS
УдалитьВладимир, если вас не затруднит, помогите со скетчем для автоматического поиска. Бьюсь уже месяц, хоть и не каждый день. Или посмотрите мой кусок:
ОтветитьУдалитьif (enc1.isRight ()) { //поворот энкодера вправо
reg02h |= RDA5807M_FLG_SEEKUP | RDA5807M_FLG_SKMODE; //устанавливаем флаги SEEKUP (направление поиска) и SKMODE (прекратить поиск при достижении диаппазона)
setRegister(RDA5807M_REG_CONFIG, reg02h); //записываем в регистр
reg03h &= ~RDA5807M_CHAN_MASK; //сбрасываем значение CHAN
setRegister(RDA5807M_REG_TUNING, reg03h); //записываем в регистр
while (sf != 1) { //начало цикла (пока не дошли до конца диаппазона)
reg02h |= RDA5807M_FLG_SEEK; //устанавливаем флаг SEEK (начало поиска)
setRegister(RDA5807M_REG_CONFIG, reg02h); //записываем в регистр
reg0Ah = getRegister(RDA5807M_REG_STATUS1); //читаем регистр 0AH
bool stc = (reg0Ah & RDA5807M_FLAG_STC); //читаем флаг STC (найдена радиостанции)
// Serial.println ("STC " + String (stc));
reg0Ah = getRegister(RDA5807M_REG_STATUS1); //читаем регистр 0AH
sf = (reg0Ah & RDA5807M_FLAG_SF); //читаем флаг SF (успешность поиска)
//Serial.println ("SF " + String (sf));
if (stc == true && sf == false) { //если найдена радиостанция и не дошли до конца диаппазона
reg0Ah = getRegister (RDA5807M_REG_STATUS1); //читаем регистр 0AH
readChan = (reg0Ah & RDA5807M_READCHAN_MASK); //читаем значение readChan (частота)
channel[i] = readChan; //присваиваем элементу массива channel с индексом i значение readChan
Serial.println ("READCHAN " + String (readChan));
Serial.println ("CHANNEL " + String (channel[i]) + String (i));
i++; //увеличиваем индекс i на 1
break;
}
}
}
}
Где-то я что-то путаю.
Добрый день!
УдалитьСтрока, где вы сбрасываете CHAN - новое его значение не запишется без установки флага TUNE. Но ошибка скетча не в этом, скорее в операторе break, который прерывает цикл поиска радиостанций после первого же нахождения.
Флаги, которые сбрасываются приемником автоматически (TUNE, SEEK), я бы советовал записывать не в переменные, а непосредственно в регистры. Чтобы потом, например, при включении/выключении усиления басов не записать в регистр 02h флаг SEEK повторно. Иначе придется считывать содержимое регистра перед каждым его изменением.
Для автоматического поиска попробуйте такой алгоритм:
- Установка начальных значений регистров (CHAN, SEEKUP, SKMODE и т.д.)
- Бесконечный цикл
--- Установка флага SEEK в регистре 02h
--- Цикл, пока в 0ah не установится STC (ждем завершения поиска). Внутри цикла можно добавить delay, чтобы не дергать приемник всё это время
--- Считываем флаг SF. Если установлен, то выходим из цикла
--- Считываем и сохраняем значение CHAN
- Возврат к началу цикла
Кода, реализующего такой алгоритм, у меня нет. Но он совсем простой, проблем c реализацией возникнуть не должно.
И еще, внутри цикла вы несколько раз читали регистр 0ah - это лишнее. Достаточно 1 раза, для приведенного выше алгоритма - внутри вложенного цикла. Считанное значение потом используется и для проверки SF, и для получения READCHAN.
Этот комментарий был удален автором.
УдалитьШумодав не гасит шумы,а тупо снижает громкость-печалька.Хотел для переговорного приемник и жук с кварцем на передачу.Не судьба.
УдалитьДобрый день!
УдалитьВы случаем не путаете шумоподавление (SOFTBLEND) с SOFTMUTE_EN?
TH_SOFTBLEND и SOFTBLEND_EN на самом деле гасят шумы. Я это не из даташита взял, а проверил сам при плохом приеме. Работает.
Думал-помучаю,отпишусь.Но то делал отцу приемник(по болгарски где),то приболел-начинаю отходить.Вроде не путал,сейчас доигрался-тишина вообще.По одному параметру меняю-слушаю.Исправно с др скетчами.Мне не ПРИГЛУШАТЬ надо а шумоподавление!полное.Буду играться еще.Ну и срисовал несколько схем ШП.Мне 5-6 фраз за смену на 0.5 км-эфир не засру. Если можно-проверте ШП между станциями.
УдалитьСпасибо Владимир, буду пробовать.
ОтветитьУдалитьгоспода, очень понравился проект, собрал. все супер с одним лишь отличием - у автора 4х строчный дисплей и скетч под него. ткните пальцем как подправить его под двухстрочный? был бы благодарен!!!
ОтветитьУдалитьи еще пытаюсь найти в коде как сделать более плавной регулировку громкости и что бы минимальный порог был потише. это возможно или ограничивается возможностями модуля rda5807?
ОтветитьУдалитьЧтобы сделать тише, нужно подобрать резисторный делитель. Сам так планирую поступить, для наушников максимальная громкость слишком высока. А вот регулировку сделать плавнее в этом модуле не получится.
УдалитьВладимир, спасибо. Я подключил еще усилитель на pam8403 вроде самая минимальная громкость не очень громкая)) а по поводу адаптации под двухстрочный дисплей сможете ответить?
Удалитьспасибо!
При использовании двухстрочного что-то не умещается? Можете сделать фотки, чтобы я понял где править? По идее при объявлении
УдалитьLiquidCrystal_I2C_Menu lcd(0x27, 16, 2);
все функции должны подстроиться под указанный размер дисплея. Но я это не тестировал, у меня нет lcd1602, только четырехстрочный
да, не помещались пункты меню например которые ниже идут. и чтобы их выбрать нужно было сначала прокрутить чтоб они появились на экране а потом обратно крутить энкодер чтоб его выбрать и войти в него. таким образом "back" на экране вообще никогда не появлялось))
Удалитьисправил, спасибо, все теперь помещается. я просто абсолютный нуб в ардуино поэтому задаю такие вопросы. еще осталась проблема с энкодером. по идее вращение вправо - увеличение (громкости) а влево - уменьшение. сейчас наоборот. влево увеличение вправо уменьшение. поможет ли замена в коде eRight на eLeft и наоборот?
От энкодера к Ардуино идут 2 провода (CLK и DT, если энкодер как у меня). Просто поменяйте их местами, подключая к Ардуино
УдалитьТогда изменится направление перемещения по строкам меню.
УдалитьДобрый день. Спасибо большое за полный и понятный разбор управления регистрами! Есть еще один вопрос. Магазины закрыты, али долго, нет энкодера в общем. можно как нибудь заменить его на кнопки + и -? заранее спасибо.
ОтветитьУдалитьДобрый день!
УдалитьЧтобы переделать на управление кнопками, надо изменить функцию getEncoderState в файле LiquidCrystal_I2C_Menu.cpp. Сейчас она опрашивает одну кнопку и выводы энкодера A и B. Сделайте вместо опроса A, B опрос еще двух кнопок по аналогии с первой. Для них надо будет завести переменные для хранения предыдущих значений. Номер пина можно хранить в имеющихся _pinA и _pinB или переименовать их в _pinLeft, _pinRight (переименовать надо в нескольких местах, где они используются).
В общем изменения минимальные. Попробуйте.
Спасибо! Буду пробовать!
УдалитьСпасибо! Оформление материала на высшем уровне!
ОтветитьУдалитьБлагодарю! Да, удачно получилось)
УдалитьЗашибенный сайт! Вы лучший!
ОтветитьУдалитьСпасибо!
УдалитьВ этом даташите Rev.1.8 https://datasheet.lcsc.com/szlcsc/1810010217_RDA-Microelectronics-RDA5807M_C82537.pdf более полная информация по регистрам.
ОтветитьУдалитьНа первый взгляд больше похоже на описание от другой микросхемы с поддержкой I2S и GPIO. Проверю, может есть что недостающее, актуальное для RDA5807M. Спасибо.
УдалитьВладимир, здравствуйте! Может подскажите, как здесь работает режим моно (если конечно сталкивались с этим)? В регистре 02 прописываю 13 бит в 1, но разницы в звуке не ощущаю. Причем индикатор стерео также продолжает отображаться.
ОтветитьУдалитьДобрый день!
УдалитьНасколько я понимаю, данный индикатор сигнализирует о наличии стерео в принимаемом радиосигнале, который содержит как моно, так и стерео, плюс пилот-тон, еще RDS. И бит MONO на него не влияет.
Установка бита MONO регистра 02 принуждает декодер использовать моно сигнал. Он в свою очередь состоит из суммы сигналов левого и правого каналов.
А насчет разницы в звуке, думаю, её можно будет заметить на знакомых песнях, если в режиме стерео включить только один динамик. И если эти песни, действительно, со стереоэффектами.
Ошибочку нашел в таблице регистров. 0Ah 9:0 созданы для удобства. Прочитать биты 03h 15:6 возможно. Их и читал пока не наткнулся на упоминание в таблице. Дело в том, что удобно прочитать 0Ah и определится что настройка(поиск) станции завершен и чтоб повторно не читать частоту из этого же регистра уже прочитана частота. Выглядит так:
ОтветитьУдалить#define RDA5807M_READCHAN_MASK 0x3FF
uint16_t getFrequency () {
uint16_t Reg0Ah = 0;
do { // Ждем окончания настройки частоты
Reg0Ah = getRegister(RDA5807M_REG_STATE);
} while (~Reg0Ah & (1 << RDA5807M_BIT_STC));
Reg0Ah &= RDA5807M_READCHAN_MASK;
return (Reg0Ah + 870);
}
А вообще спасибо, уже из вашего примера библиотеку написал под себя.
Собственно вот и библиотека. Пример внутри. Все очень просто. Добавил несколько полезных функций из таблицы.
Удалитьradio.setFrequency(1070);//Задаем частоту 107,0 // После этой строки радио начнет играть. Остальные настройки не обязательны
radio.antena(2);// 0 -отключена 1 - земля, 2 - вход FMIN 3 - оба источника
radio.bass(true);// Усиление баса
radio.setStereo(false); // включаем моно режим. По умолчанию стерео
radio.setVolume(15);//0..15
radio.mute(true);
radio.mute(false);
radio.powerOFF(true);
radio.powerOFF(false); // тоже что и radio.begin();
radio.noisReduction(31); // от 0 до 31 шумодав
radio.nextStation();
radio.getRSSI();
https://drive.google.com/file/d/1UC76ne0fgzVc9WwlQz_wA7zIapd_Tx6e/view?usp=sharing
Добрый день!
Удалить1. RDA5807M имеет три I2C адреса: 0x10h, 0x11h, 0x60h.
2. Адрес 0x10h используется для последовательного доступа к регистрам. Стартовые адреса регистров для операций чтения и записи фиксированные. Для записи это 0x02h, для чтения - 0x0Ah. После каждой операции чтения/записи счетчик адреса инкрементируется.
3. Запросив по I2C адресу 0x10h N байт, вы прочитаете N/2 регистров, начиная с регистра 0x0Ah. К младшим регистрам доступа на чтение нет, и дублирование битов CHAN в 0x0Ah - это не удобство, а необходимость в данном режиме работы.
4. В режиме произвольного доступа, конечно, можно прочитать 0x03h.
radio.noisReduction(31);
Удалитьшумоподавление на холостых частотах
Спасибо за наиболее полное и внятное обсуждение регистров, помогло подключить объект к stm32F103C8T6 ;-) Отлично работает, сигнал захватывает, звук хороший. Интересно, что CHIP_ID стабильно читает 5004, а не 5804. Возможно, микросхема-китайская копия.
ОтветитьУдалитьРад помочь!
УдалитьСкажите по командам они одинаковы с RDA5807FP
ОтветитьУдалитьВ плане базового функционала - да.
УдалитьВообще все приёмники данной серии, чьи даташаты я изучал (RDA5807M / N / P / FP / SP и другие), одинаковы в управлении. Различия только в конкретном функционале: наличии или отсутствии RDS, дополнительных выводов GPIO, аудио интерфейса I2S, управлении по I2C/SPI и т.д. Соответственно, в одних даташитах описаны отвечающие за этот функционал биты, в других они пропущены или Reserved.
Владимир, спасибо! Отличный обзор! Все внятно, достаточно обстоятельно и без лишней воды! Хочу собрать FM-тюнер на чипсете Si4703. Случайно нет у Вас Вашей замечательной и удобной для понимания сути работы программы-монитора для ПК, чтобы читать/записывать данные в/из регистра FM-тюнера Si4703? Или может быть выложите исходный программы RDA5807M.exe, чтобы адаптировать ее под Si4703? Кстати, Вы не проводили сравнительный анализ этих двух чипов RDA5807 vs Si4703?
ОтветитьУдалитьДобрый день!
УдалитьСпасибо за отзыв.
Только вернулся из отпуска.
Для Si4703 у меня пока ничего нет, но сам приёмник лежит и в планах есть помучить его, может и программу для ПК написать. На мой взгляд, это очень удобный вариант изучения регистров микросхемы.
Сравнение с RDA5807M я не проводил. Но, когда смотрел даташит на Si4703, для себя отметил, что по описанию и управлению они очень похожи. И что документация у этих двух микросхем - небо и земля. У SiliconLabs всё подробно, с апнотами по программированию и RDS.
Обязательно доберусь до этой микросхемы. Сам хотел сравнить их
Исходники на Делфи. Если нужны, могу выложить
УдалитьВладимир, спасибо за ответ. Делфи к сожалению не знаю, боюсь не смогу переделать Ваш исходник. Но если когда-нибудь появится у Вас программа для Si4703, буду сильно признателен, если ей поделитесь. Я провел сравнительный технический анализ Si4703 vs RDA5807M. Из минусов Si4703 - у нее менее чувствительный приемник, чем у RDA5807. У RDA больше ручных настроек, которые позволяют настроить FM-тюнер и на автопоиск (по сигнал/шум) и на шумоподавление даже в зоне неуверенного приема, где Si4703 работает совсем плохо. Зато в зоне уверенного радиоприема Si4703 работает очень хорошо, не требует никаких ручных настроек (особо их там никаких и нет). Понравился у Si4703 и хороший RDS-приемник (читал в обзорах, что у Si более правильный чем у RDA алгоритм аппаратной обработки ошибки RDS-данных). Правда под обработку RDS использовал стандартную библиотеку.
ОтветитьУдалитьПока не понял какой из этих чипсетов я выберу для своей задачи.
Но с удовольствием почитаю и Ваши статьи про Si4703, если надумаете ее поковырять!
Заранее спасибо!
Тоись, если передача стерео, то как бы я ни ставил бит 13 регистра 0х02 в принудительное моно, в 10 бите регистра 0х0А все равно будет выставлен бит "Стерео"?
ОтветитьУдалитьПроверил: выставляем моно в 02h - индикатор стерео в 0Ah сбрасывается.
Удалить0Ah это флаги состояния а не регистр настройки.
УдалитьЭтта хорошо. Спасибо.
УдалитьА подскажи еще, какой бит отвечает за бесшумную настройку? Чтоб не шипело между станциями.
ОтветитьУдалитьИ еще вопрос, биты RSSI, которые показывают уровень принимаемого сигнала я ни разу не видел в них значения больше 32, где бы я ни находился, хоть под вышкой, у всех так? На даче в 30 км от вышки в прямой видимости, RSSI = 19, приём нормальный, дома на этой же радиостанции RSSI = 32, до вышки 5 км по прямой. Или я чот не так делаю?
Можно DHIZ (0 бит в 02h) сбрасывать при поиске. А при завершении, когда флаг STC (14 бит в 0Ah) = 1, снова выставлять DHIZ в 1.
УдалитьRSSI здесь меня самого смущает. Я уж думал, не ошибка ли в даташитах и значение 5-, а не 6-битное. Но, по-моему, я видел значения больше 31, поэтому забил на этот момент.
Надо будет проверить RSSI при приёме с SI4713. Интересно, что покажет.
У меня (Санкт-Петербург) до радиовышки 31 км, но хорошая антенна (1 метр) RSSI показывает и больше 60
УдалитьСпасибо. :)
ОтветитьУдалитьЗдравствуйте, Владимир.
ОтветитьУдалитьПодскажите, пожалуйста, как ввести в этот проект отображение уровня сигнала.
Добрый день!
УдалитьПример кода для получения RTTI есть в этой статье. А как добавить его в скетч - тут разные варианты. Наверное, самый простой - это добавить блок в конец функции loop. Блок типа if (millis() - LastRTTIUpdate > 5000) {...}. Внутри блока чтение RTTI, вывод его на дисплей в виде палок (посмотрите пример создания и вывода пользовательских символов: https://github.com/fdebrabander/Arduino-LiquidCrystal-I2C-library/blob/master/examples/CustomChars/CustomChars.ino) и в конце блока LastRTTIUpdate = millis();
Спасибо большое.
ОтветитьУдалитьСкетчь не компилируется подсвечивает 322 строчку EEPROM.get(EEPROM_START_ADDRESS, reg02h);
ОтветитьУдалитьс ошибкой exit status 1
'reg02h' was not declared in this scope
Не подскажите в чем проблема?
Какой скеч вы компилируете где 322 строчки?
УдалитьИзвините сам виноват. Запустил скетч из архива. А там 2 файла после распаковки архива все скомпилировалась
ОтветитьУдалитьЧто сделать чтобы энкодер KY-040 глючит
ОтветитьУдалитьЭтот комментарий был удален автором.
УдалитьПавел28 сентября 2021 г., 17:49
УдалитьЧто бы он глючил соедините его на скрутках и намажте их слюной. Еще сам энкодер можно намочить, в идеале паяльной кислотой.
Добрый день!
УдалитьИван, что у вас не так с энкрдером?
Как будто дребезг контактов сам выйдет с меню или проскочит несколько пунктов
УдалитьПочему "как будто", это дребезг и есть. Вы раньше не работали с энкодерами? Можно попробовать сгладить дребезг: между выходом энкодера и землёй установите ёмкость 0,01..0,1мкф и подтяните вывод к питанию резистором 10к или больше - пробуйте, как будет лучше.
УдалитьЕсть ещё аппаратные подавители дребезга. MC14490 хорош
Владимир, а не растолкуете как все таки правильно вычислять частоту
ОтветитьУдалитьУ вас код
// Регистр 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);
Т.е.фактически если я хочу установить частоту 102,3 она вычислится как (1023-870)/1=153.Т.е это число я должен записать в регистр 03 и установить бит TUNE
У вас же вычисленная частота еще сдвигается влево на 6.Откуда взялось 6 и почему влево?Ведь сдвиг влево это фактически умножение на 2 в степени 6 ( 64)
Буду благодарен за ответ
BAND = 00 - означает, что начало диапазона 87МГц. К нему будет прибавляться значение, определяемое:
Удалить-значением SPACE (в данном случае 100кГц)
-и значением CHAN
Если в CHAN записано 10, то это значение умножится на 100кГц (SPACE) и прибавится к 87МГц (начало диапазона). Это даст результирующую частоту 88МГц. И наоборот, зная желаемую частоту, не составит труда найти CHAN по известным SPACE и BAND.
У меня в расчетах SPACE явно не участвует, т.к. он уже учтён переходом от 87 к 870 и от 107,3 к 1073. Если бы SPACE был = 50 или 200 кГц, то простой перестановкой десятичной точки дело бы не обошлось, и его значение использовалось бы в формуле явно.
(1023-870)/1=153.Т.е это число я должен записать в регистр 03 - ДА
Посмотрите еще раз описание регистра 03H, значение CHAN хранится в битах с 6 по 15. Поэтому и сдвигаем влево на 6
PS. Обратил внимание, что местами для битов 0-1 регистра 03H я использовал название STEP - шаг. Смысл тот же, но по факту эти биты обозначены как SPACE. Поправлю.
Этот комментарий был удален автором.
ОтветитьУдалитьРазобрались? регистры и переменная reg03h 16 бит
УдалитьДа, взял лист экселя, разрисовал там регистры для наглядности, подвигал и все понял
Удалитьмогу выслать файлик- вдруг понадобится для статьи или для просвещения других чайников)
Кстати RDA5807FP можно вообще без контроллера управлять.6 ножку на плюс3В, 1 ножка через кнопку и резистор на землю - сброс, кнопки к 16 и 15 - громкость + - , кнопки к 7 и 8 - каналы вперед-назад
вот ссылка на файлик
ОтветитьУдалитьhttps://turb.cc/etzhd7viqp1j.html
Здравствуйте, как можно отключить звук на пустой (шумовой) частоте на фм радио, что для этого использовать?
ОтветитьУдалитьЯ использую FM-модуль RDA5807M.
пример :
vzssssssssssssssssssssssssssssssssssssss (белый шум)
мне нужна помощь сейчас, как я могу уменьшить шум пустой радиостанции, есть ли код для предотвращения шума на пустых частотах?
мне просто нужен код для отображения значений шума на экране и код для вырезания шума
Кто-нибудь знает об этом?
УдалитьЯ открывал тему на эту тему.
https://electronics.stackexchange.com/questions/633747/what-is-the-method-to-mute-sound-during-seek-on-rda5807-fm#633747