FM радио на RDA5807M
- Сычевский Виталий
- 28 мая 2016 г.
- 10 мин. чтения
Чтобы не "изобретать "велосипед"", был взят проект:
" Цифровой FM приемник на Arduino и модуле RDA5807 с графическим дисплеем и функцией RDS "
Как я понял, настоящий автор проекта - Испанец, т.к. в тексте программы использованы Испанские названия.
Мной было использовано:
1. Контроллер Arduino Pro Mini Atmega168 5V 16MHz .
2. FM приемник - микросхема RDA5807M на печатной плате для Arduino.
3. Усилитель мощности 2х15W на микросхеме PAM8610.
4. Дисплей Nokia 5110 на печатной плате для Arduino.
5. EEPROM микросхема 24Сxx (в моем случае под руками оказалась 24С256).
6. Аналоговые стабилизаторы на 5В и 3.3В AMS1117.
7. Электролитические конденсаторы 22мкфХ16В и керамические 0,1мкфХ50В, использованные в цепях AMS1117 и питания модулей.
8. Макетная плата 8х6см.
9. Разъемы.
В итоге получилось следующее:

Контроллер Arduino Pro Mini Atmega168 5V 16MHz подключен через разъемное соединение и имеет угловые выводы для программатора, под экраном расположен блок усилителя, экран также размещен на разъемном соединении. Схема включения такая же, как и у автора, что указан в начале

Дополнительно подключен EEPROM согласно классическому подключению: выводы микросхемы 24Схх подключены:
1. Выводы 1, 2, 3, 4, 7 - к общей шине
2. Вывод 8 - к "+" 5В питания
3. Вывод 5 к А4 ардуино
5. Вывод 6 к А5 ардуино
Подключение AMS1117 согласно Data Sheet на микросхему.
Но я не просто скопировал программное обеспечение, а
1. ASCII кодировку разместил в памяти EEPROM, для чего использовал специально написанную программу, превратившую двумерный массив в последовательный поток данных для записи в EEPROM.
2. Также в EEPROM разместил текущие установки, чтобы тюнер всегда включался при том же уровне громкости, той же радиостанции и установленном режиме БАССа.
3. Добавил включение и индикацию режима БАСС.
4. Добавил в программу работу с EEPROM.
Всё это позволило несколько улучшить потребительские свойства приемника и позволило разместить код на контроллере, у которого ограничена память, в результате чего авторский программный код не работал на данном контроллере.
Вот программа для загрузки в EEPROM таблицы ASCII. Программа загружается и исполняется всего один раз, после чего (через 1-2 мин) можно загрузить основную программу.
#include <EEPROM.h> void setup() { // put your setup code here, to run once: } void loop() { static const byte ASCII[][5] = { { 0x00, 0x00, 0x00, 0x00, 0x00 }, // 01 20 space { 0x00, 0x00, 0x5f, 0x00, 0x00 }, // 02 21 ! { 0x00, 0x07, 0x00, 0x07, 0x00 }, // 03 22 " { 0x14, 0x7f, 0x14, 0x7f, 0x14 }, // 04 23 # { 0x24, 0x2a, 0x7f, 0x2a, 0x12 }, // 05 24 $ { 0x23, 0x13, 0x08, 0x64, 0x62 }, // 06 25 % { 0x36, 0x49, 0x55, 0x22, 0x50 }, // 07 26 & { 0x00, 0x05, 0x03, 0x00, 0x00 }, // 08 27 ' { 0x00, 0x1c, 0x22, 0x41, 0x00 }, // 09 28 ( { 0x00, 0x41, 0x22, 0x1c, 0x00 }, // 10 29 ) { 0x14, 0x08, 0x3e, 0x08, 0x14 }, // 11 2a * { 0x08, 0x08, 0x3e, 0x08, 0x08 }, // 12 2b + { 0x00, 0x50, 0x30, 0x00, 0x00 }, // 13 2c , { 0x08, 0x08, 0x08, 0x08, 0x08 }, // 14 2d - { 0x00, 0x60, 0x60, 0x00, 0x00 }, // 15 2e . { 0x20, 0x10, 0x08, 0x04, 0x02 }, // 16 2f / { 0x3e, 0x51, 0x49, 0x45, 0x3e }, // 17 30 0 { 0x00, 0x42, 0x7f, 0x40, 0x00 }, // 18 31 1 { 0x42, 0x61, 0x51, 0x49, 0x46 }, // 19 32 2 { 0x21, 0x41, 0x45, 0x4b, 0x31 }, // 20 33 3 { 0x18, 0x14, 0x12, 0x7f, 0x10 }, // 21 34 4 { 0x27, 0x45, 0x45, 0x45, 0x39 }, // 22 35 5 { 0x3c, 0x4a, 0x49, 0x49, 0x30 }, // 23 36 6 { 0x01, 0x71, 0x09, 0x05, 0x03 }, // 24 37 7 { 0x36, 0x49, 0x49, 0x49, 0x36 }, // 25 38 8 { 0x06, 0x49, 0x49, 0x29, 0x1e }, // 26 39 9 { 0x00, 0x36, 0x36, 0x00, 0x00 }, // 27 3a : { 0x00, 0x56, 0x36, 0x00, 0x00 }, // 28 3b ; { 0x08, 0x14, 0x22, 0x41, 0x00 }, // 29 3c < { 0x14, 0x14, 0x14, 0x14, 0x14 }, // 30 3d = { 0x00, 0x41, 0x22, 0x14, 0x08 }, // 31 3e > { 0x02, 0x01, 0x51, 0x09, 0x06 }, // 32 3f ? { 0x32, 0x49, 0x79, 0x41, 0x3e }, // 33 40 @ { 0x7e, 0x11, 0x11, 0x11, 0x7e }, // 34 41 A { 0x7f, 0x49, 0x49, 0x49, 0x36 }, // 35 42 B { 0x3e, 0x41, 0x41, 0x41, 0x22 }, // 36 43 C { 0x7f, 0x41, 0x41, 0x22, 0x1c }, // 37 44 D { 0x7f, 0x49, 0x49, 0x49, 0x41 }, // 38 45 E { 0x7f, 0x09, 0x09, 0x09, 0x01 }, // 39 46 F { 0x3e, 0x41, 0x49, 0x49, 0x7a }, // 40 47 G { 0x7f, 0x08, 0x08, 0x08, 0x7f }, // 41 48 H { 0x00, 0x41, 0x7f, 0x41, 0x00 }, // 42 49 I { 0x20, 0x40, 0x41, 0x3f, 0x01 }, // 43 4a J { 0x7f, 0x08, 0x14, 0x22, 0x41 }, // 44 4b K { 0x7f, 0x40, 0x40, 0x40, 0x40 }, // 45 4c L { 0x7f, 0x02, 0x0c, 0x02, 0x7f }, // 46 4d M { 0x7f, 0x04, 0x08, 0x10, 0x7f }, // 47 4e N { 0x3e, 0x41, 0x41, 0x41, 0x3e }, // 48 4f O { 0x7f, 0x09, 0x09, 0x09, 0x06 }, // 49 50 P { 0x3e, 0x41, 0x51, 0x21, 0x5e }, // 50 51 Q { 0x7f, 0x09, 0x19, 0x29, 0x46 }, // 51 52 R { 0x46, 0x49, 0x49, 0x49, 0x31 }, // 52 53 S { 0x01, 0x01, 0x7f, 0x01, 0x01 }, // 53 54 T { 0x3f, 0x40, 0x40, 0x40, 0x3f }, // 54 55 U { 0x1f, 0x20, 0x40, 0x20, 0x1f }, // 55 56 V { 0x3f, 0x40, 0x38, 0x40, 0x3f }, // 56 57 W { 0x63, 0x14, 0x08, 0x14, 0x63 }, // 57 58 X { 0x07, 0x08, 0x70, 0x08, 0x07 }, // 58 59 Y { 0x61, 0x51, 0x49, 0x45, 0x43 }, // 59 5a Z { 0x00, 0x7f, 0x41, 0x41, 0x00 }, // 60 5b [ { 0x02, 0x04, 0x08, 0x10, 0x20 }, // 61 5c backslash { 0x00, 0x41, 0x41, 0x7f, 0x00 }, // 62 5d ] { 0x04, 0x02, 0x01, 0x02, 0x04 }, // 63 5e ^ { 0x40, 0x40, 0x40, 0x40, 0x40 }, // 64 5f _ { 0x00, 0x01, 0x02, 0x04, 0x00 }, // 65 60 ` { 0x20, 0x54, 0x54, 0x54, 0x78 }, // 66 61 a { 0x7f, 0x48, 0x44, 0x44, 0x38 }, // 67 62 b { 0x38, 0x44, 0x44, 0x44, 0x20 }, // 68 63 c { 0x38, 0x44, 0x44, 0x48, 0x7f }, // 69 64 d { 0x38, 0x54, 0x54, 0x54, 0x18 }, // 70 65 e { 0x08, 0x7e, 0x09, 0x01, 0x02 }, // 71 66 f { 0x0c, 0x52, 0x52, 0x52, 0x3e }, // 72 67 g { 0x7f, 0x08, 0x04, 0x04, 0x78 }, // 73 68 h { 0x00, 0x44, 0x7d, 0x40, 0x00 }, // 74 69 i { 0x20, 0x40, 0x44, 0x3d, 0x00 }, // 75 6a j { 0x7f, 0x10, 0x28, 0x44, 0x00 }, // 76 6b k { 0x00, 0x41, 0x7f, 0x40, 0x00 }, // 77 6c l { 0x7c, 0x04, 0x18, 0x04, 0x78 }, // 78 6d m { 0x7c, 0x08, 0x04, 0x04, 0x78 }, // 79 6e n { 0x38, 0x44, 0x44, 0x44, 0x38 }, // 80 6f o { 0x7c, 0x14, 0x14, 0x14, 0x08 }, // 81 70 p { 0x08, 0x14, 0x14, 0x18, 0x7c }, // 82 71 q { 0x7c, 0x08, 0x04, 0x04, 0x08 }, // 83 72 r { 0x48, 0x54, 0x54, 0x54, 0x20 }, // 84 73 s { 0x04, 0x3f, 0x44, 0x40, 0x20 }, // 85 74 t { 0x3c, 0x40, 0x40, 0x20, 0x7c }, // 86 75 u { 0x1c, 0x20, 0x40, 0x20, 0x1c }, // 87 76 v { 0x3c, 0x40, 0x30, 0x40, 0x3c }, // 88 77 w { 0x44, 0x28, 0x10, 0x28, 0x44 }, // 89 78 x { 0x0c, 0x50, 0x50, 0x50, 0x3c }, // 90 79 y { 0x44, 0x64, 0x54, 0x4c, 0x44 }, // 91 7a z { 0x00, 0x08, 0x36, 0x41, 0x00 }, // 92 7b { { 0x00, 0x00, 0x7f, 0x00, 0x00 }, // 93 7c | { 0x00, 0x41, 0x36, 0x08, 0x00 }, // 94 7d } { 0x10, 0x08, 0x08, 0x10, 0x08 }, // 95 7e ~ // { 0x00, 0x00, 0x00, 0x00, 0x00 }, // 7f {B11111111, B01111110, B00011000, B01111110, B11111111} //Stereo 127 }; int i=0; for (int indexY = 0; indexY < 96; indexY++) { for (int index = 0; index < 5; index++) { EEPROM.write(i, ASCII[indexY][index]); i++; } } }
Вот основная программа:
//Edition Sychevsky Vitaly 20016.05.28 vita_run@mail.ru
#include <EEPROM.h> #include <Wire.h> const int input = A0; int inputV = 0; int menu; #define MAXmenu 5 int menux; #define MAXmenux 5 static char* menuS[]= {" ","MANUAL TUNE","VOLUME ","AUTO TUNE","INFO ","BASS BOST"}; int vol=EEPROM.read(480),volOld=7; int frequency,frequencyOld; bool bassboost; unsigned int z,z1; byte xfrecu,xfrecuOld; unsigned int estado[6]; unsigned long time,time1,time2,time3; // int RDA5807_adrs=0x10; // I2C-Address RDA Chip for sequential Access // int RDA5807_adrr=0x11; // I2C-Address RDA Chip for random Access // int RDA5807_adrt=0x60; // I2C-Address RDA Chip for TEA5767like Access char buffer[30]; unsigned int RDS[4]; char seg_RDS[8]; char seg_RDS1[64]; char indexRDS1; char hora,minuto,grupo,versio; unsigned long julian; int mezcla; void setup() { Wire.begin(); LcdInitialise(); LcdClear(); //drawBox(); WriteReg(0x02,0xC00d); // write 0xC00d into Reg.2 ( soft reset, enable, RDS, ) WriteReg(0x05,0x84d8); // write ,0x84d8 into Reg.3 // setup frequency frequency=EEPROM.read(481); //104.7 time3=time2=time1=time = millis(); menu=3; canal(frequency); clearRDS; bassboost=EEPROM.read(482); } void loop() { inputV = analogRead(input); // bottom menu if(inputV>500 && inputV<524) { menu++; if(menu>MAXmenu)menu=1; Visualizar(); while(1020>analogRead(input))delay(5); } // bottom increase if(inputV<50) { menux++; if(menux>MAXmenux)menux=MAXmenux; switch(menu) { case 1: frequency++; if(frequency>205)frequency=205; // верхняя граница частот delay(130); break; case 2: vol++; if(vol>15)vol=15; while(1020>analogRead(input))delay(5); break; case 3: busqueda(0); while(1020>analogRead(input))delay(5); break; case 4: LcdClear(); visualPI(); delay(3000); LcdClear(); frequencyOld=-1; break; case 5: bassboost=true; WriteReg(0x02,0xD00D); EEPROM.write(482, 1); while(1020>analogRead(input))delay(5); break; } } // bottom decrease if( inputV<700 && inputV>660) { menux--; if(menux<1)menux=1; switch(menu) { case 1: frequency--; if(frequency<0)frequency=0; delay(130); break; case 2: vol--; if(vol<0)vol=0; while(1020>analogRead(input))delay(5); break; case 3: busqueda(1); while(1020>analogRead(input))delay(5); break; case 4: LcdClear(); visualPTY(); delay(3000); LcdClear(); frequencyOld=-1; break; case 5: bassboost=false; WriteReg(0x02,0xC00D); EEPROM.write(482, 0); while(1020>analogRead(input))delay(5); break; } } if( millis()-time2>50) { ReadEstado(); time1 = millis(); //RDS if ((estado[0] & 0x8000)!=0) {get_RDS();} } if( millis()-time3>500) { time3 = millis(); Visualizar(); } if (bassboost){gotoXY(2,1); LcdString("Bass");} else {gotoXY(2,1); LcdString(" ");} if( frequency!=frequencyOld) { EEPROM.write(481, frequency); frequencyOld=frequency; z=870+frequency; sprintf(buffer,"%04d ",z); gotoXY(1,3); for(z=0;z<5;z++) { if(z==3) LcdStringX("."); LcdCharacterX(buffer[z]); } gotoXY(62,3); LcdString("MHz"); canal(frequency); clearRDS(); } //Cambio de vol if(vol!=volOld) { EEPROM.write(480, vol); volOld=vol; sprintf(buffer,"Vol %02d",vol); gotoXY(38,1); LcdString(buffer); WriteReg(5, 0x84D0 | vol); } } void visualPI(void) { gotoXY(1,3);sprintf(buffer,"Country-%02d",RDS[0]>>12 & 0X000F); LcdString(buffer); gotoXY(1,4);sprintf(buffer,"Region -%02d",RDS[0]>>8 & 0X000F); LcdString(buffer); gotoXY(1,5);sprintf(buffer,"Code -%02d",RDS[0] & 0X00FF); LcdString(buffer); } void visualPTY(void) { gotoXY(1,3); LcdString("Type"); gotoXY(1,4); LcdString("Program"); gotoXY(1,5);sprintf(buffer,"%02d",RDS[1]>>5 & 0X001F); LcdString(buffer); } void busqueda(byte direc) { byte i; if(!direc) WriteReg(0x02,0xC30d); else WriteReg(0x02,0xC10d); for(i=0;i<10;i++) { delay(200); ReadEstado(); if(estado[0]&0x4000) { //Serial.println("Найденная станция"); frequency=estado[0] & 0x03ff; break; } } } void clearRDS(void) { gotoXY(10,4); for (z=0;z<8;z++) {seg_RDS[z]=32; LcdCharacter(32);} //borrar Name LCD Emisora gotoXY(38,2); for (z=0;z<6;z++) { LcdCharacter(32);} //borrar linea Hora for (z=0;z<64;z++) seg_RDS1[z]=32; } void Visualizar(void) { gotoXY(2,0); LcdStringX("FM"); sprintf(buffer,"%s",menuS[menu]); gotoXY(2,2); LcdString(buffer); //Detect stereo gotoXY(72,0); if((estado[0] & 0x0400)==0) LcdCharacter(32); else LcdCharacter(127); //Señal z=estado[1]>>10; sprintf(buffer,"S-%02d",z); gotoXY(38,0); LcdString(buffer); sprintf(buffer,"Vol %02d",vol); gotoXY(38,1); LcdString(buffer); //ver RADIO_TXT gotoXY(0,5); z1=indexRDS1; for (z=0;z<12;z++) { LcdCharacter(seg_RDS1[z1]); z1++; if(z1>35)z1=0; } indexRDS1++; if(indexRDS1>35) indexRDS1=0; frequency=estado[0] & 0x03ff; } void canal( int canal) { byte numberH,numberL; numberH= canal>>2; numberL = ((canal&3)<<6 | 0x10); Wire.beginTransmission(0x11); Wire.write(0x03); Wire.write(numberH); // write frequency into bits 15:6, set tune bit Wire.write(numberL); Wire.endTransmission(); } //________________________ //RDA5807_adrr=0x11; // I2C-Address RDA Chip for random Access void WriteReg(byte reg,unsigned int valor) { Wire.beginTransmission(0x11); Wire.write(reg); Wire.write(valor >> 8); Wire.write(valor & 0xFF); Wire.endTransmission(); } //RDA5807_adrs=0x10; // I2C-Address RDA Chip for sequential Access int ReadEstado() { Wire.requestFrom(0x10, 12); for (int i=0; i<6; i++) { estado[i] = 256*Wire.read ()+Wire.read(); } Wire.endTransmission(); } //READ RDS Direccion 0x11 for random access void ReadW() { Wire.beginTransmission(0x11); // Device 0x11 for random access Wire.write(0x0C); // Start at Register 0x0C Wire.endTransmission(0); // restart condition Wire.requestFrom(0x11,8, 1); // Retransmit device address with READ, followed by 8 bytes for (int i=0; i<4; i++) {RDS[i]=256*Wire.read()+Wire.read();} // Read Data into Array of Unsigned Ints Wire.endTransmission(); } void get_RDS() { int i; ReadW(); grupo=(RDS[1]>>12)&0xf; if(RDS[1]&0x0800) versio=1; else versio=0; //Version A=0 Version B=1 if(versio==0) { switch(grupo) { case 0: i=(RDS[1] & 3) <<1; seg_RDS[i]=(RDS[3]>>8); seg_RDS[i+1]=(RDS[3]&0xFF); gotoXY(10,4); for (i=0;i<8;i++) { if(seg_RDS[i]>31 && seg_RDS[i]<128) LcdCharacter(seg_RDS[i]); else LcdCharacter(32); } break; case 2: i=(RDS[1] & 15) <<2; seg_RDS1[i]=(RDS[2]>>8); seg_RDS1[i+1]=(RDS[2]&0xFF); seg_RDS1[i+2]=(RDS[3]>>8); seg_RDS1[i+3]=(RDS[3]&0xFF); break; case 4: i=RDS[3]& 0x003f; minuto=(RDS[3]>>6)& 0x003f; hora=(RDS[3]>>12)& 0x000f; if(RDS[2]&1) hora+=16; hora+=i; z=RDS[2]>>1; julian=z; if(RDS[1]&1) julian+=32768; if(RDS[1]&2) julian+=65536; break; default: ; } } } // The pins to use on the arduino #define PIN_SCE 3 #define PIN_RESET 4 #define PIN_DC 5 #define PIN_SDIN 6 #define PIN_SCLK 7 // COnfiguration for the LCD #define LCD_C LOW #define LCD_D HIGH #define LCD_CMD 0 // Size of the LCD #define LCD_X 84 #define LCD_Y 48 int scrollPosition = -10; void LcdCharacter(char character) { unsigned char z,z1; z1=character - 0x20; LcdWrite(LCD_D, 0x00); for (int index = 0; index < 5; index++) { z=EEPROM.read(z1*5+index); LcdWrite(LCD_D, z); // LcdWrite(LCD_D,ASCII[character - 0x20][index]); } LcdWrite(LCD_D, 0x00); } void LcdCharacterX(char character) { unsigned char z,z1; z1=character - 0x20; // z1=character; LcdWrite(LCD_D, 0x00); for (int index = 0; index < 5; index++) { //para que funciona en proteus z=EEPROM.read(z1*5+index); LcdWrite(LCD_D, z); LcdWrite(LCD_D, z); } LcdWrite(LCD_D, 0x00); } void LcdClear(void) { for (int index = 0; index < LCD_X * LCD_Y / 8; index++) { LcdWrite(LCD_D, 0x00); } } void LcdInitialise(void) { pinMode(PIN_SCE, OUTPUT); pinMode(PIN_RESET, OUTPUT); pinMode(PIN_DC, OUTPUT); pinMode(PIN_SDIN, OUTPUT); pinMode(PIN_SCLK, OUTPUT); digitalWrite(PIN_RESET, LOW); digitalWrite(PIN_RESET, HIGH); LcdWrite(LCD_CMD, 0x21); // LCD Extended Commands. LcdWrite(LCD_CMD, 0xB5); // Set LCD Vop (Contrast). //B1 LcdWrite(LCD_CMD, 0x04); // Set Temp coefficent. //0x04 LcdWrite(LCD_CMD, 0x01); // LCD bias mode 1:48. //0x13 LcdWrite(LCD_CMD, 0x0C); // LCD in normal mode. 0x0d LcdWrite(LCD_C, 0x20); LcdWrite(LCD_C, 0x0C); } void LcdString(char *characters) { while (*characters) { LcdCharacter(*characters++); } } void LcdStringX(char *characters) { while (*characters) { LcdCharacterX(*characters++); } } void LcdWrite(byte dc, byte data) { digitalWrite(PIN_DC, dc); digitalWrite(PIN_SCE, LOW); shiftOut(PIN_SDIN, PIN_SCLK, MSBFIRST, data); digitalWrite(PIN_SCE, HIGH); } /** * gotoXY routine to position cursor * x - range: 0 to 84 * y - range: 0 to 5 */ void gotoXY(int x, int y) { LcdWrite( 0, 0x80 | x); // Column. LcdWrite( 0, 0x40 | y); // Row. } void drawBox(void) { int j; for(j = 0; j < 84; j++) // top { gotoXY(j, 0); LcdWrite(1, 0x01); } for(j = 0; j < 84; j++) //Bottom { gotoXY(j, 5); LcdWrite(1, 0x80); } for(j = 0; j < 6; j++) // Right { gotoXY(83, j); LcdWrite(1, 0xff); } for(j = 0; j < 6; j++) // Left { gotoXY(0, j); LcdWrite(1, 0xff); } } void Scroll(String message) { for (int i = scrollPosition; i < scrollPosition + 11; i++) { if ((i >= message.length()) || (i < 0)) { LcdCharacter(' '); } else { LcdCharacter(message.charAt(i)); } } scrollPosition++; if ((scrollPosition >= message.length()) && (scrollPosition > 0)) { scrollPosition = -10; } }
Commentaires