TTGO T-CameraをESP-IDF & Eclipseで動かす(その2)
前回の”TTGO T-CameraをESP-IDF & Eclipseで動かす“を元にOLED(有機EL)表示と人感センサー検知を追加していきます。前回の続きでやってもいいですし、環境ができていれば新規でプロジェクトを作ってもそんなに手間はかからないと思います。
私は新規でプロジェクト名を”TTGO_Camera_v2″としてやっています。
OLEDをやる前に前回ではブラウザーでリロードするときに画像が更新されていましたが、これを連続して画像が更新されるモーションJPEGにします。前回で使った”espressif/esp32-camera“のサンプルコードにある”jpg_stream_httpd_handler()”に”jpg_httpd_handler()”から置き換えます。合わせて”httpd_uri_t camera ->.handler”を”jpg_httpd_handler”から”jpg_stream_httpd_handler”に変更します。
ブラウザーで”192.168.xx.xx/camera”などにアクセスすると連続して画像が更新されるモーションJPEGになっているのがわかります。
このモーションJPEG化は今回の記事とは直接関係ないのでお好みで。
さてそれではOLED(有機EL)に文字表示をしていきましょう!!!
OLEDドライバ/コントローラICはSSD1306を使用していてTTGO T-CameraではI2C接続しています。SSD1306のデータシートを見てやっていけば表示できるとは思いますが、面倒なのとGitHubにライブラリーがきっとあるでしょうから探してみます。
GitHubで”esp-idf ssd1306″で検索してヒットしたものの中から”https://github.com/nopnop2002/esp-idf-ssd1306“でできたので今回はこちらを使わせてもらいました。
“esp-idf-ssd1306″をexamplesフォルダー下にcloneします(componentsフォルダーに入れてそのままbuidするとエラーします)。examplesフォルダーに入れておけば新規プロジェクトを作ったとき”esp-idf-ssd1306″Templateとして選択できるようになります。
今回はこれらのコードを既存プロジェクトに追加していきます。”esp-idf-ssd1306/main”フォルダー内のファイルを”main.c”を除いてそっくり”プロジェクト名/main”にコピペ。
“main.c”に#include “ssd1306.h”を追加。
”app_main()”関数に”esp-idf-ssd1306/main/main.c”内の”app_main()”関数の内容を参考にOLEDにデータを表示するコードを追加します。
1 |
SSD1306_t dev; |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
#if CONFIG_I2C_INTERFACE ESP_LOGI(tag, "INTERFACE is i2c"); ESP_LOGI(tag, "CONFIG_SDA_GPIO=%d",CONFIG_SDA_GPIO); ESP_LOGI(tag, "CONFIG_SCL_GPIO=%d",CONFIG_SCL_GPIO); ESP_LOGI(tag, "CONFIG_RESET_GPIO=%d",CONFIG_RESET_GPIO); i2c_master_init(CONFIG_SDA_GPIO, CONFIG_SCL_GPIO, CONFIG_RESET_GPIO); #if CONFIG_SSD1306_128x64 ESP_LOGI(tag, "Panel is 128x64"); i2c_init(&dev, 128, 64, 0x3C); #endif // CONFIG_SSD1306_128x64 #endif // CONFIG_I2C_INTERFACE ssd1306_clear_screen(&dev, false); ssd1306_contrast(&dev, 0xff); ssd1306_display_text(&dev, 0, "TTGO_Camera_v2", 14, false); ssd1306_display_text(&dev, 1, " SSD1306 128x64", 15, false); |
build/flashすると”TTGO_Camera_v2″、” SSD1306 128×64″の2行が表示されます。
”esp-idf-ssd1306/main/Kconfig.projbuild”を組み込んでいるのでbuild後にsdkconfigを開くと”SSD1306 Configuration”が追加されています。設定はこのままでいいです。上記のコードもSPI Interface、128×32がないので省いています。
OLEDが使えるようになったので接続しているIPアドレスを表示してみましょう。
現在、”app_main()”関数内で”example_connect()”を呼び出していますがこのソースコードは”esp-idf/examples/common_components/protocol_examples_common/connect.c”です。このソースコードを参考に以下のコードでIPアドレスが表示されます。
1 2 3 4 5 6 7 8 9 |
tcpip_adapter_ip_info_t s_ip_info; char char_ip_addr[16]; int strLen; ssd1306_display_text(&dev, 3, "IP address:", 11, false); tcpip_adapter_get_ip_info(TCPIP_ADAPTER_IF_STA, &s_ip_info); strLen = sprintf(char_ip_addr, IPSTR, IP2STR(&s_ip_info.ip)); ssd1306_display_text(&dev, 4, char_ip_addr, strLen, false); |
最後に人感センサーです。人感センサーは33ピンがHighならOn/LowならOffです。
1 |
#define PIR_SENSOR_PIN 33 |
まずこの33ピンを入力に設定します。
1 |
gpio_set_direction(PIR_SENSOR_PIN, GPIO_MODE_INPUT); |
これをTimerイベント発生時に判定してOLEDに表示したいと思います。
Timerイベントの設定についてはEspressif提供の文書”Event Loop Library“や使用例として”esp-idf\examples\system\esp_event\default_event_loop\main\main.c”を参照しました。
1 2 3 |
esp_timer_handle_t TIMER; /* Event source periodic timer related definitions */ ESP_EVENT_DEFINE_BASE(TIMER_EVENTS); |
1 2 3 4 5 6 7 8 9 |
ESP_ERROR_CHECK(esp_event_handler_register(TIMER_EVENTS, TIMER_EVENT_EXPIRY, timer_expiry_handler, NULL)); // Create and start the event sources esp_timer_create_args_t timer_args = { .callback = &timer_callback, }; ESP_ERROR_CHECK(esp_timer_create(&timer_args, &TIMER)); ESP_ERROR_CHECK(esp_timer_start_periodic(TIMER, TIMER_PERIOD)); |
ここで登録したtimer_callback、timer_expiry_handlerをそれぞれ実装します。
timer_expiry_handlerで人感センサーを判定して表示しています。
また動作しているのがわかるように次の行の1文字を点滅させています。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
int blink = 0; // Handler which executes when the timer expiry event gets executed by the loop. static void timer_expiry_handler(void* handler_args, esp_event_base_t base, int32_t id, void* event_data) { if(gpio_get_level(PIR_SENSOR_PIN)) { ssd1306_display_text(&dev, 6, "Pir Sensor On ", 14, true); } else { ssd1306_display_text(&dev, 6, "Pir Sensor Off", 14, false); } if(blink) { blink = 0; ssd1306_display_text(&dev, 7, " ", 1, false); } else { blink = 1; ssd1306_display_text(&dev, 7, " ", 1, true); } } // Callback that will be executed when the timer period lapses. Posts the timer expiry event // to the default event loop. static void timer_callback(void* arg) { ESP_ERROR_CHECK(esp_event_post(TIMER_EVENTS, TIMER_EVENT_EXPIRY, NULL, 0, portMAX_DELAY)); } |
これをbuild/flashすると人感センサー動作および動作確認点滅ができました。
プロジェクト全体はGitHubにあります。