Как стать автором
Обновить

Радиоприемник на RDA5807, Arduino Nano и … DeepSeek

Уровень сложностиПростой
Время на прочтение6 мин
Количество просмотров3.1K

Практически все функциональные возможности микросхемы RDA5807M реализованы в примерах ардуиновских библиотек Radio от Matthias Hertel и PU2CLR_RDA5807 от Ricardo Lima Caratti. Обе ищутся и устанавливаются в IDE.

Меня интересовала в основном реализация RDS, но не устраивало большое количество кнопок управления (не менее 4-х), так как в основном я ориентировался на управление энкодером. Просмотрев все примеры, я обратился к поиску радиоприемников, ориентируясь только на те модули, которые были у меня: модуль RDA5807M c кварцем, OLED SSD1306 128х64 синий с желтой верхней полосой, энкодер TZT и Arduino Nano (далее МК). Варианты с дополнительными кнопками, как в примерах библиотек, не рассматривались. В результате я остановился на двух вариантах. Первый.

Схемы подключения модулей приемника и дисплея стандартные — это шина I2C, организованная на выводах А4 и А5 МК; D2, D3, D4 для энкодера. Для написания кода я использовал в основном DeepSeek (далее просто чат-бот). Grok и YandexGPT применялясь от случая к случаю, об этом ниже. Выбор был основан в основном на доступности без бальных танцев из-за блокировок. Правда, совсем без танцев не обошлось, а решилось совсем просто. Ну, вы поняли, о чем речь.

Описал первое задание и боты взялись за дело. Конечно, с первого раза ничего путного не получилось и со второго тоже. Дело пошло лучше, когда я стал использовать диалоги, подбрасывая в диалог сообщения об ошибках компиляции. В результате получил более-менее работающий код, но с одним недостатком. На дисплей не выводилась кириллица. Чат-боты печатают очередную итерацию, но становится только хуже. В какой-то момент Arduino IDE написала мне, что для шрифтов не хватает памяти МК. Тут я понял, что надо остановиться — дело зашло в тупик.

На примете у меня давно была конструкция приемника О.В. Полякова и тут я отвел душу. Заработало что называется «из коробки». После консультаций с автором в чате, внес всего изменения — свою предустановленную частоту и задержку в 2 секунды на инициализацию RDA5807M. Последнее скорее вызвано тем, что у меня все компоненты и в первую очередь МК так называемые noname.

И вот тут я столкнулся лицом к лицу c RDS в том виде, как его понимают местные вещатели. То есть с его отсутствием. На паре радиостанций эта система работает, передает свое название и номер телефона для рекламы. И все. В общем ожидания не оправдались. Переходим ко второму варианту.

Постоянно я слушаю две радиостанции, еще пару от случая к случаю. Следовательно дисплей мне не нужен вообще. Немного подумав, я решил, что будет достаточно одного СИД и одной кнопки. При включении приемника он устанавливается на первую частоту; СИД мигает один раз в две секунды. Нажимаем кнопку, приемник переключается на вторую частоту, СИД мигает два раза с интервалом 2 секунды. И так далее.

Я описал это все на русском языке и отправил чат-боту. Получил что-такое неработающее даже после третьей итерации, а к пятой дело пошло к бреду. Тогда переформулировал задание, что далось с некоторым трудом — утратились навыки такой технической писанины. А для чистоты эксперимента сделал автоматический перевод на английский.

Новый чат и … я получаю работающий код с первого раза! Замечаю только одну ошибку: СИД работает с инверсией — вместо вспышек гаснет заданное число раз с заданным интервалом. Меняю подключение и все. Вот такой код получился.

Скрытый текст
/*
 * Arduino Nano Radio Controller for RDA5807M
 * 
 * Libraries:
 * - RDA5807M (https://github.com/mathertel/Radio) v3.0.1
 * - Wire (built-in) for I2C communication
 * 
 * Connections:
 * - RDA5807M:
 *   SDA -> A4
 *   SCL -> A5
 *   VCC -> 3.3V
 *   GND -> GND
 * - Button:
 *   One side -> D2 and D2 with resistor 10k to +3.3V 
 *   Other side -> GND
 * - LED:
 *   Anode -> D4
 *   Cathode -> GND (with appropriate current-limiting resistor)
 */

#include <Arduino.h>
#include <Wire.h>
#include <radio.h>
#include <RDA5807M.h>

// Pin definitions
#define BUTTON_PIN 2
#define LED_PIN 4

// Radio frequencies (in MHz)
const float PRESET_FREQS[] = {100.6, 104.6, 102.1, 107.2};
const int PRESET_COUNT = sizeof(PRESET_FREQS) / sizeof(PRESET_FREQS[0]);

// Radio settings
#define VOLUME_LEVEL 10
#define BASS_BOOST false

// LED patterns
const unsigned long LED_INTERVAL = 2000; // 2 second
const unsigned long LED_DURATION = 200;  // 200 ms on/off

// Variables
RDA5807M radio;
int currentPreset = 0;
unsigned long lastButtonPress = 0;
unsigned long lastLedUpdate = 0;
int ledState = LOW;
int blinkCount = 0;
int blinkStep = 0;

void setup() {
  // Initialize serial for debugging
  Serial.begin(9600);
  while (!Serial);

  // Initialize pins
  pinMode(BUTTON_PIN, INPUT_PULLUP);
  pinMode(LED_PIN, OUTPUT);
  digitalWrite(LED_PIN, HIGH);

  // Delay for receiver initialization
  delay(1000);

  // Initialize radio
  Wire.begin();
  if (!radio.initWire(Wire)) {
    Serial.println("Radio init failed!");
    while (1);
  }

  // Set radio parameters
  radio.setVolume(10);
  radio.setBassBoost(BASS_BOOST);
  radio.setMono(false);
  radio.setMute(false);

  // Set initial frequency
  radio.setFrequency(PRESET_FREQS[currentPreset] * 100);
  Serial.print("Tuned to: ");
  Serial.print(PRESET_FREQS[currentPreset]);
  Serial.println(" MHz");
}

void loop() {
  // Handle button press for frequency change
  if (digitalRead(BUTTON_PIN) == LOW&& millis() - lastButtonPress > 400) {
    lastButtonPress = millis();
    
    currentPreset = (currentPreset + 1) % PRESET_COUNT;
    radio.setFrequency(PRESET_FREQS[currentPreset] * 100);
    
    Serial.print("Tuned to: ");
    Serial.print(PRESET_FREQS[currentPreset]);
    Serial.println(" MHz");
    
    // Reset LED timing
    lastLedUpdate = millis();
    blinkStep = 0;
  }

  // Handle LED blinking pattern based on current preset
  unsigned long currentTime = millis();
  
  if (currentTime - lastLedUpdate >= LED_INTERVAL) {
    lastLedUpdate = currentTime;
    blinkStep = 0;
    blinkCount = currentPreset + 2; // Number of blinks (1 for first freq, 2 for second, etc.)
  }

  if (blinkStep < blinkCount * 2) {
    if (blinkStep % 2 == 0) {
      // LED on
      if (ledState == LOW) {
        ledState = HIGH;
        digitalWrite(LED_PIN, ledState);
      }
    } else {
      // LED off
      if (ledState == HIGH) {
        ledState = LOW;
        digitalWrite(LED_PIN, ledState);
      }
    }
    
    if (currentTime - lastLedUpdate >= (blinkStep * LED_DURATION)) {
      blinkStep++;
    }
  } else {
    // Keep LED off between patterns
    if (ledState == HIGH) {
      ledState = LOW;
      digitalWrite(LED_PIN, ledState);
    }
  }
}

Немного изменил комментарии и все. Дальше были опыты с другими чат-ботами. Я давал им задание на написание кода, меняя только язык. Grok справился с заданием, но допустил ошибки с версией библиотеки Radio и параметрами инициализации приемника, а с YandexGPT ничего путного не получилось ни в английском варианте задания, ни в русском.

Примерно через пару недель я дал чат-боту точно такое же задание, как в случае, когда он выдал мне рабочий код. Каково же было мое удивление, когда я получил совершенно другой код; совпали только комментарии в шапке. Сравнил два кода в NotePad++ и вот что получилось.

Как видите различия большие. При компиляции выдавалась одна ошибка. Я исправил ее вручную и попробовал загрузить. Скомпилировалось, загрузилось и ничего не работало.

Общее впечатление от общения с чат-ботами у меня сложилось такое. Задание для простых задач боты выполняют с первого раза. Для более сложных задач нужно очень тщательно писать задание и желательно на английском языке. Надеюсь, когда-нибудь боты станут настолько умными, что в ответ будут писать словами персонажа известного фильма: - Ну барин, ты задачи ставишь! Тут гомо сапиенс нужен!

Технические проблемы

Модуль приемника можно питать как от стороннего источника +3 … 3,3 В, так и от вывода МК. В последнем случае надо ставить конденсатор 22 … 100 мкФ, так как это напряжение идет от микросхемы CH340.

В качестве антенны у меня был кусочек провода 10 см длиной. Прием был отличный. Как только я подключил конструкцию к аккумулятору, прием резко ухудшился. Касаюсь рукой корпуса разъема USB на МК — прием резко улучшается. В даташите RDA5807M на антенном входе стоит паралельный контур на 102 МГц, а на звуковых выходах FM-фильтры.

Это для того, чтобы в качестве антенны работал общий провод кабеля наушников. Я их не использую, а хороший прием получился с обычной антенной.

Пока занимался общением с чат-ботами, я не особо обращал внимание на качество звука; играет без шипения и ладно. В процессе изучения опыта применения RDA5807M мне часто попадались комментарии типа «не работает», «сгорела через пару часов» и т. д. В какой-то момент я обратил внимание, что звук в одном канале заметно тише. Включил осциллограф и обнаружил вот такую картину.

Выходное напряжение одного из каналов ограничено снизу. При этом уровни смещения в обеих каналах были одинаковыми примерно 0,9 В. Так бывает, если в двухтактном выходном каскаде нижний транзистор не работает. Тогда между выходом этого канала и общим проводом был включен резистор 2,7 кОм. Уровень смещения уменьшился примерно на 100 мВ, а форма сигнала полностью восстановилась.

Конечно, наушники такой выход не потянет, но с внешним усилителем работает.

Заключение

Микросхема RDA5807M привлекательна тем, что имеет низкую цену и имеет множество конструкций с большим разнообразием индикаторов и органов управления. Среди недостатков многие отмечают низкую надежность, слабую документацию и нестандартный конструктив под названием RRD-102 Ver 2.0. Хороший обзор проблем и возможностей этой микросхемы приведен на сайте радиолюбителя OE3HBW.

Если этот текст читают студенты изучающие курс «Радиоприемные устройства», напишите в комментариях, по каким российским учебникам сейчас изучается эта наука и какие микросхемы используются при выполнении лабораторных работ. Очень интересно почитать современные учебные материалы.

Спасибо всем, кто дочитал до конца.

Теги:
Хабы:
+6
Комментарии4

Публикации

Ближайшие события