uGFXライブラリを使用したesp8266でのクールなGUIの開発

esp8266の多くのプロジェクトでは、タッチスクリーン付きのTFTスクリーンを使用しています。 プロジェクトによっては、インターフェイスは単純な場合があります。たとえば、アプリケーションのログを表示するテキストコンソールや、入力信号を変更するためのスケジュールだけです。 また、いくつかの画面では、いくつかの画面、グラフィックボタン、テキスト入力行、さらには仮想キーボードを備えた複雑なGUI


この記事では、タッチスクリーン付きの画面をesp8266に接続し、Arduino環境でグラフィカルインターフェースを実装する方法に関する私の経験を共有したいと思います。


ビデオティーザー:



それでは始めましょう


最初の部分、ハードウェア


画面モデルの選択


現在、aliexpressで読むと、TFTスクリーンの膨大な数のモデルが販売されています-異なるサイズ、異なる解像度、タッチスクリーンの有無にかかわらず。


TFTスクリーンは接続方法が異なります-SPIバスを介して接続するスクリーンと、パラレルバスを介して接続するスクリーンがあります。


最小、SPIバス経由で接続するには、4つの信号出力(GPIO)のみが必要で、パラレルバス経由で接続するには、最低10(タッチスクリーンコントローラーは含まれません)。 パラレルバスを介した接続は、高速で、 1クロックサイクルで8ビットの情報が一度に送信され、SPIの場合は1ビットのみです。


ただし、SPI接続にはもう1つの利点があります。関与するピンが少なくなります。 esp8266では、必要なピンの数が決定的な要因です。空きGPIOの数は限られています。


SPIインターフェースを備えた最も人気のあるTFTスクリーンモジュールを選びます。


  1. ili9341 "、タッチスクリーンコントローラーリンク付き
  2. ili9225 、タッチスクリーンリンクなし
  3. st7735 、タッチスクリーンリンクなし

TFTスクリーンをesp8266に接続します。


ほとんどのSPI画面は類似したハードウェアインターフェイスを備えているため、同じ方法でプロセッサに接続され、名前の小さな違いに対して正確です。 以下のネームプレートには、調査結果のリストと、それらの意味の説明が含まれています。


おわりに別名esp8266への接続予定
SCLKSCK、SCLGPIO14SPIバスクロッキング
SDAMOSIGPIO13プロセッサからスクリーンへのSPIデータ転送
CSSSGPIO5チップ選択(複数のデバイスをSPIバスに接続可能)
A0RS、D / CGPIO15データ/コマンド転送モードの選択
リセットRstVccハードウェアリセット
SDO味iso-画面からプロセッサへのデータ転送(オプション)
LED +LEDVccバックライトオン
VssVccVccスクリーン電源、+ 3.3V
GNDGND地球

RESETおよびLED+結論は、+ 3.3ボルトの電源バスに接続できますが、必要に応じてGPIO esp8266に接続でき、画面のリセットとバックライトをプログラムで制御できます。


CSおよびA0ピンは、便利なGPIO esp8266に接続できます。


最も重要な部分は、 SCLKおよびSDA結果です。 これらは、SPIバスでデータを送信する責任があります。 SPI esp8266コントローラーの対応するピンに接続する必要があります。 これらはそれぞれGPIO14GPIO13です。


画面にタッチスクリーンコントローラーがある場合は、SPIバスにも接続する必要があります。


おわりにesp8266への接続予定
T_CLKGPIO14SPIバスクロッキング
T_DINGPIO13プロセッサからタッチスクリーンコントローラーへのSPIデータ転送
T_CSGPIO16チップ選択(複数のデバイスをSPIバスに接続可能)
T_DOGPIO12コントローラーからプロセッサーへのデータ転送
T_IRQGPIO4タッチスクリーンタッチサイン

esp8266 GPIO14およびGPIO13の出力は、画面とタッチスクリーンコントローラーに並列に接続されていることに注意してください。 実際、複数のデバイスをSPIバスに接続できます。 デバイスを選択するには、必要なデバイスのCS出力で論理レベル0を設定します。


ili9341画面をesp8266に接続するスキーム


esp8266-screen


パート2、ソフトウェア


画面と接続図を決定しました。今度はソフトウェアの部分に進みます。 まず、GUIを実装するグラフィックライブラリを選択します。


数十のライブラリを試した後、 uGFXライブラリを選択しました。 私の意見では、これはマイクロコントローラー用の最高のグラフィックライブラリーの一つです。 豊富な機能がモジュール性と組み合わされ、必要なコンポーネントのみがプロジェクトに含まれます。 このライブラリはオープンソースであり、非営利的な使用は無料です。 ライブラリには、プロジェクトのWebサイトで入手可能な品質のドキュメントがあります。


uGFXライブラリの大きな利点は、utf8をサポートする開発されたフォントレンダリングエンジンです。 キットには、キリル文字を含むttfファイルからフォントを生成するためのプログラムが含まれています。


ライブラリはクロスプラットフォームです-これは、アプリケーションのGUI部分をesp8266を含む任意のプロセッサ向けにアセンブルできることを意味します。


スクリーンドライバーとタッチスクリーンドライバーは専用モジュールに接続されており、必要なドライバーが含まれていない場合は、個別に実装できます。


さらに、uGFXにはuGFX studio(WYSWIGインターフェイスエディター)が付属しています。このエディターでは、インターフェイスのレイアウトを視覚的に準備でき、uGFX studioは自動的にコードを生成し、リソースを分解します。 残念ながら、現在uGFXスタジオはまだベータ版の状態にあります。ベータ版を入手するには、フォーラムで開発者に連絡する必要があります。


そして、ケーキの最後のチェリー:アプリケーションのGUIコードは、デスクトップ(Linux / Windows / OSX)の下でアセンブルし、コンピューター上でインターフェースがどのように見えるかを直接確認できます。


PCデモ


uGFXをプロジェクトに接続します


ライブラリはビルドシステムを使用しますが、Arduinoビルドシステムではサポートされていません。 ただし、この制限は回避できます。 この記事を参考にしてください


以下のテキストは、esp8266をサポートするArduino開発環境がすでにインストールおよび構成されていることを前提としています。 まだインストールされていない場合は、環境のインストールと構成については、 ギークタイムに関するこの記事を参照してください。


ライブラリを接続する手順:


  1. Arduino環境からLibrariesフォルダーを見つけます。 プラットフォームに応じて、次のような場所に配置できます。


  1. uGFXをライブラリフォルダーに複製またはコピーします。 ここからダウンロードできます-すでにキリル文字フォントが組み込まれているバージョンです。


  2. 画面およびタッチスクリーンドライバーのI / O実装を含むラッパーライブラリを作成し、必要なuGFXコンポーネントをアセンブリに接続します。 これを行うには、LibrariesフォルダーにサブフォルダーuGFXespを作成する必要があります。およそ次の内容が含まれます。

 uGFXesp ├── library.properties └── src ├── board_ILI9341.cpp ├── board_ILI9341.h ├── gdisp_lld_config.h ├── gdisp_lld_ili9341.c ├── gfxconf.h ├── gfxlib.c ├── gmouse_lld_ADS7843.c ├── gmouse_lld_ADS7843_board.cpp └── gmouse_lld_ADS7843_board.h 


library.propertiesの内容
 name=uGFXesp version=1.0.0 author=Oleg V. Gerasimov <ogerasimov@gmail.com> maintainer=Oleg V. Gerasimov <ogerasimov@gmail.com> sentence=UI features of esp paragraph=This library add support screen and touch panel of esp board<br />Requires uGFX library<br /> category=Display architectures=esp8266 includes=gfx.h url=http://github.com 


Board_ILI9341.cppコンテンツ
 #include <Arduino.h> #include <SPI.h> extern "C" { #include "user_interface.h" } // Pin,     RS  #define ESP_LCD_RS 15 // Pin,     CS  #define ESP_LCD_CS 5 //   SPI     : 1/ #define SPILOWSPEED 1000000 //   SPI  : 32/ #define SPIHIGHSPEED 32000000 static SPISettings spiSettings(SPILOWSPEED, MSBFIRST, SPI_MODE0); //     static inline void cmdmode() { digitalWrite(ESP_LCD_RS, 0); } //     static inline void datamode() { digitalWrite(ESP_LCD_RS, 1); } //   extern "C" void esp_lcd_init_board(void) { SPI.begin(); pinMode(ESP_LCD_CS, OUTPUT); digitalWrite(ESP_LCD_CS, 1); pinMode(ESP_LCD_RS, OUTPUT); datamode(); } // -  -  SPI    extern "C" void esp_lcd_post_init_board(void) { spiSettings = SPISettings(SPIHIGHSPEED, MSBFIRST, SPI_MODE0); } static int aquire_count = 0; //   SPI:  0   CS    SPI    extern "C" void esp_lcd_aquirebus(void) { if (!aquire_count++) { SPI.beginTransaction(spiSettings); digitalWrite(ESP_LCD_CS, 0); } } //   SPI:  1   CS    SPI extern "C" void esp_lcd_releasebus(void) { if (aquire_count && !--aquire_count) { digitalWrite(ESP_LCD_CS, 1); SPI.endTransaction(); } } //   extern "C" void esp_lcd_write_index(uint16_t cmd) { cmdmode(); SPI.write(cmd); datamode(); } //    extern "C" void esp_lcd_write_data(uint16_t data) { SPI.write(data); } 


Gmouse_lld_ADS7843_board.cppコンテンツ
 #include <Arduino.h> #include <SPI.h> extern "C" { #include "user_interface.h" } // Pin,     TC_IRQ   #define ESP_TC_IRQ 4 // Pin,     CS   #define ESP_TC_CS 16 //   SPI    2/ #define SPISPEED 2000000 static SPISettings spiSettings(SPISPEED, MSBFIRST, SPI_MODE0); //   extern "C" int esp_gmouse_init_board() { pinMode(ESP_TC_CS, OUTPUT); digitalWrite(ESP_TC_CS, 1); pinMode(ESP_TC_IRQ, INPUT); return 1; } //    TC_IRQ (   ) extern "C" int esp_getpin_pressed() { //      watch dog,   esp8266   system_soft_wdt_feed (); //    return digitalRead (ESP_TC_IRQ)==0; } static int aquire_count = 0; //   SPI:  0   CS    SPI    extern "C" void esp_aquire_bus() { if (!aquire_count++) { SPI.beginTransaction(spiSettings); digitalWrite(ESP_TC_CS, 0); } } //   SPI:  1   CS    SPI extern "C" void esp_release_bus() { if (aquire_count && !--aquire_count) { digitalWrite(ESP_TC_CS, 1); SPI.endTransaction(); } } //      extern "C" uint16_t esp_read_value(uint16_t port) { SPI.write (port); return SPI.transfer16(0); } 

実際、準備作業は終わりました。 ソースファイルのセットはgithubにあります


これで準備が完了しました。美しく便利なGUIでプログラムまたはスケッチの開発を始めましょう。


GUIを使用したスケッチの開発


前の記事で 、現代のクリスマスツリー用の「スマート」延長コードについて書いた。 スケッチGUIは2つの画面で構成されています



w1w2


以下は、このプロジェクトのGUIによって実装されたコードのスニペットです。


変数の定義
 //   GHandle ghContainerMain; //  GHandle ghButton1,ghButton2,ghButton3,ghButton4,ghButtonAll,ghButtonVoice,ghButtonTree; //  gdispImage ballImg,bearImg,candleImg,microphoneImg,treeImg,bigTreeImg,lightsImg; //   GListener glistener; //         extern "C" void gwinButtonDraw_ImageText(GWidgetObject *gw, void *param); 

GUI初期化関数
 void guiCreate(void) { gfxInit(); //  ""  geventListenerInit(&glistener); geventAttachSource(&glistener, ginputGetKeyboard(0), 0); gwinAttachListener(&glistener); //    GUI gwinSetDefaultFont(gdispOpenFont("DejaVuSans16")); gwinSetDefaultStyle(&WhiteWidgetStyle, FALSE); gwinSetDefaultColor(HTML2COLOR(0x000000)); gwinSetDefaultBgColor(HTML2COLOR(0xFFFFFF)); //  ,       SPIFFs gdispImageOpenFile(&ballImg, "ball.bmp"); gdispImageOpenFile(&bearImg, "bear.bmp"); gdispImageOpenFile(&candleImg, "candle.bmp"); gdispImageOpenFile(&microphoneImg, "music.bmp"); gdispImageOpenFile(&treeImg, "tree.bmp"); gdispImageOpenFile(&lightsImg, "lights.bmp"); gdispImageOpenFile(&bigTreeImg, "bigtree.bmp"); //    GUI GWidgetInit wi; gwinWidgetClearInit(&wi); wi.gx = 0; wi.gy = 0; wi.g.width = 176; wi.g.height = 220; wi.g.show = TRUE; ghContainerMain = gwinContainerCreate(0, &wi, 0); wi.g.parent = ghContainerMain; wi.customDraw = gwinButtonDraw_ImageText; wi.customStyle = 0; wi.customParam = &bigTreeImg; wi.gx = 0; wi.gy = 0; wi.text = ""; ghButtonTree = gwinButtonCreate(0, &wi); wi.g.show = FALSE; wi.customParam = &ballImg; wi.g.width = 88; wi.g.height = 73; wi.text = ""; ghButton1 = gwinButtonCreate(0, &wi); wi.customParam = &candleImg; wi.gx = 88; wi.gy = 0; wi.text = ""; ghButton2 = gwinButtonCreate(0, &wi); wi.customParam = &bearImg; wi.gx = 0; wi.gy = 73; wi.text = ""; ghButton3 = gwinButtonCreate(0, &wi); wi.customParam = &lightsImg; wi.gx = 88; wi.gy = 73; wi.text = ""; ghButton4 = gwinButtonCreate(0, &wi); wi.customParam = &treeImg; wi.gx = 0; wi.gy = 146; wi.text = ""; ghButtonAll = gwinButtonCreate(0, &wi); wi.customParam = &microphoneImg; wi.gx = 88; wi.gy = 146; wi.text = ""; ghButtonVoice = gwinButtonCreate(0, &wi); } 

イベント処理
 static bool screenSaver = false; //       void switchScreen (bool flag) { gwinSetVisible (ghButton1,flag); gwinSetVisible (ghButton2,flag); gwinSetVisible (ghButton3,flag); gwinSetVisible (ghButton4,flag); gwinSetVisible (ghButtonAll,flag); gwinSetVisible (ghButtonVoice,flag); gwinSetVisible (ghButtonTree,!flag); screenSaver = !flag; } static unsigned long timeLastActivity =0; void loop() { unsigned long now = millis(); //      GEvent* pe = geventEventWait(&glistener, 2); if (pe && pe->type == GEVENT_GWIN_BUTTON) { GEventGWinButton *we = (GEventGWinButton *)pe; if (we->gwin == ghButton1) {/*    */} if (we->gwin == ghButton2) {/*    */} if (we->gwin == ghButton3) {/*    */} if (we->gwin == ghButton4) {/*    */} if (we->gwin == ghButtonAll) {/*    */}; if (we->gwin == ghButtonVoice) {/*    */}; if (we->gwin == ghButtonTree) {switchScreen (true); startRecognize();} timeLastActivity = now; } //      10 ,    if (!screenSaver && now - timeLastActivity > 10000) { switchScreen (false); } delay (10); } 

その結果、合理的な数のコード行により、本格的で、私の好みにとっては美しいGUIが得られます。 githubでスケッチの完全版


その他の使用例


シンプルなオシロスコープ



Githubソース: スケッチ自体


チャートの実装


テトリス



Githubソース: テトリス


最初のビデオのソースをスケッチ


全体として、この記事では、オープンソースで利用可能なライブラリを使用して、便利で美しいGUIソリューションを作成しました。



Source: https://habr.com/ru/post/J346276/


All Articles