//----------------------------------------------------------------- // VKV vysilac 87.5 - 108 MHz FM // ovladany pomoci Arduina s LCD 16x2 Shieldem //----------------------------------------------------------------- #define lcdSvit 10 #define RESETPIN A1 #define MEMORDSS 0 //RDS nazev stanice #define MEMORDST 10 // RDS text #define MEMOFH 40 //ulozeni vysilciho kmitoctu #define MEMOFL 41 //ulozeni vysilciho kmitoctu #define MEMOP 42 //vykon (88-115) #define charsCount 64 //#define _BV(n) (1 << n) #define btnSelect 1 //tlacitka #define btnLeft 2 #define btnRight 3 #define btnUp 4 #define btnDown 5 #include #include #include LiquidCrystal lcd(8, 9, 4, 5, 6, 7); // inicializace LCD displeje Adafruit_Si4713 vkv = Adafruit_Si4713(RESETPIN); char chars[charsCount + 1] = {"ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-abcdefghijklmnopqrstuvwxyz"}; char charInfo[17]; // 1234567890123456789012345678901234567890123456789012345678901234 char charBuffer[33]; // 1 2 3 4 5 6 byte charIndex = 0; byte charPos = 0; byte vkvP = 88; int vkvF = 8750; bool dispOn = false; bool dispF = true; bool vkvOK; unsigned long timeOut = 0; //-------------------------------------------------------------------------------------------- void displayOn() { dispOn = true; digitalWrite(lcdSvit, HIGH); } void displayOff() { dispOn = false; digitalWrite(lcdSvit, LOW); } //-- eeprom ----------------------------------------------------------------------------------- uint16_t vkvRead() { byte h = EEPROM.read(MEMOFH); byte l = EEPROM.read(MEMOFL); uint16_t r = (256 * h) + l; if (r < 8750) return 8750; if (r > 10800) return 10800; return r; } void vkvWrite(uint16_t vkvF) { EEPROM.update(MEMOFH, highByte(vkvF)); EEPROM.update(MEMOFL, lowByte(vkvF)); } byte vykonRead() { byte result = EEPROM.read(MEMOP); if (result < 88) result = 88; if (result > 115) result = 115; return result; } void vykonWrite(byte vykon) { EEPROM.update(MEMOP, vykon); } void txtWrite(int addr, byte cnt) { for (byte i = 0; i < cnt; i++) if (charExists(charBuffer[i])) EEPROM.update(addr + i, charBuffer[i]); } void txtRead(int addr, byte cnt){ for (byte i = 0; i < cnt; i++) charBuffer[i] = 0; for (byte i = 0; i < cnt; i++) { char c = EEPROM.read(addr + i); if (charExists(c)) charBuffer[i] = c; else charBuffer[i] = '_'; } } void txtRDS() { for (byte i = 0; i < 32; i++) charBuffer[i] = ' '; charBuffer[32] = 0; for (byte i = 0; i < 16; i++) { char c = EEPROM.read(MEMORDST + i); if (c == '_') charBuffer[i] = ' '; else { if (charExists(c)) charBuffer[i] = c; else charBuffer[i] = ' '; } } } //-- edit ------------------------------------------------------------------------------------ bool charExists(char c) { if (c < 32) return false; for (byte i = 0; i < charsCount; i++) { if (chars[i] == c) return true; } return false; } void charOf(char c) { for (byte i = 0; i < charsCount; i++) { if (chars[i] == c) charIndex = i; } } void waitUp () { while (analogRead(0) < 750); } byte readKey() { byte k = 255; int n = analogRead(0); if (n < 50) k = btnRight; //Vpravo(RIGHT) if ((n > 95) && (n < 150)) k = btnUp; //Nahoru(UP) if ((n > 250) && (n < 350)) k = btnDown; //Dolu(DOWN) if ((n > 400) && (n < 500)) k = btnLeft; //Vlevo(LEFT) if ((n > 600) && (n < 750)) k = btnSelect; //Vyber(SELECT) if (k < 255) waitUp(); return k; } void setChar() { charBuffer[charPos] = chars[charIndex]; lcd.setCursor(charPos, 1); lcd.print(charBuffer[charPos]); lcd.setCursor(charPos, 1); } byte lineEdit(byte maxLen, byte charCount) { byte n; int t = 0; charPos = 0; charIndex = 0; charOf(charBuffer[charPos]); lcd.cursor(); setChar(); waitUp(); do { n = readKey(); switch (n) { case btnUp : if (charIndex > 0) charIndex--; else charIndex = charCount - 1; setChar(); t = 0; break; case btnDown : if (charIndex < charCount - 1) charIndex++; else charIndex = 0; setChar(); t = 0; break; case btnLeft : if (charPos > 0) charPos--; charOf(charBuffer[charPos]); setChar(); t = 0; break; case btnRight: if (charPos < (maxLen - 1)) charPos++; charOf(charBuffer[charPos]); setChar(); t = 0; break; } delay(1); t++; } while ((t < 8000) && (n != btnSelect)); lcd.noCursor(); return n; } //-- nastaveni ------------------------------------------------------------------------------ void info() { lcd.clear(); lcd.setCursor(0, 0); lcd.print(charInfo); lcd.setCursor(0, 1); if (dispF) { int f = vkvRead(); lcd.print(f / 100); lcd.print("."); lcd.print(f % 100); lcd.print("MHz"); //lcd.print((1<<2) | (1<<1)); lcd.setCursor(9, 1); lcd.print(vykonRead()); lcd.print("dBuV"); } else { lcd.print("C[a]="); lcd.print(vkv.currAntCap); lcd.print("pF"); } } // nastaveni RDS void showBuffer(byte len) { lcd.setCursor(0, 1); lcd.print(" "); lcd.setCursor(0, 1); for (byte i = 0; i < len; i++) { if (charExists(charBuffer[i])) lcd.print(charBuffer[i]); } } void menuRDSS() { lcd.clear(); lcd.print("RDS nazev"); txtRead(MEMORDSS, 8); showBuffer(8); if (lineEdit(8, 37) == btnSelect) { txtWrite(MEMORDSS, 8); } } void menuRDST() { lcd.clear(); lcd.print("RDS text"); txtRead(MEMORDST, 16); showBuffer(16); if (lineEdit(16, 64) == btnSelect) { txtWrite(MEMORDST, 16); } } // nastaveni kmitoctu void showF(int f) { String s = String(f); lcd.clear(); lcd.print("Nastaveni F"); lcd.setCursor(0, 1); s.concat("0 kHz "); lcd.print(s); } void menuF() { int f = vkvRead(); if (f == 0) f = 8750; showF(f); int t = 0; byte k; waitUp(); do { delay(1); k = readKey(); switch (k) { case btnLeft : if (f >= 8760) f -= 10; showF(f); t = 0; break; case btnRight: if (f <= 10790) f += 10; showF(f); t = 0; break; case btnUp : if (f <= 10700) f += 100; else f = 10800; showF(f); t = 0; break; case btnDown : if (f >= 8850) f -= 100; else f = 8750; showF(f); t = 0; break; } if (k == btnSelect) { vkvWrite(f); return; } t++; } while (t < 8000); } // nastaveni vykonu void showP(byte p) { String s = String(p); lcd.clear(); lcd.print("Nastaveni P"); lcd.setCursor(0, 1); s.concat(" dBuV "); lcd.print(s); } void menuP() { byte p = vykonRead(); showP(p); int t = 0; byte k; waitUp(); do { delay(1); k = readKey(); switch (k) { case btnLeft : if (p > 88) p--; showP(p); t = 0; break; case btnRight: if (p < 115) p++; showP(p); t = 0; break; case btnUp: if (p <= 105) p += 10; else p = 115; showP(p); t = 0; break; case btnDown : if (p >= 98) p -= 10; else p = 88; showP(p); t = 0; break; } if (k == btnSelect) { vykonWrite(p); return; } t++; } while (t < 8000); } // main menu void showMM(byte m) { lcd.clear(); lcd.setCursor(0, 0); switch (m) { case 1: lcd.print("Kmitocet"); break; case 2: lcd.print("RDS nazev"); break; case 3: lcd.print("RDS text"); break; case 4: lcd.print("Vykon"); break; } } byte mainMenu() { byte menuMode = 1; showMM(menuMode); int t = 0; waitUp(); do { delay(1); byte k = readKey(); switch (k) { case btnUp : if (menuMode > 1) menuMode--; t = 0; showMM(menuMode); break; case btnDown : if (menuMode < 4) menuMode++; t = 0; showMM(menuMode); break; case btnLeft : ; case btnRight : return 0; case btnSelect: return menuMode; } t++; } while (t < 8000); return 0; } //-- vysilac -------------------------------------------------------------------------------- bool startVKV() { lcd.clear(); strcpy(charInfo, "VKV mini vysilac"); lcd.print(charInfo); lcd.setCursor(0, 1); lcd.print("Start ..."); delay(2048); vkvP = vykonRead(); vkvF = vkvRead(); if (!vkv.begin()) { // begin with address 0x63 (CS high default) strcpy(charInfo, "Si4713 nenalezen"); return false; } delay(1024); vkv.setTXpower(vkvP); // dBuV, 88-115 max vkv.tuneFM(vkvF); // 102.3 mhz vkv.beginRDS(); txtRead(MEMORDSS, 8); vkv.setRDSstation(charBuffer); txtRDS(); vkv.setRDSbuffer(charBuffer); delay(1024) ; vkv.readTuneStatus(); return true; } //=========================================================================================== void setup() { lcd.begin(16, 2); pinMode(lcdSvit, OUTPUT); displayOn(); vkvOK = startVKV(); info(); } void loop() { int k = readKey(); if (!dispOn && (k < 255)) { displayOn(); timeOut = 0; k = 255; waitUp(); return; } if (dispOn && (k < 255)) { switch (k) { case btnSelect: { byte m = mainMenu(); switch (m) { case 1: menuF(); break; case 2: menuRDSS(); break; case 3: menuRDST(); break; case 4: menuP(); break; } info(); break; } case btnDown: timeOut = 450000; break; case btnUp: dispF = !dispF; info(); break; } } if (!dispOn) return; timeOut++; if (timeOut > 450000) displayOff(); delay(8); }