
- Цена: US $0.45
Наткнулся на данную платку RDA5807m.
Характеристики FM-тюнера RDA5807m:
* Все в одном корпусе, практически не требуется внешних компонентов
* КМОП технология
* Полоса частот от 50 МГц до 115 МГц
* Настраиваемый шаг между каналами – 200 кГц, 100 кГц, 50 кГц, 25 кГц
* Поддерживает RDS/RBDS
* Высококачественный АЦП
* Синтезатор частот полностью встроен в микросхему
* Автоматическая регулировка усиления
* Цифровое адаптивное подавление шума
* Поддержка выхода звука как в моно, так и в стерео
* Индикатор уровня сигнала (Receive signal strength indicator — RSSI) и SNR
* Усилитель низких частот
* Регулировка звука и функция mute
* Цифровой интерфейс I2C
* Нагрузка на выходе звукового канала 32 Ом
* Встроенный LDO регулятор
* Корпус MSOP (10 выводов)
Электрические параметры FM тюнера RDA5807m:
* Напряжение питания — 3 вольта (от 1,8 до 3,3 вольт)
* Температура окружающей среды — 27 градусов Цельсия (от -20 до +75 градусов Цельсия)
* Ток потребления в рабочем режиме — до 21 мА
* Ток потребления в спящем режиме – 5 мкА
* Коэффициент нелинейных искажений – 0,15 – 0,2 %
* Максимальная частота I2C – 400 кГц
Для начала нашёл библиотеку для работы с радио, и опробовал на Arduino pro mini
!!! Внимание Arduino надо питать от 3.3В !!!, тк питание радио макс 3.3В.
Радио заработало сразу.
Звук чистый, без искажений на высоких частотах ( как на 174ха34), в наушниках звук громкий, достаточный.
Дальше решено было конструкцию удешевить,
Применить контроллер Attiny13a
Подключил библиотеки для attiny13
В контроллере Attiny13 всего 1024 байт памяти и нет железного протокола i2c.
После недели мучений по эмуляции протокола I2C, радио заработало. Но умело оно только включать радио на одну станцию.
На большее просто не хватало памяти.
И началясь тогда оптимизация кода, битва шла за каждый байт.
* Прееключать радостанции покругу ( из списка в коде)
* Регулировка уровня громкости
* Моно / Стерео
* Усиление Басов вкл /выкл
* Все режимы запоминаются в память.
#include <util/delay.h> #include <avr/io.h> #include <avr/eeprom.h> #include <avr/pgmspace.h> #define F_CPU 4800000UL // Define software reference clock for delay duration #define SDA_release DDRB &= 0xEF #define SDA_low DDRB |= 0x10 #define SCL_release DDRB &= 0xF7 #define SCL_low DDRB |= 0x08 #define FREQ_STEPS 10 #define RADIO_REG_CHIPID 0x00 #define RADIO_REG_CTRL 0x02 #define RADIO_REG_CTRL_OUTPUT 0x8000 #define RADIO_REG_CTRL_UNMUTE 0x4000 #define RADIO_REG_CTRL_MONO 0x2000 #define RADIO_REG_CTRL_BASS 0x1000 #define RADIO_REG_CTRL_SEEKUP 0x0200 #define RADIO_REG_CTRL_SEEK 0x0100 #define RADIO_REG_CTRL_RDS 0x0008 #define RADIO_REG_CTRL_NEW 0x0004 #define RADIO_REG_CTRL_RESET 0x0002 #define RADIO_REG_CTRL_ENABLE 0x0001 #define RADIO_REG_CHAN 0x03 #define RADIO_REG_CHAN_SPACE 0x0003 #define RADIO_REG_CHAN_SPACE_100 0x0000 #define RADIO_REG_CHAN_BAND 0x000C #define RADIO_REG_CHAN_BAND_FM 0x0000 #define RADIO_REG_CHAN_BAND_FMWORLD 0x0008 #define RADIO_REG_CHAN_TUNE 0x0010 #define RADIO_REG_CHAN_NR 0x7FC0 #define RADIO_REG_R4 0x04 #define RADIO_REG_R4_EM50 0x0800 #define RADIO_REG_R4_SOFTMUTE 0x0200 #define RADIO_REG_R4_AFC 0x0100 #define RADIO_REG_VOL 0x05 #define RADIO_REG_VOL_VOL 0x000F #define RADIO_REG_RA 0x0A #define RADIO_REG_RA_RDS 0x8000 #define RADIO_REG_RA_RDSBLOCK 0x0800 #define RADIO_REG_RA_STEREO 0x0400 #define RADIO_REG_RA_NR 0x03FF #define RADIO_REG_RB 0x0B #define RADIO_REG_RB_FMTRUE 0x0100 #define RADIO_REG_RB_FMREADY 0x0080 #define RADIO_REG_RDSA 0x0C #define RADIO_REG_RDSB 0x0D #define RADIO_REG_RDSC 0x0E #define RADIO_REG_RDSD 0x0F // I2C-Address RDA Chip for sequential Access #define I2C_SEQ 0x20 // I2C-Address RDA Chip for Index Access #define I2C_INDX 0x22 #define RADIO_BAND_NONE 0x0 #define RADIO_BAND_FM 0x1 #define RADIO_BAND_FMWORLD 0x2 // ----- implement uint16_t registers[10]={ 0x5804, 0x0000, 0x0001, 0x0000, 0x0800, 0x9089, // последняя цифра громкость 1 - F 0x0000, 0x0000, 0x0000, 0x0000 }; uint8_t fm, vol; bool BTNUP, BTNDN, BTNSK, BASS , MONO ; // Частоты радиостанций в вашем регионе static uint16_t preset[] PROGMEM= { 9080, 10100, 10140, 10180, // hr1 10220, 10290, // Bayern2 10340, // ??? 10390, // * hr3 10430, 10490, 10670, 10720 }; int main( void ) { // всё что до while(1){ выполняется один раз при старте //-----setup-------- DDRB = 0x00; //PORTB = Inputs PORTB = 0x87; //Set Outputs to Low (when DDRB is set to low the pin associated goes Hi-Z) fm=EEPROM_read(0); vol=EEPROM_read(1); BASS=EEPROM_read(2); MONO=EEPROM_read(3); _delay_ms(1000); _saveRegisters(); setVol(); setBassBoost(); setMono(); setFrequency(); while(1){ // вечный цыкл, тоже самое что и void loop(){ //----loop-------- if (PINB & (1<<PINB0)) BTNUP=0; if (PINB & (1<<PINB1)) BTNDN=0; if (PINB & (1<<PINB2)) BTNSK=0; if (!BTNUP & !BTNDN & !BTNSK) { _delay_ms(5); if (!(PINB & (1<<PINB2))) {BTNSK=1; fm ++; if (fm>11) fm=0; // 11 Количество радиостанций в таблице setFrequency(); EEPROM_write(0, fm); } if (!(PINB & (1<<PINB1))) {BTNDN=1; vol --; if (vol<1) vol=1; setVol(); } if (!(PINB & (1<<PINB0))) {BTNUP=1; vol ++; if (vol>15) vol=15; setVol(); } } else { _delay_ms(5); if (!(PINB & (1<<PINB2))) { if (BTNUP) {BASS=!BASS; setBassBoost(); BTNUP=0;BTNSK=1;} if (BTNDN) {MONO=!MONO;setMono(); BTNDN=0;BTNSK=1;} } } } // конец вечного цикла return 0; } void setVol(void) { registers[RADIO_REG_VOL] = (0x9080 | vol); _saveRegister(RADIO_REG_VOL); EEPROM_write(1, vol); } // setBassBoost() void setBassBoost() { if (BASS) registers[RADIO_REG_CTRL] |= RADIO_REG_CTRL_BASS; else registers[RADIO_REG_CTRL] &= (~RADIO_REG_CTRL_BASS); _saveRegister(RADIO_REG_CTRL); EEPROM_write(2, BASS); } // setBassBoost() // Mono / Stereo void setMono(void) { registers[RADIO_REG_CTRL] &= (~RADIO_REG_CTRL_SEEK); if (!MONO) { registers[RADIO_REG_CTRL] |= RADIO_REG_CTRL_MONO; } else { registers[RADIO_REG_CTRL] &= ~RADIO_REG_CTRL_MONO; } _saveRegister(RADIO_REG_CTRL); EEPROM_write(3, MONO); } // setMono void setFrequency(void) { uint16_t newChannel; uint16_t regChannel = registers[RADIO_REG_CHAN] & (RADIO_REG_CHAN_SPACE | RADIO_REG_CHAN_BAND); newChannel = (pgm_read_word_near(preset + fm) - 8700) / 10; regChannel += RADIO_REG_CHAN_TUNE; // enable tuning regChannel |= newChannel << 6; // enable output and unmute registers[RADIO_REG_CTRL] |= RADIO_REG_CTRL_OUTPUT | RADIO_REG_CTRL_UNMUTE | RADIO_REG_CTRL_ENABLE; // | RADIO_REG_CTRL_NEW _saveRegister(RADIO_REG_CTRL); registers[RADIO_REG_CHAN] = regChannel; _saveRegister(RADIO_REG_CHAN); // adjust Volume // _saveRegister(RADIO_REG_VOL); } // setFrequency() // Save one register back to the chip void _saveRegister(byte regNr) { i2c_start(I2C_INDX); i2c_write(regNr); _write16(registers[regNr]); i2c_stop(); } // _saveRegister void _saveRegisters() { i2c_start(I2C_SEQ); for (int i = 2; i <= 6; i++) _write16(registers[i]); i2c_stop(); } // _saveRegisters void _write16(uint16_t val) { i2c_write(val >> 8); i2c_write(val & 0xFF); } // _write16 void i2c_clk(void) { SCL_release; //Release Clock _delay_us(5); SCL_low; //Pull Clock Low } /**************************************************************/ void i2c_write(char data) { int i; for (i=0;i<=7;i++) //Clocks out byte MSB first { if (data & 0x80) {SDA_release;} //Release Data else {SDA_low;}; //Pull Data Low data = data * 2; i2c_clk(); } // _delay_us(5); SDA_release; //Release Data to check for ACK if (PINB & 0x08){ } //slave didn't acknowledge (data held low by slave) else { } //slave did acknowledge (data not held low by slave) i2c_clk(); SDA_low; //Pull Data Low } /**************************************************************/ void i2c_start(char data) { SDA_low; //Pull Data Low SCL_low; //Pull Clock Low i2c_write(data); } /**************************************************************/ void i2c_stop(void) { SCL_release; //Release Clock SDA_release ; //Release Data } void EEPROM_write(unsigned int uiAddress, unsigned char ucData) { while(EECR & (1<<EEWE)); /*Ждать завершения предыдущей записи*/ EEAR = uiAddress; /*Проинициализировать регистры*/ EEDR = ucData; EECR |= (1<<EEMWE); /*Установить флаг EEMWE*/ EECR |= (1<<EEWE); /*Начать запись в EEPROM*/ } unsigned char EEPROM_read(unsigned int uiAddress) { while(EECR & (1<<EEWE)); /*Ждать завершения предыдущей записи*/ EEAR = uiAddress; /* Проинициализировать регистр адреса*/ EECR |= (1<<EERE); /*Выполнить чтение*/ return EEDR; }
Для приёмника была изготовлена плата методом ЛУТ
Конденсаторы на плате 10 мкФ керамические.
Управление
SK- Переключение станций
Vol + — Громкость +
Vol — — Громкость — Удерживаем Vol+, короткое нажатие SK — Усиление Басов
Удерживаем Vol-, короткое нажатие SK — Моно/ Стерео
Контроллеры Attiny13a 10 штук 3.2$ 0.32$ Штука
Стабилизатор AMS1117 10 штук 0.39$ 0.04$ Штука
Готовое радио 0.45 + 0.32 + 0.04 = 0.81$ 50р. ))
Документация, скетч, библиотека attiny13
Советы по оптимизации кода приветствуются))
(c) 2015 Источник материала.