Создаем FM-радио на основе платы Arduino Pro Mini

В этом уроке мы создадим своими руками FM-радио на основе платы Arduino Pro Mini в стиле ар-деко с самого начала.

Введение

Мы собираемся создать FM-радиоприемник в стиле ар-деко. Дизайн этого радио основан на впечатляющем радиоприемнике AWA 1935 года. Можно найти фото этого старого радио в Интернете. Дизайн этого радио очень красивый, так что сделать свой радиоприемник в аналогичном стиле - отличный вызов. Ушел ровно месяц на то, чтобы реализовать такой проект с нуля, но повторить результат теперь каждый сможет буквально за один день.

В уроке используется ЖК-дисплей Nokia 5110 для отображения частоты, которую мы слушаем. Используется поворотный регулятор для изменения частоты и другая ручка для увеличения или уменьшения громкости. На фото выше видно, что на ЖК-дисплее FM-радио Ардуино используется шрифт в стиле ар-деко. Кроме того, если мы прослушиваем одну и ту же радиостанцию ​​более 5 минут, радиостанция автоматически сохранит ее в памяти, поэтому при следующем включении радиостанции она автоматически настроится на частоту, которую мы использовали ранее. Радио также имеет встроенную литиевую батарею и соответствующее зарядное устройство, поэтому оно может работать от батарей в течение нескольких дней.

Качество звука проекта довольно хорошее. Используется небольшой динамик 3 Вт с усилителем малой мощности. Радио звучит хорошо, а выглядит еще лучше. Давайте теперь посмотрим, какие детали нужны для создания этого проекта.

Шаг 1. Собираем все комплектующие

Нам понадобится много деталей, чтобы сделать этот проект. Если вы новичок в Arduino, сначала постарайтесь сделать несколько более простых проектов (посмотрите наши уроки), потому что это продвинутый проект и есть много вещей, которые могут быть непонятны или пойти не так.

Итак, нам понадобятся следующие части:

  • Arduino Pro Mini
  • Программатор FTDI
  • Модуль FM-радио TEA5767 FM 76-108MHZ
  • Динамик 3 Вт
  • Модуль усилителя PAM8403
  • Поворотный регулятор
  • ЖК-дисплей Nokia 5110
  • Аккумуляторная батарея, шилд Wemos
  • Аккумулятор 18650
  • Держатель батареи 18650
  • Переключатель
  • Макетная плата 5x7 CM
  • Провода
  • Сетка

Общая стоимость проекта может получиться в районе $22.

Шаг 2. Электроника

Прежде всего, начнем с электронике, которая является основой нашего радио Ардуино. Сейчас используется Arduino Nano, но позже мы будем использовать Arduino Pro Mini для более низкого энергопотребления. Схема всех наших соединений:

Далее, как и в любом проекте (не только радио) мы собираем все детали вместе и тестируем до того, как поместим всё в корпус.

Если мы включим проект, то увидим, что на дисплее Nokia в течение нескольких секунд отображается заставка, а затем радиостанция загружает из памяти EEPROM предыдущую радиостанцию, которую мы слушали. Мы можем изменить частоту и громкость соответственными ручками. Проект работает нормально. Теперь нужно сделать проект меньше по размеру, чтобы уместить его в корпус. Для этого мы собираемся использовать Arduino Pro Mini. Плата очень маленькая по размеру, а также предлагает более низкое энергопотребление. Мы также собираемся использовать маленькую макетную плату для пайки некоторых компонентов на ней. Но перед этим нужно разработать корпус в Fusion 360 - бесплатное, но чрезвычайно мощное программное обеспечение.

Шаг 3. Проектирование корпуса

Поскольку мы собираемся спроектировать сложный корпус и собираемся использовать множество деталей, мы сначала должны смоделировать каждую деталь в Fusion 360. Таким образом, мы будем уверены, что каждая деталь будет идеально подходить и корпус достаточный, чтобы вместить все внутри. Ушло около недели, чтобы научиться моделировать детали в Fusion 360, а затем смоделировать всё остальное. Еще неделя ушла на разработку корпуса в Fusion 360. Скачать все файлы вы можете ниже:

Результат того стоил. Дизайн выглядит фантастически, а все детали отлично располагаются внутри корпуса. Еще одна интересная особенность, которую предлагает Fusion 360 - это возможность создавать высококачественные рендеры вашего дизайна с использованием различных материалов и видеть, как проект будет выглядеть в реальности.

Шаг 4. Печатаем корпус

Проект состоит из 7 частей. Сначала печатаем мелкие детали. Последняя - большая часть корпуса, оказалась сложной для печати. По какой-то причине сопло забивалось каждый раз, когда предпринимались попытки её распечатать. Пришлось перепробовать множество настроек, меняя скорость, отвод, высоту слоя, температуру. Ничего не получалось. Было заменено сопло на 0,5 мм. Тогда же возник вопрос - можно ли возобновить печать неисправной детали после замены забитого сопла? После поиска в Интернете обнаружилось, что это возможно.

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

Шаг 5. Собираем всё вместе

Следующим шагом была задача сжатия электроники, чтобы она поместилась в корпусе. Поскольку уже были смоделированы все детали в Fusion 360, то была уверенность, что это не сложно реализовать. На фото выше и на схеме на одном из предыдущих шагов видно, что каждая деталь имеет свое специфическое положение в корпусе.

Все комплектующие нашего FM-радио Ардуино спаяны согласно схеме, которая была приложена выше. Сначала паяется Arduino Pro Mini и загружается в неё код, используя программатор FTDI. Следующий шаг - создание источника питания для схемы. Использовался аккумуляторный шилд Wemos, очень удобный, который может заряжать аккумулятор 18650 и повышать его напряжение до 5 В. Снимаем разъем аккумулятора с шилда и припаиваем провода от разъема аккумулятора 18650. Далее припаиваем переключатель к выходу 5V.

Затем паяем все остальные детали одну за другой. Это примерно на пару часов работы. На этот раз не используется аудиокабель на аудиовыходе радиомодуля FM, но вместо этого припаиваются провода внизу платы. Сигнал теперь может идти в усилитель для усиления. Также добавляем конденсатор 330 мкФ к шине питания на макетной плате. Это дополнение уменьшило шум на радиосигнале. После того, как все пайки будут сделаны, можно протестировать проект.

Последний пункт этого шага - собрать всё вместе, части корпуса и части электроники. Сначала приклеиваем решетку радиоприемника, а затем приклеиваем сетку. После клеим дисплей обычным клеем, а динамик горячим клеем. Далее горячим клеем закрепляем держатель батареи, выключатель и зарядное устройство. Затем модуль усилителя, поворотный энкодер и, наконец, макетную плату.

Шаг 6. Код для FM-радио

Теперь давайте перейдем к компьютеру, чтобы взглянуть на программную часть урока. В этом уроке используется много библиотек. Код более сложен, чем в большинстве проектов, которые были созданы ранее. Он сделан максимально простым и легкими для чтения и понимания функциями.

Скопировать или скачать код FM-радио Arduino вы можете ниже:

#include <TEA5767N.h>  //https://github.com/mroger/TEA5767
#include <SPI.h>
#include <Adafruit_GFX.h>  //https://github.com/adafruit/Adafruit-GFX-Library
#include <Adafruit_PCD8544.h> //https://github.com/adafruit/Adafruit-PCD8544-Nokia-5110-LCD-library
#include "GrenadierNF18pt7b.h"
#include "GrenadierNF15pt7b.h"
#include "splash.h"
#include <ClickEncoder.h> //https://github.com/0xPIT/encoder
#include <TimerOne.h>  //https://github.com/PaulStoffregen/TimerOne
#include <EEPROM.h>

Adafruit_PCD8544 display = Adafruit_PCD8544(5, 4, 3);

int SECONDS_TO_AUTOSAVE = 300;
float previous_frequency = 0;
float frequency = 95.0f;

ClickEncoder *encoder;
int16_t last, value;

boolean up = false;
boolean down = false;
boolean middle = false;

long seconds = 0;
long previousMillis = 0; 

bool backlightON = false;

long interval = 1000; 
  
TEA5767N radio = TEA5767N();

void setup() 
{
  pinMode(7, OUTPUT);
  digitalWrite(7,HIGH);
  
  initDisplay();
  
  showSplashScreen();
  
  radio.setMonoReception();
  
  radio.setStereoNoiseCancellingOn();

  initRotaryEncoder();
  
  Serial.begin(9600);

  frequency = readFrequencyFromEEPROM();

  if(isnan(frequency))
  {
    Serial.println("setup(): EEPROM has no stored frequency.");
    frequency = 88.0;
    writeFrequencyToEEPROM(&frequency);
  }
    
  printText(String(frequency,1),String(frequency,1));
}

void loop() {

  unsigned long currentMillis = millis();

  checkRotaryEncoderButton();

  if(currentMillis - previousMillis > interval) 
  {
    if(frequency!=previous_frequency)
    {
      previous_frequency = frequency;
      radio.selectFrequency(frequency);  
      seconds = 0;
    }else
    {
      seconds++;
      if(seconds == SECONDS_TO_AUTOSAVE)
      {
          float read_frequency = readFrequencyFromEEPROM();
          if(read_frequency!=frequency)
          {
            Serial.println("loop(): Saving new frequency to EEPROM");
            writeFrequencyToEEPROM(&frequency);
          }
      }
    }
    previousMillis = currentMillis; 
    Serial.println("loop(): "+String(seconds));  
  }

 readRotaryEncoder();

 if(up)
 {
  up = false;
  previous_frequency = frequency;
  frequency = frequency+0.1f;
  printText(String(frequency,1),String(previous_frequency,1));
 }

 if(down)
 {
  down = false;
  previous_frequency = frequency;
  frequency = frequency-0.1f;
  printText(String(frequency,1),String(previous_frequency,1));
 }
}

void printText(String text, String previous_text)
{
  display.clearDisplay();   // clears the screen and, WHITE buffer  

  if(previous_text.length() == 4)
  {
    display.setFont(&GrenadierNF18pt7b);
  }else
  {
    display.setFont(&GrenadierNF15pt7b);
  }
  display.setTextColor(WHITE);
  display.setCursor(0,37);
  display.println(previous_text);
  display.display();
  
  if(text.length() == 4)
  {
    display.setFont(&GrenadierNF18pt7b);
  }else
  {
    display.setFont(&GrenadierNF15pt7b);
  }
  display.setTextColor(BLACK);
  display.setCursor(0,37);
  display.println(text);
  display.display();
}

void initRotaryEncoder()
{
  encoder = new ClickEncoder(A1, A0, A2);
  encoder->setAccelerationEnabled(false);
   
  Timer1.initialize(1000);
  Timer1.attachInterrupt(timerIsr); 

  last = encoder->getValue();  
}

void initDisplay()
{
  display.begin();
  display.setContrast(60);
  display.clearDisplay();   // clears the screen and, WHITE buffer  
  display.display();
}

 void timerIsr() 
{
  encoder->service();
}

void showSplashScreen()
{
  display.clearDisplay();
  display.drawBitmap(0, 0,  SPLASH, 84, 48, 1);
  display.display();
  delay(3000);
  display.clearDisplay();   // clears the screen and, WHITE buffer  
}

void writeFrequencyToEEPROM(float *freq)
{
 byte ByteArray[4];
 memcpy(ByteArray, freq, 4);
 for(int x = 0; x < 4; x++)
 {
   EEPROM.write(x, ByteArray[x]);
 }  
 Serial.println("writeFrequencyFromEEPROM(): "+String(frequency));
}

float readFrequencyFromEEPROM()
{
  float frequency = 86.0;
  byte ByteArray[4];
  for(int x = 0; x < 4; x++)
  {
   ByteArray[x] = EEPROM.read(x);    
  }
  memcpy(&frequency, ByteArray, 4);
  Serial.println("readFrequencyFromEEPROM(): "+String(frequency));
  return frequency;
}

void checkRotaryEncoderButton()
{
    ClickEncoder::Button b = encoder->getButton();
  if (b != ClickEncoder::Open) {
    if(b==ClickEncoder::Clicked)
    {
      Serial.println("Toggle BackLight");
      if(backlightON == false)
      {
        backlightON = true;
        turnOnBacklight();
      }else
      {
        backlightON = false;
        turnOffBacklight();
      }
    }
  }
}

void turnOnBacklight()
{
  digitalWrite(7,LOW);
}

void turnOffBacklight()
{
  digitalWrite(7,HIGH);
}

void readRotaryEncoder()
{
  value += encoder->getValue();
  
  if (value/2 > last) {
    last = value/2;
    up = true;
    delay(50);
  }else   if (value/2 < last) {
    last = value/2;
    down = true;
    delay(50);
  }
}

Основная идея такова: если вал поворотного энкодера изменил положение и оставался в одном и том же положении более 1 секунды, нам нужно установить эту частоту для модуля FM-радио.

if(currentMillis - previousMillis > interval) 
  {
    if(frequency!=previous_frequency)
    {
      previous_frequency = frequency;
      radio.selectFrequency(frequency);  
      seconds = 0;
    }else

Радиомодулю FM требуется около 1 секунды, чтобы настроиться на новую частоту. Мы не можем изменять частоту при каждом изменении поворотного энкодера, потому что таким образом изменение частоты будет очень медленным. Когда новая частота установлена на модуле, мы подсчитываем, сколько секунд прошло с момента установки частоты. Если время превышает 5-минутную отметку, мы сохраняем эту частоту в памяти EEPROM.

else
    {
      seconds++;
      if(seconds == SECONDS_TO_AUTOSAVE)
      {
          float read_frequency = readFrequencyFromEEPROM();
          if(read_frequency!=frequency)
          {
            Serial.println("loop(): Saving new frequency to EEPROM");
            writeFrequencyToEEPROM(&frequency);
          }
      }
    }

Итоговый результат

Нам очень повезло, что мы живем в эпоху, когда мы сами можем сделать все, что захотим. У нас есть инструменты и ресурсы для создания всего, что мы хотим, в течение нескольких недель и при низких затратах. Конечный результат стоит времени и усилий, которые вы вложили в него. Вы потратите много часов на этот проект, но узнаете много нового, получите драгоценный опыт и наработаете навыки и уверенность для создания еще более классных проектов.

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

28.01.2019 | Уроки | Теги статьи
Ардуино+