Библиотека Radio (управление RDA5807M)? помогите разобраться
- Войдите на сайт для отправки комментариев
Попытался "вырезать" из библиотеки "radio" функции непосредственно только для RDA5807M, т.к. если использовать всю библиотеку, слишком много памяти уходит. Но возник вопрос, ну или проблема: функция из библиотеки (getFrequency) не верно считывает частоту.
При старте устанавливаю частоту 97.6МГц, и после ее считываю (108 строка, вызов функции вывода частоты), считывается как 118.9МГц. Потом начинает рандомно частоту устанавливать, печать в порт для отладки вставил. Если из этой функции убрать считывание текущей частоты, то все работает как нужно (ее тоже для отладки в код вставил).
Дальше, если пользоваться ручной настройкой или предустановкой частот, то все нормально. Если же использовать автопоиск, то начинаются глюки: частота не понятно какая отбражается и при нажатии кнопок громкости начинает перестраиваться частота на 0,1МГц вместе с изменентем громкости.
Вот скетч и сам файл библиотеки:
//#include <EEPROM.h> #include <Wire.h> #include <LiquidCrystal_I2C.h> #include <OneButton.h> #include <RDA5807M.h> //номера пинов для кнопок const uint8_t leftBtnPin = 8; const uint8_t rightBtnPin = 12; const uint8_t upBtnPin = 11; const uint8_t downBtnPin = 9; const uint8_t okBtnPin = 10; //const uint8_t seekMenu = 1; //const uint8_t mTuneMenu = 2; //const uint8_t channelMenu = 3; const word startFr = 9760; //частота, с которой стартуем // список частот станций ****************************** uint16_t stations[] = {9380, 9490, 9530, 9570, 9610, 9650, 9720, 9760, 9830, 9880, 10000, 10060, 10110, 10150, 10200, 10260, 10310, 10360, 10400, 10450, 10510, 10560, 10600, 10640, 10660}; // символы ************************************* uint8_t antChar [8] = {31,0,14,0,4,4,4,4}; //антена /* uint8_t sigLevel_1 [8] = {0,0,0,0,0,0,0,31}; //уровень сигнала uint8_t sigLevel_2 [8] = {0,0,0,0,0,0,31,31}; //уровень сигнала uint8_t sigLevel_3 [8] = {0,0,0,0,0,31,31,31}; //уровень сигнала uint8_t sigLevel_4 [8] = {0,0,0,0,31,31,31,31}; //уровень сигнала uint8_t sigLevel_5 [8] = {0,0,0,31,31,31,31,31}; //уровень сигнала uint8_t sigLevel_6 [8] = {0,0,31,31,31,31,31,31}; //уровень сигнала uint8_t sigLevel_7 [8] = {31,31,31,31,31,31,31,31}; //уровень сигнала */ uint8_t soundChar [8] = {1,3,15,15,15,15,3,1}; //динамик uint8_t soundOnChar [8] = {8,16,0,28,28,0,16,8}; //динамик вкл uint16_t maxStations = sizeof(stations)/sizeof(uint16_t); uint16_t frequency; uint8_t menuLevel = 1; //AutoTuneMenu; uint8_t volLevel = 4; uint8_t rssiLevel; uint8_t stNumber = 1; bool muteFlag = false; bool maxVolFlag = false, minVolFlag = false; LiquidCrystal_I2C lcd(0x27, 16, 2); // Set the LCD address to 0x27 for a 16 chars and 2 line display RDA5807M radio; //Create an instance of the RDA5807M named radio\ OneButton leftButton(leftBtnPin, true); //создаем объект типа OneButton с именем leftButton OneButton rightButton(rightBtnPin, true); //создаем объект типа OneButton с именем rightButton OneButton upButton(upBtnPin, true); //создаем объект типа OneButton с именем upButton OneButton downButton(downBtnPin, true); //создаем объект типа OneButton с именем downButton OneButton okButton(okBtnPin, true); //создаем объект типа OneButton с именем okButton void setup() { Serial.begin(9600); Wire.begin(); // Инициализация двухпроводной шины I2C. lcd.begin(); // инициализация LCD lcd.backlight(); // включаем подсветку // создаем символы lcd.createChar(0, antChar); //значек антены lcd.createChar(1,soundChar); //значек динамика lcd.createChar(2,soundOnChar); //звук вкл if (radio.init()) radio.setBand(RADIO_BAND_FM); // инициализация радиомодуля RDA5807M диапазон 87-108 МГц radio.setVolume(volLevel); frequency = startFr; // Частота при включении startFr radio.setFrequency(frequency); leftButton.attachClick(leftClick); //кнопка влево нажатие leftButton.setDebounceTicks(50); leftButton.attachDuringLongPress(leftClick); //кнопка влево долгое нажатие leftButton.setPressTicks(500); rightButton.attachClick(rightClick); //кнопка вправо rightButton.setDebounceTicks(50); rightButton.attachDuringLongPress(rightClick); //кнопка вправо долгое нажатие rightButton.setPressTicks(500); upButton.attachClick(upClick); //кнопка вверх upButton.setDebounceTicks(50); downButton.attachClick(downClick); //кнопка вниз downButton.setDebounceTicks(50); okButton.attachClick(okClick); //кнопка ОК клик okButton.setPressTicks(1500); okButton.attachLongPressStart(okPress); //кнопка ОК долгое нажатие okButton.setDebounceTicks(50); printFreq(); // Выводим информацию о частоте printRSSI(); // Выводим информацию о и силе сигнала printVol(); // Уровень громкости printStNum(); // Номер станции или режим настройки на канылы }//end setup void loop() { leftButton.tick(); rightButton.tick(); upButton.tick(); downButton.tick(); okButton.tick(); delay (50); printRSSI (); }//end loop() void leftClick() { switch (menuLevel) { case 1: radio.seekDown(1); //frequency = radio.getFrequency(); printFreq(); printRSSI(); printVol(); break; case 2: if (frequency > 8700)frequency -= 10; else frequency = 10800; radio.setFrequency(frequency); printFreq(); printRSSI(); printVol(); break; case 3: if (stNumber > 1)stNumber -= 1 ; else stNumber = maxStations; frequency = stations[stNumber - 1]; radio.setFrequency(frequency); printStNum(); printFreq(); printRSSI(); printVol(); break; }//end switch }//end leftClick() void rightClick() { switch (menuLevel) { case 1: radio.seekUp(1); //frequency = radio.getFrequency(); printFreq(); printRSSI(); printVol(); break; case 2: if (frequency < 10800)frequency += 10; else frequency = 8700; radio.setFrequency(frequency); printFreq(); printRSSI(); printVol(); break; case 3: if (stNumber >= maxStations)stNumber = 1; else stNumber += 1; frequency = stations[stNumber - 1]; radio.setFrequency(frequency); printStNum(); printFreq(); printRSSI(); printVol(); break; }//end switch }//end rightClick() void upClick() { if (volLevel < 15) volLevel += 1; muteFlag = false; radio.setVolume(volLevel); printVol(); }//end upClick() void downClick() { if (volLevel > 0) volLevel -= 1; radio.setVolume(volLevel); printVol(); }//end downClick() void okClick() { if (menuLevel <3) menuLevel += 1; else menuLevel = 1; printStNum (); }//end okClick() void okPress() { muteFlag = !muteFlag; printVol(); }//end okPress() void printFreq() { frequency = radio.getFrequency(); Serial.println(frequency); lcd.setCursor(0,0); // lcd.print("FM "); // lcd.print(frequency / 100); // выводим на дисплей частоту lcd.print("."); // lcd.print(frequency % 100); // lcd.println(" "); // }//end printFreq() void printRSSI() { rssiLevel = radio.getRSSI(); lcd.setCursor(8,0); // lcd.print(" "); lcd.print(char(0)); //Значек антены lcd.print(" "); lcd.print(rssiLevel); // lcd.print(" "); // }//printRSSI() void printVol() { //frequency = radio.getFrequency(); //Serial.println(frequency); if ((muteFlag == false) && (volLevel > 0)) { radio.setMute(muteFlag); lcd.setCursor(0,1); if (volLevel > 14) { lcd.print(" MAX"); }//end if else { if (volLevel < 10) lcd.print(" 0"); else lcd.print(" "); lcd.print(volLevel); lcd.setCursor(4,1); lcd.print(char(1)); lcd.print(char(2)); }//end else }//end if else { muteFlag = true; radio.setMute(muteFlag); lcd.setCursor(0,1); lcd.print("MUTE"); lcd.setCursor(4,1); lcd.print(char(1)); lcd.print(" "); }//end else }//end printVol() void printStNum() { //radio.setFrequency(frequency); switch (menuLevel) { case 1: lcd.setCursor(11,1); lcd.print("[A] "); break; case 2: lcd.setCursor(11,1); lcd.print("[M] "); break; case 3: lcd.setCursor(11,1); lcd.print("["); if (stNumber < 10)lcd.print("0"); lcd.print(stNumber); lcd.print("]"); break; }//end switch }//end printStNum() /****** END ********/ /// \file RDA5807M.cpp /// \brief Implementation for the radio library to control the RDA5807M radio chip. /// /// \author Matthias Hertel, http://www.mathertel.de /// \copyright Copyright (c) 2014-2015 by Matthias Hertel.\n /// This work is licensed under a BSD style license.\n /// See http://www.mathertel.de/License.aspx /// /// This library enables the use of the radio chip RDA5807M from http://www.rdamicro.com/. /// /// More documentation and source code is available at http://www.mathertel.de/Arduino /// /// History: /// -------- /// * 05.08.2014 created. #include <Arduino.h> #include <Wire.h> #include <RDA5807M.h> // ----- Register Definitions ----- // this chip only supports FM mode #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 // RADIO_REG_CHAN_TEST 0x0020 #define RADIO_REG_CHAN_NR 0x7FC0 #define RADIO_REG_R4 0x04 #define RADIO_REG_R4_EM50 0x0800 // RADIO_REG_R4_RES 0x0400 #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 0x10 // I2C-Address RDA Chip for Index Access #define I2C_INDX 0x11 // ----- implement // initialize the extra variables in RDA5807M RDA5807M::RDA5807M() { // t.b.d. ??? } // initialize all internals. bool RDA5807M::init() { bool result = false; // no chip found yet. Wire.begin(); Wire.beginTransmission(I2C_INDX); result = Wire.endTransmission(); if (result == 0) { result = true; // initialize all registers registers[RADIO_REG_CHIPID] = 0x5804; // 00 id registers[1] = 0x0000; // 01 not used registers[RADIO_REG_CTRL] = (RADIO_REG_CTRL_RESET | RADIO_REG_CTRL_ENABLE); setBand(RADIO_BAND_FM); registers[RADIO_REG_R4] = RADIO_REG_R4_EM50;// 0x1800; // 04 DE ? SOFTMUTE registers[RADIO_REG_VOL] = 0x9081; // 0x81D1; // 0x82D1 / INT_MODE, SEEKTH=0110,????, Volume=1 registers[6] = 0x0000; registers[7] = 0x0000; registers[8] = 0x0000; registers[9] = 0x0000; // reset the chip _saveRegisters(); registers[RADIO_REG_CTRL] = RADIO_REG_CTRL_ENABLE; _saveRegister(RADIO_REG_CTRL); } // if return(result); } // init() // switch the power off void RDA5807M::term() { setVolume(0); registers[RADIO_REG_CTRL] = 0x0000; // all bits off _saveRegisters(); } // term // ----- Volume control ----- void RDA5807M::setVolume(uint8_t newVolume) { newVolume &= RADIO_REG_VOL_VOL; registers[RADIO_REG_VOL] &= (~RADIO_REG_VOL_VOL); registers[RADIO_REG_VOL] |= newVolume; _saveRegister(RADIO_REG_VOL); } // setVolume() void RDA5807M::setBassBoost(bool switchOn) { uint16_t regCtrl = registers[RADIO_REG_CTRL]; if (switchOn) regCtrl |= RADIO_REG_CTRL_BASS; else regCtrl &= (~RADIO_REG_CTRL_BASS); registers[RADIO_REG_CTRL] = regCtrl; _saveRegister(RADIO_REG_CTRL); } // setBassBoost() // Mono / Stereo void RDA5807M::setMono(bool switchOn) { registers[RADIO_REG_CTRL] &= (~RADIO_REG_CTRL_SEEK); if (switchOn) { registers[RADIO_REG_CTRL] |= RADIO_REG_CTRL_MONO; } else { registers[RADIO_REG_CTRL] &= ~RADIO_REG_CTRL_MONO; } _saveRegister(RADIO_REG_CTRL); } // setMono // Switch mute mode. void RDA5807M::setMute(bool switchOn) { if (switchOn) { // now don't unmute registers[RADIO_REG_CTRL] &= (~RADIO_REG_CTRL_UNMUTE); } else { // now unmute registers[RADIO_REG_CTRL] |= RADIO_REG_CTRL_UNMUTE; } // if _saveRegister(RADIO_REG_CTRL); } // setMute() // Switch softmute mode. void RDA5807M::setSoftMute(bool switchOn) { if (switchOn) { registers[RADIO_REG_R4] |= (RADIO_REG_R4_SOFTMUTE); } else { registers[RADIO_REG_R4] &= (~RADIO_REG_R4_SOFTMUTE); } // if _saveRegister(RADIO_REG_R4); } // setSoftMute() // ----- Band and frequency control methods ----- // tune to new band. void RDA5807M::setBand(RADIO_BAND newBand) { if (newBand == RADIO_BAND_FM){ _freqLow = 8700; _freqHigh = 10800; _freqSteps = 10; registers[RADIO_REG_CHAN] = (RADIO_REG_CHAN_BAND_FM | RADIO_REG_CHAN_SPACE_100); } else if (newBand == RADIO_BAND_FMWORLD) { _freqLow = 7600; _freqHigh = 10800; _freqSteps = 10; registers[RADIO_REG_CHAN] = (RADIO_REG_CHAN_BAND_FMWORLD | RADIO_REG_CHAN_SPACE_100); } else if (newBand == RADIO_BAND_FMEE) { _freqLow = 6500; _freqHigh = 7600; _freqSteps = 5; registers[RADIO_REG_CHAN] = (RADIO_REG_CHAN_BAND | RADIO_REG_CHAN_SPACE); } } // setBand() // retrieve the real frequency from the chip after automatic tuning. RADIO_FREQ RDA5807M::getFrequency() { // check register A Wire.requestFrom (I2C_SEQ, 2); registers[RADIO_REG_RA] = _read16(); Wire.endTransmission(); uint16_t ch = registers[RADIO_REG_RA] & RADIO_REG_RA_NR; _freq = _freqLow + (ch * 10); // assume 100 kHz spacing return (_freq); } // getFrequency void RDA5807M::setFrequency(RADIO_FREQ newF) { uint16_t newChannel; uint16_t regChannel = registers[RADIO_REG_CHAN] & (RADIO_REG_CHAN_SPACE | RADIO_REG_CHAN_BAND); if (newF < _freqLow) newF = _freqLow; if (newF > _freqHigh) newF = _freqHigh; newChannel = (newF - _freqLow) / 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_RDS | 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() // start seek mode upwards void RDA5807M::seekUp(bool toNextSender) { // start seek mode registers[RADIO_REG_CTRL] |= RADIO_REG_CTRL_SEEKUP; registers[RADIO_REG_CTRL] |= RADIO_REG_CTRL_SEEK; _saveRegister(RADIO_REG_CTRL); if (! toNextSender) { // stop scanning right now registers[RADIO_REG_CTRL] &= (~RADIO_REG_CTRL_SEEK); _saveRegister(RADIO_REG_CTRL); } // if } // seekUp() // start seek mode downwards void RDA5807M::seekDown(bool toNextSender) { registers[RADIO_REG_CTRL] &= (~RADIO_REG_CTRL_SEEKUP); registers[RADIO_REG_CTRL] |= RADIO_REG_CTRL_SEEK; _saveRegister(RADIO_REG_CTRL); if (! toNextSender) { // stop scanning right now registers[RADIO_REG_CTRL] &= (~RADIO_REG_CTRL_SEEK); _saveRegister(RADIO_REG_CTRL); } // if } // seekDown() // return current Radio Station Strength Information uint8_t RDA5807M::getRSSI() { _readRegisters(); uint8_t rssi = registers[RADIO_REG_RB] >> 10; return(rssi); } // getRSSI // Load all status registers from to the chip // registers 0A through 0F // using the sequential read access mode. void RDA5807M::_readRegisters() { Wire.requestFrom (I2C_SEQ, (6 * 2) ); for (int i = 0; i < 6; i++) { registers[0xA+i] = _read16(); } Wire.endTransmission(); } // Save writable registers back to the chip // The registers 02 through 06, containing the configuration // using the sequential write access mode. void RDA5807M::_saveRegisters() { Wire.beginTransmission(I2C_SEQ); for (int i = 2; i <= 6; i++) _write16(registers[i]); Wire.endTransmission(); } // _saveRegisters // Save one register back to the chip void RDA5807M::_saveRegister(byte regNr) { Wire.beginTransmission(I2C_INDX); Wire.write(regNr); _write16(registers[regNr]); Wire.endTransmission(); } // _saveRegister // write a register value using 2 bytes into the Wire. void RDA5807M::_write16(uint16_t val) { Wire.write(val >> 8); Wire.write(val & 0xFF); } // _write16 // read a register value using 2 bytes in a row uint16_t RDA5807M::_read16(void) { uint8_t hiByte = Wire.read(); uint8_t loByte = Wire.read(); return(256*hiByte + loByte); } // _read16 void RDA5807M::checkRDS() { // check RDS data if there is a listener ! if (_sendRDS) { // check register A Wire.requestFrom (I2C_SEQ, 2); registers[RADIO_REG_RA] = _read16(); Wire.endTransmission(); if (registers[RADIO_REG_RA] & RADIO_REG_RA_RDS) { // check for new RDS data available uint16_t newData; bool result = false; Wire.beginTransmission(I2C_INDX); // Device 0x11 for random access Wire.write(RADIO_REG_RDSA); // Start at Register 0x0C Wire.endTransmission(0); // restart condition Wire.requestFrom(I2C_INDX, 8, 1); // Retransmit device address with READ, followed by 8 bytes newData = _read16(); if (newData != registers[RADIO_REG_RDSA]) { registers[RADIO_REG_RDSA] = newData; result = true; } newData = _read16(); if (newData != registers[RADIO_REG_RDSB]) { registers[RADIO_REG_RDSB] = newData; result = true; } newData = _read16(); if (newData != registers[RADIO_REG_RDSC]) { registers[RADIO_REG_RDSC] = newData; result = true; } newData = _read16(); if (newData != registers[RADIO_REG_RDSD]) { registers[RADIO_REG_RDSD] = newData; result = true; } Wire.endTransmission(); // _printHex(registers[RADIO_REG_RDSA]); _printHex(registers[RADIO_REG_RDSB]); // _printHex(registers[RADIO_REG_RDSC]); _printHex(registers[RADIO_REG_RDSD]); // Serial.println(); if (result) { // new data in the registers // send to RDS decoder _sendRDS(registers[RADIO_REG_RDSA], registers[RADIO_REG_RDSB], registers[RADIO_REG_RDSC], registers[RADIO_REG_RDSD]); } // if } // if } } /// Retrieve all the information related to the current radio receiving situation. void RDA5807M::getRadioInfo(RADIO_INFO *info) { // read data from registers A .. F of the chip into class memory _readRegisters(); info->active = true; // ??? if (registers[RADIO_REG_RA] & RADIO_REG_RA_STEREO) info->stereo = true; if (registers[RADIO_REG_RA] & RADIO_REG_RA_RDS) info->rds = true; info->rssi = registers[RADIO_REG_RB] >> 10; if (registers[RADIO_REG_RB] & RADIO_REG_RB_FMTRUE) info->tuned = true; if (registers[RADIO_REG_CTRL] & RADIO_REG_CTRL_MONO) info->mono = true; } // getRadioInfo() // ----- internal functions ----- // The End.
Если Вы используете вот эту библиотеку - https://github.com/mathertel/Radio/tree/master/src
То в ней ошибка: после поиска не работает установка частоты. Нужно добавить сброс бита SEEK в функцию setFrequency. Ну, или прямо в seekUp/seekDown после отгрузки регистра.
Спаисбо! Понял. Попробую разобраться. Просто я не программист и с ардуиной около месяца всего общаюсь. Можете еще подсказать по работе с Wire.requestFrom (I2C_SEQ, 2), как эта функция работает и где забирать считанные байты. Тогда, думаю, сам все пороавлю в библиотеке.