Arduino-hoz színes, szagos, karakteres képernyő kezelés

 

2020-06-19

Egy olyan Arduino-ra épülő kütyün töröm a fejem, aminek egy csomó beállítása lenne. Be lehet ezeket állítgatni egy kétsoros LCD segítségével is, de macerás. Kínálkozik az Arduino keretrendszer beépített terminálja, de csak az alap dolgokat tudja. Anno a számítógépeket úgynevezett terminálokon keresztül kezeltünk. Azoknak a régi DEC PDP kompatibilis számítógépeknek nem volt billentyűzetük, video kártyájuk, hanem egy soros vonaluk volt, amire rá kellett kötni a terminált. A terminál soros vonalon adta a lenyomkodott billyentyűket, és soros vonalon vette a számítógépből jövő betüket. Alap esetben tehát ahhoz is kellett egy program (echo), hogy a lenyomott billentyűknek megfelelő betüket a számítógép kiírja a terminál 24 soros és 80 oszlopos képenyőjére (screen/display). Ezek a terminálok nem csak betük kiírására voltak képesek, hanem úgynevezett vezérlő szekvenciákat is tudtak értelmezni, úgy mint képernyő törlés, aláhúzott betük vagy inverz betük írása, vagy a kurzor pozícionálás a képenyőn. Persze manapság nem rohanunk a boltba egy DEC VT52 vagy egy DEC VT100... terminálért, hanem a feltöltünk a PC-re egy terminál emulátor programot. Linux esetében az embernek talán könnyebb a helyzete, WINxx esetében a TeraTerm használatát ajánlom.

TeraTerm Home page.

Az alábbi képen a TeraTerm terminál ablaka látható. Pontosabban az, amit Arduino demo programom kiírt rá.

Pár dolgot be kell állítsunk, ezeket a [Setup] oszlopban találjuk.

Sajnos a WINxx attól függően melyik USB csatlakozóra dugjuk az Arduino-nkat, más-más COM porton fogja látni. Tehát válasszuk ki a [Serial port] menüpontot és állítsuk be a COM port számát, valamint hogy milyen sebességet (bit/sec - Baud) fogunk használni. A [New setting] gombbal jóváhagyjuk. Lehet a többi paramétert is állítgatni, akit érdekel olvasson utána.

Következő lépésben válasszuk ki a [Terminal] menüpontot, itt lehet beállítani milyen típusú terminált szeretnénk emulálni. Tulajdonképpen hagyjuk meg ezt az alapbeállítást. A TeraTerm nagyon sokat tud még, de most ennyit fogok belőle használni. Ne felejtsük el menteni a beállításainkat a [Setup] oszlopban a [Save setup...] menüpontban.

A kt_teraterm objektumba írtam bele a terminál vezérlésére alkalmazható szekvenciákat. Ha utána olvastok, sok olyan szekvencia is van, amit én nem programoztam le. Részben azért mert nincs mindenre szükségem, részeben nem minden működött. Azután írtam néhány saját függvényt, amik vonalat, kockát, keretet rajzolnak a karakteres képernyőre. Ez a full retro :).



/******************************************************************************
*   Author       -  Kiraly Tibor
*                   http://www.tkiraaly.hu
*   Date         -  2020.06.17.
*   Chip         -  TeraTerm terminal emulator
*   Compiler     -  Arduino IDE
*
*   TeraTerm control
*   
*******************************************************************************/

#include "Arduino.h"


class kt_teraterm
{
   public:
   kt_teraterm( void) {};
   void cls( void) { Serial.print( "\033[0m\033[2J\033[1;1H");};     // clear screen
   void yx( byte, byte);                                             // move cursor to y/x
   void normal( void) { Serial.print( "\033[0m");};                  // clear all text attributes
   void underline( void) { Serial.print( "\033[4m");};               // underline text
   void underline_off( void) { Serial.print( "\033[24m");};          // not underline text
   void inverz( void) { Serial.print( "\033[7m");};                  // inverz text
   void inverz_off( void) { Serial.print( "\033[27m");};             // not inverz text
   void ink_black( void) { Serial.print( "\033[30m");};              // text color
   void ink_red( void) { Serial.print( "\033[31m");};
   void ink_green( void) { Serial.print( "\033[32m");};
   void ink_yellow( void) { Serial.print( "\033[33m");};
   void ink_blue( void) { Serial.print( "\033[34m");};
   void ink_magenta( void) { Serial.print( "\033[35m");};
   void ink_cyan( void) { Serial.print( "\033[36m");};
   void ink_white( void) { Serial.print( "\033[37m");};
   void paper_black( void) { Serial.print( "\033[40m");};            // background color
   void paper_red( void) { Serial.print( "\033[41m");};
   void paper_green( void) { Serial.print( "\033[42m");};
   void paper_yellow( void) { Serial.print( "\033[43m");};
   void paper_blue( void) { Serial.print( "\033[44m");};
   void paper_magenta( void) { Serial.print( "\033[45m");};
   void paper_cyan( void) { Serial.print( "\033[46m");};
   void paper_white( void) { Serial.print( "\033[47m");};
   void draw_box( byte, byte, byte, byte);                           // draw box
   void draw_frame( byte, byte, byte, byte);                         // draw frame
   void draw_x( byte, byte, byte);                                   // draw row
   void draw_y( byte, byte, byte);                                   // drav column
};


void kt_teraterm::yx( byte y, byte x)
{
   Serial.print( "\033["); 
   Serial.print( y);   
   Serial.print( ";");   
   Serial.print( x);   
   Serial.print( "H");   
}


void kt_teraterm::draw_box( byte y, byte x, byte dy, byte dx)
{
   byte i;
   while( dy)
   {
      yx( y+ dy- 1, x);
      for( i= 0; i < dx; i++) Serial.write( ' ');
      dy--;
   }    
}


void kt_teraterm::draw_y( byte y, byte x, byte dy)
{
   yx( y, x);
   Serial.write( '+');   
   yx( y+ dy- 1, x);
   Serial.write( '+');
   dy-= 2;
   while( dy--)
   {
      yx( y+ dy+ 1, x);
      Serial.write( '!');   
   }
}


void kt_teraterm::draw_x( byte y, byte x, byte dx)
{
   yx( y, x);
   Serial.write( '+');   
   yx( y, x+ 1);
   dx-= 2;
   while( dx--) Serial.write( '-');
   Serial.write( '+');   
}


void kt_teraterm::draw_frame( byte y, byte x, byte dy, byte dx)
{
   draw_x( y, x, dx);
   draw_x( y+ dy- 1, x, dx);
   draw_y( y, x, dy);
   draw_y( y, x+ dx- 1, dy);
}


kt_teraterm t= kt_teraterm();


void setup()
{
   Serial.begin( 19200);
   
   t.cls();

   Serial.print("1234567890");
   t.inverz();
   Serial.print("1234567890");
   t.inverz_off();
   Serial.print("1234567890");
   t.inverz();
   Serial.print("1234567890");
   t.inverz_off();
   Serial.print("1234567890");
   t.inverz();
   Serial.print("1234567890");
   t.inverz_off();
   Serial.print("1234567890");
   t.inverz();
   Serial.println("1234567890");
   t.inverz_off();

   Serial.println("2");
   Serial.println("3");
   Serial.println("4");
   Serial.println("5");
   Serial.println("6");
   Serial.println("7");
   Serial.println("8");
   Serial.println("9");
   Serial.println("0");

   t.inverz();
   Serial.println("1");
   Serial.println("2");
   Serial.println("3");
   Serial.println("4");
   Serial.println("5");
   Serial.println("6");
   Serial.println("7");
   Serial.println("8");
   Serial.println("9");
   Serial.println("0");
   t.inverz_off();

   Serial.println("1");
   Serial.println("2");
   Serial.println("3");
   Serial.print("4");

   t.underline();
   t.yx( 3, 15);   
   Serial.println( "TeraTerm test!");
   t.underline_off();

   t.draw_x( 2, 12, 30);
   t.draw_y( 3, 55, 10);
   t.draw_frame( 6, 8, 4, 20);
   
   t.ink_yellow();
   t.paper_blue();
   t.yx( 8, 20);   
   Serial.print( " 0123 ");

   t.paper_red();
   t.ink_black();
   t.draw_box( 12, 15, 3, 20);
   t.yx( 13, 20);   
   Serial.print( "Game ower!");

}


void loop()
{}

Az alábbi program a bebillentyűzött adatok begyüjtését van hivatva bemutatni. A Serial.peek() függvénnyel talán ritkábban találkozunk. Tulajdonképpen ugyanaz mint a Serial.read(), csak az adatot nem veszi ki a bufferből. Mindkettő -1-et ad vissza, ha nem volt lenyomott gomb. A loop()-ot azért bővítettem ki, hogy bemutassam, ha a bejövő betüket így kezeljük, akkor emellett a programunk tovább futhat.


/******************************************************************************
*   Author       -  Kiraly Tibor
*                   http://www.tkiraaly.hu
*   Date         -  2020.06.19.
*   Chip         -  TeraTerm terminal emulator
*   Compiler     -  Arduino IDE
*
*   Echo
*   
*******************************************************************************/
#include "Arduino.h"


void setup()
{
   Serial.begin( 19200);
}


void loop()
{
   if( Serial.peek() != -1) Serial.write( Serial.read());    // arduino echo
   Serial.println( ".");
   delay( 300);
}

Az alábbi program képernyőjén egy gombsort látunk.

A 0..9 billentyűkkel egyenként pirosba, majd vissza, kékbe kapcsolhatjuk őket.


/******************************************************************************
*   Author       -  Kiraly Tibor
*                   http://www.tkiraaly.hu
*   Date         -  2020.06.19.
*   Chip         -  TeraTerm terminal emulator
*   Compiler     -  Arduino IDE
*
*   TeraTerm demo2
*   
*******************************************************************************/
#include "arduino.h"

class kt_teraterm
{
   public:
   kt_teraterm( void) {};
   void cls( void) { Serial.print( "\033[0m\033[2J\033[1;1H");};     // clear screen
   void yx( byte, byte);                                             // move cursor to y/x
   void normal( void) { Serial.print( "\033[0m");};                  // clear all text attributes
   void underline( void) { Serial.print( "\033[4m");};               // underline text
   void underline_off( void) { Serial.print( "\033[24m");};          // not underline text
   void inverz( void) { Serial.print( "\033[7m");};                  // inverz text
   void inverz_off( void) { Serial.print( "\033[27m");};             // not inverz text
   void ink_black( void) { Serial.print( "\033[30m");};              // text color
   void ink_red( void) { Serial.print( "\033[31m");};
   void ink_green( void) { Serial.print( "\033[32m");};
   void ink_yellow( void) { Serial.print( "\033[33m");};
   void ink_blue( void) { Serial.print( "\033[34m");};
   void ink_magenta( void) { Serial.print( "\033[35m");};
   void ink_cyan( void) { Serial.print( "\033[36m");};
   void ink_white( void) { Serial.print( "\033[37m");};
   void paper_black( void) { Serial.print( "\033[40m");};            // background color
   void paper_red( void) { Serial.print( "\033[41m");};
   void paper_green( void) { Serial.print( "\033[42m");};
   void paper_yellow( void) { Serial.print( "\033[43m");};
   void paper_blue( void) { Serial.print( "\033[44m");};
   void paper_magenta( void) { Serial.print( "\033[45m");};
   void paper_cyan( void) { Serial.print( "\033[46m");};
   void paper_white( void) { Serial.print( "\033[47m");};
   void draw_box( byte, byte, byte, byte);                           // draw box
   void draw_frame( byte, byte, byte, byte);                         // draw frame
   void draw_x( byte, byte, byte);                                   // draw row
   void draw_y( byte, byte, byte);                                   // drav column
};


void kt_teraterm::yx( byte y, byte x)
{
   Serial.print( "\033["); 
   Serial.print( y);   
   Serial.print( ";");   
   Serial.print( x);   
   Serial.print( "H");   
}


void kt_teraterm::draw_box( byte y, byte x, byte dy, byte dx)
{
   byte i;
   while( dy)
   {
      yx( y+ dy- 1, x);
      for( i= 0; i < dx; i++) Serial.write( ' ');
      dy--;
   }    
}


void kt_teraterm::draw_y( byte y, byte x, byte dy)
{
   yx( y, x);
   Serial.write( '+');   
   yx( y+ dy- 1, x);
   Serial.write( '+');
   dy-= 2;
   while( dy--)
   {
      yx( y+ dy+ 1, x);
      Serial.write( '!');   
   }
}


void kt_teraterm::draw_x( byte y, byte x, byte dx)
{
   yx( y, x);
   Serial.write( '+');   
   yx( y, x+ 1);
   dx-= 2;
   while( dx--) Serial.write( '-');
   Serial.write( '+');   
}


void kt_teraterm::draw_frame( byte y, byte x, byte dy, byte dx)
{
   draw_x( y, x, dx);
   draw_x( y+ dy- 1, x, dx);
   draw_y( y, x, dy);
   draw_y( y, x+ dx- 1, dy);
}

kt_teraterm t= kt_teraterm();


byte g[]= { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1};
byte k;


void gomb( byte n)
{
   if( g[ n])
   {
      g[ n]= 0;                        // invertalas
      t.paper_blue();
   }
   else
   {
      g[ n]= 1;                        // invertalas
      t.paper_red();
   }
   switch( n)
   {
      case 0: t.yx(  2, 5); Serial.println("  0  "); break;
      case 1: t.yx(  4, 5); Serial.println("  1  "); break;
      case 2: t.yx(  6, 5); Serial.println("  2  "); break;
      case 3: t.yx(  8, 5); Serial.println("  3  "); break;
      case 4: t.yx( 10, 5); Serial.println("  4  "); break;
      case 5: t.yx( 12, 5); Serial.println("  5  "); break;
      case 6: t.yx( 14, 5); Serial.println("  6  "); break;
      case 7: t.yx( 16, 5); Serial.println("  7  "); break;
      case 8: t.yx( 18, 5); Serial.println("  8  "); break;
      case 9: t.yx( 20, 5); Serial.println("  9  "); break;
   }
   t.yx( 1, 1);
}


void setup()
{
   byte i;
   Serial.begin( 19200);
   t.cls();
   for( i= 0; i < 10; i++) gomb( i);
}


void loop()
{
   if( Serial.peek() != -1)
   {
      k= Serial.read()- '0';
      if( k >= 0 && k <= 9) gomb( k);
   }
}

Ennyi az egész, itt a vége, fuss el véle.