- Alat dan Bahan :
- LED matrix P10 3 Block
- Tumer FM TEA5767
- Board Arduino Uno
- Konverter socket DMD P10
- Gambar
#include
#include
#include
#include
#include
#include
#include
#include
// Init radio object
TEA5767N radio = TEA5767N();
// Buttons codes
#define btnRIGHT 0
#define btnUP 1
#define btnDOWN 2
#define btnLEFT 3
#define btnSELECT 4
#define btnNONE 5
// Delay between clock transitions
#define DELAY_VOLUME_TRANSITION 90
// Definition of the 3-dimension array
#define MENU_DEPTH 3
#define MENU_LINES 8
#define MENU_TEXT 16
// Arduino pin for backlight intensity control
#define BACKLIGHT_PIN 3
// Arduino pins connected to digital potentiometers
// for volume control
#define UPDOWN_PIN 11
#define INC_PIN 12
// Predefined stations array
float defaultStations[16] = {88.0, 88.8,94.7,91.1, 98.4, 98.8, 101.5, 101.7, 102.2, 104.5, 106.0, 107.7, 101.4, 102.2, 103.4, 88.8};
// Initialized station arrays
float stations[16] = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0};
byte stationIndex = 0;
byte applicationState = 0;
byte selectedMenuItem = 0;
float selectedStation;
boolean buttonWasReleased = true;
int lcd_key = 0;
// Menu labels
char menu[MENU_DEPTH][MENU_LINES][MENU_TEXT] = {
{{" Diam"}, {" Pencarian"}, {" Cari Halus"}, {" Simpan Station"}, {" Configuration"}, {" Stand by"}, {" Load deflt stn"}, {" Exit"}},
{{" Search level"}, {" Backlit inten."}, {" Exit"}},
{{" Low"}, {" Medium"}, {" High"}, {"Exit"}}
};
// Level required to search
byte searchLevel;
// Intensity of LCD backlight.
// Varies from 0 to 255
int backlightIntensity;
// Copy the predefined stations into the
// array used by the application
void loadDefaultStations() {
for (int i=0 ; i < 16 ; i++) {
stations[i] = defaultStations[i];
}
}
// Convert the analog values read from Arduino pin A0
// into one of the five commands plus the NONE button
int read_LCD_buttons() {
int adc_key_in = analogRead(0);
if (adc_key_in > 1000) return btnNONE;
if (adc_key_in < 50) return btnRIGHT;
if (adc_key_in < 195) return btnUP;
if (adc_key_in < 380) return btnDOWN;
if (adc_key_in < 555) return btnLEFT;
if (adc_key_in < 790) return btnSELECT;
return btnNONE;
}
byte findSelectedStationIndex(float station) {
for (int i = 0 ; i < 16 ; i++) {
if (stations[i] == station) {
return i;
}
}
return 0;
}
// Load the station stored in the EEPROM static memory
void loadStation() {
byte intStation, floatStation;
float station;
intStation = EEPROM.read(0);
floatStation = EEPROM.read(1);
if (intStation != 0xFF) {
station = (intStation * 1.0) + (floatStation * .1);
radio.selectFrequency(station);
printSelectedFrequency(radio.readFrequencyInMHz());
stationIndex = findSelectedStationIndex(station);
} else {
radio.selectFrequency(stations[stationIndex]);
}
}
// Load the search level stored in the EEPROM static memory
void loadSearchLevel() {
searchLevel = EEPROM.read(2);
if (searchLevel == 0xFF) {
searchLevel = MID_STOP_LEVEL;
}
switch(searchLevel) {
case LOW_STOP_LEVEL: {
radio.setSearchLowStopLevel();
break;
}
case MID_STOP_LEVEL: {
radio.setSearchMidStopLevel();
break;
}
case HIGH_STOP_LEVEL: {
radio.setSearchHighStopLevel();
break;
}
}
}
// Load the backlight intensity stored in the EEPROM static memory
void loadBacklightIntensity() {
backlightIntensity = EEPROM.read(3);
analogWrite(BACKLIGHT_PIN, (byte) backlightIntensity);
}
void setupVolume() {
// Lowest volume
digitalWrite(UPDOWN_PIN, LOW);
for (int i = 0 ; i < 100 ; i++) {
digitalWrite(INC_PIN, LOW);
delay(1);
digitalWrite(INC_PIN, HIGH);
delay(1);
}
// Pleasant level
digitalWrite(UPDOWN_PIN, HIGH);
for (int i = 0 ; i < 15 ; i++) {
digitalWrite(INC_PIN, LOW);
delay(1);
digitalWrite(INC_PIN, HIGH);
delay(1);
}
}
void loadConfiguration() {
radio.mute();
loadDefaultStations();
loadStation();
loadSearchLevel();
loadBacklightIntensity();
setupVolume();
radio.turnTheSoundBackOn();
}
void saveStation(float station) {
float aux;
byte byteValue;
byteValue = (byte) floor(station);
EEPROM.write(0, byteValue);
aux = station - floor(station);
aux *= 10.0;
if (aux > 5.0) {
byteValue = byte(aux);
if ((((float)byteValue) - aux) > 0.1) {
byteValue--;
} else if ((aux - ((float)byteValue)) > 0.1) {
byteValue++;
}
} else {
byteValue = (int) ceil(aux);
}
EEPROM.write(1, byteValue);
}
void saveSearchLevel(byte searchLevel) {
EEPROM.write(2, searchLevel);
}
DMD dmd(3, 1);
void ScanDMD()
{
dmd.scanDisplayBySPI();
}
//================================================
void setup(){
Wire.begin();
Timer1.initialize( 500 );
Timer1.attachInterrupt( ScanDMD );
pinMode(BACKLIGHT_PIN, OUTPUT);
pinMode(UPDOWN_PIN, OUTPUT);
pinMode(INC_PIN, OUTPUT);
digitalWrite(UPDOWN_PIN, HIGH);
digitalWrite(INC_PIN, HIGH);
analogWrite(BACKLIGHT_PIN, 255);
dmd.selectFont(SystemFont5x7);
dmd.drawString(1,0,"TEA5767 FM Radio",16,0);
dmd.drawString(1,9,"By Suparno, M.Pd",16,0);
delay(3000);
dmd.clearScreen(true);
dmd.drawString(36,0,"MHz",3,0);
// Loads configuration
loadConfiguration();
radio.setSoftMuteOn();
radio.setHighCutControlOn();
}
void printSelectedFrequency(float frequency) {
printSelectedFrequency(frequency, 0, 0);
}
void printSelectedFrequency(float frequency, byte col, byte row) {
char str_freq[5];
dtostrf(frequency, 1, 1, str_freq);
dmd.drawString(0,0,str_freq,5,0);
}
void printMuteStatus() {
if (radio.isMuted()) {
dmd.drawString(84,9,"Mu",2,0);
} else {
dmd.drawString(84,9,"Re",2,0);
}
}
void printStereoStatus() {
//dmd.clearScreen(true);
if (radio.isStereo()) {
dmd.drawString(60,0,"Stereo",6,0);
} else {
dmd.drawString(60,0,"Mono ",6,0);
}
}
void markSelectedMenuItem(char *firstLine, char *secondLine) {
dmd.drawString(90,1,firstLine,16,0);
dmd.drawString(90,9,secondLine,16,0);
}
void updateLevelIndicator() {
byte x, y, sl;
char barGraph[17];
sl = radio.getSignalLevel();
for (x=0 ; x
barGraph[x] = 255;
}
for (y=x ; y<16 div="" y="">16>
barGraph[y] = 16;//32;
barGraph[y] = '>';
}
dmd.drawString(0,9,barGraph,16,0);
}
void loop() {
lcd_key = read_LCD_buttons();
if ((lcd_key != btnNONE) && radio.isStandBy() && buttonWasReleased) {
buttonWasReleased = false;
applicationState = 0;
radio.mute();
radio.setStandByOff();
delay(150);
radio.turnTheSoundBackOn();
analogWrite(BACKLIGHT_PIN, (byte) backlightIntensity);
dmd.clearScreen(true);
dmd.drawString(0,0," MHz",16,0);
printSelectedFrequency(radio.readFrequencyInMHz());
}
switch (lcd_key) {
case btnRIGHT: {
if (buttonWasReleased) {
buttonWasReleased = false;
switch (applicationState) {
case 0: {
if ((stationIndex < 15) && (stations[stationIndex+1] != 0.0)) {
stationIndex++;
} else {
stationIndex = 0;
}
radio.mute();
radio.selectFrequency(stations[stationIndex]);
radio.turnTheSoundBackOn();
printSelectedFrequency(radio.readFrequencyInMHz());
saveStation(stations[stationIndex]);
break;
}
// Search ahead
case 5: {
byte isBandLimitReached = false;
if (selectedMenuItem == 1) {
radio.setSearchUp();
isBandLimitReached = radio.searchNextMuting();
if (isBandLimitReached) {
radio.setSearchDown();
isBandLimitReached = radio.searchNextMuting();
}
printSelectedFrequency(radio.readFrequencyInMHz(), 2, 0);
}
break;
}
case 6: {
if (selectedStation < 108.0) {
selectedStation += .1;
radio.selectFrequency(selectedStation);
printSelectedFrequency(selectedStation, 2, 0);
saveStation(selectedStation);
}
break;
}
case 7: {
backlightIntensity += 10;
if (backlightIntensity > 255) {
backlightIntensity = 255;
}
analogWrite(BACKLIGHT_PIN, (byte) backlightIntensity);
EEPROM.write(3, (byte) backlightIntensity);
break;
}
}
}
break;
}
case btnLEFT: {
if (buttonWasReleased) {
buttonWasReleased = false;
switch (applicationState) {
// First screen, so change station
case 0: {
if (stationIndex > 0) {
stationIndex--;
} else {
stationIndex = 15;
while((stations[stationIndex] == 0.0) && (stationIndex > 0)) {
stationIndex--;
}
}
radio.mute();
radio.selectFrequency(stations[stationIndex]);
radio.turnTheSoundBackOn();
printSelectedFrequency(radio.readFrequencyInMHz());
saveStation(stations[stationIndex]);
break;
}
// Search backwards
case 5: {
byte isBandLimitReached;
if (selectedMenuItem == 1) {
radio.setSearchDown();
isBandLimitReached = radio.searchNextMuting();
if (isBandLimitReached) {
radio.setSearchUp();
isBandLimitReached = radio.searchNextMuting();
}
printSelectedFrequency(radio.readFrequencyInMHz(), 2, 0);
}
break;
}
// Decrement fine search station
case 6: {
if (selectedStation > 88.0) {
selectedStation -= .1;
radio.selectFrequency(selectedStation);
printSelectedFrequency(selectedStation, 2, 0);
saveStation(selectedStation);
}
break;
}
// Decrement backlight intensity
case 7: {
backlightIntensity -= 10;
if (backlightIntensity < 0) {
backlightIntensity = 0;
}
analogWrite(BACKLIGHT_PIN, (byte) backlightIntensity);
EEPROM.write(3, (byte) backlightIntensity);
break;
}
}
}
break;
}
case btnUP: {
if (buttonWasReleased || (applicationState == 0)) {
buttonWasReleased = false;
switch (applicationState) {
//Volume UP
case 0: {
digitalWrite(UPDOWN_PIN, HIGH);
digitalWrite(INC_PIN, LOW);
delay(DELAY_VOLUME_TRANSITION);
digitalWrite(INC_PIN, HIGH);
delay(DELAY_VOLUME_TRANSITION);
break;
}
// Menu navigation up
case 1: {
if (selectedMenuItem > 0) {
selectedMenuItem--;
if (selectedMenuItem != 3) {
dmd.clearScreen(true);
dmd.drawString(0,0,menu[0][selectedMenuItem],16,0);
dmd.drawString(0,9,menu[0][selectedMenuItem+1],16,0);
}
}
markSelectedMenuItem("<", " ");
break;
}
case 3: {
if (selectedMenuItem > 0) {
selectedMenuItem--;
if (selectedMenuItem != 3) {
dmd.clearScreen(true);
dmd.drawString(0,0,menu[1][selectedMenuItem],16,0);
dmd.drawString(0,9,menu[1][selectedMenuItem+1],16,0);
}
}
markSelectedMenuItem("<", " ");
break;
}
// Search level navigation up
case 4: {
if (selectedMenuItem > 0) {
selectedMenuItem--;
if (selectedMenuItem != 2) {
dmd.clearScreen(true);
dmd.drawString(0,0,menu[2][selectedMenuItem],16,0);
dmd.drawString(0,9,menu[2][selectedMenuItem+1],16,0);
}
}
markSelectedMenuItem("<", " ");
break;
}
}
}
break;
}
case btnDOWN: {
if (buttonWasReleased || (applicationState == 0)) {
buttonWasReleased = false;
switch (applicationState) {
//Volume DOWN
case 0: {
digitalWrite(UPDOWN_PIN, LOW);
digitalWrite(INC_PIN, LOW);
delay(DELAY_VOLUME_TRANSITION);
digitalWrite(INC_PIN, HIGH);
delay(DELAY_VOLUME_TRANSITION);
break;
}
// Menu navigation down
case 1: {
if (selectedMenuItem < (MENU_LINES-1)) {
selectedMenuItem++;
if (selectedMenuItem != 1) {
dmd.clearScreen(true);
dmd.drawString(0,0,menu[0][selectedMenuItem-1],16,0);
dmd.drawString(0,9,menu[0][selectedMenuItem],16,0);
}
}
markSelectedMenuItem(" ", "<");
break;
}
case 3:
if (selectedMenuItem < 2) {
selectedMenuItem++;
if (selectedMenuItem != 1) {
dmd.clearScreen(true);
dmd.drawString(0,0,menu[1][selectedMenuItem-1],16,0);
dmd.drawString(0,9,menu[1][selectedMenuItem],16,0);
}
}
markSelectedMenuItem(" ", "<");
break;
// Search level navigation down
case 4: {
if (selectedMenuItem < 2) {
selectedMenuItem++;
if (selectedMenuItem != 1) {
dmd.clearScreen(true);
dmd.drawString(0,0,menu[2][selectedMenuItem-1],16,0);
dmd.drawString(0,9,menu[2][selectedMenuItem],16,0);
}
}
markSelectedMenuItem(" ", "<");
break;
}
}
}
break;
}
// Typically starts the menu or execute a command
case btnSELECT: {
if (buttonWasReleased) {
buttonWasReleased = false;
switch (applicationState) {
case 0: {
applicationState = 1;
// lcd.clear();
dmd.clearScreen(true);
dmd.drawString(0,0,menu[0][0],16,0);
dmd.drawString(0,9,menu[0][1],16,0);
markSelectedMenuItem("<", " ");
selectedMenuItem = 0;
break;
}
case 1: {
switch(selectedMenuItem) {
//Mute function
case 0: {
applicationState = 0;
if (!radio.isMuted()) {
radio.mute();
} else {
radio.turnTheSoundBackOn();
}
dmd.drawString(0,0, " MHz",16,0);
dmd.drawString(0,9, " ",16,0);
printMuteStatus();
// Starts station
printSelectedFrequency(radio.readFrequencyInMHz());
break;
}
//Search
case 1: {
applicationState = 5;
dmd.clearScreen(true);
dmd.drawString(0,0, "<",1,0);
dmd.drawString(90,0, ">",1,0);
printSelectedFrequency(radio.readFrequencyInMHz(), 2, 0);
break;
}
//Fine search
case 2: {
applicationState = 6;
dmd.clearScreen(true);
dmd.drawString(0,0, "<<",2,0);
dmd.drawString(84,0, ">>",2,0);
selectedStation = radio.readFrequencyInMHz();
printSelectedFrequency(selectedStation, 2, 0);
break;
}
case 3: {
byte isBandLimitReached = 0;
byte progress = 0;
applicationState = 0;
dmd.clearScreen(true);
dmd.drawString(0,0, "Searching ...",16,0);
radio.mute();
radio.selectFrequency(88.0);
radio.setSearchUp();
while(!isBandLimitReached && (progress < 16)) {
isBandLimitReached = radio.searchNext();
stations[progress] = radio.readFrequencyInMHz();
dmd.drawString(0,9, progress,16,0);
dmd.drawString(0,9,(char)255,16,0);
progress++;
}
radio.turnTheSoundBackOn();
dmd.drawString(0,0," MHz ",16,0);
dmd.drawString(0,9," ",16,0);
// Starts station
stationIndex = 0;
saveStation(stations[stationIndex]);
printSelectedFrequency(stations[stationIndex]);
break;
}
//Configuration
case 4: {
applicationState = 3;
dmd.clearScreen(true);
dmd.drawString(0,0,menu[1][0],16,0);
dmd.drawString(0,9,menu[1][1],16,0);
markSelectedMenuItem("<", " ");
selectedMenuItem = 0;
break;
}
case 5: {
applicationState = 2;
//lcd.clear();
dmd.clearScreen(true);
radio.setStandByOn();
analogWrite(BACKLIGHT_PIN, 0);
break;
}
//Load default station
case 6: {
applicationState = 0;
dmd.drawString(0,0," MHz ",16,0);
dmd.drawString(0,9," ",16,0);
// Starts station
loadDefaultStations();
radio.mute();
radio.selectFrequency(stations[0]);
radio.turnTheSoundBackOn();
printSelectedFrequency(radio.readFrequencyInMHz());
saveStation(stations[stationIndex]);
break;
}
//Exit
case 7: {
applicationState = 0;
dmd.drawString(0,0," MHz ",16,0);
dmd.drawString(0,9," ",16,0);
// Starts station
printMuteStatus();
// Starts station
printSelectedFrequency(radio.readFrequencyInMHz());
break;
}
}
break;
}
case 3: {
switch(selectedMenuItem) {
case 0: {
applicationState = 4;
//lcd.clear();
dmd.clearScreen(true);
if (searchLevel < 3) {
dmd.drawString(0,0,menu[2][0],16,0);
dmd.drawString(0,9,menu[2][1],16,0);
} else {
dmd.drawString(0,0,menu[2][1],16,0);
dmd.drawString(0,9,menu[2][2],16,0);
}
if (searchLevel == 1) {
markSelectedMenuItem("<", " ");
} else {
markSelectedMenuItem(" ", "<");
}
selectedMenuItem = searchLevel - 1;
break;
}
// Backlight intensity selected
case 1: {
applicationState = 7;
dmd.clearScreen(true);
dmd.drawString(0,0,"Backlight int.",16,0);
break;
}
// Exit
case 2: {
applicationState = 0;
dmd.drawString(0,0," MHz ",16,0);
dmd.drawString(0,9," ",16,0);
printMuteStatus();
// Starts station
printSelectedFrequency(radio.readFrequencyInMHz());
break;
}
}
break;
}
// One of the levels selected
case 4: {
applicationState = 0;
switch(selectedMenuItem+1) {
case LOW_STOP_LEVEL: {
radio.setSearchLowStopLevel();
saveSearchLevel(LOW_STOP_LEVEL);
break;
}
case MID_STOP_LEVEL: {
radio.setSearchMidStopLevel();
saveSearchLevel(MID_STOP_LEVEL);
break;
}
case HIGH_STOP_LEVEL: {
radio.setSearchHighStopLevel();
saveSearchLevel(HIGH_STOP_LEVEL);
break;
}
}
dmd.drawString(0,0," MHz ",16,0);
dmd.drawString(0,9," ",16,0);
printMuteStatus();
// Starts station
printSelectedFrequency(radio.readFrequencyInMHz());
break;
}
// Exit
// Several states to exit from
case 5: // Exit from Search
case 6: // Exit from Fine search
case 7: { // Exit from Backlight intensity
applicationState = 0;
dmd.clearScreen(true);
dmd.drawString(0,0," MHz ",16,0);
printMuteStatus();
// Starts station
printSelectedFrequency(radio.readFrequencyInMHz());
break;
}
}
}
break;
}
// The buttons were scanned and none were pressed
case btnNONE: {
if (!buttonWasReleased) {
buttonWasReleased = true;
}
switch (applicationState) {
case 0: {
if (!radio.isStandBy()) {
printStereoStatus();
}
updateLevelIndicator();
break;
}
case 5: {
updateLevelIndicator();
break;
}
}
break;
}
}
delay(10);
}