Make the FM radio fully functional with the RDA5807M and arduino nano. Touch button control
Devices and components
Arduino-Nano
Resistance 220 ohms
variable resistor 10k
RDA5807M
LCD1602 module
Micro USB to DIP PCBA
Wire, Flexivolt-E
Speaker: 3 W, 4 ohms
TTP223 touch sensor module
PAM8403 amplifier module
Materials and tools
Soldering iron (generic)
Project description
Press Next to play the next channel in ROM, press Previous to play the previous channel.
Press Mute to mute and unmute the sound.
Press and hold Vol- or Vol+ to adjust the volume.
Press and hold Menu will display channel info (RSSI, channel status)
Press and hold Search to automatically search and find the next channel
Press Menu for Menu selection and choose function by F1, F2 according to display
ress Next will play next channel in ROM, Press Prev will play previous channel.
Press Mute to mute and unmute the sound.
Press and hold Vol- or Vol+ to adjust the volume.
Press and hold Menu will display channel info (RSSI, channel status)
Press and hold Search to automatically search and find the next channel
Press Save to save the channel to ROM, input Name of station by Up, down, Enter
Press up and down to change frequency.
Press and hold Enter to change the frequency by x10 or x1 change
Press Save to save the frequency in ROM
NANOFMRADIO.ino
arduino
1
2
3/*
4 * FM CHANNEL AT HO CHI MINH CITY - VIET NAM
5 * VOHKT 87.7
6 * VOV89 89
7 * VOVGT 91
8 * BINHD 92.5
9 * VOV1 94
10 * VOHGT 95.6
11 * VOV2 96.5
12 * DONGN 97.5
13 * VOHFM 99.9
14 * TA247 104
15 * VOV3 104.5
16 * VOV5 105.7
17 */
18
19
20
21
22
23#include <Wire.h>
24#include <LiquidCrystal.h>
25#include <EEPROM.h>
26#include <RADIO_RDA5807M.h>
27
28
29//Define byte of custom char in LCD
30#define DSignalchar byte(0)
31#define DSignal100 byte(1)
32#define DSignal80 byte(2)
33#define DSignal60 byte(3)
34#define DSignal40 byte(4)
35#define DSignal20 byte(5)
36#define DSignal0 byte(6)
37#define DPlaysign byte(7)
38
39//Define button Pin No
40#define BMenu 2
41#define BEnter 3
42#define BDown 4
43#define BUp 5
44#define LCDBackLight 6
45
46//Define Buton active level
47#define ACTIVE_LOW 0
48#define ACTIVE_HIGH 1
49
50//define State of device
51#define NO_RADIO_FOUND 0
52#define NO_CHANNEL_FOUND 1
53#define FIRST_SETUP_SELECT 2
54#define DONE_LOAD_VN_CHANNEL 3
55#define PLAYING 4
56#define SEEKING 5
57#define SAVE_CHANNEL_SEEK 6
58#define MENU_PAGE1 7
59#define MENU_PAGE2 8
60#define MENU_PAGE3 9
61#define PLAY_BY_FREQ 10
62#define EDIT_CHANNEL 11
63#define REMOVE_CHANNEL 12
64#define ERASE_ALL 13
65#define REMOVE_CHANNEL_DONE 14
66#define LCD_BACKLIGHT 15
67#define DONE_ERASE_ALL 16
68#define DATA_ERASING 17
69#define DISPLAY_CHANNEL_INFO 18
70#define SAVE_CHANNEL_FREQ 19
71#define LOAD_DEFAULT_DATA 20
72#define SET_BACKLIGHT 21
73
74
75
76//define ButtonState
77#define NO_BUTTON_PRESS 0
78#define MENU_LONG_PRESS 1
79#define MENU_SHORT_PRESS 2
80#define UP_LONG_PRESS 3
81#define UP_SHORT_PRESS 4
82#define DOWN_LONG_PRESS 5
83#define DOWN_SHORT_PRESS 6
84#define ENTER_LONG_PRESS 7
85#define ENTER_SHORT_PRESS 8
86
87//Define BackLight macro
88#define ONLCDLED digitalWrite(LCDBackLight, LOW)
89#define OFFLCDLED digitalWrite(LCDBackLight, HIGH)
90
91struct RadioChannelInfo
92{
93 uint8_t ChannelIndex;
94 char ChannelName[5];
95 unsigned int ChannelFreq;
96};
97
98
99LiquidCrystal LCDDISPLAY(12, 11, 10, 9, 8, 7);
100
101byte SignalChar[8] = {31,14,4,4,4,4,4,0};
102byte Signal100[8]= {1,3,7,15,31,0,31,0};
103byte Signal80[8]= {0,2,6,14,30,0,31,0};
104byte Signal60[8]= {0,0,4,12,28,0,31,0};
105byte Signal40[8]= {0,0,0,8,24,0,31,0};
106byte Signal20[8]= {0,0,0,0,16,0,31,0};
107byte Signal0[8]= {17,10,4,10,17,0,31,0};
108byte Playsign[8]= {16,24,28,30,30,28,24,16};
109
110const byte DefaultROMDataVietnamChannel[]= {1,'V','O','H','K','T',0x22,0x42,
111 2,'V','O','V','8','9',0x22,0xC4,
112 3,'V','O','V','G','T',0x23,0x8C,
113 4,'B','I','N','H','D',0x24,0x22,
114 5,'V','O','V','1',0,0x24,0xB8,
115 6,'V','O','H','G','T',0x25,0x58,
116 7,'V','O','V','2',0,0x25,0xB2,
117 8,'D','O','N','G','N',0x26,0x16,
118 9,'V','O','H','F','M',0x27,0x06,
119 10,'T','A','2','4',0,0x28,0xA0,
120 11,'V','O','V','3',0,0x28,0xD2,
121 12,'V','O','V','5',0,0x29,0x4A
122 };
123
124
125
126byte SignalLevel;
127byte CurrentState;
128byte LastState;
129RadioChannelInfo CurrentChannelInfo;
130byte CurrentChannelIndex;
131byte CurrentVolume;
132byte MuteVolume=1;
133unsigned int CurrentFreq;
134bool FreqMode10x;
135
136byte CurrentBacklightLife=5;
137unsigned int BackLighOnpoint;
138
139RDA5807M MyRadio;
140bool RadioFound;
141bool ChannelDefined;
142byte ROMData;
143byte NumofChannel;
144byte CurrentCharacter=0;
145byte CurrentCharacterIndex=0;
146char SaveChannelName[5];
147
148
149bool ButtonHolding=false;
150
151byte ReadCurrentBackLightLife()
152{
153 byte ReturnBacklightLife;
154 ReturnBacklightLife=EEPROM.read(0x03);
155 return ReturnBacklightLife;
156}
157
158void WriteCurrentBackLightLife(byte LifeSecond)
159{
160 EEPROM.write(0x03,LifeSecond);
161}
162
163void SaveChanneltoROM(RadioChannelInfo ChannelDataSave)
164{
165 byte RomAddress;
166 byte FreqData;
167 RomAddress=((ChannelDataSave.ChannelIndex-1)*8)+10;
168 EEPROM.write(RomAddress,ChannelDataSave.ChannelIndex);
169 EEPROM.write(RomAddress+1,ChannelDataSave.ChannelName[0]);
170 EEPROM.write(RomAddress+2,ChannelDataSave.ChannelName[1]);
171 EEPROM.write(RomAddress+3,ChannelDataSave.ChannelName[2]);
172 EEPROM.write(RomAddress+4,ChannelDataSave.ChannelName[3]);
173 EEPROM.write(RomAddress+5,ChannelDataSave.ChannelName[4]);
174 FreqData=highByte(ChannelDataSave.ChannelFreq);
175 EEPROM.write(RomAddress+6,FreqData);
176 FreqData=lowByte(ChannelDataSave.ChannelFreq);
177 EEPROM.write(RomAddress+7,FreqData);
178}
179
180void SaveRadioParametertoROM()
181{
182 EEPROM.write(0,NumofChannel);
183 EEPROM.write(1,CurrentChannelIndex);
184 if(CurrentVolume==0) CurrentVolume = 8; //Prevent from saving mute
185 EEPROM.write(2,CurrentVolume);
186}
187void EraseAllChannelInROM()
188{
189 unsigned int RomAddress;
190 EEPROM.write(0,0xFF);//Num of channel
191 EEPROM.write(1,0);//current channel
192 EEPROM.write(2,8);//Current volume
193 for(RomAddress=3;RomAddress<400;RomAddress++)
194 {
195 EEPROM.write(RomAddress,0xFF);
196 }
197
198}
199
200void RemoveChannelfromROM(byte RemoveChannelIndex)
201{
202 byte ChannelIndexMoving;
203 RadioChannelInfo ChannelInArray;
204 for(ChannelIndexMoving=RemoveChannelIndex+1;ChannelIndexMoving<=NumofChannel;ChannelIndexMoving++)// re-arrange the channel array (shift left)
205 {
206 ChannelInArray=GetChannelROM(ChannelIndexMoving);
207 ChannelInArray.ChannelIndex=ChannelInArray.ChannelIndex-1;
208 SaveChanneltoROM(ChannelInArray);
209 }
210 NumofChannel=NumofChannel-1;
211 SaveRadioParametertoROM();
212}
213
214void LoadDefaultChannel()
215{
216 byte RomAddress;
217 byte DataArrayIndex;
218 DataArrayIndex=0;
219 EEPROM.write(0x00,12); // save number of channel
220 EEPROM.write(0x01,1); // save Current channel index
221 EEPROM.write(0x02,8); // save Current volume
222 EEPROM.write(0x03,5); // save Current backlight life second
223 for(RomAddress=10;RomAddress<106;RomAddress++)
224 {
225 EEPROM.write(RomAddress,DefaultROMDataVietnamChannel[DataArrayIndex]);
226 DataArrayIndex++;
227 }
228 NumofChannel=12;
229 CurrentChannelIndex=1;
230 CurrentVolume=8;
231}
232
233RadioChannelInfo GetChannelROM(byte ChannelIndex)
234{
235 byte ROMAddress;
236 uint16_t ROMChannelFreq;
237 RadioChannelInfo ReturnChannel;
238
239 ROMAddress=(ChannelIndex-1)*8 + 10;// 10 is ROm slot use for Num of channel, curent channel,LED backlight time and volume storage, user storage
240 ReturnChannel.ChannelIndex=EEPROM.read(ROMAddress);
241 ReturnChannel.ChannelName[0]=EEPROM.read(ROMAddress+1);
242 ReturnChannel.ChannelName[1]=EEPROM.read(ROMAddress+2);
243 ReturnChannel.ChannelName[2]=EEPROM.read(ROMAddress+3);
244 ReturnChannel.ChannelName[3]=EEPROM.read(ROMAddress+4);
245 ReturnChannel.ChannelName[4]=EEPROM.read(ROMAddress+5);
246 ROMChannelFreq=EEPROM.read(ROMAddress+6);
247 ROMChannelFreq=ROMChannelFreq<<8;
248 ROMChannelFreq=ROMChannelFreq+EEPROM.read(ROMAddress+7);
249 ReturnChannel.ChannelFreq=ROMChannelFreq;
250 return ReturnChannel;
251}
252
253void GetLastPlayingToCurrent()
254{
255 NumofChannel=EEPROM.read(0x0000);
256 CurrentChannelIndex=EEPROM.read(0x0001);
257 CurrentVolume=EEPROM.read(0x0002);
258}
259
260
261
262
263void DisplayWelCome() {
264 LCDDISPLAY.setCursor(4, 0);
265 LCDDISPLAY.print("RADIO FM");
266 LCDDISPLAY.setCursor(14, 0);
267 LCDDISPLAY.write(DSignalchar);
268 LCDDISPLAY.setCursor(0, 1);
269 LCDDISPLAY.print("Have fun time!!!");
270 delay(1000);
271}
272
273
274void Displaysignal(byte SignalLevelDisplay)
275{
276 LCDDISPLAY.setCursor(14, 0);
277 LCDDISPLAY.write(DSignalchar);
278 SignalLevelDisplay=SignalLevelDisplay/20;
279 switch(SignalLevelDisplay)
280 {
281 case 0:
282 {
283 LCDDISPLAY.write(DSignal0);
284 break;
285 }
286 case 1:
287 {
288 LCDDISPLAY.write(DSignal20);
289 break;
290 }
291 case 2:
292 {
293 LCDDISPLAY.write(DSignal40);
294 break;
295 }
296 case 3:
297 {
298 LCDDISPLAY.write(DSignal60);
299 break;
300 }
301 case 4:
302 {
303 LCDDISPLAY.write(DSignal80);
304 break;
305 }
306 case 5:
307 {
308 LCDDISPLAY.write(DSignal100);
309 break;
310 }
311 }
312}
313
314void DisplayPlayInfo(RadioChannelInfo ChannelData,byte Voldata)
315{
316 byte Voldisplay;
317 byte FreqDisplay;
318 byte FMInfoData; //yzzzzzzz bit y=1: is station found, zzzzzzz: RSSI data
319 unsigned int RSSIData;
320 byte RSSILevel;
321
322 LCDDISPLAY.setCursor(0, 0);
323 if(ChannelData.ChannelIndex==0xFF) LCDDISPLAY.print("SEK");
324 else
325 {
326 LCDDISPLAY.print(ChannelData.ChannelIndex/10);
327 LCDDISPLAY.print(ChannelData.ChannelIndex%10);
328 }
329 if(MuteVolume!=0)
330 {
331 Voldata=Voldata/2; // Vol level on RDA5708M is 16 level, display in 8 level
332 LCDDISPLAY.setCursor(4, 0);
333 for(Voldisplay=0;Voldisplay<Voldata;Voldisplay++)
334 {
335 LCDDISPLAY.print("=");
336 }
337 for(Voldisplay=Voldata;Voldisplay<8;Voldisplay++)
338 {
339 LCDDISPLAY.print(" ");
340 }
341 }
342 else
343 {
344 LCDDISPLAY.setCursor(4, 0);
345 for(Voldisplay=0;Voldisplay<8;Voldisplay++)
346 {
347 LCDDISPLAY.print(" ");
348 }
349 LCDDISPLAY.setCursor(5, 0);
350 LCDDISPLAY.print("Muted");
351 }
352
353 LCDDISPLAY.setCursor(0, 1);
354 if(ChannelData.ChannelName[0]!=0) LCDDISPLAY.print(ChannelData.ChannelName[0]);
355 else LCDDISPLAY.print(" ");
356 if(ChannelData.ChannelName[1]!=0) LCDDISPLAY.print(ChannelData.ChannelName[1]);
357 else LCDDISPLAY.print(" ");
358 if(ChannelData.ChannelName[2]!=0) LCDDISPLAY.print(ChannelData.ChannelName[2]);
359 else LCDDISPLAY.print(" ");
360 if(ChannelData.ChannelName[3]!=0) LCDDISPLAY.print(ChannelData.ChannelName[3]);
361 else LCDDISPLAY.print(" ");
362 if(ChannelData.ChannelName[4]!=0) LCDDISPLAY.print(ChannelData.ChannelName[4]);
363 else LCDDISPLAY.print(" ");
364 LCDDISPLAY.print(" ");
365 FreqDisplay=ChannelData.ChannelFreq/10000;
366 if(FreqDisplay!=0) LCDDISPLAY.print(FreqDisplay);
367 else LCDDISPLAY.print(" ");
368 FreqDisplay=(ChannelData.ChannelFreq%10000)/1000;
369 LCDDISPLAY.print(FreqDisplay);
370 FreqDisplay=(ChannelData.ChannelFreq%1000)/100;
371 LCDDISPLAY.print(FreqDisplay);
372 LCDDISPLAY.print(".");
373 FreqDisplay=(ChannelData.ChannelFreq%100)/10;
374 LCDDISPLAY.print(FreqDisplay);
375 LCDDISPLAY.noBlink();
376
377 FMInfoData = MyRadio.GetRSSI_FMInfo();
378 FMInfoData=FMInfoData & 0x7F;
379 RSSIData = FMInfoData*100/127;
380 RSSILevel= (byte) RSSIData;
381 Displaysignal(RSSILevel);
382
383}
384
385
386void LCDDisplay(byte DisplayMode)
387{
388 switch(DisplayMode)
389 {
390 case NO_RADIO_FOUND:
391 {
392 LCDDISPLAY.clear();
393 LCDDISPLAY.setCursor(4, 0);
394 LCDDISPLAY.print("RADIO FM");
395 LCDDISPLAY.setCursor(14, 0);
396 LCDDISPLAY.write(DSignalchar);
397 LCDDISPLAY.setCursor(0, 1);
398 LCDDISPLAY.print("Cannot found RDA");
399 break;
400 }
401 case NO_CHANNEL_FOUND:
402 {
403 LCDDISPLAY.clear();
404 LCDDISPLAY.setCursor(0, 0);
405 LCDDISPLAY.print("No Channel set");
406 LCDDISPLAY.setCursor(0, 1);
407 LCDDISPLAY.print("Pls Press Menu");
408 Displaysignal(SignalLevel);
409 break;
410 }
411 case FIRST_SETUP_SELECT:
412 {
413 LCDDISPLAY.clear();
414 LCDDISPLAY.setCursor(0, 0);
415 LCDDISPLAY.print("F1>AUTO SCAN");
416 LCDDISPLAY.setCursor(0, 1);
417 LCDDISPLAY.print("F2>LOAD VN CHAN");
418 Displaysignal(SignalLevel);
419 break;
420 }
421 case DONE_LOAD_VN_CHANNEL:
422 {
423 LCDDISPLAY.clear();
424 LCDDISPLAY.setCursor(0, 0);
425 LCDDISPLAY.print("DATA LOADED");
426 LCDDISPLAY.setCursor(0, 1);
427 LCDDISPLAY.print("Pls Press Exit");
428 Displaysignal(SignalLevel);
429 break;
430 }
431 case PLAYING:
432 {
433 LCDDISPLAY.clear();
434 LCDDISPLAY.setCursor(3, 0);
435 LCDDISPLAY.print("[");
436 LCDDISPLAY.setCursor(12, 0);
437 LCDDISPLAY.print("]");
438 LCDDISPLAY.setCursor(12, 1);
439 LCDDISPLAY.print("Mhz");
440 Displaysignal(SignalLevel);
441 break;
442 }
443 case MENU_PAGE1:
444 {
445 LCDDISPLAY.clear();
446 LCDDISPLAY.setCursor(0, 0);
447 LCDDISPLAY.print("F1>PLAY by Freq");
448 LCDDISPLAY.setCursor(0, 1);
449 LCDDISPLAY.print("F2>Edit Channel");
450 break;
451 }
452
453 case MENU_PAGE2:
454 {
455 LCDDISPLAY.clear();
456 LCDDISPLAY.setCursor(0, 0);
457 LCDDISPLAY.print("F1>Del Channel");
458 LCDDISPLAY.setCursor(0, 1);
459 LCDDISPLAY.print("F2>EraseAll Data");
460 break;
461 }
462
463 case MENU_PAGE3:
464 {
465 LCDDISPLAY.clear();
466 LCDDISPLAY.setCursor(0, 0);
467 LCDDISPLAY.print("F1>LCD BackLight");
468 LCDDISPLAY.setCursor(0, 1);
469 LCDDISPLAY.print("F2>ReLoad VNchannel");
470 break;
471 }
472
473 case ERASE_ALL:
474 {
475 LCDDISPLAY.clear();
476 LCDDISPLAY.setCursor(0, 0);
477 LCDDISPLAY.print("Erase All Data?");
478 LCDDISPLAY.setCursor(0, 1);
479 LCDDISPLAY.print("Enter to confirm");
480 break;
481 }
482 case DONE_ERASE_ALL:
483 {
484 LCDDISPLAY.clear();
485 LCDDISPLAY.setCursor(0, 0);
486 LCDDISPLAY.print("All Data clear");
487 LCDDISPLAY.setCursor(0, 1);
488 LCDDISPLAY.print("Exit to return");
489 break;
490 }
491 case DATA_ERASING:
492 {
493 LCDDISPLAY.clear();
494 LCDDISPLAY.setCursor(0, 0);
495 LCDDISPLAY.print("Data erasing");
496 LCDDISPLAY.setCursor(0, 1);
497 LCDDISPLAY.print("Please wait...");
498 break;
499 }
500 case DISPLAY_CHANNEL_INFO:
501 {
502 LCDDISPLAY.clear();
503 LCDDISPLAY.setCursor(0, 0);
504 LCDDISPLAY.print("STATION FOUND: _");
505 LCDDISPLAY.setCursor(0, 1);
506 LCDDISPLAY.print("___._Mhz RS: %");
507 break;
508 }
509
510 case PLAY_BY_FREQ:
511 {
512 LCDDISPLAY.clear();
513 LCDDISPLAY.setCursor(0, 0);
514 LCDDISPLAY.print("PlayFRQ:___._Mhz");
515 LCDDISPLAY.setCursor(0, 1);
516 LCDDISPLAY.print("Vol:__ RS: % *");
517 break;
518 }
519 case EDIT_CHANNEL:
520 {
521 LCDDISPLAY.clear();
522 LCDDISPLAY.setCursor(0, 0);
523 LCDDISPLAY.print("Channel __ edit");
524 LCDDISPLAY.setCursor(0, 1);
525 LCDDISPLAY.print(" ___._ Mhz");
526 break;
527 }
528 case REMOVE_CHANNEL:
529 {
530 LCDDISPLAY.clear();
531 LCDDISPLAY.setCursor(0, 0);
532 LCDDISPLAY.print("Del Channel __ ?");
533 LCDDISPLAY.setCursor(0, 1);
534 LCDDISPLAY.print("_____ ___._ Mhz");
535 break;
536 }
537 case REMOVE_CHANNEL_DONE:
538 {
539 LCDDISPLAY.clear();
540 LCDDISPLAY.setCursor(0, 0);
541 LCDDISPLAY.print("Del Channel Done");
542 LCDDISPLAY.setCursor(0, 1);
543 LCDDISPLAY.print("Pls Press Exit");
544 break;
545 }
546 case LOAD_DEFAULT_DATA:
547 {
548 LCDDISPLAY.clear();
549 LCDDISPLAY.setCursor(0, 0);
550 LCDDISPLAY.print("LoadDefalt Data?");
551 LCDDISPLAY.setCursor(0, 1);
552 LCDDISPLAY.print("Old Data erase?");
553 break;
554 }
555 case SET_BACKLIGHT:
556 {
557 LCDDISPLAY.clear();
558 LCDDISPLAY.setCursor(0, 0);
559 LCDDISPLAY.print("LCD Backlight __");
560 LCDDISPLAY.setCursor(0, 1);
561 LCDDISPLAY.print("0 sec = Alway ON");
562 break;
563 }
564 }
565}
566
567
568void InceaseCharacter()
569{
570 if(SaveChannelName[CurrentCharacterIndex]==0) CurrentCharacter='@';
571 else CurrentCharacter=SaveChannelName[CurrentCharacterIndex];
572 CurrentCharacter++;
573 if(CurrentCharacter=='[') CurrentCharacter=' ';
574 else if(CurrentCharacter=='!') CurrentCharacter='0';
575 else if(CurrentCharacter==':') CurrentCharacter='A';
576 LCDDISPLAY.setCursor(CurrentCharacterIndex, 1);
577 LCDDISPLAY.write(CurrentCharacter);
578 LCDDISPLAY.setCursor(CurrentCharacterIndex, 1);
579 SaveChannelName[CurrentCharacterIndex]=CurrentCharacter;
580}
581
582void DecreaseCharacter()
583{
584 if(SaveChannelName[CurrentCharacterIndex]==0) CurrentCharacter='B';
585 else CurrentCharacter=SaveChannelName[CurrentCharacterIndex];
586 CurrentCharacter--;
587 if(CurrentCharacter=='/') CurrentCharacter=' ';
588 else if(CurrentCharacter==31) CurrentCharacter='Z';
589 else if(CurrentCharacter=='@') CurrentCharacter='9';
590 LCDDISPLAY.setCursor(CurrentCharacterIndex, 1);
591 LCDDISPLAY.write(CurrentCharacter);
592 LCDDISPLAY.setCursor(CurrentCharacterIndex, 1);
593 SaveChannelName[CurrentCharacterIndex]=CurrentCharacter;
594}
595
596void DisplaySaveChannel()
597{
598 byte SaveChannelIndex;
599 SaveChannelIndex=NumofChannel+1;
600
601 LCDDISPLAY.setCursor(0, 0);
602 LCDDISPLAY.print(" ");
603 LCDDISPLAY.setCursor(0, 0);
604 LCDDISPLAY.print(SaveChannelIndex/10);
605 LCDDISPLAY.print(SaveChannelIndex%10);
606 LCDDISPLAY.setCursor(CurrentCharacterIndex, 1);
607 LCDDISPLAY.blink();
608 InceaseCharacter();
609}
610
611
612void PlayFM(RadioChannelInfo RadioData,byte VolumeData)
613{
614
615 CurrentState=PLAYING;
616 LCDDISPLAY.clear();
617 CurrentVolume=VolumeData;
618 LCDDisplay(CurrentState);
619 //Play Freq command here
620 MyRadio.SetFrequency(RadioData.ChannelFreq,CurrentVolume-1);
621 DisplayPlayInfo(RadioData,VolumeData);
622}
623
624void PlaybyFreq(unsigned FreqPlay) // ussing for play by Freq
625{
626 byte FreqDisplay;
627 byte FMInfoData; //yzzzzzzz bit y=1: is station found, zzzzzzz: RSSI data
628 unsigned int RSSIData;
629 byte RSSILevel;
630 MyRadio.SetFrequency(FreqPlay,CurrentVolume-1);
631 delay(100);
632 FMInfoData = MyRadio.GetRSSI_FMInfo();
633
634 LCDDISPLAY.setCursor(4, 1);
635 LCDDISPLAY.print(CurrentVolume/10);
636 LCDDISPLAY.print(CurrentVolume%10);
637
638 LCDDISPLAY.setCursor(15, 1);
639 if(bitRead(FMInfoData,7)==0) LCDDISPLAY.print(" ");
640 else LCDDISPLAY.print("*");
641
642 FMInfoData=FMInfoData & 0x7F;
643 RSSIData = FMInfoData*100/127;
644 RSSILevel= (byte) RSSIData;
645 if(RSSILevel>99) LCDDISPLAY.setCursor(10, 1);
646 else LCDDISPLAY.setCursor(11, 1);
647 LCDDISPLAY.print(RSSILevel);
648
649 LCDDISPLAY.setCursor(8, 0);
650 FreqDisplay=FreqPlay/10000;
651 if(FreqDisplay!=0) LCDDISPLAY.print(FreqDisplay);
652 else LCDDISPLAY.print(" ");
653 FreqDisplay=(FreqPlay%10000)/1000;
654 LCDDISPLAY.print(FreqDisplay);
655 FreqDisplay=(FreqPlay%1000)/100;
656 LCDDISPLAY.print(FreqDisplay);
657 LCDDISPLAY.print(".");
658 FreqDisplay=(FreqPlay%100)/10;
659 LCDDISPLAY.print(FreqDisplay);
660
661 if(FreqMode10x==true)
662 {
663 LCDDISPLAY.setCursor(10, 0);
664 LCDDISPLAY.blink();
665 }
666 else
667 {
668 LCDDISPLAY.setCursor(12, 0);
669 LCDDISPLAY.blink();
670 }
671}
672
673void DisplaySaveFrequency()
674{
675 byte FreqDisplay;
676 LCDDISPLAY.clear();
677 LCDDISPLAY.setCursor(3, 0);
678 LCDDISPLAY.print("Save Channel ");
679 LCDDISPLAY.setCursor(12, 1);
680 LCDDISPLAY.print(" Mhz");
681 LCDDISPLAY.setCursor(7, 1);
682 FreqDisplay=CurrentFreq/10000;
683 if(FreqDisplay!=0) LCDDISPLAY.print(FreqDisplay);
684 else LCDDISPLAY.print(" ");
685 FreqDisplay=(CurrentFreq%10000)/1000;
686 LCDDISPLAY.print(FreqDisplay);
687 FreqDisplay=(CurrentFreq%1000)/100;
688 LCDDISPLAY.print(FreqDisplay);
689 LCDDISPLAY.print(".");
690 FreqDisplay=(CurrentFreq%100)/10;
691 LCDDISPLAY.print(FreqDisplay);
692
693}
694
695void IncreaseFreqPlay() // ussing for play by Freq
696{
697 if(FreqMode10x==true) CurrentFreq=CurrentFreq+100;
698 else CurrentFreq=CurrentFreq+10;
699 if(CurrentFreq>MyRadio.MaxFreq) CurrentFreq=MyRadio.MaxFreq;
700 PlaybyFreq(CurrentFreq);
701}
702
703
704void DecreaseFreqPlay() // ussing for play by Freq
705{
706 if(FreqMode10x==true) CurrentFreq=CurrentFreq-100;
707 else CurrentFreq=CurrentFreq-10;
708 if(CurrentFreq<MyRadio.MinFreq) CurrentFreq=MyRadio.MinFreq;
709 PlaybyFreq(CurrentFreq);
710}
711
712void ChangeFreqTurn()
713{
714 if(FreqMode10x==true)
715 {
716 FreqMode10x=false;
717 LCDDISPLAY.setCursor(12, 0);
718 }
719 else
720 {
721 FreqMode10x=true;
722 LCDDISPLAY.setCursor(10, 0);
723 }
724}
725
726
727void StopPlayFM()
728{
729 // Stop play FM here
730 MyRadio.ResetChip();
731}
732
733void DisplayFMInfo()
734{
735 byte FMInfoData; //yzzzzzzz bit y=1: is station found, zzzzzzz: RSSI data
736 unsigned int RSSIData;
737 byte RSSILevel;
738 byte FreqDisplay;
739 unsigned int FreqData;
740 FMInfoData = MyRadio.GetRSSI_FMInfo();
741 FreqData = MyRadio.GetFrequency();
742
743 LCDDISPLAY.setCursor(15, 0);
744 if(bitRead(FMInfoData,7)==0) LCDDISPLAY.print("N");
745 else LCDDISPLAY.print("Y");
746
747 FMInfoData=FMInfoData & 0x7F;
748 RSSIData = FMInfoData*100/127;
749 RSSILevel= (byte) RSSIData;
750 if(RSSILevel>99) LCDDISPLAY.setCursor(12, 1);
751 else LCDDISPLAY.setCursor(13, 1);
752 LCDDISPLAY.print(RSSILevel);
753
754
755 LCDDISPLAY.setCursor(0, 1);
756 FreqDisplay=FreqData/10000;
757 if(FreqDisplay!=0) LCDDISPLAY.print(FreqDisplay);
758 else LCDDISPLAY.print(" ");
759 FreqDisplay=(FreqData%10000)/1000;
760 LCDDISPLAY.print(FreqDisplay);
761 FreqDisplay=(FreqData%1000)/100;
762 LCDDISPLAY.print(FreqDisplay);
763 LCDDISPLAY.print(".");
764 FreqDisplay=(FreqData%100)/10;
765 LCDDISPLAY.print(FreqDisplay);
766 LCDDISPLAY.noBlink();
767
768}
769
770void PlayNextChannel()
771{
772 if(NumofChannel>0)
773 {
774 CurrentChannelIndex++;
775 if(CurrentChannelIndex>NumofChannel) CurrentChannelIndex =1;
776 CurrentChannelInfo=GetChannelROM(CurrentChannelIndex);
777 PlayFM(CurrentChannelInfo,CurrentVolume);
778 SaveRadioParametertoROM();
779 }
780}
781
782void PlayPrevChannel()
783{
784 if(NumofChannel>0)
785 {
786 CurrentChannelIndex--;
787 if(CurrentChannelIndex<1) CurrentChannelIndex = NumofChannel;
788 CurrentChannelInfo=GetChannelROM(CurrentChannelIndex);
789 PlayFM(CurrentChannelInfo,CurrentVolume);
790 SaveRadioParametertoROM();
791 }
792}
793
794void IncVol()
795{
796 CurrentVolume++;
797 if(CurrentVolume>16) CurrentVolume=16;
798 MuteVolume=CurrentVolume; // unmute if muted
799 SaveRadioParametertoROM();
800 // Increase volume here
801 MyRadio.SetVolume(CurrentVolume-1);
802 if(CurrentState==PLAY_BY_FREQ) // when play by Freq
803 {
804 LCDDISPLAY.setCursor(4, 1);
805 LCDDISPLAY.print(CurrentVolume/10);
806 LCDDISPLAY.print(CurrentVolume%10);
807 if(FreqMode10x==true) LCDDISPLAY.setCursor(10, 0);
808 else LCDDISPLAY.setCursor(12, 0);
809 }
810 else
811 {
812 DisplayPlayInfo(CurrentChannelInfo,CurrentVolume); // when play by SEEK, CHANNEL
813 }
814
815
816}
817void DecVol()
818{
819 CurrentVolume--;
820 if(CurrentVolume<1) CurrentVolume=1;
821 MuteVolume=CurrentVolume;//unmute if muted
822 SaveRadioParametertoROM();
823 // Decrease volume here
824 MyRadio.SetVolume(CurrentVolume-1);
825
826 if(CurrentState==PLAY_BY_FREQ) // when play by Freq
827 {
828 LCDDISPLAY.setCursor(4, 1);
829 LCDDISPLAY.print(CurrentVolume/10);
830 LCDDISPLAY.print(CurrentVolume%10);
831 if(FreqMode10x==true) LCDDISPLAY.setCursor(10, 0);
832 else LCDDISPLAY.setCursor(12, 0);
833 }
834
835 else // when play by SEEK, CHANNEL
836 {
837 DisplayPlayInfo(CurrentChannelInfo,CurrentVolume);
838 }
839}
840
841void Mute_Unmute()
842{
843
844 if(CurrentState==PLAY_BY_FREQ) // when play by Freq
845 {
846 if(MuteVolume==0)
847 {
848 MuteVolume=CurrentVolume;
849 MyRadio.SetMute(false);
850 LCDDISPLAY.setCursor(4, 1);
851 LCDDISPLAY.print(CurrentVolume/10);
852 LCDDISPLAY.print(CurrentVolume%10);
853 if(FreqMode10x==true) LCDDISPLAY.setCursor(10, 0);
854 else LCDDISPLAY.setCursor(12, 0);
855
856 }
857 else
858 {
859 MuteVolume=0;
860 MyRadio.SetMute(true);
861 LCDDISPLAY.setCursor(4, 1);
862 LCDDISPLAY.print("--");
863 if(FreqMode10x==true) LCDDISPLAY.setCursor(10, 0);
864 else LCDDISPLAY.setCursor(12, 0);
865 }
866
867 }
868 else // when play by SEEK, CHANNEL
869 {
870 if(MuteVolume==0)
871 {
872 MuteVolume=CurrentVolume;
873 DisplayPlayInfo(CurrentChannelInfo,CurrentVolume);
874 //Set mute here
875 MyRadio.SetMute(false);
876 }
877 else
878 {
879 MuteVolume=0;
880 DisplayPlayInfo(CurrentChannelInfo,CurrentVolume);
881 //Set unmute here
882 MyRadio.SetMute(true);
883 }
884 }
885
886
887}
888
889void SeekChannel()
890{
891 unsigned int GetFreq;
892 CurrentChannelInfo.ChannelIndex=0xFF;
893 CurrentChannelInfo.ChannelName[0]='_';
894 CurrentChannelInfo.ChannelName[1]='_';
895 CurrentChannelInfo.ChannelName[2]='_';
896 CurrentChannelInfo.ChannelName[3]='_';
897 CurrentChannelInfo.ChannelName[4]='_';
898 //Seek up channel here
899 MyRadio.SeekUp();
900 GetFreq=MyRadio.GetFrequency();
901 CurrentChannelInfo.ChannelFreq=GetFreq;
902 CurrentFreq=CurrentChannelInfo.ChannelFreq;
903 DisplayPlayInfo(CurrentChannelInfo,CurrentVolume);
904 LCDDISPLAY.noBlink();
905}
906
907
908void SaveChannel()
909{
910 CurrentChannelInfo.ChannelIndex=NumofChannel;
911 NumofChannel++;
912 CurrentChannelIndex=NumofChannel;
913 CurrentChannelInfo.ChannelIndex=NumofChannel;
914 CurrentChannelInfo.ChannelName[0]=SaveChannelName[0];
915 CurrentChannelInfo.ChannelName[1]=SaveChannelName[1];
916 CurrentChannelInfo.ChannelName[2]=SaveChannelName[2];
917 CurrentChannelInfo.ChannelName[3]=SaveChannelName[3];
918 CurrentChannelInfo.ChannelName[4]=SaveChannelName[4];
919 CurrentChannelInfo.ChannelFreq=CurrentFreq;
920 SaveChanneltoROM(CurrentChannelInfo);
921 SaveRadioParametertoROM();
922}
923
924void UpdateChannel()
925{
926 CurrentChannelInfo.ChannelIndex=CurrentChannelIndex;
927 CurrentChannelInfo.ChannelName[0]=SaveChannelName[0];
928 CurrentChannelInfo.ChannelName[1]=SaveChannelName[1];
929 CurrentChannelInfo.ChannelName[2]=SaveChannelName[2];
930 CurrentChannelInfo.ChannelName[3]=SaveChannelName[3];
931 CurrentChannelInfo.ChannelName[4]=SaveChannelName[4];
932 CurrentChannelInfo.ChannelFreq=CurrentFreq;
933 SaveChanneltoROM(CurrentChannelInfo);
934 SaveRadioParametertoROM();
935
936}
937
938void EditChannel()
939{
940 byte FreqDisplay;
941 RadioChannelInfo ChannelInfo;
942
943 ChannelInfo = GetChannelROM(CurrentChannelIndex);
944 SaveChannelName[0]=ChannelInfo.ChannelName[0];
945 SaveChannelName[1]=ChannelInfo.ChannelName[1];
946 SaveChannelName[2]=ChannelInfo.ChannelName[2];
947 SaveChannelName[3]=ChannelInfo.ChannelName[3];
948 SaveChannelName[4]=ChannelInfo.ChannelName[4];
949
950
951 LCDDISPLAY.setCursor(8, 0);
952 LCDDISPLAY.print(CurrentChannelIndex/10);
953 LCDDISPLAY.print(CurrentChannelIndex%10);
954 LCDDISPLAY.setCursor(0, 1);
955 LCDDISPLAY.print(SaveChannelName);
956
957 LCDDISPLAY.setCursor(7, 1);
958 CurrentFreq=ChannelInfo.ChannelFreq;
959 FreqDisplay=CurrentFreq/10000;
960 if(FreqDisplay!=0) LCDDISPLAY.print(FreqDisplay);
961 else LCDDISPLAY.print(" ");
962 FreqDisplay=(CurrentFreq%10000)/1000;
963 LCDDISPLAY.print(FreqDisplay);
964 FreqDisplay=(CurrentFreq%1000)/100;
965 LCDDISPLAY.print(FreqDisplay);
966 LCDDISPLAY.print(".");
967 FreqDisplay=(CurrentFreq%100)/10;
968 LCDDISPLAY.print(FreqDisplay);
969
970 LCDDISPLAY.setCursor(0, 1);
971 LCDDISPLAY.blink();
972 CurrentCharacterIndex=0;
973 CurrentCharacter=SaveChannelName[CurrentCharacterIndex];
974}
975
976void DisplayRemoveChannel()
977{
978 byte FreqDisplay;
979 CurrentChannelInfo=GetChannelROM(CurrentChannelIndex);
980 LCDDISPLAY.setCursor(12, 0);
981 LCDDISPLAY.print(CurrentChannelIndex/10);
982 LCDDISPLAY.print(CurrentChannelIndex%10);
983 LCDDISPLAY.setCursor(0, 1);
984 if(CurrentChannelInfo.ChannelName[0]!=0) LCDDISPLAY.print(CurrentChannelInfo.ChannelName[0]);
985 else LCDDISPLAY.print(" ");
986 if(CurrentChannelInfo.ChannelName[1]!=0) LCDDISPLAY.print(CurrentChannelInfo.ChannelName[1]);
987 else LCDDISPLAY.print(" ");
988 if(CurrentChannelInfo.ChannelName[2]!=0) LCDDISPLAY.print(CurrentChannelInfo.ChannelName[2]);
989 else LCDDISPLAY.print(" ");
990 if(CurrentChannelInfo.ChannelName[3]!=0) LCDDISPLAY.print(CurrentChannelInfo.ChannelName[3]);
991 else LCDDISPLAY.print(" ");
992 if(CurrentChannelInfo.ChannelName[4]!=0) LCDDISPLAY.print(CurrentChannelInfo.ChannelName[4]);
993 else LCDDISPLAY.print(" ");
994 LCDDISPLAY.print(" ");
995
996 LCDDISPLAY.setCursor(7, 1);
997 CurrentFreq=CurrentChannelInfo.ChannelFreq;
998 FreqDisplay=CurrentFreq/10000;
999 if(FreqDisplay!=0) LCDDISPLAY.print(FreqDisplay);
1000 else LCDDISPLAY.print(" ");
1001 FreqDisplay=(CurrentFreq%10000)/1000;
1002 LCDDISPLAY.print(FreqDisplay);
1003 FreqDisplay=(CurrentFreq%1000)/100;
1004 LCDDISPLAY.print(FreqDisplay);
1005 LCDDISPLAY.print(".");
1006 FreqDisplay=(CurrentFreq%100)/10;
1007 LCDDISPLAY.print(FreqDisplay);
1008
1009 LCDDISPLAY.setCursor(13, 0);
1010 LCDDISPLAY.blink();
1011}
1012
1013void DisplaySetBackLight()
1014{
1015
1016 LCDDISPLAY.setCursor(14, 0);
1017 LCDDISPLAY.print(CurrentBacklightLife/10);
1018 LCDDISPLAY.print(CurrentBacklightLife%10);
1019 LCDDISPLAY.setCursor(15, 0);
1020 LCDDISPLAY.blink();
1021}
1022
1023
1024
1025byte CheckButton(bool ActiveLevel)
1026{
1027 unsigned long CurrentTimecount;
1028 unsigned long PreviousTimecount;
1029 const unsigned long Buttonholdtime=500;
1030 byte Checkresult;
1031 bool TimeOver;
1032 Checkresult = NO_BUTTON_PRESS;
1033
1034 if(digitalRead(BMenu)==ActiveLevel) // Button was press.
1035 {
1036 ActiveBackLight();
1037 delay(200); // debounce button
1038 PreviousTimecount=millis();
1039 TimeOver=false;
1040 while(digitalRead(BMenu)==ActiveLevel && TimeOver==false)// Wait until button release
1041 {
1042 CurrentTimecount=millis();
1043 if(CurrentTimecount-PreviousTimecount>Buttonholdtime) TimeOver=true;
1044 }
1045 if(TimeOver==true)
1046 {
1047 Checkresult = MENU_LONG_PRESS;
1048 ButtonHolding=true;
1049 }
1050 else if(ButtonHolding==false) Checkresult = MENU_SHORT_PRESS; // First press after release
1051
1052 }
1053 else if(digitalRead(BUp)==ActiveLevel) // Button was press.
1054 {
1055 ActiveBackLight();
1056 delay(200); // debounce button
1057 PreviousTimecount=millis();
1058 TimeOver=false;
1059 while(digitalRead(BUp)==ActiveLevel && TimeOver==false)// Wait until button release
1060 {
1061 CurrentTimecount=millis();
1062 if(CurrentTimecount-PreviousTimecount>Buttonholdtime) TimeOver=true;
1063 }
1064 if(TimeOver==true)
1065 {
1066 Checkresult = UP_LONG_PRESS;
1067 ButtonHolding=true;
1068 }
1069 else if(ButtonHolding==false) Checkresult = UP_SHORT_PRESS; // First press after release
1070 }
1071 else if(digitalRead(BDown)==ActiveLevel) // Button was press.
1072 {
1073 ActiveBackLight();
1074 delay(200); // debounce button
1075 PreviousTimecount=millis();
1076 TimeOver=false;
1077 while(digitalRead(BDown)==ActiveLevel && TimeOver==false)// Wait until button release
1078 {
1079 CurrentTimecount=millis();
1080 if(CurrentTimecount-PreviousTimecount>Buttonholdtime) TimeOver=true;
1081 }
1082 if(TimeOver==true)
1083 {
1084 Checkresult = DOWN_LONG_PRESS;
1085 ButtonHolding=true;
1086 }
1087 else if(ButtonHolding==false) Checkresult = DOWN_SHORT_PRESS; // First press after release
1088 }
1089 else if(digitalRead(BEnter)==ActiveLevel) // Button was press.
1090 {
1091 ActiveBackLight();
1092 delay(200); // debounce button
1093 PreviousTimecount=millis();
1094 TimeOver=false;
1095 while(digitalRead(BEnter)==ActiveLevel && TimeOver==false)// Wait until button release
1096 {
1097 CurrentTimecount=millis();
1098 if(CurrentTimecount-PreviousTimecount>Buttonholdtime) TimeOver=true;
1099 }
1100 if(TimeOver==true)
1101 {
1102 Checkresult = ENTER_LONG_PRESS;
1103 ButtonHolding=true;
1104 }
1105 else if(ButtonHolding==false) Checkresult = ENTER_SHORT_PRESS; // First press after release
1106 }
1107 else ButtonHolding=false; // No button pressed. release holding variable
1108 return Checkresult;
1109}
1110
1111
1112
1113void ProcessButton(byte ButtonData,byte CurrentStateData)
1114{
1115
1116 switch(ButtonData)
1117 {
1118 case MENU_SHORT_PRESS:
1119 {
1120 switch(CurrentStateData)
1121 {
1122 case NO_CHANNEL_FOUND:
1123 {
1124 CurrentState=FIRST_SETUP_SELECT;
1125 LCDDisplay(CurrentState);
1126 break;
1127 }
1128 case DONE_LOAD_VN_CHANNEL: case REMOVE_CHANNEL_DONE:
1129 {
1130 CurrentChannelInfo=GetChannelROM(CurrentChannelIndex);
1131 PlayFM(CurrentChannelInfo,CurrentVolume);
1132 break;
1133 }
1134
1135 case SEEKING:
1136 {
1137 CurrentState=SAVE_CHANNEL_SEEK;
1138 CurrentCharacterIndex=0;
1139 SaveChannelName[0]=0;
1140 SaveChannelName[1]=0;
1141 SaveChannelName[2]=0;
1142 SaveChannelName[3]=0;
1143 SaveChannelName[4]=0;
1144 DisplaySaveChannel();
1145 break;
1146 }
1147 case PLAY_BY_FREQ:
1148 {
1149 DisplaySaveFrequency();
1150 CurrentState=SAVE_CHANNEL_FREQ;
1151 CurrentCharacterIndex=0;
1152 SaveChannelName[0]=0;
1153 SaveChannelName[1]=0;
1154 SaveChannelName[2]=0;
1155 SaveChannelName[3]=0;
1156 SaveChannelName[4]=0;
1157 DisplaySaveChannel();
1158 break;
1159 }
1160 case SAVE_CHANNEL_SEEK: case SAVE_CHANNEL_FREQ:
1161 {
1162 SaveChannel();
1163 CurrentState=PLAYING;
1164 CurrentChannelIndex--;
1165 PlayNextChannel();
1166 break;
1167 }
1168 case EDIT_CHANNEL:
1169 {
1170 UpdateChannel();
1171 CurrentState=PLAYING;
1172 CurrentChannelIndex--;
1173 PlayNextChannel();
1174 break;
1175 }
1176 case PLAYING:
1177 {
1178 StopPlayFM();
1179 CurrentState=MENU_PAGE1;
1180 LCDDisplay(CurrentState);
1181 break;
1182 }
1183 case MENU_PAGE1:
1184 {
1185 CurrentState=MENU_PAGE2;
1186 LCDDisplay(CurrentState);
1187 break;
1188 }
1189
1190 case MENU_PAGE2:
1191 {
1192 CurrentState=MENU_PAGE3;
1193 LCDDisplay(CurrentState);
1194 break;
1195 }
1196
1197 case MENU_PAGE3:
1198 {
1199 CurrentState=PLAYING;
1200 CurrentChannelIndex--;
1201 PlayNextChannel();
1202 break;
1203 }
1204 case DONE_ERASE_ALL:
1205 {
1206 CurrentState=NO_CHANNEL_FOUND;
1207 LCDDisplay(CurrentState);
1208 break;
1209 }
1210 }
1211 break;
1212 }
1213
1214 case MENU_LONG_PRESS:
1215 {
1216 switch(CurrentStateData)
1217 {
1218 case SAVE_CHANNEL_SEEK:
1219 {
1220 DisplayPlayInfo(CurrentChannelInfo,CurrentVolume);
1221 LCDDISPLAY.noBlink();
1222 CurrentState=SEEKING;
1223 break;
1224 }
1225 case SAVE_CHANNEL_FREQ:
1226 {
1227 CurrentState=PLAY_BY_FREQ;
1228 LCDDisplay(CurrentState);
1229 PlaybyFreq(CurrentFreq);
1230 break;
1231 }
1232 case EDIT_CHANNEL:
1233 {
1234 CurrentState=PLAYING;
1235 CurrentChannelIndex--;
1236 PlayNextChannel();
1237 break;
1238 }
1239 case MENU_PAGE1: case MENU_PAGE2: case MENU_PAGE3: case LOAD_DEFAULT_DATA: case SET_BACKLIGHT:
1240 {
1241 PlayFM(CurrentChannelInfo,CurrentVolume);
1242 CurrentState=PLAYING;
1243 break;
1244 }
1245 case PLAYING: case SEEKING:
1246 {
1247 LastState=CurrentState;
1248 CurrentState=DISPLAY_CHANNEL_INFO;
1249 LCDDisplay(CurrentState);
1250 DisplayFMInfo();
1251 break;
1252 }
1253 case DISPLAY_CHANNEL_INFO:
1254 {
1255 CurrentState=LastState;
1256 LCDDisplay(PLAYING);
1257 DisplayPlayInfo(CurrentChannelInfo,CurrentVolume);
1258 break;
1259 }
1260 case PLAY_BY_FREQ:
1261 {
1262 CurrentChannelIndex--;
1263 PlayNextChannel();
1264 break;
1265 }
1266 }
1267 break;
1268 }
1269
1270 case UP_SHORT_PRESS:
1271 {
1272 switch(CurrentStateData)
1273 {
1274 case FIRST_SETUP_SELECT:
1275 {
1276 CurrentState=PLAYING;
1277 CurrentVolume=8;
1278 NumofChannel=0;
1279 CurrentChannelIndex=0;
1280 SaveRadioParametertoROM();
1281 LCDDisplay(CurrentState);
1282 CurrentState=SEEKING;
1283 SeekChannel();
1284 break;
1285 }
1286 case PLAYING: case SEEKING:
1287 {
1288 PlayNextChannel();
1289 break;
1290 }
1291
1292 case SAVE_CHANNEL_SEEK: case EDIT_CHANNEL: case SAVE_CHANNEL_FREQ:
1293 {
1294 InceaseCharacter();
1295 break;
1296 }
1297 case MENU_PAGE1:
1298 {
1299 CurrentState = PLAY_BY_FREQ;
1300 FreqMode10x=false;
1301 LCDDisplay(CurrentState);
1302 CurrentFreq=MyRadio.MinFreq;// Lowest FM Freq
1303 PlaybyFreq(CurrentFreq);
1304
1305 break;
1306 }
1307
1308 case MENU_PAGE2:
1309 {
1310 CurrentState = REMOVE_CHANNEL;
1311 LCDDisplay(CurrentState);
1312 DisplayRemoveChannel();
1313
1314 break;
1315 }
1316 case MENU_PAGE3:
1317 {
1318 CurrentState = SET_BACKLIGHT;
1319 LCDDisplay(CurrentState);
1320 DisplaySetBackLight();
1321 break;
1322 }
1323
1324 case PLAY_BY_FREQ:
1325 {
1326 IncreaseFreqPlay();
1327 break;
1328 }
1329
1330 case REMOVE_CHANNEL:
1331 {
1332 CurrentChannelIndex++;
1333 if(CurrentChannelIndex>NumofChannel) CurrentChannelIndex=1;
1334 DisplayRemoveChannel();
1335 break;
1336 }
1337 case SET_BACKLIGHT:
1338 {
1339 CurrentBacklightLife++;
1340 if(CurrentBacklightLife>15) CurrentBacklightLife=15;
1341 DisplaySetBackLight();
1342 break;
1343 }
1344 }
1345 break;
1346 }
1347
1348 case UP_LONG_PRESS:
1349 {
1350 switch(CurrentStateData)
1351 {
1352 case PLAYING: case SEEKING: case PLAY_BY_FREQ:
1353 {
1354 IncVol();
1355 break;
1356 }
1357 }
1358 break;
1359 }
1360
1361 case DOWN_SHORT_PRESS:
1362 {
1363 switch(CurrentStateData)
1364 {
1365 case FIRST_SETUP_SELECT:
1366 {
1367 LoadDefaultChannel();
1368 CurrentState=DONE_LOAD_VN_CHANNEL;
1369 LCDDisplay(CurrentState);
1370 break;
1371 }
1372 case PLAYING: case SEEKING:
1373 {
1374 PlayPrevChannel();
1375 break;
1376 }
1377 case SAVE_CHANNEL_SEEK: case EDIT_CHANNEL: case SAVE_CHANNEL_FREQ:
1378 {
1379 DecreaseCharacter();
1380 break;
1381 }
1382 case MENU_PAGE1:
1383 {
1384 CurrentState=EDIT_CHANNEL;
1385 LCDDisplay(CurrentState);
1386 CurrentCharacterIndex=0;
1387 EditChannel();
1388 break;
1389 }
1390 case MENU_PAGE2:
1391 {
1392 CurrentState=ERASE_ALL;
1393 LCDDisplay(CurrentState);
1394 break;
1395 }
1396
1397 case MENU_PAGE3:
1398 {
1399 CurrentState=LOAD_DEFAULT_DATA;
1400 LCDDisplay(CurrentState);
1401 break;
1402 }
1403
1404 case PLAY_BY_FREQ:
1405 {
1406 DecreaseFreqPlay();
1407 break;
1408 }
1409
1410 case REMOVE_CHANNEL:
1411 {
1412 CurrentChannelIndex--;
1413 if(CurrentChannelIndex==0) CurrentChannelIndex=NumofChannel;
1414 DisplayRemoveChannel();
1415 break;
1416 }
1417
1418 case SET_BACKLIGHT:
1419 {
1420 CurrentBacklightLife--;
1421 if(CurrentBacklightLife==255) CurrentBacklightLife=0;
1422 DisplaySetBackLight();
1423 break;
1424 }
1425 }
1426 break;
1427 }
1428
1429 case DOWN_LONG_PRESS:
1430 {
1431 switch(CurrentStateData)
1432 {
1433 case PLAYING: case SEEKING: case PLAY_BY_FREQ:
1434 {
1435 DecVol();
1436 break;
1437 }
1438 }
1439 break;
1440 }
1441
1442 case ENTER_SHORT_PRESS:
1443 {
1444 switch(CurrentStateData)
1445 {
1446 case PLAYING: case SEEKING: case PLAY_BY_FREQ:
1447 {
1448 Mute_Unmute();
1449 break;
1450 }
1451 case SAVE_CHANNEL_SEEK:
1452 {
1453 CurrentCharacterIndex++;
1454 if(CurrentCharacterIndex==5) CurrentCharacterIndex=0;
1455 DisplaySaveChannel();
1456 break;
1457 }
1458 case EDIT_CHANNEL: case SAVE_CHANNEL_FREQ:
1459 {
1460 CurrentCharacterIndex++;
1461 if(CurrentCharacterIndex==5) CurrentCharacterIndex=0;
1462 LCDDISPLAY.setCursor(CurrentCharacterIndex, 1);
1463 break;
1464 }
1465 case ERASE_ALL:
1466 {
1467 CurrentState=DATA_ERASING;
1468 LCDDisplay(CurrentState);
1469 EraseAllChannelInROM();
1470 CurrentState=DONE_ERASE_ALL;
1471 LCDDisplay(CurrentState);
1472 break;
1473 }
1474 case REMOVE_CHANNEL:
1475 {
1476 RemoveChannelfromROM(CurrentChannelIndex);
1477 CurrentState=REMOVE_CHANNEL_DONE;
1478 LCDDisplay(CurrentState);
1479 CurrentChannelIndex--;
1480 break;
1481 }
1482 case LOAD_DEFAULT_DATA:
1483 {
1484 LoadDefaultChannel();
1485 CurrentState=DONE_LOAD_VN_CHANNEL;
1486 LCDDisplay(CurrentState);
1487 break;
1488 }
1489 case SET_BACKLIGHT:
1490 {
1491 WriteCurrentBackLightLife(CurrentBacklightLife);
1492 PlayFM(CurrentChannelInfo,CurrentVolume);
1493 CurrentState=PLAYING;
1494 break;
1495 }
1496 }
1497 break;
1498 }
1499
1500 case ENTER_LONG_PRESS:
1501 {
1502 switch(CurrentStateData)
1503 {
1504 case PLAYING: case SAVE_CHANNEL_SEEK: case SEEKING:
1505 {
1506 CurrentState=SEEKING;
1507 SeekChannel();
1508 break;
1509 }
1510 case PLAY_BY_FREQ:
1511 {
1512 ChangeFreqTurn();
1513 break;
1514 }
1515 }
1516 break;
1517 }
1518 }
1519}
1520void ActiveBackLight()
1521{
1522 ONLCDLED;
1523 BackLighOnpoint=millis();
1524}
1525
1526void CheckBackLightLife()
1527{
1528 unsigned int CurrentTimePoint;
1529 if(CurrentBacklightLife>0)
1530 {
1531 CurrentTimePoint=millis();
1532 if(CurrentTimePoint-BackLighOnpoint>(CurrentBacklightLife*1000))
1533 {
1534 OFFLCDLED;
1535 }
1536 }
1537}
1538
1539
1540void setup() {
1541 pinMode(BMenu,INPUT_PULLUP);
1542 pinMode(BEnter,INPUT_PULLUP);
1543 pinMode(BUp,INPUT_PULLUP);
1544 pinMode(BDown,INPUT_PULLUP);
1545 pinMode(LCDBackLight,OUTPUT);
1546 ONLCDLED;
1547 BackLighOnpoint=millis();
1548
1549 LCDDISPLAY.createChar(0, SignalChar);
1550 LCDDISPLAY.createChar(1, Signal100);
1551 LCDDISPLAY.createChar(2, Signal80);
1552 LCDDISPLAY.createChar(3, Signal60);
1553 LCDDISPLAY.createChar(4, Signal40);
1554 LCDDISPLAY.createChar(5, Signal20);
1555 LCDDISPLAY.createChar(6, Signal0);
1556 LCDDISPLAY.createChar(7, Playsign);
1557 LCDDISPLAY.begin(16,2);
1558 Serial.begin(9600);
1559 DisplayWelCome();
1560 ButtonHolding=false;
1561 MuteVolume=1;
1562 RadioFound = MyRadio.Radioinit(); // Return to true if found RDA5807M chips. else, return false.
1563 if(RadioFound==false)
1564 {
1565 CurrentState=NO_RADIO_FOUND;
1566 LCDDisplay(CurrentState);
1567 }
1568 else
1569 {
1570 //EEPROM.write(0x0000,0xFF);
1571 NumofChannel=EEPROM.read(0x0000);
1572 if(NumofChannel>200 or NumofChannel==0) // Max storage is 200 channel. if greater than 200 mean no data
1573 {
1574 ChannelDefined=false; // not yet found channel save in ROM.
1575 CurrentState=NO_CHANNEL_FOUND;
1576 LCDDisplay(CurrentState);
1577 }
1578 else
1579 {
1580 ChannelDefined=true; //Found channel as found number of channel at 0x0000 ROM
1581 GetLastPlayingToCurrent();
1582 CurrentChannelInfo=GetChannelROM(CurrentChannelIndex);
1583 PlayFM(CurrentChannelInfo,CurrentVolume);
1584 }
1585 }
1586
1587 CurrentBacklightLife=ReadCurrentBackLightLife();
1588 if(CurrentBacklightLife>15)
1589 {CurrentBacklightLife=5;
1590 WriteCurrentBackLightLife(CurrentBacklightLife);
1591 }
1592}
1593
1594void loop()
1595{
1596 byte CheckButtonResult;
1597 CheckButtonResult=CheckButton(ACTIVE_HIGH);
1598 ProcessButton(CheckButtonResult,CurrentState);
1599 CheckBackLightLife();
1600 }
1601
1602
RADIO_RDA5807M_VN.zip
Library for RDA5807M
1inary file (no preview
NANOFMRADIO.ino
arduino
1
2
3/*
4 * FM CHANNEL AT HO CHI MINH CITY - VIET NAM
5 * VOHKT
6 87.7
7 * VOV89 89
8 * VOVGT 91
9 * BINHD 92.5
10 * VOV1 94
11 *
12 VOHGT 95.6
13 * VOV2 96.5
14 * DONGN 97.5
15 * VOHFM 99.9
16 * TA247
17 104
18 * VOV3 104.5
19 * VOV5 105.7
20 */
21
22
23
24
25
26#include
27 <Wire.h>
28#include <LiquidCrystal.h>
29#include <EEPROM.h>
30#include <RADIO_RDA5807M.h>
31
32
33//Define
34 byte of custom char in LCD
35#define DSignalchar byte(0)
36#define DSignal100
37 byte(1)
38#define DSignal80 byte(2)
39#define DSignal60 byte(3)
40#define
41 DSignal40 byte(4)
42#define DSignal20 byte(5)
43#define DSignal0 byte(6)
44#define
45 DPlaysign byte(7)
46
47//Define button Pin No
48#define BMenu 2
49#define
50 BEnter 3
51#define BDown 4
52#define BUp 5
53#define LCDBackLight 6
54
55//Define
56 Buton active level
57#define ACTIVE_LOW 0
58#define ACTIVE_HIGH 1
59
60//define
61 State of device
62#define NO_RADIO_FOUND 0
63#define NO_CHANNEL_FOUND
64 1
65#define FIRST_SETUP_SELECT 2
66#define DONE_LOAD_VN_CHANNEL 3
67#define
68 PLAYING 4
69#define SEEKING 5
70#define SAVE_CHANNEL_SEEK
71 6
72#define MENU_PAGE1 7
73#define MENU_PAGE2 8
74#define
75 MENU_PAGE3 9
76#define PLAY_BY_FREQ 10
77#define EDIT_CHANNEL
78 11
79#define REMOVE_CHANNEL 12
80#define ERASE_ALL 13
81#define
82 REMOVE_CHANNEL_DONE 14
83#define LCD_BACKLIGHT 15
84#define DONE_ERASE_ALL
85 16
86#define DATA_ERASING 17
87#define DISPLAY_CHANNEL_INFO
88 18
89#define SAVE_CHANNEL_FREQ 19
90#define LOAD_DEFAULT_DATA 20
91#define
92 SET_BACKLIGHT 21
93
94
95
96//define ButtonState
97#define NO_BUTTON_PRESS
98 0
99#define MENU_LONG_PRESS 1
100#define MENU_SHORT_PRESS 2
101#define
102 UP_LONG_PRESS 3
103#define UP_SHORT_PRESS 4
104#define DOWN_LONG_PRESS
105 5
106#define DOWN_SHORT_PRESS 6
107#define ENTER_LONG_PRESS 7
108#define
109 ENTER_SHORT_PRESS 8
110
111//Define BackLight macro
112#define ONLCDLED digitalWrite(LCDBackLight,
113 LOW)
114#define OFFLCDLED digitalWrite(LCDBackLight, HIGH)
115
116struct RadioChannelInfo
117{
118
119 uint8_t ChannelIndex;
120 char ChannelName[5];
121 unsigned int ChannelFreq;
122};
123
124
125LiquidCrystal
126 LCDDISPLAY(12, 11, 10, 9, 8, 7);
127
128byte SignalChar[8] = {31,14,4,4,4,4,4,0};
129byte
130 Signal100[8]= {1,3,7,15,31,0,31,0};
131byte Signal80[8]= {0,2,6,14,30,0,31,0};
132byte
133 Signal60[8]= {0,0,4,12,28,0,31,0};
134byte Signal40[8]= {0,0,0,8,24,0,31,0};
135byte
136 Signal20[8]= {0,0,0,0,16,0,31,0};
137byte Signal0[8]= {17,10,4,10,17,0,31,0};
138byte
139 Playsign[8]= {16,24,28,30,30,28,24,16};
140
141const byte DefaultROMDataVietnamChannel[]=
142 {1,'V','O','H','K','T',0x22,0x42,
143 2,'V','O','V','8','9',0x22,0xC4,
144
145 3,'V','O','V','G','T',0x23,0x8C,
146
147 4,'B','I','N','H','D',0x24,0x22,
148
149 5,'V','O','V','1',0,0x24,0xB8,
150
151 6,'V','O','H','G','T',0x25,0x58,
152
153 7,'V','O','V','2',0,0x25,0xB2,
154
155 8,'D','O','N','G','N',0x26,0x16,
156
157 9,'V','O','H','F','M',0x27,0x06,
158
159 10,'T','A','2','4',0,0x28,0xA0,
160
161 11,'V','O','V','3',0,0x28,0xD2,
162
163 12,'V','O','V','5',0,0x29,0x4A
164
165 };
166
167
168
169byte
170 SignalLevel;
171byte CurrentState;
172byte LastState;
173RadioChannelInfo CurrentChannelInfo;
174byte
175 CurrentChannelIndex;
176byte CurrentVolume;
177byte MuteVolume=1;
178unsigned int
179 CurrentFreq;
180bool FreqMode10x;
181
182byte CurrentBacklightLife=5;
183unsigned
184 int BackLighOnpoint;
185
186RDA5807M MyRadio;
187bool RadioFound;
188bool ChannelDefined;
189byte
190 ROMData;
191byte NumofChannel;
192byte CurrentCharacter=0;
193byte CurrentCharacterIndex=0;
194char
195 SaveChannelName[5];
196
197
198bool ButtonHolding=false;
199
200byte ReadCurrentBackLightLife()
201{
202
203 byte ReturnBacklightLife;
204 ReturnBacklightLife=EEPROM.read(0x03);
205 return
206 ReturnBacklightLife;
207}
208
209void WriteCurrentBackLightLife(byte LifeSecond)
210{
211
212 EEPROM.write(0x03,LifeSecond);
213}
214
215void SaveChanneltoROM(RadioChannelInfo
216 ChannelDataSave)
217{
218 byte RomAddress;
219 byte FreqData;
220 RomAddress=((ChannelDataSave.ChannelIndex-1)*8)+10;
221
222 EEPROM.write(RomAddress,ChannelDataSave.ChannelIndex);
223 EEPROM.write(RomAddress+1,ChannelDataSave.ChannelName[0]);
224
225 EEPROM.write(RomAddress+2,ChannelDataSave.ChannelName[1]);
226 EEPROM.write(RomAddress+3,ChannelDataSave.ChannelName[2]);
227
228 EEPROM.write(RomAddress+4,ChannelDataSave.ChannelName[3]);
229 EEPROM.write(RomAddress+5,ChannelDataSave.ChannelName[4]);
230
231 FreqData=highByte(ChannelDataSave.ChannelFreq);
232 EEPROM.write(RomAddress+6,FreqData);
233
234 FreqData=lowByte(ChannelDataSave.ChannelFreq);
235 EEPROM.write(RomAddress+7,FreqData);
236}
237
238void
239 SaveRadioParametertoROM()
240{
241 EEPROM.write(0,NumofChannel);
242 EEPROM.write(1,CurrentChannelIndex);
243
244 if(CurrentVolume==0) CurrentVolume = 8; //Prevent from saving mute
245 EEPROM.write(2,CurrentVolume);
246}
247void
248 EraseAllChannelInROM()
249{
250 unsigned int RomAddress;
251 EEPROM.write(0,0xFF);//Num
252 of channel
253 EEPROM.write(1,0);//current channel
254 EEPROM.write(2,8);//Current
255 volume
256 for(RomAddress=3;RomAddress<400;RomAddress++)
257 {
258 EEPROM.write(RomAddress,0xFF);
259
260 }
261
262}
263
264void RemoveChannelfromROM(byte RemoveChannelIndex)
265{
266
267 byte ChannelIndexMoving;
268 RadioChannelInfo ChannelInArray;
269 for(ChannelIndexMoving=RemoveChannelIndex+1;ChannelIndexMoving<=NumofChannel;ChannelIndexMoving++)//
270 re-arrange the channel array (shift left)
271 {
272 ChannelInArray=GetChannelROM(ChannelIndexMoving);
273
274 ChannelInArray.ChannelIndex=ChannelInArray.ChannelIndex-1;
275 SaveChanneltoROM(ChannelInArray);
276
277 }
278 NumofChannel=NumofChannel-1;
279 SaveRadioParametertoROM();
280}
281
282void
283 LoadDefaultChannel()
284{
285 byte RomAddress;
286 byte DataArrayIndex;
287 DataArrayIndex=0;
288
289 EEPROM.write(0x00,12); // save number of channel
290 EEPROM.write(0x01,1); //
291 save Current channel index
292 EEPROM.write(0x02,8); // save Current volume
293
294 EEPROM.write(0x03,5); // save Current backlight life second
295 for(RomAddress=10;RomAddress<106;RomAddress++)
296
297 {
298 EEPROM.write(RomAddress,DefaultROMDataVietnamChannel[DataArrayIndex]);
299
300 DataArrayIndex++;
301 }
302 NumofChannel=12;
303 CurrentChannelIndex=1;
304
305 CurrentVolume=8;
306}
307
308RadioChannelInfo GetChannelROM(byte ChannelIndex)
309{
310
311 byte ROMAddress;
312 uint16_t ROMChannelFreq;
313 RadioChannelInfo ReturnChannel;
314
315
316 ROMAddress=(ChannelIndex-1)*8 + 10;// 10 is ROm slot use for Num of channel, curent
317 channel,LED backlight time and volume storage, user storage
318 ReturnChannel.ChannelIndex=EEPROM.read(ROMAddress);
319
320 ReturnChannel.ChannelName[0]=EEPROM.read(ROMAddress+1);
321 ReturnChannel.ChannelName[1]=EEPROM.read(ROMAddress+2);
322
323 ReturnChannel.ChannelName[2]=EEPROM.read(ROMAddress+3);
324 ReturnChannel.ChannelName[3]=EEPROM.read(ROMAddress+4);
325
326 ReturnChannel.ChannelName[4]=EEPROM.read(ROMAddress+5);
327 ROMChannelFreq=EEPROM.read(ROMAddress+6);
328
329 ROMChannelFreq=ROMChannelFreq<<8;
330 ROMChannelFreq=ROMChannelFreq+EEPROM.read(ROMAddress+7);
331
332 ReturnChannel.ChannelFreq=ROMChannelFreq;
333 return ReturnChannel;
334}
335
336void
337 GetLastPlayingToCurrent()
338{
339 NumofChannel=EEPROM.read(0x0000);
340 CurrentChannelIndex=EEPROM.read(0x0001);
341
342 CurrentVolume=EEPROM.read(0x0002);
343}
344
345
346
347
348void DisplayWelCome()
349 {
350 LCDDISPLAY.setCursor(4, 0);
351 LCDDISPLAY.print("RADIO FM");
352 LCDDISPLAY.setCursor(14,
353 0);
354 LCDDISPLAY.write(DSignalchar);
355 LCDDISPLAY.setCursor(0, 1);
356 LCDDISPLAY.print("Have
357 fun time!!!");
358 delay(1000);
359}
360
361
362void Displaysignal(byte SignalLevelDisplay)
363{
364
365 LCDDISPLAY.setCursor(14, 0);
366 LCDDISPLAY.write(DSignalchar);
367 SignalLevelDisplay=SignalLevelDisplay/20;
368
369 switch(SignalLevelDisplay)
370 {
371 case 0:
372 {
373 LCDDISPLAY.write(DSignal0);
374
375 break;
376 }
377 case 1:
378 {
379 LCDDISPLAY.write(DSignal20);
380
381 break;
382 }
383 case 2:
384 {
385 LCDDISPLAY.write(DSignal40);
386
387 break;
388 }
389 case 3:
390 {
391 LCDDISPLAY.write(DSignal60);
392
393 break;
394 }
395 case 4:
396 {
397 LCDDISPLAY.write(DSignal80);
398
399 break;
400 }
401 case 5:
402 {
403 LCDDISPLAY.write(DSignal100);
404
405 break;
406 }
407 }
408}
409
410void DisplayPlayInfo(RadioChannelInfo ChannelData,byte
411 Voldata)
412{
413 byte Voldisplay;
414 byte FreqDisplay;
415 byte FMInfoData; //yzzzzzzz
416 bit y=1: is station found, zzzzzzz: RSSI data
417 unsigned int RSSIData;
418 byte
419 RSSILevel;
420
421 LCDDISPLAY.setCursor(0, 0);
422 if(ChannelData.ChannelIndex==0xFF)
423 LCDDISPLAY.print("SEK");
424 else
425 {
426 LCDDISPLAY.print(ChannelData.ChannelIndex/10);
427
428 LCDDISPLAY.print(ChannelData.ChannelIndex%10);
429 }
430 if(MuteVolume!=0)
431
432 {
433 Voldata=Voldata/2; // Vol level on RDA5708M is 16 level, display in 8
434 level
435 LCDDISPLAY.setCursor(4, 0);
436 for(Voldisplay=0;Voldisplay<Voldata;Voldisplay++)
437
438 {
439 LCDDISPLAY.print("=");
440 }
441 for(Voldisplay=Voldata;Voldisplay<8;Voldisplay++)
442
443 {
444 LCDDISPLAY.print(" ");
445 }
446 }
447 else
448 {
449 LCDDISPLAY.setCursor(4,
450 0);
451 for(Voldisplay=0;Voldisplay<8;Voldisplay++)
452 {
453 LCDDISPLAY.print("
454 ");
455 }
456 LCDDISPLAY.setCursor(5, 0);
457 LCDDISPLAY.print("Muted");
458
459 }
460
461 LCDDISPLAY.setCursor(0, 1);
462 if(ChannelData.ChannelName[0]!=0) LCDDISPLAY.print(ChannelData.ChannelName[0]);
463
464 else LCDDISPLAY.print(" ");
465 if(ChannelData.ChannelName[1]!=0) LCDDISPLAY.print(ChannelData.ChannelName[1]);
466
467 else LCDDISPLAY.print(" ");
468 if(ChannelData.ChannelName[2]!=0) LCDDISPLAY.print(ChannelData.ChannelName[2]);
469
470 else LCDDISPLAY.print(" ");
471 if(ChannelData.ChannelName[3]!=0) LCDDISPLAY.print(ChannelData.ChannelName[3]);
472
473 else LCDDISPLAY.print(" ");
474 if(ChannelData.ChannelName[4]!=0) LCDDISPLAY.print(ChannelData.ChannelName[4]);
475
476 else LCDDISPLAY.print(" ");
477 LCDDISPLAY.print(" ");
478 FreqDisplay=ChannelData.ChannelFreq/10000;
479
480 if(FreqDisplay!=0) LCDDISPLAY.print(FreqDisplay);
481 else LCDDISPLAY.print(" ");
482
483 FreqDisplay=(ChannelData.ChannelFreq%10000)/1000;
484 LCDDISPLAY.print(FreqDisplay);
485
486 FreqDisplay=(ChannelData.ChannelFreq%1000)/100;
487 LCDDISPLAY.print(FreqDisplay);
488
489 LCDDISPLAY.print(".");
490 FreqDisplay=(ChannelData.ChannelFreq%100)/10;
491 LCDDISPLAY.print(FreqDisplay);
492
493 LCDDISPLAY.noBlink();
494
495 FMInfoData = MyRadio.GetRSSI_FMInfo();
496 FMInfoData=FMInfoData
497 & 0x7F;
498 RSSIData = FMInfoData*100/127;
499 RSSILevel= (byte) RSSIData;
500
501 Displaysignal(RSSILevel);
502
503}
504
505
506void LCDDisplay(byte DisplayMode)
507{
508
509 switch(DisplayMode)
510 {
511 case NO_RADIO_FOUND:
512 {
513 LCDDISPLAY.clear();
514
515 LCDDISPLAY.setCursor(4, 0);
516 LCDDISPLAY.print("RADIO FM");
517 LCDDISPLAY.setCursor(14,
518 0);
519 LCDDISPLAY.write(DSignalchar);
520 LCDDISPLAY.setCursor(0, 1);
521
522 LCDDISPLAY.print("Cannot found RDA");
523 break;
524 }
525 case
526 NO_CHANNEL_FOUND:
527 {
528 LCDDISPLAY.clear();
529 LCDDISPLAY.setCursor(0,
530 0);
531 LCDDISPLAY.print("No Channel set");
532 LCDDISPLAY.setCursor(0,
533 1);
534 LCDDISPLAY.print("Pls Press Menu");
535 Displaysignal(SignalLevel);
536
537 break;
538 }
539 case FIRST_SETUP_SELECT:
540 {
541 LCDDISPLAY.clear();
542
543 LCDDISPLAY.setCursor(0, 0);
544 LCDDISPLAY.print("F1>AUTO SCAN");
545
546 LCDDISPLAY.setCursor(0, 1);
547 LCDDISPLAY.print("F2>LOAD VN CHAN");
548
549 Displaysignal(SignalLevel);
550 break;
551 }
552 case DONE_LOAD_VN_CHANNEL:
553
554 {
555 LCDDISPLAY.clear();
556 LCDDISPLAY.setCursor(0, 0);
557 LCDDISPLAY.print("DATA
558 LOADED");
559 LCDDISPLAY.setCursor(0, 1);
560 LCDDISPLAY.print("Pls
561 Press Exit");
562 Displaysignal(SignalLevel);
563 break;
564 }
565
566 case PLAYING:
567 {
568 LCDDISPLAY.clear();
569 LCDDISPLAY.setCursor(3,
570 0);
571 LCDDISPLAY.print("[");
572 LCDDISPLAY.setCursor(12, 0);
573
574 LCDDISPLAY.print("]");
575 LCDDISPLAY.setCursor(12, 1);
576 LCDDISPLAY.print("Mhz");
577
578 Displaysignal(SignalLevel);
579 break;
580 }
581 case MENU_PAGE1:
582
583 {
584 LCDDISPLAY.clear();
585 LCDDISPLAY.setCursor(0, 0);
586 LCDDISPLAY.print("F1>PLAY
587 by Freq");
588 LCDDISPLAY.setCursor(0, 1);
589 LCDDISPLAY.print("F2>Edit
590 Channel");
591 break;
592 }
593
594 case MENU_PAGE2:
595 {
596
597 LCDDISPLAY.clear();
598 LCDDISPLAY.setCursor(0, 0);
599 LCDDISPLAY.print("F1>Del
600 Channel");
601 LCDDISPLAY.setCursor(0, 1);
602 LCDDISPLAY.print("F2>EraseAll
603 Data");
604 break;
605 }
606
607 case MENU_PAGE3:
608 {
609 LCDDISPLAY.clear();
610
611 LCDDISPLAY.setCursor(0, 0);
612 LCDDISPLAY.print("F1>LCD BackLight");
613
614 LCDDISPLAY.setCursor(0, 1);
615 LCDDISPLAY.print("F2>ReLoad VNchannel");
616
617 break;
618 }
619
620 case ERASE_ALL:
621 {
622 LCDDISPLAY.clear();
623
624 LCDDISPLAY.setCursor(0, 0);
625 LCDDISPLAY.print("Erase All Data?");
626
627 LCDDISPLAY.setCursor(0, 1);
628 LCDDISPLAY.print("Enter to confirm");
629
630 break;
631 }
632 case DONE_ERASE_ALL:
633 {
634 LCDDISPLAY.clear();
635
636 LCDDISPLAY.setCursor(0, 0);
637 LCDDISPLAY.print("All Data clear");
638
639 LCDDISPLAY.setCursor(0, 1);
640 LCDDISPLAY.print("Exit to return");
641
642 break;
643 }
644 case DATA_ERASING:
645 {
646 LCDDISPLAY.clear();
647
648 LCDDISPLAY.setCursor(0, 0);
649 LCDDISPLAY.print("Data erasing");
650
651 LCDDISPLAY.setCursor(0, 1);
652 LCDDISPLAY.print("Please wait...");
653
654 break;
655 }
656 case DISPLAY_CHANNEL_INFO:
657 {
658 LCDDISPLAY.clear();
659
660 LCDDISPLAY.setCursor(0, 0);
661 LCDDISPLAY.print("STATION FOUND: _");
662
663 LCDDISPLAY.setCursor(0, 1);
664 LCDDISPLAY.print("___._Mhz RS: %");
665
666 break;
667 }
668
669 case PLAY_BY_FREQ:
670 {
671 LCDDISPLAY.clear();
672
673 LCDDISPLAY.setCursor(0, 0);
674 LCDDISPLAY.print("PlayFRQ:___._Mhz");
675
676 LCDDISPLAY.setCursor(0, 1);
677 LCDDISPLAY.print("Vol:__ RS: % *");
678
679 break;
680 }
681 case EDIT_CHANNEL:
682 {
683 LCDDISPLAY.clear();
684
685 LCDDISPLAY.setCursor(0, 0);
686 LCDDISPLAY.print("Channel __ edit");
687
688 LCDDISPLAY.setCursor(0, 1);
689 LCDDISPLAY.print(" ___._ Mhz");
690
691 break;
692 }
693 case REMOVE_CHANNEL:
694 {
695 LCDDISPLAY.clear();
696
697 LCDDISPLAY.setCursor(0, 0);
698 LCDDISPLAY.print("Del Channel __ ?");
699
700 LCDDISPLAY.setCursor(0, 1);
701 LCDDISPLAY.print("_____ ___._ Mhz");
702
703 break;
704 }
705 case REMOVE_CHANNEL_DONE:
706 {
707 LCDDISPLAY.clear();
708
709 LCDDISPLAY.setCursor(0, 0);
710 LCDDISPLAY.print("Del Channel Done");
711
712 LCDDISPLAY.setCursor(0, 1);
713 LCDDISPLAY.print("Pls Press Exit");
714
715 break;
716 }
717 case LOAD_DEFAULT_DATA:
718 {
719 LCDDISPLAY.clear();
720
721 LCDDISPLAY.setCursor(0, 0);
722 LCDDISPLAY.print("LoadDefalt Data?");
723
724 LCDDISPLAY.setCursor(0, 1);
725 LCDDISPLAY.print("Old Data erase?");
726
727 break;
728 }
729 case SET_BACKLIGHT:
730 {
731 LCDDISPLAY.clear();
732
733 LCDDISPLAY.setCursor(0, 0);
734 LCDDISPLAY.print("LCD Backlight __");
735
736 LCDDISPLAY.setCursor(0, 1);
737 LCDDISPLAY.print("0 sec = Alway ON");
738
739 break;
740 }
741 }
742}
743
744
745void InceaseCharacter()
746{
747 if(SaveChannelName[CurrentCharacterIndex]==0)
748 CurrentCharacter='@';
749 else CurrentCharacter=SaveChannelName[CurrentCharacterIndex];
750
751 CurrentCharacter++;
752 if(CurrentCharacter=='[') CurrentCharacter=' ';
753 else
754 if(CurrentCharacter=='!') CurrentCharacter='0';
755 else if(CurrentCharacter==':')
756 CurrentCharacter='A';
757 LCDDISPLAY.setCursor(CurrentCharacterIndex, 1);
758 LCDDISPLAY.write(CurrentCharacter);
759
760 LCDDISPLAY.setCursor(CurrentCharacterIndex, 1);
761 SaveChannelName[CurrentCharacterIndex]=CurrentCharacter;
762}
763
764void
765 DecreaseCharacter()
766{
767 if(SaveChannelName[CurrentCharacterIndex]==0) CurrentCharacter='B';
768
769 else CurrentCharacter=SaveChannelName[CurrentCharacterIndex];
770 CurrentCharacter--;
771
772 if(CurrentCharacter=='/') CurrentCharacter=' ';
773 else if(CurrentCharacter==31)
774 CurrentCharacter='Z';
775 else if(CurrentCharacter=='@') CurrentCharacter='9';
776
777 LCDDISPLAY.setCursor(CurrentCharacterIndex, 1);
778 LCDDISPLAY.write(CurrentCharacter);
779
780 LCDDISPLAY.setCursor(CurrentCharacterIndex, 1);
781 SaveChannelName[CurrentCharacterIndex]=CurrentCharacter;
782}
783
784void
785 DisplaySaveChannel()
786{
787 byte SaveChannelIndex;
788 SaveChannelIndex=NumofChannel+1;
789
790
791 LCDDISPLAY.setCursor(0, 0);
792 LCDDISPLAY.print(" ");
793 LCDDISPLAY.setCursor(0,
794 0);
795 LCDDISPLAY.print(SaveChannelIndex/10);
796 LCDDISPLAY.print(SaveChannelIndex%10);
797
798 LCDDISPLAY.setCursor(CurrentCharacterIndex, 1);
799 LCDDISPLAY.blink();
800 InceaseCharacter();
801}
802
803
804void
805 PlayFM(RadioChannelInfo RadioData,byte VolumeData)
806{
807
808 CurrentState=PLAYING;
809
810 LCDDISPLAY.clear();
811 CurrentVolume=VolumeData;
812 LCDDisplay(CurrentState);
813
814 //Play Freq command here
815 MyRadio.SetFrequency(RadioData.ChannelFreq,CurrentVolume-1);
816
817 DisplayPlayInfo(RadioData,VolumeData);
818}
819
820void PlaybyFreq(unsigned FreqPlay)
821 // ussing for play by Freq
822{
823 byte FreqDisplay;
824 byte FMInfoData; //yzzzzzzz
825 bit y=1: is station found, zzzzzzz: RSSI data
826 unsigned int RSSIData;
827
828 byte RSSILevel;
829 MyRadio.SetFrequency(FreqPlay,CurrentVolume-1);
830 delay(100);
831
832 FMInfoData = MyRadio.GetRSSI_FMInfo();
833
834 LCDDISPLAY.setCursor(4, 1);
835
836 LCDDISPLAY.print(CurrentVolume/10);
837 LCDDISPLAY.print(CurrentVolume%10);
838
839
840 LCDDISPLAY.setCursor(15, 1);
841 if(bitRead(FMInfoData,7)==0) LCDDISPLAY.print("
842 ");
843 else LCDDISPLAY.print("*");
844
845 FMInfoData=FMInfoData & 0x7F;
846
847 RSSIData = FMInfoData*100/127;
848 RSSILevel= (byte) RSSIData;
849 if(RSSILevel>99)
850 LCDDISPLAY.setCursor(10, 1);
851 else LCDDISPLAY.setCursor(11, 1);
852 LCDDISPLAY.print(RSSILevel);
853
854
855 LCDDISPLAY.setCursor(8, 0);
856 FreqDisplay=FreqPlay/10000;
857 if(FreqDisplay!=0)
858 LCDDISPLAY.print(FreqDisplay);
859 else LCDDISPLAY.print(" ");
860 FreqDisplay=(FreqPlay%10000)/1000;
861
862 LCDDISPLAY.print(FreqDisplay);
863 FreqDisplay=(FreqPlay%1000)/100;
864 LCDDISPLAY.print(FreqDisplay);
865
866 LCDDISPLAY.print(".");
867 FreqDisplay=(FreqPlay%100)/10;
868 LCDDISPLAY.print(FreqDisplay);
869
870
871 if(FreqMode10x==true)
872 {
873 LCDDISPLAY.setCursor(10, 0);
874
875 LCDDISPLAY.blink();
876 }
877 else
878 {
879 LCDDISPLAY.setCursor(12,
880 0);
881 LCDDISPLAY.blink();
882 }
883}
884
885void DisplaySaveFrequency()
886{
887
888 byte FreqDisplay;
889 LCDDISPLAY.clear();
890 LCDDISPLAY.setCursor(3,
891 0);
892 LCDDISPLAY.print("Save Channel ");
893 LCDDISPLAY.setCursor(12,
894 1);
895 LCDDISPLAY.print(" Mhz");
896 LCDDISPLAY.setCursor(7, 1);
897
898 FreqDisplay=CurrentFreq/10000;
899 if(FreqDisplay!=0) LCDDISPLAY.print(FreqDisplay);
900
901 else LCDDISPLAY.print(" ");
902 FreqDisplay=(CurrentFreq%10000)/1000;
903
904 LCDDISPLAY.print(FreqDisplay);
905 FreqDisplay=(CurrentFreq%1000)/100;
906
907 LCDDISPLAY.print(FreqDisplay);
908 LCDDISPLAY.print(".");
909 FreqDisplay=(CurrentFreq%100)/10;
910
911 LCDDISPLAY.print(FreqDisplay);
912
913}
914
915void IncreaseFreqPlay()
916 // ussing for play by Freq
917{
918 if(FreqMode10x==true) CurrentFreq=CurrentFreq+100;
919
920 else CurrentFreq=CurrentFreq+10;
921 if(CurrentFreq>MyRadio.MaxFreq) CurrentFreq=MyRadio.MaxFreq;
922
923 PlaybyFreq(CurrentFreq);
924}
925
926
927void DecreaseFreqPlay() // ussing for
928 play by Freq
929{
930 if(FreqMode10x==true) CurrentFreq=CurrentFreq-100;
931 else
932 CurrentFreq=CurrentFreq-10;
933 if(CurrentFreq<MyRadio.MinFreq) CurrentFreq=MyRadio.MinFreq;
934
935 PlaybyFreq(CurrentFreq);
936}
937
938void ChangeFreqTurn()
939{
940 if(FreqMode10x==true)
941
942 {
943 FreqMode10x=false;
944 LCDDISPLAY.setCursor(12, 0);
945 }
946 else
947
948 {
949 FreqMode10x=true;
950 LCDDISPLAY.setCursor(10, 0);
951 }
952}
953
954
955void
956 StopPlayFM()
957{
958 // Stop play FM here
959 MyRadio.ResetChip();
960}
961
962void
963 DisplayFMInfo()
964{
965 byte FMInfoData; //yzzzzzzz bit y=1: is station found,
966 zzzzzzz: RSSI data
967 unsigned int RSSIData;
968 byte RSSILevel;
969 byte FreqDisplay;
970
971 unsigned int FreqData;
972 FMInfoData = MyRadio.GetRSSI_FMInfo();
973 FreqData =
974 MyRadio.GetFrequency();
975
976 LCDDISPLAY.setCursor(15, 0);
977 if(bitRead(FMInfoData,7)==0)
978 LCDDISPLAY.print("N");
979 else LCDDISPLAY.print("Y");
980
981 FMInfoData=FMInfoData
982 & 0x7F;
983 RSSIData = FMInfoData*100/127;
984 RSSILevel= (byte) RSSIData;
985 if(RSSILevel>99)
986 LCDDISPLAY.setCursor(12, 1);
987 else LCDDISPLAY.setCursor(13, 1);
988 LCDDISPLAY.print(RSSILevel);
989
990
991
992 LCDDISPLAY.setCursor(0, 1);
993 FreqDisplay=FreqData/10000;
994 if(FreqDisplay!=0)
995 LCDDISPLAY.print(FreqDisplay);
996 else LCDDISPLAY.print(" ");
997 FreqDisplay=(FreqData%10000)/1000;
998
999 LCDDISPLAY.print(FreqDisplay);
1000 FreqDisplay=(FreqData%1000)/100;
1001 LCDDISPLAY.print(FreqDisplay);
1002
1003 LCDDISPLAY.print(".");
1004 FreqDisplay=(FreqData%100)/10;
1005 LCDDISPLAY.print(FreqDisplay);
1006
1007 LCDDISPLAY.noBlink();
1008
1009}
1010
1011void PlayNextChannel()
1012{
1013 if(NumofChannel>0)
1014
1015 {
1016 CurrentChannelIndex++;
1017 if(CurrentChannelIndex>NumofChannel) CurrentChannelIndex
1018 =1;
1019 CurrentChannelInfo=GetChannelROM(CurrentChannelIndex);
1020 PlayFM(CurrentChannelInfo,CurrentVolume);
1021
1022 SaveRadioParametertoROM();
1023 }
1024}
1025
1026void PlayPrevChannel()
1027{
1028
1029 if(NumofChannel>0)
1030 {
1031 CurrentChannelIndex--;
1032 if(CurrentChannelIndex<1)
1033 CurrentChannelIndex = NumofChannel;
1034 CurrentChannelInfo=GetChannelROM(CurrentChannelIndex);
1035
1036 PlayFM(CurrentChannelInfo,CurrentVolume);
1037 SaveRadioParametertoROM();
1038
1039 }
1040}
1041
1042void IncVol()
1043{
1044 CurrentVolume++;
1045 if(CurrentVolume>16)
1046 CurrentVolume=16;
1047 MuteVolume=CurrentVolume; // unmute if muted
1048 SaveRadioParametertoROM();
1049
1050 // Increase volume here
1051 MyRadio.SetVolume(CurrentVolume-1);
1052 if(CurrentState==PLAY_BY_FREQ)
1053 // when play by Freq
1054 {
1055 LCDDISPLAY.setCursor(4, 1);
1056 LCDDISPLAY.print(CurrentVolume/10);
1057
1058 LCDDISPLAY.print(CurrentVolume%10);
1059 if(FreqMode10x==true) LCDDISPLAY.setCursor(10,
1060 0);
1061 else LCDDISPLAY.setCursor(12, 0);
1062 }
1063 else
1064 {
1065 DisplayPlayInfo(CurrentChannelInfo,CurrentVolume);
1066 // when play by SEEK, CHANNEL
1067 }
1068
1069
1070}
1071void DecVol()
1072{
1073 CurrentVolume--;
1074
1075 if(CurrentVolume<1) CurrentVolume=1;
1076 MuteVolume=CurrentVolume;//unmute if
1077 muted
1078 SaveRadioParametertoROM();
1079 // Decrease volume here
1080 MyRadio.SetVolume(CurrentVolume-1);
1081
1082
1083 if(CurrentState==PLAY_BY_FREQ) // when play by Freq
1084 {
1085 LCDDISPLAY.setCursor(4,
1086 1);
1087 LCDDISPLAY.print(CurrentVolume/10);
1088 LCDDISPLAY.print(CurrentVolume%10);
1089
1090 if(FreqMode10x==true) LCDDISPLAY.setCursor(10, 0);
1091 else LCDDISPLAY.setCursor(12,
1092 0);
1093 }
1094
1095 else // when play by SEEK, CHANNEL
1096 {
1097 DisplayPlayInfo(CurrentChannelInfo,CurrentVolume);
1098
1099 }
1100}
1101
1102void Mute_Unmute()
1103{
1104
1105 if(CurrentState==PLAY_BY_FREQ) //
1106 when play by Freq
1107 {
1108 if(MuteVolume==0)
1109 {
1110 MuteVolume=CurrentVolume;
1111
1112 MyRadio.SetMute(false);
1113 LCDDISPLAY.setCursor(4, 1);
1114 LCDDISPLAY.print(CurrentVolume/10);
1115
1116 LCDDISPLAY.print(CurrentVolume%10);
1117 if(FreqMode10x==true) LCDDISPLAY.setCursor(10,
1118 0);
1119 else LCDDISPLAY.setCursor(12, 0);
1120
1121 }
1122 else
1123
1124 {
1125 MuteVolume=0;
1126 MyRadio.SetMute(true);
1127 LCDDISPLAY.setCursor(4,
1128 1);
1129 LCDDISPLAY.print("--");
1130 if(FreqMode10x==true) LCDDISPLAY.setCursor(10,
1131 0);
1132 else LCDDISPLAY.setCursor(12, 0);
1133 }
1134
1135 }
1136
1137 else // when play by SEEK, CHANNEL
1138 {
1139 if(MuteVolume==0)
1140 {
1141 MuteVolume=CurrentVolume;
1142
1143 DisplayPlayInfo(CurrentChannelInfo,CurrentVolume);
1144 //Set mute
1145 here
1146 MyRadio.SetMute(false);
1147 }
1148 else
1149 {
1150
1151 MuteVolume=0;
1152 DisplayPlayInfo(CurrentChannelInfo,CurrentVolume);
1153
1154 //Set unmute here
1155 MyRadio.SetMute(true);
1156 }
1157 }
1158
1159
1160
1161}
1162
1163void SeekChannel()
1164{
1165 unsigned int GetFreq;
1166 CurrentChannelInfo.ChannelIndex=0xFF;
1167
1168 CurrentChannelInfo.ChannelName[0]='_';
1169 CurrentChannelInfo.ChannelName[1]='_';
1170
1171 CurrentChannelInfo.ChannelName[2]='_';
1172 CurrentChannelInfo.ChannelName[3]='_';
1173
1174 CurrentChannelInfo.ChannelName[4]='_';
1175 //Seek up channel here
1176 MyRadio.SeekUp();
1177
1178 GetFreq=MyRadio.GetFrequency();
1179 CurrentChannelInfo.ChannelFreq=GetFreq;
1180
1181 CurrentFreq=CurrentChannelInfo.ChannelFreq;
1182 DisplayPlayInfo(CurrentChannelInfo,CurrentVolume);
1183
1184 LCDDISPLAY.noBlink();
1185}
1186
1187
1188void SaveChannel()
1189{
1190 CurrentChannelInfo.ChannelIndex=NumofChannel;
1191
1192 NumofChannel++;
1193 CurrentChannelIndex=NumofChannel;
1194 CurrentChannelInfo.ChannelIndex=NumofChannel;
1195
1196 CurrentChannelInfo.ChannelName[0]=SaveChannelName[0];
1197 CurrentChannelInfo.ChannelName[1]=SaveChannelName[1];
1198
1199 CurrentChannelInfo.ChannelName[2]=SaveChannelName[2];
1200 CurrentChannelInfo.ChannelName[3]=SaveChannelName[3];
1201
1202 CurrentChannelInfo.ChannelName[4]=SaveChannelName[4];
1203 CurrentChannelInfo.ChannelFreq=CurrentFreq;
1204
1205 SaveChanneltoROM(CurrentChannelInfo);
1206 SaveRadioParametertoROM();
1207}
1208
1209void
1210 UpdateChannel()
1211{
1212 CurrentChannelInfo.ChannelIndex=CurrentChannelIndex;
1213
1214 CurrentChannelInfo.ChannelName[0]=SaveChannelName[0];
1215 CurrentChannelInfo.ChannelName[1]=SaveChannelName[1];
1216
1217 CurrentChannelInfo.ChannelName[2]=SaveChannelName[2];
1218 CurrentChannelInfo.ChannelName[3]=SaveChannelName[3];
1219
1220 CurrentChannelInfo.ChannelName[4]=SaveChannelName[4];
1221 CurrentChannelInfo.ChannelFreq=CurrentFreq;
1222
1223 SaveChanneltoROM(CurrentChannelInfo);
1224 SaveRadioParametertoROM();
1225
1226}
1227
1228void
1229 EditChannel()
1230{
1231 byte FreqDisplay;
1232 RadioChannelInfo ChannelInfo;
1233
1234
1235 ChannelInfo = GetChannelROM(CurrentChannelIndex);
1236 SaveChannelName[0]=ChannelInfo.ChannelName[0];
1237
1238 SaveChannelName[1]=ChannelInfo.ChannelName[1];
1239 SaveChannelName[2]=ChannelInfo.ChannelName[2];
1240
1241 SaveChannelName[3]=ChannelInfo.ChannelName[3];
1242 SaveChannelName[4]=ChannelInfo.ChannelName[4];
1243
1244
1245
1246 LCDDISPLAY.setCursor(8, 0);
1247 LCDDISPLAY.print(CurrentChannelIndex/10);
1248
1249 LCDDISPLAY.print(CurrentChannelIndex%10);
1250 LCDDISPLAY.setCursor(0, 1);
1251 LCDDISPLAY.print(SaveChannelName);
1252
1253
1254 LCDDISPLAY.setCursor(7, 1);
1255 CurrentFreq=ChannelInfo.ChannelFreq;
1256 FreqDisplay=CurrentFreq/10000;
1257
1258 if(FreqDisplay!=0) LCDDISPLAY.print(FreqDisplay);
1259 else LCDDISPLAY.print(" ");
1260
1261 FreqDisplay=(CurrentFreq%10000)/1000;
1262 LCDDISPLAY.print(FreqDisplay);
1263 FreqDisplay=(CurrentFreq%1000)/100;
1264
1265 LCDDISPLAY.print(FreqDisplay);
1266 LCDDISPLAY.print(".");
1267 FreqDisplay=(CurrentFreq%100)/10;
1268
1269 LCDDISPLAY.print(FreqDisplay);
1270
1271 LCDDISPLAY.setCursor(0, 1);
1272 LCDDISPLAY.blink();
1273
1274 CurrentCharacterIndex=0;
1275 CurrentCharacter=SaveChannelName[CurrentCharacterIndex];
1276}
1277
1278void
1279 DisplayRemoveChannel()
1280{
1281 byte FreqDisplay;
1282 CurrentChannelInfo=GetChannelROM(CurrentChannelIndex);
1283
1284 LCDDISPLAY.setCursor(12, 0);
1285 LCDDISPLAY.print(CurrentChannelIndex/10);
1286
1287 LCDDISPLAY.print(CurrentChannelIndex%10);
1288 LCDDISPLAY.setCursor(0,
1289 1);
1290 if(CurrentChannelInfo.ChannelName[0]!=0) LCDDISPLAY.print(CurrentChannelInfo.ChannelName[0]);
1291
1292 else LCDDISPLAY.print(" ");
1293 if(CurrentChannelInfo.ChannelName[1]!=0)
1294 LCDDISPLAY.print(CurrentChannelInfo.ChannelName[1]);
1295 else LCDDISPLAY.print("
1296 ");
1297 if(CurrentChannelInfo.ChannelName[2]!=0) LCDDISPLAY.print(CurrentChannelInfo.ChannelName[2]);
1298
1299 else LCDDISPLAY.print(" ");
1300 if(CurrentChannelInfo.ChannelName[3]!=0)
1301 LCDDISPLAY.print(CurrentChannelInfo.ChannelName[3]);
1302 else LCDDISPLAY.print("
1303 ");
1304 if(CurrentChannelInfo.ChannelName[4]!=0) LCDDISPLAY.print(CurrentChannelInfo.ChannelName[4]);
1305
1306 else LCDDISPLAY.print(" ");
1307 LCDDISPLAY.print(" ");
1308
1309
1310 LCDDISPLAY.setCursor(7, 1);
1311 CurrentFreq=CurrentChannelInfo.ChannelFreq;
1312
1313 FreqDisplay=CurrentFreq/10000;
1314 if(FreqDisplay!=0) LCDDISPLAY.print(FreqDisplay);
1315
1316 else LCDDISPLAY.print(" ");
1317 FreqDisplay=(CurrentFreq%10000)/1000;
1318
1319 LCDDISPLAY.print(FreqDisplay);
1320 FreqDisplay=(CurrentFreq%1000)/100;
1321
1322 LCDDISPLAY.print(FreqDisplay);
1323 LCDDISPLAY.print(".");
1324 FreqDisplay=(CurrentFreq%100)/10;
1325
1326 LCDDISPLAY.print(FreqDisplay);
1327
1328 LCDDISPLAY.setCursor(13, 0);
1329
1330 LCDDISPLAY.blink();
1331}
1332
1333void DisplaySetBackLight()
1334{
1335
1336
1337 LCDDISPLAY.setCursor(14, 0);
1338 LCDDISPLAY.print(CurrentBacklightLife/10);
1339
1340 LCDDISPLAY.print(CurrentBacklightLife%10);
1341 LCDDISPLAY.setCursor(15,
1342 0);
1343 LCDDISPLAY.blink();
1344}
1345
1346
1347
1348byte CheckButton(bool ActiveLevel)
1349{
1350
1351 unsigned long CurrentTimecount;
1352 unsigned long PreviousTimecount;
1353 const unsigned
1354 long Buttonholdtime=500;
1355 byte Checkresult;
1356 bool TimeOver;
1357 Checkresult
1358 = NO_BUTTON_PRESS;
1359
1360 if(digitalRead(BMenu)==ActiveLevel) // Button was press.
1361
1362 {
1363 ActiveBackLight();
1364 delay(200); // debounce button
1365 PreviousTimecount=millis();
1366
1367 TimeOver=false;
1368 while(digitalRead(BMenu)==ActiveLevel && TimeOver==false)//
1369 Wait until button release
1370 {
1371 CurrentTimecount=millis();
1372 if(CurrentTimecount-PreviousTimecount>Buttonholdtime)
1373 TimeOver=true;
1374 }
1375 if(TimeOver==true)
1376 {
1377 Checkresult
1378 = MENU_LONG_PRESS;
1379 ButtonHolding=true;
1380 }
1381 else if(ButtonHolding==false)
1382 Checkresult = MENU_SHORT_PRESS; // First press after release
1383
1384 }
1385 else
1386 if(digitalRead(BUp)==ActiveLevel) // Button was press.
1387 {
1388 ActiveBackLight();
1389
1390 delay(200); // debounce button
1391 PreviousTimecount=millis();
1392 TimeOver=false;
1393
1394 while(digitalRead(BUp)==ActiveLevel && TimeOver==false)// Wait until button
1395 release
1396 {
1397 CurrentTimecount=millis();
1398 if(CurrentTimecount-PreviousTimecount>Buttonholdtime)
1399 TimeOver=true;
1400 }
1401 if(TimeOver==true)
1402 {
1403 Checkresult
1404 = UP_LONG_PRESS;
1405 ButtonHolding=true;
1406 }
1407 else if(ButtonHolding==false)
1408 Checkresult = UP_SHORT_PRESS; // First press after release
1409 }
1410 else if(digitalRead(BDown)==ActiveLevel)
1411 // Button was press.
1412 {
1413 ActiveBackLight();
1414 delay(200); // debounce
1415 button
1416 PreviousTimecount=millis();
1417 TimeOver=false;
1418 while(digitalRead(BDown)==ActiveLevel
1419 && TimeOver==false)// Wait until button release
1420 {
1421 CurrentTimecount=millis();
1422
1423 if(CurrentTimecount-PreviousTimecount>Buttonholdtime) TimeOver=true;
1424
1425 }
1426 if(TimeOver==true)
1427 {
1428 Checkresult = DOWN_LONG_PRESS;
1429
1430 ButtonHolding=true;
1431 }
1432 else if(ButtonHolding==false) Checkresult
1433 = DOWN_SHORT_PRESS; // First press after release
1434 }
1435 else if(digitalRead(BEnter)==ActiveLevel)
1436 // Button was press.
1437 {
1438 ActiveBackLight();
1439 delay(200); // debounce
1440 button
1441 PreviousTimecount=millis();
1442 TimeOver=false;
1443 while(digitalRead(BEnter)==ActiveLevel
1444 && TimeOver==false)// Wait until button release
1445 {
1446 CurrentTimecount=millis();
1447
1448 if(CurrentTimecount-PreviousTimecount>Buttonholdtime) TimeOver=true;
1449
1450 }
1451 if(TimeOver==true)
1452 {
1453 Checkresult = ENTER_LONG_PRESS;
1454
1455 ButtonHolding=true;
1456 }
1457 else if(ButtonHolding==false) Checkresult
1458 = ENTER_SHORT_PRESS; // First press after release
1459 }
1460 else ButtonHolding=false;
1461 // No button pressed. release holding variable
1462 return Checkresult;
1463}
1464
1465
1466
1467void
1468 ProcessButton(byte ButtonData,byte CurrentStateData)
1469{
1470
1471 switch(ButtonData)
1472
1473 {
1474 case MENU_SHORT_PRESS:
1475 {
1476 switch(CurrentStateData)
1477
1478 {
1479 case NO_CHANNEL_FOUND:
1480 {
1481 CurrentState=FIRST_SETUP_SELECT;
1482
1483 LCDDisplay(CurrentState);
1484 break;
1485 }
1486 case
1487 DONE_LOAD_VN_CHANNEL: case REMOVE_CHANNEL_DONE:
1488 {
1489 CurrentChannelInfo=GetChannelROM(CurrentChannelIndex);
1490
1491 PlayFM(CurrentChannelInfo,CurrentVolume);
1492 break;
1493 }
1494
1495
1496 case SEEKING:
1497 {
1498 CurrentState=SAVE_CHANNEL_SEEK;
1499
1500 CurrentCharacterIndex=0;
1501 SaveChannelName[0]=0;
1502 SaveChannelName[1]=0;
1503
1504 SaveChannelName[2]=0;
1505 SaveChannelName[3]=0;
1506 SaveChannelName[4]=0;
1507
1508 DisplaySaveChannel();
1509 break;
1510 }
1511 case PLAY_BY_FREQ:
1512
1513 {
1514 DisplaySaveFrequency();
1515 CurrentState=SAVE_CHANNEL_FREQ;
1516
1517 CurrentCharacterIndex=0;
1518 SaveChannelName[0]=0;
1519 SaveChannelName[1]=0;
1520
1521 SaveChannelName[2]=0;
1522 SaveChannelName[3]=0;
1523 SaveChannelName[4]=0;
1524
1525 DisplaySaveChannel();
1526 break;
1527 }
1528 case
1529 SAVE_CHANNEL_SEEK: case SAVE_CHANNEL_FREQ:
1530 {
1531 SaveChannel();
1532
1533 CurrentState=PLAYING;
1534 CurrentChannelIndex--;
1535 PlayNextChannel();
1536
1537 break;
1538 }
1539 case EDIT_CHANNEL:
1540 {
1541 UpdateChannel();
1542
1543 CurrentState=PLAYING;
1544 CurrentChannelIndex--;
1545 PlayNextChannel();
1546
1547 break;
1548 }
1549 case PLAYING:
1550 {
1551 StopPlayFM();
1552
1553 CurrentState=MENU_PAGE1;
1554 LCDDisplay(CurrentState);
1555 break;
1556
1557 }
1558 case MENU_PAGE1:
1559 {
1560 CurrentState=MENU_PAGE2;
1561
1562 LCDDisplay(CurrentState);
1563 break;
1564 }
1565
1566 case
1567 MENU_PAGE2:
1568 {
1569 CurrentState=MENU_PAGE3;
1570 LCDDisplay(CurrentState);
1571
1572 break;
1573 }
1574
1575 case MENU_PAGE3:
1576 {
1577 CurrentState=PLAYING;
1578
1579 CurrentChannelIndex--;
1580 PlayNextChannel();
1581 break;
1582
1583 }
1584 case DONE_ERASE_ALL:
1585 {
1586 CurrentState=NO_CHANNEL_FOUND;
1587
1588 LCDDisplay(CurrentState);
1589 break;
1590 }
1591 }
1592
1593 break;
1594 }
1595
1596 case MENU_LONG_PRESS:
1597 {
1598 switch(CurrentStateData)
1599
1600 {
1601 case SAVE_CHANNEL_SEEK:
1602 {
1603 DisplayPlayInfo(CurrentChannelInfo,CurrentVolume);
1604
1605 LCDDISPLAY.noBlink();
1606 CurrentState=SEEKING;
1607 break;
1608
1609 }
1610 case SAVE_CHANNEL_FREQ:
1611 {
1612 CurrentState=PLAY_BY_FREQ;
1613
1614 LCDDisplay(CurrentState);
1615 PlaybyFreq(CurrentFreq);
1616 break;
1617
1618 }
1619 case EDIT_CHANNEL:
1620 {
1621 CurrentState=PLAYING;
1622
1623 CurrentChannelIndex--;
1624 PlayNextChannel();
1625 break;
1626
1627 }
1628 case MENU_PAGE1: case MENU_PAGE2: case MENU_PAGE3: case LOAD_DEFAULT_DATA:
1629 case SET_BACKLIGHT:
1630 {
1631 PlayFM(CurrentChannelInfo,CurrentVolume);
1632
1633 CurrentState=PLAYING;
1634 break;
1635 }
1636 case
1637 PLAYING: case SEEKING:
1638 {
1639 LastState=CurrentState;
1640 CurrentState=DISPLAY_CHANNEL_INFO;
1641
1642 LCDDisplay(CurrentState);
1643 DisplayFMInfo();
1644 break;
1645
1646 }
1647 case DISPLAY_CHANNEL_INFO:
1648 {
1649 CurrentState=LastState;
1650
1651 LCDDisplay(PLAYING);
1652 DisplayPlayInfo(CurrentChannelInfo,CurrentVolume);
1653
1654 break;
1655 }
1656 case PLAY_BY_FREQ:
1657 {
1658 CurrentChannelIndex--;
1659
1660 PlayNextChannel();
1661 break;
1662 }
1663 }
1664 break;
1665
1666 }
1667
1668 case UP_SHORT_PRESS:
1669 {
1670 switch(CurrentStateData)
1671
1672 {
1673 case FIRST_SETUP_SELECT:
1674 {
1675 CurrentState=PLAYING;
1676
1677 CurrentVolume=8;
1678 NumofChannel=0;
1679 CurrentChannelIndex=0;
1680
1681 SaveRadioParametertoROM();
1682 LCDDisplay(CurrentState);
1683
1684 CurrentState=SEEKING;
1685 SeekChannel();
1686 break;
1687
1688 }
1689 case PLAYING: case SEEKING:
1690 {
1691 PlayNextChannel();
1692
1693 break;
1694 }
1695
1696 case SAVE_CHANNEL_SEEK: case EDIT_CHANNEL:
1697 case SAVE_CHANNEL_FREQ:
1698 {
1699 InceaseCharacter();
1700 break;
1701
1702 }
1703 case MENU_PAGE1:
1704 {
1705 CurrentState = PLAY_BY_FREQ;
1706
1707 FreqMode10x=false;
1708 LCDDisplay(CurrentState);
1709 CurrentFreq=MyRadio.MinFreq;//
1710 Lowest FM Freq
1711 PlaybyFreq(CurrentFreq);
1712
1713 break;
1714
1715 }
1716
1717 case MENU_PAGE2:
1718 {
1719 CurrentState
1720 = REMOVE_CHANNEL;
1721 LCDDisplay(CurrentState);
1722 DisplayRemoveChannel();
1723
1724
1725 break;
1726 }
1727 case MENU_PAGE3:
1728 {
1729
1730 CurrentState = SET_BACKLIGHT;
1731 LCDDisplay(CurrentState);
1732
1733 DisplaySetBackLight();
1734 break;
1735 }
1736
1737 case
1738 PLAY_BY_FREQ:
1739 {
1740 IncreaseFreqPlay();
1741 break;
1742
1743 }
1744
1745 case REMOVE_CHANNEL:
1746 {
1747 CurrentChannelIndex++;
1748
1749 if(CurrentChannelIndex>NumofChannel) CurrentChannelIndex=1;
1750 DisplayRemoveChannel();
1751
1752 break;
1753 }
1754 case SET_BACKLIGHT:
1755 {
1756 CurrentBacklightLife++;
1757
1758 if(CurrentBacklightLife>15) CurrentBacklightLife=15;
1759 DisplaySetBackLight();
1760
1761 break;
1762 }
1763 }
1764 break;
1765 }
1766
1767
1768 case UP_LONG_PRESS:
1769 {
1770 switch(CurrentStateData)
1771 {
1772
1773 case PLAYING: case SEEKING: case PLAY_BY_FREQ:
1774 {
1775 IncVol();
1776
1777 break;
1778 }
1779 }
1780 break;
1781 }
1782
1783 case
1784 DOWN_SHORT_PRESS:
1785 {
1786 switch(CurrentStateData)
1787 {
1788 case
1789 FIRST_SETUP_SELECT:
1790 {
1791 LoadDefaultChannel();
1792 CurrentState=DONE_LOAD_VN_CHANNEL;
1793
1794 LCDDisplay(CurrentState);
1795 break;
1796 }
1797 case
1798 PLAYING: case SEEKING:
1799 {
1800 PlayPrevChannel();
1801 break;
1802
1803 }
1804 case SAVE_CHANNEL_SEEK: case EDIT_CHANNEL: case SAVE_CHANNEL_FREQ:
1805
1806 {
1807 DecreaseCharacter();
1808 break;
1809 }
1810
1811 case MENU_PAGE1:
1812 {
1813 CurrentState=EDIT_CHANNEL;
1814
1815 LCDDisplay(CurrentState);
1816 CurrentCharacterIndex=0;
1817 EditChannel();
1818
1819 break;
1820 }
1821 case MENU_PAGE2:
1822 {
1823 CurrentState=ERASE_ALL;
1824
1825 LCDDisplay(CurrentState);
1826 break;
1827 }
1828
1829 case
1830 MENU_PAGE3:
1831 {
1832 CurrentState=LOAD_DEFAULT_DATA;
1833 LCDDisplay(CurrentState);
1834
1835 break;
1836 }
1837
1838 case PLAY_BY_FREQ:
1839 {
1840
1841 DecreaseFreqPlay();
1842 break;
1843 }
1844
1845 case
1846 REMOVE_CHANNEL:
1847 {
1848 CurrentChannelIndex--;
1849 if(CurrentChannelIndex==0)
1850 CurrentChannelIndex=NumofChannel;
1851 DisplayRemoveChannel();
1852 break;
1853
1854 }
1855
1856 case SET_BACKLIGHT:
1857 {
1858 CurrentBacklightLife--;
1859
1860 if(CurrentBacklightLife==255) CurrentBacklightLife=0;
1861 DisplaySetBackLight();
1862
1863 break;
1864 }
1865 }
1866 break;
1867 }
1868
1869 case
1870 DOWN_LONG_PRESS:
1871 {
1872 switch(CurrentStateData)
1873 {
1874 case
1875 PLAYING: case SEEKING: case PLAY_BY_FREQ:
1876 {
1877 DecVol();
1878
1879 break;
1880 }
1881 }
1882 break;
1883 }
1884
1885 case
1886 ENTER_SHORT_PRESS:
1887 {
1888 switch(CurrentStateData)
1889 {
1890 case
1891 PLAYING: case SEEKING: case PLAY_BY_FREQ:
1892 {
1893 Mute_Unmute();
1894
1895 break;
1896 }
1897 case SAVE_CHANNEL_SEEK:
1898 {
1899
1900 CurrentCharacterIndex++;
1901 if(CurrentCharacterIndex==5) CurrentCharacterIndex=0;
1902
1903 DisplaySaveChannel();
1904 break;
1905 }
1906 case
1907 EDIT_CHANNEL: case SAVE_CHANNEL_FREQ:
1908 {
1909 CurrentCharacterIndex++;
1910
1911 if(CurrentCharacterIndex==5) CurrentCharacterIndex=0;
1912 LCDDISPLAY.setCursor(CurrentCharacterIndex,
1913 1);
1914 break;
1915 }
1916 case ERASE_ALL:
1917 {
1918
1919 CurrentState=DATA_ERASING;
1920 LCDDisplay(CurrentState);
1921
1922 EraseAllChannelInROM();
1923 CurrentState=DONE_ERASE_ALL;
1924
1925 LCDDisplay(CurrentState);
1926 break;
1927 }
1928 case
1929 REMOVE_CHANNEL:
1930 {
1931 RemoveChannelfromROM(CurrentChannelIndex);
1932
1933 CurrentState=REMOVE_CHANNEL_DONE;
1934 LCDDisplay(CurrentState);
1935
1936 CurrentChannelIndex--;
1937 break;
1938 }
1939 case
1940 LOAD_DEFAULT_DATA:
1941 {
1942 LoadDefaultChannel();
1943 CurrentState=DONE_LOAD_VN_CHANNEL;
1944
1945 LCDDisplay(CurrentState);
1946 break;
1947 }
1948 case
1949 SET_BACKLIGHT:
1950 {
1951 WriteCurrentBackLightLife(CurrentBacklightLife);
1952
1953 PlayFM(CurrentChannelInfo,CurrentVolume);
1954 CurrentState=PLAYING;
1955
1956 break;
1957 }
1958 }
1959 break;
1960 }
1961
1962 case
1963 ENTER_LONG_PRESS:
1964 {
1965 switch(CurrentStateData)
1966 {
1967 case
1968 PLAYING: case SAVE_CHANNEL_SEEK: case SEEKING:
1969 {
1970 CurrentState=SEEKING;
1971
1972 SeekChannel();
1973 break;
1974 }
1975 case PLAY_BY_FREQ:
1976
1977 {
1978 ChangeFreqTurn();
1979 break;
1980 }
1981 }
1982
1983 break;
1984 }
1985 }
1986}
1987void ActiveBackLight()
1988{
1989 ONLCDLED;
1990
1991 BackLighOnpoint=millis();
1992}
1993
1994void CheckBackLightLife()
1995{
1996 unsigned
1997 int CurrentTimePoint;
1998 if(CurrentBacklightLife>0)
1999 {
2000 CurrentTimePoint=millis();
2001
2002 if(CurrentTimePoint-BackLighOnpoint>(CurrentBacklightLife*1000))
2003 {
2004
2005 OFFLCDLED;
2006 }
2007 }
2008}
2009
2010
2011void setup() {
2012 pinMode(BMenu,INPUT_PULLUP);
2013
2014 pinMode(BEnter,INPUT_PULLUP);
2015 pinMode(BUp,INPUT_PULLUP);
2016 pinMode(BDown,INPUT_PULLUP);
2017
2018 pinMode(LCDBackLight,OUTPUT);
2019 ONLCDLED;
2020 BackLighOnpoint=millis();
2021
2022
2023 LCDDISPLAY.createChar(0, SignalChar);
2024 LCDDISPLAY.createChar(1, Signal100);
2025
2026 LCDDISPLAY.createChar(2, Signal80);
2027 LCDDISPLAY.createChar(3, Signal60);
2028
2029 LCDDISPLAY.createChar(4, Signal40);
2030 LCDDISPLAY.createChar(5, Signal20);
2031
2032 LCDDISPLAY.createChar(6, Signal0);
2033 LCDDISPLAY.createChar(7, Playsign);
2034
2035 LCDDISPLAY.begin(16,2);
2036 Serial.begin(9600);
2037 DisplayWelCome();
2038 ButtonHolding=false;
2039
2040 MuteVolume=1;
2041 RadioFound = MyRadio.Radioinit(); // Return to true if found
2042 RDA5807M chips. else, return false.
2043 if(RadioFound==false)
2044 {
2045 CurrentState=NO_RADIO_FOUND;
2046
2047 LCDDisplay(CurrentState);
2048 }
2049 else
2050 {
2051 //EEPROM.write(0x0000,0xFF);
2052
2053 NumofChannel=EEPROM.read(0x0000);
2054 if(NumofChannel>200 or NumofChannel==0)
2055 // Max storage is 200 channel. if greater than 200 mean no data
2056 {
2057 ChannelDefined=false;
2058 // not yet found channel save in ROM.
2059 CurrentState=NO_CHANNEL_FOUND;
2060
2061 LCDDisplay(CurrentState);
2062 }
2063 else
2064 {
2065 ChannelDefined=true;
2066 //Found channel as found number of channel at 0x0000 ROM
2067 GetLastPlayingToCurrent();
2068
2069 CurrentChannelInfo=GetChannelROM(CurrentChannelIndex);
2070 PlayFM(CurrentChannelInfo,CurrentVolume);
2071
2072 }
2073 }
2074
2075 CurrentBacklightLife=ReadCurrentBackLightLife();
2076 if(CurrentBacklightLife>15)
2077
2078 {CurrentBacklightLife=5;
2079 WriteCurrentBackLightLife(CurrentBacklightLife);
2080
2081 }
2082}
2083
2084void loop()
2085{
2086 byte CheckButtonResult;
2087 CheckButtonResult=CheckButton(ACTIVE_HIGH);
2088
2089 ProcessButton(CheckButtonResult,CurrentState);
2090 CheckBackLightLife();
2091
2092 }
2093
2094
RADIO_RDA5807M_VN.zip
Library for RDA5807M
1inary file (no preview
Downloadable files
Schematic
Schematic
Note: Content and images are from: https://projecthub.arduino.cc/, with some modifications.
If you want it removed due to copyright reasons, please leave a comment. Thank you.
I want to share this article more widely so that everyone knows about Arduino and your project.