/* PicoTerm-demo zur Ansteuerung der PicoTerm-TFT Anzeige mit Text und Grafik zur Verwendung auf Arduino uno oder anderer Hardware mit ATmega328. Reines C-Programm ohne spezifische Befehle der Arduino-IDE Das Programm gliedert sich in folgende Bereiche: 1. Parametervorgabe/Init für ATmega mit UART und Timer 2. Definitionen fuer Farbe/Text/Grafik des TFT 3. Initialisierung des ATmega328 4. Basisroutinen zur TFT-Ansteuerung 5. Routinen zur Anzeige von Text und Demo-Tastatur 6. Demoprogramm unter Verwendung der vorhandenen Funktionen Michael Nowak www.mino-elektronik.de info@mino-elektronik.de 2023-12-10 */ #define BIT(x) (1< #include #include #include // Vorwaertsreferenzen void tft_touchmeld(unsigned char nr); void tft_clear(void); void tft_fcol(unsigned char fcol); void tft_bcol(unsigned char bcol); void tft_zoom(unsigned char nr); void zeige_grafik(int laenge, short *werte, short max); void loesche_rxd_puffer(); void loesche_txd_puffer(); #define DEF_BAUDRATE 57600 #define SOLL_BAUDRATE 250000 #define DEF_CPU_CLOCK 16000000 #define INT_PRO_SEKUNDE 1000 #define T1_TEILER (DEF_CPU_CLOCK/1000) // f�r 1 ms Raster #define RX_INT_ENABLE 0x80 #define TX_INT_ENABLE 0x40 static uint8_t txd_puffer[TXD_PUFFER_LEN+2], rxd_puffer[RXD_PUFFER_LEN+2]; static volatile uint8_t rxd_puffer_lese_zeiger, rxd_puffer_schreib_zeiger, txd_puffer_lese_zeiger, txd_puffer_schreib_zeiger, rxd_puffer_anzahl, txd_puffer_anzahl; /* Die Bytes fuer die Farbeinstellung sind wie folgt: 0b000000xx xx steht f�r die Helligkeit von Rot 0b0000xx00 xx steht f�r die Helligkeit von Gr�n 0b00xx0000 xx steht f�r die Helligkeit von Blau 0b0x000000 x steht f�r Transparente Farbe 0bx0000000 x steht f�r Blinken */ #define SCHWARZ 0x00 #define ROT 0x03 #define GRUEN 0x0c #define BLAU 0x30 #define WEISS (ROT+BLAU+GRUEN) #define GELB (ROT+GRUEN) #define TUERKIS (0x2d) #define VIOLETT (BLAU+GRUEN) #define HELLGRAU 0x2a #define DUNKELGRAU 0x15 #define DEF_SCHRIFT_FARBE SCHWARZ // Vorgabewert nach dem Einschalten #define DEF_HINTERGRUND_FARBE WEISS // Vorgabewert nach dem Einschalten enum {PUSH_ZOOM, POP_ZOOM, CLR_ZOOM, // fuer push-pop von Zoom+Farbe+Cursor PUSH_XY, POP_XY, CLR_XY, PUSH_FONT, POP_FONT, CLR_FONT, PUSH_COLOR, POP_COLOR, CLR_COLOR}; #define EINFACH 1 // Zoomfaktoren #define DOPPELT 2 #define ZOOM DOPPELT #define TRANSPARENT 0x40 // fuer Farbeinstellung #define BLINKEN 0x80 #define MIN_HELLIGKEIT 0 #define MAX_HELLIGKEIT 8 #define SCHRIFT_BREITE 8 // Vorgabewerte nach dem Einschalten #define SCHRIFT_HOEHE 16 #define MAX_X 480 #define MAX_Y 272 #define ESC 27 #define LF 10 #define CR 13 #define NEUE_TASTE 1 // neue Taste erkannt #define REPEAT_TASTE 2 // repeat-Taste #define ENTPRELL_ZEIT_TFT 2 // fuer TFT-Touch #define FIRST_REPEAT 50 // nach 0,5 Sekunden #define NEXT_REPEAT 10 // alle 0,10 Sekunden // Struktur fuer eine einzelene Taste typedef struct {int16_t x1, y1, x_len, y_len; uint8_t farbe, status; uint8_t tast_code, repeat_code; char *text; char *ueberschrift; char *format; int8_t eingabefeld; } EINE_TASTE; #define RAHMEN 1 // als Attribute zum zeichnen der Tasten #define MAX_TASTEN 30 // auf sinnvolles Mass beschraenken #define DEF_X 40 // feste Tastengroesse fuer x #define DEF_Y 40 // und y #define X_OFFSET 80 // fuer 480 // default Tastatur nur '+' und '-' Tasten haben Repeat-Funktion! EINE_TASTE def_taste[] = { // Position Tastengroesse Farbe Att. Code+rpt Beschriftung Ueberschrift {10+X_OFFSET,100, DEF_X*2+10, DEF_Y, ROT, RAHMEN,'A',0, "Zeichens. 1", "CP850-uni"}, {110+X_OFFSET,100, DEF_X*2+20, DEF_Y, BLAU, RAHMEN,'B',0, "Zeichens. 2", "CP850 8x16"}, {220+X_OFFSET,100, DEF_X*2+10, DEF_Y, BLAU, RAHMEN,'C',0, "Zeichens. 3", "CP437 klein"}, {10+X_OFFSET,150, DEF_X, DEF_Y, ROT, RAHMEN,'D',0, "Clear", ""}, {60+X_OFFSET,150, DEF_X, DEF_Y, BLAU, RAHMEN,'E',0, "Save", ""}, {110+X_OFFSET,150, DEF_X*2+20, DEF_Y, BLAU, RAHMEN,'F',0, "Zeichens. 4", ""}, {220+X_OFFSET,150, DEF_X, DEF_Y, SCHWARZ,RAHMEN+DOPPELT,'H','h', "-", ""}, // + und - mit Repeat-Funktion {270+X_OFFSET,150, DEF_X, DEF_Y, SCHWARZ,RAHMEN+DOPPELT,'I','i', "+", ""}, {10+X_OFFSET,200, DEF_X*2+10, DEF_Y, GELB, RAHMEN,'J',0, "Textausgabe", ""}, // Schriftfarbe wird dyn. angepasst {110+X_OFFSET,200, DEF_X*2+20, DEF_Y, GRUEN, RAHMEN,'K',0, "Zeichens. 5", ""}, {220+X_OFFSET,200, DEF_X*2+10, DEF_Y, TUERKIS,RAHMEN,'L',0, "Farben", ""}, {-1} }; char taste_beschriftet[20+1]; // 1, wenn beschriftet static char akt_zeile, akt_spalte; // fuer LCD-Simualtion static uint8_t entprell_sperre; // fuer Bausratensuche static volatile char timer_flag; // freie Verwendung static volatile long timer; // dto. static volatile uint8_t sync_flag; // fuer Warteschleifen static volatile short tft_x, tft_y; // Touch-Koordinaten volatile char tft_status, zoom=1; // fuer Touch-Auswertung, bzw. Schriftgroesse static EINE_TASTE *tab; // Zeiger auf Struktur static short tab_size; // aktuelle Groesse static char hintergrund_farbe, schrift_farbe; // lokale Werte int8_t helligkeit = MAX_HELLIGKEIT; // RS232-Routinen zu Kommunikation ISR(USART_RX_vect) { char temp; temp = UDR0; /* zeichen immer lesen */ if(rxd_puffer_anzahl < RXD_PUFFER_LEN) { rxd_puffer[rxd_puffer_schreib_zeiger++] = temp; if(rxd_puffer_schreib_zeiger >= RXD_PUFFER_LEN) rxd_puffer_schreib_zeiger = 0; rxd_puffer_anzahl++; } } ISR(USART_UDRE_vect) { UCSR0B &= ~BIT(UDRIE0); // sender zunaechst sperren if(txd_puffer_anzahl) { /* noch zeichen im puffer */ UDR0 = txd_puffer[txd_puffer_lese_zeiger++]; /* Zeichen senden: ins register */ if(txd_puffer_lese_zeiger >= TXD_PUFFER_LEN) txd_puffer_lese_zeiger = 0; txd_puffer_anzahl--; UCSR0B |= BIT(UDRIE0); // sender wieder freigeben } } void stelle_baudrate(long bd) { long temp; temp=((DEF_CPU_CLOCK/16/(bd/10)+5)/10) - 1; /* runden !!! */ UBRR0L=temp%256; UBRR0H=temp/256; } void loesche_txd_puffer() { UCSR0B &= ~TX_INT_ENABLE; /* int sofort sperren */ txd_puffer_lese_zeiger = 0; txd_puffer_schreib_zeiger = 0; txd_puffer_anzahl = 0; } void loesche_rxd_puffer() { UCSR0B &= ~RX_INT_ENABLE; /* nicht unterbrechen */ rxd_puffer_anzahl = 0; rxd_puffer_lese_zeiger = 0; rxd_puffer_schreib_zeiger = 0; UCSR0B |= RX_INT_ENABLE; /* rx immer aktiv */ } void init_serio(uint32_t baudrate) { UCSR0B = 0x0; // TX und RX sperren loesche_rxd_puffer(); loesche_txd_puffer(); stelle_baudrate(baudrate); UCSR0B |= BIT(RXEN0) + BIT(TXEN0) + BIT(RXCIE0); UDR0; // evtl. Zeichen loeschen sei(); } void tft_ausgabe_ISR(uint8_t c) // bei hoeheren Baudraten nicht sinnvoll { while(txd_puffer_anzahl >= TXD_PUFFER_LEN); /* warten, wenn puffer voll ist */ txd_puffer[txd_puffer_schreib_zeiger++] = c; /* zeichen in puffer geben */ if(txd_puffer_schreib_zeiger >= TXD_PUFFER_LEN) txd_puffer_schreib_zeiger = 0; UCSR0B &= ~BIT(UDRIE0); // nicht unterbrechen txd_puffer_anzahl++; UCSR0B |= BIT(UDRIE0); /* ausgabe starten, wenn zulawssig */ } // Standard Augabe-Routine ohne Interrupt, damit RX-ISR nicht blockiert wird void tft_ausgabe(uint8_t c) { while((UCSR0A & 0x20) == 0); // einzelne Zeichen als ASCII aufs TFT UDR0 = c; } char lese_rxd_puffer() { char c; if(rxd_puffer_anzahl == 0) return(0); c = rxd_puffer[rxd_puffer_lese_zeiger++]; if(rxd_puffer_lese_zeiger >= RXD_PUFFER_LEN) rxd_puffer_lese_zeiger = 0; UCSR0B &= ~RX_INT_ENABLE; /* nicht unterbrechen */ rxd_puffer_anzahl--; UCSR0B |= RX_INT_ENABLE; return(c); } int lese_rxd_puffer_anzahl() {return(rxd_puffer_anzahl);} int lese_txd_puffer_anzahl() {return(txd_puffer_anzahl);} // alle 1 ms aufrufen ISR(TIMER1_COMPA_vect) { static int8_t delay; OCR1A += T1_TEILER; timer++; timer_flag=1; sync_flag=1; TIMSK1 &= ~BIT(OCIE1A); // Timer-Interrupt abschalten sei(); // global fuer RXD wieder freigeben delay--; if(delay <= 0) { // nur alle 10 ms bearbeiten delay = 10; if(!entprell_sperre) teste_tft(); // nicht bei autom. Baudratensuche aufrufen } cli(); // global wieder sperren TIMSK1 = BIT(OCIE1A); // COMP1A Int-enable } void init_timer1() { static char init=0; if(init) return; init=1; timer=0; sync_flag=0; timer_flag=0; TCCR1B = BIT(CS10); // vorteiler /1, compa-clear TIMSK1 = BIT(OCIE1A); // COMP1A Int-enable f�r 1000 Hz sei(); } // 1 ms Langzeittimer auslesen uint32_t lese_timer(void) { uint32_t temp; cli(); temp = timer; sei(); return(temp); } static void sync() { init_timer1(); sync_flag=0; while(!sync_flag); } // ins 1 ms Intervallen warten void delay_ms(uint32_t zeit) { init_timer1(); while(zeit--) sync(); } // ab hier Routinen zum Zeichen von Tasten und Zeichenausgabe // aktuelle Tastatur festlegen void init_tast_tab(EINE_TASTE *p, char schrift, char hintergrund) { int i=0; tab = p; hintergrund_farbe = hintergrund; schrift_farbe = schrift; while(tab[i].x1 >= 0) i++; tab_size = i; for(i=0; i> 8); tft_ausgabe(i16); } // fuer Textausgabe void tft_putstr(char *p) { while(*p) tft_ausgabe(*p++);} // fuer begrenzte Textausgabe void tft_putstrn(char *p, char n) { while(n--) tft_ausgabe(*p++);} // Reset vom TFT auf Standardeinstellungen void tft_init() // auf Default-Werte setzen { tft_command('@'); } // alternative Farbe fuer Blinken void tft_acol(unsigned char fcol) { tft_command('c'); tft_ausgabe('1'); tft_ausgabe(fcol); } // Vordergrundfarbe: Grafik + Schrift void tft_fcol(unsigned char fcol) { tft_command('c'); tft_ausgabe('3'); tft_ausgabe(fcol); } // Hintergrundfarbe auch zum loeschen void tft_bcol(unsigned char bcol) { tft_command('c'); tft_ausgabe('4'); tft_ausgabe(bcol); } // Vergoesserungsfaktoren: oberes nibble x, unteres y // ist x = 0, wird x = y verwendet. // zoom = 2 setzt x und y auf 2, alternativ zu: 0x22 // zomm = 0x12 setzt x auf 1 und y auf 2 void tft_zoom(unsigned char zoom) { tft_command('c'); tft_ausgabe('5'); tft_ausgabe(zoom); } // Rettet und restauriert aktuelle Einstellungen: Farbe, Cursor, Zeichensatz, zoom void tft_push_pop(unsigned char cmd) { tft_command('c'); tft_ausgabe('p'); tft_ausgabe(cmd); } // stellt Zeichensatz ein void tft_font(unsigned char nr) { tft_command('c'); tft_ausgabe('6'); tft_ausgabe(nr); } // Blinkfrequenz in 10 ms Schritten void tft_f_blink(unsigned char rate) { tft_command('c'); tft_ausgabe('7'); tft_ausgabe(rate); } // Tabellenindex: 0 ... 8 // dunkel -> hell void tft_backlight(unsigned char intens) { tft_command('c'); tft_ausgabe('8'); tft_ausgabe(intens); } // automatisches Senden von touch-Koordinaten ein-aus void tft_touchmeld(unsigned char ein_aus) { tft_command('c'); tft_ausgabe('t'); tft_ausgabe(ein_aus); } // gesamtes Bild auf Hintergrundfarbe, Cursor auf links oben void tft_clear(void) { tft_ausgabe(0x0c); } // nur die Umrandung void zeichne_rechteck(short x1,short y1, short x2, short y2, uint8_t col) { tft_command('g'); tft_ausgabe('r'); tft_int16(x1); tft_int16(y1); tft_int16(x2); tft_int16(y2); tft_ausgabe(col); } // mit Farbe Rechteck fuellen void fuelle_rechteck(short x1,short y1, short x2, short y2, uint8_t col) { tft_command('g'); tft_ausgabe('f'); tft_int16(x1); tft_int16(y1); tft_int16(x2); tft_int16(y2); tft_ausgabe(col); } // Linie zwischen den Endpunkten void zeichne_linie(short x1,short y1, short x2, short y2, uint8_t col) { tft_command('g'); tft_ausgabe('l'); tft_int16(x1); tft_int16(y1); tft_int16(x2); tft_int16(y2); tft_ausgabe(col); } // einzelner Punkt void tft_dot(short x1,short y1, uint8_t col) { tft_command('G'); tft_ausgabe('p'); tft_int16(x1); tft_int16(y1); tft_ausgabe(col); } // einzelnes Grafikzeichen frei positioniert schreiben void tft_gchar(short x1,short y1, uint8_t z) { tft_command('G'); tft_ausgabe('c'); tft_int16(x1); tft_int16(y1); tft_ausgabe(z); } // Cursor fuer Grafikausgabe setzen und Anstand für Inkrement von x-Position void tft_set_gcursor(short x1,short y1, uint8_t abstand) { tft_command('G'); tft_ausgabe('t'); tft_int16(x1); tft_int16(y1); tft_ausgabe(abstand); } // Text als Grafikzeichen ausgeben void tft_gtext(short x, short y, short xraster , char *p) { while(*p){ tft_gchar(x, y, *p++); x += xraster; } } // einzelne Zeichen als ASCII aufs TFT void text_putchar(char c) { tft_ausgabe(c);} void tft_alarm(unsigned short w) { tft_command('c'); tft_ausgabe('O'); tft_ausgabe(w); } void tft_bd_index(uint8_t index){ tft_command('c'); tft_ausgabe('b'); tft_ausgabe(index); } // Zeichenposition im Raster wie LC-Display ausgeben void tft_set_textcursor(char z, char s) { tft_command('C'); tft_ausgabe(z); tft_ausgabe(s); akt_zeile = z; akt_spalte = s; } // ganze LC-Zeile l�schen void loesche_zeile(char n) { char *s = " "; akt_zeile = n; akt_spalte = 1; tft_set_textcursor(akt_zeile, akt_spalte); tft_putstr(s); } // oberste Zeile anzeigen void text_zeile1(char *s) { if(zoom != DOPPELT) { zoom = DOPPELT; tft_zoom(zoom); } tft_set_textcursor(1,1); akt_spalte += strlen(s); tft_putstr(s); } // 2. Zeile anzeigen void text_zeile2(char *s) { if(zoom != DOPPELT) { zoom = DOPPELT; tft_zoom(zoom); } tft_set_textcursor(2,1); akt_spalte += strlen(s); tft_putstr(s); } // zum Einmitten Blanks entfernen void blanks_entfernen(char *s) { uint8_t temp,i; temp = strlen(s)-1; while(temp && (s[temp] == ' ')) s[temp--] = 0; /* blanks am ende loeschen */ temp = 0; while(s[temp] == ' ') temp++; /* blanks am anfang suchen */ if(temp) { /* nur, wenn welche vorhanden */ i=0; do { s[i++] = s[temp]; /* verschieben */ } while(s[temp++]); /* bis ende erreicht */ } } // als LC-Zeile ausgeben void text_zeile_einmitten(char *t, char zeile) { char s[30]; short start_x, start_y; strcpy(s,t); /* string muss im RAM stehen !!! */ if(zoom != DOPPELT) { zoom = DOPPELT; tft_zoom(zoom); } blanks_entfernen(s); loesche_zeile(zeile); start_y = (zeile-1) * SCHRIFT_HOEHE*zoom; start_x = (MAX_X - strlen(s) * SCHRIFT_BREITE*zoom) / 2 + 1; tft_gtext(start_x, start_y, SCHRIFT_BREITE*zoom, s); } void text_zeile1_einmitten(char *s) {text_zeile_einmitten(s,1);} void text_zeile2_einmitten(char *s) {text_zeile_einmitten(s,2);} // erzeugt blinkenden Unterstrich void text_cursor_on(uint8_t farbe) { fuelle_rechteck(akt_spalte*SCHRIFT_BREITE, akt_zeile*SCHRIFT_HOEHE-5, akt_spalte*SCHRIFT_BREITE+16, akt_zeile*SCHRIFT_HOEHE-1, farbe); } void text_string(char *s) { tft_putstr(s); akt_spalte += strlen(s);} // fuer Bildueberschriften wie 20 x 2 LCD behandeln, // kann auch auf weitere Zeilen erweitert werden void text_clear() { loesche_zeile(1); loesche_zeile(2); tft_set_textcursor(1,1); } // Funktionen um Tasten fuer Bedienmenue zu Zeichnen // // dekorativer Rahmen zu Einzeltaste void zeichne_rahmen(uint8_t n, uint8_t farbe) { short x1, x2, y1, y2; x1 = tab[n].x1; y1 = tab[n].y1; x2 = x1 + tab[n].x_len; y2 = y1 + tab[n].y_len; zeichne_rechteck(x1-2, y1-2, x2+2, y2+2, farbe); } // einzelne Taste zeichnen void zeichne_taste(uint8_t n) { short x1, x2, y1, y2; x1 = tab[n].x1; y1 = tab[n].y1; x2 = x1 + tab[n].x_len; y2 = y1 + tab[n].y_len; fuelle_rechteck(x1-3, y1-3, x2+3, y2+3, tab[n].farbe); if(tab[n].status & RAHMEN) // sieht besser aus: mit Rahmen zeichne_rahmen(n, hintergrund_farbe); } // alle Tasten eine Tastatur void zeichne_tasten() { char n; for(n = 0; n < tab_size; n++) { zeichne_taste(n); } } // test, ob xy-Koordinaten einem Tastenfeld entsprechen char teste_tastenfeld(short x, short y, uint8_t n) { if(x >= tab[n].x1 && x <= tab[n].x1+tab[n].x_len) /* im x-Bereich */ if(y >= tab[n].y1 && y <= tab[n].y1+tab[n].y_len) /* und im y-Bereich */ return(1); /* gefunden */ return(0); } // Taste erkennen char suche_taste(short x, short y) { uint8_t n; for(n = 0; n < tab_size; n++) { if(teste_tastenfeld(x,y,n)) { return(n); /* gefunden */ } } return(-1); } // Index zum Tastencode suchen uint8_t suche_tasten_index(uint8_t taste) { uint8_t index; for(index=0; index < tab_size; index++) { if(tab[index].tast_code == taste || tab[index].repeat_code == taste) return(index); } return(-1); } // Touch-Taste suchen und Code oder Repeat-Code liefern uint8_t tft_getkey() { char temp, taste = 0; short x,y; temp = get_tft_touch(&x,&y); switch (temp) { case NEUE_TASTE: temp = suche_taste(x,y); /* neu gedrueckt */ if(temp >= 0) { taste = tab[(uint8_t) temp].tast_code; tft_alarm(5); /* Tastklick */ } break; case REPEAT_TASTE: temp = suche_taste(x,y); /* repeat */ if(temp >= 0) { taste = tab[(uint8_t) temp].repeat_code; if(taste) tft_alarm(5); /* Tastklick */ } break; } return(taste); } // der Tastenindex muss verwendet werden void taste_beschriften(uint8_t n, uint8_t farbe) { char *text; volatile char neu_zoom, alt_zoom, breite = SCHRIFT_BREITE*2, hoehe = SCHRIFT_HOEHE*2; short x,y; if(n >= tab_size) return; // Taste nicht vorhanden taste_beschriftet[n] = 1; // Beschriftung merken alt_zoom = neu_zoom = zoom; // Groesse merken if((tab[n].status) & ZOOM) { // Zoom fuer jede Taste separat neu_zoom = DOPPELT; } else { neu_zoom = EINFACH; breite /= 2; hoehe /= 2; } if(neu_zoom != alt_zoom) tft_zoom(neu_zoom); // neue Groesse einstellen tft_push_pop(PUSH_COLOR); // akt. Farben retten tft_bcol(tab[n].farbe); // Farben nach Vorgabe tft_fcol(farbe); text = tab[n].text; x = (tab[n].x_len - (strlen(text) * breite))/2 + 1; // x-Start zum Einmitten x += tab[n].x1; // Offset dazu, eff. Startadresse y = (tab[n].y_len - hoehe)/2 + 1; // y-Start zum Einmitten y += tab[n].y1; // Offset dazu tft_gtext(x, y, breite, text); // Taste beschriften tft_push_pop(POP_COLOR); // alter Zustand text = tab[n].ueberschrift; // Falls Ueberschrift vorhanden if(*text != 0) { x = (tab[n].x_len - (strlen(text) * breite))/2 + 1; // einmitten wie bei Beschriftung der Taste x += tab[n].x1; // eff. Startadresse y = tab[n].y1 -(SCHRIFT_HOEHE+3)*neu_zoom; // eff. Startadresse tft_gtext(x, y, breite, text); // Ueberschrift ausgeben } if(neu_zoom != alt_zoom) tft_zoom(alt_zoom); // alte groesse einstellen } // Beschriftung loeschen void loesche_taste_nr(uint8_t n) { if(n >= tab_size) return; // Taste nicht vorhanden if(taste_beschriftet[n]) { // nur wenn schon beschriftet taste_beschriftet[n] = 0; zeichne_taste(n); // ohne Beschriftung neu zeichnen } } // nachtraegliche Beschriftung mit beliebigem Text void set_tasten_text(uint8_t n, char *text, uint8_t farbe) { char neu_zoom, alt_zoom, breite = SCHRIFT_BREITE*2, hoehe = SCHRIFT_HOEHE*2; short x,y; if(n >= tab_size) return; // Taste nicht vorhanden if(strlen(text) < strlen(tab[n].text)) // nur, wenn neur Text kuerzer ist taste_beschriften(n,tab[n].farbe); // mit tastenfarbe loeschnen taste_beschriftet[n] = 1; // beschriftung merken alt_zoom = neu_zoom = zoom; // groesse merken if(tab[n].status & ZOOM) { neu_zoom = DOPPELT; } else { neu_zoom = EINFACH; breite /= 2; hoehe /= 2; } if(neu_zoom != alt_zoom) tft_zoom(neu_zoom); // neue Groesse einstellen tft_push_pop(PUSH_COLOR); // akt. Farben retten tft_bcol(tab[n].farbe); // Farben nach Vorgabe tft_fcol(farbe); x = (tab[n].x_len - (strlen(text) * breite))/2 + 1; // x-Start zum Einmitten x += tab[n].x1; // Offset dazu, eff. Startadresse y = (tab[n].y_len - hoehe)/2 + 1; // y-Start zum Einmitten y += tab[n].y1; // Offset dazu tft_gtext(x, y, breite, text); // Taste beschriften tft_push_pop(POP_COLOR); // alter Zustand if(neu_zoom != alt_zoom) tft_zoom(alt_zoom); // alte Groesse einstellen } // alle Tasten beschriften void zeige_tasten() { static char init; char c; if(!init) { init_tft(); init = 1; } zeichne_tasten(); for(c = tab_size-1; c >= 0; c--) { // rueckwaerts beschriften wirkt besser taste_beschriften(c,WEISS); } } void zeige_taste(char c) { taste_beschriften(c,WEISS); } void blink_taste(char c) { taste_beschriften(c,WEISS+BLINKEN); } void zeige_tasten_text(char c, char *s) { set_tasten_text(c,s,WEISS); } void blinkend_tasten_text(char c, char *s) { set_tasten_text(c,s,WEISS+BLINKEN); } // Baudrate beim TFT einstellen // 0 = 9600 // 1 = 19200 // 2 = 38400 // 3 = 57600 // 4 = 76800 // 5 = 115200 // 6 = 125000 ab hier mu� auf passende RS232-Treiber geachtet werden! // 7 = 230400 // 8 = 250000 // 9 = 460800 // 10 = 500000 // 0 = CP850 8x16 mit Unicode-Anpassung // 1 = CP850 8x16 // 2 = CP437 6x10 modifiziert // 3 = CP437 8x16 // 4 = CP866 8x16 // die Ausgabe von 2 x ESC-Zeichen gibt als Echo einen '*' // Damit kann man testen, ob die vorgegebene Baudrate erkannt wird char startsync() { char i; loesche_rxd_puffer(); // puffer leeren for(i=0; i<4; i++) { tft_ausgabe(27); delay_ms(10); if(lese_rxd_puffer() == '*') return(1); // Baudrate wird erkannt } return(0); } // je nach Tabelle auf sinnvolle Werte begrenzen #define MAX_TFT_BAUD sizeof(baud_tab)/sizeof(baud_tab[0]) #define SOLL_BAUD_INDEX 8 // fuer 250000 Bd // akt. eingestellte Baudrate suchen (typ. 57600 nach dem Einschalten) // und dann auf 250000 einstellen void stelle_tft_baud() { uint32_t baud_tab[] = {9600, 19200, 38400, 57600, 76800, 115200, 125000, 230400, 250000, 460800, 500000}; static uint8_t tft_baud; uint8_t i=0; entprell_sperre = 1; // Touch-Abfrage unterbinden stelle_baudrate(baud_tab[tft_baud]); // letzte Einstellung zuerst probieren delay_ms(100); if(!startsync()) { // hat nicht geklappt for(i=0; i < MAX_TFT_BAUD; i++) { stelle_baudrate(baud_tab[i]); // alle probieren delay_ms(100); if(startsync()) { tft_baud = i; // akt. Baudrate gefunden break; } } } tft_bd_index(SOLL_BAUD_INDEX); // TFT dann auf Sollbaudrate einstellen delay_ms(100); // abwarten bis aktiv init_serio(baud_tab[SOLL_BAUD_INDEX]); // und dann eigene Schnittstelle einstellen delay_ms(100); entprell_sperre = 0; // Touch darf wieder angesprochen werden } // Antippen an beliebiger Stelle abwarten uint8_t tft_touch() { short x,y; return(get_tft_touch(&x,&y)); // auf Beruehrung vom touch warten } // Demo void zeichensatz_anzeigen(uint8_t z, char* titel) { short n,m; uint8_t alt_zoom = zoom; tft_clear(); tft_zoom(2); tft_fcol(ROT); text_zeile2_einmitten(titel); tft_fcol(SCHWARZ); tft_zoom(1); if(z <= 4) tft_font(z); for(m = 0; m < 8; m++) { for(n = 0; n < 32; n++) { tft_gchar((n+14)*SCHRIFT_BREITE,(m+5)*SCHRIFT_HOEHE, n+m*32); } } while(!tft_touch()); // auf Beruehrung vom touch warten tft_alarm(30); zoom = alt_zoom; // wie zuvor tft_zoom(zoom); tft_font(0); // default } // demo farbige Rechtecke void farben() { short x1,x2,y1,y2; char farbe, muster = 0; tft_clear(); do { x1 = 0, x2 = MAX_X-1; y1 = 0, y2 = MAX_Y-1; for(farbe = 0; farbe < 64; farbe++) { zeichne_rechteck(x1,y1,x2,y2,farbe ^ muster); zeichne_rechteck(x1+1,y1+1,x2-1,y2-1,farbe ^ muster); zeichne_rechteck(x1+2,y1+2,x2-2,y2-2,farbe ^ muster); x1 += 3; x2 -= 3; y1 +=2; y2 -=2; } delay_ms(300); muster ++; muster &= 0x3f; // ohne Attribute } while(!tft_touch()); // auf Beruehrung vom touch warten tft_alarm(30); } // demo Ausgabegeschwindigkeit void textausgabe() { uint16_t i=0; uint32_t j; char s[50]; tft_push_pop(PUSH_COLOR); // akt. Farbe sichern tft_bcol(GRUEN); // Hintergrund auf gruen tft_clear(); do { i++; j = i; j *= j; sprintf(s,"i=%6d ",i); tft_fcol(ROT); // Schriftfarbe auf rot tft_putstr(s); tft_fcol(BLAU); // Schriftfarbe auf rot sprintf(s,"i*i=%10ld\n\r",j); tft_putstr(s); delay_ms(2); // bei Baudrate < 125000 Bd notwendig } while(!tft_touch()); // auf Beruehrung vom touch warten tft_alarm(30); tft_push_pop(POP_COLOR); // alte Farbe } int main(void) { uint8_t taste, neue_anzeige = 1; init_serio(DEF_BAUDRATE); // AVR initialisieren init_timer1(); // 1000 Hz Timer sei(); delay_ms(200); // Einschalten des TFTs abwarten!!! stelle_tft_baud(); // Baudarte hochsetzen init_tft(); // Vorgabewerte setzen, Touch zulassen tft_backlight(helligkeit); while(1) { if(neue_anzeige) { tft_clear(); init_default_tastatur(); // zum Spielen zeige_tasten(); // und anzeigen // andere Farbe fuer Beschriftung taste_beschriften(8,ROT); taste_beschriften(9,BLAU); taste_beschriften(10,SCHWARZ); text_zeile1_einmitten("Testprogramm"); text_zeile2_einmitten("f\x81r TFT-Bedienung"); // kleines 'ü' ist anders kodiert // testweise Textcursor auf oben rechts setzen tft_set_textcursor(1,9); // wegen Textzoom_x = 2 tft_push_pop(PUSH_COLOR); tft_fcol(ROT+BLINKEN); // blinkende rote Schriftfarbe tft_acol(GRUEN); // auf gruen wechselnd tft_ausgabe(3); // Herz anzeigen tft_set_textcursor(1,22); // wegen zoom_x = 2 tft_fcol(GRUEN+BLINKEN); // blinkende gruene Schriftfarbe tft_acol(ROT); // auf rot wechselnd tft_ausgabe(3); // Herz anzeigen tft_f_blink(40); // Blinkfrequenz etwas langsamer als Default tft_push_pop(POP_COLOR); neue_anzeige = 0; } do { // auf Tastendruck warten DDRB |= BIT(5); PORTB ^= BIT(5); taste = tft_getkey(); // Taste = Zeichen aus der Init-Tabelle PORTB ^= BIT(5); delay_ms(10); } while(!taste); switch(taste) { case 0: break; // keine Taste case 'H': // '-' Taste case 'h': // mit repeat if(helligkeit > MIN_HELLIGKEIT) { helligkeit--; tft_backlight(helligkeit); } else tft_alarm(50); break; case 'I': // '+' Taste case 'i': // mit repeat if(helligkeit < MAX_HELLIGKEIT) { helligkeit++; tft_backlight(helligkeit); } else tft_alarm(50); break; case 'D': zeige_tasten(); // alle Tasten neu schreiben + weiss beschriften break; case 'E': neue_anzeige = 1; // Bild neu aufbauen break; case 'A': zeichensatz_anzeigen(0,"CP850 8x16 uni"); // alle Tasten neu schreiben+beschriften neue_anzeige = 1; break; case 'B': zeichensatz_anzeigen(1,"CP850 8x16"); // alle Tasten neu schreiben+beschriften neue_anzeige = 1; break; case 'C': zeichensatz_anzeigen(2,"CP437 6x10 mod"); // alle Tasten neu schreiben+beschriften neue_anzeige = 1; break; case 'F': zeichensatz_anzeigen(3,"CP437 8x16"); // alle Tasten neu schreiben+beschriften neue_anzeige = 1; break; case 'K': zeichensatz_anzeigen(4,"CP866 8x16"); // alle Tasten neu schreiben+beschriften neue_anzeige = 1; break; case 'J': textausgabe(); // Testausgabe mit auto-scroll neue_anzeige = 1; break; case 'L': farben(); // farbige Rechtecke zeichnen neue_anzeige = 1; break; default: blink_taste(suche_tasten_index(taste)); // Schrift blinken lassen, wenn keine Funktion vorhanden } } }