[099] Budujemy arduinowe radio cz. 3

[099] Budujemy arduinowe radio cz. 3

Skoro nasze radio działa jak należy, czas na obiecany programator. W tym celu pozmieniamy znaczenie trzech z pięciu przycisków znajdujących się na płytce edukacyjnej TME: skanowanie zostawiamy, natomiast przyciski w górę i w dół będą zmieniać jeden z dziewięciu programów. Środkowy przycisk natomiast będzie zapisywał w aktualnym programie stację, którą właśnie słychać, czyli wybraną przyciskami skanowania. Brakło możliwości przełączania się w mono, ale każdy kto chce, może sobie dołożyć szósty przycisk i pozostawić procedurę, która dotąd tkwiła w poprzednich szkicach.


#include <radio.h      // Biblioteka obsługi serii tunerów FM
#include <EEPROM.h     // Biblioteka obsługi pamięci nieulotnej.
#include <RDA5807FP.h  // Biblioteka obsługi konkretnej wersji tunera.
// #include <RDA5807M.h>
// #include <SI4705.h>
// #include <SI47xx.h>
// #include <TEA5767.h>

RDA5807FP radio;  // Nadaj układowi nazwę "radio"
// RDA5807M radio;
// SI4705   radio;
// SI47xx radio;
// TEA5767  radio;

const byte poprzednia = 4;     // Pstryczek "Poprzednia stacja"
const byte nastepna = 7;       // Pstryczek "Następna stacja"
const byte programMinus = 5;   // Pstryczek "Zmniejsz numer programu"
const byte programPlus = 6;    // Pstryczek "Zwiększ numer programu"
const byte programZapisz = 8;  // Pstryczek "Zapisz program"

const byte potencjometr = A1;  // Potencjometr głośności.
int napiecieStare = 0;         // Poprzednie zmierzone napięcie ustawione potencjometrem.
int napiecieNowe = 1023;       // Aktualne zmierzone napięcie ustawione potencjometrem.

byte program = 1;   // numer aktualnego programu (1-9)
int czestotliwosc;  // aktualna częstotliwość stacji.

void setup() {
  radio.initWire(Wire);                                // Inicjuj tuner.
  radio.setup(RADIO_FMSPACING, RADIO_FMSPACING_100);   // Ustaw krok strojenia równy 100 kHz.
  radio.setup(RADIO_DEEMPHASIS, RADIO_DEEMPHASIS_50);  // Ustaw deemfazę obowiązującą w Europie.
  radio.setBandFrequency(RADIO_BAND_FM, 9800);         // Ustaw częstotliwość początkową na środek zakresu.
  radio.setMono(false);                                // Ustaw tryb stereo.

  pinMode(poprzednia, INPUT_PULLUP);  // Deklaruj linie pstryczków jako wejścia podciągnięte wewnętrznie do wysokiego stanu.
  pinMode(nastepna, INPUT_PULLUP);
  pinMode(programMinus, INPUT_PULLUP);
  pinMode(programPlus, INPUT_PULLUP);
  pinMode(programZapisz, INPUT_PULLUP);

  zmienProgram();  // Pobierz częstotliwość pierwszego programu z pamięci EEPROM i wyślij ją do tunera.
}

void loop() {

  if (digitalRead(poprzednia) == HIGH) {        // Jeśli wciśnięto przycisk "Poprzednia stacja"...
    radio.seekDown(1);                          // Przestrój się w górę do najbliższej stacji (zero skacze 100 kHz do góry).
    while (digitalRead(poprzednia) == HIGH) {}  // Czekaj aż przycisk zostanie puszczony.
  }

  if (digitalRead(nastepna) == HIGH) {        // Jeśli wciśnięto przycisk "Następna stacja"...
    radio.seekUp(1);                          // Przestrój się w dół do najbliższej stacji (zero skacze 100 kHz w dół).
    while (digitalRead(nastepna) == HIGH) {}  // Czekaj aż przycisk zostanie puszczony.
  }

  if (digitalRead(programMinus) == HIGH) {  // Jeśli wciśnięto przycisk "Zmniejsz numer programu"...
    --program;                              // Zmniejsz numer programu.
    if (program < 1) {                      // Jeśli numer programu jest mniejszy od 1...
      program = 9;                          // Numer programu będzie równy 9
    }
    zmienProgram();                               // Reszta procedury.
    while (digitalRead(programMinus) == HIGH) {}  // Czekaj aż przycisk zostanie puszczony.
  }

  if (digitalRead(programPlus) == HIGH) {  // Jeśli wciśnięto przycisk "Zwiększ numer programu"...
    ++program;                             // Zwiększ numer programu.
    if (program > 9) {                     // Jeśli numer programu jest większy od 9...
      program = 1;                         // Numer programu będzie równy 1
    }
    zmienProgram();                              // Reszta procedury.
    while (digitalRead(programPlus) == HIGH) {}  // Czekaj aż przycisk zostanie puszczony.
  }

  if (digitalRead(programZapisz) == HIGH) {         // Jeśli wciśnięto przycisk "programZapisz"...
    EEPROM.put(program * 2, radio.getFrequency());  // Zapisz w pamięci EEPROM aktualną częstotliwość.
    delay(100);                                     // Po rozkazie zapisu warto na chwilę zatrzymać się.
    while (digitalRead(programZapisz) == HIGH) {}   // Czekaj aż przycisk zostanie puszczony.
  }

  napiecieNowe = analogRead(potencjometr);                 // Mierzymy napięcie ustawione ślizgaczem potencjometru.
  if (abs(napiecieNowe - napiecieStare) > 3) {             // Odejmujemy tę wartość od wartości zmierzonej poprzednio i jeśli wartość bezwzględna wyniku jest większa od 3, to...
    napiecieStare = napiecieNowe;                          // Przepisujemy wartość zmierzonego napięcia do zmiennej napiecieStare.
    if (napiecieNowe < 4) {                                // Jeśli napięcie jest mniejsze od 4...
      radio.setMute(1);                                    // Wycisz radio.
    } else {                                               // W przeciwnym razie...
      radio.setMute(0);                                    // Wyłącz wyciszenie oraz...
      radio.setVolume(map(napiecieNowe, 4, 1020, 0, 15));  // Wyślij wartość napięcia do rejestru głośności, po przemapowaniu do zakresu (0-15)
    }
  }
}
void zmienProgram() {
  EEPROM.get(program * 2, czestotliwosc);                // Pobierz z pamięci EEPROM częstotliwość aktualnego kanału.
  radio.setBandFrequency(RADIO_BAND_FM, czestotliwosc);  // Wyślij tę częstotliwość do tunera.
}

Dokładamy także dwie nowe zmienne: program - numer aktualnego programu. Jak pisałem, będzie ich dziewięć oraz czestotliwosc - wartość częstotliwości odbieranej aktualnie stacji, którą będziemy zapisywać i odczytywać z pamięci. A skoro o pamięci mowa, by nią żonglować, potrzebna jest biblioteka o nazwie EEPROM. Nie trzeba jej ściągać, bo jest już w zestawie.

Zmienią nam się te trzy bloki, które dotąd służyły zmianom głośności za pomocą klawiatury i wejścia w tryb mono. Bloki związane ze zmianą programów zwiększają lub zmniejszają jego wartość, pilnując, by po przekroczeniu dziewiątki program przeskakiwał na pierwszy i odwrotnie – poniżej pierwszego pojawiała się dziewiątka. Reszta działań jest wspólna, więc wydzieliłem ją do podprogramu. Ale zaczekajmy chwilę i przypatrzmy się blokowi piątemu, w którym zapisujemy częstotliwość do pamięci EEPROM:

if (digitalRead(programZapisz) == HIGH) {         // Jeśli wciśnięto przycisk "programZapisz"...
  EEPROM.put(program * 2, radio.getFrequency());  // Zapisz w pamięci EEPROM aktualną częstotliwość.
  delay(100);                                     // Po rozkazie zapisu warto na chwilę zatrzymać się.
  while (digitalRead(programZapisz) == HIGH) {}   // Czekaj aż przycisk zostanie puszczony.
}

Rozkazy związane z tą pamięcią, a więc z biblioteką ją obsługującą, umożliwiają zapisywanie i odczytywanie pojedynczych bajtów, wyrażeń i tablic pod wybranym adresem. W tym wypadku użyjemy rozkazu put, który odkłada w pamięci wartość w sposób inteligentny, dopasowując zużycie bajtów do niezbędnego minimum. Zatem tutaj będą to dwa bajty, ponieważ częstotliwość aktualnie grającej stacji, pozyskana znowu tym rozkazem, to liczba z zakresu od 8750 do 10800, a więc typu int. A skoro int zajmuje dwa bajty, adresować musimy co dwa – stąd tu znak mnożenia i dwójka. Innymi słowy, rozkazy z serii EEPROM zawierają dwa argumenty: pierwszy to adres tej pamięci, drugi – wartość do zapisania bądź odczytania.

Po naciśnięciu przycisku programZapisz aktualna częstotliwość zostanie odczytana i przesłana do pamięci EEPROM pod adres równy dwukrotnej wartości programu.

void zmienProgram() {
  EEPROM.get(program * 2, czestotliwosc);                // Pobierz z pamięci EEPROM częstotliwość aktualnego kanału.
  radio.setBandFrequency(RADIO_BAND_FM, czestotliwosc);  // Wyślj tę częstotliwość do tunera.
}

Wróćmy do porzuconego podprogramu. Gdy zmienialiśmy programy, lądowaliśmy tutaj. Mamy tu instrukcję działającą dokładnie odwrotnie do tej, o której pisałem przed chwilą. Pobieramy dane spod adresu będącego podwojonym numerem programu rozkazem get, ładujemy je do zmiennej czestotliwosc, po czym wysyłamy do tunera rozkazem setBandFrequency, którego dotąd nie mieliśmy okazji używać. Od tej pory mamy radio z programatorem i nie musimy już klikać na chybił trafił w przyciski wyszukiwania następnej stacji. Tylko że nadal trochę nie wiadomo która stacja akurat została wybrana. Przydałby się jednak jakiś wyświetlacz.

Tym razem nie będę wymyślał nic nowego, a sięgnę do starszego już artykułu, w którym omawiałem magistralę I2C oraz ekspandery. Tam bawiliśmy się wyświetlaczem siedmiosegmentowym podłączonym przez taki ekspander, więc znowu odsyłam do źródeł, tutaj jedynie wspominając pokrótce o nowych elementach.

#include <radio.h>      // Biblioteka obsługi serii tunerów FM
#include <EEPROM.h>     // Biblioteka obsługi pamięci nieulotnej.
#include <RDA5807FP.h>  // Biblioteka obsługi konkretnej wersji tunera.
// #include <RDA5807M.h>
// #include <SI4705.h>
// #include <SI47xx.h>
// #include <TEA5767.h>

RDA5807FP radio;  // Nadaj układowi nazwę "radio"
// RDA5807M radio;
// SI4705   radio;
// SI47xx radio;
// TEA5767  radio;

#include <Adafruit_MCP23008.h>  // Biblioteka sterującą układem MCP23008
Adafruit_MCP23008 ekspander;    // Nadaj układowi nazwę "ekspander"

const byte poprzednia = 4;     // Pstryczek "Poprzednia stacja"
const byte nastepna = 7;       // Pstryczek "Następna stacja"
const byte programMinus = 5;   // Pstryczek "Zmniejsz numer programu"
const byte programPlus = 6;    // Pstryczek "Zwiększ numer programu"
const byte programZapisz = 8;  // Pstryczek "Zapisz program"

const byte potencjometr = A1;  // Potencjometr głośności.
int napiecieStare = 0;         // Poprzednie zmierzone napięcie ustawione potencjometrem.
int napiecieNowe = 1023;       // Aktualne zmierzone napięcie ustawione potencjometrem.

byte program = 1;   // numer aktualnego programu (1-9)
int czestotliwosc;  // aktualna częstotliwość stacji.

const byte tablica[9] = {
  // Tablica zawierająca wzorce znaków wyświetlacza siedmiosegmentowego.
  B00000110,  // 1, połączenia: P-G-F-E-D-C-B-A
  B01011011,  // 2
  B01001111,  // 3
  B01100110,  // 4
  B01101101,  // 5
  B01111101,  // 6
  B00000111,  // 7
  B01111111,  // 8
  B01101111,  // 9
};

void setup() {
  radio.initWire(Wire);                                // Inicjuj tuner.
  radio.setup(RADIO_FMSPACING, RADIO_FMSPACING_100);   // Ustaw krok strojenia równy 100 kHz.
  radio.setup(RADIO_DEEMPHASIS, RADIO_DEEMPHASIS_50);  // Ustaw deemfazę obowiązującą w Europie.
  radio.setBandFrequency(RADIO_BAND_FM, 9800);         // Ustaw częstotliwość początkową na środek zakresu.
  radio.setMono(false);                                // Ustaw tryb stereo.

  pinMode(poprzednia, INPUT_PULLUP);  // Deklaruj linie pstryczków jako wejścia podciągnięte wewnętrznie do wysokiego stanu.
  pinMode(nastepna, INPUT_PULLUP);
  pinMode(programMinus, INPUT_PULLUP);
  pinMode(programPlus, INPUT_PULLUP);
  pinMode(programZapisz, INPUT_PULLUP);

  ekspander.begin(36);            // Inicjuj bibliotekę sterującą układem MCP23008 pod adresem 0x4
  for (byte x = 0; x < 8; x++) {  // Zadeklaruj wszystkie porty jako wyjścia.
    ekspander.pinMode(x, OUTPUT);
  }
  zmienProgram();  // Pobierz częstotliwość pierwszego programu z pamięci EEPROM i wyślij ją do tunera.
}

void loop() {

  if (digitalRead(poprzednia) == HIGH) {        // Jeśli wciśnięto przycisk "Poprzednia stacja"...
    radio.seekDown(1);                          // Przestrój się w górę do najbliższej stacji (zero skacze 100 kHz do góry).
    while (digitalRead(poprzednia) == HIGH) {}  // Czekaj aż przycisk zostanie puszczony.
  }

  if (digitalRead(nastepna) == HIGH) {        // Jeśli wciśnięto przycisk "Następna stacja"...
    radio.seekUp(1);                          // Przestrój się w dół do najbliższej stacji (zero skacze 100 kHz w dół).
    while (digitalRead(nastepna) == HIGH) {}  // Czekaj aż przycisk zostanie puszczony.
  }

  if (digitalRead(programMinus) == HIGH) {  // Jeśli wciśnięto przycisk "Zmniejsz numer programu"...
    --program;                              // Zmniejsz numer programu.
    if (program < 1) {                      // Jeśli numer programu jest mniejszy od 1...
      program = 9;                          // Numer programu będzie równy 9
    }
    zmienProgram();                               // Reszta procedury.
    while (digitalRead(programMinus) == HIGH) {}  // Czekaj aż przycisk zostanie puszczony.
  }

  if (digitalRead(programPlus) == HIGH) {  // Jeśli wciśnięto przycisk "Zwiększ numer programu"...
    ++program;                             // Zwiększ numer programu.
    if (program > 9) {                     // Jeśli numer programu jest większy od 9...
      program = 1;                         // Numer programu będzie równy 1
    }
    zmienProgram();                              // Reszta procedury.
    while (digitalRead(programPlus) == HIGH) {}  // Czekaj aż przycisk zostanie puszczony.
  }

  if (digitalRead(programZapisz) == HIGH) {         // Jeśli wciśnięto przycisk "programZapisz"...
    EEPROM.put(program * 2, radio.getFrequency());  // Zapisz w pamięci EEPROM aktualną częstotliwość.
    delay(100);                                     // Po rozkazie zapisu warto na chwilę zatrzymać się.
    while (digitalRead(programZapisz) == HIGH) {}   // Czekaj aż przycisk zostanie puszczony.
  }

  napiecieNowe = analogRead(potencjometr);                 // Mierzymy napięcie ustawione ślizgaczem potencjometru.
  if (abs(napiecieNowe - napiecieStare) > 3) {             // Odejmujemy tę wartość od wartości zmierzonej poprzednio i jeśli wartość bezwzględna wyniku jest większa od 3, to...
    napiecieStare = napiecieNowe;                          // Przepisujemy wartość zmierzonego napięcia do zmiennej napiecieStare.
    if (napiecieNowe < 4) {                                // Jeśli napięcie jest mniejsze od 4...
      radio.setMute(1);                                    // Wycisz radio.
    } else {                                               // W przeciwnym razie...
      radio.setMute(0);                                    // Wyłącz wyciszenie oraz...
      radio.setVolume(map(napiecieNowe, 4, 1020, 0, 15));  // Wyślij wartość napięcia do rejestru głośności, po przemapowaniu do zakresu (0-15)
    }
  }
}
void zmienProgram() {
  EEPROM.get(program * 2, czestotliwosc);                         // Pobierz z pamięci EEPROM częstotliwość aktualnego kanału.
  radio.setBandFrequency(RADIO_BAND_FM, czestotliwosc);           // Wyślij tę częstotliwość do tunera.
  for (byte x = 0; x < 8; x++)                                    // Ustawiaj każdy bit - segment wyświetlacza - według wzorców z tablicy.
    ekspander.digitalWrite(x, bitRead(tablica[program - 1], x));  // Wyślij dane na wyświetlacz.
}

Po pierwsze wykorzystamy teraz jeszcze bibliotekę ekspandera Adafruit_MCP23008.h która współpracuje z wymienionym w opisie układem.

Następnie zadeklarujemy tablicę grafik odpowiadających kolejnym cyfrom od jednego do dziewięciu. Wzorce te ustaliłem jeszcze we wspomnianym artykule, więc nie będę tu niczego zmieniał.

Kolejno inicjujemy układ ekspandera i definiujemy wyjścia. Zauważmy, że zarówno tuner jak i ekspander korzystają ze wspólnej magistrali, ale nie wchodzą sobie w drogę.

Samo już wyświetlanie aktualnego programu będziemy przeprowadzać w podprogramie związanym z jego zmianą. Dopisujemy na końcu procedurę sczytywania wszystkich bitów z tablicy, spod indeksu wyznaczonego aktualnym programem i wysyłania ich do ekspandera, a więc na wyświetlacz. Teraz nasze radio jest już w pełni użyteczne, choć oczywiście nadal można by tu jeszcze wiele rzeczy ulepszyć i zrobimy to za jakiś czas.

Powiązane tematy

Płytka edukacyjna TME-EDU-ARD-2Płytka edukacyjna TME-EDU-ARD-2Sprawdź tutaj

Przeczytaj również

Nasi partnerzy

TMETech Master EventTME EducationPoweredby
Copyright © 2025 arduino.pl