#include "menu.h" #include "CPU_init.h" #include "tftv2.h" #include "lcd.h" #include "math.h" #include "stm32f4xx.h" extern TFT Tft; // Index auf ZF-Filter (provisorisch) extern int Filter; // Empfangsfrequenz in internen Einheiten extern int NCO_Frequenz; // liefert Index der gedrückten Taste vom übergebenen Tasten-Array oder 'NoOfButtons', // wenn keine Taste gedrückt ist oder Touch ausserhalb der Tasten // NoOfButtons ist Anzahl Tasten, also Anzahl Array-Elemente int Menu_getKey(Button_t *Button, int NoOfButtons) { int i; static int OldKey = 0x7fffffff; Point_t Pos; // Tastenabfrage Pos = LCD_getTouch(); if (Pos.x != 32767) { // Taste gedrückt i = OldKey; OldKey = 0; while (OldKey < NoOfButtons) { // Taste suchen if (Button[OldKey].touch(Pos)) { Button[OldKey].hilite(RED); break; } OldKey = OldKey + 1; } if ((i < NoOfButtons) && (i != OldKey)) Button[i].unhilite(); // 'fliegender' Übergang von einer gedrückten Taste zur nächsten } else // keine Taste gedrückt if (OldKey < NoOfButtons) { // Taste wurde losgelassen Button[OldKey].unhilite(); OldKey = NoOfButtons; } return OldKey; } // Zahleneingabe // MaxLen die max. Anzahl Ziffern, BackGroundColor die Hintergrundfarbe und 'Value' der Wert. // Return-Wert ist 'true', wenn ok, und 'false', wenn Eingabe abgebrochen wurde. // Dargestellt werden die Tasten in der linken Displayhälfte. int Menu_getNumValue(int MaxLen, INT16U BackGroundColor, int *Value) { int i, ctr, down; const int16_t X0 = 40; Point_t Pos = {X0, X0+10}; // Mitte der ersten Taste const Point_t Dim = {40, 40}; // Tastengrösse const int Abstand = 50; // Abstand der Tastenmitten const Point_t Location = {Pos.x, Pos.y - (Abstand>>1) - 15}; Button_t Button[12]; char s[3]; uint32_t Time; *Value = 0; // Rückgabewert initialisieren // Hintergrund löschen Tft.fillRectangle(Pos.x-(Dim.x>>1)-5, Location.y-6, Abstand * 2 + Dim.x + 10, Abstand * 3 + Dim.y + 6 + 25, BackGroundColor); Tft.drawRectangle(Pos.x-(Dim.x>>1)-5, Location.y-6, Abstand * 2 + Dim.x + 10, Abstand * 3 + Dim.y + 6 + 25, BLUE); // Rahmen um Zahl Tft.drawRectangle(Location.x - 2, Location.y-2, 12*MaxLen+5, 19, BLUE); // Ziffern 1..9 s[1] = 0; for (i = 1; i<10; i++) { s[0] = 48+i; Button[i].draw(Pos, Dim, LCD_getColor(120, 120, 120), LCD_getColor(0, 0, 30)); Button[i].setText(s, 2, LCD_getColor(255, 255, 255)); Pos.x = Pos.x + Abstand; if ((i == 3) || (i == 6)) { Pos.x = X0; Pos.y = Pos.y + Abstand; } } // unterste Zeile schreiben (C, 0, OK) Pos.x = X0; Pos.y = Pos.y + Abstand; s[0]='C'; Button[10].draw(Pos, Dim, LCD_getColor(120, 120, 120), LCD_getColor(0, 0, 30)); Button[10].setText(s, 2, LCD_getColor(255, 255, 255)); Pos.x = Pos.x + Abstand; s[0] = '0'; Button[0].draw(Pos, Dim, LCD_getColor(120, 120, 120), LCD_getColor(0, 0, 30)); Button[0].setText(s, 2, LCD_getColor(255, 255, 255)); Pos.x = Pos.x + Abstand; s[0] = 'O'; s[1] = 'K'; s[2] = 0; Button[11].draw(Pos, Dim, LCD_getColor(120, 120, 120), LCD_getColor(0, 0, 30)); Button[11].setText(s, 2, LCD_getColor(255, 255, 255)); ctr = 0; down = 0; while(ctr >= 0) { do { i = Menu_getKey(Button, 12); }while (Menu_getKey(Button, 12) != i); if ((i > 11) && ((getTimer() - Time) > 200)) down = 0; // entprellen if ((i < 12) && (down == 0)) { // Taste neu gedrückt down = 1; Time = getTimer(); switch (i) { case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7: case 8: case 9: if (ctr < MaxLen) { Tft.drawNumber(i, Location.x + FONT_SPACE * 2 * ctr, Location.y, 2, RED); *Value = *Value * 10 + i; ctr = ctr + 1; } break; case 10: // Clear Tft.drawNumber(*Value, Location.x, Location.y, 2, BackGroundColor); *Value = 0; if (ctr == 0) ctr = -2; // Eingabe abbrechen else ctr = 0; // Eingabe löschen break; case 11: // Enter ctr = -1; // Ende der Eingabe break; default: break; } // end case } // end if } // end while return ctr + 2; } /*************************************** Bildschirmdarstellung *************************/ // Hintergrundfarbe #define BackGndColor 1 // Tastenfarben #define KeyNormalColor (16 << 11) + (16 << 6) + 16 #define KeyHiLiteColor (31 << 11) + (0 << 5) + 0 #define KeyFillColor (0 << 11) + (0 << 6) + 6 #define KeyTextColor (31 << 11) + (31 << 6) + 0 // Füllfarben Modulationstasten #define KeyAMColor (5 << 11) + (0 << 6) + 0 #define KeySSBColor (0 << 11) + (5 << 6) + 0 // Textfarben Modulationstasten #define ModInactivColor (0 << 11) + (18 << 6) + 0 #define ModActivColor (31 << 11) + (0 << 6) + 31 // Farbe der Trennlinien #define LineColor (0 << 11) + (4 << 6) + 8 // Textfarben #define FrqColor YELLOW #define BWColor RED #define LevelColor CYAN // *************** Positionen der diversen Elemente ******************* const Point_t Menu_FrqPosition = {160,5}; const Point_t Menu_BWPosition = {133,108}; const Point_t Menu_LevelPosition = {140, 65}; // ************** Variablen ************************** int Frequenz = 183000; // Frequenz in Hz uint8_t Modulation; // Modulation: 0->AM, 1->AM synchron, 2->USB, 3->LSB, 4->CW // numerische Frequenzeingabe in kHz, Übergabeparameter ist Position der Eingabe-Anzeige void enterFrq(void) { int Value, x; x = Menu_getNumValue(3, BackGndColor, &Value); if (x) Frequenz = Value * 1000; NCO_Frequenz = (int)((float)(Frequenz) * 4.2949673e9 / 1e6); } // zeigt Frequenz in kHz void Menu_dispFrq(uint16_t Color) { const int CharSize = 2; const int YSTEP = (FONT_Y + 3) * CharSize; // max. 5 Stellen vor Dezimalpunkt int Pos = Menu_FrqPosition.x + FONT_SPACE * CharSize * 4; //Anzahl Stellen vor Dezimalpunkt bestimmen und Startposition entsprechend schieben if (Frequenz > 9999) Pos = Pos - FONT_SPACE * CharSize; if (Frequenz > 99999) Pos = Pos - FONT_SPACE * CharSize; if (Frequenz > 999999) Pos = Pos - FONT_SPACE * CharSize; if (Frequenz > 9999999) Pos = Pos - FONT_SPACE * CharSize; Tft.drawFloat((float)(Frequenz)/1000.0, 3, Pos, Menu_FrqPosition.y + YSTEP, CharSize, Color); Tft.drawString("kHz", Menu_FrqPosition.x + FONT_SPACE * CharSize * 9, Menu_FrqPosition.y + YSTEP, CharSize, Color); } // Anzeige Bandbreite, dabei ist 'Filter' der Index auf die Filterkoeffizienten. // Index 0 ist für 500Hz Bandbreite, die Schrittweite beträgt 100Hz und die höchste Bandbreite ist 9.5kHz void Menu_dispBW(uint16_t Color) { const int CharSize = 2; const int YSTEP = (FONT_Y + 3) * CharSize * 2; Tft.drawFloat((float)(Filter+5) * 0.1, 1, Menu_BWPosition.x, Menu_BWPosition.y + YSTEP, CharSize, Color); Tft.drawString("kHz", Menu_BWPosition.x + FONT_SPACE * CharSize * 3, Menu_BWPosition.y + YSTEP, CharSize, Color); } // Modulation umschalten, die globale Variable 'Modulation' schaltet im Interrupt auf den // entsprechenden Demodulator void Menu_setModulation(int NewMod, Button_t *DefKey) { if (Modulation != NewMod) { DefKey[5].setText("AM", 2, ModInactivColor); DefKey[6].setText("Synchron", "AM", 1, ModInactivColor); DefKey[7].setText("USB", 2, ModInactivColor); DefKey[8].setText("LSB", 2, ModInactivColor); DefKey[9].setText("CW", 2, ModInactivColor); } Modulation = NewMod; } // LCD-Userinterface, muss periodisch aufgerufen werden und blockiert während aktiven Eingaben void LCD_Interface(void) { static int State = 0; // aktuelle Bildschirmebene static Button_t DefKey[11]; // Standardknöpfe (Frequenz +/-/Eingabe, Bandbreite +/- int i, tempColor; static uint32_t Time; static int OldLevel; extern float AGC_Gain; const uint32_t UpdateDelay = 10000; // Einheit 0.1ms switch(State) { case 0: // Initialisierung, Inhalt neu zeichnen Tft.fillRectangle(0, 0, 320, 240, BackGndColor); Menu_dispFrq(FrqColor); // Bedienelemente Frequenz: +, num. Eingabe, - DefKey[0].draw({30, 35}, {50,50}, KeyNormalColor, KeyFillColor); DefKey[0].setText("-", 3, FrqColor); DefKey[1].draw({65, 80}, {120,30}, KeyNormalColor, KeyFillColor); DefKey[1].setText("Direkteingabe", 1, FrqColor); DefKey[2].draw({100, 35}, {50,50}, KeyNormalColor, KeyFillColor); DefKey[2].setText("+", 3, FrqColor); // Trennlinie Tft.fillRectangle(0, 104, 320, 2, LineColor); // Bandbreitentasten: +, - DefKey[3].draw({30, 140}, {50,50}, KeyNormalColor, KeyFillColor); DefKey[3].setText("-", 3, BWColor); DefKey[4].draw({100, 140}, {50,50}, KeyNormalColor, KeyFillColor); DefKey[4].setText("+", 3, BWColor); Menu_dispBW(BWColor); // Trennlinien Tft.fillRectangle(220, 104, 2, 70, LineColor); Tft.fillRectangle(0, 174, 320, 2, LineColor); // Modulation: AM, Syn, USB, LSB, CW DefKey[5].draw({30, 210}, {50,50}, KeyNormalColor, KeyAMColor); DefKey[5].setText("AM", 2, ModActivColor); DefKey[6].draw({94, 210}, {56,50}, KeyNormalColor, KeyAMColor); DefKey[6].setText("Synchron", "AM", 1, ModInactivColor); DefKey[7].draw({160, 210}, {50,50}, KeyNormalColor, KeySSBColor); DefKey[7].setText("USB", 2, ModInactivColor); DefKey[8].draw({220, 210}, {50,50}, KeyNormalColor, KeySSBColor); DefKey[8].setText("LSB", 2, ModInactivColor); DefKey[9].draw({280, 210}, {50,50}, KeyNormalColor, KeyFillColor); DefKey[9].setText("CW", 2, ModInactivColor); // Taste für weitere Funktionen DefKey[10].draw({270, 140}, {70,50}, KeyNormalColor, KeyFillColor); DefKey[10].setText("weitere", "Funktionen", 1, KeyTextColor); // statische Texte Tft.drawString(" Frequenz", Menu_FrqPosition.x, Menu_FrqPosition.y, 2, FrqColor); Tft.drawString("Band-\nbreite", Menu_BWPosition.x, Menu_BWPosition.y, 2, BWColor); Tft.drawString("Pegel(dB)", Menu_LevelPosition.x, Menu_LevelPosition.y, 1, LevelColor); Tft.drawRectangle(Menu_LevelPosition.x -2, Menu_LevelPosition.y + 13, 160, 8, LineColor); State = 1; break; case 1: // Standard-Bedienelemente, Abfrage // Anzeige dynamischer Grössen, Update jede Sekunde if ((getTimer() - Time) > UpdateDelay) { // Pegel i = 40 * log10f(AGC_Gain); if (i != OldLevel) { // Pegel hat geändert, anzeigen if (ADC1->SR & 1) { // ADC übersteuert, Anzeige rot tempColor = RED; ADC1->SR = ADC1->SR & ~1; } else // nicht übersteuert, normal tempColor = LevelColor; Tft.drawNumber(OldLevel >> 1, Menu_LevelPosition.x + 59, Menu_LevelPosition.y, 1, BackGndColor); Tft.drawNumber(i >> 1, Menu_LevelPosition.x + 59, Menu_LevelPosition.y, 1, tempColor); // Balkenanzeige, nur positive Werte Tft.fillRectangle(Menu_LevelPosition.x, Menu_LevelPosition.y + 15, 150, 4, BackGndColor); if (i > 0) Tft.fillRectangle(Menu_LevelPosition.x, Menu_LevelPosition.y + 15, i, 4, tempColor); OldLevel = i; } Time = getTimer(); } // Tastenabfrage, zur Störunterdrückung muss zweimal derselbe Tastencode gelesen werden do { i = Menu_getKey(DefKey, 11); } while (Menu_getKey(DefKey, 11) != i); // Auswertung switch(i) { case 0: // Frequenz - Menu_dispFrq(BackGndColor); Frequenz = Frequenz - 100; NCO_Frequenz = (int)((float)(Frequenz) * 4.2949673e9 / 1e6); Menu_dispFrq(FrqColor); break; case 1: // Frequenz Direkteingabe enterFrq(); State = 0; break; case 2: // Frequenz + Menu_dispFrq(BackGndColor); Frequenz = Frequenz + 100; NCO_Frequenz = (int)((float)(Frequenz) * 4.2949673e9 / 1e6); Menu_dispFrq(FrqColor); break; case 3: // Bandbreite - if (Filter > 0) { Menu_dispBW(BackGndColor); Filter = Filter - 1; Menu_dispBW(BWColor); } break; case 4: // Bandbreite + if (Filter < 90) { Menu_dispBW(BackGndColor); Filter = Filter + 1; Menu_dispBW(BWColor); } break; case 5: // AM Menu_setModulation(0, DefKey); DefKey[5].setText("AM", 2, ModActivColor); break; case 6: // Synchron AM Menu_setModulation(1, DefKey); DefKey[6].setText("Synchron", "AM", 1, ModActivColor); break; case 7: // USB Menu_setModulation(2, DefKey); DefKey[7].setText("USB", 2, ModActivColor); break; case 8: // LSB Menu_setModulation(3, DefKey); DefKey[8].setText("LSB", 2, ModActivColor); break; case 9: // CW Menu_setModulation(4, DefKey); DefKey[9].setText("CW", 2, ModActivColor); break; case 10: // weitere Funktionen break; default: // keine Taste gedrückt break; } break; default: // Fehler, darf nicht vorkommen State = 0; break; } // end switch }