Components and supplies
BOM: see the parts in the schematics and in the text.
Apps and platforms
Arduino IDE
Project description
Code
DSP Radio Receiver Code Rev. 2.5
c_cpp
Just load it to Arduino Nano
1/********************************************************************************************************************************************************* 2 Si473x LW/MW/SW/CB AM/FM Stereo RDS Radio Receiver w/ ST7735 TFT Display and Arduino Nano/Uno - AM 150kHz To 30MHz - FM 64 to 108MHz Stereo with RDS. 3 Please see the schematics for wiring connections and install all needed libraries that are located in the "INSTALL THESE LIBRARIES" folder. 4 By J.CesarSound - ver 2.5 - Mar/2021. 5**********************************************************************************************************************************************************/ 6 7//Libraries 8#include <EEPROM.h> //IDE Standard 9#include <SPI.h> //IDE Standard 10#include "Wire.h" //IDE Standard 11#include <TFT_ST7735.h> //BODMER graphics and font library for ST7735 TFT display 12#include <Si4735.h> //Michael Kennedy SI4735 I2C library modified by J.CesarSound 13#include <Rotary.h> //Ben Buxton https://github.com/brianlow/Rotary 14 15//User preferences 16//------------------------------------------------------------------------------------------------------------------------------------------- 17#define SI7435_ADDRESS 0x63 //Si473x I2C address (0x11 = sen pin to GND or 0x63 = sen pin to 3v3), module PL102BA-S V2 uses 0x63 18#define pb_0 A0 //AM mode and AM Band selector: short press AM / UP band, long press DOWN band 19#define pb_1 A1 //Save current frequency, band, theme to EEPROM and Tuning Step selector: short press SAVE, long press Tstep 20#define pb_2 A2 //Bandwidth IF Filter selector for AM and FM 21#define pb_3 A3 //FM mode, RDS program type and color theme selector: short press FM / RDS type, long press switch color theme 22//-------------------------------------------------------------------------------------------------------------------------------------------- 23 24TFT_ST7735 tft = TFT_ST7735(); 25Rotary r = Rotary(2, 3); 26Si4735 radio; 27 28unsigned int freq, fstep, freqold; 29unsigned int freq_eeprom_am, freq_eeprom_fm; 30int sm, sm_old, mx, sn, texsw = 0; 31int stp = 2; 32int mode = 2; 33byte fr_eeprom_h, fr_eeprom_l, sts_am_fm, sts_theme; 34byte encoder = 1, push_count = 0; 35byte count, ctr; 36byte filter = 0x03; 37byte fil = 4; 38byte fr_h; 39byte fr_l; 40byte ssb_m = 0x00; 41byte mw_sw = 0x00; 42byte am_fm; 43bool hasRun = false, hasRun1 = false, hasRun2 = false, hasRun3 = false, rds_t = false; 44unsigned int period = 0; 45unsigned long time_now = 0; 46unsigned int period_rds = 500; 47unsigned long time_now_rds = 0; 48unsigned int ca, cb, cc, cd, ce, cf, cg, ch; 49bool buttonActive_0 = false, buttonActive_1 = false, longPressActive = false; 50unsigned int longPressTime = 600; 51unsigned long buttonTimer = 0; 52 53void setup() { 54 tft.init(); 55 tft.setRotation(3); 56 Wire.begin(); 57 start_msg(); 58 tft.fillScreen(ca); 59 60 pinMode(pb_0, INPUT_PULLUP); 61 pinMode(pb_1, INPUT_PULLUP); 62 pinMode(pb_2, INPUT_PULLUP); 63 pinMode(pb_3, INPUT_PULLUP); 64 65 if (digitalRead(A1) == LOW) { 66 tft.fillScreen(TFT_BLUE); tft.setTextColor(TFT_WHITE, TFT_BLUE); tft.drawString("* DEFAULT VALUES *", 12, 58, 2); 67 delay(500); 68 am_fm = 0x20; 69 freq = 10050; 70 EEPROM.write(5, 6); 71 eeprom_write(); 72 } 73 74 PCICR |= (1 << PCIE2); 75 PCMSK2 |= (1 << PCINT18) | (1 << PCINT19); 76 sei(); 77 78 eeprom_read(); sts_theme = EEPROM.read(6); 79 if (sts_theme == false) blue_theme(); else black_theme(); 80 if (sts_am_fm == false) am_init(); else fm_init(); 81} 82 83void loop() { 84 if (freqold != freq) { 85 freqold = freq; 86 tune_freq(); 87 frequency(); 88 if (am_fm != 0x20) band_ind(); 89 } 90 91 if (digitalRead(pb_0) == LOW) { 92 delay(100); 93 if (buttonActive_0 == false) { 94 buttonActive_0 = true; 95 buttonTimer = millis(); 96 } 97 if ((millis() - buttonTimer > longPressTime) && (longPressActive == false)) { 98 longPressActive = true; 99 dec_preset(); 100 } 101 } else { 102 if (buttonActive_0 == true) { 103 if (longPressActive == true) { 104 longPressActive = false; 105 } else { 106 inc_preset(); 107 } 108 buttonActive_0 = false; 109 } 110 } 111 112 if (digitalRead(pb_1) == LOW) { 113 delay(100); 114 if (buttonActive_1 == false) { 115 buttonActive_1 = true; 116 buttonTimer = millis(); 117 } 118 if ((millis() - buttonTimer > longPressTime) && (longPressActive == false)) { 119 longPressActive = true; 120 if (am_fm != 0x20) inc_step(); 121 if (am_fm == 0x20) setstepFM(); 122 } 123 } else { 124 if (buttonActive_1 == true) { 125 if (longPressActive == true) { 126 longPressActive = false; 127 } else { 128 eeprom_write(); 129 } 130 buttonActive_1 = false; 131 } 132 } 133 134 if ((digitalRead(pb_2)) == LOW) { 135 delay(200); 136 if (am_fm != 0x20) filterAM(); 137 if (am_fm == 0x20) filterFM(); 138 while (digitalRead(pb_2) == LOW); 139 } 140 141 if (digitalRead(pb_3) == LOW) { 142 delay(500); 143 if (am_fm != 0x20) { 144 fm_init(); 145 } else rds_t = !rds_t; 146 tft.drawString(" ", 0, 74, 2); 147 148 push_count++; 149 if (push_count > 2) { 150 sw_theme(); 151 while (digitalRead(pb_3) == LOW); 152 } 153 } else push_count = 0; 154 155 if (millis() > time_now + period) { 156 time_now = millis(); 157 rsq(); 158 smeter(); 159 snmeter(); 160 if (am_fm == 0x20) pilot(); 161 } 162 163 if (am_fm == 0x20) { 164 if (millis() > time_now_rds + period_rds) { 165 time_now_rds = millis(); 166 rds(); 167 } 168 } 169} 170 171ISR(PCINT2_vect) { 172 char result = r.process(); 173 if (result == DIR_CW) set_frequency(1); 174 else if (result == DIR_CCW) set_frequency(-1); 175} 176 177void set_frequency(short dir) { 178 if (encoder == 1) { 179 if (dir == 1) freq = freq + fstep; 180 if (freq >= 30000) freq = 30000; 181 if (dir == -1) freq = freq - fstep; 182 if (freq <= 150) freq = 150; 183 } 184 if (encoder == 2) { 185 if (dir == 1) freq = freq + fstep; 186 if (freq >= 10810) freq = 10810; 187 if (dir == -1) freq = freq - fstep; 188 if (freq <= 6410) freq = 6410; 189 } 190} 191 192void inc_preset() { 193 count++; 194 if (count > 14) count = 1; 195 bandpresets(); 196} 197 198void dec_preset() { 199 count--; 200 if (count < 1) count = 14; 201 bandpresets(); 202} 203 204void bandpresets() { 205 tft.setTextSize(1); tft.setTextColor(cb, ca); tft.drawString(" ", 30, 57, 2); 206 switch (count) { 207 case 1: 208 freq = 198; 209 stp = 1; 210 setstep(); 211 break; 212 case 2: 213 freq = 522; 214 stp = 4; 215 setstep(); 216 break; 217 case 3: 218 freq = 520; 219 stp = 3; 220 setstep(); 221 break; 222 case 4: 223 freq = 3700; 224 stp = 2; 225 setstep(); 226 break; 227 case 5: 228 freq = 5000; 229 stp = 2; 230 setstep(); 231 break; 232 case 6: 233 freq = 6100; 234 stp = 2; 235 setstep(); 236 break; 237 case 7: 238 freq = 7200; 239 stp = 2; 240 setstep(); 241 break; 242 case 8: 243 freq = 10000; 244 stp = 2; 245 setstep(); 246 break; 247 case 9: 248 freq = 11940; 249 stp = 2; 250 setstep(); 251 break; 252 case 10: 253 freq = 13790; 254 stp = 2; 255 setstep(); 256 break; 257 case 11: 258 freq = 15400; 259 stp = 2; 260 setstep(); 261 break; 262 case 12: 263 freq = 17780; 264 stp = 2; 265 setstep(); 266 break; 267 case 13: 268 freq = 21525; 269 stp = 2; 270 setstep(); 271 break; 272 case 14: 273 freq = 27015; 274 stp = 2; 275 setstep(); 276 break; 277 } 278 if (hasRun2 == false) { 279 am_init(); hasRun2 = true; 280 } 281 if (count >= 1 && count <= 4) period = 4000; else period = 500; band_ind(); 282} 283 284void filterAM() { 285 tft.setTextSize(1); 286 tft.setTextColor(cb, ca); 287 switch (fil) { 288 case 0: 289 fil = 1; 290 filter = 0x00; tft.drawString("6k ", 135, 92, 2); 291 break; 292 case 1: 293 fil = 2; 294 filter = 0x01; tft.drawString("4k ", 135, 92, 2); 295 break; 296 case 2: 297 fil = 3; 298 filter = 0x02; tft.drawString("3k ", 135, 92, 2); 299 break; 300 case 3: 301 fil = 4; 302 filter = 0x06; tft.drawString("2k5", 135, 92, 2); 303 break; 304 case 4: 305 fil = 5; 306 filter = 0x03; tft.drawString("2k ", 135, 92, 2); 307 break; 308 case 5: 309 fil = 6; 310 filter = 0x05; tft.drawString("1k8", 135, 92, 2); 311 break; 312 case 6: 313 fil = 0; 314 filter = 0x04; tft.drawString("1k ", 135, 92, 2); 315 break; 316 } 317 property_filter_AM(); 318} 319 320void filterFM() { 321 tft.setTextSize(1); 322 tft.setTextColor(cb, ca); 323 switch (fil) { 324 case 0: 325 fil = 1; 326 filter = 0x00; tft.drawString("Aut", 135, 92, 2); 327 break; 328 case 1: 329 fil = 2; 330 filter = 0x01; tft.drawString("110", 134, 92, 2); 331 break; 332 case 2: 333 fil = 3; 334 filter = 0x02; tft.drawString("84k", 135, 92, 2); 335 break; 336 case 3: 337 fil = 4; 338 filter = 0x03; tft.drawString("60k", 135, 92, 2); 339 break; 340 case 4: 341 fil = 0; 342 filter = 0x04; tft.drawString("40k", 135, 92, 2); 343 break; 344 } 345 fm_command(); 346} 347 348void inc_step() { 349 ctr++; if (ctr > 3) ctr = 1; 350 byte eu[3] = {1, 4, 1}; byte us[3] = {1, 2, 3}; 351 if (count == 2) stp = eu[ctr]; 352 if (count != 2) stp = us[ctr]; 353 setstep(); 354} 355 356void setstep() { 357 tft.setTextSize(1); 358 tft.setTextColor(cb, ca); 359 switch (stp) { 360 case 1: 361 fstep = 1; 362 tft.drawString(" 1k", 100, 57, 2); 363 break; 364 case 2: 365 fstep = 5; 366 tft.drawString(" 5k", 100, 57, 2); 367 break; 368 case 3: 369 fstep = 10; 370 tft.drawString("10k", 100, 57, 2); 371 break; 372 case 4: 373 fstep = 9; 374 tft.drawString(" 9k", 100, 57, 2); 375 break; 376 } 377} 378 379void setstepFM() { 380 tft.setTextSize(1); 381 tft.setTextColor(cb, ca); 382 switch (stp) { 383 case 0: 384 stp = 1; 385 fstep = 10; // 100kHz 386 tft.drawString(" x1 ", 100, 57, 2); 387 break; 388 case 1: 389 stp = 0; 390 fstep = 20; // 200kHz 391 tft.drawString(" x2 ", 100, 57, 2); 392 break; 393 } 394} 395 396void frequency() { 397 tft.setTextColor(cg, ca); 398 if (freq >= 10000) tft.drawNumber(freq, 0, 1, 7); if (freq < 10000 && freq >= 1000) tft.drawNumber(freq, 32, 1, 7); 399 if (freq < 1000 && freq >= 100) tft.drawNumber(freq, 64, 1, 7); if (freq < 100 && freq >= 10) tft.drawNumber(freq, 96, 1, 7); 400 if (freq < 10) tft.drawNumber(freq, 128, 1, 7); if (freq < 10000) tft.fillRect (2, 1, 28, 48, ca); 401 if (freq < 1000) tft.fillRect (34, 1, 28, 48, ca); 402 403 if (am_fm == 0x40 && freq >= 1000) tft.fillCircle(63, 51, 2, cg); else tft.fillCircle(63, 51, 2, ca); 404 if (am_fm == 0x20) tft.fillCircle(95, 51, 2, cg); else tft.fillCircle(95, 51, 2, ca); 405} 406 407void snmeter() { 408 if (sn > 42) sn = 42; 409 byte range; if (am_fm == 0x20) range = 42; else range = 28; 410 byte sn_g = map(sn, 0, range, 0, 65); 411 tft.fillRect(31, 95, sn_g, 11, ce); 412 tft.fillRect(31 + sn_g, 95, 65 - sn_g, 11, cf); 413} 414 415void smeter() { 416 if (sm > 90) sm = 90; mx = sm; 417 tft.fillRect(31, 113, sm, 11, cd); 418 tft.fillRect(31 + sm, 113, 90 - sm, 11, cf); 419 420 tft.setTextSize(1); 421 tft.setTextColor(cb, ca); 422 if (mx < 1) tft.drawString(" S0", 130, 111, 2); 423 if ((mx >= 1) && (mx < 10)) tft.drawString(" S1", 130, 111, 2); 424 if ((mx >= 10) && (mx < 25)) tft.drawString(" S3", 130, 111, 2); 425 if ((mx >= 25) && (mx < 35)) tft.drawString(" S5", 130, 111, 2); 426 if ((mx >= 35) && (mx < 50)) tft.drawString(" S7", 130, 111, 2); 427 if ((mx >= 50) && (mx < 60)) tft.drawString(" S9", 130, 111, 2); 428 if ((mx >= 60) && (mx < 70)) tft.drawString("+10", 130, 111, 2); 429 if ((mx >= 70) && (mx < 75)) tft.drawString("+20", 130, 111, 2); 430 if ((mx >= 75) && (mx < 80)) tft.drawString("+40", 130, 111, 2); 431 if (mx >= 80) tft.drawString("+60", 130, 111, 2); 432} 433 434void layout() { 435 tft.setTextColor(TFT_WHITE, TFT_BLUE); 436 tft.drawFastHLine(0, 56, 160, cc); 437 tft.drawFastVLine(125, 59, 12, cc); 438 tft.drawFastHLine(0, 73, 160, cc); 439 tft.drawFastHLine(0, 91, 160, cc); 440 tft.drawFastHLine(0, 109, 160, cc); 441 442 tft.drawFastHLine(30, 106, 67, cc); tft.drawFastHLine(30, 124, 92, cc); 443 tft.drawFastVLine(30, 95, 11, cc); tft.drawFastVLine(30, 113, 11, cc); 444 tft.drawFastVLine(96, 102, 4, cc); tft.drawFastVLine(121, 120, 4, cc); 445 446 tft.setTextSize(1); 447 tft.setTextColor(cb, ca); 448 tft.drawString("Ts", 85, 57, 2); 449 tft.drawString("S/N", 3, 92, 2); 450 tft.drawString("BWF", 105, 92, 2); 451 tft.drawString("SIG", 3, 111, 2); 452} 453 454void start_msg() { 455 tft.fillScreen(TFT_BLACK); 456 tft.setTextSize(1); 457 tft.setTextColor(TFT_WHITE, TFT_BLACK); 458 tft.drawString("JCR RADIO", 48, 20, 2); 459 tft.drawString("AM/FM RDS Receiver", 15, 50, 2); 460 tft.drawString("VER 2.5 - MAR/2021", 15, 80, 2); 461 delay(1600); 462} 463 464void band_ind() { 465 tft.setTextSize(1); tft.setTextColor(cb, ca); 466 if (freq >= 1800 && freq <= 2000) tft.drawString("160m ", 30, 57, 2); if (freq >= 2300 && freq <= 2495) tft.drawString("120m", 30, 57, 2); 467 if (freq >= 3200 && freq <= 3400) tft.drawString("90m ", 30, 57, 2); if (freq >= 3500 && freq <= 3800) tft.drawString("80m", 30, 57, 2); 468 if (freq >= 3900 && freq <= 4000) tft.drawString("75m", 30, 57, 2); if (freq >= 4750 && freq <= 5500) tft.drawString("60m", 30, 57, 2); 469 if (freq >= 5700 && freq <= 6200) tft.drawString("49m", 30, 57, 2); if (freq >= 7000 && freq <= 7299) tft.drawString("40m", 30, 57, 2); 470 if (freq >= 7300 && freq <= 7600) tft.drawString("41m", 30, 57, 2); if (freq >= 9400 && freq <= 10000) tft.drawString("31m", 30, 57, 2); 471 if (freq >= 10100 && freq <= 10150) tft.drawString("30m", 30, 57, 2); if (freq >= 11600 && freq <= 12100) tft.drawString("25m", 30, 57, 2); 472 if (freq >= 13570 && freq <= 13870) tft.drawString("22m", 30, 57, 2); if (freq >= 14000 && freq <= 14350) tft.drawString("20m", 30, 57, 2); 473 if (freq >= 15100 && freq <= 15830) tft.drawString("19m", 30, 57, 2); if (freq >= 18068 && freq <= 18168) tft.drawString("17m", 30, 57, 2); 474 if (freq >= 17480 && freq <= 17900) tft.drawString("16m", 30, 57, 2); if (freq >= 21000 && freq <= 21450) tft.drawString("15m", 30, 57, 2); 475 if (freq >= 21451 && freq <= 21850) tft.drawString("13m", 30, 57, 2); if (freq >= 24890 && freq <= 24990) tft.drawString("12m", 30, 57, 2); 476 if (freq >= 25670 && freq <= 27999) tft.drawString("11m", 30, 57, 2); if (freq >= 28000 && freq <= 29700) tft.drawString("10m", 30, 57, 2); 477 if (freq >= 150 && freq <= 515) tft.drawString("LW ", 30, 57, 2); 478 if (freq >= 520 && freq <= 1710 && count == 3) tft.drawString("MW US", 30, 57, 2); 479 if (freq >= 522 && freq <= 1728 && count == 2) tft.drawString("MW EU", 30, 57, 2); 480} 481 482void tune_freq() { 483 fr_h = (freq) >> 8; 484 fr_l = (freq) & 0x00FF; 485 if ((freq) < 1800) mw_sw = 0x00; else (mw_sw = 0x01); 486 tune(); 487} 488 489void rsq() { 490 RSQMetrics rsq; 491 radio.getRSQ(&rsq); 492 sm = (rsq.RSSI); 493 sn = (rsq.SNR) * 0.5 + sn * 0.5; 494} 495 496void pilot() { 497 RSQMetrics rsq; 498 radio.getRSQ(&rsq); 499 tft.setTextSize(1); 500 501 if (rsq.stereo == 1 && hasRun1 == false) { 502 tft.setTextColor(TFT_WHITE, ca); tft.drawString(" Stereo ", 30, 57, 2); hasRun1 = true; 503 } 504 if (rsq.stereo == 0 && hasRun1 == true) { 505 tft.setTextColor(TFT_DARKGREY, ca); tft.drawString(" Stereo ", 30, 57, 2); hasRun1 = false; 506 } 507} 508 509void rds() { 510 radio.getRDS(); 511 512 if (rds_t == false) { 513 if (radio.rds.RDSSignal) { 514 texsw++; if (texsw > 60) texsw = 1; 515 tft.setTextSize(1); tft.setTextColor(cb, ca); 516 if (hasRun == false) { 517 tft.drawString(" ", 0, 74, 2); 518 hasRun = true; 519 } 520 tft.drawString("RDS ", 3, 74, 2); 521 if (texsw > 0 && texsw < 41) tft.drawString(radio.rds.programService, 60, 74, 2); 522 if (texsw == 41) tft.drawString(" ", 33, 74, 2); 523 if (texsw > 40 && texsw < 61) tft.drawString(radio.rds.radioText, 33, 74, 2); 524 if (texsw == 1) tft.drawString(" ", 33, 74, 2); 525 hasRun3 = false; 526 } else { 527 radio.clearStationInfo(); 528 tft.setTextColor(cb, ca); tft.fillRect (0, 75, 3, 15, ca); 529 if (hasRun3 == false) { 530 tft.drawString("RDS No Information ", 3, 74, 2); 531 hasRun3 = true; 532 } 533 hasRun = false; 534 } 535 } 536 537 if (rds_t == true) { 538 if (radio.rds.RDSSignal) { 539 texsw += 8; if (texsw > 296) texsw = 0; 540 tft.setTextSize(1); tft.setTextColor(cb, ca); 541 if (hasRun == false) { 542 tft.drawString(" ", 0, 74, 2); 543 hasRun = true; 544 } 545 tft.drawString(radio.rds.radioText, 20 - texsw, 74, 2); tft.fillRect (156, 75, 4, 15, ca); 546 if (texsw == 296) tft.drawString(" ", 0, 74, 2); 547 hasRun3 = false; 548 } else { 549 radio.clearStationInfo(); texsw = 0; 550 tft.setTextColor(cb, ca); tft.fillRect (0, 75, 3, 15, ca); 551 if (hasRun3 == false) { 552 tft.drawString("RDS No Information ", 3, 74, 2); 553 hasRun3 = true; 554 } 555 hasRun = false; 556 } 557 } 558} 559 560void am_init() { 561 encoder = 1; 562 radio.begin(0, SI7435_ADDRESS); 563 power_down(); 564 power_up_norm(); 565 delay(400); 566 am_fm = 0x40; 567 ssb_m = 0x00; 568 eeprom_read(); 569 freq = freq_eeprom_am; 570 if (count == 2) stp = 4; else stp = 2; setstep(); 571 tune(); 572 am_command(); 573 filter = 0x03; layout(); frequency(); if (count >= 1 && count <= 4) period = 4000; else period = 500; 574 tft.setTextColor(cg, ca); tft.drawString("kHz ", 132, 57, 2); tft.setTextColor(cb, ca); tft.drawString("AM ", 3, 57, 2); 575 tft.drawString(" AM/FM RDS Receiver ", 0, 74, 2); tft.drawString("2k ", 135, 92, 2); 576 tft.drawString(" ", 30, 57, 2); 577} 578 579void fm_init() { 580 encoder = 2; 581 radio.begin(0, SI7435_ADDRESS); 582 power_down(); 583 power_up_FM(); 584 delay(400); 585 am_fm = 0x20; 586 ssb_m = 0x00; 587 eeprom_read(); 588 freq = freq_eeprom_fm; 589 tune(); pilot(); 590 radio.setMode(FM); 591 fil = 0; filterFM(); 592 stp = 0; setstepFM(); fm_command(); 593 hasRun2 = false; count--; layout(); frequency(); period = 2000; 594 tft.setTextColor(cg, ca); tft.drawString("MHz", 132, 57, 2); tft.setTextColor(cb, ca); tft.drawString("FM ", 3, 57, 2); 595 tft.setTextColor(TFT_DARKGREY, ca); tft.drawString(" Stereo ", 30, 57, 2); 596} 597 598void sw_theme() { 599 sts_theme = !sts_theme; 600 if (sts_theme == false) blue_theme(); else black_theme(); 601 tft.fillScreen(ca); tft.setTextColor(cb, ca); 602 hasRun1 = !hasRun1; 603 fm_init(); 604 if (am_fm != 0x20) { 605 fil = 4; filterAM(); 606 } 607 if (am_fm == 0x20) { 608 fil = 0; filterFM(); 609 } 610} 611 612void blue_theme() { 613 ca = TFT_BLUE; //Screen background 614 cb = TFT_WHITE; //Texts 615 cc = TFT_LIGHTGREY; //Lines 616 cd = TFT_GREEN; //S-Meter bargraph 617 ce = TFT_MAGENTA; //S/N bargraph 618 cf = TFT_BLUE; //Bargraph background 619 cg = TFT_WHITE; //Frequency and kHz MHz 620 ch = TFT_CYAN; //Reserved 621 tft.fillScreen(ca); 622} 623 624void black_theme() { 625 ca = TFT_BLACK; //Screen background 626 cb = TFT_WHITE; //Texts 627 cc = TFT_LIGHTGREY; //Lines 628 cd = TFT_GREEN; //S-Meter bargraph 629 ce = TFT_MAGENTA; //S/N bargraph 630 cf = TFT_BLACK; //Bargraph background 631 cg = TFT_CYAN; //Frequency and kHz MHz 632 ch = TFT_RED; //Reserved 633 tft.fillScreen(ca); 634} 635 636void am_command() { 637 radio.setProperty(PROP_AM_SOFT_MUTE_MAX_ATTENUATION, 1); // 0 (OFF) - 63 638 radio.setProperty(PROP_AM_AUTOMATIC_VOLUME_CONTROL_MAX_GAIN, 0x32C8); // 0x1000 - 0x7800 639 radio.setProperty(PROP_AM_AGC_ATTACK_RATE, 4); // 4–248 640 radio.setProperty(PROP_AM_AGC_RELEASE_RATE, 4); // 4–248 641} 642 643void fm_command() { 644 radio.setProperty(PROP_FM_DEEMPHASIS, 0x0001); // 02 = 75 μs; 01 = 50 μs 645 radio.setProperty(PROP_FM_CHANNEL_FILTER, filter); // 0 = automat; 1 = 110kHz; 4 = 40kHz 646 radio.setProperty(PROP_FM_SOFT_MUTE_MAX_ATTENUATION, 0); // 0 = disable; 31 = max 647 radio.setProperty(PROP_FM_BLEND_STEREO_THRESHOLD, 0); // 0 = stereo; 127 = mono 648 radio.setProperty(PROP_FM_BLEND_MONO_THRESHOLD, 0); // 0 = stereo; 127 = mono 649} 650 651void power_down() { 652 Wire.beginTransmission(SI7435_ADDRESS); 653 Wire.write(0x11); 654 Wire.endTransmission(); 655 delay(1); 656} 657 658void power_up_norm() { 659 Wire.beginTransmission(SI7435_ADDRESS); 660 Wire.write(0x01); 661 Wire.write(0x11); 662 Wire.write(0x05); 663 Wire.endTransmission(); 664 delay(1); 665} 666 667void power_up_FM() { 668 Wire.beginTransmission(SI7435_ADDRESS); 669 Wire.write(0x01); 670 Wire.write(0x10); 671 Wire.write(0x05); 672 Wire.endTransmission(); 673 delay(1); 674} 675 676void tune() { 677 Wire.beginTransmission(SI7435_ADDRESS); 678 Wire.write(am_fm); 679 Wire.write(ssb_m); 680 Wire.write(fr_h); 681 Wire.write(fr_l); 682 Wire.write(0x00); 683 Wire.write(mw_sw); 684 Wire.endTransmission(); 685 delay(1); 686} 687 688void property_filter_AM() { 689 Wire.beginTransmission(SI7435_ADDRESS); 690 Wire.write(0x12); 691 Wire.write(0x00); 692 Wire.write(0x31); 693 Wire.write(0x02); 694 Wire.write(0x00); 695 Wire.write(filter); 696 Wire.endTransmission(); 697 delay(1); 698} 699 700void eeprom_write() { 701 if (am_fm == 0x20) { 702 fr_eeprom_h = (freq) >> 8; 703 fr_eeprom_l = (freq) & 0x00FF; 704 EEPROM.write(0, fr_eeprom_l); 705 EEPROM.write(1, fr_eeprom_h); 706 EEPROM.write(2, 1); 707 } 708 if (am_fm != 0x20) { 709 fr_eeprom_h = (freq) >> 8; 710 fr_eeprom_l = (freq) & 0x00FF; 711 EEPROM.write(3, fr_eeprom_l); 712 EEPROM.write(4, fr_eeprom_h); 713 EEPROM.write(2, 0); 714 EEPROM.write(5, count); 715 } 716 EEPROM.write(6, sts_theme); 717 tft.setTextColor(TFT_WHITE, TFT_MAGENTA); tft.drawString("SAVE", 126, 111, 2); 718 delay(1500); 719 tft.setTextColor(cb, ca); tft.drawString(" ", 126, 111, 2); 720 delay(300); 721} 722 723void eeprom_read() { 724 if (am_fm == 0x20) { 725 fr_eeprom_l = EEPROM.read(0); 726 fr_eeprom_h = EEPROM.read(1); 727 freq_eeprom_fm = (fr_eeprom_h << 8U) | fr_eeprom_l; 728 } 729 if (am_fm != 0x20) { 730 fr_eeprom_l = EEPROM.read(3); 731 fr_eeprom_h = EEPROM.read(4); 732 freq_eeprom_am = (fr_eeprom_h << 8U) | fr_eeprom_l; 733 count = EEPROM.read(5); 734 } 735 sts_am_fm = EEPROM.read(2); 736}
DSP Radio Receiver Code Rev. 2.5
c_cpp
Just load it to Arduino Nano
1/********************************************************************************************************************************************************* 2 Si473x LW/MW/SW/CB AM/FM Stereo RDS Radio Receiver w/ ST7735 TFT Display and Arduino Nano/Uno - AM 150kHz To 30MHz - FM 64 to 108MHz Stereo with RDS. 3 Please see the schematics for wiring connections and install all needed libraries that are located in the "INSTALL THESE LIBRARIES" folder. 4 By J.CesarSound - ver 2.5 - Mar/2021. 5**********************************************************************************************************************************************************/ 6 7//Libraries 8#include <EEPROM.h> //IDE Standard 9#include <SPI.h> //IDE Standard 10#include "Wire.h" //IDE Standard 11#include <TFT_ST7735.h> //BODMER graphics and font library for ST7735 TFT display 12#include <Si4735.h> //Michael Kennedy SI4735 I2C library modified by J.CesarSound 13#include <Rotary.h> //Ben Buxton https://github.com/brianlow/Rotary 14 15//User preferences 16//------------------------------------------------------------------------------------------------------------------------------------------- 17#define SI7435_ADDRESS 0x63 //Si473x I2C address (0x11 = sen pin to GND or 0x63 = sen pin to 3v3), module PL102BA-S V2 uses 0x63 18#define pb_0 A0 //AM mode and AM Band selector: short press AM / UP band, long press DOWN band 19#define pb_1 A1 //Save current frequency, band, theme to EEPROM and Tuning Step selector: short press SAVE, long press Tstep 20#define pb_2 A2 //Bandwidth IF Filter selector for AM and FM 21#define pb_3 A3 //FM mode, RDS program type and color theme selector: short press FM / RDS type, long press switch color theme 22//-------------------------------------------------------------------------------------------------------------------------------------------- 23 24TFT_ST7735 tft = TFT_ST7735(); 25Rotary r = Rotary(2, 3); 26Si4735 radio; 27 28unsigned int freq, fstep, freqold; 29unsigned int freq_eeprom_am, freq_eeprom_fm; 30int sm, sm_old, mx, sn, texsw = 0; 31int stp = 2; 32int mode = 2; 33byte fr_eeprom_h, fr_eeprom_l, sts_am_fm, sts_theme; 34byte encoder = 1, push_count = 0; 35byte count, ctr; 36byte filter = 0x03; 37byte fil = 4; 38byte fr_h; 39byte fr_l; 40byte ssb_m = 0x00; 41byte mw_sw = 0x00; 42byte am_fm; 43bool hasRun = false, hasRun1 = false, hasRun2 = false, hasRun3 = false, rds_t = false; 44unsigned int period = 0; 45unsigned long time_now = 0; 46unsigned int period_rds = 500; 47unsigned long time_now_rds = 0; 48unsigned int ca, cb, cc, cd, ce, cf, cg, ch; 49bool buttonActive_0 = false, buttonActive_1 = false, longPressActive = false; 50unsigned int longPressTime = 600; 51unsigned long buttonTimer = 0; 52 53void setup() { 54 tft.init(); 55 tft.setRotation(3); 56 Wire.begin(); 57 start_msg(); 58 tft.fillScreen(ca); 59 60 pinMode(pb_0, INPUT_PULLUP); 61 pinMode(pb_1, INPUT_PULLUP); 62 pinMode(pb_2, INPUT_PULLUP); 63 pinMode(pb_3, INPUT_PULLUP); 64 65 if (digitalRead(A1) == LOW) { 66 tft.fillScreen(TFT_BLUE); tft.setTextColor(TFT_WHITE, TFT_BLUE); tft.drawString("* DEFAULT VALUES *", 12, 58, 2); 67 delay(500); 68 am_fm = 0x20; 69 freq = 10050; 70 EEPROM.write(5, 6); 71 eeprom_write(); 72 } 73 74 PCICR |= (1 << PCIE2); 75 PCMSK2 |= (1 << PCINT18) | (1 << PCINT19); 76 sei(); 77 78 eeprom_read(); sts_theme = EEPROM.read(6); 79 if (sts_theme == false) blue_theme(); else black_theme(); 80 if (sts_am_fm == false) am_init(); else fm_init(); 81} 82 83void loop() { 84 if (freqold != freq) { 85 freqold = freq; 86 tune_freq(); 87 frequency(); 88 if (am_fm != 0x20) band_ind(); 89 } 90 91 if (digitalRead(pb_0) == LOW) { 92 delay(100); 93 if (buttonActive_0 == false) { 94 buttonActive_0 = true; 95 buttonTimer = millis(); 96 } 97 if ((millis() - buttonTimer > longPressTime) && (longPressActive == false)) { 98 longPressActive = true; 99 dec_preset(); 100 } 101 } else { 102 if (buttonActive_0 == true) { 103 if (longPressActive == true) { 104 longPressActive = false; 105 } else { 106 inc_preset(); 107 } 108 buttonActive_0 = false; 109 } 110 } 111 112 if (digitalRead(pb_1) == LOW) { 113 delay(100); 114 if (buttonActive_1 == false) { 115 buttonActive_1 = true; 116 buttonTimer = millis(); 117 } 118 if ((millis() - buttonTimer > longPressTime) && (longPressActive == false)) { 119 longPressActive = true; 120 if (am_fm != 0x20) inc_step(); 121 if (am_fm == 0x20) setstepFM(); 122 } 123 } else { 124 if (buttonActive_1 == true) { 125 if (longPressActive == true) { 126 longPressActive = false; 127 } else { 128 eeprom_write(); 129 } 130 buttonActive_1 = false; 131 } 132 } 133 134 if ((digitalRead(pb_2)) == LOW) { 135 delay(200); 136 if (am_fm != 0x20) filterAM(); 137 if (am_fm == 0x20) filterFM(); 138 while (digitalRead(pb_2) == LOW); 139 } 140 141 if (digitalRead(pb_3) == LOW) { 142 delay(500); 143 if (am_fm != 0x20) { 144 fm_init(); 145 } else rds_t = !rds_t; 146 tft.drawString(" ", 0, 74, 2); 147 148 push_count++; 149 if (push_count > 2) { 150 sw_theme(); 151 while (digitalRead(pb_3) == LOW); 152 } 153 } else push_count = 0; 154 155 if (millis() > time_now + period) { 156 time_now = millis(); 157 rsq(); 158 smeter(); 159 snmeter(); 160 if (am_fm == 0x20) pilot(); 161 } 162 163 if (am_fm == 0x20) { 164 if (millis() > time_now_rds + period_rds) { 165 time_now_rds = millis(); 166 rds(); 167 } 168 } 169} 170 171ISR(PCINT2_vect) { 172 char result = r.process(); 173 if (result == DIR_CW) set_frequency(1); 174 else if (result == DIR_CCW) set_frequency(-1); 175} 176 177void set_frequency(short dir) { 178 if (encoder == 1) { 179 if (dir == 1) freq = freq + fstep; 180 if (freq >= 30000) freq = 30000; 181 if (dir == -1) freq = freq - fstep; 182 if (freq <= 150) freq = 150; 183 } 184 if (encoder == 2) { 185 if (dir == 1) freq = freq + fstep; 186 if (freq >= 10810) freq = 10810; 187 if (dir == -1) freq = freq - fstep; 188 if (freq <= 6410) freq = 6410; 189 } 190} 191 192void inc_preset() { 193 count++; 194 if (count > 14) count = 1; 195 bandpresets(); 196} 197 198void dec_preset() { 199 count--; 200 if (count < 1) count = 14; 201 bandpresets(); 202} 203 204void bandpresets() { 205 tft.setTextSize(1); tft.setTextColor(cb, ca); tft.drawString(" ", 30, 57, 2); 206 switch (count) { 207 case 1: 208 freq = 198; 209 stp = 1; 210 setstep(); 211 break; 212 case 2: 213 freq = 522; 214 stp = 4; 215 setstep(); 216 break; 217 case 3: 218 freq = 520; 219 stp = 3; 220 setstep(); 221 break; 222 case 4: 223 freq = 3700; 224 stp = 2; 225 setstep(); 226 break; 227 case 5: 228 freq = 5000; 229 stp = 2; 230 setstep(); 231 break; 232 case 6: 233 freq = 6100; 234 stp = 2; 235 setstep(); 236 break; 237 case 7: 238 freq = 7200; 239 stp = 2; 240 setstep(); 241 break; 242 case 8: 243 freq = 10000; 244 stp = 2; 245 setstep(); 246 break; 247 case 9: 248 freq = 11940; 249 stp = 2; 250 setstep(); 251 break; 252 case 10: 253 freq = 13790; 254 stp = 2; 255 setstep(); 256 break; 257 case 11: 258 freq = 15400; 259 stp = 2; 260 setstep(); 261 break; 262 case 12: 263 freq = 17780; 264 stp = 2; 265 setstep(); 266 break; 267 case 13: 268 freq = 21525; 269 stp = 2; 270 setstep(); 271 break; 272 case 14: 273 freq = 27015; 274 stp = 2; 275 setstep(); 276 break; 277 } 278 if (hasRun2 == false) { 279 am_init(); hasRun2 = true; 280 } 281 if (count >= 1 && count <= 4) period = 4000; else period = 500; band_ind(); 282} 283 284void filterAM() { 285 tft.setTextSize(1); 286 tft.setTextColor(cb, ca); 287 switch (fil) { 288 case 0: 289 fil = 1; 290 filter = 0x00; tft.drawString("6k ", 135, 92, 2); 291 break; 292 case 1: 293 fil = 2; 294 filter = 0x01; tft.drawString("4k ", 135, 92, 2); 295 break; 296 case 2: 297 fil = 3; 298 filter = 0x02; tft.drawString("3k ", 135, 92, 2); 299 break; 300 case 3: 301 fil = 4; 302 filter = 0x06; tft.drawString("2k5", 135, 92, 2); 303 break; 304 case 4: 305 fil = 5; 306 filter = 0x03; tft.drawString("2k ", 135, 92, 2); 307 break; 308 case 5: 309 fil = 6; 310 filter = 0x05; tft.drawString("1k8", 135, 92, 2); 311 break; 312 case 6: 313 fil = 0; 314 filter = 0x04; tft.drawString("1k ", 135, 92, 2); 315 break; 316 } 317 property_filter_AM(); 318} 319 320void filterFM() { 321 tft.setTextSize(1); 322 tft.setTextColor(cb, ca); 323 switch (fil) { 324 case 0: 325 fil = 1; 326 filter = 0x00; tft.drawString("Aut", 135, 92, 2); 327 break; 328 case 1: 329 fil = 2; 330 filter = 0x01; tft.drawString("110", 134, 92, 2); 331 break; 332 case 2: 333 fil = 3; 334 filter = 0x02; tft.drawString("84k", 135, 92, 2); 335 break; 336 case 3: 337 fil = 4; 338 filter = 0x03; tft.drawString("60k", 135, 92, 2); 339 break; 340 case 4: 341 fil = 0; 342 filter = 0x04; tft.drawString("40k", 135, 92, 2); 343 break; 344 } 345 fm_command(); 346} 347 348void inc_step() { 349 ctr++; if (ctr > 3) ctr = 1; 350 byte eu[3] = {1, 4, 1}; byte us[3] = {1, 2, 3}; 351 if (count == 2) stp = eu[ctr]; 352 if (count != 2) stp = us[ctr]; 353 setstep(); 354} 355 356void setstep() { 357 tft.setTextSize(1); 358 tft.setTextColor(cb, ca); 359 switch (stp) { 360 case 1: 361 fstep = 1; 362 tft.drawString(" 1k", 100, 57, 2); 363 break; 364 case 2: 365 fstep = 5; 366 tft.drawString(" 5k", 100, 57, 2); 367 break; 368 case 3: 369 fstep = 10; 370 tft.drawString("10k", 100, 57, 2); 371 break; 372 case 4: 373 fstep = 9; 374 tft.drawString(" 9k", 100, 57, 2); 375 break; 376 } 377} 378 379void setstepFM() { 380 tft.setTextSize(1); 381 tft.setTextColor(cb, ca); 382 switch (stp) { 383 case 0: 384 stp = 1; 385 fstep = 10; // 100kHz 386 tft.drawString(" x1 ", 100, 57, 2); 387 break; 388 case 1: 389 stp = 0; 390 fstep = 20; // 200kHz 391 tft.drawString(" x2 ", 100, 57, 2); 392 break; 393 } 394} 395 396void frequency() { 397 tft.setTextColor(cg, ca); 398 if (freq >= 10000) tft.drawNumber(freq, 0, 1, 7); if (freq < 10000 && freq >= 1000) tft.drawNumber(freq, 32, 1, 7); 399 if (freq < 1000 && freq >= 100) tft.drawNumber(freq, 64, 1, 7); if (freq < 100 && freq >= 10) tft.drawNumber(freq, 96, 1, 7); 400 if (freq < 10) tft.drawNumber(freq, 128, 1, 7); if (freq < 10000) tft.fillRect (2, 1, 28, 48, ca); 401 if (freq < 1000) tft.fillRect (34, 1, 28, 48, ca); 402 403 if (am_fm == 0x40 && freq >= 1000) tft.fillCircle(63, 51, 2, cg); else tft.fillCircle(63, 51, 2, ca); 404 if (am_fm == 0x20) tft.fillCircle(95, 51, 2, cg); else tft.fillCircle(95, 51, 2, ca); 405} 406 407void snmeter() { 408 if (sn > 42) sn = 42; 409 byte range; if (am_fm == 0x20) range = 42; else range = 28; 410 byte sn_g = map(sn, 0, range, 0, 65); 411 tft.fillRect(31, 95, sn_g, 11, ce); 412 tft.fillRect(31 + sn_g, 95, 65 - sn_g, 11, cf); 413} 414 415void smeter() { 416 if (sm > 90) sm = 90; mx = sm; 417 tft.fillRect(31, 113, sm, 11, cd); 418 tft.fillRect(31 + sm, 113, 90 - sm, 11, cf); 419 420 tft.setTextSize(1); 421 tft.setTextColor(cb, ca); 422 if (mx < 1) tft.drawString(" S0", 130, 111, 2); 423 if ((mx >= 1) && (mx < 10)) tft.drawString(" S1", 130, 111, 2); 424 if ((mx >= 10) && (mx < 25)) tft.drawString(" S3", 130, 111, 2); 425 if ((mx >= 25) && (mx < 35)) tft.drawString(" S5", 130, 111, 2); 426 if ((mx >= 35) && (mx < 50)) tft.drawString(" S7", 130, 111, 2); 427 if ((mx >= 50) && (mx < 60)) tft.drawString(" S9", 130, 111, 2); 428 if ((mx >= 60) && (mx < 70)) tft.drawString("+10", 130, 111, 2); 429 if ((mx >= 70) && (mx < 75)) tft.drawString("+20", 130, 111, 2); 430 if ((mx >= 75) && (mx < 80)) tft.drawString("+40", 130, 111, 2); 431 if (mx >= 80) tft.drawString("+60", 130, 111, 2); 432} 433 434void layout() { 435 tft.setTextColor(TFT_WHITE, TFT_BLUE); 436 tft.drawFastHLine(0, 56, 160, cc); 437 tft.drawFastVLine(125, 59, 12, cc); 438 tft.drawFastHLine(0, 73, 160, cc); 439 tft.drawFastHLine(0, 91, 160, cc); 440 tft.drawFastHLine(0, 109, 160, cc); 441 442 tft.drawFastHLine(30, 106, 67, cc); tft.drawFastHLine(30, 124, 92, cc); 443 tft.drawFastVLine(30, 95, 11, cc); tft.drawFastVLine(30, 113, 11, cc); 444 tft.drawFastVLine(96, 102, 4, cc); tft.drawFastVLine(121, 120, 4, cc); 445 446 tft.setTextSize(1); 447 tft.setTextColor(cb, ca); 448 tft.drawString("Ts", 85, 57, 2); 449 tft.drawString("S/N", 3, 92, 2); 450 tft.drawString("BWF", 105, 92, 2); 451 tft.drawString("SIG", 3, 111, 2); 452} 453 454void start_msg() { 455 tft.fillScreen(TFT_BLACK); 456 tft.setTextSize(1); 457 tft.setTextColor(TFT_WHITE, TFT_BLACK); 458 tft.drawString("JCR RADIO", 48, 20, 2); 459 tft.drawString("AM/FM RDS Receiver", 15, 50, 2); 460 tft.drawString("VER 2.5 - MAR/2021", 15, 80, 2); 461 delay(1600); 462} 463 464void band_ind() { 465 tft.setTextSize(1); tft.setTextColor(cb, ca); 466 if (freq >= 1800 && freq <= 2000) tft.drawString("160m ", 30, 57, 2); if (freq >= 2300 && freq <= 2495) tft.drawString("120m", 30, 57, 2); 467 if (freq >= 3200 && freq <= 3400) tft.drawString("90m ", 30, 57, 2); if (freq >= 3500 && freq <= 3800) tft.drawString("80m", 30, 57, 2); 468 if (freq >= 3900 && freq <= 4000) tft.drawString("75m", 30, 57, 2); if (freq >= 4750 && freq <= 5500) tft.drawString("60m", 30, 57, 2); 469 if (freq >= 5700 && freq <= 6200) tft.drawString("49m", 30, 57, 2); if (freq >= 7000 && freq <= 7299) tft.drawString("40m", 30, 57, 2); 470 if (freq >= 7300 && freq <= 7600) tft.drawString("41m", 30, 57, 2); if (freq >= 9400 && freq <= 10000) tft.drawString("31m", 30, 57, 2); 471 if (freq >= 10100 && freq <= 10150) tft.drawString("30m", 30, 57, 2); if (freq >= 11600 && freq <= 12100) tft.drawString("25m", 30, 57, 2); 472 if (freq >= 13570 && freq <= 13870) tft.drawString("22m", 30, 57, 2); if (freq >= 14000 && freq <= 14350) tft.drawString("20m", 30, 57, 2); 473 if (freq >= 15100 && freq <= 15830) tft.drawString("19m", 30, 57, 2); if (freq >= 18068 && freq <= 18168) tft.drawString("17m", 30, 57, 2); 474 if (freq >= 17480 && freq <= 17900) tft.drawString("16m", 30, 57, 2); if (freq >= 21000 && freq <= 21450) tft.drawString("15m", 30, 57, 2); 475 if (freq >= 21451 && freq <= 21850) tft.drawString("13m", 30, 57, 2); if (freq >= 24890 && freq <= 24990) tft.drawString("12m", 30, 57, 2); 476 if (freq >= 25670 && freq <= 27999) tft.drawString("11m", 30, 57, 2); if (freq >= 28000 && freq <= 29700) tft.drawString("10m", 30, 57, 2); 477 if (freq >= 150 && freq <= 515) tft.drawString("LW ", 30, 57, 2); 478 if (freq >= 520 && freq <= 1710 && count == 3) tft.drawString("MW US", 30, 57, 2); 479 if (freq >= 522 && freq <= 1728 && count == 2) tft.drawString("MW EU", 30, 57, 2); 480} 481 482void tune_freq() { 483 fr_h = (freq) >> 8; 484 fr_l = (freq) & 0x00FF; 485 if ((freq) < 1800) mw_sw = 0x00; else (mw_sw = 0x01); 486 tune(); 487} 488 489void rsq() { 490 RSQMetrics rsq; 491 radio.getRSQ(&rsq); 492 sm = (rsq.RSSI); 493 sn = (rsq.SNR) * 0.5 + sn * 0.5; 494} 495 496void pilot() { 497 RSQMetrics rsq; 498 radio.getRSQ(&rsq); 499 tft.setTextSize(1); 500 501 if (rsq.stereo == 1 && hasRun1 == false) { 502 tft.setTextColor(TFT_WHITE, ca); tft.drawString(" Stereo ", 30, 57, 2); hasRun1 = true; 503 } 504 if (rsq.stereo == 0 && hasRun1 == true) { 505 tft.setTextColor(TFT_DARKGREY, ca); tft.drawString(" Stereo ", 30, 57, 2); hasRun1 = false; 506 } 507} 508 509void rds() { 510 radio.getRDS(); 511 512 if (rds_t == false) { 513 if (radio.rds.RDSSignal) { 514 texsw++; if (texsw > 60) texsw = 1; 515 tft.setTextSize(1); tft.setTextColor(cb, ca); 516 if (hasRun == false) { 517 tft.drawString(" ", 0, 74, 2); 518 hasRun = true; 519 } 520 tft.drawString("RDS ", 3, 74, 2); 521 if (texsw > 0 && texsw < 41) tft.drawString(radio.rds.programService, 60, 74, 2); 522 if (texsw == 41) tft.drawString(" ", 33, 74, 2); 523 if (texsw > 40 && texsw < 61) tft.drawString(radio.rds.radioText, 33, 74, 2); 524 if (texsw == 1) tft.drawString(" ", 33, 74, 2); 525 hasRun3 = false; 526 } else { 527 radio.clearStationInfo(); 528 tft.setTextColor(cb, ca); tft.fillRect (0, 75, 3, 15, ca); 529 if (hasRun3 == false) { 530 tft.drawString("RDS No Information ", 3, 74, 2); 531 hasRun3 = true; 532 } 533 hasRun = false; 534 } 535 } 536 537 if (rds_t == true) { 538 if (radio.rds.RDSSignal) { 539 texsw += 8; if (texsw > 296) texsw = 0; 540 tft.setTextSize(1); tft.setTextColor(cb, ca); 541 if (hasRun == false) { 542 tft.drawString(" ", 0, 74, 2); 543 hasRun = true; 544 } 545 tft.drawString(radio.rds.radioText, 20 - texsw, 74, 2); tft.fillRect (156, 75, 4, 15, ca); 546 if (texsw == 296) tft.drawString(" ", 0, 74, 2); 547 hasRun3 = false; 548 } else { 549 radio.clearStationInfo(); texsw = 0; 550 tft.setTextColor(cb, ca); tft.fillRect (0, 75, 3, 15, ca); 551 if (hasRun3 == false) { 552 tft.drawString("RDS No Information ", 3, 74, 2); 553 hasRun3 = true; 554 } 555 hasRun = false; 556 } 557 } 558} 559 560void am_init() { 561 encoder = 1; 562 radio.begin(0, SI7435_ADDRESS); 563 power_down(); 564 power_up_norm(); 565 delay(400); 566 am_fm = 0x40; 567 ssb_m = 0x00; 568 eeprom_read(); 569 freq = freq_eeprom_am; 570 if (count == 2) stp = 4; else stp = 2; setstep(); 571 tune(); 572 am_command(); 573 filter = 0x03; layout(); frequency(); if (count >= 1 && count <= 4) period = 4000; else period = 500; 574 tft.setTextColor(cg, ca); tft.drawString("kHz ", 132, 57, 2); tft.setTextColor(cb, ca); tft.drawString("AM ", 3, 57, 2); 575 tft.drawString(" AM/FM RDS Receiver ", 0, 74, 2); tft.drawString("2k ", 135, 92, 2); 576 tft.drawString(" ", 30, 57, 2); 577} 578 579void fm_init() { 580 encoder = 2; 581 radio.begin(0, SI7435_ADDRESS); 582 power_down(); 583 power_up_FM(); 584 delay(400); 585 am_fm = 0x20; 586 ssb_m = 0x00; 587 eeprom_read(); 588 freq = freq_eeprom_fm; 589 tune(); pilot(); 590 radio.setMode(FM); 591 fil = 0; filterFM(); 592 stp = 0; setstepFM(); fm_command(); 593 hasRun2 = false; count--; layout(); frequency(); period = 2000; 594 tft.setTextColor(cg, ca); tft.drawString("MHz", 132, 57, 2); tft.setTextColor(cb, ca); tft.drawString("FM ", 3, 57, 2); 595 tft.setTextColor(TFT_DARKGREY, ca); tft.drawString(" Stereo ", 30, 57, 2); 596} 597 598void sw_theme() { 599 sts_theme = !sts_theme; 600 if (sts_theme == false) blue_theme(); else black_theme(); 601 tft.fillScreen(ca); tft.setTextColor(cb, ca); 602 hasRun1 = !hasRun1; 603 fm_init(); 604 if (am_fm != 0x20) { 605 fil = 4; filterAM(); 606 } 607 if (am_fm == 0x20) { 608 fil = 0; filterFM(); 609 } 610} 611 612void blue_theme() { 613 ca = TFT_BLUE; //Screen background 614 cb = TFT_WHITE; //Texts 615 cc = TFT_LIGHTGREY; //Lines 616 cd = TFT_GREEN; //S-Meter bargraph 617 ce = TFT_MAGENTA; //S/N bargraph 618 cf = TFT_BLUE; //Bargraph background 619 cg = TFT_WHITE; //Frequency and kHz MHz 620 ch = TFT_CYAN; //Reserved 621 tft.fillScreen(ca); 622} 623 624void black_theme() { 625 ca = TFT_BLACK; //Screen background 626 cb = TFT_WHITE; //Texts 627 cc = TFT_LIGHTGREY; //Lines 628 cd = TFT_GREEN; //S-Meter bargraph 629 ce = TFT_MAGENTA; //S/N bargraph 630 cf = TFT_BLACK; //Bargraph background 631 cg = TFT_CYAN; //Frequency and kHz MHz 632 ch = TFT_RED; //Reserved 633 tft.fillScreen(ca); 634} 635 636void am_command() { 637 radio.setProperty(PROP_AM_SOFT_MUTE_MAX_ATTENUATION, 1); // 0 (OFF) - 63 638 radio.setProperty(PROP_AM_AUTOMATIC_VOLUME_CONTROL_MAX_GAIN, 0x32C8); // 0x1000 - 0x7800 639 radio.setProperty(PROP_AM_AGC_ATTACK_RATE, 4); // 4–248 640 radio.setProperty(PROP_AM_AGC_RELEASE_RATE, 4); // 4–248 641} 642 643void fm_command() { 644 radio.setProperty(PROP_FM_DEEMPHASIS, 0x0001); // 02 = 75 μs; 01 = 50 μs 645 radio.setProperty(PROP_FM_CHANNEL_FILTER, filter); // 0 = automat; 1 = 110kHz; 4 = 40kHz 646 radio.setProperty(PROP_FM_SOFT_MUTE_MAX_ATTENUATION, 0); // 0 = disable; 31 = max 647 radio.setProperty(PROP_FM_BLEND_STEREO_THRESHOLD, 0); // 0 = stereo; 127 = mono 648 radio.setProperty(PROP_FM_BLEND_MONO_THRESHOLD, 0); // 0 = stereo; 127 = mono 649} 650 651void power_down() { 652 Wire.beginTransmission(SI7435_ADDRESS); 653 Wire.write(0x11); 654 Wire.endTransmission(); 655 delay(1); 656} 657 658void power_up_norm() { 659 Wire.beginTransmission(SI7435_ADDRESS); 660 Wire.write(0x01); 661 Wire.write(0x11); 662 Wire.write(0x05); 663 Wire.endTransmission(); 664 delay(1); 665} 666 667void power_up_FM() { 668 Wire.beginTransmission(SI7435_ADDRESS); 669 Wire.write(0x01); 670 Wire.write(0x10); 671 Wire.write(0x05); 672 Wire.endTransmission(); 673 delay(1); 674} 675 676void tune() { 677 Wire.beginTransmission(SI7435_ADDRESS); 678 Wire.write(am_fm); 679 Wire.write(ssb_m); 680 Wire.write(fr_h); 681 Wire.write(fr_l); 682 Wire.write(0x00); 683 Wire.write(mw_sw); 684 Wire.endTransmission(); 685 delay(1); 686} 687 688void property_filter_AM() { 689 Wire.beginTransmission(SI7435_ADDRESS); 690 Wire.write(0x12); 691 Wire.write(0x00); 692 Wire.write(0x31); 693 Wire.write(0x02); 694 Wire.write(0x00); 695 Wire.write(filter); 696 Wire.endTransmission(); 697 delay(1); 698} 699 700void eeprom_write() { 701 if (am_fm == 0x20) { 702 fr_eeprom_h = (freq) >> 8; 703 fr_eeprom_l = (freq) & 0x00FF; 704 EEPROM.write(0, fr_eeprom_l); 705 EEPROM.write(1, fr_eeprom_h); 706 EEPROM.write(2, 1); 707 } 708 if (am_fm != 0x20) { 709 fr_eeprom_h = (freq) >> 8; 710 fr_eeprom_l = (freq) & 0x00FF; 711 EEPROM.write(3, fr_eeprom_l); 712 EEPROM.write(4, fr_eeprom_h); 713 EEPROM.write(2, 0); 714 EEPROM.write(5, count); 715 } 716 EEPROM.write(6, sts_theme); 717 tft.setTextColor(TFT_WHITE, TFT_MAGENTA); tft.drawString("SAVE", 126, 111, 2); 718 delay(1500); 719 tft.setTextColor(cb, ca); tft.drawString(" ", 126, 111, 2); 720 delay(300); 721} 722 723void eeprom_read() { 724 if (am_fm == 0x20) { 725 fr_eeprom_l = EEPROM.read(0); 726 fr_eeprom_h = EEPROM.read(1); 727 freq_eeprom_fm = (fr_eeprom_h << 8U) | fr_eeprom_l; 728 } 729 if (am_fm != 0x20) { 730 fr_eeprom_l = EEPROM.read(3); 731 fr_eeprom_h = EEPROM.read(4); 732 freq_eeprom_am = (fr_eeprom_h << 8U) | fr_eeprom_l; 733 count = EEPROM.read(5); 734 } 735 sts_am_fm = EEPROM.read(2); 736}
Downloadable files
Audio amp LM386 DIY PCB layout
It is not necessary to resize the PCB designs, they are already in the 1: 1 scale and you do not need to mirror them.
Audio amp LM386 DIY PCB layout
Audio amp LM386 DIY PCB top mask
Audio amp LM386 DIY PCB top mask
Audio amp LM386 DIY PCB top mask
Audio amp LM386 DIY PCB top mask
Audio amp LM386 DIY PCB top mask
Audio amp LM386 DIY PCB top mask
Audio amp LM386 DIY PCB layout
It is not necessary to resize the PCB designs, they are already in the 1: 1 scale and you do not need to mirror them.
Audio amp LM386 DIY PCB layout
Audio amp LM386 DIY Schematics
Audio amp LM386 DIY Schematics
Audio amp LM386 DIY Schematics
Comments
Only logged in users can leave comments