В настоящее время большая часть человечества использует мобильные телефоны для прослушивания музыки, новостей и другой аудио информации. Однако не так давно доминирующую роль в этих задачах играли системы FM радиосвязи (радиовещания). Сейчас традиционные системы радиосвязи (радиовещания) понемногу утрачивают свою роль, однако в экстренных случаях, когда интернет не доступен, системы радиосвязи (радиовещания) могут стать единственно возможным средством связи (вещания), поэтому определенная часть этих систем до сих пор поддерживается в рабочем состоянии на случай появления экстренных ситуаций. В связи с этим мы считаем, что у каждого уважающего себя радиолюбителя дома должна быть хотя бы простенькая FM радиостанция.
В этой статье мы рассмотрим создание простого FM приёмника на основе платы Arduino и микросхемы (модуля) FM приёмника RDA5807. С помощью данного приемника мы сможем осуществлять прием сигналов от станций, вещающих в FM диапазоне. Настройку на сигнал конкретной станции мы будем производить с помощью потенциометра. Также в нашем проекте мы будем использовать усилитель звуковой частоты и регулировать уровень сигнала на его выходе с помощью потенциометра.
Общие принципы работы FM приёмника
Принцип работы радиостанций заключается в том, что они преобразуют первичные электрические сигналы в радиосигналы (более высокой частоты чем первичные сигналы), усиливают их до необходимого уровня и затем излучают их в окружающее пространство с помощью антенны. В процессе преобразования сигналов в радиостанции они подвергаются модуляции. Одними из самых известных (старейших) методов модуляции являются амплитудная (AM - amplitude modulation) и частотная модуляции (FM - frequency modulation).
Мы в нашем проекте будем рассматривать приемник, предназначенный для приема сигналов частотной модуляции (FM, в рус. языке - ЧМ). В данном виде модуляции частота несущего колебания модулируется (изменяется) по закону амплитуды первичного низкочастотного сигнала. Проектируемый нами приемник сможет принимать сигналы частотной модуляции (ЧМ) на определенной частоте и преобразовывать их в сигналы звуковой частоты (первичный электрический сигнал). Наш FM приемник будет построен на основе микросхемы RDA5807.
Необходимые компоненты
- Плата Arduino Nano (купить на AliExpress).
- Приемник RDA5807 (RDA5807 receiver) (купить на AliExpress).
- Усилитель звуковой частоты.
- Потенциометры 10 и 100 кОм (купить на AliExpress).
- Перфорированная плата.
- Соединительные провода.
Приемник RDA5807
RDA5807 представляет собой однокристальный модуль (микросхему) FM стерео радиоприёмника с интегрированным в него синтезатором частоты. Модуль способен работать в диапазоне частот 50 – 115 МГц, обеспечивать управление уровнем громкости и владеть информацией об уровне принимаемого сигнала. Модуль содержит кварцевый генератор на 32.768 КГц, цифровой усилитель и другие компоненты. Структурная схема модуля RDA5807M представлена на следующем рисунке.
Модуль построен на цифровой архитектуре и включает малошумящий усилитель, работающий в диапазоне от 50 до 115 МГц. Также модуль содержит программируемый усилитель на ПЛИСах (PGA), АЦП (аналого-цифровой преобразователь) высокого разрешения и высокоточный ЦАП (цифро-аналоговый преобразователь). Амплитудный ограничитель на входе модуля предотвращает его перегрузку (по уровню) и ограничивает число интермодуляционных составляющих, создаваемых соседними каналами. Усилитель на ПЛИСах усиливает входной сигнал, который затем преобразуется в цифровую форму с помощью АЦП. Ядро цифровой обработки сигналов модуля управляет выбором каналов, демодуляцией FM сигналов и разуплотнением стерео сигнала. Назначение контактов (распиновка) микросхемы RDA5807 представлено на следующем рисунке.
Питающее напряжение для модуля составляет от 1.8 до 3.3V. Подключить модуль RDA5807 к микроконтроллеру можно по интерфейсу I2C. Модуль имеет 13 16-битных регистров, каждый из которых выполняет свою определенную функцию. Адреса регистров начинаются с 00H и заканчиваются 0FH. Во всех 13 регистрах некоторые биты зарезервированы. Регистры выполняют такие функции как изменение уровня, смена канала и т.д.
Модуль проблематично использовать для подключения к нему соединительных проводов, поэтому мы использовали перфорированную плату, чтобы с ее помощью и олова сделать контакты для подключения проводов как показано на выше приведенном рисунке.
Усилитель звуковой частоты
Усилитель звуковой частоты представляет собой устройство, которое усиливает слабые сигналы звуковой частоты до уровня, необходимого для нормальной работы громкоговорителя (динамика). Для нашего проекта мы спроектировали усилитель звуковой частоты на основе микросхемы LM386, его схема показана на следующем рисунке.
Схема проекта
Схема FM приёмника на основе платы Arduino и модуля RDA5807 представлена на следующем рисунке.
В схеме мы использовали два потенциометра, один из которых используется для настройки приемника на нужную частоту, а второй – для регулировки уровня громкости в усилителе звуковой частоты. При этом для регулировки уровня громкости можно использовать как потенциометр, подключенный между 1 и 8 контактами микросхемы LM386, так и потенциометр, который подключен к контакту 3 микросхемы LM386.
Но по мере тестирования проекта мы решили внести небольшие изменения в схему представленного усилителя звуковой частоты. Так, вместо двух потенциометров в схеме усилителя мы использовали только один, а другой потенциометр мы заменили на обычный резистор.
Потенциометр, который используется для настройки приемника на нужную частоту, подключен к плате Arduino nano – его средний контакт подключен к контакту A0 платы, а остальные два контакта – к 5V и земле (GND) соответственно.
Контакты A4 и A5 платы Arduino (это контакты интерфейса I2C), подключены к контактам SDA и SCL модуля RDA5807M. При этом учитывайте то, что модуль RDA5807M работает от питающего напряжения 3.3V, поэтому его контакт VCC необходимо подключить к контакту 3v3 платы Arduino Nano.
После сборки проекта на макетной плате у нас получилась конструкция следующего вида:
Объяснение программы для Arduino
Полный код программы приведен в конце статьи, здесь же мы кратко рассмотрим его основные фрагменты.
В коде программы нам необходимо инициализировать модуль приемника RDA5807M и установить канал с необходимой частотой. Вращение ручки потенциометра, подключенного к контакту A0 платы Arduino Nano, будет приводить к изменению частоты настройки и, следовательно, к изменению канала приемника.
Вначале в программе нам необходимо инициализировать библиотеку wire для взаимодействия с модулем RDA5807. В переменной “channel” мы будем хранить значение канала настройки. Первоначально у нас в этой переменной будет храниться значение 187, поэтому при включении схемы (подачи на нее питания) наш приемник всегда будет настраиваться именно на этот канал.
1 2 |
#include <Wire.h> uint16_t channel = 187; |
Далее нам необходимо загрузить требуемые значения байтов во все регистры микросхемы RDA5807 чтобы произвести ее первоначальную инициализацию.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
uint8_t boot_config[] = { /* register 0x02 */ 0b11000001, 0b00000011, /* register 0x03 */ 0b00000000, 0b00000000, /* register 0x04 */ 0b00001010, 0b00000000, /* register 0x05 */ 0b10001000, 0b00001111, /* register 0x06 */ 0b00000000, 0b00000000, /* register 0x07 */ 0b01000010, 0b00000010, }; |
После того, как мы инициализировали первоначальное состояние приемника, мы можем производить его настройку на требуемый канал. Для настройки приемника на требуемый канал (то есть изменения частоты настройки) нам необходимо изменить только первые 4 байта, передаваемые в регистры модуля. Также нам необходимо начать передачу данных по интерфейсу I2C. В нашей программе нам нет необходимости назначать адрес I2C поскольку в даташите на модуль RDA5807 указано что он имеет фиксированные адреса I2C: 0x02h – для операций записи данных и 0x0Ah для операций считывания данных.
1 2 3 4 5 6 7 8 |
uint8_t tune_config[] = { /* register 0x02 */ 0b11000000, 0b00000001, /* register 0x03 */ (channel >> 2), ((channel & 0b11) << 6 ) | 0b00010000 }; |
В функции void setup() мы загрузим в модуль RDA5807M его загрузочные настройки по умолчанию.
1 2 3 4 5 6 7 8 9 10 11 12 13 |
void setup() { Serial.begin(9600); pinMode(A0,INPUT); /* Conect to RDA5807M FM Tuner: */ Wire.begin(); Wire.beginTransmission(RDA5807M_ADDRESS); Wire.write(boot_config, BOOT_CONFIG_LEN); Wire.endTransmission(); Wire.beginTransmission(RDA5807M_ADDRESS); Wire.write(tune_config, TUNE_CONFIG_LEN); Wire.endTransmission(); } |
Во время считывания значения частоты с потенциометра, подключенного к контакту A0, у нас возник ряд проблем. Прежде всего они были связаны с наличием шума, который мешал настройке на нужную частоту. Для уменьшения уровня шума мы использовали керамический конденсатор емкостью 0,1 мкФ, подключенный между контактом A0 и землей схемы (GND). В результате влияние шума на работу нашего приемника уменьшилось, но все равно его влияние ощущалось еще достаточно сильно. Поэтому мы внесли ряд изменений в код программы чтобы нейтрализовать его действие. Опытным путем мы установили, что максимальное значение шума не превышает 10. Поэтому в программу мы добавили специальное условие, которое учитывает изменение положения ручки потенциометра если считываемое с него значение (new value) не менее чем на 10 больше чем предыдущее значение (old value), считанное с него.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
void loop() { int channel1 =187 ,avg=0, newA; static int oldA = 0; int result = 0; newA = analogRead(A0); if ((newA - oldA) > 10 || (oldA - newA) > 10){ Serial.println(newA); if(newA!= oldA){ channel = channel1+(newA/10); myChangeChannel(channel); oldA=newA; } } }//loop end |
Следующая функция используется для установки байтов в массиве tune_config и затем передает данные модулю RDA5807M с помощью протокола I2C.
1 2 3 4 5 6 7 8 |
void myChangeChannel(int channel){ /* void if nothing is returned else int */ tune_config[2] = (channel >> 2); tune_config[3] = ((channel & 0b11) << 6 ) | 0b00010000; Wire.begin(); Wire.beginTransmission(RDA5807M_ADDRESS); Wire.write(tune_config, TUNE_CONFIG_LEN); Wire.endTransmission(); } |
Тестирование работы FM приёмника
Когда на схему нашего проекта подается питание происходит сброс модуля RDA5807M и установка в нем канала по выбору пользователя. При вращения ручки потенциометра, отвечающего за настройку приемника на требуемую частоту, подключенного к контакту A0, значения, считываемые платой Arduino Nano с этого контакта, изменяются. Если разница между старым и новым значениями больше 10, мы считаем это изменение истинным (то есть произошедшим не вследствие действия шума) и изменяем в соответствии с ним канал, на который будет настроен радиоприемник. Уровень громкости звука мы изменяем с помощью потенциометра, подключенного между контактом 3 и GND.
Более подробно работа нашего FM приёмника представлена в видео, приведенном в конце статьи.
Исходный код программы (скетча)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 |
#include <Wire.h> /* Select the frequency we want to tune to by way * of selecting the channel for the desired frequency */ uint16_t channel = 187; /* * предполагаем что диапазон начинается с частоты 87.0MHz (для приведенных ниже настроек) * расстояние между каналами составляет 100kHz (0.1MHz) (per settings below) * тогда номер канала можно вычислить с помощью следующего выражения: * * channel = (<desired freq in MHz> - 87.0) / 0.1 * * или можно записать это выражение в другом виде: * <10 x desired freq in MHz> - 870 */ #define RDA5807M_ADDRESS 0b0010000 // 0x10 #define BOOT_CONFIG_LEN 12 #define TUNE_CONFIG_LEN 4 /* * Эти байты устанавливают нашу первоначальную конфигурацию * На этом этапе мы не беспокоимся о настройке приемника на нужный канал. * Здесь мы производим сброс модуля. */ uint8_t boot_config[] = { /* register 0x02 */ 0b11000001, /* * DHIZ audio output high-z disable * 1 = normal operation * * DMUTE mute disable * 1 = normal operation * * MONO mono select * 0 = stereo * * BASS bass boost * 0 = disabled * * RCLK NON-CALIBRATE MODE * 0 = RCLK is always supplied * * RCLK DIRECT INPUT MODE * 0 = ??? not certain what this does * * SEEKUP * 0 = seek in down direction * * SEEK * 0 = disable / stop seek (i.e. don't seek) */ 0b00000011, /* * SKMODE seek mode: * 0 = wrap at upper or lower band limit and contiue seeking * * CLK_MODE clock mode * 000 = 32.768kHZ clock rate (match the watch cystal on the module) * * RDS_EN radio data system enable * 0 = disable radio data system * * NEW_METHOD use new demodulate method for improved sensitivity * 0 = presumably disabled * * SOFT_RESET * 1 = perform a reset * * ENABLE power up enable: * 1 = enabled */ /* register 0x03 */ /* Don't bother to tune to a channel at this stage*/ 0b00000000, /* * CHAN channel select 8 most significant bits of 10 in total * 0000 0000 = don't boher to program a channel at this time */ 0b00000000, /* * CHAN two least significant bits of 10 in total * 00 = don't bother to program a channel at this time * * DIRECT MODE used only when test * 0 = presumably disabled * * TUNE commence tune operation * 0 = disable (i.e. don't tune to selected channel) * * BAND band select * 00 = select the 87-108MHz band * * SPACE channel spacing * 00 = select spacing of 100kHz between channels */ /* register 0x04 */ 0b00001010, /* * RESERVED 15 * 0 * * PRESUMABLY RESERVED 14 * 0 * * RESERVED 13:12 * 00 * * DE de-emphasis: * 1 = 50us de-emphasis as used in Australia * * RESERVED * 0 * * SOFTMUTE_EN * 1 = soft mute enabled * * AFCD AFC disable * 0 = AFC enabled */ 0b00000000, /* * Bits 7-0 are not specified, so assume all 0's * 0000 0000 */ /* register 0x05 */ 0b10001000, /* * INT_MODE * 1 = interrupt last until read reg 0x0C * * RESERVED 14:12 * 000 * * SEEKTH seek signal to noise ratio threshold * 1000 = suggested default */ 0b00001111, /* * PRESUMABLY RESERVED 7:6 * 00 * * RESERVED 5:4 * 00 * * VOLUME * 1111 = loudest volume */ /* register 0x06 */ 0b00000000, /* * RESERVED 15 * 0 * * OPEN_MODE open reserved registers mode * 00 = suggested default * * Bits 12:8 are not specified, so assume all 0's * 00000 */ 0b00000000, /* * Bits 7:0 are not specified, so assume all 0's * 00000000 */ /* register 0x07 */ 0b01000010, /* * RESERVED 15 * 0 * * TH_SOFRBLEND threshhold for noise soft blend setting * 10000 = using default value * * 65M_50M MODE * 1 = only applies to BAND setting of 0b11, so could probably use 0 here too * * RESERVED 8 * 0 */ 0b00000010, /* * SEEK_TH_OLD seek threshold for old seek mode * 000000 * * SOFTBLEND_EN soft blend enable * 1 = using default value * * FREQ_MODE * 0 = используем значение по умолчанию */ }; /* After reset, we can tune the device * We only need program the first 4 bytes in order to do this */ uint8_t tune_config[] = { /* register 0x02 */ 0b11000000, /* * DHIZ audio output high-z disable * 1 = normal operation * * DMUTE mute disable * 1 = normal operation * * MONO mono select * 0 = mono * * BASS bass boost * 0 = disabled * * RCLK NON-CALIBRATE MODE * 0 = RCLK is always supplied * * RCLK DIRECT INPUT MODE * 0 = ??? not certain what this does * * SEEKUP * 0 = seek in down direction * * SEEK * 0 = disable / stop seek (i.e. don't seek) */ 0b00000001, /* * SKMODE seek mode: * 0 = wrap at upper or lower band limit and contiue seeking * * CLK_MODE clock mode * 000 = 32.768kHZ clock rate (match the watch cystal on the module) * * RDS_EN radio data system enable * 0 = disable radio data system * * NEW_METHOD use new demodulate method for improved sensitivity * 0 = presumably disabled * * SOFT_RESET * 0 = don't reset this time around * * ENABLE power up enable: * 1 = enabled */ /* register 0x03 */ /* Here's where we set the frequency we want to tune to */ (channel >> 2), /* CHAN channel select 8 most significant bits of 10 in total */ ((channel & 0b11) << 6 ) | 0b00010000 /* * CHAN two least significant bits of 10 in total * * DIRECT MODE used only when test * 0 = presumably disabled * * TUNE commence tune operation * 1 = enable (i.e. tune to selected channel) * * BAND band select * 00 = select the 87-108MHz band * * SPACE channel spacing * 00 = select spacing of 100kHz between channels */ }; void setup() { Serial.begin(9600); pinMode(A0,INPUT); Wire.begin(); Wire.beginTransmission(RDA5807M_ADDRESS); Wire.write(boot_config, BOOT_CONFIG_LEN); Wire.endTransmission(); Wire.beginTransmission(RDA5807M_ADDRESS); Wire.write(tune_config, TUNE_CONFIG_LEN); Wire.endTransmission(); }//setup end void loop() { int channel1 =90,newA; static int oldA = 0; // set the oldA as HIGH int result = 0; newA = analogRead(A0); if ((newA - oldA) > 10 || (oldA - newA) > 10){ Serial.println(newA); if(newA!= oldA){ channel = channel1+(newA/10); myChangeChannel(channel); oldA=newA; } } uint16_t frequency = channel+870; uint16_t num1 = (frequency / 1000) % 10; uint16_t num2 = (frequency / 100) % 10; uint16_t num3 = (frequency / 10) % 10; uint16_t num4 = frequency % 10; Serial.print(num1); Serial.print(num2); Serial.print(num3); Serial.print(num4); Serial.print("--"); Serial.println(channel+870); }//конец цикла loop /* * функция для изменения канала в модуле RDA5807 * Example: channel = 191 */ void myChangeChannel(int channel){ /* void if nothing is returned else int */ /* * первым делом записываем новый канал в массив tune_config, потом передаем его значение модулю RDA5807 */ tune_config[2] = (channel >> 2); tune_config[3] = ((channel & 0b11) << 6 ) | 0b00010000; Wire.begin(); Wire.beginTransmission(RDA5807M_ADDRESS); Wire.write(tune_config, TUNE_CONFIG_LEN); Wire.endTransmission(); } |
Приветствую, подскажите, данный модуль после настройки с контроллера и отключении от него, работает автономно на той волне, на которую был настроен и сохраняются ли настройки после перезапуска?
Добрый вечер. После настройки его можно отключить от микроконтроллера и он будет работать автономно, но в его даташите я не нашел никакого упоминания на энергонезависимую память, следовательно, после отключения питания его настройки будут сбрасываться
Понял, спасибо большое!!!
Хорошо, удачи вам в сборке проекта
НЕ ВЕРИФИЦИРУЕТСЯ, В СТРОКЕ СООБЩЕНИЯ:
Arduino: 1.8.19 (Linux), Board: "Arduino Nano, ATmega168"
/home/an/Arduino/rda5807-pot/rda5807-pot.ino:245:13: warning: narrowing conversion of '(channel >> 2)' from 'uint16_t {aka unsigned int}' to 'uint8_t {aka unsigned char}' inside { } [-Wnarrowing]
(channel >> 2),
~~~~~~~~~^~~~~
/home/an/Arduino/rda5807-pot/rda5807-pot.ino:247:29: warning: narrowing conversion of '(((channel & 3) << 6) | 16)' from 'uint16_t {aka unsigned int}' to 'uint8_t {aka unsigned char}' inside { } [-Wnarrowing]
((channel & 0b11) << 6 ) | 0b00010000
~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~
Sketch uses 4420 bytes (30%) of program storage space. Maximum is 14336 bytes.
Global variables use 426 bytes (41%) of dynamic memory, leaving 598 bytes for local variables. Maximum is 1024 bytes.
Это у вас с резистором на 10 кОм? Попробуйте начать с простого, отключите модуль RDA5807 из схемы и из программы удалите все строки, связанные с ним. Посмотрите, заработает или нет программа в таком усеченном варианте
Здравствуйте.
Как изменить программу для применения переменного резистора номиналом 10ком для настройки приемника на нужную частоту ( в моем случае многооборотного) вместо используемого в статье потенциометра на 100ком.
Спасибо.
Добрый день, можно попробовать поизменять значение шума в 282 строке программы, то есть в команде if ((newA - oldA) > 10 || (oldA - newA) > 10) изменять 10 на какое либо другое значение. Но в минимальном варианте все должно и без изменений заработать, мы же с этого потенциометра считываем только уровень напряжения с помощью АЦП на аналоговом контакте Arduino
Добрый день !
А чувствительность приемника - как то регулируется, не разбирались ?
Здравствуйте, ну здесь она полностью зависит от модуля RDA5807. Надо смотреть даташит на него чтобы разобраться в этом
Собрал без шунта (конденсатора) на pin A0. Да, шумы сильные. Надо попробовать добавить конденсатор.
В Вашем коде пропущены строки
#define RDA5807M_ADDRESS 0b0010000 // 0x10
#define BOOT_CONFIG_LEN 12
#define TUNE_CONFIG_LEN 4
кто будет подключать, учтите.
Как, вроде есть эти строки в коде программы - строки с 16 по 18. Но все равно спасибо за конструктивный комментарий
Не переводил в коде программы комментарии, связанные с настройкой регистров модуля RDA5807M, но если кому нужна помощь в этом вопросе, пишите об этом здесь в комментариях, помогу чем смогу